File: hollow_rectangular_prism_thin_walls.c

package info (click to toggle)
mccode 3.5.19%2Bds5-2
  • links: PTS, VCS
  • area: main
  • in suites: 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 (131 lines) | stat: -rw-r--r-- 4,720 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
static double
shell_volume(double length_a, double b2a_ratio, double c2a_ratio)
{
    const double length_b = length_a * b2a_ratio;
    const double length_c = length_a * c2a_ratio;
    const double shell_volume = 2.0 * (length_a*length_b + length_a*length_c + length_b*length_c);
    return shell_volume;
}

static double
form_volume(double length_a, double b2a_ratio, double c2a_ratio)
{
    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)
{
    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)
{
    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;

   //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;
        double sin_c, cos_c;
        SINCOS(theta, sin_theta, cos_theta);
        SINCOS(q*c_half*cos_theta, sin_c, cos_c);

        // To check potential problems if denominator goes to zero here !!!
        const double termAL_theta = 8.0 * cos_c / (q*q*sin_theta*sin_theta);
        const double termAT_theta = 8.0 * sin_c / (q*q*sin_theta*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;
            double sin_a, cos_a;
            double sin_b, cos_b;
            SINCOS(phi, sin_phi, cos_phi);
            SINCOS(q*a_half*sin_theta*sin_phi, sin_a, cos_a);
            SINCOS(q*b_half*sin_theta*cos_phi, sin_b, cos_b);

            // Amplitude AL from eqn. (7c)
            const double AL = termAL_theta
                * sin_a*sin_b / (sin_phi*cos_phi);

            // Amplitude AT from eqn. (9)
            const double AT = termAT_theta
                * ( cos_a*sin_b/cos_phi + cos_b*sin_a/sin_phi );

            inner_sum_F1 += GAUSS_W[j] * (AL+AT);
            inner_sum_F2 += GAUSS_W[j] * square(AL+AT);
        }

        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 = 1e-2 * contrast * form_avg;
    *F2 = 1e-4 * contrast * contrast * form_squared_avg;
}