source: sasview/src/sas/sasgui/perspectives/fitting/media/plugin.rst @ 31d7803

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 31d7803 was 31d7803, checked in by smk78, 8 years ago

Completed review - minor changes

  • Property mode set to 100644
File size: 29.7 KB
RevLine 
[05829fb]1.. _Writing_a_Plugin:
2
[7f23423]3Writing a Plugin Model
4======================
[05829fb]5
[7f23423]6Overview
7^^^^^^^^
8
9You can write your own model and save it to the the SasView
[05829fb]10*plugin_models* folder
11
[7f23423]12  *C:\\Users\\[username]\\.sasview\\plugin_models* (on Windows)
[05829fb]13
14The next time SasView is started it will compile the plugin and add
[7f23423]15it to the list of *Customized Models* in a FitPage.  It is recommended that an
[05829fb]16existing model be used as a template.
17
18SasView has three ways of writing models:
19
20- As a pure python model : Example -
21  `broadpeak.py <https://github.com/SasView/sasmodels/blob/master/sasmodels/models/broad_peak.py>`_
22- As a python model with embedded C : Example -
23  `sphere.py <https://github.com/SasView/sasmodels/blob/master/sasmodels/models/sphere.py>`_
24- As a python wrapper with separate C code : Example -
25  `cylinder.py <https://github.com/SasView/sasmodels/blob/master/sasmodels/models/cylinder.py>`_,
26  `cylinder.c <https://github.com/SasView/sasmodels/blob/master/sasmodels/models/cylinder.c>`_
27
[3d164b9]28The built-in modules are available in the *sasmodels-data\\models* subdirectory
[7f23423]29of your SasView installation folder.  On Windows, this will be something like
30*C:\\Program Files (x86)\\SasView\\sasmodels-data\\models*.  On Mac OSX, these will be within
[05829fb]31the application bundle as
32*/Applications/SasView 4.0.app/Contents/Resources/sasmodels-data/models*.
33
[7f23423]34Other models are available for download from our
35`Model Marketplace <http://marketplace.sasview.org/>`_. You can contribute your own models to the
36Marketplace aswell.
37
[05829fb]38Create New Model Files
39^^^^^^^^^^^^^^^^^^^^^^
40
[3d164b9]41In the *~\\.sasview\\plugin_models* directory, copy the appropriate files
[05829fb]42(using the examples above as templates) to mymodel.py (and mymodel.c, etc)
43as required, where "mymodel" is the name for the model you are creating.
44
45*Please follow these naming rules:*
46
[7f23423]47- No capitalization and thus no CamelCase
[3d164b9]48- If necessary use underscore to separate words (i.e. barbell not BarBell or
[05829fb]49  broad_peak not BroadPeak)
[3d164b9]50- Do not include “model” in the name (i.e. barbell not BarBellModel)
[05829fb]51
52
53Edit New Model Files
54^^^^^^^^^^^^^^^^^^^^
55
[7f23423]56Model Contents
57..............
58
[05829fb]59The model interface definition is in the .py file.  This file contains:
60
61- a **model name**:
62   - this is the **name** string in the *.py* file
63   - titles should be:
64
65    - all in *lower* case
66    - without spaces (use underscores to separate words instead)
67    - without any capitalization or CamelCase
[7f23423]68    - without incorporating the word "model"
[05829fb]69    - examples: *barbell* **not** *BarBell*; *broad_peak* **not** *BroadPeak*;
70      *barbell* **not** *BarBellModel*
71
72- a **model title**:
73   - this is the **title** string in the *.py* file
74   - this is a one or two line description of the model, which will appear
[7f23423]75     at the start of the model documentation and as a tooltip in the SasView GUI
[05829fb]76
77- a **short discription**:
78   - this is the **description** string in the *.py* file
79   - this is a medium length description which appears when you click
[7f23423]80     *Description* on the model FitPage
[05829fb]81
82- a **parameter table**:
83   - this will be auto-generated from the *parameters* in the *.py* file
84
85- a **long description**:
86   - this is ReStructuredText enclosed between the r""" and """ delimiters
87     at the top of the *.py* file
[7f23423]88   - what you write here is abstracted into the SasView help documentation
89   - this is what other users will refer to when they want to know what your model does;
90     so please be helpful!
[05829fb]91
92- a **definition** of the model:
93   - as part of the **long description**
94
95- a **formula** defining the function the model calculates:
96   - as part of the **long description**
97
98- an **explanation of the parameters**:
99   - as part of the **long description**
100   - explaining how the symbols in the formula map to the model parameters
101
102- a **plot** of the function, with a **figure caption**:
[7f23423]103   - this is automatically generated from your default parameters
[05829fb]104
105- at least one **reference**:
106   - as part of the **long description**
107   - specifying where the reader can obtain more information about the model
108
109- the **name of the author**
110   - as part of the **long description**
111   - the *.py* file should also contain a comment identifying *who*
112     converted/created the model file
113
[3d164b9]114Models that do not conform to these requirements will *never* be incorporated
115into the built-in library.
116
[05829fb]117More complete documentation for the sasmodels package can be found at
118`<http://www.sasview.org/sasmodels>`_. In particular,
119`<http://www.sasview.org/sasmodels/api/generate.html#module-sasmodels.generate>`_
120describes the structure of a model.
121
122
123Model Documentation
124...................
125
126The *.py* file starts with an r (for raw) and three sets of quotes
127to start the doc string and ends with a second set of three quotes.
128For example::
129
130    r"""
131    Definition
132    ----------
133
134    The 1D scattering intensity of the sphere is calculated in the following
135    way (Guinier, 1955)
136
137    .. math::
138
139        I(q) = \frac{\text{scale}}{V} \cdot \left[
140            3V(\Delta\rho) \cdot \frac{\sin(qr) - qr\cos(qr))}{(qr)^3}
141            \right]^2 + \text{background}
142
143    where *scale* is a volume fraction, $V$ is the volume of the scatterer,
144    $r$ is the radius of the sphere and *background* is the background level.
145    *sld* and *sld_solvent* are the scattering length densities (SLDs) of the
146    scatterer and the solvent respectively, whose difference is $\Delta\rho$.
147
148    You can included figures in your documentation, as in the following
149    figure for the cylinder model.
150
151    .. figure:: img/cylinder_angle_definition.jpg
152
153        Definition of the angles for oriented cylinders.
154
155    References
156    ----------
157
158    A Guinier, G Fournet, *Small-Angle Scattering of X-Rays*,
159    John Wiley and Sons, New York, (1955)
160    """
161
162This is where the FULL documentation for the model goes (to be picked up by
163the automatic documentation system).  Although it feels odd, you
164should start the documentation immediately with the **definition**---the model
165name, a brief description and the parameter table are automatically inserted
166above the definition, and the a plot of the model is automatically inserted
167before the **reference**.
168
169Figures can be included using the *figure* command, with the name
170of the *.png* file containing the figure and a caption to appear below the
171figure.  Figure numbers will be added automatically.
172
173See this `Sphinx cheat sheet <http://matplotlib.org/sampledoc/cheatsheet.html>`_
174for a quick guide to the documentation layout commands, or the
175`Sphinx Documentation <http://www.sphinx-doc.org/en/stable/>`_ for
176complete details.
177
178The model should include a **formula** written using LaTeX markup.
[7f23423]179The example above uses the *math* command to make a displayed equation.  You
[05829fb]180can also use *\$formula\$* for an inline formula. This is handy for defining
181the relationship between the model parameters and formula variables, such
182as the phrase "\$r\$ is the radius" used above.  The live demo MathJax
183page `<http://www.mathjax.org/>`_ is handy for checking that the equations
[7f23423]184will look like you intend.
[05829fb]185
186Math layout uses the `amsmath <http://www.ams.org/publications/authors/tex/amslatex>`_
187package for aligning equations (see amsldoc.pdf on that page for complete documentation).
188You will automatically be in an aligned environment, with blank lines separating
189the lines of the equation.  Place an ampersand before the operator on which to
190align.  For example::
191
192    .. math::
193
194      x + y &= 1 \\
195      y &= x - 1
196
197produces
198
199.. math::
200
201      x + y &= 1 \\
202      y &= x - 1
203
204If you need more control, use::
205
206    .. math::
207        :nowrap:
208
209
210Model Definition
211................
212
213Following the documentation string, there are a series of definitions::
214
215    name = "sphere"  # optional: defaults to the filename without .py
[7f23423]216
[05829fb]217    title = "Spheres with uniform scattering length density"
[7f23423]218
[05829fb]219    description = """\
220    P(q)=(scale/V)*[3V(sld-sld_solvent)*(sin(qr)-qr cos(qr))
221                    /(qr)^3]^2 + background
222        r: radius of sphere
223        V: The volume of the scatter
224        sld: the SLD of the sphere
225        sld_solvent: the SLD of the solvent
226    """
[7f23423]227
[05829fb]228    category = "shape:sphere"
[7f23423]229
[05829fb]230    single = True   # optional: defaults to True
[7f23423]231
[05829fb]232    opencl = False  # optional: defaults to False
[7f23423]233
[05829fb]234    structure_factor = False  # optional: defaults to False
235
236**name = "mymodel"** defines the name of the model that is shown to the user.
237If it is not provided, it will use the name of the model file, with '_'
238replaced by spaces and the parts capitalized.  So *adsorbed_layer.py* will
239become *Adsorbed Layer*.  The predefined models all use the name of the
240model file as the name of the model, so the default may be changed.
241
242**title = "short description"** is short description of the model which
243is included after the model name in the automatically generated documentation.
[7f23423]244The title can also be used for a tooltip.
[05829fb]245
246**description = """doc string"""** is a longer description of the model. It
[7f23423]247shows up when you press the "Description" button of the SasView FitPage.
[05829fb]248It should give a brief description of the equation and the parameters
249without the need to read the entire model documentation. The triple quotes
250allow you to write the description over multiple lines. Keep the lines
251short since the GUI will wrap each one separately if they are too long.
[7f23423]252**Make sure the parameter names in the description match the model definition!**
[05829fb]253
254**category = "shape:sphere"** defines where the model will appear in the
255model documentation.  In this example, the model will appear alphabetically
[7f23423]256in the list of spheroid models in the *Shape* category.
[05829fb]257
258**single = True** indicates that the model can be run using single
259precision floating point values.  Set it to False if the numerical
260calculation for the model is unstable, which is the case for about 20 of
261the built in models.  It is worthwhile modifying the calculation to support
262single precision, allowing models to run up to 10 times faster.  The
263section `Test_Your_New_Model`_  describes how to compare model values for
264single vs. double precision so you can decide if you need to set
265single to False.
266
267**opencl = False** indicates that the model should not be run using OpenCL.
268This may be because the model definition includes code that cannot be
269compiled for the GPU (for example, goto statements).  It can also be used
270for large models which can't run on most GPUs.  This flag has not been
271used on any of the built in models; models which were failing were
272streamlined so this flag was not necessary.
273
274**structure_factor = True** indicates that the model can be used as a
275structure factor to account for interactions between particles.  See
276`Form_Factors`_ for more details.
277
278Model Parameters
279................
280
281Next comes the parameter table.  For example::
282
283    # pylint: disable=bad-whitespace, line-too-long
284    #   ["name",        "units", default, [min, max], "type",    "description"],
285    parameters = [
286        ["sld",         "1e-6/Ang^2",  1, [-inf, inf], "sld",    "Layer scattering length density"],
287        ["sld_solvent", "1e-6/Ang^2",  6, [-inf, inf], "sld",    "Solvent scattering length density"],
288        ["radius",      "Ang",        50, [0, inf],    "volume", "Sphere radius"],
289    ]
[31d7803]290    # pylint: enable=bad-whitespace, line-too-long
[05829fb]291
292**parameters = [["name", "units", default, [min,max], "type", "tooltip"],...]**
[7f23423]293defines the parameters that form the model.
[05829fb]294
[7f23423]295**Note: The order of the parameters in the definition will be the order of the
296parameters in the user interface and the order of the parameters in Iq(),
297Iqxy() and form_volume(). And** *scale* **and** *background* **parameters are
298implicit to all models, so they do not need to be included in the parameter table.**
[05829fb]299
[7f23423]300- **"name"** is the name of the parameter shown on the FitPage.
[05829fb]301
302  - parameter names should follow the mathematical convention; e.g.,
[7f23423]303    *radius_core* not *core_radius*, or *sld_solvent* not *solvent_sld*.
304
[05829fb]305  - model parameter names should be consistent between different models,
306    so *sld_solvent*, for example, should have exactly the same name
[7f23423]307    in every model.
308
[05829fb]309  - to see all the parameter names currently in use, type the following in the
310    python shell/editor under the Tools menu::
311
312       import sasmodels.list_pars
313       sasmodels.list_pars.list_pars()
314
315    *re-use* as many as possible!!!
[7f23423]316
[05829fb]317  - use "name[n]" for multiplicity parameters, where *n* is the name of
318    the parameter defining the number of shells/layers/segments, etc.
319
320- **"units"** are displayed along with the parameter name
321
[7f23423]322  - every parameter should have units; use "None" if there are no units.
323
[05829fb]324  - **sld's should be given in units of 1e-6/Ang^2, and not simply
325    1/Ang^2 to be consistent with the builtin models.  Adjust your formulas
326    appropriately.**
[7f23423]327
[05829fb]328  - fancy units markup is available for some units, including::
329
330        Ang, 1/Ang, 1/Ang^2, 1e-6/Ang^2, degrees, 1/cm, Ang/cm, g/cm^3, mg/m^2
331
332  - the list of units is defined in the variable *RST_UNITS* within
333    `sasmodels/generate.py <https://github.com/SasView/sasmodels/tree/master/sasmodels/generate.py>`_
334
335    - new units can be added using the macros defined in *doc/rst_prolog*
336      in the sasmodels source.
337    - units should be properly formatted using sub-/super-scripts
338      and using negative exponents instead of the / operator, though
339      the unit name should use the / operator for consistency.
[7f23423]340    - please post a message to the SasView developers mailing list with your changes.
[05829fb]341
[7f23423]342- **default** is the initial value for the parameter.
[05829fb]343
344  - **the parameter default values are used to auto-generate a plot of
345    the model function in the documentation.**
346
[7f23423]347- **[min, max]** are the lower and upper limits on the parameter.
348
349  - lower and upper limits can be any number, or *-inf* or *inf*.
[05829fb]350
351  - the limits will show up as the default limits for the fit making it easy,
352    for example, to force the radius to always be greater than zero.
353
[7f23423]354- **"type"** can be one of: "", "sld", "volume", or "orientation".
[05829fb]355
356  - "sld" parameters can have magnetic moments when fitting magnetic models;
357    depending on the spin polarization of the beam and the $q$ value being
358    examined, the effective sld for that material will be used to compute the
[7f23423]359    scattered intensity.
360
[05829fb]361  - "volume" parameters are passed to Iq(), Iqxy(), and form_volume(), and
362    have polydispersity loops generated automatically.
[7f23423]363
[05829fb]364  - "orientation" parameters are only passed to Iqxy(), and have angular
365    dispersion.
366
367
368Model Computation
369.................
370
371Models can be defined as pure python models, or they can be a mixture of
372python and C models.  C models are run on the GPU if it is available,
373otherwise they are compiled and run on the CPU.
374
375Models are defined by the scattering kernel, which takes a set of parameter
376values defining the shape, orientation and material, and returns the
377expected scattering. Polydispersity and angular dispersion are defined
378by the computational infrastructure.  Any parameters defined as "volume"
379parameters are polydisperse, with polydispersity defined in proportion
380to their value.  "orientation" parameters use angular dispersion defined
381in degrees, and are not relative to the current angle.
382
383Based on a weighting function $G(x)$ and a number of points $n$, the
384computed value is
385
386.. math::
387
388     \hat I(q)
389     = \frac{\int G(x) I(q, x)\,dx}{\int G(x) V(x)\,dx}
390     \approx \frac{\sum_{i=1}^n G(x_i) I(q,x_i)}{\sum_{i=1}^n G(x_i) V(x_i)}
391
392That is, the indivdual models do not need to include polydispersity
393calculations, but instead rely on numerical integration to compute the
394appropriately smeared pattern.   Angular dispersion values over polar angle
395$\theta$ requires an additional $\cos \theta$ weighting due to decreased
396arc length for the equatorial angle $\phi$ with increasing latitude.
397
398Python Models
399.............
400
[7f23423]401For pure python models, define the *Iq* function::
[05829fb]402
403      import numpy as np
404      from numpy import cos, sin, ...
405
406      def Iq(q, par1, par2, ...):
407          return I(q, par1, par2, ...)
408      Iq.vectorized = True
409
410The parameters *par1, par2, ...* are the list of non-orientation parameters
411to the model in the order that they appear in the parameter table.
[7f23423]412**Note that the autogenerated model file uses** *x* **rather than** *q*.
[05829fb]413
414The *.py* file should import trigonometric and exponential functions from
[7f23423]415numpy rather than from math.  This lets us evaluate the model for the whole
[05829fb]416range of $q$ values at once rather than looping over each $q$ separately in
417python.  With $q$ as a vector, you cannot use if statements, but must instead
418do tricks like
419
420::
421
422     a = x*q*(q>0) + y*q*(q<=0)
423
424or
425
426::
427
428     a = np.empty_like(q)
429     index = q>0
430     a[index] = x*q[index]
431     a[~index] = y*q[~index]
432
433which sets $a$ to $q \cdot x$ if $q$ is positive or $q \cdot y$ if $q$
434is zero or negative. If you have not converted your function to use $q$
435vectors, you can set the following and it will only receive one $q$
436value at a time::
437
438    Iq.vectorized = False
439
440Return np.NaN if the parameters are not valid (e.g., cap_radius < radius in
441barbell).  If I(q; pars) is NaN for any $q$, then those parameters will be
442ignored, and not included in the calculation of the weighted polydispersity.
443
444Similar to *Iq*, you can define *Iqxy(qx, qy, par1, par2, ...)* where the
445parameter list includes any orientation parameters.  If *Iqxy* is not defined,
446then it will default to *Iqxy = Iq(sqrt(qx**2+qy**2), par1, par2, ...)*.
447
448Models should define *form_volume(par1, par2, ...)* where the parameter
449list includes the *volume* parameters in order.  This is used for a weighted
450volume normalization so that scattering is on an absolute scale.  If
[7f23423]451*form_volume* is not defined, then the default *form_volume = 1.0* will be
[05829fb]452used.
453
454Embedded C Models
455.................
456
[7f23423]457Like pure python models, inline C models need to define an *Iq* function::
[05829fb]458
459    Iq = """
460        return I(q, par1, par2, ...);
461    """
462
463This expands into the equivalent C code::
464
465    #include <math.h>
466    double Iq(double q, double par1, double par2, ...);
467    double Iq(double q, double par1, double par2, ...)
468    {
469        return I(q, par1, par2, ...);
470    }
471
472The C model operates on a single $q$ value at a time.  The code will be
473run in parallel across different $q$ values, either on the graphics card
474or the processor.
475
476Rather than returning NAN from Iq, you must define the *INVALID(v)*.  The
477*v* parameter lets you access all the parameters in the model using
478*v.par1*, *v.par2*, etc. For example::
479
480    #define INVALID(v) (v.bell_radius < v.radius)
481
482*Iqxy* is similar to *Iq*, except it uses parameters *qx, qy* instead of *q*,
483and it includes orientation parameters. As in python models, *form_volume*
484includes only the volume parameters.  *Iqxy* will default to
485*Iq(sqrt(qx**2 + qy**2), par1, ...)* and *form_volume* will default to 1.0.
486
487The C code follows the C99 standard, including the usual math functions,
488as defined in
489`OpenCL <https://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/mathFunctions.html>`_.
490
491The standard constants and functions include the following::
492
493    M_PI = pi
494    M_PI_2 = pi/2
495    M_PI_4 = pi/4
496    M_E = e
497    M_SQRT1_2 = 1/sqrt(2)
498    NAN = NaN
499    INFINITY = 1/0
500    erf(x) = error function
501    erfc(x) = 1-erf(x)
502    expm1(x) = exp(x) - 1
503    tgamma(x) = gamma function
504
505Some non-standard constants and functions are also provided::
506
507    M_PI_180 = pi/180
508    M_4PI_3 = 4pi/3
509    square(x) = x*x
510    cube(x) = x*x*x
511    sinc(x) = sin(x)/x, with sin(0)/0 -> 1
512    SINCOS(x, s, c) sets s=sin(angle) and c=cos(angle)
513    powr(x, y) = x^y for x >= 0
514    pown(x, n) = x^n for n integer
515
516**source=['lib/fn.c', ...]** includes the listed C source files in the
517program before *Iq* and *Iqxy* are defined. This allows you to extend the
518library of available C functions. Additional special functions and
519scattering calculations are defined in
520`sasmodels/models/lib <https://github.com/SasView/sasmodels/tree/master/sasmodels/models/lib>`_,
521including::
522
523    sph_j1c(x) = 3 j1(x)/x = 3 (sin(x) - x cos(x))/x^3  [spherical bessel function]
524    sas_J1c(x) = 2 J1(x)/x  [bessel function of the first kind]
525    sas_gamma(x) = gamma function  [tgamma is unstable below 1]
526    sas_erf(x) = error function [erf is broken on some Intel OpenCL drivers]
527    sas_erfc(x) = 1-erf(x)
528    sas_J0(x) = J0(x)
529    sas_J1(x) = J1(x)
530    sas_JN(x) = JN(x)
531    Si(x) = integral sin(z)/z from 0 to x
532    Gauss76Wt = gaussian quadrature weights for 76 point integral
533    Gauss76Z = gaussian quadrature values for 76 point integral
534
535These functions have been tuned to be fast and numerically stable down
536to $q=0$ even in single precision.  In some cases they work around bugs
[7f23423]537which appear on some platforms but not others. So use them where needed!!!
[05829fb]538
539Models are defined using double precision declarations for the
540parameters and return values.  Declarations and constants will be converted
541to float or long double depending on the precision requested.
[7f23423]542
[05829fb]543**Floating point constants must include the decimal point.**  This allows us
544to convert values such as 1.0 (double precision) to 1.0f (single precision)
545so that expressions that use these values are not promoted to double precision
546expressions.  Some graphics card drivers are confused when functions
547that expect floating point values are passed integers, such as 4*atan(1); it
548is safest to not use integers in floating point expressions.  Even better,
549use the builtin constant M_PI rather than 4*atan(1); it is faster and smaller!
550
551FLOAT_SIZE is the number of bytes in the converted variables. If your
552algorithm depends on precision (which is not uncommon for numerical
553algorithms), use the following::
554
555    #if FLOAT_SIZE>4
556    ... code for double precision ...
557    #else
558    ... code for single precision ...
559    #endif
560
561A value defined as SAS_DOUBLE will stay double precision; this should
[7f23423]562not be used since some graphics cards do not support double precision.
[05829fb]563
564
565External C Models
566.................
567
568External C models are very much like embedded C models, except that
569*Iq*, *Iqxy* and *form_volume* are defined in an external source file
570loaded using the *source=[...]*  method. You need to supply the function
571declarations for each of these that you need instead of building them
572automatically from the parameter table.
573
574
575.. _Form_Factors:
576
577Form Factors
578............
579
580Away from the dilute limit you can estimate scattering including
581particle-particle interactions using $I(q) = P(q)*S(q)$ where $P(q)$
582is the form factor and $S(q)$ is the structure factor.  The simplest
583structure factor is the *hardsphere* interaction, which
584uses the effective radius of the form factor as an input to the structure
585factor model.  The effective radius is the average radius of the
586form averaged over all the polydispersity values.
587
[31d7803]588::
589
590    def ER(radius, thickness):
591        """Effective radius of a core-shell sphere."""
592        return radius + thickness
593
594Now consider the *core_shell_sphere*, which has a simple effective radius
[05829fb]595equal to the radius of the core plus the thickness of the shell, as
596shown above. Given polydispersity over *(r1, r2, ..., rm)* in radius and
597*(t1, t2, ..., tn)* in thickness, *ER* is called with a mesh
598grid covering all possible combinations of radius and thickness.
599That is, *radius* is *(r1, r2, ..., rm, r1, r2, ..., rm, ...)*
600and *thickness* is *(t1, t1, ... t1, t2, t2, ..., t2, ...)*.
601The *ER* function returns one effective radius for each combination.
602The effective radius calculator weights each of these according to
603the polydispersity distributions and calls the structure factor
604with the average *ER*.
605
606::
607
608    def VR(radius, thickness):
609        """Sphere and shell volumes for a core-shell sphere."""
610        whole = 4.0/3.0 * pi * (radius + thickness)**3
611        core = 4.0/3.0 * pi * radius**3
612        return whole, whole - core
613
614Core-shell type models have an additional volume ratio which scales
615the structure factor.  The *VR* function returns the volume of
616the whole sphere and the volume of the shell. Like *ER*, there is
617one return value for each point in the mesh grid.
618
[31d7803]619*NOTE: we may be removing or modifying this feature soon. As of the
620time of writing, core-shell sphere returns (1., 1.) for VR, giving a volume
621ratio of 1.0.*
[05829fb]622
623Unit Tests
624..........
625
626THESE ARE VERY IMPORTANT. Include at least one test for each model and
627PLEASE make sure that the answer value is correct (i.e. not a random number).
628
629::
630
631    tests = [
632        [{}, 0.2, 0.726362],
633        [{"scale": 1., "background": 0., "sld": 6., "sld_solvent": 1.,
634          "radius": 120., "radius_pd": 0.2, "radius_pd_n":45},
635         0.2, 0.228843],
636        [{"radius": 120., "radius_pd": 0.2, "radius_pd_n":45}, "ER", 120.],
637        [{"radius": 120., "radius_pd": 0.2, "radius_pd_n":45}, "VR", 1.],
638    ]
639
640
641**tests=[[{parameters}, q, result], ...]** is a list of lists.
642Each list is one test and contains, in order:
643
644- a dictionary of parameter values. This can be {} using the default
645  parameters, or filled with some parameters that will be different
646  from the default, such as {‘radius’:10.0, ‘sld’:4}. Unlisted parameters
647  will be given the default values.
648- the input $q$ value or tuple of $(q_x, q_y)$ values.
649- the output $I(q)$ or $I(q_x,q_y)$ expected of the model for the parameters
650  and input value given.
651- input and output values can themselves be lists if you have several
652  $q$ values to test for the same model parameters.
653- for testing *ER* and *VR*, give the inputs as "ER" and "VR" respectively;
654  the output for *VR* should be the sphere/shell ratio, not the individual
655  sphere and shell values.
656
657.. _Test_Your_New_Model:
658
659Test Your New Model
660^^^^^^^^^^^^^^^^^^^
661
662If you are editing your model from the SasView GUI, you can test it
[31d7803]663by selecting *Run > Compile* from the *Model Editor* menu bar. An
[05829fb]664*Info* box will appear with the results of the compilation and a
665check that the model runs.
666
667If the model compiles and runs, you can next run the unit tests that
[31d7803]668you have added using the **test =** values. Switch to the *Shell* tab
[05829fb]669and type the following::
670
671    from sasmodels.model_test import run_one
672    run_one("~/.sasview/plugin_models/model.py")
673
674This should print::
675
676    test_model_python (sasmodels.model_test.ModelTestCase) ... ok
677
678To check whether single precision is good enough, type the following::
679
680    from sasmodels.compare import main
681    main("~/.sasview/plugin_models/model.py")
682
683This will pop up a plot showing the difference between single precision
684and double precision on a range of $q$ values.
685
686::
687
688  demo = dict(scale=1, background=0,
689              sld=6, sld_solvent=1,
690              radius=120,
691              radius_pd=.2, radius_pd_n=45)
692
693**demo={'par': value, ...}** in the model file sets the default values for
694the comparison. You can include polydispersity parameters such as
695*radius_pd=0.2, radius_pd_n=45* which would otherwise be zero.
696
697The options to compare are quite extensive; type the following for help::
698
699    main()
700
701Options will need to be passed as separate strings.
702For example to run your model with a random set of parameters::
703
704    main("-random", "-pars", "~/.sasview/plugin_models/model.py")
705
706For the random models,
707
[31d7803]708- *sld* will be in the range (-0.5,10.5),
709- angles (*theta, phi, psi*) will be in the range (-180,180),
710- angular dispersion will be in the range (0,45),
711- polydispersity will be in the range (0,1)
712- other values will be in the range (0, 2\ *v*), where *v* is the value of the parameter in demo.
[05829fb]713
[31d7803]714Dispersion parameters *n*\, *sigma* and *type* will be unchanged from demo so that
[05829fb]715run times are predictable.
716
717If your model has 2D orientational calculation, then you should also
718test with::
719
720    main("-2d", "~/.sasview/plugin_models/model.py")
721
722
723Clean Lint
724^^^^^^^^^^
725
[31d7803]726**NB: For now we are not providing pylint with SasView; so unless you have a
727SasView development environment available, you can ignore this section!**
[05829fb]728
729Run the lint check with::
730
731    python -m pylint --rcfile=extra/pylint.rc ~/.sasview/plugin_models/model.py
732
733We are not aiming for zero lint just yet, only keeping it to a minimum.
734For now, don't worry too much about *invalid-name*. If you really want a
735variable name *Rg* for example because $R_g$ is the right name for the model
736parameter then ignore the lint errors.  Also, ignore *missing-docstring*
737for standard model functions *Iq*, *Iqxy*, etc.
738
[31d7803]739We will have delinting sessions at the SasView Code Camps, where we can
[05829fb]740decide on standards for model files, parameter names, etc.
741
[31d7803]742For now, you can tell pylint to ignore things.  For example, to align your
[05829fb]743parameters in blocks::
744
745    # pylint: disable=bad-whitespace,line-too-long
746    #   ["name",                  "units", default, [lower, upper], "type", "description"],
747    parameters = [
748        ["contrast_factor",       "barns",    10.0,  [-inf, inf], "", "Contrast factor of the polymer"],
749        ["bjerrum_length",        "Ang",       7.1,  [0, inf],    "", "Bjerrum length"],
750        ["virial_param",          "1/Ang^2",  12.0,  [-inf, inf], "", "Virial parameter"],
751        ["monomer_length",        "Ang",      10.0,  [0, inf],    "", "Monomer length"],
752        ["salt_concentration",    "mol/L",     0.0,  [-inf, inf], "", "Concentration of monovalent salt"],
753        ["ionization_degree",     "",          0.05, [0, inf],    "", "Degree of ionization"],
754        ["polymer_concentration", "mol/L",     0.7,  [0, inf],    "", "Polymer molar concentration"],
755        ]
756    # pylint: enable=bad-whitespace,line-too-long
757
758Don't put in too many pylint statements, though, since they make the code ugly.
759
760Check The Docs
761^^^^^^^^^^^^^^
762
763You can get a rough idea of how the documentation will look using the
764following::
765
766    from sasmodels.generate import view_html
767    view_html('~/.sasview/plugin_models/model.py')
768
769This does not use the same styling as the SasView docs, but it will allow
770you to check that your ReStructuredText and LaTeX formatting.  Here are
771some tools to help with the inevitable syntax errors:
772
773- `Sphinx cheat sheet <http://matplotlib.org/sampledoc/cheatsheet.html>`_
774- `Sphinx Documentation <http://www.sphinx-doc.org/en/stable/>`_
775- `MathJax <http://www.mathjax.org/>`_
776- `amsmath <http://www.ams.org/publications/authors/tex/amslatex>`_
777
[31d7803]778There is also a neat online WYSIWYG ReStructuredText editor at http://rst.ninjs.org\ .
779
[05829fb]780Finally
781^^^^^^^
782
783Once compare and the unit test(s) pass properly and everything is done,
784consider adding your model to the
[31d7803]785`Model Marketplace <http://marketplace.sasview.org/>`_.
Note: See TracBrowser for help on using the repository browser.