File: hollow_rectangular_prism.c

package info (click to toggle)
mccode 3.5.19%2Bds5-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,113,256 kB
  • sloc: ansic: 40,697; python: 25,137; yacc: 8,438; sh: 5,405; javascript: 4,596; lex: 1,632; cpp: 742; perl: 296; lisp: 273; makefile: 226; fortran: 132
file content (172 lines) | stat: -rw-r--r-- 6,435 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
static double
shell_volume(double length_a, double b2a_ratio, double c2a_ratio, double thickness)
{
    const double length_b = length_a * b2a_ratio;
    const double length_c = length_a * c2a_ratio;
    const double form_volume = length_a * length_b * length_c;
    const double a_core = length_a - 2.0*thickness;
    const double b_core = length_b - 2.0*thickness;
    const double c_core = length_c - 2.0*thickness;
    const double core_volume = a_core * b_core * c_core;
    return form_volume - core_volume;
}

static double
form_volume(double length_a, double b2a_ratio, double c2a_ratio, double thickness)
{
    const double length_b = length_a * b2a_ratio;
    const double length_c = length_a * c2a_ratio;
    const double form_volume = length_a * length_b * length_c;
    return form_volume;
}

static double
radius_from_excluded_volume(double length_a, double b2a_ratio, double c2a_ratio)
{
    const double r_equiv = sqrt(length_a*length_a*b2a_ratio/M_PI);
    const double length_c = length_a*c2a_ratio;
    return 0.5*cbrt(0.75*r_equiv*(2.0*r_equiv*length_c + (r_equiv + length_c)*(M_PI*r_equiv + length_c)));
}

static double
radius_effective(int mode, double length_a, double b2a_ratio, double c2a_ratio, double thickness)
// NOTE length_a is external dimension!
{
    switch (mode) {
    default:
    case 1: // equivalent cylinder excluded volume
        return radius_from_excluded_volume(length_a, b2a_ratio, c2a_ratio);
    case 2: // equivalent outer volume sphere
        return cbrt(cube(length_a)*b2a_ratio*c2a_ratio/M_4PI_3);
    case 3: // half length_a
        return 0.5 * length_a;
    case 4: // half length_b
        return 0.5 * length_a*b2a_ratio;
    case 5: // half length_c
        return 0.5 * length_a*c2a_ratio;
    case 6: // equivalent outer circular cross-section
        return length_a*sqrt(b2a_ratio/M_PI);
    case 7: // half ab diagonal
        return 0.5*sqrt(square(length_a) * (1.0 + square(b2a_ratio)));
    case 8: // half diagonal
        return 0.5*sqrt(square(length_a) * (1.0 + square(b2a_ratio) + square(c2a_ratio)));
    }
}

static void
Fq(double q,
    double *F1,
    double *F2,
    double sld,
    double solvent_sld,
    double length_a,
    double b2a_ratio,
    double c2a_ratio,
    double thickness)
{
    const double length_b = length_a * b2a_ratio;
    const double length_c = length_a * c2a_ratio;
    const double a_half = 0.5 * length_a;
    const double b_half = 0.5 * length_b;
    const double c_half = 0.5 * length_c;
    const double vol_total = length_a * length_b * length_c;
    const double vol_core = 8.0 * (a_half-thickness) * (b_half-thickness) * (c_half-thickness);

    //Integration limits to use in Gaussian quadrature
    const double v1a = 0.0;
    const double v1b = M_PI_2;  //theta integration limits
    const double v2a = 0.0;
    const double v2b = M_PI_2;  //phi integration limits

    double outer_sum_F1 = 0.0;
    double outer_sum_F2 = 0.0;
    for(int i=0; i<GAUSS_N; i++) {

        const double theta = 0.5 * ( GAUSS_Z[i]*(v1b-v1a) + v1a + v1b );
        double sin_theta, cos_theta;
        SINCOS(theta, sin_theta, cos_theta);

        const double termC1 = sas_sinx_x(q * c_half * cos(theta));
        const double termC2 = sas_sinx_x(q * (c_half-thickness)*cos(theta));

        double inner_sum_F1 = 0.0;
        double inner_sum_F2 = 0.0;
        for(int j=0; j<GAUSS_N; j++) {

            const double phi = 0.5 * ( GAUSS_Z[j]*(v2b-v2a) + v2a + v2b );
            double sin_phi, cos_phi;
            SINCOS(phi, sin_phi, cos_phi);

            // Amplitude AP from eqn. (13), rewritten to avoid round-off effects when arg=0

            const double termA1 = sas_sinx_x(q * a_half * sin_theta * sin_phi);
            const double termA2 = sas_sinx_x(q * (a_half-thickness) * sin_theta * sin_phi);

            const double termB1 = sas_sinx_x(q * b_half * sin_theta * cos_phi);
            const double termB2 = sas_sinx_x(q * (b_half-thickness) * sin_theta * cos_phi);

            const double AP1 = vol_total * termA1 * termB1 * termC1;
            const double AP2 = vol_core * termA2 * termB2 * termC2;

            inner_sum_F1 += GAUSS_W[j] * (AP1-AP2);
            inner_sum_F2 += GAUSS_W[j] * square(AP1-AP2);
        }
        inner_sum_F1 *= 0.5 * (v2b-v2a);
        inner_sum_F2 *= 0.5 * (v2b-v2a);

        outer_sum_F1 += GAUSS_W[i] * inner_sum_F1 * sin(theta);
        outer_sum_F2 += GAUSS_W[i] * inner_sum_F2 * sin(theta);
    }
    outer_sum_F1 *= 0.5*(v1b-v1a);
    outer_sum_F2 *= 0.5*(v1b-v1a);

    // Normalize as in Eqn. (15) without the volume factor (as cancels with (V*DelRho)^2 normalization)
    // The factor 2 is due to the different theta integration limit (pi/2 instead of pi)
    const double form_avg = outer_sum_F1/M_PI_2;
    const double form_squared_avg = outer_sum_F2/M_PI_2;

    // Multiply by contrast^2. Factor corresponding to volume^2 cancels with previous normalization.
    const double contrast = sld - solvent_sld;

    // Convert from [1e-12 A-1] to [cm-1]
    *F1 = 1.0e-2 * contrast * form_avg;
    *F2 = 1.0e-4 * contrast * contrast * form_squared_avg;
}

static double
Iqabc(double qa, double qb, double qc,
    double sld,
    double solvent_sld,
    double length_a,
    double b2a_ratio,
    double c2a_ratio,
    double thickness)
{
    const double length_b = length_a * b2a_ratio;
    const double length_c = length_a * c2a_ratio;
    const double a_half = 0.5 * length_a;
    const double b_half = 0.5 * length_b;
    const double c_half = 0.5 * length_c;
    const double vol_total = length_a * length_b * length_c;
    const double vol_core = 8.0 * (a_half-thickness) * (b_half-thickness) * (c_half-thickness);

    // Amplitude AP from eqn. (13)

    const double termA1 = sas_sinx_x(qa * a_half);
    const double termA2 = sas_sinx_x(qa * (a_half-thickness));

    const double termB1 = sas_sinx_x(qb * b_half);
    const double termB2 = sas_sinx_x(qb * (b_half-thickness));

    const double termC1 = sas_sinx_x(qc * c_half);
    const double termC2 = sas_sinx_x(qc * (c_half-thickness));

    const double AP1 = vol_total * termA1 * termB1 * termC1;
    const double AP2 = vol_core * termA2 * termB2 * termC2;

    // Multiply by contrast^2. Factor corresponding to volume^2 cancels with previous normalization.
    const double delrho = sld - solvent_sld;

    // Convert from [1e-12 A-1] to [cm-1]
    return 1.0e-4 * square(delrho * (AP1-AP2));
}