source: sasmodels/explore/sc.c @ 10ee838

core_shell_microgelsmagnetic_modelticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since 10ee838 was 64ca163, checked in by Paul Kienzle <pkienzle@…>, 8 years ago

add code to switch between sc/bcc/fcc in explore/sc.c

  • Property mode set to 100644
File size: 4.5 KB
RevLine 
[fdd56a1]1static double
[7e0b281]2sc_Zq(double qa, double qb, double qc, double dnn, double d_factor)
[fdd56a1]3{
4    // Rewriting equations for efficiency, accuracy and readability, and so
5    // code is reusable between 1D and 2D models.
[64ca163]6    #if 1  // SC
[fdd56a1]7    const double a1 = qa;
8    const double a2 = qb;
9    const double a3 = qc;
[64ca163]10    #elif 1 // BCC
11    const double a1 = (+qa + qb + qc)/2.;
12    const double a2 = (-qa - qb + qc)/2.;
13    const double a3 = (-qa + qb - qc)/2.;
14    #elif 1 // FCC
15    const double a1 = ( qa + qb)/2.0;
16    const double a2 = (-qa + qc)/2.0;
17    const double a3 = (-qa + qb)/2.0;
18    #endif
[fdd56a1]19
[7e0b281]20    const double arg = -0.5*square(dnn*d_factor)*(a1*a1 + a2*a2 + a3*a3);
[fdd56a1]21
22    // Numerator: (1 - exp(a)^2)^3
23    //         => (-(exp(2a) - 1))^3
24    //         => -expm1(2a)^3
25    // Denominator: prod(1 - 2 cos(xk) exp(a) + exp(a)^2)
26    //         => exp(a)^2 - 2 cos(xk) exp(a) + 1
27    //         => (exp(a) - 2 cos(xk)) * exp(a) + 1
[7e0b281]28    const double exp_arg = exp(arg);
29    const double Zq = -cube(expm1(2.0*arg))
[fdd56a1]30        / ( ((exp_arg - 2.0*cos(dnn*a1))*exp_arg + 1.0)
31          * ((exp_arg - 2.0*cos(dnn*a2))*exp_arg + 1.0)
32          * ((exp_arg - 2.0*cos(dnn*a3))*exp_arg + 1.0));
33
[7e0b281]34    return Zq;
[fdd56a1]35}
36
37// occupied volume fraction calculated from lattice symmetry and sphere radius
38static double
[7e0b281]39sc_volume_fraction(double radius, double dnn)
[fdd56a1]40{
41    return sphere_volume(radius/dnn);
42}
43
44static double
45form_volume(double radius)
46{
47    return sphere_volume(radius);
48}
49
50
51static double Iq(double q, double dnn,
52  double d_factor, double radius,
53  double sld, double solvent_sld,
54  double n, double sym)
55{
56double phi_m, phi_b, theta_m, theta_b;
57if (sym>0.) {
58    // translate a point in [-1,1] to a point in [0, 2 pi]
59    phi_m = M_PI_4;
60    phi_b = M_PI_4;
61    // translate a point in [-1,1] to a point in [0, pi]
62    theta_m = M_PI_4;
63    theta_b = M_PI_4;
64} else {
65    // translate a point in [-1,1] to a point in [0, 2 pi]
66    phi_m = M_PI;
67    phi_b = M_PI;
68    // translate a point in [-1,1] to a point in [0, pi]
69    theta_m = M_PI_2;
70    theta_b = M_PI_2;
71}
72
73#if 0
74    double outer_sum = 0.0;
75    for(int i=0; i<150; i++) {
76        double inner_sum = 0.0;
77        const double theta = Gauss150Z[i]*theta_m + theta_b;
78        double sin_theta, cos_theta;
79        SINCOS(theta, sin_theta, cos_theta);
80        const double qc = q*cos_theta;
81        const double qab = q*sin_theta;
82        for(int j=0;j<150;j++) {
83            const double phi = Gauss150Z[j]*phi_m + phi_b;
84            double sin_phi, cos_phi;
85            SINCOS(phi, sin_phi, cos_phi);
86            const double qa = qab*cos_phi;
87            const double qb = qab*sin_phi;
88            const double fq = _sq_sc(qa, qb, qc, dnn, d_factor);
89            inner_sum += Gauss150Wt[j] * fq;
90        }
91        inner_sum *= phi_m;  // sum(f(x)dx) = sum(f(x)) dx
92        outer_sum += Gauss150Wt[i] * inner_sum * sin_theta;
93    }
94    outer_sum *= theta_m;
95#else
96    double outer_sum = 0.0;
97    for(int i=0; i<(int)n; i++) {
98        double inner_sum = 0.0;
99        const double theta = (i*2./n-1.)*theta_m + theta_b;
100        double sin_theta, cos_theta;
101        SINCOS(theta, sin_theta, cos_theta);
102        const double qc = q*cos_theta;
103        const double qab = q*sin_theta;
104        for(int j=0;j<(int)n;j++) {
105            const double phi = (j*2./n-1.)*phi_m + phi_b;
106            double sin_phi, cos_phi;
107            SINCOS(phi, sin_phi, cos_phi);
108            const double qa = qab*cos_phi;
109            const double qb = qab*sin_phi;
[7e0b281]110            const double form = sc_Zq(qa, qb, qc, dnn, d_factor);
111            inner_sum += form;
[fdd56a1]112        }
113        inner_sum *= phi_m;  // sum(f(x)dx) = sum(f(x)) dx
114        outer_sum += inner_sum * sin_theta;
115    }
116    outer_sum *= theta_m/(n*n);
117#endif
[7e0b281]118double Zq;
[fdd56a1]119if (sym > 0.) {
[7e0b281]120    Zq = outer_sum/M_PI_2;
[fdd56a1]121} else {
[7e0b281]122    Zq = outer_sum/(4.0*M_PI);
[fdd56a1]123}
124
[64ca163]125    //return Zq;
[fdd56a1]126    const double Pq = sphere_form(q, radius, sld, solvent_sld);
[7e0b281]127    return sc_volume_fraction(radius, dnn) * Pq * Zq;
[fdd56a1]128}
129
130
131static double Iqxy(double qx, double qy,
132    double dnn, double d_factor, double radius,
133    double sld, double solvent_sld,
134    double n, double sym,
135    double theta, double phi, double psi)
136{
137    double q, zhat, yhat, xhat;
138    ORIENT_ASYMMETRIC(qx, qy, theta, phi, psi, q, xhat, yhat, zhat);
139    const double qa = q*xhat;
140    const double qb = q*yhat;
141    const double qc = q*zhat;
142
143    q = sqrt(qa*qa + qb*qb + qc*qc);
144    const double Pq = sphere_form(q, radius, sld, solvent_sld);
[7e0b281]145    const double Zq = sc_Zq(qa, qb, qc, dnn, d_factor);
[64ca163]146    return Zq;
[7e0b281]147    return sc_volume_fraction(radius, dnn) * Pq * Zq;
[64ca163]148}
Note: See TracBrowser for help on using the repository browser.