source: sasmodels/sasmodels/models/superball.c @ 8b7ce55

ticket_1265_superball
Last change on this file since 8b7ce55 was 8b7ce55, checked in by DomiDre <homiedomi@…>, 5 years ago

Add superball form factor

  • Property mode set to 100644
File size: 4.5 KB
Line 
1static double
2form_volume(double length_a, double exponent_p)
3{
4  double g1 = sas_gamma(1.0 / (2.0 * exponent_p));
5  double g3 = sas_gamma(3.0 / (2.0 * exponent_p));
6  return cube(length_a) / 12.0 / square(exponent_p) * cube(g1) / g3;
7}
8
9static double
10radius_from_excluded_volume(double length_a, double exponent_p)
11{
12  double g1 = sas_gamma(1.0 / (2.0 * exponent_p));
13  double g3 = sas_gamma(3.0 / (2.0 * exponent_p));
14  double g5 = sas_gamma(5.0 / (2.0 * exponent_p));
15
16  return length_a * g3 * sqrt(3.0 / 10.0 / g1 / g5);
17}
18
19static double
20effective_radius(int mode, double length_a, double exponent_p)
21{
22  switch (mode)
23  {
24  default:
25  case 1: // radius of gyration
26    return radius_from_excluded_volume(length_a, exponent_p);
27  case 2: // equivalent volume sphere
28    return cbrt(form_volume(length_a, exponent_p) / M_4PI_3);
29  case 3: // half length_a
30    return 0.5 * length_a;
31  }
32}
33
34static double oriented_superball(
35    double qx,
36    double qy,
37    double qz,
38    double length_a,
39    double exponent_p)
40{
41  // oriented superball form factor
42
43  // outer integral for x
44  const double radius = length_a / 2.0; // superball radius
45  const double inverse_2p = 1.0 / (2.0 * exponent_p);
46
47  double outer_integral = 0.0; //initialize integral
48
49  for (int i_x = 0; i_x < GAUSS_N; i_x++)
50  {
51    const double x = 0.5 * (GAUSS_Z[i_x] + 1.0); // integrate 0, 1
52    const double x2p = pow(x, 2.0 * exponent_p);
53    const double gamma = pow(1.0 - x2p, inverse_2p);
54
55    // inner integral for y
56    double inner_integral = 0.0; //initialize integral
57    for (int i_y = 0; i_y < GAUSS_N; i_y++)
58    {
59      const double y = 0.5 * gamma * (GAUSS_Z[i_y] + 1.0); // integrate 0, gamma
60      const double y2p = pow(y, 2.0 * exponent_p);
61      const double zeta = pow(1.0 - x2p - y2p, inverse_2p);
62      const double cos1 = cos(radius * qy * y);
63      const double sinc2 = qz == 0 ? radius * zeta : sin(radius * qz * zeta) / qz;
64      const double fq = cos1 * sinc2;
65      inner_integral += GAUSS_W[i_y] * fq;
66    }
67
68    const double co = cos(radius * qx * x);
69
70    // integration factor for -1,1 quadrature to 0, gamma: gamma/2
71    const double integration_factor = 0.5 * gamma;
72    outer_integral += GAUSS_W[i_x] * integration_factor * inner_integral * co;
73  }
74  // integration factor for -1,1 quadrature to 0, 1: 1/2
75  return 0.5 * outer_integral;
76}
77
78static void
79Fq(double q,
80   double *F1,
81   double *F2,
82   double sld,
83   double solvent_sld,
84   double length_a,
85   double exponent_p)
86{
87  double orient_averaged_outer_total_F1 = 0.0; //initialize integral
88  double orient_averaged_outer_total_F2 = 0.0; //initialize integral
89  // phi integral
90  for (int i_phi = 0; i_phi < GAUSS_N; i_phi++)
91  {
92    const double phi = (GAUSS_Z[i_phi] + 1.0) * M_PI_4; // integrate 0 .. pi/2
93    double sin_phi, cos_phi;
94    SINCOS(phi, sin_phi, cos_phi);
95
96    double orient_averaged_inner_total_F1 = 0.0; //initialize integral
97    double orient_averaged_inner_total_F2 = 0.0; //initialize integral
98    // theta integral
99    for (int i_theta = 0; i_theta < GAUSS_N; i_theta++)
100    {
101      const double theta = (GAUSS_Z[i_theta] + 1.0) * M_PI_4; // integrate 0, pi/2
102      double sin_theta, cos_theta;
103      SINCOS(theta, sin_theta, cos_theta);
104      const double qx = q * cos_phi * sin_theta;
105      const double qy = q * sin_phi * sin_theta;
106      const double qz = q * cos_theta;
107
108      const double f_oriented = oriented_superball(qx, qy, qz, length_a, exponent_p);
109
110      orient_averaged_inner_total_F1 += GAUSS_W[i_theta] * f_oriented * sin_theta;
111      orient_averaged_inner_total_F2 += GAUSS_W[i_theta] * square(f_oriented) * sin_theta;
112    }
113    orient_averaged_outer_total_F1 += GAUSS_W[i_phi] * orient_averaged_inner_total_F1;
114    orient_averaged_outer_total_F2 += GAUSS_W[i_phi] * orient_averaged_inner_total_F2;
115  }
116  // Multiply by contrast^2 and convert from [1e-12 A-1] to [cm-1]
117  const double contrast = (sld - solvent_sld);
118  const double s = 2.0 * contrast * square(length_a);
119  *F1 = 1.0e-2 * s * orient_averaged_outer_total_F1 * M_PI_4 * 0.5;
120  *F2 = 1.0e-4 * s * s * orient_averaged_outer_total_F2 * M_PI_4 * 0.5;
121}
122
123static double
124Iqabc(double qa, double qb, double qc,
125      double sld,
126      double solvent_sld,
127      double length_a,
128      double exponent_p)
129{
130  const double f_oriented = oriented_superball(qa, qb, qc, length_a, exponent_p);
131  const double contrast = (sld - solvent_sld);
132  const double s = 2.0 * contrast * square(length_a);
133
134  const double form = square(s * f_oriented);
135  // Square and convert from [1e-12 A-1] to [cm-1]
136  return 1.0e-4 * form;
137}
Note: See TracBrowser for help on using the repository browser.