source: sasmodels/sasmodels/models/parallelepiped.c @ 6cefbc9

core_shell_microgelscostrafo411magnetic_modelrelease_v0.94release_v0.95ticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since 6cefbc9 was deb7ee0, checked in by gonzalezm, 8 years ago

Added four parallelepiped-like models

  • Property mode set to 100644
File size: 4.7 KB
Line 
1double form_volume(double a_side, double b_side, double c_side);
2double Iq(double q, double sld, double solvent_sld, double a_side, double b_side, double c_side);
3double Iqxy(double qx, double qy, double sld, double solvent_sld,
4    double a_side, double b_side, double c_side, double theta, double phi, double psi);
5
6// From Igor library
7double _pkernel(double a, double b,double c, double ala, double alb, double alc);
8double _pkernel(double a, double b,double c, double ala, double alb, double alc){
9    double argA,argB,argC,tmp1,tmp2,tmp3;
10    //handle arg=0 separately, as sin(t)/t -> 1 as t->0
11    argA = 0.5*a*ala;
12    argB = 0.5*b*alb;
13    argC = 0.5*c*alc;
14    if(argA==0.0) {
15        tmp1 = 1.0;
16    } else {
17        tmp1 = sin(argA)*sin(argA)/argA/argA;
18    }
19    if (argB==0.0) {
20        tmp2 = 1.0;
21    } else {
22        tmp2 = sin(argB)*sin(argB)/argB/argB;
23    }
24    if (argC==0.0) {
25        tmp3 = 1.0;
26    } else {
27        tmp3 = sin(argC)*sin(argC)/argC/argC;
28    }
29    return (tmp1*tmp2*tmp3);
30
31}
32
33
34double form_volume(double a_side, double b_side, double c_side)
35{
36    return a_side * b_side * c_side;
37}
38
39
40double Iq(double q,
41    double sld,
42    double solvent_sld,
43    double a_side,
44    double b_side,
45    double c_side)
46{
47    double tmp1, tmp2;
48   
49    double mu = q * b_side;
50   
51    // Scale sides by B
52    double a_scaled = a_side / b_side;
53    double c_scaled = c_side / b_side;
54       
55    //Order of integration
56    int nordi=76;                               
57    int nordj=76;
58
59    // outer integral (with nordi gauss points), integration limits = 0, 1
60    double summ = 0; //initialize integral
61
62    for( int i=0; i<nordi; i++) {
63               
64        // inner integral (with nordj gauss points), integration limits = 0, 1
65       
66        double summj = 0.0;
67            double sigma = 0.5 * ( Gauss76Z[i] + 1.0 );         
68               
69            for(int j=0; j<nordj; j++) {
70
71            double uu = 0.5 * ( Gauss76Z[j] + 1.0 );
72            double mudum = mu * sqrt(1.0-sigma*sigma);
73                double arg1 = 0.5 * mudum * cos(0.5*M_PI*uu);
74                double arg2 = 0.5 * mudum * a_scaled * sin(0.5*M_PI*uu);
75            if(arg1==0.0) {
76                tmp1 = 1.0;
77            } else {
78                tmp1 = sin(arg1)*sin(arg1)/arg1/arg1;
79            }
80            if (arg2==0.0) {
81                tmp2 = 1.0;
82            } else {
83                tmp2 = sin(arg2)*sin(arg2)/arg2/arg2;
84            }
85
86            summj += Gauss76Wt[j] * tmp1 * tmp2;
87        }
88               
89        // value of the inner integral
90        double answer = 0.5 * summj;
91
92        double arg = 0.5 * mu * c_scaled * sigma;
93        if ( arg == 0.0 ) {
94            answer *= 1.0;
95        } else {
96            answer *= sin(arg)*sin(arg)/arg/arg;
97        }
98               
99            // sum of outer integral
100        summ += Gauss76Wt[i] * answer;
101       
102    }   
103   
104    const double vd = (sld-solvent_sld) * form_volume(a_side, b_side, c_side);
105   
106    // convert from [1e-12 A-1] to [cm-1] and 0.5 factor for outer integral
107    return 1.0e-4 * 0.5 * vd * vd * summ;
108   
109}
110
111
112double Iqxy(double qx, double qy,
113    double sld,
114    double solvent_sld,
115    double a_side,
116    double b_side,
117    double c_side,
118    double theta,
119    double phi,
120    double psi)
121{
122    double q = sqrt(qx*qx+qy*qy);
123    double qx_scaled = qx/q;
124    double qy_scaled = qy/q;
125
126    // Convert angles given in degrees to radians
127    theta *= M_PI_180;
128    phi   *= M_PI_180;
129    psi   *= M_PI_180;
130   
131    // Parallelepiped c axis orientation
132    double cparallel_x = cos(theta) * cos(phi);
133    double cparallel_y = sin(theta);
134   
135    // Compute angle between q and parallelepiped axis
136    double cos_val_c = cparallel_x*qx_scaled + cparallel_y*qy_scaled;// + cparallel_z*qz;
137
138    // Parallelepiped a axis orientation
139    double parallel_x = -cos(phi)*sin(psi) * sin(theta)+sin(phi)*cos(psi);
140    double parallel_y = sin(psi)*cos(theta);
141    double cos_val_a = parallel_x*qx_scaled + parallel_y*qy_scaled;
142
143    // Parallelepiped b axis orientation
144    double bparallel_x = -sin(theta)*cos(psi)*cos(phi)-sin(psi)*sin(phi);
145    double bparallel_y = cos(theta)*cos(psi);
146    double cos_val_b = bparallel_x*qx_scaled + bparallel_y*qy_scaled;
147
148    // The following tests should always pass
149    if (fabs(cos_val_c)>1.0) {
150      //printf("parallel_ana_2D: Unexpected error: cos(alpha)>1\n");
151      cos_val_c = 1.0;
152    }
153    if (fabs(cos_val_a)>1.0) {
154      //printf("parallel_ana_2D: Unexpected error: cos(alpha)>1\n");
155      cos_val_a = 1.0;
156    }
157    if (fabs(cos_val_b)>1.0) {
158      //printf("parallel_ana_2D: Unexpected error: cos(alpha)>1\n");
159      cos_val_b = 1.0;
160    }
161   
162    // Call the IGOR library function to get the kernel
163    double form = _pkernel( q*a_side, q*b_side, q*c_side, cos_val_a, cos_val_b, cos_val_c);
164 
165    // Multiply by contrast^2
166    const double vd = (sld - solvent_sld) * form_volume(a_side, b_side, c_side);
167    return 1.0e-4 * vd * vd * form;
168}
Note: See TracBrowser for help on using the repository browser.