source: sasview/sansmodels/src/sans/models/libigor/libCylinder.c @ 07b5556d

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 07b5556d was 34c2649, checked in by Mathieu Doucet <doucetm@…>, 13 years ago

Re #4 Fixed warnings

  • Property mode set to 100644
File size: 69.0 KB
Line 
1/*      CylinderFit.c
2
3A simplified project designed to act as a template for your curve fitting function.
4The fitting function is a Cylinder form factor. No resolution effects are included (yet)
5*/
6
7#include "StandardHeaders.h"                    // Include ANSI headers, Mac headers
8#include "GaussWeights.h"
9#include "libCylinder.h"
10
11/*      CylinderForm  :  calculates the form factor of a cylinder at the give x-value p->x
12
13Warning:
14The call to WaveData() below returns a pointer to the middle
15of an unlocked Macintosh handle. In the unlikely event that your
16calculations could cause memory to move, you should copy the coefficient
17values to local variables or an array before such operations.
18*/
19double
20CylinderForm(double dp[], double q)
21{
22        int i;
23        double Pi;
24        double scale,radius,length,delrho,bkg,halfheight,sldCyl,sldSolv;                //local variables of coefficient wave
25        int nord=76;                    //order of integration
26        double uplim,lolim;             //upper and lower integration limits
27        double summ,zi,yyy,answer,vcyl;                 //running tally of integration
28       
29        Pi = 4.0*atan(1.0);
30        lolim = 0.0;
31        uplim = Pi/2.0;
32       
33        summ = 0.0;                     //initialize intergral
34       
35        scale = dp[0];                  //make local copies in case memory moves
36        radius = dp[1];
37        length = dp[2];
38        sldCyl = dp[3];
39        sldSolv = dp[4];
40        bkg = dp[5];
41       
42        delrho = sldCyl-sldSolv;
43        halfheight = length/2.0;
44        for(i=0;i<nord;i++) {
45                zi = ( Gauss76Z[i]*(uplim-lolim) + uplim + lolim )/2.0;
46                yyy = Gauss76Wt[i] * CylKernel(q, radius, halfheight, zi);
47                summ += yyy;
48        }
49       
50        answer = (uplim-lolim)/2.0*summ;
51        // Multiply by contrast^2
52        answer *= delrho*delrho;
53        //normalize by cylinder volume
54        //NOTE that for this (Fournet) definition of the integral, one must MULTIPLY by Vcyl
55        vcyl=Pi*radius*radius*length;
56        answer *= vcyl;
57        //convert to [cm-1]
58        answer *= 1.0e8;
59        //Scale
60        answer *= scale;
61        // add in the background
62        answer += bkg;
63       
64        return answer;
65}
66
67/*      EllipCyl76X  :  calculates the form factor of a elliptical cylinder at the given x-value p->x
68
69Uses 76 pt Gaussian quadrature for both integrals
70
71Warning:
72The call to WaveData() below returns a pointer to the middle
73of an unlocked Macintosh handle. In the unlikely event that your
74calculations could cause memory to move, you should copy the coefficient
75values to local variables or an array before such operations.
76*/
77double
78EllipCyl76(double dp[], double q)
79{
80        int i,j;
81        double Pi,slde,sld;
82        double scale,ra,nu,length,delrho,bkg;           //local variables of coefficient wave
83        int nord=76;                    //order of integration
84        double va,vb;           //upper and lower integration limits
85        double summ,zi,yyy,answer,vell;                 //running tally of integration
86        double summj,vaj,vbj,zij,arg, si;                       //for the inner integration
87
88        Pi = 4.0*atan(1.0);
89        va = 0.0;
90        vb = 1.0;               //orintational average, outer integral
91        vaj=0.0;
92        vbj=Pi;         //endpoints of inner integral
93       
94        summ = 0.0;                     //initialize intergral
95       
96        scale = dp[0];                  //make local copies in case memory moves
97        ra = dp[1];
98        nu = dp[2];
99        length = dp[3];
100        slde = dp[4];
101        sld = dp[5];
102        delrho = slde - sld;
103        bkg = dp[6];
104       
105        for(i=0;i<nord;i++) {
106                //setup inner integral over the ellipsoidal cross-section
107                summj=0;
108                zi = ( Gauss76Z[i]*(vb-va) + va + vb )/2.0;             //the "x" dummy
109                arg = ra*sqrt(1.0-zi*zi);
110                for(j=0;j<nord;j++) {
111                        //76 gauss points for the inner integral as well
112                        zij = ( Gauss76Z[j]*(vbj-vaj) + vaj + vbj )/2.0;                //the "y" dummy
113                        yyy = Gauss76Wt[j] * EllipCylKernel(q,arg,nu,zij);
114                        summj += yyy;
115                }
116                //now calculate the value of the inner integral
117                answer = (vbj-vaj)/2.0*summj;
118                //divide integral by Pi
119                answer /=Pi;
120               
121                //now calculate outer integral
122                arg = q*length*zi/2.0;
123                if (arg == 0.0){
124                        si = 1.0;
125                }else{
126                        si = sin(arg) * sin(arg) / arg / arg;
127                }
128                yyy = Gauss76Wt[i] * answer * si;
129                summ += yyy;
130        }
131        answer = (vb-va)/2.0*summ;
132        // Multiply by contrast^2
133        answer *= delrho*delrho;
134        //normalize by cylinder volume
135        //NOTE that for this (Fournet) definition of the integral, one must MULTIPLY by Vcyl
136        vell = Pi*ra*(nu*ra)*length;
137        answer *= vell;
138        //convert to [cm-1]
139        answer *= 1.0e8;
140        //Scale
141        answer *= scale;
142        // add in the background
143        answer += bkg;
144       
145        return answer;
146}
147
148/*      EllipCyl20X  :  calculates the form factor of a elliptical cylinder at the given x-value p->x
149
150Uses 76 pt Gaussian quadrature for orientational integral
151Uses 20 pt quadrature for the inner integral over the elliptical cross-section
152
153Warning:
154The call to WaveData() below returns a pointer to the middle
155of an unlocked Macintosh handle. In the unlikely event that your
156calculations could cause memory to move, you should copy the coefficient
157values to local variables or an array before such operations.
158*/
159double
160EllipCyl20(double dp[], double q)
161{
162        int i,j;
163        double Pi,slde,sld;
164        double scale,ra,nu,length,delrho,bkg;           //local variables of coefficient wave
165        int nordi=76;                   //order of integration
166        int nordj=20;
167        double va,vb;           //upper and lower integration limits
168        double summ,zi,yyy,answer,vell;                 //running tally of integration
169        double summj,vaj,vbj,zij,arg,si;                        //for the inner integration
170
171        Pi = 4.0*atan(1.0);
172        va = 0.0;
173        vb = 1.0;               //orintational average, outer integral
174        vaj=0.0;
175        vbj=Pi;         //endpoints of inner integral
176       
177        summ = 0.0;                     //initialize intergral
178       
179        scale = dp[0];                  //make local copies in case memory moves
180        ra = dp[1];
181        nu = dp[2];
182        length = dp[3];
183        slde = dp[4];
184        sld = dp[5];
185        delrho = slde - sld;
186        bkg = dp[6];
187       
188        for(i=0;i<nordi;i++) {
189                //setup inner integral over the ellipsoidal cross-section
190                summj=0;
191                zi = ( Gauss76Z[i]*(vb-va) + va + vb )/2.0;             //the "x" dummy
192                arg = ra*sqrt(1.0-zi*zi);
193                for(j=0;j<nordj;j++) {
194                        //20 gauss points for the inner integral
195                        zij = ( Gauss20Z[j]*(vbj-vaj) + vaj + vbj )/2.0;                //the "y" dummy
196                        yyy = Gauss20Wt[j] * EllipCylKernel(q,arg,nu,zij);
197                        summj += yyy;
198                }
199                //now calculate the value of the inner integral
200                answer = (vbj-vaj)/2.0*summj;
201                //divide integral by Pi
202                answer /=Pi;
203               
204                //now calculate outer integral
205                arg = q*length*zi/2.0;
206                if (arg == 0.0){
207                        si = 1.0;
208                }else{
209                        si = sin(arg) * sin(arg) / arg / arg;
210                }
211                yyy = Gauss76Wt[i] * answer * si;
212                summ += yyy;
213        }
214       
215        answer = (vb-va)/2.0*summ;
216        // Multiply by contrast^2
217        answer *= delrho*delrho;
218        //normalize by cylinder volume
219        //NOTE that for this (Fournet) definition of the integral, one must MULTIPLY by Vcyl
220        vell = Pi*ra*(nu*ra)*length;
221        answer *= vell;
222        //convert to [cm-1]
223        answer *= 1.0e8;
224        //Scale
225        answer *= scale;
226        // add in the background
227        answer += bkg;
228
229        return answer;
230}
231
232/*      TriaxialEllipsoidX  :  calculates the form factor of a Triaxial Ellipsoid at the given x-value p->x
233
234Uses 76 pt Gaussian quadrature for both integrals
235
236Warning:
237The call to WaveData() below returns a pointer to the middle
238of an unlocked Macintosh handle. In the unlikely event that your
239calculations could cause memory to move, you should copy the coefficient
240values to local variables or an array before such operations.
241*/
242double
243TriaxialEllipsoid(double dp[], double q)
244{
245        int i,j;
246        double Pi;
247        double scale,aa,bb,cc,delrho,bkg;               //local variables of coefficient wave
248        int nordi=76;                   //order of integration
249        int nordj=76;
250        double va,vb;           //upper and lower integration limits
251        double summ,zi,yyy,answer;                      //running tally of integration
252        double summj,vaj,vbj,zij,slde,sld;                      //for the inner integration
253       
254        Pi = 4.0*atan(1.0);
255        va = 0.0;
256        vb = 1.0;               //orintational average, outer integral
257        vaj = 0.0;
258        vbj = 1.0;              //endpoints of inner integral
259       
260        summ = 0.0;                     //initialize intergral
261       
262        scale = dp[0];                  //make local copies in case memory moves
263        aa = dp[1];
264        bb = dp[2];
265        cc = dp[3];
266        slde = dp[4];
267        sld = dp[5];
268        delrho = slde - sld;
269        bkg = dp[6];
270        for(i=0;i<nordi;i++) {
271                //setup inner integral over the ellipsoidal cross-section
272                summj=0.0;
273                zi = ( Gauss76Z[i]*(vb-va) + va + vb )/2.0;             //the "x" dummy
274                for(j=0;j<nordj;j++) {
275                        //20 gauss points for the inner integral
276                        zij = ( Gauss76Z[j]*(vbj-vaj) + vaj + vbj )/2.0;                //the "y" dummy
277                        yyy = Gauss76Wt[j] * TriaxialKernel(q,aa,bb,cc,zi,zij);
278                        summj += yyy;
279                }
280                //now calculate the value of the inner integral
281                answer = (vbj-vaj)/2.0*summj;
282               
283                //now calculate outer integral
284                yyy = Gauss76Wt[i] * answer;
285                summ += yyy;
286        }               //final scaling is done at the end of the function, after the NT_FP64 case
287       
288        answer = (vb-va)/2.0*summ;
289        // Multiply by contrast^2
290        answer *= delrho*delrho;
291        //normalize by ellipsoid volume
292        answer *= 4.0*Pi/3.0*aa*bb*cc;
293        //convert to [cm-1]
294        answer *= 1.0e8;
295        //Scale
296        answer *= scale;
297        // add in the background
298        answer += bkg;
299       
300        return answer;
301}
302
303/*      ParallelepipedX  :  calculates the form factor of a Parallelepiped (a rectangular solid)
304at the given x-value p->x
305
306Uses 76 pt Gaussian quadrature for both integrals
307
308Warning:
309The call to WaveData() below returns a pointer to the middle
310of an unlocked Macintosh handle. In the unlikely event that your
311calculations could cause memory to move, you should copy the coefficient
312values to local variables or an array before such operations.
313*/
314double
315Parallelepiped(double dp[], double q)
316{
317        int i,j;
318        double scale,aa,bb,cc,delrho,bkg;               //local variables of coefficient wave
319        int nordi=76;                   //order of integration
320        int nordj=76;
321        double va,vb;           //upper and lower integration limits
322        double summ,yyy,answer;                 //running tally of integration
323        double summj,vaj,vbj;                   //for the inner integration
324        double mu,mudum,arg,sigma,uu,vol,sldp,sld;
325       
326       
327        //      Pi = 4.0*atan(1.0);
328        va = 0.0;
329        vb = 1.0;               //orintational average, outer integral
330        vaj = 0.0;
331        vbj = 1.0;              //endpoints of inner integral
332
333        summ = 0.0;                     //initialize intergral
334       
335        scale = dp[0];                  //make local copies in case memory moves
336        aa = dp[1];
337        bb = dp[2];
338        cc = dp[3];
339        sldp = dp[4];
340        sld = dp[5];
341        delrho = sldp - sld;
342        bkg = dp[6];
343       
344        mu = q*bb;
345        vol = aa*bb*cc;
346        // normalize all WRT bb
347        aa = aa/bb;
348        cc = cc/bb;
349       
350        for(i=0;i<nordi;i++) {
351                //setup inner integral over the ellipsoidal cross-section
352                summj=0.0;
353                sigma = ( Gauss76Z[i]*(vb-va) + va + vb )/2.0;          //the outer dummy
354               
355                for(j=0;j<nordj;j++) {
356                        //76 gauss points for the inner integral
357                        uu = ( Gauss76Z[j]*(vbj-vaj) + vaj + vbj )/2.0;         //the inner dummy
358                        mudum = mu*sqrt(1.0-sigma*sigma);
359                        yyy = Gauss76Wt[j] * PPKernel(aa,mudum,uu);
360                        summj += yyy;
361                }
362                //now calculate the value of the inner integral
363                answer = (vbj-vaj)/2.0*summj;
364
365                arg = mu*cc*sigma/2.0;
366                if ( arg == 0.0 ) {
367                        answer *= 1.0;
368                } else {
369                        answer *= sin(arg)*sin(arg)/arg/arg;
370                }
371               
372                //now sum up the outer integral
373                yyy = Gauss76Wt[i] * answer;
374                summ += yyy;
375        }               //final scaling is done at the end of the function, after the NT_FP64 case
376       
377        answer = (vb-va)/2.0*summ;
378        // Multiply by contrast^2
379        answer *= delrho*delrho;
380        //normalize by volume
381        answer *= vol;
382        //convert to [cm-1]
383        answer *= 1.0e8;
384        //Scale
385        answer *= scale;
386        // add in the background
387        answer += bkg;
388       
389        return answer;
390}
391
392/*      HollowCylinderX  :  calculates the form factor of a Hollow Cylinder
393at the given x-value p->x
394
395Uses 76 pt Gaussian quadrature for the single integral
396
397Warning:
398The call to WaveData() below returns a pointer to the middle
399of an unlocked Macintosh handle. In the unlikely event that your
400calculations could cause memory to move, you should copy the coefficient
401values to local variables or an array before such operations.
402*/
403double
404HollowCylinder(double dp[], double q)
405{
406        int i;
407        double scale,rcore,rshell,length,delrho,bkg;            //local variables of coefficient wave
408        int nord=76;                    //order of integration
409        double va,vb,zi;                //upper and lower integration limits
410        double summ,answer,pi,sldc,sld;                 //running tally of integration
411       
412        pi = 4.0*atan(1.0);
413        va = 0.0;
414        vb = 1.0;               //limits of numerical integral
415
416        summ = 0.0;                     //initialize intergral
417       
418        scale = dp[0];          //make local copies in case memory moves
419        rcore = dp[1];
420        rshell = dp[2];
421        length = dp[3];
422        sldc = dp[4];
423        sld = dp[5];
424        delrho = sldc - sld;
425        bkg = dp[6];
426       
427        for(i=0;i<nord;i++) {
428                zi = ( Gauss76Z[i]*(vb-va) + va + vb )/2.0;
429                summ += Gauss76Wt[i] * HolCylKernel(q, rcore, rshell, length, zi);
430        }
431       
432        answer = (vb-va)/2.0*summ;
433        // Multiply by contrast^2
434        answer *= delrho*delrho;
435        //normalize by volume
436        answer *= pi*(rshell*rshell-rcore*rcore)*length;
437        //convert to [cm-1]
438        answer *= 1.0e8;
439        //Scale
440        answer *= scale;
441        // add in the background
442        answer += bkg;
443       
444        return answer;
445}
446
447/*      EllipsoidFormX  :  calculates the form factor of an ellipsoid of revolution with semiaxes a:a:nua
448at the given x-value p->x
449
450Uses 76 pt Gaussian quadrature for the single integral
451
452Warning:
453The call to WaveData() below returns a pointer to the middle
454of an unlocked Macintosh handle. In the unlikely event that your
455calculations could cause memory to move, you should copy the coefficient
456values to local variables or an array before such operations.
457*/
458double
459EllipsoidForm(double dp[], double q)
460{
461        int i;
462        double scale,a,nua,delrho,bkg;          //local variables of coefficient wave
463        int nord=76;                    //order of integration
464        double va,vb,zi;                //upper and lower integration limits
465        double summ,answer,pi,slde,sld;                 //running tally of integration
466       
467        pi = 4.0*atan(1.0);
468        va = 0.0;
469        vb = 1.0;               //limits of numerical integral
470
471        summ = 0.0;                     //initialize intergral
472       
473        scale = dp[0];                  //make local copies in case memory moves
474        nua = dp[1];
475        a = dp[2];
476        slde = dp[3];
477        sld = dp[4];
478        delrho = slde - sld;
479        bkg = dp[5];
480       
481        for(i=0;i<nord;i++) {
482                zi = ( Gauss76Z[i]*(vb-va) + va + vb )/2.0;
483                summ += Gauss76Wt[i] * EllipsoidKernel(q, a, nua, zi);
484        }
485       
486        answer = (vb-va)/2.0*summ;
487        // Multiply by contrast^2
488        answer *= delrho*delrho;
489        //normalize by volume
490        answer *= 4.0*pi/3.0*a*a*nua;
491        //convert to [cm-1]
492        answer *= 1.0e8;
493        //Scale
494        answer *= scale;
495        // add in the background
496        answer += bkg;
497       
498        return answer;
499}
500
501
502/*      Cyl_PolyRadiusX  :  calculates the form factor of a cylinder at the given x-value p->x
503the cylinder has a polydisperse cross section
504
505*/
506double
507Cyl_PolyRadius(double dp[], double q)
508{
509        int i;
510        double scale,radius,length,pd,delrho,bkg;               //local variables of coefficient wave
511        int nord=20;                    //order of integration
512        double uplim,lolim;             //upper and lower integration limits
513        double summ,zi,yyy,answer,Vpoly;                        //running tally of integration
514        double range,zz,Pi,sldc,sld;
515       
516        Pi = 4.0*atan(1.0);
517        range = 3.4;
518       
519        summ = 0.0;                     //initialize intergral
520       
521        scale = dp[0];                  //make local copies in case memory moves
522        radius = dp[1];
523        length = dp[2];
524        pd = dp[3];
525        sldc = dp[4];
526        sld = dp[5];
527        delrho = sldc - sld;
528        bkg = dp[6];
529       
530        zz = (1.0/pd)*(1.0/pd) - 1.0;
531       
532        lolim = radius*(1.0-range*pd);          //set the upper/lower limits to cover the distribution
533        if(lolim<0.0) {
534                lolim = 0.0;
535        }
536        if(pd>0.3) {
537                range = 3.4 + (pd-0.3)*18.0;
538        }
539        uplim = radius*(1.0+range*pd);
540       
541        for(i=0;i<nord;i++) {
542                zi = ( Gauss20Z[i]*(uplim-lolim) + uplim + lolim )/2.0;
543                yyy = Gauss20Wt[i] * Cyl_PolyRadKernel(q, radius, length, zz, delrho, zi);
544                summ += yyy;
545        }
546       
547        answer = (uplim-lolim)/2.0*summ;
548        //normalize by average cylinder volume
549        //NOTE that for this (Fournet) definition of the integral, one must MULTIPLY by Vcyl
550        Vpoly=Pi*radius*radius*length*(zz+2.0)/(zz+1.0);
551        answer /= Vpoly;
552        //convert to [cm-1]
553        answer *= 1.0e8;
554        //Scale
555        answer *= scale;
556        // add in the background
557        answer += bkg;
558       
559        return answer;
560}
561
562/*      Cyl_PolyLengthX  :  calculates the form factor of a cylinder at the given x-value p->x
563the cylinder has a polydisperse Length
564
565*/
566double
567Cyl_PolyLength(double dp[], double q)
568{
569        int i;
570        double scale,radius,length,pd,delrho,bkg;               //local variables of coefficient wave
571        int nord=20;                    //order of integration
572        double uplim,lolim;             //upper and lower integration limits
573        double summ,zi,yyy,answer,Vpoly;                        //running tally of integration
574        double range,zz,Pi,sldc,sld;
575       
576       
577        Pi = 4.0*atan(1.0);
578        range = 3.4;
579       
580        summ = 0.0;                     //initialize intergral
581       
582        scale = dp[0];                  //make local copies in case memory moves
583        radius = dp[1];
584        length = dp[2];
585        pd = dp[3];
586        sldc = dp[4];
587        sld = dp[5];
588        delrho = sldc - sld;
589        bkg = dp[6];
590       
591        zz = (1.0/pd)*(1.0/pd) - 1.0;
592       
593        lolim = length*(1.0-range*pd);          //set the upper/lower limits to cover the distribution
594        if(lolim<0.0) {
595                lolim = 0.0;
596        }
597        if(pd>0.3) {
598                range = 3.4 + (pd-0.3)*18.0;
599        }
600        uplim = length*(1.0+range*pd);
601       
602        for(i=0;i<nord;i++) {
603                zi = ( Gauss20Z[i]*(uplim-lolim) + uplim + lolim )/2.0;
604                yyy = Gauss20Wt[i] * Cyl_PolyLenKernel(q, radius, length, zz, delrho, zi);
605                summ += yyy;
606        }
607       
608        answer = (uplim-lolim)/2.0*summ;
609        //normalize by average cylinder volume (first moment)
610        //NOTE that for this (Fournet) definition of the integral, one must MULTIPLY by Vcyl
611        Vpoly=Pi*radius*radius*length;
612        answer /= Vpoly;
613        //convert to [cm-1]
614        answer *= 1.0e8;
615        //Scale
616        answer *= scale;
617        // add in the background
618        answer += bkg;
619       
620        return answer;
621}
622
623/*      CoreShellCylinderX  :  calculates the form factor of a cylinder at the given x-value p->x
624the cylinder has a core-shell structure
625
626*/
627double
628CoreShellCylinder(double dp[], double q)
629{
630        int i;
631        double scale,rcore,length,bkg;          //local variables of coefficient wave
632        double thick,rhoc,rhos,rhosolv;
633        int nord=76;                    //order of integration
634        double uplim,lolim,halfheight;          //upper and lower integration limits
635        double summ,zi,yyy,answer,Vcyl;                 //running tally of integration
636        double Pi;
637       
638        Pi = 4.0*atan(1.0);
639       
640        lolim = 0.0;
641        uplim = Pi/2.0;
642       
643        summ = 0.0;                     //initialize intergral
644       
645        scale = dp[0];          //make local copies in case memory moves
646        rcore = dp[1];
647        thick = dp[2];
648        length = dp[3];
649        rhoc = dp[4];
650        rhos = dp[5];
651        rhosolv = dp[6];
652        bkg = dp[7];
653       
654        halfheight = length/2.0;
655       
656        for(i=0;i<nord;i++) {
657                zi = ( Gauss76Z[i]*(uplim-lolim) + uplim + lolim )/2.0;
658                yyy = Gauss76Wt[i] * CoreShellCylKernel(q, rcore, thick, rhoc,rhos,rhosolv, halfheight, zi);
659                summ += yyy;
660        }
661       
662        answer = (uplim-lolim)/2.0*summ;
663        // length is the total core length
664        Vcyl=Pi*(rcore+thick)*(rcore+thick)*(length+2.0*thick);
665        answer /= Vcyl;
666        //convert to [cm-1]
667        answer *= 1.0e8;
668        //Scale
669        answer *= scale;
670        // add in the background
671        answer += bkg;
672       
673        return answer;
674}
675
676
677/*      PolyCoShCylinderX  :  calculates the form factor of a core-shell cylinder at the given x-value p->x
678the cylinder has a polydisperse CORE radius
679
680*/
681double
682PolyCoShCylinder(double dp[], double q)
683{
684        int i;
685        double scale,radius,length,sigma,bkg;           //local variables of coefficient wave
686        double rad,radthick,facthick,rhoc,rhos,rhosolv;
687        int nord=20;                    //order of integration
688        double uplim,lolim;             //upper and lower integration limits
689        double summ,yyy,answer,Vpoly;                   //running tally of integration
690        double Pi,AR,Rsqrsumm,Rsqryyy,Rsqr;
691               
692        Pi = 4.0*atan(1.0);
693       
694        summ = 0.0;                     //initialize intergral
695        Rsqrsumm = 0.0;
696       
697        scale = dp[0];
698        radius = dp[1];
699        sigma = dp[2];                          //sigma is the standard mean deviation
700        length = dp[3];
701        radthick = dp[4];
702        facthick= dp[5];
703        rhoc = dp[6];
704        rhos = dp[7];
705        rhosolv = dp[8];
706        bkg = dp[9];
707       
708        lolim = exp(log(radius)-(4.*sigma));
709        if (lolim<0.0) {
710                lolim=0.0;              //to avoid numerical error when  va<0 (-ve r value)
711        }
712        uplim = exp(log(radius)+(4.*sigma));
713       
714        for(i=0;i<nord;i++) {
715                rad = ( Gauss20Z[i]*(uplim-lolim) + uplim + lolim )/2.0;
716                AR=(1.0/(rad*sigma*sqrt(2.0*Pi)))*exp(-(0.5*((log(radius/rad))/sigma)*((log(radius/rad))/sigma)));
717                yyy = AR* Gauss20Wt[i] * CSCylIntegration(q,rad,radthick,facthick,rhoc,rhos,rhosolv,length);
718                Rsqryyy= Gauss20Wt[i] * AR * (rad+radthick)*(rad+radthick);             //SRK normalize to total dimensions
719                summ += yyy;
720                Rsqrsumm += Rsqryyy;
721        }
722       
723        answer = (uplim-lolim)/2.0*summ;
724        Rsqr = (uplim-lolim)/2.0*Rsqrsumm;
725        //normalize by average cylinder volume
726        Vpoly = Pi*Rsqr*(length+2*facthick);
727        answer /= Vpoly;
728        //convert to [cm-1]
729        answer *= 1.0e8;
730        //Scale
731        answer *= scale;
732        // add in the background
733        answer += bkg;
734       
735        return answer;
736}
737
738/*      OblateFormX  :  calculates the form factor of a core-shell Oblate ellipsoid at the given x-value p->x
739the ellipsoid has a core-shell structure
740
741*/
742double
743OblateForm(double dp[], double q)
744{
745        int i;
746        double scale,crmaj,crmin,trmaj,trmin,delpc,delps,bkg;
747        int nord=76;                    //order of integration
748        double uplim,lolim;             //upper and lower integration limits
749        double summ,zi,yyy,answer,oblatevol;                    //running tally of integration
750        double Pi,sldc,slds,sld;
751       
752        Pi = 4.0*atan(1.0);
753       
754        lolim = 0.0;
755        uplim = 1.0;
756       
757        summ = 0.0;                     //initialize intergral
758       
759       
760        scale = dp[0];          //make local copies in case memory moves
761        crmaj = dp[1];
762        crmin = dp[2];
763        trmaj = dp[3];
764        trmin = dp[4];
765        sldc = dp[5];
766        slds = dp[6];
767        sld = dp[7];
768        delpc = sldc - slds;    //core - shell
769        delps = slds - sld;             //shell - solvent
770        bkg = dp[8];
771
772        for(i=0;i<nord;i++) {
773                zi = ( Gauss76Z[i]*(uplim-lolim) + uplim + lolim )/2.0;
774                yyy = Gauss76Wt[i] * gfn4(zi,crmaj,crmin,trmaj,trmin,delpc,delps,q);
775                summ += yyy;
776        }
777       
778        answer = (uplim-lolim)/2.0*summ;
779        // normalize by particle volume
780        oblatevol = 4.0*Pi/3.0*trmaj*trmaj*trmin;
781        answer /= oblatevol;
782       
783        //convert to [cm-1]
784        answer *= 1.0e8;
785        //Scale
786        answer *= scale;
787        // add in the background
788        answer += bkg;
789       
790        return answer;
791}
792
793/*      ProlateFormX  :  calculates the form factor of a core-shell Prolate ellipsoid at the given x-value p->x
794the ellipsoid has a core-shell structure
795
796*/
797double
798ProlateForm(double dp[], double q)
799{
800        int i;
801        double scale,crmaj,crmin,trmaj,trmin,delpc,delps,bkg;
802        int nord=76;                    //order of integration
803        double uplim,lolim;             //upper and lower integration limits
804        double summ,zi,yyy,answer,prolatevol;                   //running tally of integration
805        double Pi,sldc,slds,sld;
806       
807        Pi = 4.0*atan(1.0);
808       
809        lolim = 0.0;
810        uplim = 1.0;
811       
812        summ = 0.0;                     //initialize intergral
813       
814        scale = dp[0];          //make local copies in case memory moves
815        crmaj = dp[1];
816        crmin = dp[2];
817        trmaj = dp[3];
818        trmin = dp[4];
819        sldc = dp[5];
820        slds = dp[6];
821        sld = dp[7];
822        delpc = sldc - slds;            //core - shell
823        delps = slds - sld;             //shell  - sovent
824        bkg = dp[8];
825
826        for(i=0;i<nord;i++) {
827                zi = ( Gauss76Z[i]*(uplim-lolim) + uplim + lolim )/2.0;
828                yyy = Gauss76Wt[i] * gfn2(zi,crmaj,crmin,trmaj,trmin,delpc,delps,q);
829                summ += yyy;
830        }
831       
832        answer = (uplim-lolim)/2.0*summ;
833        // normalize by particle volume
834        prolatevol = 4.0*Pi/3.0*trmaj*trmin*trmin;
835        answer /= prolatevol;
836       
837        //convert to [cm-1]
838        answer *= 1.0e8;
839        //Scale
840        answer *= scale;
841        // add in the background
842        answer += bkg;
843       
844        return answer;
845}
846
847
848/*      StackedDiscsX  :  calculates the form factor of a stacked "tactoid" of core shell disks
849like clay platelets that are not exfoliated
850
851*/
852double
853StackedDiscs(double dp[], double q)
854{
855        int i;
856        double scale,length,bkg,rcore,thick,rhoc,rhol,rhosolv,N,gsd;            //local variables of coefficient wave
857        double va,vb,vcyl,summ,yyy,zi,halfheight,d,answer;
858        int nord=76;                    //order of integration
859        double Pi;
860       
861       
862        Pi = 4.0*atan(1.0);
863       
864        va = 0.0;
865        vb = Pi/2.0;
866       
867        summ = 0.0;                     //initialize intergral
868       
869        scale = dp[0];
870        rcore = dp[1];
871        length = dp[2];
872        thick = dp[3];
873        rhoc = dp[4];
874        rhol = dp[5];
875        rhosolv = dp[6];
876        N = dp[7];
877        gsd = dp[8];
878        bkg = dp[9];
879       
880        d=2.0*thick+length;
881        halfheight = length/2.0;
882       
883        for(i=0;i<nord;i++) {
884                zi = ( Gauss76Z[i]*(vb-va) + vb + va )/2.0;
885                yyy = Gauss76Wt[i] * Stackdisc_kern(q, rcore, rhoc,rhol,rhosolv, halfheight,thick,zi,gsd,d,N);
886                summ += yyy;
887        }
888       
889        answer = (vb-va)/2.0*summ;
890        // length is the total core length
891        vcyl=Pi*rcore*rcore*(2.0*thick+length)*N;
892        answer /= vcyl;
893        //Convert to [cm-1]
894        answer *= 1.0e8;
895        //Scale
896        answer *= scale;
897        // add in the background
898        answer += bkg;
899       
900        return answer;
901}
902
903
904/*      LamellarFFX  :  calculates the form factor of a lamellar structure - no S(q) effects included
905
906*/
907double
908LamellarFF(double dp[], double q)
909{
910        double scale,del,sig,contr,bkg;         //local variables of coefficient wave
911        double inten, qval,Pq;
912        double Pi,sldb,sld;
913       
914       
915        Pi = 4.0*atan(1.0);
916        scale = dp[0];
917        del = dp[1];
918        sig = dp[2]*del;
919        sldb = dp[3];
920        sld = dp[4];
921        contr = sldb - sld;
922        bkg = dp[5];
923        qval=q;
924       
925        Pq = 2.0*contr*contr/qval/qval*(1.0-cos(qval*del)*exp(-0.5*qval*qval*sig*sig));
926       
927        inten = 2.0*Pi*scale*Pq/(qval*qval);            //this is now dimensionless...
928       
929        inten /= del;                   //normalize by the thickness (in A)
930       
931        inten *= 1.0e8;         // 1/A to 1/cm
932       
933        return(inten+bkg);
934}
935
936/*      LamellarPSX  :  calculates the form factor of a lamellar structure - with S(q) effects included
937--- now the proper resolution effects are used - the "default" resolution is turned off (= 0) and the
938model is smeared just like any other function
939*/
940double
941LamellarPS(double dp[], double q)
942{
943        double scale,dd,del,sig,contr,NN,Cp,bkg;                //local variables of coefficient wave
944        double inten,qval,Pq,Sq,alpha,temp,t1,t2,t3,dQ;
945        double Pi,Euler,dQDefault,fii,sldb,sld;
946        int ii,NNint;
947//      char buf[256];
948
949       
950        Euler = 0.5772156649;           // Euler's constant
951//      dQDefault = 0.0025;             //[=] 1/A, q-resolution, default value
952        dQDefault = 0.0;
953        dQ = dQDefault;
954       
955        Pi = 4.0*atan(1.0);
956        qval = q;
957       
958        scale = dp[0];
959        dd = dp[1];
960        del = dp[2];
961        sig = dp[3]*del;
962        sldb = dp[4];
963        sld = dp[5];
964        contr = sldb - sld;
965        NN = trunc(dp[6]);              //be sure that NN is an integer
966        Cp = dp[7];
967        bkg = dp[8];
968       
969        Pq = 2.0*contr*contr/qval/qval*(1.0-cos(qval*del)*exp(-0.5*qval*qval*sig*sig));
970       
971        NNint = (int)NN;                //cast to an integer for the loop
972       
973//      sprintf(buf, "qval = %g\r", qval);
974//      XOPNotice(buf);
975       
976        ii=0;
977        Sq = 0.0;
978        for(ii=1;ii<(NNint-1);ii+=1) {
979       
980                fii = (double)ii;               //do I really need to do this?
981               
982                temp = 0.0;
983                alpha = Cp/4.0/Pi/Pi*(log(Pi*fii) + Euler);
984                t1 = 2.0*dQ*dQ*dd*dd*alpha;
985                t2 = 2.0*qval*qval*dd*dd*alpha;
986                t3 = dQ*dQ*dd*dd*fii*fii;
987               
988                temp = 1.0-fii/NN;
989                temp *= cos(dd*qval*fii/(1.0+t1));
990                temp *= exp(-1.0*(t2 + t3)/(2.0*(1.0+t1)) );
991                temp /= sqrt(1.0+t1);
992               
993                Sq += temp;
994        }
995       
996        Sq *= 2.0;
997        Sq += 1.0;
998       
999        inten = 2.0*Pi*scale*Pq*Sq/(dd*qval*qval);
1000       
1001        inten *= 1.0e8;         // 1/A to 1/cm
1002       
1003    return(inten+bkg);
1004}
1005
1006
1007/*      LamellarPS_HGX  :  calculates the form factor of a lamellar structure - with S(q) effects included
1008--- now the proper resolution effects are used - the "default" resolution is turned off (= 0) and the
1009model is smeared just like any other function
1010*/
1011double
1012LamellarPS_HG(double dp[], double q)
1013{
1014        double scale,dd,delT,delH,SLD_T,SLD_H,SLD_S,NN,Cp,bkg;          //local variables of coefficient wave
1015        double inten,qval,Pq,Sq,alpha,temp,t1,t2,t3,dQ,drh,drt;
1016        double Pi,Euler,dQDefault,fii;
1017        int ii,NNint;
1018       
1019       
1020        Euler = 0.5772156649;           // Euler's constant
1021//      dQDefault = 0.0025;             //[=] 1/A, q-resolution, default value
1022        dQDefault = 0.0;
1023        dQ = dQDefault;
1024       
1025        Pi = 4.0*atan(1.0);
1026        qval= q;
1027       
1028        scale = dp[0];
1029        dd = dp[1];
1030        delT = dp[2];
1031        delH = dp[3];
1032        SLD_T = dp[4];
1033        SLD_H = dp[5];
1034        SLD_S = dp[6];
1035        NN = trunc(dp[7]);              //be sure that NN is an integer
1036        Cp = dp[8];
1037        bkg = dp[9];
1038       
1039       
1040        drh = SLD_H - SLD_S;
1041        drt = SLD_T - SLD_S;    //correction 13FEB06 by L.Porcar
1042       
1043        Pq = drh*(sin(qval*(delH+delT))-sin(qval*delT)) + drt*sin(qval*delT);
1044        Pq *= Pq;
1045        Pq *= 4.0/(qval*qval);
1046       
1047        NNint = (int)NN;                //cast to an integer for the loop
1048        ii=0;
1049        Sq = 0.0;
1050        for(ii=1;ii<(NNint-1);ii+=1) {
1051       
1052                fii = (double)ii;               //do I really need to do this?
1053               
1054                temp = 0.0;
1055                alpha = Cp/4.0/Pi/Pi*(log(Pi*ii) + Euler);
1056                t1 = 2.0*dQ*dQ*dd*dd*alpha;
1057                t2 = 2.0*qval*qval*dd*dd*alpha;
1058                t3 = dQ*dQ*dd*dd*ii*ii;
1059               
1060                temp = 1.0-ii/NN;
1061                temp *= cos(dd*qval*ii/(1.0+t1));
1062                temp *= exp(-1.0*(t2 + t3)/(2.0*(1.0+t1)) );
1063                temp /= sqrt(1.0+t1);
1064               
1065                Sq += temp;
1066        }
1067       
1068        Sq *= 2.0;
1069        Sq += 1.0;
1070       
1071        inten = 2.0*Pi*scale*Pq*Sq/(dd*qval*qval);
1072       
1073        inten *= 1.0e8;         // 1/A to 1/cm
1074       
1075        return(inten+bkg);
1076}
1077
1078/*      LamellarFF_HGX  :  calculates the form factor of a lamellar structure - no S(q) effects included
1079but extra SLD for head groups is included
1080
1081*/
1082double
1083LamellarFF_HG(double dp[], double q)
1084{
1085        double scale,delT,delH,slds,sldh,sldt,bkg;              //local variables of coefficient wave
1086        double inten, qval,Pq,drh,drt;
1087        double Pi;
1088       
1089       
1090        Pi = 4.0*atan(1.0);
1091        qval= q;
1092        scale = dp[0];
1093        delT = dp[1];
1094        delH = dp[2];
1095        sldt = dp[3];
1096        sldh = dp[4];
1097        slds = dp[5];
1098        bkg = dp[6];
1099       
1100       
1101        drh = sldh - slds;
1102        drt = sldt - slds;              //correction 13FEB06 by L.Porcar
1103       
1104        Pq = drh*(sin(qval*(delH+delT))-sin(qval*delT)) + drt*sin(qval*delT);
1105        Pq *= Pq;
1106        Pq *= 4.0/(qval*qval);
1107       
1108        inten = 2.0*Pi*scale*Pq/(qval*qval);            //dimensionless...
1109       
1110        inten /= 2.0*(delT+delH);                       //normalize by the bilayer thickness
1111       
1112        inten *= 1.0e8;         // 1/A to 1/cm
1113       
1114        return(inten+bkg);
1115}
1116
1117/*      FlexExclVolCylX  :  calculates the form factor of a flexible cylinder with a circular cross section
1118-- incorporates Wei-Ren Chen's fixes - 2006
1119
1120        */
1121double
1122FlexExclVolCyl(double dp[], double q)
1123{
1124        double scale,L,B,bkg,rad,qr,cont,sldc,slds;
1125        double Pi,flex,crossSect,answer;
1126       
1127       
1128        Pi = 4.0*atan(1.0);
1129       
1130        scale = dp[0];          //make local copies in case memory moves
1131        L = dp[1];
1132        B = dp[2];
1133        rad = dp[3];
1134        sldc = dp[4];
1135        slds = dp[5];
1136        cont = sldc-slds;
1137        bkg = dp[6];
1138       
1139   
1140        qr = q*rad;
1141       
1142        flex = Sk_WR(q,L,B);
1143       
1144        crossSect = (2.0*NR_BessJ1(qr)/qr)*(2.0*NR_BessJ1(qr)/qr);
1145        flex *= crossSect;
1146        flex *= Pi*rad*rad*L;
1147        flex *= cont*cont;
1148        flex *= 1.0e8;
1149        answer = scale*flex + bkg;
1150       
1151        return answer;
1152}
1153
1154/*      FlexCyl_EllipX  :  calculates the form factor of a flexible cylinder with an elliptical cross section
1155-- incorporates Wei-Ren Chen's fixes - 2006
1156
1157        */
1158double
1159FlexCyl_Ellip(double dp[], double q)
1160{
1161        double scale,L,B,bkg,rad,qr,cont,ellRatio,slds,sldc;
1162        double Pi,flex,crossSect,answer;
1163       
1164       
1165        Pi = 4.0*atan(1.0);
1166        scale = dp[0];          //make local copies in case memory moves
1167        L = dp[1];
1168        B = dp[2];
1169        rad = dp[3];
1170        ellRatio = dp[4];
1171        sldc = dp[5];
1172        slds = dp[6];
1173        bkg = dp[7];
1174       
1175        cont = sldc - slds;
1176        qr = q*rad;
1177       
1178        flex = Sk_WR(q,L,B);
1179       
1180        crossSect = EllipticalCross_fn(q,rad,(rad*ellRatio));
1181        flex *= crossSect;
1182        flex *= Pi*rad*rad*ellRatio*L;
1183        flex *= cont*cont;
1184        flex *= 1.0e8;
1185        answer = scale*flex + bkg;
1186       
1187        return answer;
1188}
1189
1190double
1191EllipticalCross_fn(double qq, double a, double b)
1192{
1193    double uplim,lolim,Pi,summ,arg,zi,yyy,answer;
1194    int i,nord=76;
1195   
1196    Pi = 4.0*atan(1.0);
1197    lolim=0.0;
1198    uplim=Pi/2.0;
1199    summ=0.0;
1200   
1201    for(i=0;i<nord;i++) {
1202                zi = ( Gauss76Z[i]*(uplim-lolim) + uplim + lolim )/2.0;
1203                arg = qq*sqrt(a*a*sin(zi)*sin(zi)+b*b*cos(zi)*cos(zi));
1204                yyy = pow((2.0 * NR_BessJ1(arg) / arg),2);
1205                yyy *= Gauss76Wt[i];
1206                summ += yyy;
1207    }
1208    answer = (uplim-lolim)/2.0*summ;
1209    answer *= 2.0/Pi;
1210    return(answer);
1211       
1212}
1213/*      FlexCyl_PolyLenX  :  calculates the form factor of a flecible cylinder at the given x-value p->x
1214the cylinder has a polydisperse Length
1215
1216*/
1217double
1218FlexCyl_PolyLen(double dp[], double q)
1219{
1220        int i;
1221        double scale,radius,length,pd,bkg,lb,delrho,sldc,slds;          //local variables of coefficient wave
1222        int nord=20;                    //order of integration
1223        double uplim,lolim;             //upper and lower integration limits
1224        double summ,zi,yyy,answer,Vpoly;                        //running tally of integration
1225        double range,zz,Pi;
1226       
1227        Pi = 4.0*atan(1.0);
1228        range = 3.4;
1229       
1230        summ = 0.0;                     //initialize intergral
1231        scale = dp[0];                  //make local copies in case memory moves
1232        length = dp[1];                 //radius
1233        pd = dp[2];                     // average length
1234        lb = dp[3];
1235        radius = dp[4];
1236        sldc = dp[5];
1237        slds = dp[6];
1238        bkg = dp[7];
1239       
1240        delrho = sldc - slds;
1241        zz = (1.0/pd)*(1.0/pd) - 1.0;
1242       
1243        lolim = length*(1.0-range*pd);          //set the upper/lower limits to cover the distribution
1244        if(lolim<0.0) {
1245                lolim = 0.0;
1246        }
1247        if(pd>0.3) {
1248                range = 3.4 + (pd-0.3)*18.0;
1249        }
1250        uplim = length*(1.0+range*pd);
1251       
1252        for(i=0;i<nord;i++) {
1253                zi = ( Gauss20Z[i]*(uplim-lolim) + uplim + lolim )/2.0;
1254                yyy = Gauss20Wt[i] * FlePolyLen_kernel(q,radius,length,lb,zz,delrho,zi);
1255                summ += yyy;
1256        }
1257       
1258        answer = (uplim-lolim)/2.0*summ;
1259        //normalize by average cylinder volume (first moment), using the average length
1260        Vpoly=Pi*radius*radius*length;
1261        answer /= Vpoly;
1262       
1263        answer *=delrho*delrho;
1264       
1265        //convert to [cm-1]
1266        answer *= 1.0e8;
1267        //Scale
1268        answer *= scale;
1269        // add in the background
1270        answer += bkg;
1271       
1272        return answer;
1273}
1274
1275/*      FlexCyl_PolyLenX  :  calculates the form factor of a flexible cylinder at the given x-value p->x
1276the cylinder has a polydisperse cross sectional radius
1277
1278*/
1279double
1280FlexCyl_PolyRad(double dp[], double q)
1281{
1282        int i;
1283        double scale,radius,length,pd,delrho,bkg,lb,sldc,slds;          //local variables of coefficient wave
1284        int nord=76;                    //order of integration
1285        double uplim,lolim;             //upper and lower integration limits
1286        double summ,zi,yyy,answer,Vpoly;                        //running tally of integration
1287        double range,zz,Pi;
1288       
1289       
1290        Pi = 4.0*atan(1.0);
1291        range = 3.4;
1292       
1293        summ = 0.0;                     //initialize intergral
1294       
1295        scale = dp[0];                  //make local copies in case memory moves
1296        length = dp[1];                 //radius
1297        lb = dp[2];                     // average length
1298        radius = dp[3];
1299        pd = dp[4];
1300        sldc = dp[5];
1301        slds = dp[6];
1302        bkg = dp[7];
1303       
1304        delrho = sldc-slds;
1305        zz = (1.0/pd)*(1.0/pd) - 1.0;
1306       
1307        lolim = radius*(1.0-range*pd);          //set the upper/lower limits to cover the distribution
1308        if(lolim<0.0) {
1309                lolim = 0.0;
1310        }
1311        if(pd>0.3) {
1312                range = 3.4 + (pd-0.3)*18.0;
1313        }
1314        uplim = radius*(1.0+range*pd);
1315       
1316        for(i=0;i<nord;i++) {
1317                //zi = ( Gauss20Z[i]*(uplim-lolim) + uplim + lolim )/2.0;
1318                //yyy = Gauss20Wt[i] * FlePolyRad_kernel(q,radius,length,lb,zz,delrho,zi);
1319                zi = ( Gauss76Z[i]*(uplim-lolim) + uplim + lolim )/2.0;
1320                yyy = Gauss76Wt[i] * FlePolyRad_kernel(q,radius,length,lb,zz,delrho,zi);
1321                summ += yyy;
1322        }
1323       
1324        answer = (uplim-lolim)/2.0*summ;
1325        //normalize by average cylinder volume (second moment), using the average radius
1326        Vpoly = Pi*radius*radius*length*(zz+2.0)/(zz+1.0);
1327        answer /= Vpoly;
1328       
1329        answer *=delrho*delrho;
1330       
1331        //convert to [cm-1]
1332        answer *= 1.0e8;
1333        //Scale
1334        answer *= scale;
1335        // add in the background
1336        answer += bkg;
1337       
1338        return answer;
1339}
1340
1341
1342
1343///////////////
1344
1345//
1346//     FUNCTION gfn2:    CONTAINS F(Q,A,B,mu)**2  AS GIVEN
1347//                       BY (53) AND (56,57) IN CHEN AND
1348//                       KOTLARCHYK REFERENCE
1349//
1350//     <PROLATE ELLIPSOIDS>
1351//
1352double
1353gfn2(double xx, double crmaj, double crmin, double trmaj, double trmin, double delpc, double delps, double qq)
1354{
1355        // local variables
1356        double aa,bb,u2,ut2,uq,ut,vc,vt,siq,sit,gfnc,gfnt,gfn2,pi43,gfn,Pi;
1357
1358        Pi = 4.0*atan(1.0);
1359       
1360        pi43=4.0/3.0*Pi;
1361        aa = crmaj;
1362        bb = crmin;
1363        u2 = (aa*aa*xx*xx + bb*bb*(1.0-xx*xx));
1364        ut2 = (trmaj*trmaj*xx*xx + trmin*trmin*(1.0-xx*xx));
1365        uq = sqrt(u2)*qq;
1366        ut= sqrt(ut2)*qq;
1367        vc = pi43*aa*bb*bb;
1368        vt = pi43*trmaj*trmin*trmin;
1369        if (uq == 0.0){
1370                siq = 1.0/3.0;
1371        }else{
1372                siq = (sin(uq)/uq/uq - cos(uq)/uq)/uq;
1373        }
1374        if (ut == 0.0){
1375                sit = 1.0/3.0;
1376        }else{
1377                sit = (sin(ut)/ut/ut - cos(ut)/ut)/ut;
1378        }
1379        gfnc = 3.0*siq*vc*delpc;
1380        gfnt = 3.0*sit*vt*delps;
1381        gfn = gfnc+gfnt;
1382        gfn2 = gfn*gfn;
1383       
1384        return (gfn2);
1385}
1386
1387//
1388//     FUNCTION gfn4:    CONTAINS F(Q,A,B,MU)**2  AS GIVEN
1389//                       BY (53) & (58-59) IN CHEN AND
1390//                       KOTLARCHYK REFERENCE
1391//
1392//       <OBLATE ELLIPSOID>
1393// function gfn4 for oblate ellipsoids
1394double
1395gfn4(double xx, double crmaj, double crmin, double trmaj, double trmin, double delpc, double delps, double qq)
1396{
1397        // local variables
1398        double aa,bb,u2,ut2,uq,ut,vc,vt,siq,sit,gfnc,gfnt,tgfn,gfn4,pi43,Pi;
1399
1400        Pi = 4.0*atan(1.0);
1401        pi43=4.0/3.0*Pi;
1402        aa = crmaj;
1403        bb = crmin;
1404        u2 = (bb*bb*xx*xx + aa*aa*(1.0-xx*xx));
1405        ut2 = (trmin*trmin*xx*xx + trmaj*trmaj*(1.0-xx*xx));
1406        uq = sqrt(u2)*qq;
1407        ut= sqrt(ut2)*qq;
1408        vc = pi43*aa*aa*bb;
1409        vt = pi43*trmaj*trmaj*trmin;
1410        if (uq == 0.0){
1411                siq = 1.0/3.0;
1412        }else{
1413                siq = (sin(uq)/uq/uq - cos(uq)/uq)/uq;
1414        }
1415        if (ut == 0.0){
1416                sit = 1.0/3.0;
1417        }else{
1418                sit = (sin(ut)/ut/ut - cos(ut)/ut)/ut;
1419        }
1420        gfnc = 3.0*siq*vc*delpc;
1421        gfnt = 3.0*sit*vt*delps;
1422        tgfn = gfnc+gfnt;
1423        gfn4 = tgfn*tgfn;
1424       
1425        return (gfn4);
1426}
1427
1428double
1429FlePolyLen_kernel(double q, double radius, double length, double lb, double zz, double delrho, double zi)
1430{
1431    double Pq,vcyl,dl;
1432    double Pi,qr;
1433   
1434    Pi = 4.0*atan(1.0);
1435    qr = q*radius;
1436   
1437    Pq = Sk_WR(q,zi,lb);                //does not have cross section term
1438    if (qr !=0){
1439        Pq *= (2.0*NR_BessJ1(qr)/qr)*(2.0*NR_BessJ1(qr)/qr);
1440    } 
1441    vcyl=Pi*radius*radius*zi;
1442    Pq *= vcyl*vcyl;
1443   
1444    dl = SchulzPoint_cpr(zi,length,zz);
1445    return (Pq*dl);     
1446       
1447}
1448
1449double
1450FlePolyRad_kernel(double q, double ravg, double Lc, double Lb, double zz, double delrho, double zi)
1451{
1452    double Pq,vcyl,dr;
1453    double Pi,qr;
1454   
1455    Pi = 4.0*atan(1.0);
1456    qr = q*zi;
1457   
1458    Pq = Sk_WR(q,Lc,Lb);                //does not have cross section term
1459    if (qr !=0){
1460        Pq *= (2.0*NR_BessJ1(qr)/qr)*(2.0*NR_BessJ1(qr)/qr);
1461    }
1462
1463    vcyl=Pi*zi*zi*Lc;
1464    Pq *= vcyl*vcyl;
1465   
1466    dr = SchulzPoint_cpr(zi,ravg,zz);
1467    return (Pq*dr);     
1468       
1469}
1470
1471double
1472CSCylIntegration(double qq, double rad, double radthick, double facthick, double rhoc, double rhos, double rhosolv, double length)
1473{
1474        double answer,halfheight,Pi;
1475        double lolim,uplim,summ,yyy,zi;
1476        int nord,i;
1477       
1478        // set up the integration end points
1479        Pi = 4.0*atan(1.0);
1480        nord = 76;
1481        lolim = 0.0;
1482        uplim = Pi/2.0;
1483        halfheight = length/2.0;
1484       
1485        summ = 0.0;                             // initialize integral
1486        i=0;
1487        for(i=0;i<nord;i++) {
1488                zi = ( Gauss76Z[i]*(uplim-lolim) + uplim + lolim )/2.0;
1489                yyy = Gauss76Wt[i] * CScyl(qq, rad, radthick, facthick, rhoc,rhos,rhosolv, halfheight, zi);
1490                summ += yyy;
1491        }
1492       
1493        // calculate value of integral to return
1494        answer = (uplim-lolim)/2.0*summ;
1495        return (answer);
1496}
1497
1498double
1499CScyl(double qq, double rad, double radthick, double facthick, double rhoc, double rhos, double rhosolv, double length, double dum)
1500{       
1501        // qq is the q-value for the calculation (1/A)
1502        // radius is the core radius of the cylinder (A)
1503        //  radthick and facthick are the radial and face layer thicknesses
1504        // rho(n) are the respective SLD's
1505        // length is the *Half* CORE-LENGTH of the cylinder
1506        // dum is the dummy variable for the integration (theta)
1507
1508        double dr1,dr2,besarg1,besarg2,vol1,vol2,sinarg1,sinarg2,si1,si2,be1,be2,t1,t2,retval;
1509        double Pi;
1510       
1511        Pi = 4.0*atan(1.0); 
1512       
1513        dr1 = rhoc-rhos;
1514        dr2 = rhos-rhosolv;
1515        vol1 = Pi*rad*rad*(2.0*length);
1516        vol2 = Pi*(rad+radthick)*(rad+radthick)*(2.0*length+2.0*facthick);
1517       
1518        besarg1 = qq*rad*sin(dum);
1519        besarg2 = qq*(rad+radthick)*sin(dum);
1520        sinarg1 = qq*length*cos(dum);
1521        sinarg2 = qq*(length+facthick)*cos(dum);
1522        if (besarg1 == 0.0){
1523                be1 = 0.5;
1524        }else{
1525                be1 = NR_BessJ1(besarg1)/besarg1;
1526        }
1527        if (besarg2 == 0.0){
1528                be2 = 0.5;
1529        }else{
1530                be2 = NR_BessJ1(besarg2)/besarg2;
1531        }
1532        if (sinarg1 == 0.0){
1533                si1 = 1.0;
1534        }else{
1535                si1 = sin(sinarg1)/sinarg1;
1536        }
1537        if (sinarg2 == 0.0){
1538                si2 = 1.0;
1539        }else{
1540                si2 = sin(sinarg2)/sinarg2;
1541        }
1542
1543        t1 = 2.0*vol1*dr1*si1*be1;
1544        t2 = 2.0*vol2*dr2*si2*be2;
1545
1546        retval = ((t1+t2)*(t1+t2))*sin(dum);
1547        return (retval);
1548   
1549}
1550
1551
1552double
1553CoreShellCylKernel(double qq, double rcore, double thick, double rhoc, double rhos, double rhosolv, double length, double dum)
1554{
1555
1556    double dr1,dr2,besarg1,besarg2,vol1,vol2,sinarg1,sinarg2,si1,si2,be1,be2,t1,t2,retval;
1557    double Pi;
1558   
1559    Pi = 4.0*atan(1.0);
1560   
1561    dr1 = rhoc-rhos;
1562    dr2 = rhos-rhosolv;
1563    vol1 = Pi*rcore*rcore*(2.0*length);
1564    vol2 = Pi*(rcore+thick)*(rcore+thick)*(2.0*length+2.0*thick);
1565   
1566    besarg1 = qq*rcore*sin(dum);
1567    besarg2 = qq*(rcore+thick)*sin(dum);
1568    sinarg1 = qq*length*cos(dum);
1569    sinarg2 = qq*(length+thick)*cos(dum);
1570
1571        if (besarg1 == 0.0){
1572                be1 = 0.5;
1573        }else{
1574                be1 = NR_BessJ1(besarg1)/besarg1;
1575        }
1576        if (besarg2 == 0.0){
1577                be2 = 0.5;
1578        }else{
1579                be2 = NR_BessJ1(besarg2)/besarg2;
1580        }
1581        if (sinarg1 == 0.0){
1582                si1 = 1.0;
1583        }else{
1584                si1 = sin(sinarg1)/sinarg1;
1585        }
1586        if (sinarg2 == 0.0){
1587                si2 = 1.0;
1588        }else{
1589                si2 = sin(sinarg2)/sinarg2;
1590        }
1591
1592    t1 = 2.0*vol1*dr1*si1*be1;
1593    t2 = 2.0*vol2*dr2*si2*be2;
1594
1595    retval = ((t1+t2)*(t1+t2))*sin(dum);
1596       
1597    return (retval);
1598}
1599
1600double
1601Cyl_PolyLenKernel(double q, double radius, double len_avg, double zz, double delrho, double dumLen)
1602{
1603       
1604    double halfheight,uplim,lolim,zi,summ,yyy,Pi;
1605    double answer,dr,Vcyl;
1606    int i,nord;
1607   
1608    Pi = 4.0*atan(1.0);
1609    lolim = 0.0;
1610    uplim = Pi/2.0;
1611    halfheight = dumLen/2.0;
1612    nord=20;
1613    summ = 0.0;
1614   
1615    //do the cylinder orientational average
1616    for(i=0;i<nord;i++) {
1617                zi = ( Gauss20Z[i]*(uplim-lolim) + uplim + lolim )/2.0;
1618                yyy = Gauss20Wt[i] * CylKernel(q, radius, halfheight, zi);
1619                summ += yyy;
1620    }
1621    answer = (uplim-lolim)/2.0*summ;
1622    // Multiply by contrast^2
1623    answer *= delrho*delrho;
1624    // don't do the normal scaling to volume here
1625    // instead, multiply by VCyl^2 to get rid of the normalization for this radius of cylinder
1626    Vcyl = Pi*radius*radius*dumLen;
1627    answer *= Vcyl*Vcyl;
1628   
1629    dr = SchulzPoint_cpr(dumLen,len_avg,zz);
1630    return(dr*answer);
1631}
1632
1633
1634double
1635Stackdisc_kern(double qq, double rcore, double rhoc, double rhol, double rhosolv, double length, double thick, double dum, double gsd, double d, double N)
1636{               
1637        // qq is the q-value for the calculation (1/A)
1638        // rcore is the core radius of the cylinder (A)
1639        // rho(n) are the respective SLD's
1640        // length is the *Half* CORE-LENGTH of the cylinder = L (A)
1641        // dum is the dummy variable for the integration (x in Feigin's notation)
1642
1643        //Local variables
1644        double totald,dr1,dr2,besarg1,besarg2,be1,be2,si1,si2,area,sinarg1,sinarg2,t1,t2,retval,sqq,dexpt;
1645        double Pi;
1646        int kk;
1647       
1648        Pi = 4.0*atan(1.0);
1649       
1650        dr1 = rhoc-rhosolv;
1651        dr2 = rhol-rhosolv;
1652        area = Pi*rcore*rcore;
1653        totald=2.0*(thick+length);
1654       
1655        besarg1 = qq*rcore*sin(dum);
1656        besarg2 = qq*rcore*sin(dum);
1657       
1658        sinarg1 = qq*length*cos(dum);
1659        sinarg2 = qq*(length+thick)*cos(dum);
1660
1661        if (besarg1 == 0.0){
1662                be1 = 0.5;
1663        }else{
1664                be1 = NR_BessJ1(besarg1)/besarg1;
1665        }
1666        if (besarg2 == 0.0){
1667                be2 = 0.5;
1668        }else{
1669                be2 = NR_BessJ1(besarg2)/besarg2;
1670        }
1671        if (sinarg1 == 0.0){
1672                si1 = 1.0;
1673        }else{
1674                si1 = sin(sinarg1)/sinarg1;
1675        }
1676        if (sinarg2 == 0.0){
1677                si2 = 1.0;
1678        }else{
1679                si2 = sin(sinarg2)/sinarg2;
1680        }
1681
1682        t1 = 2.0*area*(2.0*length)*dr1*(si1)*(be1);
1683        t2 = 2.0*area*dr2*(totald*si2-2.0*length*si1)*(be2);
1684
1685        retval =((t1+t2)*(t1+t2))*sin(dum);
1686       
1687        // loop for the structure facture S(q)
1688        sqq=0.0;
1689        for(kk=1;kk<N;kk+=1) {
1690                dexpt=qq*cos(dum)*qq*cos(dum)*d*d*gsd*gsd*kk/2.0;
1691                sqq=sqq+(N-kk)*cos(qq*cos(dum)*d*kk)*exp(-1.*dexpt);
1692        }                       
1693       
1694        // end of loop for S(q)
1695        sqq=1.0+2.0*sqq/N;
1696        retval *= sqq;
1697   
1698        return(retval);
1699}
1700
1701
1702double
1703Cyl_PolyRadKernel(double q, double radius, double length, double zz, double delrho, double dumRad)
1704{
1705       
1706    double halfheight,uplim,lolim,zi,summ,yyy,Pi;
1707    double answer,dr,Vcyl;
1708    int i,nord;
1709   
1710    Pi = 4.0*atan(1.0);
1711    lolim = 0.0;
1712    uplim = Pi/2.0;
1713    halfheight = length/2.0;
1714        //    nord=20;
1715    nord=76;
1716    summ = 0.0;
1717   
1718    //do the cylinder orientational average
1719        //    for(i=0;i<nord;i++) {
1720        //            zi = ( Gauss20Z[i]*(uplim-lolim) + uplim + lolim )/2.0;
1721        //            yyy = Gauss20Wt[i] * CylKernel(q, dumRad, halfheight, zi);
1722        //            summ += yyy;
1723        //    }
1724    for(i=0;i<nord;i++) {
1725                zi = ( Gauss76Z[i]*(uplim-lolim) + uplim + lolim )/2.0;
1726                yyy = Gauss76Wt[i] * CylKernel(q, dumRad, halfheight, zi);
1727                summ += yyy;
1728    }
1729    answer = (uplim-lolim)/2.0*summ;
1730    // Multiply by contrast^2
1731    answer *= delrho*delrho;
1732    // don't do the normal scaling to volume here
1733    // instead, multiply by VCyl^2 to get rid of the normalization for this radius of cylinder
1734    Vcyl = Pi*dumRad*dumRad*length;
1735    answer *= Vcyl*Vcyl;
1736   
1737    dr = SchulzPoint_cpr(dumRad,radius,zz);
1738    return(dr*answer);
1739}
1740
1741double
1742SchulzPoint_cpr(double dumRad, double radius, double zz)
1743{
1744    double dr;
1745   
1746    dr = zz*log(dumRad) - gammaln(zz+1.0) + (zz+1.0)*log((zz+1.0)/radius)-(dumRad/radius*(zz+1.0));
1747    return(exp(dr));
1748}
1749
1750
1751double
1752EllipsoidKernel(double qq, double a, double nua, double dum)
1753{
1754    double arg,nu,retval;               //local variables
1755       
1756    nu = nua/a;
1757    arg = qq*a*sqrt(1.0+dum*dum*(nu*nu-1.0));
1758    if (arg == 0.0){
1759        retval =1.0/3.0;
1760    }else{
1761        retval = (sin(arg)-arg*cos(arg))/(arg*arg*arg);
1762    }
1763    retval *= retval;
1764    retval *= 9.0;
1765
1766    return(retval);
1767}//Function EllipsoidKernel()
1768
1769double
1770HolCylKernel(double qq, double rcore, double rshell, double length, double dum)
1771{
1772    double gamma,arg1,arg2,lam1,lam2,psi,sinarg,t2,retval;              //local variables
1773   
1774    gamma = rcore/rshell;
1775    arg1 = qq*rshell*sqrt(1.0-dum*dum);         //1=shell (outer radius)
1776    arg2 = qq*rcore*sqrt(1.0-dum*dum);                  //2=core (inner radius)
1777    if (arg1 == 0.0){
1778        lam1 = 1.0;
1779    }else{
1780        lam1 = 2.0*NR_BessJ1(arg1)/arg1;
1781    }
1782    if (arg2 == 0.0){
1783        lam2 = 1.0;
1784    }else{
1785        lam2 = 2.0*NR_BessJ1(arg2)/arg2;
1786    }
1787    //Todo: Need to check psi behavior as gamma goes to 1.
1788    psi = 1.0/(1.0-gamma*gamma)*(lam1 -  gamma*gamma*lam2);             //SRK 10/19/00
1789    sinarg = qq*length*dum/2.0;
1790    if (sinarg == 0.0){
1791        t2 = 1.0;
1792    }else{
1793        t2 = sin(sinarg)/sinarg;
1794    }
1795
1796    retval = psi*psi*t2*t2;
1797   
1798    return(retval);
1799}//Function HolCylKernel()
1800
1801double
1802PPKernel(double aa, double mu, double uu)
1803{
1804    // mu passed in is really mu*sqrt(1-sig^2)
1805    double arg1,arg2,Pi,tmp1,tmp2;                      //local variables
1806       
1807    Pi = 4.0*atan(1.0);
1808   
1809    //handle arg=0 separately, as sin(t)/t -> 1 as t->0
1810    arg1 = (mu/2.0)*cos(Pi*uu/2.0);
1811    arg2 = (mu*aa/2.0)*sin(Pi*uu/2.0);
1812    if(arg1==0.0) {
1813                tmp1 = 1.0;
1814        } else {
1815                tmp1 = sin(arg1)*sin(arg1)/arg1/arg1;
1816    }
1817
1818    if (arg2==0.0) {
1819                tmp2 = 1.0;
1820        } else {
1821                tmp2 = sin(arg2)*sin(arg2)/arg2/arg2;
1822    }
1823       
1824    return (tmp1*tmp2);
1825       
1826}//Function PPKernel()
1827
1828
1829double
1830TriaxialKernel(double q, double aa, double bb, double cc, double dx, double dy)
1831{
1832       
1833    double arg,val,pi;                  //local variables
1834       
1835    pi = 4.0*atan(1.0);
1836   
1837    arg = aa*aa*cos(pi*dx/2)*cos(pi*dx/2);
1838    arg += bb*bb*sin(pi*dx/2)*sin(pi*dx/2)*(1-dy*dy);
1839    arg += cc*cc*dy*dy;
1840    arg = q*sqrt(arg);
1841    if (arg == 0.0){
1842        val = 1.0; // as arg --> 0, val should go to 1.0
1843    }else{
1844        val = 9.0 * ( (sin(arg) - arg*cos(arg))/(arg*arg*arg) ) * ( (sin(arg) - arg*cos(arg))/(arg*arg*arg) );
1845    }
1846    return (val);
1847       
1848}//Function TriaxialKernel()
1849
1850
1851double
1852CylKernel(double qq, double rr,double h, double theta)
1853{
1854       
1855        // qq is the q-value for the calculation (1/A)
1856        // rr is the radius of the cylinder (A)
1857        // h is the HALF-LENGTH of the cylinder = L/2 (A)
1858
1859    double besarg,bj,retval,d1,t1,b1,t2,b2,siarg,be,si;          //Local variables
1860
1861
1862    besarg = qq*rr*sin(theta);
1863    siarg = qq * h * cos(theta);
1864    bj =NR_BessJ1(besarg);
1865       
1866        //* Computing 2nd power */
1867    d1 = sin(siarg);
1868    t1 = d1 * d1;
1869        //* Computing 2nd power */
1870    d1 = bj;
1871    t2 = d1 * d1 * 4.0 * sin(theta);
1872        //* Computing 2nd power */
1873    d1 = siarg;
1874    b1 = d1 * d1;
1875        //* Computing 2nd power */
1876    d1 = qq * rr * sin(theta);
1877    b2 = d1 * d1;
1878    if (besarg == 0.0){
1879        be = sin(theta);
1880    }else{
1881        be = t2 / b2;
1882    }
1883    if (siarg == 0.0){
1884        si = 1.0;
1885    }else{
1886        si = t1 / b1;
1887    }
1888    retval = be * si;
1889
1890    return (retval);
1891       
1892}//Function CylKernel()
1893
1894double
1895EllipCylKernel(double qq, double ra,double nu, double theta)
1896{
1897        //this is the function LAMBDA1^2 in Feigin's notation   
1898        // qq is the q-value for the calculation (1/A)
1899        // ra is the transformed radius"a" in Feigin's notation
1900        // nu is the ratio (major radius)/(minor radius) of the Ellipsoid [=] ---
1901        // theta is the dummy variable of the integration
1902       
1903        double retval,arg;               //Local variables
1904       
1905        arg = qq*ra*sqrt((1.0+nu*nu)/2+(1.0-nu*nu)*cos(theta)/2);
1906        if (arg == 0.0){
1907                retval = 1.0;
1908        }else{
1909                retval = 2.0*NR_BessJ1(arg)/arg;
1910        }
1911
1912        //square it
1913        retval *= retval;
1914       
1915    return(retval);
1916       
1917}//Function EllipCylKernel()
1918
1919double NR_BessJ1(double x)
1920{
1921        double ax,z;
1922        double xx,y,ans,ans1,ans2;
1923       
1924        if ((ax=fabs(x)) < 8.0) {
1925                y=x*x;
1926                ans1=x*(72362614232.0+y*(-7895059235.0+y*(242396853.1
1927                                                                                                  +y*(-2972611.439+y*(15704.48260+y*(-30.16036606))))));
1928                ans2=144725228442.0+y*(2300535178.0+y*(18583304.74
1929                                                                                           +y*(99447.43394+y*(376.9991397+y*1.0))));
1930                ans=ans1/ans2;
1931        } else {
1932                z=8.0/ax;
1933                y=z*z;
1934                xx=ax-2.356194491;
1935                ans1=1.0+y*(0.183105e-2+y*(-0.3516396496e-4
1936                                                                   +y*(0.2457520174e-5+y*(-0.240337019e-6))));
1937                ans2=0.04687499995+y*(-0.2002690873e-3
1938                                                          +y*(0.8449199096e-5+y*(-0.88228987e-6
1939                                                                                                         +y*0.105787412e-6)));
1940                ans=sqrt(0.636619772/ax)*(cos(xx)*ans1-z*sin(xx)*ans2);
1941                if (x < 0.0) ans = -ans;
1942        }
1943       
1944        return(ans);
1945}
1946
1947/*      Lamellar_ParaCrystal - Pedersen's model
1948
1949*/
1950double
1951Lamellar_ParaCrystal(double w[], double q)
1952{
1953//       Input (fitting) variables are:
1954        //[0] scale factor
1955        //[1]   thickness
1956        //[2]   number of layers
1957        //[3]   spacing between layers
1958        //[4]   polydispersity of spacing
1959        //[5] SLD lamellar
1960        //[6] SLD solvent
1961        //[7] incoherent background
1962//      give them nice names
1963        double inten,qval,scale,th,nl,davg,pd,contr,bkg,xn;
1964        double xi,ww,Pbil,Znq,Snq,an,sldLayer,sldSolvent,pi;
1965        long n1,n2;
1966       
1967        pi = 4.0*atan(1.0);
1968        scale = w[0];
1969        th = w[1];
1970        nl = w[2];
1971        davg = w[3];
1972        pd = w[4];
1973        sldLayer = w[5];
1974        sldSolvent = w[6];
1975        bkg = w[7];
1976       
1977        contr = w[5] - w[6];
1978        qval = q;
1979               
1980        //get the fractional part of nl, to determine the "mixing" of N's
1981       
1982        n1 = trunc(nl);         //rounds towards zero
1983        n2 = n1 + 1;
1984        xn = (double)n2 - nl;                   //fractional contribution of n1
1985       
1986        ww = exp(-qval*qval*pd*pd*davg*davg/2.0);
1987       
1988        //calculate the n1 contribution
1989        an = paraCryst_an(ww,qval,davg,n1);
1990        Snq = paraCryst_sn(ww,qval,davg,n1,an);
1991       
1992        Znq = xn*Snq;
1993       
1994        //calculate the n2 contribution
1995        an = paraCryst_an(ww,qval,davg,n2);
1996        Snq = paraCryst_sn(ww,qval,davg,n2,an);
1997       
1998        Znq += (1.0-xn)*Snq;
1999       
2000        //and the independent contribution
2001        Znq += (1.0-ww*ww)/(1.0+ww*ww-2.0*ww*cos(qval*davg));
2002       
2003        //the limit when NL approaches infinity
2004//      Zq = (1-ww^2)/(1+ww^2-2*ww*cos(qval*davg))
2005       
2006        xi = th/2.0;            //use 1/2 the bilayer thickness
2007        Pbil = (sin(qval*xi)/(qval*xi))*(sin(qval*xi)/(qval*xi));
2008       
2009        inten = 2.0*pi*contr*contr*Pbil*Znq/(qval*qval);
2010        inten *= 1.0e8;
2011       
2012        return(scale*inten+bkg);
2013}
2014
2015// functions for the lamellar paracrystal model
2016double
2017paraCryst_sn(double ww, double qval, double davg, long nl, double an) {
2018       
2019        double Snq;
2020       
2021        Snq = an/( (double)nl*pow((1.0+ww*ww-2.0*ww*cos(qval*davg)),2) );
2022       
2023        return(Snq);
2024}
2025
2026
2027double
2028paraCryst_an(double ww, double qval, double davg, long nl) {
2029       
2030        double an;
2031       
2032        an = 4.0*ww*ww - 2.0*(ww*ww*ww+ww)*cos(qval*davg);
2033        an -= 4.0*pow(ww,(nl+2))*cos((double)nl*qval*davg);
2034        an += 2.0*pow(ww,(nl+3))*cos((double)(nl-1)*qval*davg);
2035        an += 2.0*pow(ww,(nl+1))*cos((double)(nl+1)*qval*davg);
2036       
2037        return(an);
2038}
2039
2040
2041/*      Spherocylinder  :
2042
2043Uses 76 pt Gaussian quadrature for both integrals
2044*/
2045double
2046Spherocylinder(double w[], double x)
2047{
2048        int i,j;
2049        double Pi;
2050        double scale,contr,bkg,sldc,slds;
2051        double len,rad,hDist,endRad;
2052        int nordi=76;                   //order of integration
2053        int nordj=76;
2054        double va,vb;           //upper and lower integration limits
2055        double summ,zi,yyy,answer;                      //running tally of integration
2056        double summj,vaj,vbj,zij;                       //for the inner integration
2057        double SphCyl_tmp[7],arg1,arg2,inner,be;
2058       
2059       
2060        scale = w[0];
2061        rad = w[1];
2062        len = w[2];
2063        sldc = w[3];
2064        slds = w[4];
2065        bkg = w[5];
2066       
2067        SphCyl_tmp[0] = w[0];
2068        SphCyl_tmp[1] = w[1];
2069        SphCyl_tmp[2] = w[2];
2070        SphCyl_tmp[3] = w[1];           //end radius is same as cylinder radius
2071        SphCyl_tmp[4] = w[3];
2072        SphCyl_tmp[5] = w[4];
2073        SphCyl_tmp[6] = w[5];
2074       
2075        hDist = 0;              //by definition for this model
2076        endRad = rad;
2077       
2078        contr = sldc-slds;
2079       
2080        Pi = 4.0*atan(1.0);
2081        va = 0.0;
2082        vb = Pi/2.0;            //orintational average, outer integral
2083        vaj = -1.0*hDist/endRad;
2084        vbj = 1.0;              //endpoints of inner integral
2085
2086        summ = 0.0;                     //initialize intergral
2087
2088        for(i=0;i<nordi;i++) {
2089                //setup inner integral over the ellipsoidal cross-section
2090                summj=0.0;
2091                zi = ( Gauss76Z[i]*(vb-va) + va + vb )/2.0;             //the "theta" dummy
2092               
2093                for(j=0;j<nordj;j++) {
2094                        //20 gauss points for the inner integral
2095                        zij = ( Gauss76Z[j]*(vbj-vaj) + vaj + vbj )/2.0;                //the "t" dummy
2096                        yyy = Gauss76Wt[j] * SphCyl_kernel(SphCyl_tmp,x,zij,zi);
2097                        summj += yyy;
2098                }
2099                //now calculate the value of the inner integral
2100                inner = (vbj-vaj)/2.0*summj;
2101                inner *= 4.0*Pi*endRad*endRad*endRad;
2102               
2103                //now calculate outer integrand
2104                arg1 = x*len/2.0*cos(zi);
2105                arg2 = x*rad*sin(zi);
2106                yyy = inner;
2107
2108                if(arg2 == 0) {
2109                        be = 0.5;
2110                } else {
2111                        be = NR_BessJ1(arg2)/arg2;
2112                }
2113               
2114                if(arg1 == 0.0) {               //limiting value of sinc(0) is 1; sinc is not defined in math.h
2115                        yyy += Pi*rad*rad*len*2.0*be;
2116                } else {
2117                        yyy += Pi*rad*rad*len*sin(arg1)/arg1*2.0*be;
2118                }
2119                yyy *= yyy;
2120                yyy *= sin(zi);         // = |A(q)|^2*sin(theta)
2121                yyy *= Gauss76Wt[i];
2122                summ += yyy;
2123        }               //final scaling is done at the end of the function, after the NT_FP64 case
2124       
2125        answer = (vb-va)/2.0*summ;
2126
2127        answer /= Pi*rad*rad*len + Pi*4.0*endRad*endRad*endRad/3.0;             //divide by volume
2128        answer *= 1.0e8;                //convert to cm^-1
2129        answer *= contr*contr;
2130        answer *= scale;
2131        answer += bkg;
2132               
2133        return answer;
2134}
2135
2136
2137// inner integral of the sphereocylinder model, special case of hDist = 0
2138//
2139double
2140SphCyl_kernel(double w[], double x, double tt, double theta) {
2141
2142        double val,arg1,arg2;
2143        double scale,bkg,sldc,slds;
2144        double len,rad,hDist,endRad,be;
2145        scale = w[0];
2146        rad = w[1];
2147        len = w[2];
2148        endRad = w[3];
2149        sldc = w[4];
2150        slds = w[5];
2151        bkg = w[6];
2152       
2153        hDist = 0.0;
2154               
2155        arg1 = x*cos(theta)*(endRad*tt+hDist+len/2.0);
2156        arg2 = x*endRad*sin(theta)*sqrt(1.0-tt*tt);
2157       
2158        if(arg2 == 0) {
2159                be = 0.5;
2160        } else {
2161                be = NR_BessJ1(arg2)/arg2;
2162        }
2163        val = cos(arg1)*(1.0-tt*tt)*be;
2164       
2165        return(val);
2166}
2167
2168
2169/*      Convex Lens  : special case where L ~ 0 and hDist < 0
2170
2171Uses 76 pt Gaussian quadrature for both integrals
2172*/
2173double
2174ConvexLens(double w[], double x)
2175{
2176        int i,j;
2177        double Pi;
2178        double scale,contr,bkg,sldc,slds;
2179        double len,rad,hDist,endRad;
2180        int nordi=76;                   //order of integration
2181        int nordj=76;
2182        double va,vb;           //upper and lower integration limits
2183        double summ,zi,yyy,answer;                      //running tally of integration
2184        double summj,vaj,vbj,zij;                       //for the inner integration
2185        double CLens_tmp[7],arg1,arg2,inner,hh,be;
2186       
2187       
2188        scale = w[0];
2189        rad = w[1];
2190//      len = w[2]
2191        endRad = w[2];
2192        sldc = w[3];
2193        slds = w[4];
2194        bkg = w[5];
2195       
2196        len = 0.01;
2197       
2198        CLens_tmp[0] = w[0];
2199        CLens_tmp[1] = w[1];
2200        CLens_tmp[2] = len;                     //length is some small number, essentially zero
2201        CLens_tmp[3] = w[2];
2202        CLens_tmp[4] = w[3];
2203        CLens_tmp[5] = w[4];
2204        CLens_tmp[6] = w[5];
2205               
2206        hDist = -1.0*sqrt(fabs(endRad*endRad-rad*rad));         //by definition for this model
2207       
2208        contr = sldc-slds;
2209       
2210        Pi = 4.0*atan(1.0);
2211        va = 0.0;
2212        vb = Pi/2.0;            //orintational average, outer integral
2213        vaj = -1.0*hDist/endRad;
2214        vbj = 1.0;              //endpoints of inner integral
2215
2216        summ = 0.0;                     //initialize intergral
2217
2218        for(i=0;i<nordi;i++) {
2219                //setup inner integral over the ellipsoidal cross-section
2220                summj=0.0;
2221                zi = ( Gauss76Z[i]*(vb-va) + va + vb )/2.0;             //the "theta" dummy
2222               
2223                for(j=0;j<nordj;j++) {
2224                        //20 gauss points for the inner integral
2225                        zij = ( Gauss76Z[j]*(vbj-vaj) + vaj + vbj )/2.0;                //the "t" dummy
2226                        yyy = Gauss76Wt[j] * ConvLens_kernel(CLens_tmp,x,zij,zi);
2227                        summj += yyy;
2228                }
2229                //now calculate the value of the inner integral
2230                inner = (vbj-vaj)/2.0*summj;
2231                inner *= 4.0*Pi*endRad*endRad*endRad;
2232               
2233                //now calculate outer integrand
2234                arg1 = x*len/2.0*cos(zi);
2235                arg2 = x*rad*sin(zi);
2236                yyy = inner;
2237               
2238                if(arg2 == 0) {
2239                        be = 0.5;
2240                } else {
2241                        be = NR_BessJ1(arg2)/arg2;
2242                }
2243               
2244                if(arg1 == 0.0) {               //limiting value of sinc(0) is 1; sinc is not defined in math.h
2245                        yyy += Pi*rad*rad*len*2.0*be;
2246                } else {
2247                        yyy += Pi*rad*rad*len*sin(arg1)/arg1*2.0*be;
2248                }
2249                yyy *= yyy;
2250                yyy *= sin(zi);         // = |A(q)|^2*sin(theta)
2251                yyy *= Gauss76Wt[i];
2252                summ += yyy;
2253        }               //final scaling is done at the end of the function, after the NT_FP64 case
2254       
2255        answer = (vb-va)/2.0*summ;
2256
2257        hh = fabs(hDist);               //need positive value for spherical cap volume
2258        answer /= 2.0*(1.0/3.0*Pi*(endRad-hh)*(endRad-hh)*(2.0*endRad+hh));             //divide by volume
2259        answer *= 1.0e8;                //convert to cm^-1
2260        answer *= contr*contr;
2261        answer *= scale;
2262        answer += bkg;
2263               
2264        return answer;
2265}
2266
2267/*      Capped Cylinder  : special case where L is nonzero and hDist < 0
2268
2269 -- uses the same Kernel as the Convex Lens
2270 
2271Uses 76 pt Gaussian quadrature for both integrals
2272*/
2273double
2274CappedCylinder(double w[], double x)
2275{
2276        int i,j;
2277        double Pi;
2278        double scale,contr,bkg,sldc,slds;
2279        double len,rad,hDist,endRad;
2280        int nordi=76;                   //order of integration
2281        int nordj=76;
2282        double va,vb;           //upper and lower integration limits
2283        double summ,zi,yyy,answer;                      //running tally of integration
2284        double summj,vaj,vbj,zij;                       //for the inner integration
2285        double arg1,arg2,inner,hh,be;
2286       
2287       
2288        scale = w[0];
2289        rad = w[1];
2290        len = w[2];
2291        endRad = w[3];
2292        sldc = w[4];
2293        slds = w[5];
2294        bkg = w[6];
2295               
2296        hDist = -1.0*sqrt(fabs(endRad*endRad-rad*rad));         //by definition for this model
2297       
2298        contr = sldc-slds;
2299       
2300        Pi = 4.0*atan(1.0);
2301        va = 0.0;
2302        vb = Pi/2.0;            //orintational average, outer integral
2303        vaj = -1.0*hDist/endRad;
2304        vbj = 1.0;              //endpoints of inner integral
2305
2306        summ = 0.0;                     //initialize intergral
2307
2308        for(i=0;i<nordi;i++) {
2309                //setup inner integral over the ellipsoidal cross-section
2310                summj=0.0;
2311                zi = ( Gauss76Z[i]*(vb-va) + va + vb )/2.0;             //the "theta" dummy
2312               
2313                for(j=0;j<nordj;j++) {
2314                        //20 gauss points for the inner integral
2315                        zij = ( Gauss76Z[j]*(vbj-vaj) + vaj + vbj )/2.0;                //the "t" dummy
2316                        yyy = Gauss76Wt[j] * ConvLens_kernel(w,x,zij,zi);               //uses the same kernel as ConvexLens, except here L != 0
2317                        summj += yyy;
2318                }
2319                //now calculate the value of the inner integral
2320                inner = (vbj-vaj)/2.0*summj;
2321                inner *= 4.0*Pi*endRad*endRad*endRad;
2322               
2323                //now calculate outer integrand
2324                arg1 = x*len/2.0*cos(zi);
2325                arg2 = x*rad*sin(zi);
2326                yyy = inner;
2327               
2328                if(arg2 == 0) {
2329                        be = 0.5;
2330                } else {
2331                        be = NR_BessJ1(arg2)/arg2;
2332                }
2333               
2334                if(arg1 == 0.0) {               //limiting value of sinc(0) is 1; sinc is not defined in math.h
2335                        yyy += Pi*rad*rad*len*2.0*be;
2336                } else {
2337                        yyy += Pi*rad*rad*len*sin(arg1)/arg1*2.0*be;
2338                }
2339               
2340               
2341               
2342                yyy *= yyy;
2343                yyy *= sin(zi);         // = |A(q)|^2*sin(theta)
2344                yyy *= Gauss76Wt[i];
2345                summ += yyy;
2346        }               //final scaling is done at the end of the function, after the NT_FP64 case
2347       
2348        answer = (vb-va)/2.0*summ;
2349
2350        hh = fabs(hDist);               //need positive value for spherical cap volume
2351        answer /= Pi*rad*rad*len + 2.0*(1.0/3.0*Pi*(endRad-hh)*(endRad-hh)*(2.0*endRad+hh));            //divide by volume
2352        answer *= 1.0e8;                //convert to cm^-1
2353        answer *= contr*contr;
2354        answer *= scale;
2355        answer += bkg;
2356               
2357        return answer;
2358}
2359
2360
2361
2362// inner integral of the ConvexLens model, special case where L ~ 0 and hDist < 0
2363//
2364double
2365ConvLens_kernel(double w[], double x, double tt, double theta) {
2366
2367        double val,arg1,arg2;
2368        double scale,bkg,sldc,slds;
2369        double len,rad,hDist,endRad,be;
2370        scale = w[0];
2371        rad = w[1];
2372        len = w[2];
2373        endRad = w[3];
2374        sldc = w[4];
2375        slds = w[5];
2376        bkg = w[6];
2377       
2378        hDist = -1.0*sqrt(fabs(endRad*endRad-rad*rad));
2379               
2380        arg1 = x*cos(theta)*(endRad*tt+hDist+len/2.0);
2381        arg2 = x*endRad*sin(theta)*sqrt(1.0-tt*tt);
2382       
2383        if(arg2 == 0) {
2384                be = 0.5;
2385        } else {
2386                be = NR_BessJ1(arg2)/arg2;
2387        }
2388       
2389        val = cos(arg1)*(1.0-tt*tt)*be;
2390       
2391        return(val);
2392}
2393
2394
2395/*      Dumbbell  : special case where L ~ 0 and hDist > 0
2396
2397Uses 76 pt Gaussian quadrature for both integrals
2398*/
2399double
2400Dumbbell(double w[], double x)
2401{
2402        int i,j;
2403        double Pi;
2404        double scale,contr,bkg,sldc,slds;
2405        double len,rad,hDist,endRad;
2406        int nordi=76;                   //order of integration
2407        int nordj=76;
2408        double va,vb;           //upper and lower integration limits
2409        double summ,zi,yyy,answer;                      //running tally of integration
2410        double summj,vaj,vbj,zij;                       //for the inner integration
2411        double Dumb_tmp[7],arg1,arg2,inner,be;
2412       
2413       
2414        scale = w[0];
2415        rad = w[1];
2416//      len = w[2]
2417        endRad = w[2];
2418        sldc = w[3];
2419        slds = w[4];
2420        bkg = w[5];
2421       
2422        len = 0.01;
2423       
2424        Dumb_tmp[0] = w[0];
2425        Dumb_tmp[1] = w[1];
2426        Dumb_tmp[2] = len;              //length is some small number, essentially zero
2427        Dumb_tmp[3] = w[2];
2428        Dumb_tmp[4] = w[3];
2429        Dumb_tmp[5] = w[4];
2430        Dumb_tmp[6] = w[5];
2431                       
2432        hDist = sqrt(fabs(endRad*endRad-rad*rad));              //by definition for this model
2433       
2434        contr = sldc-slds;
2435       
2436        Pi = 4.0*atan(1.0);
2437        va = 0.0;
2438        vb = Pi/2.0;            //orintational average, outer integral
2439        vaj = -1.0*hDist/endRad;
2440        vbj = 1.0;              //endpoints of inner integral
2441
2442        summ = 0.0;                     //initialize intergral
2443
2444        for(i=0;i<nordi;i++) {
2445                //setup inner integral over the ellipsoidal cross-section
2446                summj=0.0;
2447                zi = ( Gauss76Z[i]*(vb-va) + va + vb )/2.0;             //the "theta" dummy
2448               
2449                for(j=0;j<nordj;j++) {
2450                        //20 gauss points for the inner integral
2451                        zij = ( Gauss76Z[j]*(vbj-vaj) + vaj + vbj )/2.0;                //the "t" dummy
2452                        yyy = Gauss76Wt[j] * Dumb_kernel(Dumb_tmp,x,zij,zi);
2453                        summj += yyy;
2454                }
2455                //now calculate the value of the inner integral
2456                inner = (vbj-vaj)/2.0*summj;
2457                inner *= 4.0*Pi*endRad*endRad*endRad;
2458               
2459                //now calculate outer integrand
2460                arg1 = x*len/2.0*cos(zi);
2461                arg2 = x*rad*sin(zi);
2462                yyy = inner;
2463               
2464                if(arg2 == 0) {
2465                        be = 0.5;
2466                } else {
2467                        be = NR_BessJ1(arg2)/arg2;
2468                }
2469               
2470                if(arg1 == 0.0) {               //limiting value of sinc(0) is 1; sinc is not defined in math.h
2471                        yyy += Pi*rad*rad*len*2.0*be;
2472                } else {
2473                        yyy += Pi*rad*rad*len*sin(arg1)/arg1*2.0*be;
2474                }
2475                yyy *= yyy;
2476                yyy *= sin(zi);         // = |A(q)|^2*sin(theta)
2477                yyy *= Gauss76Wt[i];
2478                summ += yyy;
2479        }               //final scaling is done at the end of the function, after the NT_FP64 case
2480       
2481        answer = (vb-va)/2.0*summ;
2482
2483        answer /= 2.0*Pi*(2.0*endRad*endRad*endRad/3.0+endRad*endRad*hDist-hDist*hDist*hDist/3.0);              //divide by volume
2484        answer *= 1.0e8;                //convert to cm^-1
2485        answer *= contr*contr;
2486        answer *= scale;
2487        answer += bkg;
2488               
2489        return answer;
2490}
2491
2492
2493/*      Barbell  : "normal" case where L is nonzero 0 and hDist > 0
2494
2495-- uses the same kernel as the Dumbbell case
2496
2497Uses 76 pt Gaussian quadrature for both integrals
2498*/
2499double
2500Barbell(double w[], double x)
2501{
2502        int i,j;
2503        double Pi;
2504        double scale,contr,bkg,sldc,slds;
2505        double len,rad,hDist,endRad;
2506        int nordi=76;                   //order of integration
2507        int nordj=76;
2508        double va,vb;           //upper and lower integration limits
2509        double summ,zi,yyy,answer;                      //running tally of integration
2510        double summj,vaj,vbj,zij;                       //for the inner integration
2511        double arg1,arg2,inner,be;
2512       
2513       
2514        scale = w[0];
2515        rad = w[1];
2516        len = w[2];
2517        endRad = w[3];
2518        sldc = w[4];
2519        slds = w[5];
2520        bkg = w[6];
2521                       
2522        hDist = sqrt(fabs(endRad*endRad-rad*rad));              //by definition for this model
2523       
2524        contr = sldc-slds;
2525       
2526        Pi = 4.0*atan(1.0);
2527        va = 0.0;
2528        vb = Pi/2.0;            //orintational average, outer integral
2529        vaj = -1.0*hDist/endRad;
2530        vbj = 1.0;              //endpoints of inner integral
2531
2532        summ = 0.0;                     //initialize intergral
2533
2534        for(i=0;i<nordi;i++) {
2535                //setup inner integral over the ellipsoidal cross-section
2536                summj=0.0;
2537                zi = ( Gauss76Z[i]*(vb-va) + va + vb )/2.0;             //the "theta" dummy
2538               
2539                for(j=0;j<nordj;j++) {
2540                        //20 gauss points for the inner integral
2541                        zij = ( Gauss76Z[j]*(vbj-vaj) + vaj + vbj )/2.0;                //the "t" dummy
2542                        yyy = Gauss76Wt[j] * Dumb_kernel(w,x,zij,zi);           //uses the same Kernel as the Dumbbell, here L>0
2543                        summj += yyy;
2544                }
2545                //now calculate the value of the inner integral
2546                inner = (vbj-vaj)/2.0*summj;
2547                inner *= 4.0*Pi*endRad*endRad*endRad;
2548               
2549                //now calculate outer integrand
2550                arg1 = x*len/2.0*cos(zi);
2551                arg2 = x*rad*sin(zi);
2552                yyy = inner;
2553               
2554                if(arg2 == 0) {
2555                        be = 0.5;
2556                } else {
2557                        be = NR_BessJ1(arg2)/arg2;
2558                }
2559               
2560                if(arg1 == 0.0) {               //limiting value of sinc(0) is 1; sinc is not defined in math.h
2561                        yyy += Pi*rad*rad*len*2.0*be;
2562                } else {
2563                        yyy += Pi*rad*rad*len*sin(arg1)/arg1*2.0*be;
2564                }
2565                yyy *= yyy;
2566                yyy *= sin(zi);         // = |A(q)|^2*sin(theta)
2567                yyy *= Gauss76Wt[i];
2568                summ += yyy;
2569        }               //final scaling is done at the end of the function, after the NT_FP64 case
2570       
2571        answer = (vb-va)/2.0*summ;
2572
2573        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
2574        answer *= 1.0e8;                //convert to cm^-1
2575        answer *= contr*contr;
2576        answer *= scale;
2577        answer += bkg;
2578               
2579        return answer;
2580}
2581
2582
2583
2584// inner integral of the Dumbbell model, special case where L ~ 0 and hDist > 0
2585//
2586// inner integral of the Barbell model if L is nonzero
2587//
2588double
2589Dumb_kernel(double w[], double x, double tt, double theta) {
2590
2591        double val,arg1,arg2;
2592        double scale,bkg,sldc,slds;
2593        double len,rad,hDist,endRad,be;
2594        scale = w[0];
2595        rad = w[1];
2596        len = w[2];
2597        endRad = w[3];
2598        sldc = w[4];
2599        slds = w[5];
2600        bkg = w[6];
2601       
2602        hDist = sqrt(fabs(endRad*endRad-rad*rad));
2603               
2604        arg1 = x*cos(theta)*(endRad*tt+hDist+len/2.0);
2605        arg2 = x*endRad*sin(theta)*sqrt(1.0-tt*tt);
2606       
2607        if(arg2 == 0) {
2608                be = 0.5;
2609        } else {
2610                be = NR_BessJ1(arg2)/arg2;
2611        }
2612        val = cos(arg1)*(1.0-tt*tt)*be;
2613       
2614        return(val);
2615}
2616
2617double PolyCoreBicelle(double dp[], double q)
2618{
2619        int i;
2620        int nord = 20;
2621        double scale, length, sigma, bkg, radius, radthick, facthick;
2622        double rhoc, rhoh, rhor, rhosolv;
2623        double answer, Vpoly;
2624        double Pi,lolim,uplim,summ,yyy,rad,AR,Rsqr,Rsqrsumm,Rsqryyy;
2625       
2626        scale = dp[0];
2627        radius = dp[1];
2628        sigma = dp[2];                          //sigma is the standard mean deviation
2629        length = dp[3];
2630        radthick = dp[4];
2631        facthick= dp[5];
2632        rhoc = dp[6];
2633        rhoh = dp[7];
2634        rhor=dp[8];
2635        rhosolv = dp[9];
2636        bkg = dp[10];
2637       
2638        Pi = 4.0*atan(1.0);
2639       
2640        lolim = exp(log(radius)-(4.*sigma));
2641        if (lolim<0.0) {
2642                lolim=0.0;              //to avoid numerical error when  va<0 (-ve r value)
2643        }
2644        uplim = exp(log(radius)+(4.*sigma));
2645       
2646        summ = 0.0;
2647        Rsqrsumm = 0.0;
2648       
2649        for(i=0;i<nord;i++) {
2650                rad = ( Gauss20Z[i]*(uplim-lolim) + uplim + lolim )/2.0;
2651                AR=(1.0/(rad*sigma*sqrt(2.0*Pi)))*exp(-(0.5*((log(radius/rad))/sigma)*((log(radius/rad))/sigma)));
2652                yyy = AR* Gauss20Wt[i] * BicelleIntegration(q,rad,radthick,facthick,rhoc,rhoh,rhor,rhosolv,length);
2653                Rsqryyy= Gauss20Wt[i] * AR * (rad+radthick)*(rad+radthick);             //SRK normalize to total dimensions
2654                summ += yyy;
2655                Rsqrsumm += Rsqryyy;
2656        }
2657       
2658        answer = (uplim-lolim)/2.0*summ;
2659        Rsqr = (uplim-lolim)/2.0*Rsqrsumm;
2660        //normalize by average cylinder volume
2661        Vpoly = Pi*Rsqr*(length+2*facthick);
2662        answer /= Vpoly;
2663        //convert to [cm-1]
2664        answer *= 1.0e8;
2665        //Scale
2666        answer *= scale;
2667        // add in the background
2668        answer += bkg;
2669               
2670        return answer;
2671       
2672}
2673
2674double
2675BicelleIntegration(double qq, double rad, double radthick, double facthick, double rhoc, double rhoh, double rhor, double rhosolv, double length){
2676
2677        double answer,halfheight,Pi;
2678        double lolim,uplim,summ,yyy,zi;
2679        int nord,i;
2680       
2681        // set up the integration end points
2682        Pi = 4.0*atan(1.0);
2683        nord = 76;
2684        lolim = 0.0;
2685        uplim = Pi/2;
2686        halfheight = length/2.0;
2687       
2688        summ = 0.0;                             // initialize integral
2689        i=0;
2690        for(i=0;i<nord;i++) {
2691                zi = ( Gauss76Z[i]*(uplim-lolim) + uplim + lolim )/2.0;
2692                yyy = Gauss76Wt[i] * BicelleKernel(qq, rad, radthick, facthick, rhoc, rhoh, rhor,rhosolv, halfheight, zi);
2693                summ += yyy;
2694        }
2695       
2696        // calculate value of integral to return
2697        answer = (uplim-lolim)/2.0*summ;
2698        return(answer); 
2699}
2700
2701double
2702BicelleKernel(double qq, double rad, double radthick, double facthick, double rhoc, double rhoh, double rhor, double rhosolv, double length, double dum)
2703{
2704        double dr1,dr2,dr3;
2705        double besarg1,besarg2;
2706        double vol1,vol2,vol3;
2707        double sinarg1,sinarg2;
2708        double t1,t2,t3;
2709        double retval,si1,si2,be1,be2;
2710       
2711        double Pi = 4.0*atan(1.0);
2712       
2713        dr1 = rhoc-rhoh;
2714        dr2 = rhor-rhosolv;
2715        dr3=  rhoh-rhor;
2716        vol1 = Pi*rad*rad*(2.0*length);
2717        vol2 = Pi*(rad+radthick)*(rad+radthick)*(2.0*length+2.0*facthick);
2718        vol3= Pi*(rad)*(rad)*(2.0*length+2.0*facthick);
2719        besarg1 = qq*rad*sin(dum);
2720        besarg2 = qq*(rad+radthick)*sin(dum);
2721        sinarg1 = qq*length*cos(dum);
2722        sinarg2 = qq*(length+facthick)*cos(dum);
2723       
2724        if(besarg1 == 0) {
2725                be1 = 0.5;
2726        } else {
2727                be1 = NR_BessJ1(besarg1)/besarg1;
2728        }
2729        if(besarg2 == 0) {
2730                be2 = 0.5;
2731        } else {
2732                be2 = NR_BessJ1(besarg2)/besarg2;
2733        }       
2734        if(sinarg1 == 0) {
2735                si1 = 1.0;
2736        } else {
2737                si1 = sin(sinarg1)/sinarg1;
2738        }
2739        if(sinarg2 == 0) {
2740                si2 = 1.0;
2741        } else {
2742                si2 = sin(sinarg2)/sinarg2;
2743        }
2744        t1 = 2.0*vol1*dr1*si1*be1;
2745        t2 = 2.0*vol2*dr2*si2*be2;
2746        t3 = 2.0*vol3*dr3*si2*be1;
2747       
2748        retval = ((t1+t2+t3)*(t1+t2+t3))*sin(dum);
2749        return(retval);
2750       
2751}
2752
2753
2754double
2755CSPPKernel(double dp[], double mu, double uu)
2756{       
2757        double aa,bb,cc, ta,tb,tc; 
2758        double Vin,Vot,V1,V2;
2759        double rhoA,rhoB,rhoC, rhoP, rhosolv;
2760        double dr0, drA,drB, drC;
2761        double arg1,arg2,arg3,arg4,t1,t2, t3, t4;
2762        double Pi,retVal;
2763
2764        aa = dp[1];
2765        bb = dp[2];
2766        cc = dp[3];
2767        ta = dp[4];
2768        tb = dp[5];
2769        tc = dp[6];
2770        rhoA=dp[7];
2771        rhoB=dp[8];
2772        rhoC=dp[9];
2773        rhoP=dp[10];
2774        rhosolv=dp[11];
2775        dr0=rhoP-rhosolv;
2776        drA=rhoA-rhosolv;
2777        drB=rhoB-rhosolv;
2778        drC=rhoC-rhosolv; 
2779        Vin=(aa*bb*cc);
2780        Vot=(aa*bb*cc+2.0*ta*bb*cc+2.0*aa*tb*cc+2.0*aa*bb*tc);
2781        V1=(2.0*ta*bb*cc);   //  incorrect V1 (aa*bb*cc+2*ta*bb*cc)
2782        V2=(2.0*aa*tb*cc);  // incorrect V2(aa*bb*cc+2*aa*tb*cc)
2783        aa = aa/bb;
2784        ta=(aa+2.0*ta)/bb;
2785        tb=(aa+2.0*tb)/bb;
2786       
2787        Pi = 4.0*atan(1.0);
2788       
2789        arg1 = (mu*aa/2.0)*sin(Pi*uu/2.0);
2790        arg2 = (mu/2.0)*cos(Pi*uu/2.0);
2791        arg3=  (mu*ta/2.0)*sin(Pi*uu/2.0);
2792        arg4=  (mu*tb/2.0)*cos(Pi*uu/2.0);
2793                         
2794        if(arg1==0.0){
2795                t1 = 1.0;
2796        } else {
2797                t1 = (sin(arg1)/arg1);                //defn for CSPP model sin(arg1)/arg1    test:  (sin(arg1)/arg1)*(sin(arg1)/arg1)   
2798        }
2799        if(arg2==0.0){
2800                t2 = 1.0;
2801        } else {
2802                t2 = (sin(arg2)/arg2);           //defn for CSPP model sin(arg2)/arg2   test: (sin(arg2)/arg2)*(sin(arg2)/arg2)   
2803        }       
2804        if(arg3==0.0){
2805                t3 = 1.0;
2806        } else {
2807                t3 = sin(arg3)/arg3;
2808        }
2809        if(arg4==0.0){
2810                t4 = 1.0;
2811        } else {
2812                t4 = sin(arg4)/arg4;
2813        }
2814        retVal =( dr0*t1*t2*Vin + drA*(t3-t1)*t2*V1+ drB*t1*(t4-t2)*V2 )*( dr0*t1*t2*Vin + drA*(t3-t1)*t2*V1+ drB*t1*(t4-t2)*V2 );   //  correct FF : square of sum of phase factors
2815        return(retVal); 
2816
2817}
2818
2819/*      CSParallelepiped  :  calculates the form factor of a Parallelepiped with a core-shell structure
2820 -- different SLDs can be used for the face and rim
2821
2822Uses 76 pt Gaussian quadrature for both integrals
2823*/
2824double
2825CSParallelepiped(double dp[], double q)
2826{
2827        int i,j;
2828        double scale,aa,bb,cc,ta,tb,tc,rhoA,rhoB,rhoC,rhoP,rhosolv,bkg;         //local variables of coefficient wave
2829        int nordi=76;                   //order of integration
2830        int nordj=76;
2831        double va,vb;           //upper and lower integration limits
2832        double summ,yyy,answer;                 //running tally of integration
2833        double summj,vaj,vbj;                   //for the inner integration
2834        double mu,mudum,arg,sigma,uu,vol;
2835       
2836       
2837        //      Pi = 4.0*atan(1.0);
2838        va = 0.0;
2839        vb = 1.0;               //orintational average, outer integral
2840        vaj = 0.0;
2841        vbj = 1.0;              //endpoints of inner integral
2842       
2843        summ = 0.0;                     //initialize intergral
2844       
2845        scale = dp[0];
2846        aa = dp[1];
2847        bb = dp[2];
2848        cc = dp[3];
2849        ta  = dp[4];
2850        tb  = dp[5];
2851        tc  = dp[6];   // is 0 at the moment 
2852        rhoA=dp[7];   //rim A SLD
2853        rhoB=dp[8];   //rim B SLD
2854        rhoC=dp[9];    //rim C SLD
2855        rhoP = dp[10];   //Parallelpiped core SLD
2856        rhosolv=dp[11];  // Solvent SLD
2857        bkg = dp[12];
2858       
2859        mu = q*bb;
2860        vol = aa*bb*cc+2.0*ta*bb*cc+2.0*aa*tb*cc+2.0*aa*bb*tc;          //calculate volume before rescaling
2861       
2862        // do the rescaling here, not in the kernel
2863        // normalize all WRT bb
2864        aa = aa/bb;
2865        cc = cc/bb;
2866       
2867        for(i=0;i<nordi;i++) {
2868                //setup inner integral over the ellipsoidal cross-section
2869                summj=0.0;
2870                sigma = ( Gauss76Z[i]*(vb-va) + va + vb )/2.0;          //the outer dummy
2871               
2872                for(j=0;j<nordj;j++) {
2873                        //76 gauss points for the inner integral
2874                        uu = ( Gauss76Z[j]*(vbj-vaj) + vaj + vbj )/2.0;         //the inner dummy
2875                        mudum = mu*sqrt(1.0-sigma*sigma);
2876                        yyy = Gauss76Wt[j] * CSPPKernel(dp,mudum,uu);
2877                        summj += yyy;
2878                }
2879                //now calculate the value of the inner integral
2880                answer = (vbj-vaj)/2.0*summj;
2881               
2882                //finish the outer integral cc already scaled
2883                arg = mu*cc*sigma/2.0;
2884                if ( arg == 0.0 ) {
2885                        answer *= 1.0;
2886                } else {
2887                        answer *= sin(arg)*sin(arg)/arg/arg;
2888                }
2889               
2890                //now sum up the outer integral
2891                yyy = Gauss76Wt[i] * answer;
2892                summ += yyy;
2893        }               //final scaling is done at the end of the function, after the NT_FP64 case
2894       
2895        answer = (vb-va)/2.0*summ;
2896
2897        //normalize by volume
2898        answer /= vol;
2899        //convert to [cm-1]
2900        answer *= 1.0e8;
2901        //Scale
2902        answer *= scale;
2903        // add in the background
2904        answer += bkg;
2905       
2906        return answer;
2907}
2908
Note: See TracBrowser for help on using the repository browser.