source: sasmodels/doc/guide/plugin.rst @ c0d7ab3

core_shell_microgelscostrafo411magnetic_modelticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since c0d7ab3 was 9844c3a, checked in by Paul Kienzle <pkienzle@…>, 7 years ago

add note to the model writer about integer parameters

  • Property mode set to 100644
File size: 40.8 KB
RevLine 
[990d8df]1.. _Writing_a_Plugin:
2
3Writing a Plugin Model
4======================
5
6Overview
7^^^^^^^^
8
9In addition to the models provided with the sasmodels package, you are free to
10create your own models.
11
12Models can be of three types:
13
14- A pure python model : Example -
15  `broadpeak.py <https://github.com/SasView/sasmodels/blob/master/sasmodels/models/broad_peak.py>`_
16
17- A python model with embedded C : Example -
18  `sphere.py <https://github.com/SasView/sasmodels/blob/master/sasmodels/models/sphere.py>`_
19
20- A python wrapper with separate C code : Example -
21  `cylinder.py <https://github.com/SasView/sasmodels/blob/master/sasmodels/models/cylinder.py>`_,
22  `cylinder.c <https://github.com/SasView/sasmodels/blob/master/sasmodels/models/cylinder.c>`_
23
24When using SasView, plugin models should be saved to the SasView
25*plugin_models* folder *C:\\Users\\{username}\\.sasview\\plugin_models*
26(on Windows) or */Users/{username}/.sasview\\plugin_models* (on Mac).
27The next time SasView is started it will compile the plugin and add
28it to the list of *Plugin Models* in a FitPage.  Scripts can load
29the models from anywhere.
30
31The built-in modules are available in the *models* subdirectory
32of the sasmodels package.  For SasView on Windows, these will
33be found in *C:\\Program Files (x86)\\SasView\\sasmodels-data\\models*.
34On Mac OSX, these will be within the application bundle as
35*/Applications/SasView 4.0.app/Contents/Resources/sasmodels-data/models*.
36
37Other models are available for download from the
38`Model Marketplace <http://marketplace.sasview.org/>`_. You can contribute your
39own models to the Marketplace as well.
40
41Create New Model Files
42^^^^^^^^^^^^^^^^^^^^^^
43
44Copy the appropriate files to your plugin models directory (we recommend
45using the examples above as templates) as mymodel.py (and mymodel.c, etc)
46as required, where "mymodel" is the name for the model you are creating.
47
48*Please follow these naming rules:*
49
50- No capitalization and thus no CamelCase
51- If necessary use underscore to separate words (i.e. barbell not BarBell or
52  broad_peak not BroadPeak)
53- Do not include "model" in the name (i.e. barbell not BarBellModel)
54
55
56Edit New Model Files
57^^^^^^^^^^^^^^^^^^^^
58
59Model Contents
60..............
61
62The model interface definition is in the .py file.  This file contains:
63
64- a **model name**:
65   - this is the **name** string in the *.py* file
66   - titles should be:
67
68    - all in *lower* case
69    - without spaces (use underscores to separate words instead)
70    - without any capitalization or CamelCase
71    - without incorporating the word "model"
72    - examples: *barbell* **not** *BarBell*; *broad_peak* **not** *BroadPeak*;
73      *barbell* **not** *BarBellModel*
74
75- a **model title**:
76   - this is the **title** string in the *.py* file
77   - this is a one or two line description of the model, which will appear
78     at the start of the model documentation and as a tooltip in the SasView GUI
79
80- a **short discription**:
81   - this is the **description** string in the *.py* file
82   - this is a medium length description which appears when you click
83     *Description* on the model FitPage
84
85- a **parameter table**:
86   - this will be auto-generated from the *parameters* in the *.py* file
87
88- a **long description**:
89   - this is ReStructuredText enclosed between the r""" and """ delimiters
90     at the top of the *.py* file
91   - what you write here is abstracted into the SasView help documentation
92   - this is what other users will refer to when they want to know what
93     your model does; so please be helpful!
94
95- a **definition** of the model:
96   - as part of the **long description**
97
98- a **formula** defining the function the model calculates:
99   - as part of the **long description**
100
101- an **explanation of the parameters**:
102   - as part of the **long description**
103   - explaining how the symbols in the formula map to the model parameters
104
105- a **plot** of the function, with a **figure caption**:
106   - this is automatically generated from your default parameters
107
108- at least one **reference**:
109   - as part of the **long description**
110   - specifying where the reader can obtain more information about the model
111
112- the **name of the author**
113   - as part of the **long description**
114   - the *.py* file should also contain a comment identifying *who*
115     converted/created the model file
116
117Models that do not conform to these requirements will *never* be incorporated
118into the built-in library.
119
120
121Model Documentation
122...................
123
124The *.py* file starts with an r (for raw) and three sets of quotes
125to start the doc string and ends with a second set of three quotes.
126For example::
127
128    r"""
129    Definition
130    ----------
131
132    The 1D scattering intensity of the sphere is calculated in the following
133    way (Guinier, 1955)
134
135    .. math::
136
137        I(q) = \frac{\text{scale}}{V} \cdot \left[
138            3V(\Delta\rho) \cdot \frac{\sin(qr) - qr\cos(qr))}{(qr)^3}
139            \right]^2 + \text{background}
140
141    where *scale* is a volume fraction, $V$ is the volume of the scatterer,
142    $r$ is the radius of the sphere and *background* is the background level.
143    *sld* and *sld_solvent* are the scattering length densities (SLDs) of the
144    scatterer and the solvent respectively, whose difference is $\Delta\rho$.
145
146    You can included figures in your documentation, as in the following
147    figure for the cylinder model.
148
149    .. figure:: img/cylinder_angle_definition.jpg
150
151        Definition of the angles for oriented cylinders.
152
153    References
154    ----------
155
156    A Guinier, G Fournet, *Small-Angle Scattering of X-Rays*,
157    John Wiley and Sons, New York, (1955)
158    """
159
160This is where the FULL documentation for the model goes (to be picked up by
161the automatic documentation system).  Although it feels odd, you
162should start the documentation immediately with the **definition**---the model
163name, a brief description and the parameter table are automatically inserted
164above the definition, and the a plot of the model is automatically inserted
165before the **reference**.
166
167Figures can be included using the *figure* command, with the name
168of the *.png* file containing the figure and a caption to appear below the
169figure.  Figure numbers will be added automatically.
170
171See this `Sphinx cheat sheet <http://matplotlib.org/sampledoc/cheatsheet.html>`_
172for a quick guide to the documentation layout commands, or the
173`Sphinx Documentation <http://www.sphinx-doc.org/en/stable/>`_ for
174complete details.
175
176The model should include a **formula** written using LaTeX markup.
177The example above uses the *math* command to make a displayed equation.  You
178can also use *\$formula\$* for an inline formula. This is handy for defining
179the relationship between the model parameters and formula variables, such
180as the phrase "\$r\$ is the radius" used above.  The live demo MathJax
181page `<http://www.mathjax.org/>`_ is handy for checking that the equations
182will look like you intend.
183
184Math layout uses the `amsmath <http://www.ams.org/publications/authors/tex/amslatex>`_
185package for aligning equations (see amsldoc.pdf on that page for complete
186documentation). You will automatically be in an aligned environment, with
187blank lines separating the lines of the equation.  Place an ampersand before
188the operator on which to align.  For example::
189
190    .. math::
191
192      x + y &= 1 \\
193      y &= x - 1
194
195produces
196
197.. math::
198
199      x + y &= 1 \\
200      y &= x - 1
201
202If you need more control, use::
203
204    .. math::
205        :nowrap:
206
207
208Model Definition
209................
210
211Following the documentation string, there are a series of definitions::
212
213    name = "sphere"  # optional: defaults to the filename without .py
214
215    title = "Spheres with uniform scattering length density"
216
217    description = """\
218    P(q)=(scale/V)*[3V(sld-sld_solvent)*(sin(qr)-qr cos(qr))
219                    /(qr)^3]^2 + background
220        r: radius of sphere
221        V: The volume of the scatter
222        sld: the SLD of the sphere
223        sld_solvent: the SLD of the solvent
224    """
225
226    category = "shape:sphere"
227
228    single = True   # optional: defaults to True
229
230    opencl = False  # optional: defaults to False
231
232    structure_factor = False  # optional: defaults to False
233
234**name = "mymodel"** defines the name of the model that is shown to the user.
235If it is not provided, it will use the name of the model file, with '_'
236replaced by spaces and the parts capitalized.  So *adsorbed_layer.py* will
237become *Adsorbed Layer*.  The predefined models all use the name of the
238model file as the name of the model, so the default may be changed.
239
240**title = "short description"** is short description of the model which
241is included after the model name in the automatically generated documentation.
242The title can also be used for a tooltip.
243
244**description = """doc string"""** is a longer description of the model. It
245shows up when you press the "Description" button of the SasView FitPage.
246It should give a brief description of the equation and the parameters
247without the need to read the entire model documentation. The triple quotes
248allow you to write the description over multiple lines. Keep the lines
249short since the GUI will wrap each one separately if they are too long.
250**Make sure the parameter names in the description match the model definition!**
251
252**category = "shape:sphere"** defines where the model will appear in the
253model documentation.  In this example, the model will appear alphabetically
254in the list of spheroid models in the *Shape* category.
255
256**single = True** indicates that the model can be run using single
257precision floating point values.  Set it to False if the numerical
258calculation for the model is unstable, which is the case for about 20 of
259the built in models.  It is worthwhile modifying the calculation to support
260single precision, allowing models to run up to 10 times faster.  The
261section `Test_Your_New_Model`_  describes how to compare model values for
262single vs. double precision so you can decide if you need to set
263single to False.
264
265**opencl = False** indicates that the model should not be run using OpenCL.
266This may be because the model definition includes code that cannot be
267compiled for the GPU (for example, goto statements).  It can also be used
268for large models which can't run on most GPUs.  This flag has not been
269used on any of the built in models; models which were failing were
270streamlined so this flag was not necessary.
271
272**structure_factor = True** indicates that the model can be used as a
273structure factor to account for interactions between particles.  See
274`Form_Factors`_ for more details.
275
276Model Parameters
277................
278
279Next comes the parameter table.  For example::
280
281    # pylint: disable=bad-whitespace, line-too-long
282    #   ["name",        "units", default, [min, max], "type",    "description"],
283    parameters = [
284        ["sld",         "1e-6/Ang^2",  1, [-inf, inf], "sld",    "Layer scattering length density"],
285        ["sld_solvent", "1e-6/Ang^2",  6, [-inf, inf], "sld",    "Solvent scattering length density"],
286        ["radius",      "Ang",        50, [0, inf],    "volume", "Sphere radius"],
287    ]
288    # pylint: enable=bad-whitespace, line-too-long
289
290**parameters = [["name", "units", default, [min,max], "type", "tooltip"],...]**
291defines the parameters that form the model.
292
293**Note: The order of the parameters in the definition will be the order of the
294parameters in the user interface and the order of the parameters in Iq(),
295Iqxy() and form_volume(). And** *scale* **and** *background* **parameters are
296implicit to all models, so they do not need to be included in the parameter table.**
297
298- **"name"** is the name of the parameter shown on the FitPage.
299
300  - parameter names should follow the mathematical convention; e.g.,
301    *radius_core* not *core_radius*, or *sld_solvent* not *solvent_sld*.
302
303  - model parameter names should be consistent between different models,
304    so *sld_solvent*, for example, should have exactly the same name
305    in every model.
306
307  - to see all the parameter names currently in use, type the following in the
308    python shell/editor under the Tools menu::
309
310       import sasmodels.list_pars
311       sasmodels.list_pars.list_pars()
312
313    *re-use* as many as possible!!!
314
315  - use "name[n]" for multiplicity parameters, where *n* is the name of
316    the parameter defining the number of shells/layers/segments, etc.
317
318- **"units"** are displayed along with the parameter name
319
320  - every parameter should have units; use "None" if there are no units.
321
322  - **sld's should be given in units of 1e-6/Ang^2, and not simply
323    1/Ang^2 to be consistent with the builtin models.  Adjust your formulas
324    appropriately.**
325
326  - fancy units markup is available for some units, including::
327
328        Ang, 1/Ang, 1/Ang^2, 1e-6/Ang^2, degrees, 1/cm, Ang/cm, g/cm^3, mg/m^2
329
330  - the list of units is defined in the variable *RST_UNITS* within
331    `sasmodels/generate.py <https://github.com/SasView/sasmodels/tree/master/sasmodels/generate.py>`_
332
333    - new units can be added using the macros defined in *doc/rst_prolog*
334      in the sasmodels source.
335    - units should be properly formatted using sub-/super-scripts
336      and using negative exponents instead of the / operator, though
337      the unit name should use the / operator for consistency.
338    - please post a message to the SasView developers mailing list with your changes.
339
340- **default** is the initial value for the parameter.
341
342  - **the parameter default values are used to auto-generate a plot of
343    the model function in the documentation.**
344
345- **[min, max]** are the lower and upper limits on the parameter.
346
347  - lower and upper limits can be any number, or *-inf* or *inf*.
348
349  - the limits will show up as the default limits for the fit making it easy,
350    for example, to force the radius to always be greater than zero.
351
352  - these are hard limits defining the valid range of parameter values;
353    polydisperity distributions will be truncated at the limits.
354
355- **"type"** can be one of: "", "sld", "volume", or "orientation".
356
357  - "sld" parameters can have magnetic moments when fitting magnetic models;
358    depending on the spin polarization of the beam and the $q$ value being
359    examined, the effective sld for that material will be used to compute the
360    scattered intensity.
361
362  - "volume" parameters are passed to Iq(), Iqxy(), and form_volume(), and
363    have polydispersity loops generated automatically.
364
365  - "orientation" parameters are only passed to Iqxy(), and have angular
366    dispersion.
367
368
[9844c3a]369Integer Parameters
370..................
371
372Some models will have integer parameters, such as number of pearls in the
373pearl necklace model, or number of shells in the multi-layer vesicle model.
374The optimizers in BUMPS treat all parameters as floating point numbers which
375can take arbitrary values, even for integer parameters, so your model should
376round the incoming parameter value to the nearest integer inside your model
377you should round to the nearest integer.  In C code, you can do this using::
378
379    static double
380    Iq(double q, ..., double fp_n, ...)
381    {
382        int n = (int)(fp_n + 0.5);
383        ...
384    }
385
386in python::
387
388    def Iq(q, ..., n, ...):
389        n = int(n+0.5)
390        ...
391
392Derivatibve based optimizers such as Levenberg-Marquardt will not work
393for integer parameters since the partial derivative is always zero, but
394the remaining optimizers (DREAM, differential evolution, Nelder-Mead simplex)
395will still function.
396
[990d8df]397Model Computation
398.................
399
400Models can be defined as pure python models, or they can be a mixture of
401python and C models.  C models are run on the GPU if it is available,
402otherwise they are compiled and run on the CPU.
403
404Models are defined by the scattering kernel, which takes a set of parameter
405values defining the shape, orientation and material, and returns the
406expected scattering. Polydispersity and angular dispersion are defined
407by the computational infrastructure.  Any parameters defined as "volume"
408parameters are polydisperse, with polydispersity defined in proportion
409to their value.  "orientation" parameters use angular dispersion defined
410in degrees, and are not relative to the current angle.
411
412Based on a weighting function $G(x)$ and a number of points $n$, the
413computed value is
414
415.. math::
416
417     \hat I(q)
418     = \frac{\int G(x) I(q, x)\,dx}{\int G(x) V(x)\,dx}
419     \approx \frac{\sum_{i=1}^n G(x_i) I(q,x_i)}{\sum_{i=1}^n G(x_i) V(x_i)}
420
421That is, the indivdual models do not need to include polydispersity
422calculations, but instead rely on numerical integration to compute the
423appropriately smeared pattern.   Angular dispersion values over polar angle
424$\theta$ requires an additional $\cos \theta$ weighting due to decreased
425arc length for the equatorial angle $\phi$ with increasing latitude.
426
427Python Models
428.............
429
430For pure python models, define the *Iq* function::
431
432      import numpy as np
433      from numpy import cos, sin, ...
434
435      def Iq(q, par1, par2, ...):
436          return I(q, par1, par2, ...)
437      Iq.vectorized = True
438
439The parameters *par1, par2, ...* are the list of non-orientation parameters
440to the model in the order that they appear in the parameter table.
441**Note that the autogenerated model file uses** *x* **rather than** *q*.
442
443The *.py* file should import trigonometric and exponential functions from
444numpy rather than from math.  This lets us evaluate the model for the whole
445range of $q$ values at once rather than looping over each $q$ separately in
446python.  With $q$ as a vector, you cannot use if statements, but must instead
447do tricks like
448
449::
450
451     a = x*q*(q>0) + y*q*(q<=0)
452
453or
454
455::
456
457     a = np.empty_like(q)
458     index = q>0
459     a[index] = x*q[index]
460     a[~index] = y*q[~index]
461
462which sets $a$ to $q \cdot x$ if $q$ is positive or $q \cdot y$ if $q$
463is zero or negative. If you have not converted your function to use $q$
464vectors, you can set the following and it will only receive one $q$
465value at a time::
466
467    Iq.vectorized = False
468
469Return np.NaN if the parameters are not valid (e.g., cap_radius < radius in
470barbell).  If I(q; pars) is NaN for any $q$, then those parameters will be
471ignored, and not included in the calculation of the weighted polydispersity.
472
473Similar to *Iq*, you can define *Iqxy(qx, qy, par1, par2, ...)* where the
474parameter list includes any orientation parameters.  If *Iqxy* is not defined,
475then it will default to *Iqxy = Iq(sqrt(qx**2+qy**2), par1, par2, ...)*.
476
477Models should define *form_volume(par1, par2, ...)* where the parameter
478list includes the *volume* parameters in order.  This is used for a weighted
479volume normalization so that scattering is on an absolute scale.  If
480*form_volume* is not defined, then the default *form_volume = 1.0* will be
481used.
482
483Embedded C Models
484.................
485
486Like pure python models, inline C models need to define an *Iq* function::
487
488    Iq = """
489        return I(q, par1, par2, ...);
490    """
491
492This expands into the equivalent C code::
493
494    #include <math.h>
495    double Iq(double q, double par1, double par2, ...);
496    double Iq(double q, double par1, double par2, ...)
497    {
498        return I(q, par1, par2, ...);
499    }
500
501*Iqxy* is similar to *Iq*, except it uses parameters *qx, qy* instead of *q*,
502and it includes orientation parameters.
503
504*form_volume* defines the volume of the shape. As in python models, it
505includes only the volume parameters.
506
507*Iqxy* will default to *Iq(sqrt(qx**2 + qy**2), par1, ...)* and
508*form_volume* will default to 1.0.
509
510**source=['fn.c', ...]** includes the listed C source files in the
511program before *Iq* and *Iqxy* are defined. This allows you to extend the
512library of C functions available to your model.
513
514Models are defined using double precision declarations for the
515parameters and return values.  When a model is run using single
516precision or long double precision, each variable is converted
517to the target type, depending on the precision requested.
518
519**Floating point constants must include the decimal point.**  This allows us
520to convert values such as 1.0 (double precision) to 1.0f (single precision)
521so that expressions that use these values are not promoted to double precision
522expressions.  Some graphics card drivers are confused when functions
523that expect floating point values are passed integers, such as 4*atan(1); it
524is safest to not use integers in floating point expressions.  Even better,
525use the builtin constant M_PI rather than 4*atan(1); it is faster and smaller!
526
527The C model operates on a single $q$ value at a time.  The code will be
528run in parallel across different $q$ values, either on the graphics card
529or the processor.
530
531Rather than returning NAN from Iq, you must define the *INVALID(v)*.  The
532*v* parameter lets you access all the parameters in the model using
533*v.par1*, *v.par2*, etc. For example::
534
535    #define INVALID(v) (v.bell_radius < v.radius)
536
537Special Functions
538.................
539
540The C code follows the C99 standard, with the usual math functions,
541as defined in
542`OpenCL <https://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/mathFunctions.html>`_.
543This includes the following:
544
545    M_PI, M_PI_2, M_PI_4, M_SQRT1_2, M_E:
546        $\pi$, $\pi/2$, $\pi/4$, $1/\sqrt{2}$ and Euler's constant $e$
547    exp, log, pow(x,y), expm1, sqrt:
548        Power functions $e^x$, $\ln x$, $x^y$, $e^x - 1$, $\sqrt{x}$.
549        The function expm1(x) is accurate across all $x$, including $x$
550        very close to zero.
551    sin, cos, tan, asin, acos, atan:
552        Trigonometry functions and inverses, operating on radians.
553    sinh, cosh, tanh, asinh, acosh, atanh:
554        Hyperbolic trigonometry functions.
555    atan2(y,x):
556        Angle from the $x$\ -axis to the point $(x,y)$, which is equal to
557        $\tan^{-1}(y/x)$ corrected for quadrant.  That is, if $x$ and $y$ are
558        both negative, then atan2(y,x) returns a value in quadrant III where
559        atan(y/x) would return a value in quadrant I. Similarly for
560        quadrants II and IV when $x$ and $y$ have opposite sign.
561    fmin(x,y), fmax(x,y), trunc, rint:
562        Floating point functions.  rint(x) returns the nearest integer.
563    NAN:
564        NaN, Not a Number, $0/0$.  Use isnan(x) to test for NaN.  Note that
565        you cannot use :code:`x == NAN` to test for NaN values since that
566        will always return false.  NAN does not equal NAN!
567    INFINITY:
568        $\infty, 1/0$.  Use isinf(x) to test for infinity, or isfinite(x)
569        to test for finite and not NaN.
570    erf, erfc, tgamma, lgamma:  **do not use**
571        Special functions that should be part of the standard, but are missing
572        or inaccurate on some platforms. Use sas_erf, sas_erfc and sas_gamma
573        instead (see below). Note: lgamma(x) has not yet been tested.
574
575Some non-standard constants and functions are also provided:
576
577    M_PI_180, M_4PI_3:
578        $\frac{\pi}{180}$, $\frac{4\pi}{3}$
579    SINCOS(x, s, c):
580        Macro which sets s=sin(x) and c=cos(x). The variables *c* and *s*
581        must be declared first.
582    square(x):
583        $x^2$
584    cube(x):
585        $x^3$
586    sas_sinx_x(x):
587        $\sin(x)/x$, with limit $\sin(0)/0 = 1$.
588    powr(x, y):
589        $x^y$ for $x \ge 0$; this is faster than general $x^y$ on some GPUs.
590    pown(x, n):
591        $x^n$ for $n$ integer; this is faster than general $x^n$ on some GPUs.
592    FLOAT_SIZE:
593        The number of bytes in a floating point value.  Even though all
594        variables are declared double, they may be converted to single
595        precision float before running. If your algorithm depends on
596        precision (which is not uncommon for numerical algorithms), use
597        the following::
598
599            #if FLOAT_SIZE>4
600            ... code for double precision ...
601            #else
602            ... code for single precision ...
603            #endif
604    SAS_DOUBLE:
605        A replacement for :code:`double` so that the declared variable will
606        stay double precision; this should generally not be used since some
607        graphics cards do not support double precision.  There is no provision
608        for forcing a constant to stay double precision.
609
610The following special functions and scattering calculations are defined in
611`sasmodels/models/lib <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib>`_.
612These functions have been tuned to be fast and numerically stable down
613to $q=0$ even in single precision.  In some cases they work around bugs
614which appear on some platforms but not others, so use them where needed.
615Add the files listed in :code:`source = ["lib/file.c", ...]` to your *model.py*
616file in the order given, otherwise these functions will not be available.
617
618    polevl(x, c, n):
619        Polynomial evaluation $p(x) = \sum_{i=0}^n c_i x^i$ using Horner's
620        method so it is faster and more accurate.
621
622        $c = \{c_n, c_{n-1}, \ldots, c_0 \}$ is the table of coefficients,
623        sorted from highest to lowest.
624
625        :code:`source = ["lib/polevl.c", ...]` (`link to code <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/polevl.c>`_)
626
627    p1evl(x, c, n):
628        Evaluation of normalized polynomial $p(x) = x^n + \sum_{i=0}^{n-1} c_i x^i$
629        using Horner's method so it is faster and more accurate.
630
631        $c = \{c_{n-1}, c_{n-2} \ldots, c_0 \}$ is the table of coefficients,
632        sorted from highest to lowest.
633
634        :code:`source = ["lib/polevl.c", ...]`
[870a2f4]635        (`polevl.c <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/polevl.c>`_)
[990d8df]636
637    sas_gamma(x):
[30b60d2]638        Gamma function sas_gamma\ $(x) = \Gamma(x)$.
[990d8df]639
640        The standard math function, tgamma(x) is unstable for $x < 1$
641        on some platforms.
642
[870a2f4]643        :code:`source = ["lib/sas_gamma.c", ...]`
644        (`sas_gamma.c <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/sas_gamma.c>`_)
[990d8df]645
646    sas_erf(x), sas_erfc(x):
647        Error function
[30b60d2]648        sas_erf\ $(x) = \frac{2}{\sqrt\pi}\int_0^x e^{-t^2}\,dt$
[990d8df]649        and complementary error function
[30b60d2]650        sas_erfc\ $(x) = \frac{2}{\sqrt\pi}\int_x^{\infty} e^{-t^2}\,dt$.
[990d8df]651
652        The standard math functions erf(x) and erfc(x) are slower and broken
653        on some platforms.
654
655        :code:`source = ["lib/polevl.c", "lib/sas_erf.c", ...]`
[870a2f4]656        (`sas_erf.c <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/sas_erf.c>`_)
[990d8df]657
658    sas_J0(x):
[30b60d2]659        Bessel function of the first kind sas_J0\ $(x)=J_0(x)$ where
[990d8df]660        $J_0(x) = \frac{1}{\pi}\int_0^\pi \cos(x\sin(\tau))\,d\tau$.
661
662        The standard math function j0(x) is not available on all platforms.
663
664        :code:`source = ["lib/polevl.c", "lib/sas_J0.c", ...]`
[870a2f4]665        (`sas_J0.c <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/sas_J0.c>`_)
[990d8df]666
667    sas_J1(x):
[30b60d2]668        Bessel function of the first kind  sas_J1\ $(x)=J_1(x)$ where
[990d8df]669        $J_1(x) = \frac{1}{\pi}\int_0^\pi \cos(\tau - x\sin(\tau))\,d\tau$.
670
671        The standard math function j1(x) is not available on all platforms.
672
673        :code:`source = ["lib/polevl.c", "lib/sas_J1.c", ...]`
[870a2f4]674        (`sas_J1.c <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/sas_J1.c>`_)
[990d8df]675
676    sas_JN(n, x):
[30b60d2]677        Bessel function of the first kind and integer order $n$,
678        sas_JN\ $(n, x) =J_n(x)$ where
[990d8df]679        $J_n(x) = \frac{1}{\pi}\int_0^\pi \cos(n\tau - x\sin(\tau))\,d\tau$.
[30b60d2]680        If $n$ = 0 or 1, it uses sas_J0($x$) or sas_J1($x$), respectively.
[990d8df]681
682        The standard math function jn(n, x) is not available on all platforms.
683
684        :code:`source = ["lib/polevl.c", "lib/sas_J0.c", "lib/sas_J1.c", "lib/sas_JN.c", ...]`
[870a2f4]685        (`sas_JN.c <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/sas_JN.c>`_)
[990d8df]686
687    sas_Si(x):
[30b60d2]688        Sine integral Si\ $(x) = \int_0^x \tfrac{\sin t}{t}\,dt$.
[990d8df]689
690        This function uses Taylor series for small and large arguments:
691
692        For large arguments,
693
694        .. math::
695
696             \text{Si}(x) \sim \frac{\pi}{2}
697             - \frac{\cos(x)}{x}\left(1 - \frac{2!}{x^2} + \frac{4!}{x^4} - \frac{6!}{x^6} \right)
698             - \frac{\sin(x)}{x}\left(\frac{1}{x} - \frac{3!}{x^3} + \frac{5!}{x^5} - \frac{7!}{x^7}\right)
699
700        For small arguments,
701
702        .. math::
703
704           \text{Si}(x) \sim x
705           - \frac{x^3}{3\times 3!} + \frac{x^5}{5 \times 5!} - \frac{x^7}{7 \times 7!}
706           + \frac{x^9}{9\times 9!} - \frac{x^{11}}{11\times 11!}
707
708        :code:`source = ["lib/Si.c", ...]`
[870a2f4]709        (`Si.c <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/Si.c>`_)
[990d8df]710
711    sas_3j1x_x(x):
712        Spherical Bessel form
[30b60d2]713        sph_j1c\ $(x) = 3 j_1(x)/x = 3 (\sin(x) - x \cos(x))/x^3$,
[990d8df]714        with a limiting value of 1 at $x=0$, where $j_1(x)$ is the spherical
715        Bessel function of the first kind and first order.
716
717        This function uses a Taylor series for small $x$ for numerical accuracy.
718
719        :code:`source = ["lib/sas_3j1x_x.c", ...]`
[870a2f4]720        (`sas_3j1x_x.c <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/sas_3j1x_x.c>`_)
[990d8df]721
722
723    sas_2J1x_x(x):
[30b60d2]724        Bessel form sas_J1c\ $(x) = 2 J_1(x)/x$, with a limiting value
[990d8df]725        of 1 at $x=0$, where $J_1(x)$ is the Bessel function of first kind
726        and first order.
727
728        :code:`source = ["lib/polevl.c", "lib/sas_J1.c", ...]`
[870a2f4]729        (`sas_J1.c <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/sas_J1.c>`_)
[990d8df]730
731
732    Gauss76Z[i], Gauss76Wt[i]:
733        Points $z_i$ and weights $w_i$ for 76-point Gaussian quadrature, respectively,
734        computing $\int_{-1}^1 f(z)\,dz \approx \sum_{i=1}^{76} w_i\,f(z_i)$.
735
736        Similar arrays are available in :code:`gauss20.c` for 20-point
737        quadrature and in :code:`gauss150.c` for 150-point quadrature.
738
739        :code:`source = ["lib/gauss76.c", ...]`
[870a2f4]740        (`gauss76.c <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib/gauss76.c>`_)
[990d8df]741
742
743
744Problems with C models
745......................
746
747The graphics processor (GPU) in your computer is a specialized computer tuned
748for certain kinds of problems.  This leads to strange restrictions that you
749need to be aware of.  Your code may work fine on some platforms or for some
750models, but then return bad values on other platforms.  Some examples of
751particular problems:
752
753  **(1) Code is too complex, or uses too much memory.** GPU devices only
754  have a limited amount of memory available for each processor. If you run
755  programs which take too much memory, then rather than running multiple
756  values in parallel as it usually does, the GPU may only run a single
757  version of the code at a time, making it slower than running on the CPU.
758  It may fail to run on some platforms, or worse, cause the screen to go
759  blank or the system to reboot.
760
761  **(2) Code takes too long.** Because GPU devices are used for the computer
762  display, the OpenCL drivers are very careful about the amount of time they
763  will allow any code to run. For example, on OS X, the model will stop
764  running after 5 seconds regardless of whether the computation is complete.
765  You may end up with only some of your 2D array defined, with the rest
766  containing random data. Or it may cause the screen to go blank or the
767  system to reboot.
768
769  **(3) Memory is not aligned**. The GPU hardware is specialized to operate
770  on multiple values simultaneously. To keep the GPU simple the values in
771  memory must be aligned with the different GPU compute engines. Not
772  following these rules can lead to unexpected values being loaded into
773  memory, and wrong answers computed. The conclusion from a very long and
774  strange debugging session was that any arrays that you declare in your
775  model should be a multiple of four. For example::
776
777      double Iq(q, p1, p2, ...)
778      {
779          double vector[8];  // Only going to use seven slots, but declare 8
780          ...
781      }
782
783The first step when your model is behaving strangely is to set
784**single=False**. This automatically restricts the model to only run on the
785CPU, or on high-end GPU cards. There can still be problems even on high-end
786cards, so you can force the model off the GPU by setting **opencl=False**.
787This runs the model as a normal C program without any GPU restrictions so
788you know that strange results are probably from your code rather than the
789environment. Once the code is debugged, you can compare your output to the
790output on the GPU.
791
792Although it can be difficult to get your model to work on the GPU, the reward
793can be a model that runs 1000x faster on a good card.  Even your laptop may
794show a 50x improvement or more over the equivalent pure python model.
795
796External C Models
797.................
798
799External C models are very much like embedded C models, except that
800*Iq*, *Iqxy* and *form_volume* are defined in an external source file
801loaded using the *source=[...]* statement. You need to supply the function
802declarations for each of these that you need instead of building them
803automatically from the parameter table.
804
805
806.. _Form_Factors:
807
808Form Factors
809............
810
811Away from the dilute limit you can estimate scattering including
812particle-particle interactions using $I(q) = P(q)*S(q)$ where $P(q)$
813is the form factor and $S(q)$ is the structure factor.  The simplest
814structure factor is the *hardsphere* interaction, which
815uses the effective radius of the form factor as an input to the structure
816factor model.  The effective radius is the average radius of the
817form averaged over all the polydispersity values.
818
819::
820
821    def ER(radius, thickness):
822        """Effective radius of a core-shell sphere."""
823        return radius + thickness
824
825Now consider the *core_shell_sphere*, which has a simple effective radius
826equal to the radius of the core plus the thickness of the shell, as
827shown above. Given polydispersity over *(r1, r2, ..., rm)* in radius and
828*(t1, t2, ..., tn)* in thickness, *ER* is called with a mesh
829grid covering all possible combinations of radius and thickness.
830That is, *radius* is *(r1, r2, ..., rm, r1, r2, ..., rm, ...)*
831and *thickness* is *(t1, t1, ... t1, t2, t2, ..., t2, ...)*.
832The *ER* function returns one effective radius for each combination.
833The effective radius calculator weights each of these according to
834the polydispersity distributions and calls the structure factor
835with the average *ER*.
836
837::
838
839    def VR(radius, thickness):
840        """Sphere and shell volumes for a core-shell sphere."""
841        whole = 4.0/3.0 * pi * (radius + thickness)**3
842        core = 4.0/3.0 * pi * radius**3
843        return whole, whole - core
844
845Core-shell type models have an additional volume ratio which scales
846the structure factor.  The *VR* function returns the volume of
847the whole sphere and the volume of the shell. Like *ER*, there is
848one return value for each point in the mesh grid.
849
850*NOTE: we may be removing or modifying this feature soon. As of the
851time of writing, core-shell sphere returns (1., 1.) for VR, giving a volume
852ratio of 1.0.*
853
854Unit Tests
855..........
856
857THESE ARE VERY IMPORTANT. Include at least one test for each model and
858PLEASE make sure that the answer value is correct (i.e. not a random number).
859
860::
861
862    tests = [
863        [{}, 0.2, 0.726362],
864        [{"scale": 1., "background": 0., "sld": 6., "sld_solvent": 1.,
865          "radius": 120., "radius_pd": 0.2, "radius_pd_n":45},
866         0.2, 0.228843],
867        [{"radius": 120., "radius_pd": 0.2, "radius_pd_n":45}, "ER", 120.],
868        [{"radius": 120., "radius_pd": 0.2, "radius_pd_n":45}, "VR", 1.],
869    ]
870
871
872**tests=[[{parameters}, q, result], ...]** is a list of lists.
873Each list is one test and contains, in order:
874
875- a dictionary of parameter values. This can be *{}* using the default
876  parameters, or filled with some parameters that will be different from the
877  default, such as *{"radius":10.0, "sld":4}*. Unlisted parameters will
878  be given the default values.
879- the input $q$ value or tuple of $(q_x, q_y)$ values.
880- the output $I(q)$ or $I(q_x,q_y)$ expected of the model for the parameters
881  and input value given.
882- input and output values can themselves be lists if you have several
883  $q$ values to test for the same model parameters.
884- for testing *ER* and *VR*, give the inputs as "ER" and "VR" respectively;
885  the output for *VR* should be the sphere/shell ratio, not the individual
886  sphere and shell values.
887
888.. _Test_Your_New_Model:
889
890Test Your New Model
891^^^^^^^^^^^^^^^^^^^
892
893Minimal Testing
894...............
895
896From SasView either open the Python shell (*Tools* > *Python Shell/Editor*)
897or the plugin editor (*Fitting* > *Plugin Model Operations* > *Advanced
898Plugin Editor*), load your model, and then select *Run > Check Model* from
899the menu bar. An *Info* box will appear with the results of the compilation
900and a check that the model runs.
901
902If you are not using sasmodels from SasView, skip this step.
903
904Recommended Testing
905...................
906
907If the model compiles and runs, you can next run the unit tests that
908you have added using the **test =** values.
909
910From SasView, switch to the *Shell* tab and type the following::
911
912    from sasmodels.model_test import run_one
913    run_one("~/.sasview/plugin_models/model.py")
914
915This should print::
916
917    test_model_python (sasmodels.model_test.ModelTestCase) ... ok
918
919To check whether single precision is good enough, type the following::
920
921    from sasmodels.compare import main as compare
922    compare("~/.sasview/plugin_models/model.py")
923
924This will pop up a plot showing the difference between single precision
925and double precision on a range of $q$ values.
926
927::
928
929  demo = dict(scale=1, background=0,
930              sld=6, sld_solvent=1,
931              radius=120,
932              radius_pd=.2, radius_pd_n=45)
933
934**demo={'par': value, ...}** in the model file sets the default values for
935the comparison. You can include polydispersity parameters such as
936*radius_pd=0.2, radius_pd_n=45* which would otherwise be zero.
937
938These commands can also be run directly in the python interpreter:
939
940    $ python -m sasmodels.model_test -v ~/.sasview/plugin_models/model.py
941    $ python -m sasmodels.compare ~/.sasview/plugin_models/model.py
942
943The options to compare are quite extensive; type the following for help::
944
945    compare()
946
947Options will need to be passed as separate strings.
948For example to run your model with a random set of parameters::
949
950    compare("-random", "-pars", "~/.sasview/plugin_models/model.py")
951
952For the random models,
953
954- *sld* will be in the range (-0.5,10.5),
955- angles (*theta, phi, psi*) will be in the range (-180,180),
956- angular dispersion will be in the range (0,45),
957- polydispersity will be in the range (0,1)
958- other values will be in the range (0, 2\ *v*), where *v* is the value
959  of the parameter in demo.
960
961Dispersion parameters *n*\, *sigma* and *type* will be unchanged from
962demo so that run times are more predictable (polydispersity calculated
963across multiple parameters can be very slow).
964
965If your model has 2D orientational calculation, then you should also
966test with::
967
968    compare("-2d", "~/.sasview/plugin_models/model.py")
969
970Check The Docs
971^^^^^^^^^^^^^^
972
973You can get a rough idea of how the documentation will look using the
974following::
975
976    compare("-help", "~/.sasview/plugin_models/model.py")
977
978This does not use the same styling as the rest of the docs, but it will
979allow you to check that your ReStructuredText and LaTeX formatting.
980Here are some tools to help with the inevitable syntax errors:
981
982- `Sphinx cheat sheet <http://matplotlib.org/sampledoc/cheatsheet.html>`_
983- `Sphinx Documentation <http://www.sphinx-doc.org/en/stable/>`_
984- `MathJax <http://www.mathjax.org/>`_
985- `amsmath <http://www.ams.org/publications/authors/tex/amslatex>`_
986
987There is also a neat online WYSIWYG ReStructuredText editor at
988http://rst.ninjs.org\ .
989
990
991Clean Lint - (Developer Version Only)
992^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
993
994**NB: For now we are not providing pylint with the installer version
995of SasView; so unless you have a SasView build environment available,
996you can ignore this section!**
997
998Run the lint check with::
999
1000    python -m pylint --rcfile=extra/pylint.rc ~/.sasview/plugin_models/model.py
1001
1002We are not aiming for zero lint just yet, only keeping it to a minimum.
1003For now, don't worry too much about *invalid-name*. If you really want a
1004variable name *Rg* for example because $R_g$ is the right name for the model
1005parameter then ignore the lint errors.  Also, ignore *missing-docstring*
1006for standard model functions *Iq*, *Iqxy*, etc.
1007
1008We will have delinting sessions at the SasView Code Camps, where we can
1009decide on standards for model files, parameter names, etc.
1010
1011For now, you can tell pylint to ignore things.  For example, to align your
1012parameters in blocks::
1013
1014    # pylint: disable=bad-whitespace,line-too-long
1015    #   ["name",                  "units", default, [lower, upper], "type", "description"],
1016    parameters = [
1017        ["contrast_factor",       "barns",    10.0,  [-inf, inf], "", "Contrast factor of the polymer"],
1018        ["bjerrum_length",        "Ang",       7.1,  [0, inf],    "", "Bjerrum length"],
1019        ["virial_param",          "1/Ang^2",  12.0,  [-inf, inf], "", "Virial parameter"],
1020        ["monomer_length",        "Ang",      10.0,  [0, inf],    "", "Monomer length"],
1021        ["salt_concentration",    "mol/L",     0.0,  [-inf, inf], "", "Concentration of monovalent salt"],
1022        ["ionization_degree",     "",          0.05, [0, inf],    "", "Degree of ionization"],
1023        ["polymer_concentration", "mol/L",     0.7,  [0, inf],    "", "Polymer molar concentration"],
1024        ]
1025    # pylint: enable=bad-whitespace,line-too-long
1026
1027Don't put in too many pylint statements, though, since they make the code ugly.
1028
1029Share Your Model!
1030^^^^^^^^^^^^^^^^^
1031
1032Once compare and the unit test(s) pass properly and everything is done,
1033consider adding your model to the
1034`Model Marketplace <http://marketplace.sasview.org/>`_ so that others may use it!
1035
1036.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
1037
1038*Document History*
1039
1040| 2016-10-25 Steve King
1041| 2017-05-07 Paul Kienzle - Moved from sasview to sasmodels docs
Note: See TracBrowser for help on using the repository browser.