source: sasmodels/doc/developer/overview.rst @ 17db833

core_shell_microgelsmagnetic_modelticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since 17db833 was 3d40839, checked in by Paul Kienzle <pkienzle@…>, 7 years ago

update orientation docs

  • Property mode set to 100644
File size: 14.9 KB
RevLine 
[2e66ef5]1.. py:currentmodule:: sasmodels
2
3***************************
4Code Overview
5***************************
6
7Computational kernels
8---------------------
9
[870a2f4]10* :mod:`core`
11* :mod:`modelinfo`
12* :mod:`kernel`
13* :mod:`product`
14* :mod:`mixture`
15
[2e66ef5]16At the heart of *sasmodels* are the individual computational kernels.  These
17functions take a particular $q$ value and a set of parameter values and
18return the expected scattering for that $q$. The instructions for writing
19a kernel are documented in :ref:`Writing_a_Plugin`.  The source code for
[870a2f4]20the kernels is stored in :mod:`models`.
[2e66ef5]21
[870a2f4]22The primary interface to the models is through :mod:`core`, which
[2e66ef5]23provides functions for listing available models, loading the model definition
[870a2f4]24and compiling the model.  Use :func:`core.load_model` to load in
25a model definition and compile it.  This makes use of
26:func:`core.load_model_info` to load the model definition and
27:func:`core.build_model` to turn it into a computational kernel model
28:class:`kernel.KernelModel`.
29
30The :class:`modelinfo.ModelInfo` class defines the properties
31of the model including the available model parameters
32:class:`modelinfo.ParameterTable` with individual parameter attributes
33such as units and hard limits defined in :class:`modelinfo.Parameter`.
34
35The :class:`product.ProductModel` and :class:`mixture.MixtureModel` classes
36are derived models, created automatically for models with names like
37"hardsphere*sphere" and "cylinder+sphere".
38
39Data loaders
40------------
41
42* :mod:`data`
43
44In order to test models a minimal set of data management routines is
45provided in :mod:`data`.  In particular, it provides mock :class:`data.Data1D`
46and :class:`data.Data2D` classes which mimic those classes in *SasView*.
47The functions :func:`data.empty_data1D` and :func:`data.empty_data2D`
48are handy for creating containers with a particular set of $q$, $\Delta q$
49points which can later be evaluated, and :func:`data.plot_theory` to show
50the result.  If *SasView* is available on the path then :func:`data.load_data`
51can be used to load any data type defined in *SasView*.  The function
52:func:`data.plot_data` can plot that data alone without the theory value.
53
54Kernel execution
55----------------
56
57* :mod:`resolution`
58* :mod:`resolution2d`
59* :mod:`sesans`
60* :mod:`weights`
61* :mod:`details`
62* :mod:`direct_model`
63* :mod:`bumps_model`
64* :mod:`sasview_model`
65
66To execute a computational kernel at a particular set of $q$ values, the
67use :meth:`kernel.KernelModel.make_kernel`, which returns a callable
68:class:`kernel.Kernel` for that $q$ vector (or a pair of $q_x$, $q_y$
69for 2-D datasets).
70
71The calculated $q$ values should include the measured
72data points as well as additional $q$ values required to properly compute the
73$q$ resolution function.  The *Resolution* subclasses in :mod:`resolution`
74define the *q_calc* attribute for this purpose.  These are
75:class:`resolution.Perfect1D` for perfect resolution,
76:class:`resolution.Pinhole1D` for the usual SANS pinhole aperture,
77:class:`resolution.Slit1D` for the usual USANS slit aperture and
78:class:`resolution2d.Pinhole2D` for 2-D pinhole data.
79In addition, :class:`resolution2d.Slit2D` defines 1-D slit smeared data
80for oriented samples, which require calculation at particular $q_x$ and
81$q_y$ values instead of $|q|$ as is the case for orientationally averaged
82USANS.  The :class:`sesans.SesansTransform` class acts like a 1-D resolution,
83having a *q_calc* attribute that defines the calculated $q$ values for
84the SANS models that get converted to spin-echo values by the
85:meth:`sesnas.SesansTransform.apply` method.
86
87Polydispersity is defined by :class:`weights.Dispersion` classes,
88:class:`weights.RectangleDispersion`, :class:`weights.ArrayDispersion`,
89:class:`weights.LogNormalDispersion`, :class:`weights.GaussianDispersion`,
90:class:`weights.SchulzDispersion`.  The :func:`weights.get_weights`
91function creates a dispersion object of the class matching
92:attr:`weights.Dispersion.type`, and calls it with the current value
93of the parameter.  This returns a vector of values and weights for a
94weighted average polydispersity.
95
96In order to call the :class:`kernel.Kernel`, the values and weights for
97all parameters must be composed into a :class:`details.CallDetails` object.
98This is a compact vector representation of the entire polydispersity
99loop that can be passed easily to the kernel.  Additionally, the magnetic
100parameters must be converted from polar to cartesian coordinates.  This
101work is done by the :func:`details.make_kernel_args` function, which returns
102values that can be sent directly to the kernel.  It uses
103:func:`details.make_details` to set the details object and
104:func:`details.convert_magnetism` for the coordinate transform.
105
106In the end, making a simple theory function evaluation requires a lot of
107setup. To make calling them a little easier, the *DirectModel* and
108*BumpsModel* interfaces are provided.  See :ref:`Scripting_Interface`
109for an example.
110
111The :class:`direct_model.DirectModel` interface accepts a data object
112and a kernel model.  Within the class,
113the :meth:`direct_model.DataMixin._interpret_data` method is called to
114query the data and set the resolution.
115The :meth:`direct_model.DataMixin._calc_theory` takes a set of parameter
116values, builds the kernel arguments, calls the kernel, and applies the
117resolution function, returning the predicted value for the data $q$ values.
118The :class:`bumps_model.Experiment` class is like the DirectModel class,
119but it defines a Fitness class that can be handed directly to the
120bumps optimization and uncertainty analysis program.
121
122The :class:`sasview_model.SasviewModel` class defines a SasView 4.x
123compatible interface to the sasmodels definitions, allowing sasmodels
124to be used directly from SasView.  Over time the SasView shim should
125disappear as SasView access the :class:`modelinfo.ModelInfo` and
126computational kernels directly.
127
128Kernel execution
129----------------
130
131* :mod:`kernelcl`
132* :mod:`kerneldll`
133* :mod:`kernelpy`
134* :mod:`generate`
[2e66ef5]135
136
137The kernel functions for the most part do not define polydispersity,
[870a2f4]138resolution or magnetism directly.  Instead sasmodels automatically
139applies these, calling the computation kernel as needed.
140
141The outermost loop is the resolution calculation.  For the 1-D case
142this computes a single vector of $I(q)$ values and applies the convolution
143to the resulting set.  Since the same $I(q)$ vector is used to compute the
144convolution at each point, it can be precomputed before the convolution,
145and so the convolution is reasonably efficient.  The 2-D case is not
146that efficient, and instead recomputes the entire shifted/scaled set
147of $q_x$, $q_y$ values many times, or very many times depending on the
148accuracy requested.
149
150Polydispersity is handled as a mesh over the polydisperse parameters.
151This is the next level of the loop.  For C kernels run in a DLL or
152using OpenCL, the polydisperisty loop is generated separately for each
153model as C code.  Inside the polydispersity loop there is a loop over
154the magnetic cross sections for magnetic models, updating the SLD
155parameters with the effective magnetic SLD for that particular $q$
156value. For OpenCL, each $q$ value loops over the
157polydispersity mesh on a separate processor. For DLL, the outer loop
158cycles through polydispersity, and the inner loop distributes q values
159amongst the processors.  Like the DLL, the Python kernel execution
160cycles over the polydisperse parameters and the magnetic cross sections,
161calling the computation kernel with a vector of $q$ values.  Assuming
162the kernel code accepts vectors, this can be fast enough (though it is
163painfully slow if not vectorized).
164
165Further details are provided in the next section,
166:ref:`Calculator_Interface`
167
[eda8b30]168.. _orientation_developer:
169
[da5536f]170Orientation and Numerical Integration
171-------------------------------------
172
[e964ab1]173For 2d data from oriented anisotropic particles, the mean particle
174orientation is defined by angles $\theta$, $\phi$ and $\Psi$, which are not
175in general the same as similarly named angles in many form factors. The
176wikipedia page on Euler angles (https://en.wikipedia.org/wiki/Euler_angles)
177lists the different conventions available. To quote: "Different authors may
178use different sets of rotation axes to define Euler angles, or different
179names for the same angles. Therefore, any discussion employing Euler angles
[da5536f]180should always be preceded by their definition."
181
[3d40839]182We are using the $z$-$y$-$z$ convention with extrinsic rotations
183$\Psi$-$\theta$-$\phi$ for the particle orientation and $x$-$y$-$z$
184convention with extrinsic rotations $\Psi$-$\theta$-$\phi$ for jitter, with
185jitter applied before particle orientation.
[e964ab1]186
187For numerical integration within form factors etc. sasmodels is mostly using
188Gaussian quadrature with 20, 76 or 150 points depending on the model. It also
189makes use of symmetries such as calculating only over one quadrant rather
190than the whole sphere. There is often a U-substitution replacing $\theta$
191with $cos(\theta)$ which changes the limits of integration from 0 to $\pi/2$
192to 0 to 1 and also conveniently absorbs the $sin(\theta)$ scale factor in the
[3d40839]193integration. This can cause confusion if checking equations to include in a
194paper or thesis! Most models use the same core kernel code expressed in terms
195of the rotated view ($q_a$, $q_b$, $q_c$) for both the 1D and the 2D models,
196but there are also historical quirks such as the parallelepiped model, which
197has a useless transformation representing $j_0(a q_a)$ as $j_0(b q_a a/b)$.
[da5536f]198
[3d40839]199Useful testing routines include:
[da5536f]200
[e964ab1]201:mod:`asymint` a direct implementation of the surface integral for certain
202models to get a more trusted value for the 1D integral using a
203reimplementation of the 2D kernel in python and mpmath (which computes math
204functions to arbitrary precision). It uses $\theta$ ranging from 0 to $\pi$
205and $\phi$ ranging from 0 to $2\pi$. It perhaps would benefit from including
[3d40839]206the U-substitution for $\theta$.
[e964ab1]207
208:mod:`check1d` uses sasmodels 1D integration and compares that with a
209rectangle distribution in $\theta$ and $\phi$, with $\theta$ limits set to
[3d40839]210$\pm 90/\sqrt(3)$ and $\phi$ limits set to $\pm 180/\sqrt(3)$ [The rectangle
[e964ab1]211weight function uses the fact that the distribution width column is labelled
[3d40839]212sigma to decide that the 1-$\sigma$ width of a rectangular distribution needs to
[e964ab1]213be multiplied by $\sqrt(3)$ to get the corresponding gaussian equivalent, or
214similar reasoning.] This should rotate the sample through the entire
[3d40839]215$\theta$-$\phi$ surface according to the pattern that you see in jitter.py when
[e964ab1]216you modify it to use 'rectangle' rather than 'gaussian' for its distribution
[3d40839]217without changing the viewing angle. In order to match the 1-D pattern for
218an arbitrary viewing angle on triaxial shapes, we need to integrate
219over $\theta$, $\phi$ and $\Psi$.
220
221When computing the dispersity integral, weights are scaled by
222$|\cos(\delta \theta)|$ to account for the points in $\phi$ getting closer
223together as $\delta \theta$ increases.
224[This will probably change so that instead of adjusting the weights, we will
225adjust $\delta\theta$-$\delta\phi$ mesh so that the point density in
226$\delta\phi$ is lower at larger $\delta\theta$. The flag USE_SCALED_PHI in
227*kernel_iq.c* selects an alternative algorithm.]
228
229The integrated dispersion is computed at a set of $(qx, qy)$ points $(q
230\cos(\alpha), q \sin(\alpha))$ at some angle $\alpha$ (currently angle=0) for
231each $q$ used in the 1-D integration. The individual $q$ points should be
232equivalent to asymint rect-n when the viewing angle is set to
233$(\theta,\phi,\Psi) = (90, 0, 0)$. Such tests can help to validate that 2d
234models are consistent with 1d models.
235
236:mod:`sascomp -sphere=n` uses the same rectangular distribution as check1d to
237compute the pattern of the $q_x$-$q_y$ grid.
[e964ab1]238
239The :mod:`sascomp` utility can be used for 2d as well as 1d calculations to
240compare results for two sets of parameters or processor types, for example
[da5536f]241these two oriented cylinders here should be equivalent.
242
243:mod:`\./sascomp -2d cylinder theta=0 phi=0,90 theta_pd_type=rectangle phi_pd_type=rectangle phi_pd=10,1 theta_pd=1,10 length=500 radius=10`
244
[870a2f4]245
246Testing
247-------
248
249* :mod:`model_test`
250* :mod:`compare`
251* :mod:`compare_many`
252* :mod:`rst2html`
253* :mod:`list_pars`
254
255Individual models should all have test values to make sure that the
256evaluation is correct.  This is particularly important in the context
257of OpenCL since sasmodels doesn't control the compiler or the hardware,
258and since GPUs are notorious for preferring speed over precision.  The
259tests can be run as a group using :mod:`model_test` as main::
260
261    $ python -m sasmodels.model_test all
262
263Individual models can be listed instead of *all*, which is convenient when
264adding new models.
265
266The :mod:`compare` module, usually invoked using *./sascomp* provides a
267rich interface for exploring model accuracy, execution speed and parameter
268ranges.  It also allows different models to be compared.
269The :mod:`compare_many` module does batch comparisons, keeping a list of
270the particular random seeds which lead to large differences in output
271between different computing platforms.
272
273The :mod:`rst2html` module provides tools for converting model docs to
274html and viewing the html.  This is used by :mod:`compare` to display
275the model description, such as::
276
277    $ ./sascomp -html sphere
278
279This makes debugging the latex much faster, though this may require
280Qt in order for mathjax to work correctly.
281
282When run as main, it can display arbitrary ReStructuredText files. E.g.,
283
284::
285
286    $ python -m sasmodels.rst2html doc/developer/overview.rst
287
288This is handy for sorting out rst and latex syntax.  With some work
289the results could be improved so that it recognizes sphinx roles
290such as *mod*, *class* and *func*, and so that it uses the style sheets
291from the sasmodels docs.
292
293The :mod:`list_pars` module lists all instances of parameters across
294all models.  This helps to make sure that similar parameters have
295similar names across the different models.  With the verbose flag,
296the particular models which use each named parameter are listed.
297
298
299Model conversion
300----------------
301
302* :mod:`convert`
303* :mod:`conversion_table`
304
305Model definitions are not static.  As needs change or problems are found,
306models may be updated with new model names or may be reparameterized
307with new parameter definitions.  For example, in translating the
308Teubner-Strey model from SasView 3.x to sasmodels, the definition
309in terms of *drho*, *k*, *c1*, *c2*, *a2* and prefactor was replaced
310by the defintion in terms of *volfraction_a*, *xi*, *d*, *sld_a* and
311*sld_b*.  Within :mod:`convert`, the *_hand_convert_3_1_2_to_4_1*
312function must be called when loading a 3.x model definition to update it to
3134.1, and then the model should be further updated to 4.2, 5.0, and so on.
314The :func:`convert.convert_model` function does this, using the conversion
315table in :mod:`conversion_table` (which handled the major renaming from
316SasView 3.x to sasmodels), and using the internal *_hand_convert* function
317for the more complicated cases.
318
319Other
320-----
321
322* :mod:`exception`
323* :mod:`alignment`
324
325The :func:`exception.annotate_exception` function annotates the current
326exception with a context string, such as "while opening myfile.dat" without
327adjusting the traceback.
328
329The :mod:`alignment` module is unused.
Note: See TracBrowser for help on using the repository browser.