source: sasview/sansmodels/src/c_models/barbell.cpp @ f425805

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 f425805 was f425805, checked in by Mathieu Doucet <doucetm@…>, 12 years ago

C refactor on BarBell?

  • Property mode set to 100644
File size: 9.9 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 "models.hh"
24#include "parameters.hh"
25#include <stdio.h>
26using namespace std;
27
28extern "C" {
29        #include "libCylinder.h"
30  #include "GaussWeights.h"
31        #include "barbell.h"
32}
33
34BarBellModel :: BarBellModel() {
35        scale      = Parameter(1.0);
36        rad_bar         = Parameter(20.0);
37        rad_bar.set_min(0.0);
38        len_bar     = Parameter(400.0, true);
39        len_bar.set_min(0.0);
40        rad_bell = Parameter(40.0);
41        rad_bell.set_min(0.0);
42        sld_barbell   = Parameter(1.0e-6);
43        sld_solv   = Parameter(6.3e-6);
44        background = Parameter(0.0);
45        theta  = Parameter(0.0, true);
46        phi    = Parameter(0.0, true);
47}
48
49double bar2d_kernel(double dp[], double q, double alpha) {
50  int j;
51  double Pi;
52  double scale,contr,bkg,sldc,slds;
53  double len,rad,hDist,endRad;
54  int nordj=76;
55  double zi=alpha,yyy,answer;     //running tally of integration
56  double summj,vaj,vbj,zij;     //for the inner integration
57  double arg1,arg2,inner,be;
58
59
60  scale = dp[0];
61  rad = dp[1];
62  len = dp[2];
63  endRad = dp[3];
64  sldc = dp[4];
65  slds = dp[5];
66  bkg = dp[6];
67
68  hDist = sqrt(fabs(endRad*endRad-rad*rad));    //by definition for this model
69
70  contr = sldc-slds;
71
72  Pi = 4.0*atan(1.0);
73  vaj = -1.0*hDist/endRad;
74  vbj = 1.0;    //endpoints of inner integral
75
76  summj=0.0;
77
78  for(j=0;j<nordj;j++) {
79    //20 gauss points for the inner integral
80    zij = ( Gauss76Z[j]*(vbj-vaj) + vaj + vbj )/2.0;    //the "t" dummy
81    yyy = Gauss76Wt[j] * Dumb_kernel(dp,q,zij,zi);    //uses the same Kernel as the Dumbbell, here L>0
82    summj += yyy;
83  }
84  //now calculate the value of the inner integral
85  inner = (vbj-vaj)/2.0*summj;
86  inner *= 4.0*Pi*endRad*endRad*endRad;
87
88  //now calculate outer integrand
89  arg1 = q*len/2.0*cos(zi);
90  arg2 = q*rad*sin(zi);
91  yyy = inner;
92
93  if(arg2 == 0) {
94    be = 0.5;
95  } else {
96    be = NR_BessJ1(arg2)/arg2;
97  }
98
99  if(arg1 == 0.0) {   //limiting value of sinc(0) is 1; sinc is not defined in math.h
100    yyy += Pi*rad*rad*len*2.0*be;
101  } else {
102    yyy += Pi*rad*rad*len*sin(arg1)/arg1*2.0*be;
103  }
104  yyy *= yyy;   //sin(zi);
105  answer = yyy;
106
107
108  answer /= Pi*rad*rad*len + 2.0*Pi*(2.0*endRad*endRad*endRad/3.0+endRad*endRad*hDist-hDist*hDist*hDist/3.0);   //divide by volume
109  answer *= 1.0e8;    //convert to cm^-1
110  answer *= contr*contr;
111  answer *= scale;
112  answer += bkg;
113
114  return answer;
115}
116/**
117 * Function to evaluate 1D scattering function
118 * The NIST IGOR library is used for the actual calculation.
119 * @param q: q-value
120 * @return: function value
121 */
122double BarBellModel :: operator()(double q) {
123        double dp[7];
124
125        // Fill parameter array for IGOR library
126        // Add the background after averaging
127        dp[0] = scale();
128        dp[1] = rad_bar();
129        dp[2] = len_bar();
130        dp[3] = rad_bell();
131        dp[4] = sld_barbell();
132        dp[5] = sld_solv();
133        dp[6] = 0.0;
134
135        // Get the dispersion points for the rad_bar
136        vector<WeightPoint> weights_rad_bar;
137        rad_bar.get_weights(weights_rad_bar);
138        // Get the dispersion points for the len_bar
139        vector<WeightPoint> weights_len_bar;
140        len_bar.get_weights(weights_len_bar);
141        // Get the dispersion points for the rad_bell
142        vector<WeightPoint> weights_rad_bell;
143        rad_bell.get_weights(weights_rad_bell);
144
145        // Perform the computation, with all weight points
146        double sum = 0.0;
147        double norm = 0.0;
148        double vol = 0.0;
149        double pi,hDist,result;
150        double vol_i = 0.0;
151        pi = 4.0*atan(1.0);
152        // Loop over radius weight points
153        for(size_t i=0; i<weights_rad_bar.size(); i++) {
154                dp[1] = weights_rad_bar[i].value;
155                for(size_t j=0; j<weights_len_bar.size(); j++) {
156                        dp[2] = weights_len_bar[j].value;
157                        for(size_t k=0; k<weights_rad_bell.size(); k++) {
158                                dp[3] = weights_rad_bell[k].value;
159
160                                //Un-normalize SphereForm by volume
161                                hDist = sqrt(fabs(dp[3]*dp[3]-dp[1]*dp[1]));
162                                vol_i = pi*dp[1]*dp[1]*dp[2]+2.0*pi*(2.0*dp[3]*dp[3]*dp[3]/3.0
163                                                                +dp[3]*dp[3]*hDist-hDist*hDist*hDist/3.0);
164                                result =  Barbell(dp, q) * vol_i;
165                                // This FIXES a singualrity the kernel in libigor.
166                                if ( result == INFINITY || result == NAN){
167                                        result = 0.0;
168                                }
169                                sum += weights_rad_bar[i].weight*weights_len_bar[j].weight*weights_rad_bell[k].weight
170                                        * result;
171                                //Find average volume
172                                vol += weights_rad_bar[i].weight*weights_len_bar[j].weight*weights_rad_bell[k].weight
173                                        * vol_i;
174
175                                norm += weights_rad_bar[i].weight*weights_len_bar[j].weight*weights_rad_bell[k].weight;
176                        }
177                }
178        }
179
180        if (vol != 0.0 && norm != 0.0) {
181                //Re-normalize by avg volume
182                sum = sum/(vol/norm);}
183        return sum/norm + background();
184}
185
186/**
187 * Function to evaluate 2D scattering function
188 * @param q_x: value of Q along x
189 * @param q_y: value of Q along y
190 * @return: function value
191 */
192double BarBellModel :: operator()(double qx, double qy) {
193  double dp[7];
194
195  // Fill parameter array for IGOR library
196  // Add the background after averaging
197  dp[0] = scale();
198  dp[1] = rad_bar();
199  dp[2] = len_bar();
200  dp[3] = rad_bell();
201  dp[4] = sld_barbell();
202  dp[5] = sld_solv();
203  dp[6] = 0.0;
204
205  double _theta = 0.0;
206  double _phi = 0.0;
207
208        // Get the dispersion points for the rad_bar
209        vector<WeightPoint> weights_rad_bar;
210        rad_bar.get_weights(weights_rad_bar);
211
212        // Get the dispersion points for the len_bar
213        vector<WeightPoint> weights_len_bar;
214        len_bar.get_weights(weights_len_bar);
215
216        // Get the dispersion points for the rad_bell
217        vector<WeightPoint> weights_rad_bell;
218        rad_bell.get_weights(weights_rad_bell);
219
220        // Get angular averaging for theta
221        vector<WeightPoint> weights_theta;
222        theta.get_weights(weights_theta);
223
224        // Get angular averaging for phi
225        vector<WeightPoint> weights_phi;
226        phi.get_weights(weights_phi);
227
228
229        // Perform the computation, with all weight points
230        double sum = 0.0;
231        double norm = 0.0;
232        double norm_vol = 0.0;
233        double vol = 0.0;
234        double pi,hDist;
235        double vol_i = 0.0;
236        pi = 4.0*atan(1.0);
237
238        // Loop over radius weight points
239        for(size_t i=0; i<weights_rad_bar.size(); i++) {
240                dp[1] = weights_rad_bar[i].value;
241                for(size_t j=0; j<weights_len_bar.size(); j++) {
242                        dp[2] = weights_len_bar[j].value;
243                        for(size_t k=0; k<weights_rad_bell.size(); k++) {
244                                dp[3] = weights_rad_bell[k].value;
245                                // Average over theta distribution
246                                for(size_t l=0; l< weights_theta.size(); l++) {
247                                        _theta = weights_theta[l].value;
248                                        // Average over phi distribution
249                                        for(size_t m=0; m< weights_phi.size(); m++) {
250                                                _phi = weights_phi[m].value;
251                                                //Un-normalize Form by volume
252                                                hDist = sqrt(fabs(dp[3]*dp[3]-dp[1]*dp[1]));
253                                                vol_i = pi*dp[1]*dp[1]*dp[2]+2.0*pi*(2.0*dp[3]*dp[3]*dp[3]/3.0
254                                                                                +dp[3]*dp[3]*hDist-hDist*hDist*hDist/3.0);
255
256                                          const double q = sqrt(qx*qx+qy*qy);
257                                          //convert angle degree to radian
258                                          const double pi = 4.0*atan(1.0);
259
260                                          // Cylinder orientation
261                                    const double cyl_x = sin(_theta * pi/180.0) * cos(_phi * pi/180.0);
262                                    const double cyl_y = sin(_theta * pi/180.0) * sin(_phi * pi/180.0);
263
264                                    // Compute the angle btw vector q and the
265                                    // axis of the cylinder (assume qz = 0)
266                                    const double cos_val = cyl_x*qx + cyl_y*qy;
267
268                                    // The following test should always pass
269                                    if (fabs(cos_val)>1.0) {
270                                      return 0;
271                                    }
272
273                                    // Note: cos(alpha) = 0 and 1 will get an
274                                    // undefined value from CylKernel
275                                    const double alpha = acos( cos_val );
276
277            // Call the IGOR library function to get the kernel
278            const double output = bar2d_kernel(dp, q, alpha)/sin(alpha);
279
280                                                double _ptvalue = weights_rad_bar[i].weight
281                                                                                        * weights_len_bar[j].weight
282                                                                                        * weights_rad_bell[k].weight
283                                                                                        * weights_theta[l].weight
284                                                                                        * weights_phi[m].weight
285                                                                                        * vol_i
286                                                                                        * output;
287                                                                                        //* pow(weights_rad[i].value,3.0);
288
289                                                // Consider when there is infinte or nan.
290                                                if ( _ptvalue == INFINITY || _ptvalue == NAN){
291                                                        _ptvalue = 0.0;
292                                                }
293                                                if (weights_theta.size()>1) {
294                                                        _ptvalue *= fabs(sin(weights_theta[l].value*pi/180.0));
295                                                }
296                                                sum += _ptvalue;
297                                                // This model dose not need the volume of spheres correction!!!
298                                                //Find average volume
299                                                vol += weights_rad_bar[i].weight
300                                                                * weights_len_bar[j].weight
301                                                                * weights_rad_bell[k].weight
302                                                                * vol_i;
303                                                //Find norm for volume
304                                                norm_vol += weights_rad_bar[i].weight
305                                                                * weights_len_bar[j].weight
306                                                                * weights_rad_bell[k].weight;
307
308                                                norm += weights_rad_bar[i].weight
309                                                                * weights_len_bar[j].weight
310                                                                * weights_rad_bell[k].weight
311                                                                * weights_theta[l].weight
312                                                                * weights_phi[m].weight;
313                                        }
314                                }
315                        }
316                }
317        }
318        // Averaging in theta needs an extra normalization
319        // factor to account for the sin(theta) term in the
320        // integration (see documentation).
321        if (weights_theta.size()>1) norm = norm / asin(1.0);
322
323        if (vol != 0.0 && norm_vol != 0.0) {
324                //Re-normalize by avg volume
325                sum = sum/(vol/norm_vol);}
326
327        return sum/norm + background();
328}
329
330/**
331 * Function to evaluate 2D scattering function
332 * @param pars: parameters of the SCCrystal
333 * @param q: q-value
334 * @param phi: angle phi
335 * @return: function value
336 */
337double BarBellModel :: evaluate_rphi(double q, double phi) {
338        return (*this).operator()(q);
339}
340
341/**
342 * Function to calculate effective radius
343 * @return: effective radius value
344 */
345double BarBellModel :: calculate_ER() {
346        //NOT implemented yet!!!
347        return 0.0;
348}
Note: See TracBrowser for help on using the repository browser.