File: triaxial_ellipsoid.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 (155 lines) | stat: -rw-r--r-- 5,896 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
static double
form_volume(double radius_equat_minor, double radius_equat_major, double radius_polar)
{
    return M_4PI_3*radius_equat_minor*radius_equat_major*radius_polar;
}

static double
radius_from_curvature(double radius_equat_minor, double radius_equat_major, double radius_polar)
{
    // Trivial cases
    if (radius_equat_minor == radius_equat_major == radius_polar) return radius_polar;
    if (radius_equat_minor * radius_equat_major * radius_polar == 0.)  return 0.;


    double r_equat_equiv, r_polar_equiv;
    double radii[3] = {radius_equat_minor, radius_equat_major, radius_polar};
    double radmax = fmax(radii[0],fmax(radii[1],radii[2]));

    double radius_1 = radmax;
    double radius_2 = radmax;
    double radius_3 = radmax;

    for(int irad=0; irad<3; irad++) {
        if (radii[irad] < radius_1) {
            radius_3 = radius_2;
            radius_2 = radius_1;
            radius_1 = radii[irad];
            } else {
                if (radii[irad] < radius_2) {
                        radius_2 = radii[irad];
                }
            }
    }
    if(radius_2-radius_1 > radius_3-radius_2) {
        r_equat_equiv = sqrt(radius_2*radius_3);
        r_polar_equiv = radius_1;
    } else  {
        r_equat_equiv = sqrt(radius_1*radius_2);
        r_polar_equiv = radius_3;
    }

    // see equation (26) in A.Isihara, J.Chem.Phys. 18(1950)1446-1449
    const double ratio = (r_polar_equiv < r_equat_equiv
                          ? r_polar_equiv / r_equat_equiv
                          : r_equat_equiv / r_polar_equiv);
    const double e1 = sqrt(1.0 - ratio*ratio);
    const double b1 = 1.0 + asin(e1) / (e1 * ratio);
    const double bL = (1.0 + e1) / (1.0 - e1);
    const double b2 = 1.0 + 0.5 * ratio * ratio / e1 * log(bL);
    const double delta = 0.75 * b1 * b2;
    const double ddd = 2.0 * (delta + 1.0) * r_polar_equiv * r_equat_equiv * r_equat_equiv;
    return 0.5 * cbrt(ddd);
}

static double
radius_from_volume(double radius_equat_minor, double radius_equat_major, double radius_polar)
{
    return cbrt(radius_equat_minor*radius_equat_major*radius_polar);
}

static double
radius_from_min_dimension(double radius_equat_minor, double radius_equat_major, double radius_polar)
{
    const double rad_equat_min = (radius_equat_minor < radius_equat_major ? radius_equat_minor : radius_equat_major);
    return (rad_equat_min < radius_polar ? rad_equat_min : radius_polar);
}

static double
radius_from_max_dimension(double radius_equat_minor, double radius_equat_major, double radius_polar)
{
    const double rad_equat_max = (radius_equat_minor < radius_equat_major ? radius_equat_major : radius_equat_minor);
    return (rad_equat_max > radius_polar ? rad_equat_max : radius_polar);
}

static double
radius_effective(int mode, double radius_equat_minor, double radius_equat_major, double radius_polar)
{
    switch (mode) {
    default:
    case 1: // equivalent biaxial ellipsoid average curvature
        return radius_from_curvature(radius_equat_minor,radius_equat_major, radius_polar);
    case 2: // equivalent volume sphere
        return radius_from_volume(radius_equat_minor,radius_equat_major, radius_polar);
    case 3: // min radius
        return radius_from_min_dimension(radius_equat_minor,radius_equat_major, radius_polar);
    case 4: // max radius
        return radius_from_max_dimension(radius_equat_minor,radius_equat_major, radius_polar);
    }
}

static void
Fq(double q,
    double *F1,
    double *F2,
    double sld,
    double sld_solvent,
    double radius_equat_minor,
    double radius_equat_major,
    double radius_polar)
{
    const double pa = square(radius_equat_minor/radius_equat_major) - 1.0;
    const double pc = square(radius_polar/radius_equat_major) - 1.0;
    // 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 outer_sum_F1 = 0.0;
    double outer_sum_F2 = 0.0;
    for (int i=0;i<GAUSS_N;i++) {
        //const double u = GAUSS_Z[i]*(upper-lower)/2 + (upper + lower)/2;
        const double phi = GAUSS_Z[i]*zm + zb;
        const double pa_sinsq_phi = pa*square(sin(phi));

        double inner_sum_F1 = 0.0;
        double inner_sum_F2 = 0.0;
        const double um = 0.5;
        const double ub = 0.5;
        for (int j=0;j<GAUSS_N;j++) {
            // translate a point in [-1,1] to a point in [0, 1]
            const double usq = square(GAUSS_Z[j]*um + ub);
            const double r = radius_equat_major*sqrt(pa_sinsq_phi*(1.0-usq) + 1.0 + pc*usq);
            const double fq = sas_3j1x_x(q*r);
            inner_sum_F1 += GAUSS_W[j] * fq;
            inner_sum_F2 += GAUSS_W[j] * fq * fq;
        }
        outer_sum_F1 += GAUSS_W[i] * inner_sum_F1;  // correcting for dx later
        outer_sum_F2 += GAUSS_W[i] * inner_sum_F2;  // correcting for dx later
    }
    // translate integration ranges from [-1,1] to [lower,upper] and normalize by 4 pi
    outer_sum_F1 *= 0.25;  // = outer*um*zm*8.0/(4.0*M_PI);
    outer_sum_F2 *= 0.25;  // = outer*um*zm*8.0/(4.0*M_PI);

    const double volume = form_volume(radius_equat_minor, radius_equat_major, radius_polar);
    const double contrast = (sld - sld_solvent);
    *F1 = 1.0e-2 * contrast * volume * outer_sum_F1;
    *F2 = 1.0e-4 * square(contrast * volume) * outer_sum_F2;
}


static double
Iqabc(double qa, double qb, double qc,
    double sld,
    double sld_solvent,
    double radius_equat_minor,
    double radius_equat_major,
    double radius_polar)
{
    const double qr = sqrt(square(radius_equat_minor*qa)
                           + square(radius_equat_major*qb)
                           + square(radius_polar*qc));
    const double fq = sas_3j1x_x(qr);
    const double vol = form_volume(radius_equat_minor, radius_equat_major, radius_polar);
    const double drho = (sld - sld_solvent);

    return 1.0e-4 * square(vol * drho * fq);
}