source: sasmodels/sasmodels/models/sc_crystal.c @ d507c3a

core_shell_microgelscostrafo411magnetic_modelrelease_v0.94release_v0.95ticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since d507c3a was 9aac25d, checked in by piotr, 8 years ago

Converted SCCrystalModel

  • Property mode set to 100644
File size: 5.9 KB
Line 
1double form_volume(double radius);
2
3double Iq(double q,
4          double dnn,
5          double d_factor,
6          double radius,
7          double sphere_sld,
8          double solvent_sld);
9
10double Iqxy(double qx, double qy,
11            double dnn,
12            double d_factor,
13            double radius,
14            double sphere_sld,
15            double solvent_sld,
16            double theta,
17            double phi,
18            double psi);
19
20double form_volume(double radius)
21{
22    return 1.333333333333333*M_PI*radius*radius*radius;
23}
24
25static double
26sc_eval(double theta, double phi, double temp3, double temp4, double temp5)
27{
28    double cnt, snt;
29    SINCOS(theta, cnt, snt);
30
31    double cnp, snp;
32    SINCOS(phi, cnp, snp);
33
34        double temp6 = snt;
35        double temp7 = -1.0*temp3*snt*cnp;
36        double temp8 = temp3*snt*snp;
37        double temp9 = temp3*cnt;
38        double result = temp6/((1.0-temp4*cos((temp7))+temp5)*
39                               (1.0-temp4*cos((temp8))+temp5)*
40                               (1.0-temp4*cos((temp9))+temp5));
41        return (result);
42}
43
44static double
45sc_integrand(double dnn, double d_factor, double qq, double xx, double yy)
46{
47    //Function to calculate integrand values for simple cubic structure
48
49        double da = d_factor*dnn;
50        double temp1 = qq*qq*da*da;
51        double temp2 = pow( 1.0-exp(-1.0*temp1) ,3);
52        double temp3 = qq*dnn;
53        double temp4 = 2.0*exp(-0.5*temp1);
54        double temp5 = exp(-1.0*temp1);
55
56        double integrand = temp2*sc_eval(yy,xx,temp3,temp4,temp5);
57        integrand *= 2.0/M_PI;
58
59        return(integrand);
60}
61
62static
63double sc_crystal_kernel(double q,
64          double dnn,
65          double d_factor,
66          double radius,
67          double sphere_sld,
68          double solvent_sld)
69{
70        const double va = 0.0;
71        const double vb = M_PI/2.0; //orientation average, outer integral
72
73    double summ=0.0;
74    double answer=0.0;
75
76        for(int i=0;i<150;i++) {
77                //setup inner integral over the ellipsoidal cross-section
78                double summj=0.0;
79                double zi = ( Gauss150Z[i]*(vb-va) + va + vb )/2.0;
80                for(int j=0;j<150;j++) {
81                        //150 gauss points for the inner integral
82                        double zij = ( Gauss150Z[j]*(vb-va) + va + vb )/2.0;
83                        double tmp = Gauss150Wt[j] * sc_integrand(dnn,d_factor,q,zi,zij);
84                        summj += tmp;
85                }
86                //now calculate the value of the inner integral
87                answer = (vb-va)/2.0*summj;
88
89                //now calculate outer integral
90                double tmp = Gauss150Wt[i] * answer;
91                summ += tmp;
92        }               //final scaling is done at the end of the function, after the NT_FP64 case
93
94        answer = (vb-va)/2.0*summ;
95
96        //Volume fraction calculated from lattice symmetry and sphere radius
97        const double latticeScale = (4.0/3.0)*M_PI*(radius*radius*radius)/pow(dnn,3);
98
99        //answer *= sphere_form_paracrystal(q, radius,contrast)*latticeScale;
100        answer *= sphere_form(q, radius, sphere_sld, solvent_sld)*latticeScale;
101
102        return answer;
103}
104
105static
106double sc_crystal_kernel_2d(double q, double q_x, double q_y,
107          double dnn,
108          double d_factor,
109          double radius,
110          double sphere_sld,
111          double solvent_sld,
112          double theta,
113          double phi,
114          double psi)
115{
116    //convert angle degree to radian
117    theta = theta * M_PI_180;
118    phi = phi * M_PI_180;
119    psi = psi * M_PI_180;
120
121    const double qda_2 = pow(q*d_factor*dnn,2.0);
122
123    double snt, cnt;
124    SINCOS(theta, snt, cnt);
125
126    double snp, cnp;
127    SINCOS(phi, snp, cnp);
128
129    double sns, cns;
130    SINCOS(psi, sns, cns);
131
132    /// Angles here are respect to detector coordinate instead of against
133    //  q coordinate(PRB 36, 3, 1754)
134    // a3 axis orientation
135
136    const double a3_x = cnt * cnp;
137    const double a3_y = snt;
138
139    // Compute the angle btw vector q and the a3 axis
140    double cos_val_a3 = a3_x*q_x + a3_y*q_y;
141
142    // a1 axis orientation
143    const double a1_x = -cnp*sns * snt+snp*cns;
144    const double a1_y = sns*cnt;
145
146    double cos_val_a1 = a1_x*q_x + a1_y*q_y;
147
148    // a2 axis orientation
149    const double a2_x = -snt*cns*cnp-sns*snp;
150    const double a2_y = cnt*cns;
151
152    // a2 axis
153    const double cos_val_a2 =  a2_x*q_x + a2_y*q_y;
154
155    // The following test should always pass
156    if (fabs(cos_val_a3)>1.0) {
157        //printf("parallel_ana_2D: Unexpected error: cos(alpha)>1\n");
158        cos_val_a3 = 1.0;
159    }
160    if (fabs(cos_val_a1)>1.0) {
161        //printf("parallel_ana_2D: Unexpected error: cos(alpha)>1\n");
162        cos_val_a1 = 1.0;
163    }
164    if (fabs(cos_val_a2)>1.0) {
165        //printf("parallel_ana_2D: Unexpected error: cos(alpha)>1\n");
166        cos_val_a3 = 1.0;
167    }
168
169    const double a3_dot_q = dnn*q*cos_val_a3;
170    const double a1_dot_q = dnn*q*cos_val_a1;
171    const double a2_dot_q = dnn*q*cos_val_a2;
172
173    // Call Zq=Z1*Z2*Z3
174    double Zq = (1.0-exp(-qda_2))/(1.0-2.0*exp(-0.5*qda_2)*cos(a1_dot_q)+exp(-qda_2));
175    Zq *= (1.0-exp(-qda_2))/(1.0-2.0*exp(-0.5*qda_2)*cos(a2_dot_q)+exp(-qda_2));
176    Zq *= (1.0-exp(-qda_2))/(1.0-2.0*exp(-0.5*qda_2)*cos(a3_dot_q)+exp(-qda_2));
177
178    // Use SphereForm directly from libigor
179    double answer = sphere_form(q, radius, sphere_sld, solvent_sld)*Zq;
180
181    //consider scales
182    const double latticeScale = (4.0/3.0)*M_PI*(radius*radius*radius)/pow(dnn,3.0);
183    answer *= latticeScale;
184
185    return answer;
186}
187
188double Iq(double q,
189          double dnn,
190          double d_factor,
191          double radius,
192          double sphere_sld,
193          double solvent_sld)
194{
195    return sc_crystal_kernel(q,
196              dnn,
197              d_factor,
198              radius,
199              sphere_sld,
200              solvent_sld);
201}
202
203// Iqxy is never called since no orientation or magnetic parameters.
204double Iqxy(double qx, double qy,
205            double dnn,
206            double d_factor,
207            double radius,
208            double sphere_sld,
209            double solvent_sld,
210            double theta,
211            double phi,
212            double psi)
213{
214    double q = sqrt(qx*qx + qy*qy);
215
216
217    return sc_crystal_kernel_2d(q, qx/q, qy/q,
218                  dnn,
219                  d_factor,
220                  radius,
221                  sphere_sld,
222                  solvent_sld,
223                  theta,
224                  phi,
225                  psi);
226
227}
228
Note: See TracBrowser for help on using the repository browser.