12. Model parser

sasmodels.generate

SAS model constructor.

Small angle scattering models are defined by a set of kernel functions:

Iq(q, p1, p2, …) returns the scattering at q for a form with particular dimensions averaged over all orientations.

Iqac(qab, qc, p1, p2, …) returns the scattering at qab, qc for a rotationally symmetric form with particular dimensions. qab, qc are determined from shape orientation and scattering angles. This call is used if the shape has orientation parameters theta and phi.

Iqabc(qa, qb, qc, p1, p2, …) returns the scattering at qa, qb, qc for a form with particular dimensions. qa, qb, qc are determined from shape orientation and scattering angles. This call is used if the shape has orientation parameters theta, phi and psi.

Iqxy(qx, qy, p1, p2, …) returns the scattering at qx, qy. Use this to create an arbitrary 2D theory function, needed for q-dependent background functions and for models with non-uniform magnetism.

form_volume(p1, p2, …) returns the volume of the form with particular dimension, or 1.0 if no volume normalization is required.

shell_volume(p1, p2, …) returns the volume of the shell for forms which are hollow.

radius_effective(mode, p1, p2, …) returns the effective radius of the form with particular dimensions. Mode determines the type of effective radius returned, with mode=1 for equivalent volume.

#define INVALID(v) (expr) returns False if v.parameter is invalid for some parameter or other (e.g., v.bell_radius < v.radius). If necessary, the expression can call a function.

These functions are defined in a kernel module .py script and an associated set of .c files. The model constructor will use them to create models with polydispersity across volume and orientation parameters, and provide scale and background parameters for each model.

C code should be stylized C-99 functions written for OpenCL. All functions need prototype declarations even if the are defined before they are used. Although OpenCL supports #include preprocessor directives, the list of includes should be given as part of the metadata in the kernel module definition. The included files should be listed using a path relative to the kernel module, or if using “lib/file.c” if it is one of the standard includes provided with the sasmodels source. The includes need to be listed in order so that functions are defined before they are used.

Floating point values should be declared as double. For single precision calculations, double will be replaced by float. The single precision conversion will also tag floating point constants with “f” to make them single precision constants. When using integral values in floating point expressions, they should be expressed as floating point values by including a decimal point. This includes 0., 1. and 2.

OpenCL has a sincos function which can improve performance when both the sin and cos values are needed for a particular argument. Since this function does not exist in C99, all use of sincos should be replaced by the macro SINCOS(value, sn, cn) where sn and cn are previously declared double variables. When compiled for systems without OpenCL, SINCOS will be replaced by sin and cos calls. If value is an expression, it will appear twice in this case; whether or not it will be evaluated twice depends on the quality of the compiler.

If the input parameters are invalid, the scattering calculator should return a negative number. Particularly with polydispersity, there are some sets of shape parameters which lead to nonsensical forms, such as a capped cylinder where the cap radius is smaller than the cylinder radius. The polydispersity calculation will ignore these points, effectively chopping the parameter weight distributions at the boundary of the infeasible region. The resulting scattering will be set to background. This will work correctly even when polydispersity is off.

The kernel module must set variables defining the kernel meta data:

id is an implicit variable formed from the filename. It will be a valid python identifier, and will be used as the reference into the html documentation, with ‘_’ replaced by ‘-‘.

name is the model name as displayed to the user. If it is missing, it will be constructed from the id.

title is a short description of the model, suitable for a tool tip, or a one line model summary in a table of models.

description is an extended description of the model to be displayed while the model parameters are being edited.

parameters is the list of parameters. Parameters in the kernel functions must appear in the same order as they appear in the parameters list. Two additional parameters, scale and background are added to the beginning of the parameter list. They will show up in the documentation as model parameters, but they are never sent to the kernel functions. Note that effect_radius and volfraction must occur first in structure factor calculations.

category is the default category for the model. The category is two level structure, with the form “group:section”, indicating where in the manual the model will be located. Models are alphabetical within their section.

source is the list of C-99 source files that must be joined to create the OpenCL kernel functions. The files defining the functions need to be listed before the files which use the functions.

form_volume, Iq, Iqac, Iqabc are strings containing the C source code for the body of the volume, Iq, and Iqac functions respectively. These can also be defined in the last source file.

Iq, Iqac, Iqabc also be instead be python functions defining the kernel. If they are marked as Iq.vectorized = True then the kernel is passed the entire q vector at once, otherwise it is passed values one q at a time. The performance improvement of this step is significant.

demo is a dictionary of parameter=value defining a set of parameters to use by default when compare is called. Any parameter not set in demo gets the initial value from the parameter list. demo is mostly needed to set the default polydispersity values for tests.

A modelinfo.ModelInfo structure is constructed from the kernel meta data and returned to the caller.

The doc string at the start of the kernel module will be used to construct the model documentation web pages. Embedded figures should appear in the subdirectory “img” beside the model definition, and tagged with the kernel module name to avoid collision with other models. Some file systems are case-sensitive, so only use lower case characters for file names and extensions.

Code follows the C99 standard with the following extensions and conditions:

M_PI_180 = pi/180
M_4PI_3 = 4pi/3
square(x) = x*x
cube(x) = x*x*x
sas_sinx_x(x) = sin(x)/x, with sin(0)/0 -> 1
all double precision constants must include the decimal point
all double declarations may be converted to half, float, or long double
FLOAT_SIZE is the number of bytes in the converted variables

load_kernel_module() loads the model definition file and modelinfo.make_model_info() parses it. make_source() converts C-based model definitions to C source code, including the polydispersity integral. model_sources() returns the list of source files the model depends on, and timestamp() returns the latest time stamp amongst the source files (so you can check if the model needs to be rebuilt).

The function make_doc() extracts the doc string and adds the parameter table to the top. make_figure in sasmodels/doc/genmodel creates the default figure for the model. [These two sets of code should mignrate into docs.py so docs can be updated in one place].

sasmodels.generate.contains_Fq(source)

Return True if C source defines “void Fq(“.

sasmodels.generate.contains_shell_volume(source)

Return True if C source defines “double shell_volume(“.

sasmodels.generate.convert_section_titles_to_boldface(s)

Use explicit bold-face rather than section headings so that the table of contents is not polluted with section names from the model documentation.

Sections are identified as the title line followed by a line of punctuation at least as long as the title line.

sasmodels.generate.convert_type(source, dtype)

Convert code from double precision to the desired type.

Floating point constants are tagged with ‘f’ for single precision or ‘L’ for long double precision.

sasmodels.generate.demo_time()

Show how long it takes to process a model.

sasmodels.generate.dll_timestamp(model_info)

Return a timestamp for the model corresponding to the most recently changed file or dependency.

sasmodels.generate.find_xy_mode(source)

Return the xy mode as qa, qac, qabc or qxy.

Note this is not a C parser, and so can be easily confused by non-standard syntax. Also, it will incorrectly identify the following as having 2D models:

/*
double Iqac(qab, qc, ...) { ... fill this in later ... }
*/

If you want to comment out the function, use // on the front of the line:

/*
// double Iqac(qab, qc, ...) { ... fill this in later ... }
*/
sasmodels.generate.format_units(units)

Convert units into ReStructured Text format.

sasmodels.generate.get_data_path(external_dir, target_file)

Search for the target file relative in the installed application.

Search first in the location of the generate module in case we are running directly from the distribution. Search next to the python executable for windows installs. Search in the ../Resources directory next to the executable for Mac OS/X installs.

sasmodels.generate.indent(s, depth)

Indent a string of text with depth additional spaces on each line.

sasmodels.generate.kernel_name(model_info, variant)

Name of the exported kernel symbol.

variant is “Iq”, “Iqxy” or “Imagnetic”.

sasmodels.generate.load_kernel_module(model_name)

Return the kernel module named in model_name.

If the name ends in .py then load it as a custom model using sasmodels.custom.load_custom_kernel_module(), otherwise load it from sasmodels.models.

sasmodels.generate.load_template(filename)

Load template file from sasmodels resource directory.

sasmodels.generate.main()

Program which prints the source produced by the model.

sasmodels.generate.make_doc(model_info)

Return the documentation for the model.

sasmodels.generate.make_html(model_info)

Convert model docs directly to html.

sasmodels.generate.make_partable(pars)

Generate the parameter table to include in the sphinx documentation.

sasmodels.generate.make_source(model_info)

Generate the OpenCL/ctypes kernel from the module info.

Uses source files found in the given search path. Returns None if this is a pure python model, with no C source components.

sasmodels.generate.model_sources(model_info)

Return a list of the sources file paths for the module.

sasmodels.generate.ocl_timestamp(model_info)

Return a timestamp for the model corresponding to the most recently changed file or dependency.

Note that this does not look at the time stamps for the OpenCL header information since that need not trigger a recompile of the DLL.

sasmodels.generate.set_integration_size(info, n)

Update the model definition, replacing the gaussian integration with a gaussian integration of a different size.

Note: this really ought to be a method in modelinfo, but that leads to import loops.

sasmodels.generate.tag_source(source)

Return a unique tag for the source code.

sasmodels.generate.test_tag_float()

Check that floating point constants are identified and tagged with ‘f’

sasmodels.generate.view_html(model_name)

Load the model definition and view its help.

sasmodels.generate.view_html_from_info(info)

View the help for a loaded model definition.