Skip to content

Commit 9779ba2

Browse files
Merge pull request #687 from SasView/adding_trOh_model_pythonC
Adding truncated octahedron model (python and c)
2 parents ed30b0f + 7a444c7 commit 9779ba2

4 files changed

Lines changed: 517 additions & 0 deletions

File tree

124 KB
Loading
38.4 KB
Loading
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
#include <math.h>
2+
#include <stdio.h>
3+
4+
//truncated octahedron volume
5+
// NOTE: needs to be called form_volume() for a shape category
6+
static double
7+
form_volume(double length_a, double b2a_ratio, double c2a_ratio, double t)
8+
{
9+
// length_a is the half height along the a axis of the octahedron without truncature
10+
// length_b is the half height along the b axis of the octahedron without truncature
11+
// length_c is the half height along the c axis of the octahedron without truncature
12+
// b2a_ratio is length_b divided by Length_a
13+
// c2a_ratio is Length_c divided by Length_a
14+
// t varies from 0.5 (cuboctahedron) to 1 (octahedron)
15+
return (4./3.) * cube(length_a) * b2a_ratio * c2a_ratio *(1.-3*cube(1.-t));
16+
}
17+
18+
// remark: Iq() is generally not used because have_Fq is set to True in the Python file
19+
static double
20+
Iq(double q,
21+
double sld,
22+
double solvent_sld,
23+
double length_a,
24+
double b2a_ratio,
25+
double c2a_ratio,
26+
double t)
27+
{
28+
const double length_b = length_a * b2a_ratio;
29+
const double length_c = length_a * c2a_ratio;
30+
31+
32+
//Integration limits to use in Gaussian quadrature
33+
const double v1a = 0.0;
34+
const double v1b = M_PI_2; //theta integration limits
35+
const double v2a = 0.0;
36+
const double v2b = M_PI_2; //phi integration limits
37+
38+
double outer_sum = 0.0;
39+
for(int i=0; i<GAUSS_N; i++) {
40+
const double theta = 0.5 * ( GAUSS_Z[i]*(v1b-v1a) + v1a + v1b );
41+
double sin_theta, cos_theta;
42+
SINCOS(theta, sin_theta, cos_theta);
43+
44+
double inner_sum = 0.0;
45+
for(int j=0; j<GAUSS_N; j++) {
46+
double phi = 0.5 * ( GAUSS_Z[j]*(v2b-v2a) + v2a + v2b );
47+
double sin_phi, cos_phi;
48+
SINCOS(phi, sin_phi, cos_phi);
49+
50+
//HERE: Octahedron formula
51+
// q is the modulus of the scattering vector in [A-1]
52+
// NOTE: capital QX QY QZ are the three components in [A-1] of the scattering vector
53+
// NOTE: qx qy qz are rescaled components (no unit) for computing AA, BB and CC terms
54+
const double Qx = q * sin_theta * cos_phi;
55+
const double Qy = q * sin_theta * sin_phi;
56+
const double Qz = q * cos_theta;
57+
const double qx = Qx * length_a;
58+
const double qy = Qy * length_b;
59+
const double qz = Qz * length_c;
60+
61+
const double AA = 1./((qy*qy-qz*qz)*(qy*qy-qx*qx))*((qy-qx)*sin(qy*(1.-t)-qx*t)+(qy+qx)*sin(qy*(1.-t)+qx*t))+
62+
1./((qz*qz-qx*qx)*(qz*qz-qy*qy))*((qz-qx)*sin(qz*(1.-t)-qx*t)+(qz+qx)*sin(qz*(1.-t)+qx*t));
63+
64+
const double BB = 1./((qz*qz-qx*qx)*(qz*qz-qy*qy))*((qz-qy)*sin(qz*(1.-t)-qy*t)+(qz+qy)*sin(qz*(1.-t)+qy*t))+
65+
1./((qx*qx-qy*qy)*(qx*qx-qz*qz))*((qx-qy)*sin(qx*(1.-t)-qy*t)+(qx+qy)*sin(qx*(1.-t)+qy*t));
66+
67+
const double CC = 1./((qx*qx-qy*qy)*(qx*qx-qz*qz))*((qx-qz)*sin(qx*(1.-t)-qz*t)+(qx+qz)*sin(qx*(1.-t)+qz*t))+
68+
1./((qy*qy-qz*qz)*(qy*qy-qx*qx))*((qy-qz)*sin(qy*(1.-t)-qz*t)+(qy+qz)*sin(qy*(1.-t)+qz*t));
69+
70+
71+
// normalisation to 1. of AP at q = 0. Division by a Factor 4/3.
72+
const double AP = 6./(1.-3*(1.-t)*(1.-t)*(1.-t))*(AA+BB+CC);
73+
74+
inner_sum += GAUSS_W[j] * AP * AP;
75+
76+
77+
}
78+
inner_sum = 0.5 * (v2b-v2a) * inner_sum;
79+
outer_sum += GAUSS_W[i] * inner_sum * sin_theta;
80+
}
81+
82+
double answer = 0.5*(v1b-v1a)*outer_sum;
83+
84+
// The factor 2 appears because the theta integral has been defined between
85+
// 0 and pi/2, instead of 0 to pi.
86+
answer /= M_PI_2; //Form factor P(q)
87+
88+
// Multiply by contrast^2 and volume^2
89+
// contrast
90+
const double s = (sld-solvent_sld);
91+
// volume
92+
// s *= form_volume(length_a, b2a_ratio,c2a_ratio, t);
93+
answer *= square(s*form_volume(length_a, b2a_ratio,c2a_ratio, t));
94+
95+
// Convert from [1e-12 A-1] to [cm-1]
96+
answer *= 1.0e-4;
97+
98+
if (isnan(answer) || isinf(answer)) {
99+
return 0.0;
100+
}
101+
102+
return answer;
103+
}
104+
105+
// Fq() is called because option "have_Fq = True" is set to True in the Python file
106+
static void
107+
Fq(double q,
108+
double *F1,
109+
double *F2,
110+
double sld,
111+
double solvent_sld,
112+
double length_a,
113+
double b2a_ratio,
114+
double c2a_ratio,
115+
double t)
116+
{
117+
const double length_b = length_a * b2a_ratio;
118+
const double length_c = length_a * c2a_ratio;
119+
120+
121+
//Integration limits to use in Gaussian quadrature
122+
const double v1a = 0.0;
123+
const double v1b = M_PI_2; //theta integration limits
124+
const double v2a = 0.0;
125+
const double v2b = M_PI_2; //phi integration limits
126+
127+
double outer_sum_F1 = 0.0;
128+
double outer_sum_F2 = 0.0;
129+
130+
for(int i=0; i<GAUSS_N; i++) {
131+
const double theta = 0.5 * ( GAUSS_Z[i]*(v1b-v1a) + v1a + v1b );
132+
double sin_theta, cos_theta;
133+
SINCOS(theta, sin_theta, cos_theta);
134+
135+
double inner_sum_F1 = 0.0;
136+
double inner_sum_F2 = 0.0;
137+
for(int j=0; j<GAUSS_N; j++) {
138+
double phi = 0.5 * ( GAUSS_Z[j]*(v2b-v2a) + v2a + v2b );
139+
double sin_phi, cos_phi;
140+
SINCOS(phi, sin_phi, cos_phi);
141+
142+
//HERE: Octahedron formula
143+
// q is the modulus of the scattering vector in [A-1]
144+
// NOTE: capital QX QY QZ are the three components in [A-1] of the scattering vector
145+
// NOTE: qx qy qz are rescaled components (no unit) for computing AA, BB and CC terms
146+
const double Qx = q * sin_theta * cos_phi;
147+
const double Qy = q * sin_theta * sin_phi;
148+
const double Qz = q * cos_theta;
149+
const double qx = Qx * length_a;
150+
const double qy = Qy * length_b;
151+
const double qz = Qz * length_c;
152+
const double AA = 1./(2*(qy*qy-qz*qz)*(qy*qy-qx*qx))*((qy-qx)*sin(qy*(1.-t)-qx*t)+(qy+qx)*sin(qy*(1.-t)+qx*t))+
153+
1./(2*(qz*qz-qx*qx)*(qz*qz-qy*qy))*((qz-qx)*sin(qz*(1.-t)-qx*t)+(qz+qx)*sin(qz*(1.-t)+qx*t));
154+
155+
const double BB = 1./(2*(qz*qz-qx*qx)*(qz*qz-qy*qy))*((qz-qy)*sin(qz*(1.-t)-qy*t)+(qz+qy)*sin(qz*(1.-t)+qy*t))+
156+
1./(2*(qx*qx-qy*qy)*(qx*qx-qz*qz))*((qx-qy)*sin(qx*(1.-t)-qy*t)+(qx+qy)*sin(qx*(1.-t)+qy*t));
157+
158+
const double CC = 1./(2*(qx*qx-qy*qy)*(qx*qx-qz*qz))*((qx-qz)*sin(qx*(1.-t)-qz*t)+(qx+qz)*sin(qx*(1.-t)+qz*t))+
159+
1./(2*(qy*qy-qz*qz)*(qy*qy-qx*qx))*((qy-qz)*sin(qy*(1.-t)-qz*t)+(qy+qz)*sin(qy*(1.-t)+qz*t));
160+
161+
// normalisation to 1. of AP at q = 0. Division by a Factor 4/3.
162+
const double AP = 6./(1.-3*(1.-t)*(1.-t)*(1.-t))*(AA+BB+CC);
163+
164+
165+
inner_sum_F1 += GAUSS_W[j] * AP;
166+
inner_sum_F2 += GAUSS_W[j] * AP * AP;
167+
168+
}
169+
inner_sum_F1 = 0.5 * (v2b-v2a) * inner_sum_F1;
170+
inner_sum_F2 = 0.5 * (v2b-v2a) * inner_sum_F2;
171+
outer_sum_F1 += GAUSS_W[i] * inner_sum_F1 * sin_theta;
172+
outer_sum_F2 += GAUSS_W[i] * inner_sum_F2 * sin_theta;
173+
}
174+
175+
outer_sum_F1 *= 0.5*(v1b-v1a);
176+
outer_sum_F2 *= 0.5*(v1b-v1a);
177+
178+
// The factor 2 appears because the theta integral has been defined between
179+
// 0 and pi/2, instead of 0 to pi.
180+
outer_sum_F1 /= M_PI_2;
181+
outer_sum_F2 /= M_PI_2;
182+
183+
// Multiply by contrast and volume
184+
// contrast
185+
const double s = (sld-solvent_sld);
186+
// volume
187+
// s *= form_volume(length_a, b2a_ratio,c2a_ratio, t);
188+
189+
// Convert from [1e-12 A-1] to [cm-1]
190+
*F1 = 1e-2 * s * form_volume(length_a, b2a_ratio,c2a_ratio, t) * outer_sum_F1;
191+
*F2 = 1e-4 * square(s * form_volume(length_a, b2a_ratio,c2a_ratio, t)) * outer_sum_F2;
192+
193+
if (isnan(*F1) || isinf(*F1)) {
194+
*F1 = 0.0;
195+
}
196+
if (isnan(*F2) || isinf(*F2)) {
197+
*F2 = 0.0;
198+
}
199+
}
200+
201+
202+
static double
203+
Iqabc(double qa, double qb, double qc,
204+
double sld,
205+
double solvent_sld,
206+
double length_a,
207+
double b2a_ratio,
208+
double c2a_ratio,
209+
double t)
210+
{
211+
const double length_b = length_a * b2a_ratio;
212+
const double length_c = length_a * c2a_ratio;
213+
214+
215+
//HERE: Octahedron formula
216+
// NOTE: qa qb qc are the three components in [A-1] of the scattering vector
217+
// NOTE: qx qy qz are rescaled components (no unit) for computing AA, BB and CC terms
218+
const double qx = qa * length_a;
219+
const double qy = qb * length_b;
220+
const double qz = qc * length_c;
221+
const double AA = 1./(2*(qy*qy-qz*qz)*(qy*qy-qx*qx))*((qy-qx)*sin(qy*(1.-t)-qx*t)+(qy+qx)*sin(qy*(1.-t)+qx*t))+
222+
1./(2*(qz*qz-qx*qx)*(qz*qz-qy*qy))*((qz-qx)*sin(qz*(1.-t)-qx*t)+(qz+qx)*sin(qz*(1.-t)+qx*t));
223+
224+
const double BB = 1./(2*(qz*qz-qx*qx)*(qz*qz-qy*qy))*((qz-qy)*sin(qz*(1.-t)-qy*t)+(qz+qy)*sin(qz*(1.-t)+qy*t))+
225+
1./(2*(qx*qx-qy*qy)*(qx*qx-qz*qz))*((qx-qy)*sin(qx*(1.-t)-qy*t)+(qx+qy)*sin(qx*(1.-t)+qy*t));
226+
227+
const double CC = 1./(2*(qx*qx-qy*qy)*(qx*qx-qz*qz))*((qx-qz)*sin(qx*(1.-t)-qz*t)+(qx+qz)*sin(qx*(1.-t)+qz*t))+
228+
1./(2*(qy*qy-qz*qz)*(qy*qy-qx*qx))*((qy-qz)*sin(qy*(1.-t)-qz*t)+(qy+qz)*sin(qy*(1.-t)+qz*t));
229+
230+
// normalisation to 1. of AP at q = 0. Division by a Factor 4/3.
231+
const double AP = 6./(1.-3*(1.-t)*(1.-t)*(1.-t))*(AA+BB+CC);
232+
233+
// Multiply by contrast and volume
234+
// contrast
235+
const double s = (sld-solvent_sld);
236+
// volume
237+
// s *= form_volume(length_a, b2a_ratio,c2a_ratio, t);
238+
239+
// Convert from [1e-12 A-1] to [cm-1]
240+
double answer = 1.0e-4 * square(s * form_volume(length_a, b2a_ratio,c2a_ratio, t) * AP);
241+
if (isnan(answer) || isinf(answer)) {
242+
return 0.0;
243+
}
244+
245+
return answer;
246+
}
247+
248+
249+

0 commit comments

Comments
 (0)