source: sasmodels/sasmodels/models/parallelepiped.py @ 34a9e4e

core_shell_microgelscostrafo411magnetic_modelticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since 34a9e4e was 34a9e4e, checked in by richardh, 7 years ago

more docs fixes

  • Property mode set to 100644
File size: 10.2 KB
Line 
1# parallelepiped model
2# Note: model title and parameter table are inserted automatically
3r"""
4The form factor is normalized by the particle volume.
5For information about polarised and magnetic scattering, see
6the :ref:`magnetism` documentation.
7
8Definition
9----------
10
11 This model calculates the scattering from a rectangular parallelepiped
12 (\:numref:`parallelepiped-image`\).
13 If you need to apply polydispersity, see also :ref:`rectangular-prism`.
14
15.. _parallelepiped-image:
16
17
18.. figure:: img/parallelepiped_geometry.jpg
19
20   Parallelepiped with the corresponding definition of sides.
21
22.. note::
23
24The three dimensions of the parallelepiped (strictly here a cuboid) may be given in
25$any$ size order. To avoid multiple fit solutions, especially
26with Monte-Carlo fit methods, it may be advisable to restrict their ranges. There may
27be a number of closely similar "best fits", so some trial and error, or fixing of some
28dimensions at expected values, may help.
29
30The 1D scattering intensity $I(q)$ is calculated as:
31
32.. Comment by Miguel Gonzalez:
33   I am modifying the original text because I find the notation a little bit
34   confusing. I think that in most textbooks/papers, the notation P(Q) is
35   used for the form factor (adim, P(Q=0)=1), although F(q) seems also to
36   be used. But here (as for many other models), P(q) is used to represent
37   the scattering intensity (in cm-1 normally). It would be good to agree on
38   a common notation.
39
40.. math::
41
42    I(q) = \frac{\text{scale}}{V} (\Delta\rho \cdot V)^2
43           \left< P(q, \alpha) \right> + \text{background}
44
45where the volume $V = A B C$, the contrast is defined as
46$\Delta\rho = \rho_\text{p} - \rho_\text{solvent}$,
47$P(q, \alpha)$ is the form factor corresponding to a parallelepiped oriented
48at an angle $\alpha$ (angle between the long axis C and $\vec q$),
49and the averaging $\left<\ldots\right>$ is applied over all orientations.
50
51Assuming $a = A/B < 1$, $b = B /B = 1$, and $c = C/B > 1$, the
52form factor is given by (Mittelbach and Porod, 1961)
53
54.. math::
55
56    P(q, \alpha) = \int_0^1 \phi_Q\left(\mu \sqrt{1-\sigma^2},a\right)
57        \left[S(\mu c \sigma/2)\right]^2 d\sigma
58
59with
60
61.. math::
62
63    \phi_Q(\mu,a) &= \int_0^1
64        \left\{S\left[\frac{\mu}{2}\cos\left(\frac{\pi}{2}u\right)\right]
65               S\left[\frac{\mu a}{2}\sin\left(\frac{\pi}{2}u\right)\right]
66               \right\}^2 du
67
68    S(x) &= \frac{\sin x}{x}
69
70    \mu &= qB
71
72The scattering intensity per unit volume is returned in units of |cm^-1|.
73
74NB: The 2nd virial coefficient of the parallelepiped is calculated based on
75the averaged effective radius, after appropriately sorting the three
76dimensions, to give an oblate or prolate particle, $(=\sqrt{AB/\pi})$ and
77length $(= C)$ values, and used as the effective radius for
78$S(q)$ when $P(q) \cdot S(q)$ is applied.
79
80To provide easy access to the orientation of the parallelepiped, we define
81three angles $\theta$, $\phi$ and $\Psi$. The definition of $\theta$ and
82$\phi$ is the same as for the cylinder model (see also figures below).
83
84.. Comment by Miguel Gonzalez:
85   The following text has been commented because I think there are two
86   mistakes. Psi is the rotational angle around C (but I cannot understand
87   what it means against the q plane) and psi=0 corresponds to a||x and b||y.
88
89   The angle $\Psi$ is the rotational angle around the $C$ axis against
90   the $q$ plane. For example, $\Psi = 0$ when the $B$ axis is parallel
91   to the $x$-axis of the detector.
92
93The angle $\Psi$ is the rotational angle around the $C$ axis.
94For $\theta = 0$ and $\phi = 0$, $\Psi = 0$ corresponds to the $B$ axis
95oriented parallel to the y-axis of the detector with $A$ along the z-axis.
96For other $\theta$, $\phi$ values, the parallelepiped has to be first rotated
97$\theta$ degrees around $z$ and $\phi$ degrees around $y$,
98before doing a final rotation of $\Psi$ degrees around the resulting $C$ to
99obtain the final orientation of the parallelepiped.
100For example, for $\theta = 0$ and $\phi = 90$, we have that $\Psi = 0$
101corresponds to $A$ along $x$ and $B$ along $y$,
102while for $\theta = 90$ and $\phi = 0$, $\Psi = 0$ corresponds to
103$A$ along $z$ and $B$ along $x$.
104
105.. _parallelepiped-orientation:
106
107.. figure:: img/parallelepiped_angle_definition.png
108
109    Definition of the angles for oriented parallelepiped, shown with $A<B<C$.
110
111.. figure:: img/parallelepiped_angle_projection.png
112
113    Examples of the angles for an oriented parallelepiped against the
114    detector plane.
115
116On introducing "Orientational Distribution" in the angles, "distribution of theta" and "distribution of phi" parameters will
117appear. These are actually rotations about axes $\delta_1$ and $\delta_2$ of the parallelepiped, perpendicular to the $a$ x $c$ and $b$ x $c$ faces.
118(When $\theta = \phi = 0$ these are parallel to the $Y$ and $X$ axes of the instrument.) The third orientation distribution, in $\psi$, is
119about the $c$ axis of the particle, perpendicular to the $a$ x $b$ face. Some experimentation may be required to
120understand the 2d patterns fully. (Earlier implementations had numerical integration issues in some circumstances when orientation
121distributions passed through 90 degrees, such situations, with very broad distributions, should still be approached with care.)
122
123   
124For a given orientation of the parallelepiped, the 2D form factor is
125calculated as
126
127.. math::
128
129    P(q_x, q_y) = \left[\frac{\sin(\tfrac{1}{2}qA\cos\alpha)}{(\tfrac{1}{2}qA\cos\alpha)}\right]^2
130                  \left[\frac{\sin(\tfrac{1}{2}qB\cos\beta)}{(\tfrac{1}{2}qB\cos\beta)}\right]^2
131                  \left[\frac{\sin(\tfrac{1}{2}qC\cos\gamma)}{(\tfrac{1}{2}qC\cos\gamma)}\right]^2
132
133with
134
135.. math::
136
137    \cos\alpha &= \hat A \cdot \hat q,
138
139    \cos\beta  &= \hat B \cdot \hat q,
140
141    \cos\gamma &= \hat C \cdot \hat q
142
143and the scattering intensity as:
144
145.. math::
146
147    I(q_x, q_y) = \frac{\text{scale}}{V} V^2 \Delta\rho^2 P(q_x, q_y)
148            + \text{background}
149
150.. Comment by Miguel Gonzalez:
151   This reflects the logic of the code, as in parallelepiped.c the call
152   to _pkernel returns $P(q_x, q_y)$ and then this is multiplied by
153   $V^2 * (\Delta \rho)^2$. And finally outside parallelepiped.c it will be
154   multiplied by scale, normalized by $V$ and the background added. But
155   mathematically it makes more sense to write
156   $I(q_x, q_y) = \text{scale} V \Delta\rho^2 P(q_x, q_y) + \text{background}$,
157   with scale being the volume fraction.
158
159
160Validation
161----------
162
163Validation of the code was done by comparing the output of the 1D calculation
164to the angular average of the output of a 2D calculation over all possible
165angles.
166
167
168References
169----------
170
171P Mittelbach and G Porod, *Acta Physica Austriaca*, 14 (1961) 185-211
172
173R Nayuk and K Huber, *Z. Phys. Chem.*, 226 (2012) 837-854
174
175Authorship and Verification
176----------------------------
177
178* **Author:** This model is based on form factor calculations implemented
179    in a c-library provided by the NIST Center for Neutron Research (Kline, 2006).
180* **Last Modified by:**  Paul Kienzle **Date:** April 05, 2017
181* **Last Reviewed by:**  Richard Heenan **Date:** April 06, 2017
182
183"""
184
185import numpy as np
186from numpy import pi, inf, sqrt, sin, cos
187
188name = "parallelepiped"
189title = "Rectangular parallelepiped with uniform scattering length density."
190description = """
191    I(q)= scale*V*(sld - sld_solvent)^2*P(q,alpha)+background
192        P(q,alpha) = integral from 0 to 1 of ...
193           phi(mu*sqrt(1-sigma^2),a) * S(mu*c*sigma/2)^2 * dsigma
194        with
195            phi(mu,a) = integral from 0 to 1 of ..
196            (S((mu/2)*cos(pi*u/2))*S((mu*a/2)*sin(pi*u/2)))^2 * du
197            S(x) = sin(x)/x
198            mu = q*B
199        V: Volume of the rectangular parallelepiped
200        alpha: angle between the long axis of the
201            parallelepiped and the q-vector for 1D
202"""
203category = "shape:parallelepiped"
204
205#             ["name", "units", default, [lower, upper], "type","description"],
206parameters = [["sld", "1e-6/Ang^2", 4, [-inf, inf], "sld",
207               "Parallelepiped scattering length density"],
208              ["sld_solvent", "1e-6/Ang^2", 1, [-inf, inf], "sld",
209               "Solvent scattering length density"],
210              ["length_a", "Ang", 35, [0, inf], "volume",
211               "Shorter side of the parallelepiped"],
212              ["length_b", "Ang", 75, [0, inf], "volume",
213               "Second side of the parallelepiped"],
214              ["length_c", "Ang", 400, [0, inf], "volume",
215               "Larger side of the parallelepiped"],
216              ["theta", "degrees", 60, [-360, 360], "orientation",
217               "c axis to beam angle"],
218              ["phi", "degrees", 60, [-360, 360], "orientation",
219               "rotation about beam"],
220              ["psi", "degrees", 60, [-360, 360], "orientation",
221               "rotation about c axis"],
222             ]
223
224source = ["lib/gauss76.c", "parallelepiped.c"]
225
226def ER(length_a, length_b, length_c):
227    """
228    Return effective radius (ER) for P(q)*S(q)
229    """
230    # now that axes can be in any size order, need to sort a,b,c where a~b and c is either much smaller
231    # or much larger
232    abc = np.vstack((length_a, length_b, length_c))
233    abc = np.sort(abc, axis=0)
234    selector = (abc[1] - abc[0]) > (abc[2] - abc[1])
235    length = np.where(selector, abc[0], abc[2])
236    # surface average radius (rough approximation)
237    radius = np.sqrt(np.where(~selector, abc[0]*abc[1], abc[1]*abc[2]) / pi)
238
239    ddd = 0.75 * radius * (2*radius*length + (length + radius)*(length + pi*radius))
240    return 0.5 * (ddd) ** (1. / 3.)
241
242# VR defaults to 1.0
243
244# parameters for demo
245demo = dict(scale=1, background=0,
246            sld=6.3, sld_solvent=1.0,
247            length_a=35, length_b=75, length_c=400,
248            theta=45, phi=30, psi=15,
249            length_a_pd=0.1, length_a_pd_n=10,
250            length_b_pd=0.1, length_b_pd_n=1,
251            length_c_pd=0.1, length_c_pd_n=1,
252            theta_pd=10, theta_pd_n=1,
253            phi_pd=10, phi_pd_n=1,
254            psi_pd=10, psi_pd_n=10)
255# rkh 7/4/17 add random unit test for 2d, note make all params different, 2d values not tested against other codes or models
256qx, qy = 0.2 * cos(pi/6.), 0.2 * sin(pi/6.)
257tests = [[{}, 0.2, 0.17758004974],
258         [{}, [0.2], [0.17758004974]],
259         [{'theta':10.0, 'phi':20.0}, (qx, qy), 0.0089517140475],
260         [{'theta':10.0, 'phi':20.0}, [(qx, qy)], [0.0089517140475]],
261        ]
262del qx, qy  # not necessary to delete, but cleaner
Note: See TracBrowser for help on using the repository browser.