File: barbell.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 (150 lines) | stat: -rw-r--r-- 5,295 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
//barbell kernel - same as dumbbell
static double
_bell_kernel(double qab, double qc, double h, double radius_bell,
             double half_length)
{
    // translate a point in [-1,1] to a point in [lower,upper]
    const double upper = 1.0;
    const double lower = -h/radius_bell;
    const double zm = 0.5*(upper-lower);
    const double zb = 0.5*(upper+lower);

    // cos term in integral is:
    //    cos (q (R t - h + L/2) cos(alpha))
    // so turn it into:
    //    cos (m t + b)
    // where:
    //    m = q R cos(alpha)
    //    b = q(L/2-h) cos(alpha)
    const double m = radius_bell*qc; // cos argument slope
    const double b = (half_length+h)*qc; // cos argument intercept
    const double qab_r = radius_bell*qab; // Q*R*sin(theta)
    double total = 0.0;
    for (int i = 0; i < GAUSS_N; i++){
        const double t = GAUSS_Z[i]*zm + zb;
        const double radical = 1.0 - t*t;
        const double bj = sas_2J1x_x(qab_r*sqrt(radical));
        const double Fq = cos(m*t + b) * radical * bj;
        total += GAUSS_W[i] * Fq;
    }
    // translate dx in [-1,1] to dx in [lower,upper]
    const double integral = total*zm;
    const double bell_fq = 2.0*M_PI*cube(radius_bell)*integral;
    return bell_fq;
}

static double
_fq(double qab, double qc, double h,
    double radius_bell, double radius, double half_length)
{
    const double bell_fq = _bell_kernel(qab, qc, h, radius_bell, half_length);
    const double bj = sas_2J1x_x(radius*qab);
    const double si = sas_sinx_x(half_length*qc);
    const double cyl_fq = 2.0*M_PI*radius*radius*half_length*bj*si;
    const double Aq = bell_fq + cyl_fq;
    return Aq;
}

static double
form_volume(double radius_bell,
    double radius,
    double length)
{
    // bell radius should never be less than radius when this is called
    const double h = sqrt(square(radius_bell) - square(radius));
    const double slice = M_PI*(square(radius_bell)*h - cube(h)/3.0);
    const double hemisphere = 2.0*M_PI/3.0*cube(radius_bell);
    const double rod = M_PI*square(radius)*length;
    // h > 0 so slice is added to hemisphere
    return rod + 2.0*(hemisphere + slice);
}

static double
radius_from_excluded_volume(double radius_bell, double radius, double length)
{
    const double h = sqrt(square(radius_bell) - square(radius));
    const double length_tot = length + 2.0*(radius + h);
    // Use cylinder excluded volume with length' = length + caps and
    // radius' = bell radius since the bell is bigger than the cylinder.
    return 0.5*cbrt(0.75*radius_bell*(2.0*radius_bell*length_tot
           + (radius_bell + length_tot)*(M_PI*radius_bell + length_tot)));
}

static double
radius_from_volume(double radius_bell, double radius, double length)
{
    const double vol_barbell = form_volume(radius_bell,radius,length);
    return cbrt(vol_barbell/M_4PI_3);
}

static double
radius_from_totallength(double radius_bell, double radius, double length)
{
    const double h = sqrt(square(radius_bell) - square(radius));
    const double half_length = 0.5*length;
    return half_length + radius_bell + h;
}

static double
radius_effective(int mode, double radius_bell, double radius, double length)
{
    switch (mode) {
    default:
    case 1: // equivalent cylinder excluded volume
        return radius_from_excluded_volume(radius_bell, radius , length);
    case 2: // equivalent volume sphere
        return radius_from_volume(radius_bell, radius , length);
    case 3: // radius
        return radius;
    case 4: // half length
        return 0.5*length;
    case 5: // half total length
        return radius_from_totallength(radius_bell,radius,length);
    }
}

static void
Fq(double q,double *F1, double *F2, double sld, double solvent_sld,
    double radius_bell, double radius, double length)
{
    const double h = sqrt(square(radius_bell) - square(radius));
    const double half_length = 0.5*length;

    // translate a point in [-1,1] to a point in [0, pi/2]
    const double zm = M_PI_4;
    const double zb = M_PI_4;
    double total_F1 = 0.0;
    double total_F2 = 0.0;
    for (int i = 0; i < GAUSS_N; i++){
        const double theta = GAUSS_Z[i]*zm + zb;
        double sin_theta, cos_theta; // slots to hold sincos function output
        SINCOS(theta, sin_theta, cos_theta);
        const double qab = q*sin_theta;
        const double qc = q*cos_theta;
        const double Aq = _fq(qab, qc, h, radius_bell, radius, half_length);
        // scale by sin_theta for spherical coord integration
        total_F1 += GAUSS_W[i] * Aq * sin_theta;
        total_F2 += GAUSS_W[i] * Aq * Aq * sin_theta;
    }
    // translate dx in [-1,1] to dx in [lower,upper]
    const double form_avg = total_F1 * zm;
    const double form_squared_avg = total_F2 * zm;

    //Contrast
    const double s = (sld - solvent_sld);
    *F1 = 1.0e-2 * s * form_avg;
    *F2 = 1.0e-4 * s * s * form_squared_avg;
}

static double
Iqac(double qab, double qc,
    double sld, double solvent_sld,
    double radius_bell, double radius, double length)
{
    const double h = sqrt(square(radius_bell) - square(radius));
    const double Aq = _fq(qab, qc, h, radius_bell, radius, 0.5*length);

    // Multiply by contrast^2 and convert to cm-1
    const double s = (sld - solvent_sld);
    return 1.0e-4 * square(s * Aq);
}