source: sasmodels/doc/developer/overview.rst @ eda8b30

core_shell_microgelsmagnetic_modelticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since eda8b30 was eda8b30, checked in by richardh, 7 years ago

further changes to model docs for orientation calcs

  • 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
173For 2d data from oriented anisotropic particles, the mean particle orientation is defined by angles $\theta$, $\phi$ and $\Psi$, which
174are not in general the same as similarly named angles in many form factors. The wikipedia page on Euler angles
175(https://en.wikipedia.org/wiki/Euler_angles) lists the different conventions available. To quote: "Different authors may use different
176sets of rotation axes to define Euler angles, or different names for the same angles. Therefore, any discussion employing Euler angles
177should always be preceded by their definition."
178
179We are using the z-y-z convention with extrinsic rotations $\Psi-\theta-\phi$ for the particle orientation and $x-y-z$ convention with
180extrinsic rotations $\psi-\theta-\phi$ for jitter, with jitter applied before particle orientation.
181
182For numerical integration within form factors etc. sasmodels is mostly using Gaussian quadrature with 20, 76 or 150 points depending on
183the model.  It also makes use of symmetries such as calculating only over one quadrant rather than the whole sphere.  There is often a
184U-substitution replacing $\theta$ with $cos(\theta)$ which changes the limits of integration from 0 to $\pi/2$ to 0 to 1 and also conveniently
185absorbs the $sin(\theta)$ scale factor in the integration.  This can cause confusion if checking equations to say include in a paper or thesis!
186Most models use the same core kernel code expressed in terms of the rotated view (qa, qb, qc) for both the 1D and the 2D models, but there
187are also historical quirks such as the parallelepiped model, which has a useless transformation representing j0(a qa) as j0(b qa a/b).
188
189Useful testing routines include -
190
191:mod:`asymint` a direct implementation of the surface integral for certain models to get a more trusted value for the 1D integral using a reimplementation of the 2D kernel in python and mpmath
192(which computes math functions to arbitrary precision). It uses $\theta$ ranging from 0 to $\pi$ and $\phi$ ranging from 0 to $2\pi$.  It perhaps would benefit
193from including the U-substitution for theta.
194
195:mod:`check1d` uses sasmodels 1D integration and compares that with a rectangle distribution in $\theta$ and $\phi$, with $\theta$ limits set to
196$\pm90/\sqrt(3)$ and $\phi$ limits set to $\pm180/\sqrt(3)$ 
197[The rectangle weight function uses the fact that the distribution width column is labelled sigma to decide
198that the 1-sigma width of a rectangular distribution needs to be multiplied by $\sqrt(3)$ to get the corresponding gaussian equivalent,
199or similar reasoning.]  This should rotate the sample through the entire $\theta-\phi$
200surface according to the pattern that you see in jitter.py when you modify it to use 'rectangle' rather than 'gaussian' for its distribution
201without changing the viewing angle. When computing the dispersity integral, weights are scaled by abs(cos(dtheta)) to account for the points in
202phi getting closer together as dtheta increases.  This integrated dispersion is computed at a set of $(qx, qy)$ points $(q cos(\alpha), q sin(\alpha))$
203at some angle $\alpha$ (currently angle=0) for each q used in the 1-D integration.  The individual q points should be equivalent to asymint rect-n
204when the viewing angle is set to (theta,phi,psi) = (90, 0, 0). Such tests can help to validate that 2d intensity is consistent with 1d models.
205 
206:mod:`sascomp -sphere=n` uses the identical rectangular distribution to compute the pattern of the qx-qy grid.  You can see from triaxial_ellipsoid
207that there may be something wrong conceptually since the pattern is no longer circular when the view (theta,phi,psi) is not (90, phi, 0). 
208check1d shows that it is different from the sasmodels 1D integral even when at theta=0, psi=0. Cross checking the values with asymint,
209the sasmodels 1D integral is better at low q, though for very large structures there are not enough points in the integration for sasmodels 1D
210to compute the high q 1D integral correctly. [Some of that may now be fixed?]
211
212The :mod:`sascomp` utility can be used for 2d as well as 1d calculations to compare results for two sets of parameters or processor types, for example
213these two oriented cylinders here should be equivalent.
214
215: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`
216
[870a2f4]217
218Testing
219-------
220
221* :mod:`model_test`
222* :mod:`compare`
223* :mod:`compare_many`
224* :mod:`rst2html`
225* :mod:`list_pars`
226
227Individual models should all have test values to make sure that the
228evaluation is correct.  This is particularly important in the context
229of OpenCL since sasmodels doesn't control the compiler or the hardware,
230and since GPUs are notorious for preferring speed over precision.  The
231tests can be run as a group using :mod:`model_test` as main::
232
233    $ python -m sasmodels.model_test all
234
235Individual models can be listed instead of *all*, which is convenient when
236adding new models.
237
238The :mod:`compare` module, usually invoked using *./sascomp* provides a
239rich interface for exploring model accuracy, execution speed and parameter
240ranges.  It also allows different models to be compared.
241The :mod:`compare_many` module does batch comparisons, keeping a list of
242the particular random seeds which lead to large differences in output
243between different computing platforms.
244
245The :mod:`rst2html` module provides tools for converting model docs to
246html and viewing the html.  This is used by :mod:`compare` to display
247the model description, such as::
248
249    $ ./sascomp -html sphere
250
251This makes debugging the latex much faster, though this may require
252Qt in order for mathjax to work correctly.
253
254When run as main, it can display arbitrary ReStructuredText files. E.g.,
255
256::
257
258    $ python -m sasmodels.rst2html doc/developer/overview.rst
259
260This is handy for sorting out rst and latex syntax.  With some work
261the results could be improved so that it recognizes sphinx roles
262such as *mod*, *class* and *func*, and so that it uses the style sheets
263from the sasmodels docs.
264
265The :mod:`list_pars` module lists all instances of parameters across
266all models.  This helps to make sure that similar parameters have
267similar names across the different models.  With the verbose flag,
268the particular models which use each named parameter are listed.
269
270
271Model conversion
272----------------
273
274* :mod:`convert`
275* :mod:`conversion_table`
276
277Model definitions are not static.  As needs change or problems are found,
278models may be updated with new model names or may be reparameterized
279with new parameter definitions.  For example, in translating the
280Teubner-Strey model from SasView 3.x to sasmodels, the definition
281in terms of *drho*, *k*, *c1*, *c2*, *a2* and prefactor was replaced
282by the defintion in terms of *volfraction_a*, *xi*, *d*, *sld_a* and
283*sld_b*.  Within :mod:`convert`, the *_hand_convert_3_1_2_to_4_1*
284function must be called when loading a 3.x model definition to update it to
2854.1, and then the model should be further updated to 4.2, 5.0, and so on.
286The :func:`convert.convert_model` function does this, using the conversion
287table in :mod:`conversion_table` (which handled the major renaming from
288SasView 3.x to sasmodels), and using the internal *_hand_convert* function
289for the more complicated cases.
290
291Other
292-----
293
294* :mod:`exception`
295* :mod:`alignment`
296
297The :func:`exception.annotate_exception` function annotates the current
298exception with a context string, such as "while opening myfile.dat" without
299adjusting the traceback.
300
301The :mod:`alignment` module is unused.
Note: See TracBrowser for help on using the repository browser.