source: sasview/sansmodels/src/c_models/coreshellbicelle.cpp @ e08bd5b

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since e08bd5b was e08bd5b, checked in by Jae Cho <jhjcho@…>, 12 years ago

c models fix: scale fix for P*S

  • Property mode set to 100644
File size: 12.5 KB
Line 
1/**
2        This software was developed by the University of Tennessee as part of the
3        Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
4        project funded by the US National Science Foundation.
5
6        If you use DANSE applications to do scientific research that leads to
7        publication, we ask that you acknowledge the use of the software with the
8        following sentence:
9
10        "This work benefited from DANSE software developed under NSF award DMR-0520547."
11
12        copyright 2008, University of Tennessee
13 */
14
15/**
16 * Scattering model classes
17 * The classes use the IGOR library found in
18 *   sansmodels/src/libigor
19 *
20 */
21
22#include <math.h>
23#include "parameters.hh"
24#include <stdio.h>
25using namespace std;
26#include "core_shell_bicelle.h"
27
28extern "C" {
29#include "libCylinder.h"
30#include "libStructureFactor.h"
31}
32
33typedef struct {
34  double scale;
35  double radius;
36  double rim_thick;
37  double face_thick;
38  double length;
39  double core_sld;
40  double rim_sld;
41  double face_sld;
42  double solvent_sld;
43  double background;
44  double axis_theta;
45  double axis_phi;
46} CoreShellBicelleParameters;
47
48
49/**
50 * Function to evaluate 2D scattering function
51 * @param pars: parameters of the core-shell Bicelle
52 * @param q: q-value
53 * @param q_x: q_x / q
54 * @param q_y: q_y / q
55 * @return: function value
56 */
57static double core_shell_bicelle_analytical_2D_scaled(CoreShellBicelleParameters *pars, double q, double q_x, double q_y) {
58  double cyl_x, cyl_y, cyl_z;
59  double q_z;
60  double alpha, vol, cos_val;
61  double answer;
62  //convert angle degree to radian
63  double pi = 4.0*atan(1.0);
64  double theta = pars->axis_theta * pi/180.0;
65  double phi = pars->axis_phi * pi/180.0;
66
67  // Cylinder orientation
68  cyl_x = sin(theta) * cos(phi);
69  cyl_y = sin(theta) * sin(phi);
70  cyl_z = cos(theta);
71
72  // q vector
73  q_z = 0;
74
75  // Compute the angle btw vector q and the
76  // axis of the cylinder
77  cos_val = cyl_x*q_x + cyl_y*q_y + cyl_z*q_z;
78
79  // The following test should always pass
80  if (fabs(cos_val)>1.0) {
81    printf("core_shell_bicelle_analytical_2D: Unexpected error: cos(alpha)=%g\n", cos_val);
82    return 0;
83  }
84
85  alpha = acos( cos_val );
86
87  // Call the IGOR library function to get the kernel
88  answer = BicelleKernel(q, pars->radius, pars->rim_thick, pars->face_thick,
89      pars->core_sld,pars->face_sld,pars->rim_sld,
90      pars->solvent_sld, pars->length/2.0, alpha) / fabs(sin(alpha));
91
92  //normalize by cylinder volume
93  vol=pi*(pars->radius+pars->rim_thick)
94          *(pars->radius+pars->rim_thick)
95          *(pars->length+2.0*pars->face_thick);
96  answer /= vol;
97
98  //convert to [cm-1]
99  answer *= 1.0e8;
100
101  //Scale
102  answer *= pars->scale;
103
104  // add in the background
105  answer += pars->background;
106
107  return answer;
108}
109
110/**
111 * Function to evaluate 2D scattering function
112 * @param pars: parameters of the core-shell cylinder
113 * @param q: q-value
114 * @return: function value
115 */
116static double core_shell_bicelle_analytical_2DXY(CoreShellBicelleParameters *pars, double qx, double qy) {
117  double q;
118  q = sqrt(qx*qx+qy*qy);
119  return core_shell_bicelle_analytical_2D_scaled(pars, q, qx/q, qy/q);
120}
121
122
123CoreShellBicelleModel :: CoreShellBicelleModel() {
124  scale      = Parameter(1.0);
125  radius     = Parameter(20.0, true);
126  radius.set_min(0.0);
127  face_thick  = Parameter(10.0, true);
128  face_thick.set_min(0.0);
129  rim_thick  = Parameter(10.0, true);
130  rim_thick.set_min(0.0);
131  length     = Parameter(400.0, true);
132  length.set_min(0.0);
133  core_sld   = Parameter(1.e-6);
134  face_sld  = Parameter(4.e-6);
135  rim_sld  = Parameter(4.e-6);
136  solvent_sld= Parameter(1.e-6);
137  background = Parameter(0.0);
138  axis_theta = Parameter(90.0, true);
139  axis_phi   = Parameter(0.0, true);
140}
141
142/**
143 * Function to evaluate 1D scattering function
144 * The NIST IGOR library is used for the actual calculation.
145 * @param q: q-value
146 * @return: function value
147 */
148double CoreShellBicelleModel :: operator()(double q) {
149  double dp[10];
150
151  dp[0] = scale();
152  dp[1] = radius();
153  dp[2] = rim_thick();
154  dp[3] = face_thick();
155  dp[4] = length();
156  dp[5] = core_sld();
157  dp[6] = face_sld();
158  dp[7] = rim_sld();
159  dp[8] = solvent_sld();
160  dp[9] = 0.0;
161  double pi = 4.0*atan(1.0);
162  // Get the dispersion points for the radius
163  vector<WeightPoint> weights_rad;
164  radius.get_weights(weights_rad);
165
166  // Get the dispersion points for the thickness
167  vector<WeightPoint> weights_rthick;
168  rim_thick.get_weights(weights_rthick);
169
170  // Get the dispersion points for the thickness
171  vector<WeightPoint> weights_fthick;
172  face_thick.get_weights(weights_fthick);
173
174  // Get the dispersion points for the length
175  vector<WeightPoint> weights_len;
176  length.get_weights(weights_len);
177
178  // Perform the computation, with all weight points
179  double sum = 0.0;
180  double norm = 0.0;
181  double vol = 0.0;
182
183  // Loop over radius weight points
184  for(size_t i=0; i<weights_rad.size(); i++) {
185    dp[1] = weights_rad[i].value;
186
187    // Loop over length weight points
188    for(size_t j=0; j<weights_len.size(); j++) {
189      dp[4] = weights_len[j].value;
190
191      // Loop over thickness weight points
192      for(size_t k=0; k<weights_rthick.size(); k++) {
193        dp[2] = weights_rthick[k].value;
194        for(size_t l=0; l<weights_fthick.size(); l++) {
195            dp[3] = weights_fthick[l].value;
196                        //Un-normalize by volume
197                        sum += weights_rad[i].weight
198                                * weights_len[j].weight
199                                * weights_rthick[k].weight
200                                * weights_fthick[l].weight
201                                * BicelleIntegration(q, dp[1],dp[2], dp[3],
202                                                dp[5],dp[6],dp[7],dp[8], dp[4]);
203                        //* pow(weights_rad[i].value+weights_rthick[k].value,2)
204                        //*(weights_len[j].value+2.0*weights_fthick[k].value);
205                        //Find average volume
206                        vol += weights_rad[i].weight
207                                * weights_len[j].weight
208                                * weights_rthick[k].weight
209                                * weights_fthick[l].weight
210                                * pi * pow(weights_rad[i].value+weights_rthick[k].value,2)
211                        *(weights_len[j].value+2.0*weights_fthick[l].value);
212                        norm += weights_rad[i].weight
213                                * weights_len[j].weight
214                                * weights_rthick[k].weight
215                                * weights_fthick[l].weight;
216        }
217      }
218    }
219  }
220
221  if (vol != 0.0 && norm != 0.0) {
222    //Re-normalize by avg volume
223    sum = sum/(vol/norm);}
224  //convert to [cm-1]
225  sum *= 1.0e8;
226  return sum/norm + background();
227}
228
229/**
230 * Function to evaluate 2D scattering function
231 * @param q_x: value of Q along x
232 * @param q_y: value of Q along y
233 * @return: function value
234 */
235double CoreShellBicelleModel :: operator()(double qx, double qy) {
236  CoreShellBicelleParameters dp;
237  // Fill parameter array
238  dp.scale      = scale();
239  dp.radius     = radius();
240  dp.rim_thick  = rim_thick();
241  dp.face_thick  = face_thick();
242  dp.length     = length();
243  dp.core_sld   = core_sld();
244  dp.rim_sld  = rim_sld();
245  dp.face_sld  = face_sld();
246  dp.solvent_sld= solvent_sld();
247  dp.background = 0.0;
248  dp.axis_theta = axis_theta();
249  dp.axis_phi   = axis_phi();
250
251  // Get the dispersion points for the radius
252  vector<WeightPoint> weights_rad;
253  radius.get_weights(weights_rad);
254
255  // Get the dispersion points for the thickness
256  vector<WeightPoint> weights_rthick;
257  rim_thick.get_weights(weights_rthick);
258
259  // Get the dispersion points for the thickness
260  vector<WeightPoint> weights_fthick;
261  face_thick.get_weights(weights_fthick);
262
263  // Get the dispersion points for the length
264  vector<WeightPoint> weights_len;
265  length.get_weights(weights_len);
266
267  // Get angular averaging for theta
268  vector<WeightPoint> weights_theta;
269  axis_theta.get_weights(weights_theta);
270
271  // Get angular averaging for phi
272  vector<WeightPoint> weights_phi;
273  axis_phi.get_weights(weights_phi);
274
275  // Perform the computation, with all weight points
276  double sum = 0.0;
277  double norm = 0.0;
278  double norm_vol = 0.0;
279  double vol = 0.0;
280  double pi = 4.0*atan(1.0);
281  // Loop over radius weight points
282  for(size_t i=0; i<weights_rad.size(); i++) {
283    dp.radius = weights_rad[i].value;
284
285    // Loop over length weight points
286    for(size_t j=0; j<weights_len.size(); j++) {
287      dp.length = weights_len[j].value;
288
289      // Loop over thickness weight points
290      for(size_t m=0; m<weights_rthick.size(); m++) {
291        dp.rim_thick = weights_rthick[m].value;
292
293        // Loop over thickness weight points
294        for(size_t n=0; n<weights_fthick.size(); n++) {
295          dp.face_thick = weights_fthick[n].value;
296
297                        // Average over theta distribution
298                        for(size_t k=0; k<weights_theta.size(); k++) {
299                          dp.axis_theta = weights_theta[k].value;
300
301                          // Average over phi distribution
302                          for(size_t l=0; l<weights_phi.size(); l++) {
303                                dp.axis_phi = weights_phi[l].value;
304                                //Un-normalize by volume
305                                double _ptvalue = weights_rad[i].weight
306                                        * weights_len[j].weight
307                                        * weights_rthick[m].weight
308                                        * weights_fthick[n].weight
309                                        * weights_theta[k].weight
310                                        * weights_phi[l].weight
311                                        * core_shell_bicelle_analytical_2DXY(&dp, qx, qy)
312                                * pow(weights_rad[i].value+weights_rthick[m].value,2)
313                                *(weights_len[j].value+2.0*weights_fthick[n].value);
314
315                                if (weights_theta.size()>1) {
316                                  _ptvalue *= fabs(sin(weights_theta[k].value*pi/180.0));
317                                }
318                                sum += _ptvalue;
319
320                                //Find average volume
321                                vol += weights_rad[i].weight
322                                        * weights_len[j].weight
323                                        * weights_rthick[m].weight
324                                        * weights_fthick[n].weight
325                                        * pow(weights_rad[i].value+weights_rthick[m].value,2)
326                                *(weights_len[j].value+2.0*weights_fthick[n].value);
327                                //Find norm for volume
328                                norm_vol += weights_rad[i].weight
329                                        * weights_len[j].weight
330                                        * weights_rthick[m].weight
331                                        * weights_fthick[n].weight;
332
333                                norm += weights_rad[i].weight
334                                        * weights_len[j].weight
335                                        * weights_rthick[m].weight
336                                        * weights_fthick[n].weight
337                                        * weights_theta[k].weight
338                                        * weights_phi[l].weight;
339
340                          }
341                        }
342        }
343      }
344    }
345  }
346  // Averaging in theta needs an extra normalization
347  // factor to account for the sin(theta) term in the
348  // integration (see documentation).
349  if (weights_theta.size()>1) norm = norm / asin(1.0);
350
351  if (vol != 0.0 && norm_vol != 0.0) {
352    //Re-normalize by avg volume
353    sum = sum/(vol/norm_vol);}
354
355  return sum/norm + background();
356}
357
358/**
359 * Function to evaluate 2D scattering function
360 * @param pars: parameters of the cylinder
361 * @param q: q-value
362 * @param phi: angle phi
363 * @return: function value
364 */
365double CoreShellBicelleModel :: evaluate_rphi(double q, double phi) {
366  double qx = q*cos(phi);
367  double qy = q*sin(phi);
368  return (*this).operator()(qx, qy);
369}
370/**
371 * Function to calculate effective radius
372 * @return: effective radius value
373 */
374double CoreShellBicelleModel :: calculate_ER() {
375  CoreShellBicelleParameters dp;
376
377  dp.radius     = radius();
378  dp.rim_thick  = rim_thick();
379  dp.face_thick  = face_thick();
380  dp.length     = length();
381  double rad_out = 0.0;
382
383  // Perform the computation, with all weight points
384  double sum = 0.0;
385  double norm = 0.0;
386
387  // Get the dispersion points for the length
388  vector<WeightPoint> weights_length;
389  length.get_weights(weights_length);
390
391  // Get the dispersion points for the thickness
392  vector<WeightPoint> weights_rthick;
393  rim_thick.get_weights(weights_rthick);
394
395  // Get the dispersion points for the thickness
396  vector<WeightPoint> weights_fthick;
397  face_thick.get_weights(weights_fthick);
398
399  // Get the dispersion points for the radius
400  vector<WeightPoint> weights_radius ;
401  radius.get_weights(weights_radius);
402
403  // Loop over major shell weight points
404  for(int i=0; i< (int)weights_length.size(); i++) {
405    dp.length = weights_length[i].value;
406    for(int j=0; j< (int)weights_rthick.size(); j++) {
407      dp.rim_thick = weights_rthick[j].value;
408      for(int l=0; l< (int)weights_fthick.size(); l++) {
409          dp.face_thick = weights_fthick[l].value;
410                  for(int k=0; k< (int)weights_radius.size(); k++) {
411                        dp.radius = weights_radius[k].value;
412                        //Note: output of "DiamCyl( )" is DIAMETER.
413                        sum +=weights_length[i].weight * weights_rthick[j].weight * weights_fthick[l].weight
414                                * weights_radius[k].weight*DiamCyl(dp.length+2.0*dp.face_thick,dp.radius+dp.rim_thick)/2.0;
415                        norm += weights_length[i].weight* weights_rthick[j].weight * weights_fthick[l].weight* weights_radius[k].weight;
416                  }
417      }
418    }
419  }
420  if (norm != 0){
421    //return the averaged value
422    rad_out =  sum/norm;}
423  else{
424    //return normal value
425    //Note: output of "DiamCyl()" is DIAMETER.
426    rad_out = DiamCyl(dp.length+2.0*dp.face_thick,dp.radius+dp.rim_thick)/2.0;}
427
428  return rad_out;
429}
430double CoreShellBicelleModel :: calculate_VR() {
431  return 1.0;
432}
Note: See TracBrowser for help on using the repository browser.