source: sasview/src/sas/sasgui/perspectives/fitting/media/plugin.rst @ 199b515e

Last change on this file since 199b515e was 7e6bdf9, checked in by smk78, 8 years ago

Tweaked text to explain difference between the Custom Model editor and
Plugin Models (keeping Richard happy again!)

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