source: sasview/sansmodels/src/c_models/pringles.cpp @ a9fec15

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 a9fec15 was a9fec15, checked in by ajj, 11 years ago

Pringles model

  • Property mode set to 100644
File size: 8.2 KB
Line 
1/**
2 * PringlesModel
3 *
4 * (c) 2013 / Andrew J Jackson / andrew.jackson@esss.se
5 *
6 * Model for "pringles" particle from K. Edler @ Bath University
7 *
8 */
9#include <math.h>
10#include "parameters.hh"
11#include "pringles.h"
12using namespace std;
13
14extern "C"
15{
16#include "GaussWeights.h"
17#include "libStructureFactor.h"
18}
19
20// Convenience parameter structure
21typedef struct {
22    double scale;
23    double radius;
24    double thickness;
25    double alpha;
26    double beta;
27    double sldCyl;
28    double sldSolv;
29    double background;
30    double cyl_theta;
31    double cyl_phi;
32} PringleParameters;
33
34
35PringlesModel::PringlesModel() {
36        scale = Parameter(1.0);
37        radius = Parameter(60.0,true);
38        radius.set_min(0.0);
39        thickness = Parameter(10.0,true);
40        thickness.set_min(0.0);
41        alpha = Parameter(0.001,true);
42        beta = Parameter(0.02,true);
43        sld_pringle = Parameter(1.0e-6);
44        sld_solvent = Parameter(6.35e-6);
45        background = Parameter(0.0);
46}
47
48/**
49 * Function to evaluate 1D scattering function
50 * @param q: q-value
51 * @return: function value
52 */
53double PringlesModel::operator()(double q) {
54        double dp[8];
55        // Fill parameter array
56        // Add the background after averaging
57        dp[0] = scale();
58        dp[1] = radius();
59        dp[2] = thickness();
60        dp[3] = alpha();
61        dp[4] = beta();
62        dp[5] = sld_pringle();
63        dp[6] = sld_solvent();
64        dp[7] = 0.0;
65
66        // Get the dispersion points for the radius
67        vector<WeightPoint> weights_rad;
68        radius.get_weights(weights_rad);
69
70        // Get the dispersion points for the thickness
71        vector<WeightPoint> weights_thick;
72        thickness.get_weights(weights_thick);
73
74        // Get the dispersion points for alpha
75        vector<WeightPoint> weights_alpha;
76        alpha.get_weights(weights_alpha);
77
78        // Get the dispersion points for beta
79        vector<WeightPoint> weights_beta;
80        beta.get_weights(weights_beta);
81
82        // Perform the computation, with all weight points
83        double sum = 0.0;
84        double norm = 0.0;
85        double volnorm = 0.0;
86        double vol = 0.0;
87        double Pi;
88
89        Pi = 4.0 * atan(1.0);
90
91        // Loop over alpha weight points
92        for (size_t i = 0; i < weights_alpha.size(); i++) {
93                dp[3] = weights_alpha[i].value;
94
95                //Loop over beta weight points
96                for (size_t j = 0; j < weights_beta.size(); j++) {
97                        dp[4] = weights_beta[j].value;
98
99                        // Loop over thickness weight points
100                        for (size_t k = 0; k < weights_thick.size(); k++) {
101                                dp[2] = weights_thick[k].value;
102
103                                // Loop over radius weight points
104                                for (size_t l = 0; l < weights_rad.size(); l++) {
105                                        dp[1] = weights_rad[l].value;
106                                        sum += weights_rad[l].weight * weights_thick[k].weight
107                                                        * weights_alpha[i].weight * weights_beta[j].weight
108                                                        * pringle_form(dp, q);
109                                        //Find average volume
110                                        vol += weights_rad[l].weight * weights_thick[k].weight * Pi * pow(weights_rad[l].value, 2) * weights_thick[k].value;
111                                        volnorm += weights_rad[l].weight * weights_thick[k].weight;
112                                        norm +=  weights_rad[l].weight * weights_thick[k].weight * weights_alpha[i].weight * weights_beta[j].weight;
113
114                                }
115                        }
116                }
117        }
118
119        if (vol > 0.0 && norm > 0.0) {
120                //normalize by avg volume
121                sum = sum * (vol/volnorm);
122                return sum/norm + background();
123        } else {
124                return 0.0;
125        }
126}
127
128/**
129 * Function to evaluate 2D scattering function
130 * @param q_x: value of Q along x
131 * @param q_y: value of Q along y
132 * @return: function value
133 */
134double PringlesModel::operator()(double qx, double qy) {
135        double q = sqrt(qx * qx + qy * qy);
136        return (*this).operator()(q);
137}
138/**
139 * Function to evaluate 2D scattering function
140 * @param pars: parameters of the model
141 * @param q: q-value
142 * @param phi: angle phi
143 * @return: function value
144 */
145double PringlesModel::evaluate_rphi(double q, double phi) {
146        return (*this).operator()(q);
147}
148
149/**
150 * Function to calculate effective radius
151 * @return: effective radius value
152 */
153double PringlesModel::calculate_ER() {
154        PringleParameters dp;
155
156        dp.radius     = radius();
157        dp.thickness  = thickness();
158        double rad_out = 0.0;
159
160        // Perform the computation, with all weight points
161        double sum = 0.0;
162        double norm = 0.0;
163
164        // Get the dispersion points for the major shell
165        vector<WeightPoint> weights_thick;
166        thickness.get_weights(weights_thick);
167
168        // Get the dispersion points for the minor shell
169        vector<WeightPoint> weights_radius ;
170        radius.get_weights(weights_radius);
171
172        // Loop over major shell weight points
173        for(int i=0; i< (int)weights_thick.size(); i++) {
174                dp.thickness = weights_thick[i].value;
175                for(int k=0; k< (int)weights_radius.size(); k++) {
176                        dp.radius = weights_radius[k].value;
177                        //Note: output of "DiamCyl(dp.thick,dp.radius)" is DIAMETER.
178                        sum +=weights_thick[i].weight
179                                * weights_radius[k].weight*DiamCyl(dp.thickness,dp.radius)/2.0;
180                        norm += weights_thick[i].weight* weights_radius[k].weight;
181                }
182        }
183        if (norm != 0){
184                //return the averaged value
185                rad_out =  sum/norm;}
186        else{
187                //return normal value
188                //Note: output of "DiamCyl(dp.length,dp.radius)" is DIAMETER.
189                rad_out = DiamCyl(dp.thickness,dp.radius)/2.0;}
190
191        return rad_out;
192}
193/**
194 * Function to calculate particle volume/total volume for shape models:
195 *    Most case returns 1 but for example for the vesicle model it is
196 *    (total volume - core volume)/total volume
197 *    (< 1 depending on the thickness).
198 * @return: effective radius value
199 */
200double PringlesModel::calculate_VR() {
201        return 1.0;
202}
203
204/*
205 * Useful work functions start here!
206 *
207 */
208
209static double pringle_form(double dp[], double q) {
210
211        double Pi;
212        int nord = 76, i=0;                     //order of integration
213        double uplim, lolim;            //upper and lower integration limits
214        double summ, phi, yyy, answer, vcyl;                    //running tally of integration
215        double delrho;
216
217        Pi = 4.0 * atan(1.0);
218        lolim = 0.0;
219        uplim = Pi / 2.0;
220
221        summ = 0.0;                     //initialize integral
222
223        delrho = dp[5] - dp[6] ; //make contrast term
224
225        for (i = 0; i < nord; i++) {
226                phi = (Gauss76Z[i] * (uplim - lolim) + uplim + lolim) / 2.0;
227                yyy = Gauss76Wt[i] * pringle_kernel(dp, q, phi);
228                summ += yyy;
229        }
230
231        answer = (uplim - lolim) / 2.0 * summ;
232
233        answer *= delrho*delrho;
234
235    //normalize by cylinder volume
236        //vcyl=Pi*dp[1]*dp[1]*dp[2];
237        //answer *= vcyl;
238
239    //convert to [cm-1]
240        answer *= 1.0e8;
241
242    //Scale by volume fraction
243        answer *= dp[0];
244
245        return answer;
246}
247
248static double pringle_kernel(double dp[], double q, double phi) {
249
250        double sumterm, sincarg, sincterm, nn, retval;
251
252        sincarg = q * dp[2] * cos(phi) / 2.0; //dp[2] = thickness
253        sincterm = pow(sin(sincarg) / sincarg, 2.0);
254
255        //calculate sum term from n = -3 to 3
256        sumterm = 0;
257        for (nn = -3; nn <= 3; nn = nn + 1) {
258                sumterm = sumterm
259                                + (pow(pringleC(dp, q, phi, nn), 2.0)
260                                                + pow(pringleS(dp, q, phi, nn), 2.0));
261        }
262
263        retval = 4.0 * sin(phi) * sumterm * sincterm;
264
265        return retval;
266
267}
268
269static double pringleC(double dp[], double q, double phi, double n) {
270
271        double nord, va, vb, summ;
272        double bessargs, cosarg, bessargcb;
273        double r, retval, yyy;
274        int ii;
275        // set up the integration
276        // end points and weights
277        nord = 76;
278        va = 0;
279        vb = dp[1]; //radius
280
281        // evaluate at Gauss points
282        // remember to index from 0,size-1
283
284        summ = 0.0;             // initialize integral
285        ii = 0;
286        do {
287                // Using 76 Gauss points
288                r = (Gauss76Z[ii] * (vb - va) + vb + va) / 2.0;
289
290                bessargs = q * r * sin(phi);
291                cosarg = q * r * r * dp[3] * cos(phi);
292                bessargcb = q * r * r * dp[4] * cos(phi);
293
294                yyy = Gauss76Wt[ii] * r * cos(cosarg) * jn(n, bessargcb)
295                                * jn(2 * n, bessargs);
296                summ += yyy;
297
298                ii += 1;
299        } while (ii < nord);                    // end of loop over quadrature points
300        //
301        // calculate value of integral to return
302
303        retval = (vb - va) / 2.0 * summ;
304
305        retval = retval / pow(r, 2.0);
306
307        return retval;
308}
309
310static double pringleS(double dp[], double q, double phi, double n) {
311
312        double nord, va, vb, summ;
313        double bessargs, sinarg, bessargcb;
314        double r, retval, yyy;
315        int ii;
316        // set up the integration
317        // end points and weights
318        nord = 76;
319        va = 0;
320        vb = dp[1]; //radius
321
322        // evaluate at Gauss points
323        // remember to index from 0,size-1
324
325        summ = 0.0;             // initialize integral
326        ii = 0;
327        do {
328                // Using 76 Gauss points
329                r = (Gauss76Z[ii] * (vb - va) + vb + va) / 2.0;
330
331                bessargs = q * r * sin(phi);
332                sinarg = q * r * r * dp[3] * cos(phi);
333                bessargcb = q * r * r * dp[4] * cos(phi);
334
335                yyy = Gauss76Wt[ii] * r * sin(sinarg) * jn(n, bessargcb)
336                                * jn(2 * n, bessargs);
337
338                summ += yyy;
339
340                ii += 1;
341        } while (ii < nord);                    // end of loop over quadrature points
342        //
343        // calculate value of integral to return
344
345        retval = (vb - va) / 2.0 * summ;
346
347        retval = retval / pow(r, 2.0);
348
349        return retval;
350}
Note: See TracBrowser for help on using the repository browser.