sasmodels package


sasmodels.alignment module

GPU data alignment.

Some web sites say that maximizing performance for OpenCL code requires aligning data on certain memory boundaries. The following functions provide this service:

align_data() aligns an existing array, returning a new array of the correct alignment.

align_empty() to create an empty array of the correct alignment.

Set alignment to gpu.environment() attribute boundary.

Note: This code is unused. So far, tests have not demonstrated any improvement from forcing correct alignment. The tests should be repeated with arrays forced away from the target boundaries to decide whether it is really required.

sasmodels.alignment.align_data(x, dtype, alignment=128)[source]

Return a copy of an array on the alignment boundary.

sasmodels.alignment.align_empty(shape, dtype, alignment=128)[source]

Return an empty array aligned on the alignment boundary.

sasmodels.bumps_model module

Wrap sasmodels for direct use by bumps.

Model is a wrapper for the sasmodels kernel which defines a bumps Parameter box for each kernel parameter. Model accepts keyword arguments to set the initial value for each parameter.

Experiment combines the Model function with a data file loaded by the sasview data loader. Experiment takes a cutoff parameter controlling how far the polydispersity integral extends.

class sasmodels.bumps_model.Model(model, **kwargs)[source]

Bases: object

Bumps wrapper for a SAS model.

model is a runnable module as returned from core.load_model().

cutoff is the polydispersity weight cutoff.

Any additional key=value pairs are model dependent parameters.


Return a dictionary of parameters objects for the parameters, excluding polydispersity distribution type.


Return a dictionary of current values for all the parameters, including polydispersity distribution type.

class sasmodels.bumps_model.Experiment(data, model, cutoff=1e-05, name=None, extra_pars=None)[source]

Bases: sasmodels.direct_model.DataMixin

Bumps wrapper for a SAS experiment.

data is a data.Data1D, data.Data2D or data.Sesans object. Use data.empty_data1D() or data.empty_data2D() to define \(q, \Delta q\) calculation points for displaying the SANS curve when there is no measured data.

model is a Model object.

cutoff is the integration cutoff, which avoids computing the the SAS model where the polydispersity weight is low.

The resulting model can be used directly in a Bumps FitProblem call.


Return the negative log likelihood of seeing data given the model parameters, up to a normalizing constant which depends on the data uncertainty.


Return the number of data points


Return a dictionary of parameters


Plot the data and residuals.


Return theory minus data normalized by uncertainty.


Save the model parameters and data into a file.

Not Implemented.


Generate simulated data.


Return the theory corresponding to the model parameters.

This method uses lazy evaluation, and requires model.update() to be called when the parameters have changed.


Call when model parameters have changed and theory needs to be recalculated. module

Program to compare models using different compute engines.

This program lets you compare results between OpenCL and DLL versions of the code and between precision (half, fast, single, double, quad), where fast precision is single precision using native functions for trig, etc., and may not be completely IEEE 754 compliant. This lets make sure that the model calculations are stable, or if you need to tag the model as double precision only.

Run using ./ (Linux, Mac) or compare.bat (Windows) in the sasmodels root to see the command line options.

Note that there is no way within sasmodels to select between an OpenCL CPU device and a GPU device, but you can do so by setting the PYOPENCL_CTX environment variable ahead of time. Start a python interpreter and enter:

import pyopencl as cl

This will prompt you to select from the available OpenCL devices and tell you which string to use for the PYOPENCL_CTX variable. On Windows you will need to remove the quotes.

Program description

usage: sascomp model [options...] [key=val]

Generate and compare SAS models. If a single model is specified it shows a plot of that model. Different models can be compared, or the same model with different parameters. The same model with the same parameters can be compared with different calculation engines to see the effects of precision on the resultant values.

model or model1,model2 are the names of the models to compare (see below).

Options (* for default):

=== data generation === -data=”path” uses q, dq from the data file -noise=0 sets the measurement error dI/I -res=0 sets the resolution width dQ/Q if calculating with resolution -lowq*/-midq/-highq/-exq use q values up to 0.05, 0.2, 1.0, 10.0 -q=min:max alternative specification of qrange -nq=128 sets the number of Q points in the data set -1d*/-2d computes 1d or 2d data -zero indicates that q=0 should be included

=== model parameters === -preset*/-random[=seed] preset or random parameters -sets=n generates n random datasets with the seed given by -random=seed -pars/-nopars* prints the parameter set or not -default/-demo* use demo vs default parameters -sphere[=150] set up spherical integration over theta/phi using n points

=== calculation options === -mono*/-poly force monodisperse or allow polydisperse random parameters -cutoff=1e-5* cutoff value for including a point in polydispersity -magnetic/-nonmagnetic* suppress magnetism -accuracy=Low accuracy of the resolution calculation Low, Mid, High, Xhigh -neval=1 sets the number of evals for more accurate timing -ngauss=0 overrides the number of points in the 1-D gaussian quadrature

=== precision options === -engine=default uses the default calcution precision -single/-double/-half/-fast sets an OpenCL calculation engine -single!/-double!/-quad! sets an OpenMP calculation engine

=== plotting === -plot*/-noplot plots or suppress the plot of the model -linear/-log*/-q4 intensity scaling on plots -hist/-nohist* plot histogram of relative error -abs/-rel* plot relative or absolute error -title=”note” adds note to the plot title, after the model name -weights shows weights plots for the polydisperse parameters -profile shows the sld profile if the model has a plottable sld profile

=== output options === -edit starts the parameter explorer -help/-html shows the model docs instead of running the model

=== environment variables === -DSAS_MODELPATH=path sets directory containing custom models -DSAS_OPENCL=vendor:device|none sets the target OpenCL device -DXDG_CACHE_HOME=~/.cache sets the pyopencl cache root (linux only) -DSAS_COMPILER=tinycc|msvc|mingw|unix sets the DLL compiler -DSAS_OPENMP=1 turns on OpenMP for the DLLs -DSAS_DLL_PATH=path sets the path to the compiled modules

The interpretation of quad precision depends on architecture, and may vary from 64-bit to 128-bit, with 80-bit floats being common (1e-19 precision). On unix and mac you may need single quotes around the DLL computation engines, such as -engine=’single!,double!’ since !, is treated as a history expansion request in the shell.

Key=value pairs allow you to set specific values for the model parameters. Key=value1,value2 to compare different values of the same parameter. The value can be an expression including other parameters.

Items later on the command line override those that appear earlier.


# compare single and double precision calculation for a barbell sascomp barbell -engine=single,double

# generate 10 random lorentz models, with seed=27 sascomp lorentz -sets=10 -seed=27

# compare ellipsoid with R = R_polar = R_equatorial to sphere of radius R sascomp sphere,ellipsoid radius_polar=radius radius_equatorial=radius

# model timing test requires multiple evals to perform the estimate sascomp pringle -engine=single,double -timing=100,100 -noplot


Bases: object

Bumps wrapper for a SAS model comparison.

The resulting object can be used as a Bumps fit problem so that parameters can be adjusted in the GUI, with plots updated on the fly.


Respond to signal that model parameters have been changed.


Return cost.


Return the number of points.


Return a dictionary of parameters.


Plot the data and residuals.


Restore starting values of the parameters. = {'pow': <built-in function pow>, 'fsum': <built-in function fsum>, 'cosh': <built-in function cosh>, 'ldexp': <built-in function ldexp>, 'hypot': <built-in function hypot>, 'acosh': <built-in function acosh>, 'tan': <built-in function tan>, 'asin': <built-in function asin>, 'isnan': <built-in function isnan>, 'log': <built-in function log>, 'fabs': <built-in function fabs>, 'floor': <built-in function floor>, 'atanh': <built-in function atanh>, 'modf': <built-in function modf>, 'sqrt': <built-in function sqrt>, 'lgamma': <built-in function lgamma>, 'frexp': <built-in function frexp>, 'degrees': <built-in function degrees>, 'pi': 3.141592653589793, 'log10': <built-in function log10>, 'sin': <built-in function sin>, 'asinh': <built-in function asinh>, 'exp': <built-in function exp>, 'atan': <built-in function atan>, 'factorial': <built-in function factorial>, 'copysign': <built-in function copysign>, 'expm1': <built-in function expm1>, 'ceil': <built-in function ceil>, 'isinf': <built-in function isinf>, 'sinh': <built-in function sinh>, 'trunc': <built-in function trunc>, 'cos': <built-in function cos>, 'e': 2.718281828459045, 'tanh': <built-in function tanh>, 'radians': <built-in function radians>, 'atan2': <built-in function atan2>, 'erf': <built-in function erf>, 'erfc': <built-in function erfc>, 'fmod': <built-in function fmod>, 'acos': <built-in function acos>, 'log1p': <built-in function log1p>, 'gamma': <built-in function gamma>}

list of math functions for use in evaluating parameters[source]

build dictionary of functions from math module, indent='', width=79)[source]

Format a list of strings into columns.

Returns a string with carriage returns ready for printing., limits=None, maxdim=inf)[source]

Preform a comparison using options from the command line.

limits are the limits on the values to use, either to set the y-axis for 1D or to set the colormap scale for 2D. If None, then they are inferred from the data and returned. When exploring using Bumps, the limits are set when the model is initially called, and maintained as the values are adjusted, making it easier to see the effects of the parameters.

maxdim is the maximum value for any parameter with units of Angstrom., pars)[source]

Restrict parameters to valid values.

This includes model specific code for models such as capped_cylinder which need to support within model constraints (cap radius more than cylinder radius in this case).

Warning: this updates the pars dictionary in place.[source]

Return number date-time delta as number seconds, data, dtype='double', cutoff=0.0)[source]

Return a model calculator using the DLL calculation engine., data, dtype='single', cutoff=0.0)[source]

Return a model calculator using the OpenCL calculation engine.[source]

explore the model using the bumps gui., use_demo=False)[source]

Extract demo parameters from the model definition.[source]

Return True if string contains an int or float, pars, maxdim)[source]

Limit parameters of units of Ang to maxdim.*argv)[source]

Main program.[source]

Generate an empty dataset, used with the model to set Q points and resolution.

opts contains the options, with ‘qmax’, ‘nq’, ‘res’, ‘accuracy’, ‘is2d’ and ‘view’ parsed from the command line., data, dtype, cutoff, ngauss=0)[source]

Generate the appropriate calculation engine for the given datatype.

Datatypes with ‘!’ appended are evaluated using external C DLLs rather than OpenCL., v)[source]

Choose a parameter range based on parameter name and initial value., pars, is2d)[source]

Format the parameter list for printing.[source]

Parse command line options., maxdim=inf)[source]

Generate a parameter set.

The default values come from the model, or a randomized model if a seed value is given. Next, evaluate any parameter expressions, constraining the value of the parameter within and between models. If maxdim is given, limit parameters with units of Angstrom to this value.

Returns a pair of parameter dictionaries for base and comparison models., result, limits=None, setnum=0)[source]

Plot the results from run_model()., label='base', **args)[source]

Plot the profile returned by the model profile method.

model_info defines model parameters, etc.

mesh is a list of tuples containing (value, dispersity, weights) for each parameter, where (dispersity, weights) pairs are the distributions to be plotted.


Bases: object

Set the seed value for the random number generator.

When used in a with statement, the random number generator state is restored after the with statement is complete.

: int or array_like, optional
Seed for RandomState

Seed can be used directly to set the seed:

>>> from numpy.random import randint
>>> push_seed(24)
<...push_seed object at...>
>>> print(randint(0,1000000,3))
[242082    899 211136]

Seed can also be used in a with statement, which sets the random number generator state for the enclosed computations and restores it to the previous state on completion:

>>> with push_seed(24):
...    print(randint(0,1000000,3))
[242082    899 211136]

Using nested contexts, we can demonstrate that state is indeed restored after the block completes:

>>> with push_seed(24):
...    print(randint(0,1000000))
...    with push_seed(24):
...        print(randint(0,1000000,3))
...    print(randint(0,1000000))
[242082    899 211136]

The restore step is protected against exceptions in the block:

>>> with push_seed(24):
...    print(randint(0,1000000))
...    try:
...        with push_seed(24):
...            print(randint(0,1000000,3))
...            raise Exception()
...    except Exception:
...        print("Exception raised")
...    print(randint(0,1000000))
[242082    899 211136]
Exception raised
899, pars)[source]

Generate random values for all of the parameters.

Valid ranges for the random number generator are guessed from the name of the parameter; this will not account for constraints such as cap radius greater than cylinder radius in the capped_cylinder model, so constrain_pars() needs to be called afterward.., verbose=False)[source]

Process a parameter set, return calculation results and times., radius, outer=None)[source]

Add a beam stop of the given radius. If outer, make an annulus., steps)[source]

Set integration parameters for spherical integration over the entire surface in theta-phi coordinates.[source]

show html docs for the model, suppress=True)[source]

If suppress is True complete eliminate magnetism of the model to test models more quickly. If suppress is False, make sure at least one sld parameter is magnetic, setting the first parameter to have a strong magnetic sld (8/A^2) at 60 degrees (with no explicit demo parameters given in the model, there will be no default magnetism)., suppress=True)[source]

If suppress is True complete eliminate polydispersity of the model to test models more quickly. If suppress is False, make sure at least one parameter is polydisperse, setting the first polydispersity parameter to 15% if no polydispersity is given (with no explicit demo parameters given in the model, there will be no default polydispersity).[source]

Timer function.

Use “toc=tic()” to start the clock and “toc()” to measure a time interval., pars, evals=1)[source]

Compute the average calculation time over N evaluations.

An additional call is generated without polydispersity in order to initialize the calculation engine, and make the average more stable.

sasmodels.compare_many module

Program to compare results from many random parameter sets for a given model.

The result is a comma separated value (CSV) table that can be redirected from standard output into a file and loaded into a spreadsheet.

The models are compared for each parameter set and if the difference is greater than expected for that precision, the parameter set is labeled as bad and written to the output, along with the random seed used to generate that parameter value. This seed can be used with compare to reload and display the details of the model.

sasmodels.compare_many.calc_stats(target, value, index)[source]

Calculate statistics between the target value and the computed value.

target and value are the vectors being compared, with the difference normalized by target to get relative error. Only the elements listed in index are used, though index may be and empty slice defined by slice(None, None).


maxrel the maximum relative difference

rel95 the relative difference with the 5% biggest differences ignored

maxabs the maximum absolute difference for the 5% biggest differences

maxval the maximum value for the 5% biggest differences

sasmodels.compare_many.compare_instance(name, data, index, N=1, mono=True, cutoff=1e-05, base='single', comp='double')[source]

Compare the model under different calculation engines.

name is the name of the model.

data is the data object giving \(q, \Delta q\) calculation points.

index is the active set of points.

N is the number of comparisons to make.

cutoff is the polydispersity weight cutoff to make the calculation a little bit faster.

base and comp are the names of the calculation engines to compare.


Main program.

sasmodels.compare_many.print_column_headers(pars, parts)[source]

Generate column headers for the differences and for the parameters, and print them to standard output.


Print usage string, the option description and the list of available models.


Print the list of available models in columns.


Print the command usage string.

sasmodels.conversion_table module

Parameter conversion table

CONVERSION_TABLE gives the old model name and a dictionary of old parameter names for each parameter in sasmodels. This is used by convert to determine the equivalent parameter set when comparing a sasmodels model to the models defined in previous versions of SasView and sasmodels. This is now versioned based on the version number of SasView.

When any sasmodels parameter or model name is changed, this must be modified to account for that.


<old_Sasview_version> : {
    <new_model_name> : [
        <old_model_name> ,
            <new_param_name_1> : <old_param_name_1>,
            <new_param_name_n> : <old_param_name_n>

Any future parameter and model name changes can and should be given in this table for future compatibility.

sasmodels.convert module

Convert models to and from sasview.

sasmodels.convert.constrain_new_to_old(model_info, pars)[source]

Restrict parameter values to those that will match sasview.

sasmodels.convert.convert_model(name, pars, use_underscore=False, model_version=(3, 1, 2))[source]

Convert model from old style parameter names to new style.

sasmodels.convert.revert_pars(model_info, pars)[source]

Convert model from new style parameter names to old style.


sasmodels.core module

Core model handling routines.


Return the list of available models on the model path.

kind can be one of the following:

  • all: all models
  • py: python models only
  • c: compiled models only
  • single: models which support single precision
  • double: models which require double precision
  • opencl: controls if OpenCL is supperessed
  • 1d: models which are 1D only, or 2D using abs(q)
  • 2d: models which can be 2D
  • magnetic: models with an sld
  • nommagnetic: models without an sld

For multiple conditions, combine with plus. For example, c+single+2d would return all oriented models implemented in C which can be computed accurately with single precision arithmetic.

sasmodels.core.load_model(model_name, dtype=None, platform='ocl')[source]

Load model info and build model.

model_name is the name of the model, or perhaps a model expression such as sphere*hardsphere or sphere+cylinder.

dtype and platform are given by build_model().


Load a model definition given the model name.

model_string is the name of the model, or perhaps a model expression such as sphere*cylinder or sphere+cylinder. Use ‘@’ for a structure factor product, e.g. sphere@hardsphere. Custom models can be specified by prefixing the model name with ‘custom.’, e.g. ‘custom.MyModel+sphere’.

This returns a handle to the module defining the model. This can be used with functions in generate to build the docs or extract model info.

sasmodels.core.build_model(model_info, dtype=None, platform='ocl')[source]

Prepare the model for the default execution platform.

This will return an OpenCL model, a DLL model or a python model depending on the model and the computing platform.

model_info is the model definition structure returned from load_model_info().

dtype indicates whether the model should use single or double precision for the calculation. Choices are ‘single’, ‘double’, ‘quad’, ‘half’, or ‘fast’. If dtype ends with ‘!’, then force the use of the DLL rather than OpenCL for the calculation.

platform should be “dll” to force the dll to be used for C models, otherwise it uses the default “ocl”.

sasmodels.core.precompile_dlls(path, dtype='double')[source]

Precompile the dlls for all builtin models, returning a list of dll paths.

path is the directory in which to save the dlls. It will be created if it does not already exist.

This can be used when build the windows distribution of sasmodels which may be missing the OpenCL driver and the dll compiler. module

SAS data representations.

Plotting functions for data sets:

plot_data() plots the data file.

plot_theory() plots a calculated result from the model.

Wrappers for the sasview data loader and data manipulations:

load_data() loads a sasview data file.

set_beam_stop() masks the beam stop from the data.

set_half() selects the right or left half of the data, which can be useful for shear measurements which have not been properly corrected for path length and reflections.

set_top() cuts the top part off the data.

Empty data sets for evaluating models without data:

empty_data1D() creates an empty dataset, which is useful for plotting a theory function before the data is measured.

empty_data2D() creates an empty 2D dataset.

Note that the empty datasets use a minimal representation of the SasView objects so that models can be run without SasView on the path. You could also use these for your own data loader.

class, y=None, dx=None, dy=None)[source]

Bases: object

1D data object.

Note that this definition matches the attributes from sasview, with some generic 1D data vectors and some SAS specific definitions. Some refactoring to allow consistent naming conventions between 1D, 2D and SESANS data would be helpful.


x, dx: \(q\) vector and gaussian resolution

y, dy: \(I(q)\) vector and measurement uncertainty

mask: values to include in plotting/analysis

dxl: slit widths for slit smeared data, with dx ignored

qmin, qmax: range of \(q\) values in x

filename: label for the data line

_xaxis, _xunit: label and units for the x axis

_yaxis, _yunit: label and units for the y axis

xaxis(label, unit)[source]

set the x axis label and unit

yaxis(label, unit)[source]

set the y axis label and unit

class, y=None, z=None, dx=None, dy=None, dz=None)[source]

Bases: object

2D data object.

Note that this definition matches the attributes from sasview. Some refactoring to allow consistent naming conventions between 1D, 2D and SESANS data would be helpful.


qx_data, dqx_data: \(q_x\) matrix and gaussian resolution

qy_data, dqy_data: \(q_y\) matrix and gaussian resolution

data, err_data: \(I(q)\) matrix and measurement uncertainty

mask: values to exclude from plotting/analysis

qmin, qmax: range of \(q\) values in x

filename: label for the data line

_xaxis, _xunit: label and units for the x axis

_yaxis, _yunit: label and units for the y axis

_zaxis, _zunit: label and units for the y axis

Q_unit, I_unit: units for Q and intensity

x_bins, y_bins: grid steps in x and y directions

xaxis(label, unit)[source]

set the x axis label and unit

yaxis(label, unit)[source]

set the y axis label and unit

zaxis(label, unit)[source]

set the y axis label and unit

class, None), distance=None)[source]

Bases: object

Detector attributes.


Bases: object

Sample attributes.



SESANS data object.

This is just Data1D with a wavelength parameter.

x is spin echo length and y is polarization (P/P0).

isSesans = True

Bases: object

Beam attributes.

class, y=None, z=None)[source]

Bases: object

3-space vector of x, y, z[source]

Load and plot a SAS dataset., resolution=0.0, L=0.0, dL=0.0)[source]

Create empty 1D data using the given q as the x value.

rms resolution \(\Delta q/q\) defaults to 0%. If wavelength L and rms wavelength divergence dL are defined, then resolution defines rms \(\Delta \theta/\theta\) for the lowest q, with \(\theta\) derived from \(q = 4\pi/\lambda \sin(\theta)\)., qy=None, resolution=0.0)[source]

Create empty 2D data using the given mesh.

If qy is missing, create a square mesh with qy=qx.

resolution dq/q defaults to 5%., index=0)[source]

Load data using a sasview loader., view='log', limits=None)[source]

Plot data loaded by the sasview loader.

data is a sasview data object, either 1D, 2D or SESANS.

view is log or linear.

limits sets the intensity limits on the plot; if None then the limits are inferred from the data., theory, resid=None, view='log', use_data=True, limits=None, Iq_calc=None)[source]

Plot theory calculation.

data is needed to define the graph properties such as labels and units, and to define the data mask.

theory is a matrix of the same shape as the data.

view is log or linear

use_data is True if the data should be plotted as well as the theory.

limits sets the intensity limits on the plot; if None then the limits are inferred from the data.

Iq_calc is the raw theory values without resolution smearing[source]

Decorator to wrap calls in an exception trapper which prints the exception and continues. Keyboard interrupts are ignored., radius, outer=None)[source]

Add a beam stop of the given radius. If outer, make an annulus., half)[source]

Select half of the data, either “right” or “left”., cutoff)[source]

Chop the top off the data, above cutoff.

sasmodels.details module

Kernel Call Details

When calling sas computational kernels with polydispersity there are a number of details that need to be sent to the caller. This includes the list of polydisperse parameters, the number of points in the polydispersity weight distribution, and which parameter is the “theta” parameter for polar coordinate integration. The CallDetails object maintains this data. Use build_details() to build a details object which can be passed to one of the computational kernels.

class sasmodels.details.CallDetails(model_info)[source]

Bases: object

Manage the polydispersity information for the kernel call.

Conceptually, a polydispersity calculation is an integral over a mesh in n-D space where n is the number of polydisperse parameters. In order to keep the program responsive, and not crash the GPU, only a portion of the mesh is computed at a time. Meshes with a large number of points will therefore require many calls to the polydispersity loop. Restarting a nested loop in the middle requires that the indices of the individual mesh dimensions can be computed for the current loop location. This is handled by the pd_stride vector, with n//stride giving the loop index and n%stride giving the position in the sub loops.

One of the parameters may be the latitude. When integrating in polar coordinates, the total circumference decreases as latitude varies from pi r^2 at the equator to 0 at the pole, and the weight associated with a range of latitude values needs to be scaled by this circumference. This scale factor needs to be updated each time the theta value changes. theta_par indicates which of the values in the parameter vector is the latitude parameter, or -1 if there is no latitude parameter in the model. In practice, the normalization term cancels if the latitude is not a polydisperse parameter.


Number of active polydispersity loops


Total size of the pd mesh


Total length of all the weight vectors

parts = None

Number of weights for each polydisperse parameter


Offsets for the individual weight vectors in the set of weights


List of polydisperse parameters


Stride in the pd mesh for each pd dimension


Print the polydispersity call details to the console


Location of the theta parameter in the parameter vector

sasmodels.details.convert_magnetism(parameters, values)[source]

Convert magnetism values from polar to rectangular coordinates.

Returns True if any magnetism is present.

sasmodels.details.correct_theta_weights(parameters, dispersity, weights)[source]

Deprecated Theta weights will be computed in the kernel wrapper if they are needed.

If there is a theta parameter, update the weights of that parameter so that the cosine weighting required for polar integration is preserved.

Avoid evaluation strictly at the pole, which would otherwise send the weight to zero. This is probably not a problem in practice (if dispersity is +/- 90, then you probably should be using a 1-D model of the circular average).

Note: scale and background parameters are not include in the tuples for dispersity and weights, so index is parameters.theta_offset, not parameters.theta_offset+2

Returns updated weights vectors

sasmodels.details.dispersion_mesh(model_info, mesh)[source]

Create a mesh grid of dispersion parameters and weights.

mesh is a list of (value, dispersity, weights), where the values are the individual parameter values, and (dispersity, weights) is the distribution of parameter values.

Only the volume parameters should be included in this list. Orientation parameters do not affect the calculation of effective radius or volume ratio. This is convenient since it avoids the distinction between value and dispersity that is present in orientation parameters but not shape parameters.

Returns [p1,p2,...],w where pj is a vector of values for parameter j and w is a vector containing the products for weights for each parameter set in the vector.

sasmodels.details.make_details(model_info, length, offset, num_weights)[source]

Return a CallDetails object for a polydisperse calculation of the model defined by model_info. Polydispersity is defined by the length of the polydispersity distribution for each parameter and the offset of the distribution in the polydispersity array. Monodisperse parameters should use a polydispersity length of one with weight 1.0. num_weights is the total length of the polydispersity array.

sasmodels.details.make_kernel_args(kernel, mesh)[source]

Converts (value, dispersity, weight) for each parameter into kernel pars.

Returns a CallDetails object indicating the polydispersity, a data object containing the different values, and the magnetic flag indicating whether any magnetic magnitudes are non-zero. Magnetic vectors (M0, phi, theta) are converted to rectangular coordinates (mx, my, mz).

sasmodels.direct_model module

Class interface to the model calculator.

Calling a model is somewhat non-trivial since the functions called depend on the data type. For 1D data the Iq kernel needs to be called, for 2D data the Iqxy kernel needs to be called, and for SESANS data the Iq kernel needs to be called followed by a Hankel transform. Before the kernel is called an appropriate q calculation vector needs to be constructed. This is not the simple q vector where you have measured the data since the resolution calculation will require values beyond the range of the measured data. After the calculation the resolution calculator must be called to return the predicted value for each measured data point.

DirectModel is a callable object that takes parameter=value keyword arguments and returns the appropriate theory values for the data.

DataMixin does the real work of interpreting the data and calling the model calculator. This is used by DirectModel, which uses direct parameter values and by bumps_model.Experiment which wraps the parameter values in boxes so that the user can set fitting ranges, etc. on the individual parameters and send the model to the Bumps optimizers.

class sasmodels.direct_model.DataMixin[source]

Bases: object

DataMixin captures the common aspects of evaluating a SAS model for a particular data set, including calculating Iq and evaluating the resolution function. It is used in particular by DirectModel, which evaluates a SAS model parameters as key word arguments to the calculator method, and by bumps_model.Experiment, which wraps the model and data for use with the Bumps fitting engine. It is not currently used by sasview_model.SasviewModel since this will require a number of changes to SasView before we can do it.

_interpret_data() initializes the data structures necessary to manage the calculations. This sets attributes in the child class such as data_type and resolution.

_calc_theory() evaluates the model at the given control values.

_set_data() sets the intensity data in the data object, possibly with random noise added. This is useful for simulating a dataset with the results from _calc_theory().

class sasmodels.direct_model.DirectModel(data, model, cutoff=1e-05)[source]

Bases: sasmodels.direct_model.DataMixin

Create a calculator object for a model.

data is 1D SAS, 2D SAS or SESANS data

model is a model calculator return from generate.load_model()

cutoff is the polydispersity weight cutoff.


Generate a plottable profile.

simulate_data(noise=None, **pars)[source]

Generate simulated data for the model.

sasmodels.direct_model.call_ER(model_info, pars)[source]

Call the model ER function using values.

model_info is either if you have a loaded model, or if you have a model kernel prepared for evaluation.

sasmodels.direct_model.call_VR(model_info, pars)[source]

Call the model VR function using pars.

model_info is either if you have a loaded model, or if you have a model kernel prepared for evaluation.

sasmodels.direct_model.call_kernel(calculator, pars, cutoff=0.0, mono=False)[source]

Call kernel returned from model.make_kernel with parameters pars.

cutoff is the limiting value for the product of dispersion weights used to perform the multidimensional dispersion calculation more quickly at a slight cost to accuracy. The default value of cutoff=0 integrates over the entire dispersion cube. Using cutoff=1e-5 can be 50% faster, but with an error of about 1%, which is usually less than the measurement uncertainty.

mono is True if polydispersity should be set to none on all parameters.

sasmodels.direct_model.call_profile(model_info, **pars)[source]

Returns the profile x, y, (xlabel, ylabel) representing the model.

sasmodels.direct_model.get_mesh(model_info, values, dim='1d', mono=False)[source]

Retrieve the dispersity mesh described by the parameter set.

Returns a list of (value, dispersity, weights) with one tuple for each parameter in the model call parameters. Inactive parameters return the default value with a weight of 1.0.


Program to evaluate a particular model at a set of q values.

sasmodels.exception module

Utility to add annotations to python exceptions.

sasmodels.exception.annotate_exception(msg, exc=None)[source]

Add an annotation to the current exception, which can then be forwarded to the caller using a bare “raise” statement to raise the annotated exception. If the exception exc is provided, then that exception is the one that is annotated, otherwise sys.exc_info is used.


>>> D = {}
>>> try:
...    print(D['hello'])
... except:
...    annotate_exception("while accessing 'D'")
...    raise
Traceback (most recent call last):
KeyError: "hello while accessing 'D'"

sasmodels.generate module

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.

ER(p1, p2, ...) returns the effective radius of the form with particular dimensions.

VR(p1, p2, ...) returns the volume ratio for core-shell style forms.

#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.

ER and VR are python functions which operate on parameter vectors. The constructor code will generate the necessary vectors for computing them with the desired polydispersity. 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.

ER is a python function defining the effective radius. If it is not present, the effective radius is 0.

VR is a python function defining the volume ratio. If it is not present, the volume ratio is 1.

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 so docs can be updated in one place].


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)[source]

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.


Show how long it takes to process a model.


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


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 ... }

Convert units into ReStructured Text format.

sasmodels.generate.get_data_path(external_dir, target_file)[source]
sasmodels.generate.indent(s, depth)[source]

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

sasmodels.generate.kernel_name(model_info, variant)[source]

Name of the exported kernel symbol.

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


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.


Load template file from sasmodels resource directory.


Program which prints the source produced by the model.


Return the documentation for the model.


Convert model docs directly to html.


Generate the parameter table to include in the sphinx documentation.


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.


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


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)[source]

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.


Return a unique tag for the source code.


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


Load the model definition and view its help.


View the help for a loaded model definition.

sasmodels.gengauss module

sasmodels.gengauss.gengauss(n, path)[source]

sasmodels.guyou module

Convert between latitude-longitude and Guyou map coordinates.

sasmodels.guyou.ellipticFi(phi, psi, m)[source]
sasmodels.guyou.ellipticJi(u, v, m)[source]
sasmodels.guyou.guyou(lam, phi)[source]

Transform from (latitude, longitude) to point (x, y)

sasmodels.guyou.guyou_invert(x, y)[source]

Transform from point (x, y) on plot to (latitude, longitude)


Show the Guyou transformation


Plot the latitude-longitude grid for Guyou transform

sasmodels.jitter module

Jitter Explorer

Application to explore orientation angle and angular dispersity.


Construct a matrix to rotate points about x by angle degrees.


Construct a matrix to rotate points about y by angle degrees.


Construct a matrix to rotate points about z by angle degrees.

sasmodels.jitter.apply_jitter(jitter, points)[source]

Apply the jitter transform to a set of points.

Points are stored in a 3 x n numpy matrix, not a numpy array or tuple.

sasmodels.jitter.build_model(model_name, n=150, qmax=0.5, **pars)[source]

Build a calculator for the given shape.

model_name is any sasmodels model. n and qmax define an n x n mesh on which to evaluate the model. The remaining parameters are stored in the returned calculator as They are used by draw_scattering() to set the non-orientation parameters in the calculation.

Returns a calculator function which takes a dictionary or parameters and produces Iqxy. The Iqxy value needs to be reshaped to an n x n matrix for plotting. See the sasmodels.direct_model.DirectModel class for details.

sasmodels.jitter.clipped_range(data, portion=1.0, mode='central')[source]

Determine range from data.

If portion is 1, use full range, otherwise use the center of the range or the top of the range, depending on whether mode is ‘central’ or ‘top’.

sasmodels.jitter.draw_bcc(axes, size, view, jitter, steps=None, alpha=1)[source]

Draw points for body-centered cubic paracrystal

sasmodels.jitter.draw_beam(axes, view=(0, 0))[source]

Draw the beam going from source at (0, 0, 1) to detector at (0, 0, -1)

sasmodels.jitter.draw_ellipsoid(axes, size, view, jitter, steps=25, alpha=1)[source]

Draw an ellipsoid.

sasmodels.jitter.draw_fcc(axes, size, view, jitter, steps=None, alpha=1)[source]

Draw points for face-centered cubic paracrystal

sasmodels.jitter.draw_jitter(axes, view, jitter, dist='gaussian', size=(0.1, 0.4, 1.0), draw_shape=<function draw_parallelepiped at 0x000000000C7F0DD8>)[source]

Represent jitter as a set of shapes at different orientations.

sasmodels.jitter.draw_labels(axes, view, jitter, text)[source]

Draw text at a particular location.

sasmodels.jitter.draw_mesh(axes, view, jitter, radius=1.2, n=11, dist='gaussian', projection='equirectangular')[source]

Draw the dispersion mesh showing the theta-phi orientations at which the model will be evaluated.

jitter projections <>

equirectangular (standard latitude-longitude mesh)
<> Allows free movement in phi (around the equator), but theta is limited to +/- 90, and points are cos-weighted. Jitter in phi is uniform in weight along a line of latitude. With small theta and phi ranging over +/- 180 this forms a wobbling disk. With small phi and theta ranging over +/- 90 this forms a wedge like a slice of an orange.
azimuthal_equidistance (Postel)
<> Preserves distance from center, and so is an excellent map for representing a bivariate gaussian on the surface. Theta and phi operate identically, cutting wegdes from the antipode of the viewing angle. This unfortunately does not allow free movement in either theta or phi since the orthogonal wobble decreases to 0 as the body rotates through 180 degrees.
sinusoidal (Sanson-Flamsteed, Mercator equal-area)
<> Preserves arc length with latitude, giving bad behaviour at theta near +/- 90. Theta and phi operate somewhat differently, so a system with a-b-c dtheta-dphi-dpsi will not give the same value as one with b-a-c dphi-dtheta-dpsi, as would be the case for azimuthal equidistance. Free movement using theta or phi uniform over +/- 180 will work, but not as well as equirectangular phi, with theta being slightly worse. Computationally it is much cheaper for wide theta-phi meshes since it excludes points which lie outside the sinusoid near theta +/- 90 rather than packing them close together as in equirectangle. Note that the poles will be slightly overweighted for theta > 90 with the circle from theta at 90+dt winding backwards around the pole, overlapping the circle from theta at 90-dt.
Guyou (hemisphere-in-a-square) not weighted
<> With tiling, allows rotation in phi or theta through +/- 180, with uniform spacing. Both theta and phi allow free rotation, with wobble in the orthogonal direction reasonably well behaved (though not as good as equirectangular phi). The forward/reverse transformations relies on elliptic integrals that are somewhat expensive, so the behaviour has to be very good to justify the cost and complexity. The weighting function for each point has not yet been computed. Note: run the module directly and it will show the forward and reverse mappings.
azimuthal_equal_area incomplete
<> Preserves the relative density of the surface patches. Not that useful and not completely implemented
Gauss-Kreuger not implemented
<> Should allow free movement in theta, but phi is distorted.
sasmodels.jitter.draw_parallelepiped(axes, size, view, jitter, steps=None, alpha=1)[source]

Draw a parallelepiped.

sasmodels.jitter.draw_sc(axes, size, view, jitter, steps=None, alpha=1)[source]

Draw points for simple cubic paracrystal

sasmodels.jitter.draw_scattering(calculator, axes, view, jitter, dist='gaussian')[source]

Plot the scattering for the particular view.

calculator is returned from build_model(). axes are the 3D axes on which the data will be plotted. view and jitter are the current orientation and orientation dispersity. dist is one of the sasmodels weight distributions.

sasmodels.jitter.draw_sphere(axes, radius=10.0, steps=100)[source]

Draw a sphere

sasmodels.jitter.orient_relative_to_beam(view, points)[source]

Apply the view transform to a set of points.

Points are stored in a 3 x n numpy matrix, not a numpy array or tuple.'parallelepiped', size=(10, 40, 100), dist='gaussian', mesh=30, projection='equirectangular')[source]

Show an interactive orientation and jitter demo.

model_name is one of: sphere, ellipsoid, triaxial_ellipsoid, parallelepiped, cylinder, or sc/fcc/bcc_paracrystal

size gives the dimensions (a, b, c) of the shape.

dist is the type of dispersition: gaussian, rectangle, or uniform.

mesh is the number of points in the dispersion mesh.

projection is the map projection to use for the mesh: equirectangular, sinusoidal, guyou, azimuthal_equidistance, or azimuthal_equal_area.

sasmodels.jitter.select_calculator(model_name, n=150, size=(10, 40, 100))[source]

Create a model calculator for the given shape.

model_name is one of sphere, cylinder, ellipsoid, triaxial_ellipsoid, parallelepiped or bcc_paracrystal. n is the number of points to use in the q range. qmax is chosen based on model parameters for the given model to show something intersting.

Returns calculator and tuple size (a,b,c) giving minor and major equitorial axes and polar axis respectively. See build_model() for details on the returned calculator.

sasmodels.jitter.transform_xyz(view, jitter, x, y, z)[source]

Send a set of (x,y,z) points through the jitter and view transforms.

sasmodels.kernel module

Execution kernel interface

KernelModel defines the interface to all kernel models. In particular, each model should provide a KernelModel.make_kernel() call which returns an executable kernel, Kernel, that operates on the given set of q_vector inputs. On completion of the computation, the kernel should be released, which also releases the inputs.

class sasmodels.kernel.Kernel[source]

Bases: object

dim = None

kernel dimension, either “1d” or “2d”

dtype = None
info = None
results = None
class sasmodels.kernel.KernelModel[source]

Bases: object

dtype = None
info = None

sasmodels.kernelcl module

GPU driver for C kernels

There should be a single GPU environment running on the system. This environment is constructed on the first call to env(), and the same environment is returned on each call.

After retrieving the environment, the next step is to create the kernel. This is done with a call to GpuEnvironment.make_kernel(), which returns the type of data used by the kernel.

Next a GpuData object should be created with the correct kind of data. This data object can be used by multiple kernels, for example, if the target model is a weighted sum of multiple kernels. The data should include any extra evaluation points required to compute the proper data smearing. This need not match the square grid for 2D data if there is an index saying which q points are active.

Together the GpuData, the program, and a device form a GpuKernel. This kernel is used during fitting, receiving new sets of parameters and evaluating them. The output value is stored in an output buffer on the devices, where it can be combined with other structure factors and form factors and have instrumental resolution effects applied.

In order to use OpenCL for your models, you will need OpenCL drivers for your machine. These should be available from your graphics card vendor. Intel provides OpenCL drivers for CPUs as well as their integrated HD graphics chipsets. AMD also provides drivers for Intel CPUs, but as of this writing the performance is lacking compared to the Intel drivers. NVidia combines drivers for CUDA and OpenCL in one package. The result is a bit messy if you have multiple drivers installed. You can see which drivers are available by starting python and running:

import pyopencl as cl cl.create_some_context(interactive=True)

Once you have done that, it will show the available drivers which you can select. It will then tell you that you can use these drivers automatically by setting the SAS_OPENCL environment variable, which is PYOPENCL_CTX equivalent but not conflicting with other pyopnecl programs.

Some graphics cards have multiple devices on the same card. You cannot yet use both of them concurrently to evaluate models, but you can run the program twice using a different device for each session.

OpenCL kernels are compiled when needed by the device driver. Some drivers produce compiler output even when there is no error. You can see the output by setting PYOPENCL_COMPILER_OUTPUT=1. It should be harmless, albeit annoying.

class sasmodels.kernelcl.GpuEnvironment[source]

Bases: object

GPU context, with possibly many devices, and one queue per device.

compile_program(name, source, dtype, fast, timestamp)[source]

Compile the program for the device in the given context.


Return a OpenCL context for the kernels of type dtype.


Return a command queue for the kernels of type dtype.


Return True if all devices support a given type.

class sasmodels.kernelcl.GpuInput(q_vectors, dtype=dtype('float32'))[source]

Bases: object

Make q data available to the gpu.

q_vectors is a list of q vectors, which will be [q] for 1-D data, and [qx, qy] for 2-D data. Internally, the vectors will be reallocated to get the best performance on OpenCL, which may involve shifting and stretching the array to better match the memory architecture. Additional points will be evaluated with q=1e-3.

dtype is the data type for the q vectors. The data type should be set to match that of the kernel, which is an attribute of GpuProgram. Note that not all kernels support double precision, so even if the program was created for double precision, the GpuProgram.dtype may be single precision.

Call release() when complete. Even if not called directly, the buffer will be released when the data object is freed.


Free the memory.

class sasmodels.kernelcl.GpuKernel(kernel, dtype, model_info, q_vectors)[source]

Bases: sasmodels.kernel.Kernel

Callable SAS kernel.

kernel is the GpuKernel object to call

model_info is the module information

q_vectors is the q vectors at which the kernel should be evaluated

dtype is the kernel precision

The resulting call method takes the pars, a list of values for the fixed parameters to the kernel, and pd_pars, a list of (value,weight) vectors for the polydisperse parameters. cutoff determines the integration limits: any points with combined weight less than cutoff will not be calculated.

Call release() when done with the kernel instance.


Release resources associated with the kernel.

class sasmodels.kernelcl.GpuModel(source, model_info, dtype=dtype('float32'), fast=False)[source]

Bases: sasmodels.kernel.KernelModel

GPU wrapper for a single model.

source and model_info are the model source and interface as returned from generate.make_source() and generate.make_model_info().

dtype is the desired model precision. Any numpy dtype for single or double precision floats will do, such as ‘f’, ‘float32’ or ‘single’ for single and ‘d’, ‘float64’ or ‘double’ for double. Double precision is an optional extension which may not be available on all devices. Half precision (‘float16’,’half’) may be available on some devices. Fast precision (‘fast’) is a loose version of single precision, indicating that the compiler is allowed to take shortcuts.


Free the resources associated with the model.

sasmodels.kernelcl.compile_model(context, source, dtype, fast=False)[source]

Build a model to run on the gpu.

Returns the compiled program and its type.

Raises an error if the desired precision is not available.


Returns a singleton GpuEnvironment.

This provides an OpenCL context and one queue per device.


Monkey patch pyopencl to allow spaces in include file path.

sasmodels.kernelcl.get_warp(kernel, queue)[source]

Return the size of an execution batch for kernel running on queue.

sasmodels.kernelcl.has_type(device, dtype)[source]

Return true if device supports the requested precision.


Quote the path if it is not already quoted.

If v starts with ‘-‘, then assume that it is a -I option or similar and do not quote it. This is fragile: -Ipath with space needs to be quoted.


Call to create a new OpenCL context, such as after a change to SAS_OPENCL.


sasmodels.kerneldll module

DLL driver for C kernels

If the environment variable SAS_OPENMP is set, then sasmodels will attempt to compile with OpenMP flags so that the model can use all available kernels. This may or may not be available on your compiler toolchain. Depending on operating system and environment.

Windows does not have provide a compiler with the operating system. Instead, we assume that TinyCC is installed and available. This can be done with a simple pip command if it is not already available:

pip install tinycc

If Microsoft Visual C++ is available (because VCINSTALLDIR is defined in the environment), then that will be used instead. Microsoft Visual C++ for Python is available from Microsoft:

If neither compiler is available, sasmodels will check for MinGW, the GNU compiler toolchain. This available in packages such as Anaconda and PythonXY, or available stand alone. This toolchain has had difficulties on some systems, and may or may not work for you.

You can control which compiler to use by setting SAS_COMPILER in the environment:

  • tinycc (Windows): use the TinyCC compiler shipped with SasView
  • msvc (Windows): use the Microsoft Visual C++ compiler
  • mingw (Windows): use the MinGW GNU cc compiler
  • unix (Linux): use the system cc compiler.
  • unix (Mac): use the clang compiler. You will need XCode installed, and the XCode command line tools. Mac comes with OpenCL drivers, so generally this will not be needed.

Both msvc and mingw require that the compiler is available on your path. For msvc, this can done by running vcvarsall.bat in a windows terminal. Install locations are system dependent, such as:

C:Program Files (x86)Common FilesMicrosoftVisual C++ for Python9.0vcvarsall.bat

or maybe

C:UsersyournameAppDataLocalProgramsCommonMicrosoftVisual C++ for Python9.0vcvarsall.bat

OpenMP for msvc requires the Microsoft vcomp90.dll library, which doesn’t seem to be included with the compiler, nor does there appear to be a public download location. There may be one on your machine already in a location such as:


If you copy this to somewhere on your path, such as the python directory or the install directory for this application, then OpenMP should be supported.

For full control of the compiler, define a function compile_command(source,output) which takes the name of the source file and the name of the output file and returns a compile command that can be evaluated in the shell. For even more control, replace the entire compile(source,output) function.

The global attribute ALLOW_SINGLE_PRECISION_DLLS should be set to False if you wish to prevent single precision floating point evaluation for the compiled models, otherwise set it defaults to True.

class sasmodels.kerneldll.DllKernel(kernel, model_info, q_input)[source]

Bases: sasmodels.kernel.Kernel

Callable SAS kernel.

kernel is the c function to call.

model_info is the module information

q_input is the DllInput q vectors at which the kernel should be evaluated.

The resulting call method takes the pars, a list of values for the fixed parameters to the kernel, and pd_pars, a list of (value, weight) vectors for the polydisperse parameters. cutoff determines the integration limits: any points with combined weight less than cutoff will not be calculated.

Call release() when done with the kernel instance.


Release any resources associated with the kernel.

class sasmodels.kerneldll.DllModel(dllpath, model_info, dtype=dtype('float32'))[source]

Bases: sasmodels.kernel.KernelModel

ctypes wrapper for a single model.

source and model_info are the model source and interface as returned from gen.make().

dtype is the desired model precision. Any numpy dtype for single or double precision floats will do, such as ‘f’, ‘float32’ or ‘single’ for single and ‘d’, ‘float64’ or ‘double’ for double. Double precision is an optional extension which may not be available on all devices.

Call release() when done with the kernel.


Release any resources associated with the model.

sasmodels.kerneldll.compile(source, output)[source]

Compile source producing output.

Raises RuntimeError if the compile failed or the output wasn’t produced.

sasmodels.kerneldll.compile_command(source, output)[source]

tinycc compiler command

sasmodels.kerneldll.dll_name(model_info, dtype)[source]

Name of the dll containing the model. This is the base file name without any path or extension, with a form such as ‘sas_sphere32’.

sasmodels.kerneldll.dll_path(model_info, dtype)[source]

Complete path to the dll for the model. Note that the dll may not exist yet if it hasn’t been compiled.

sasmodels.kerneldll.load_dll(source, model_info, dtype=dtype('float64'))[source]

Create and load a dll corresponding to the source, info pair returned from sasmodels.generate.make() compiled for the target precision.

See make_dll() for details on controlling the dll path and the allowed floating point precision.

sasmodels.kerneldll.make_dll(source, model_info, dtype=dtype('float64'))[source]

Returns the path to the compiled model defined by kernel_module.

If the model has not been compiled, or if the source file(s) are newer than the dll, then make_dll will compile the model before returning. This routine does not load the resulting dll.

dtype is a numpy floating point precision specifier indicating whether the model should be single, double or long double precision. The default is double precision, np.dtype(‘d’).

Set sasmodels.ALLOW_SINGLE_PRECISION_DLLS to False if single precision models are not allowed as DLLs.

Set sasmodels.kerneldll.SAS_DLL_PATH to the compiled dll output path. Alternatively, set the environment variable SAS_DLL_PATH. The default is in ~/.sasmodels/compiled_models.

sasmodels.kernelpy module

Python driver for python kernels

Calls the kernel with a vector of \(q\) values for a single parameter set. Polydispersity is supported by looping over different parameter sets and summing the results. The interface to PyModel matches those for kernelcl.GpuModel and kerneldll.DllModel.

class sasmodels.kernelpy.PyInput(q_vectors, dtype)[source]

Bases: object

Make q data available to the gpu.

q_vectors is a list of q vectors, which will be [q] for 1-D data, and [qx, qy] for 2-D data. Internally, the vectors will be reallocated to get the best performance on OpenCL, which may involve shifting and stretching the array to better match the memory architecture. Additional points will be evaluated with q=1e-3.

dtype is the data type for the q vectors. The data type should be set to match that of the kernel, which is an attribute of GpuProgram. Note that not all kernels support double precision, so even if the program was created for double precision, the GpuProgram.dtype may be single precision.

Call release() when complete. Even if not called directly, the buffer will be released when the data object is freed.


Free resources associated with the model inputs.

class sasmodels.kernelpy.PyKernel(model_info, q_input)[source]

Bases: sasmodels.kernel.Kernel

Callable SAS kernel.

kernel is the kernel object to call.

model_info is the module information

q_input is the DllInput q vectors at which the kernel should be evaluated.

The resulting call method takes the pars, a list of values for the fixed parameters to the kernel, and pd_pars, a list of (value,weight) vectors for the polydisperse parameters. cutoff determines the integration limits: any points with combined weight less than cutoff will not be calculated.

Call release() when done with the kernel instance.


Free resources associated with the kernel.

class sasmodels.kernelpy.PyModel(model_info)[source]

Bases: sasmodels.kernel.KernelModel

Wrapper for pure python models.


Free resources associated with the model.

sasmodels.list_pars module

List all parameters used along with the models which use them.


python -m sasmodels.list_pars [-v]

If ‘-v’ is given, then list the models containing the parameter in addition to just the parameter name.


Find all parameters in all models.

Returns the reference table {parameter: [model, model, ...]}

sasmodels.list_pars.list_pars(names_only=True, type=None)[source]

Print all parameters in all models.

If names_only then only print the parameter name, not the models it occurs in.


Program to list the parameters used across all models.

sasmodels.mixture module

Mixture model

The product model multiplies the structure factor by the form factor, modulated by the effective radius of the form. The resulting model has a attributes of both the model description (with parameters, etc.) and the module evaluator (with call, release, etc.).

To use it, first load form factor P and structure factor S, then create ProductModel(P, S).

class sasmodels.mixture.MixtureKernel(model_info, kernels)[source]

Bases: sasmodels.kernel.Kernel

class sasmodels.mixture.MixtureModel(model_info, parts)[source]

Bases: sasmodels.kernel.KernelModel


Free resources associated with the model.

class sasmodels.mixture.MixtureParts(model_info, kernels, call_details, values)[source]

Bases: object

sasmodels.mixture.make_mixture_info(parts, operation='+')[source]

Create info block for mixture model.

sasmodels.model_test module

Run model unit tests.


python -m sasmodels.model_test [opencl|dll|opencl_and_dll] model1 model2 ...

if model1 is 'all', then all except the remaining models will be tested

Each model is tested using the default parameters at q=0.1, (qx, qy)=(0.1, 0.1), and the ER and VR are computed. The return values at these points are not considered. The test is only to verify that the models run to completion, and do not produce inf or NaN.

Tests are defined with the tests attribute in the file. tests is a list of individual tests to run, where each test consists of the parameter values for the test, the q-values and the expected results. For the effective radius test, the q-value should be ‘ER’. For the VR test, the q-value should be ‘VR’. For 1-D tests, either specify the q value or a list of q-values, and the corresponding I(q) value, or list of I(q) values.

That is:

tests = [
    [ {parameters}, q, I(q)],
    [ {parameters}, [q], [I(q)] ],
    [ {parameters}, [q1, q2, ...], [I(q1), I(q2), ...]],

    [ {parameters}, (qx, qy), I(qx, Iqy)],
    [ {parameters}, [(qx1, qy1), (qx2, qy2), ...],
                    [I(qx1, qy1), I(qx2, qy2), ...]],

    [ {parameters}, 'ER', ER(pars) ],
    [ {parameters}, 'VR', VR(pars) ],

Parameters are key:value pairs, where key is one of the parameters of the model and value is the value to use for the test. Any parameters not given in the parameter list will take on the default parameter value.

Precision defaults to 5 digits (relative).


Run the tests for a single model, capturing the output.

Returns success status and the output string.

sasmodels.model_test.invalid_pars(partable, pars)[source]

Return a list of parameter names that are not part of the model.

sasmodels.model_test.is_near(target, actual, digits=5)[source]

Returns true if actual is within digits significant digits of target.


Run tests given is models.

Returns 0 if success or 1 if any tests fail.

sasmodels.model_test.make_suite(loaders, models)[source]

Construct the pyunit test suite.

loaders is the list of kernel drivers to use, which is one of [“dll”, “opencl”], [“dll”] or [“opencl”]. For python models, the python driver is always used.

models is the list of models to test, or [“all”] to test all models.


Test runner visible to nosetests.

Run “nosetests sasmodels” on the command line to invoke it.


sasmodels.modelinfo module

Model Info and Parameter Tables

Defines ModelInfo and ParameterTable and the routines for manipulating them. In particular, make_model_info() converts a kernel module into the model info block as seen by the rest of the sasmodels library.

sasmodels.modelinfo.C_SYMBOLS = ['Imagnetic', 'Iq', 'Iqxy', 'Iqac', 'Iqabc', 'form_volume', 'c_code']

Set of variables defined in the model that might contain C code

sasmodels.modelinfo.MAX_PD = 5

Maximum number of simultaneously polydisperse parameters

class sasmodels.modelinfo.ModelInfo[source]

Bases: object

Interpret the model definition file, categorizing the parameters.

The module can be loaded with a normal python import statement if you know which module you need, or with __import__(‘sasmodels.model.’+name) if the name is in a string.

The structure should be mostly static, other than the delayed definition of Iq, Iqac and Iqabc if they need to be defined.

ER = None

Returns the effective radius of the model given its volume parameters. The presence of ER indicates that the model is a form factor model that may be used together with a structure factor to form an implicit multiplication model.

The parameters to the ER function must be marked with type volume. in the parameter table. They will appear in the same order as they do in the table. The values passed to ER will be vectors, with one value for each polydispersity condition. For example, if the model is polydisperse over both length and radius, then both length and radius will have the same number of values in the vector, with one value for each length X radius. If only radius is polydisperse, then the value for length will be repeated once for each value of radius. The ER function should return one effective radius for each parameter set. Multiplicity parameters will be received as arrays, with one row per polydispersity condition.

Imagnetic = None

Returns I(qx, qy, a, b, ...). The interface follows Iq.

Iq = None

Returns I(q, a, b, ...) for parameters a, b, etc. defined by the parameter table. Iq can be defined as a python function, or as a C function. If it is defined in C, then set Iq to the body of the C function, including the return statement. This function takes values for q and each of the parameters as separate double values (which may be converted to float or long double by sasmodels). All source code files listed in sources will be loaded before the Iq function is defined. If Iq is not present, then sources should define static double Iq(double q, double a, double b, ...) which will return I(q, a, b, ...). Multiplicity parameters are sent as pointers to doubles. Constants in floating point expressions should include the decimal point. See generate for more details.

Iqabc = None

Returns I(qa, qb, qc, a, b, ...). The interface follows Iq.

Iqac = None

Returns I(qab, qc, a, b, ...). The interface follows Iq.

VR = None

Returns the occupied volume and the total volume for each parameter set. See ER for details on the parameters.

c_code = None

Arbitrary C code containing supporting functions, etc., to be inserted after everything in source. This can include Iq and Iqxy functions with the full function signature, including all parameters.

category = None

Location of the model description in the documentation. This takes the form of “section” or “section:subsection”. So for example, porod uses category=”shape-independent” so it is in the Shape-Independent Functions section whereas capped_cylinder uses: category=”shape:cylinder”, which puts it in the Cylinder Functions section.

composition = None

Composition is None if this is an independent model, or it is a tuple with comoposition type (‘product’ or ‘misture’) and a list of ModelInfo blocks for the composed objects. This allows us to rebuild a complete mixture or product model from the info block. composition is not given in the model definition file, but instead arises when the model is constructed using names such as sphere*hardsphere or cylinder+sphere.

control = None

Name of the control parameter for a variant model such as rpa. The control parameter should appear in the parameter table, with limits defined as [CASES], for case names such as CASES = [“diblock copolymer”, “triblock copolymer”, ...]. This should give limits=[[case1, case2, ...]], but the model loader translates this to limits=[0, len(CASES)-1], and adds choices=CASES to the Parameter definition. Note that models can use a list of cases as a parameter without it being a control parameter. Either way, the parameter is sent to the model evaluator as float(choice_num), where choices are numbered from 0. See also hidden.

demo = None

Demo parameters as a parameter:value map used as the default values for compare. Any parameters not set in demo will use the defaults from the parameter table. That means no polydispersity, and in the case of multiplicity models, a minimal model with no interesting scattering.

description = None

Long description of the model.

docs = None

Doc string from the top of the model file. This should be formatted using ReStructuredText format, with latex markup in ”.. math” environments, or in dollar signs. This will be automatically extracted to a .rst file by generate.make_docs(), then converted to HTML or PDF by Sphinx.

filename = None

Full path to the file defining the kernel, if any.

form_volume = None

Returns the form volume for python-based models. Form volume is needed for volume normalization in the polydispersity integral. If no parameters are volume parameters, then form volume is not needed. For C-based models, (with sources defined, or with Iq defined using a string containing C code), form_volume must also be C code, either defined as a string, or in the sources.


Returns the set of hidden parameters for the model. control is the value of the control parameter. Note that multiplicity models have an implicit control parameter, which is the parameter that controls the multiplicity.

hidden = None

Different variants require different parameters. In order to show just the parameters needed for the variant selected by control, you should provide a function hidden(control) -> set([‘a’, ‘b’, ...]) indicating which parameters need to be hidden. For multiplicity models, you need to use the complete name of the parameter, including its number. So for example, if variant “a” uses only sld1 and sld2, then sld3, sld4 and sld5 of multiplicity parameter sld[5] should be in the hidden set.

id = None

Id of the kernel used to load it from the filesystem.

lineno = None

Line numbers for symbols defining C code

name = None

Display name of the model, which defaults to the model id but with capitalization of the parts so for example core_shell defaults to “Core Shell”.

opencl = None

True if the model can be run as an opencl model. If for some reason the model cannot be run in opencl (e.g., because the model passes functions by reference), then set this to false.

parameters = None

Model parameter table. Parameters are defined using a list of parameter definitions, each of which is contains parameter name, units, default value, limits, type and description. See Parameter for details on the individual parameters. The parameters are gathered into a ParameterTable, which provides various views into the parameter list.

profile = None

Returns a model profile curve x, y. If profile is defined, this curve will appear in response to the Show button in SasView. Use profile_axes to set the axis labels. Note that y values will be scaled by 1e6 before plotting.

profile_axes = None

Axis labels for the profile plot. The default is [‘x’, ‘y’]. Only the x component is used for now.

random = None

Returns a random parameter set for the model

sesans = None

Returns sesans(z, a, b, ...) for models which can directly compute the SESANS correlation function. Note: not currently implemented.

single = None

True if the model can be computed accurately with single precision. This is True by default, but models such as bcc_paracrystal set it to False because they require double precision calculations.

source = None

List of C source files used to define the model. The source files should define the Iq function, and possibly Iqac or Iqabc if the model defines orientation parameters. Files containing the most basic functions must appear first in the list, followed by the files that use those functions. Form factors are indicated by providing an ER function.

structure_factor = None

True if the model is a structure factor used to model the interaction between form factor models. This will default to False if it is not provided in the file.

tests = None

The set of tests that must pass. The format of the tests is described in model_test.

title = None

Short description of the model.

class sasmodels.modelinfo.Parameter(name, units='', default=None, limits=(-inf, inf), ptype='', description='')[source]

Bases: object

The available kernel parameters are defined as a list, with each parameter defined as a sublist with the following elements:

name is the name that will be displayed to the user. Names should be lower case, with words separated by underscore. If acronyms are used, the whole acronym should be upper case. For vector parameters, the name will be followed by [len] where len is an integer length of the vector, or the name of the parameter which controls the length. The attribute id will be created from name without the length.

units should be one of degrees for angles, Ang for lengths, 1e-6/Ang^2 for SLDs.

default value will be the initial value for the model when it is selected, or when an initial value is not otherwise specified.

limits = [lb, ub] are the hard limits on the parameter value, used to limit the polydispersity density function. In the fit, the parameter limits given to the fit are the limits on the central value of the parameter. If there is polydispersity, it will evaluate parameter values outside the fit limits, but not outside the hard limits specified in the model. If there are no limits, use +/-inf imported from numpy.

type indicates how the parameter will be used. “volume” parameters will be used in all functions. “orientation” parameters are not passed, but will be used to convert from qx, qy to qa, qb, qc in calls to Iqxy and Imagnetic. If type is the empty string, the parameter will be used in all of Iq, Iqxy and Imagnetic. “sld” parameters can automatically be promoted to magnetic parameters, each of which will have a magnitude and a direction, which may be different from other sld parameters. The volume parameters are used for calls to form_volume within the kernel (required for volume normalization) and for calls to ER and VR for effective radius and volume ratio respectively.

description is a short description of the parameter. This will be displayed in the parameter table and used as a tool tip for the parameter value in the user interface.

Additional values can be set after the parameter is created:

  • length is the length of the field if it is a vector field
  • length_control is the parameter which sets the vector length
  • is_control is True if the parameter is a control parameter for a vector
  • polydisperse is true if the parameter accepts a polydispersity
  • relative_pd is true if that polydispersity is a portion of the value (so a 10% length dipsersity would use a polydispersity value of 0.1) rather than absolute dispersisity (such as an angle plus or minus 15 degrees).

choices is the option names for a drop down list of options, as for example, might be used to set the value of a shape parameter.

These values are set by make_parameter_table() and parse_parameter() therein.


Return prefix + parameter name. For struct references, use “v.” as the prefix.


Declare space for the variable in a parameter structure.

For example, the parameter thickness with length 3 will return “double thickness[3];”, with no spaces before and no new line character afterward.


Declare the variable as a function argument.

For example, the parameter thickness with length 3 will return “double *thickness”, with no spaces before and no comma afterward.

class sasmodels.modelinfo.ParameterTable(parameters)[source]

Bases: object

ParameterTable manages the list of available parameters.

There are a couple of complications which mean that the list of parameters for the kernel differs from the list of parameters that the user sees.

(1) Common parameters. Scale and background are implicit to every model, but are not passed to the kernel.

(2) Vector parameters. Vector parameters are passed to the kernel as a pointer to an array, e.g., thick[], but they are seen by the user as n separate parameters thick1, thick2, ...

Therefore, the parameter table is organized by how it is expected to be used. The following information is needed to set up the kernel functions:

  • kernel_parameters is the list of parameters in the kernel parameter table, with vector parameter p declared as p[].
  • iq_parameters is the list of parameters to the Iq(q, ...) function, with vector parameter p sent as p[].
  • form_volume_parameters is the list of parameters to the form_volume(...) function, with vector parameter p sent as p[].

Problem details, which sets up the polydispersity loops, requires the following:

  • theta_offset is the offset of the theta parameter in the kernel parameter table, with vector parameters counted as n individual parameters p1, p2, ..., or offset is -1 if there is no theta parameter.
  • max_pd is the maximum number of polydisperse parameters, with vector parameters counted as n individual parameters p1, p2, ... Note that this number is limited to sasmodels.modelinfo.MAX_PD.
  • npars is the total number of parameters to the kernel, with vector parameters counted as n individual parameters p1, p2, ...
  • call_parameters is the complete list of parameters to the kernel, including scale and background, with vector parameters recorded as individual parameters p1, p2, ...
  • active_1d is the set of names that may be polydisperse for 1d data
  • active_2d is the set of names that may be polydisperse for 2d data

User parameters are the set of parameters visible to the user, including the scale and background parameters that the kernel does not see. User parameters don’t use vector notation, and instead use p1, p2, ...

COMMON = [P<scale>, P<background>]

Check that orientation angles are theta, phi and possibly psi.

p = ('background', '1/cm', 0.001, (-inf, inf), '', 'Source background')
user_parameters(pars, is2d=True)[source]

Return the list of parameters for the given data type.

Vector parameters are expanded in place. If multiple parameters share the same vector length, then the parameters will be interleaved in the result. The control parameters come first. For example, if the parameter table is ordered as:


and pars[num_shells]=2 then the returned list will be:


Note that shell/thickness pairs are grouped together in the result even though they were not grouped in the incoming table. The control parameter is always returned first since the GUI will want to set it early, and rerender the table when it is changed.

Parameters marked as sld will automatically have a set of associated magnetic parameters (p_M0, p_mtheta, p_mphi), as well as polarization information (up_theta, up_frac_i, up_frac_f).

sasmodels.modelinfo.expand_pars(partable, pars)[source]

Create demo parameter set from key-value pairs.

pars are the key-value pairs to use for the parameters. Any parameters not specified in pars are set from the partable defaults.

If pars references vector fields, such as thickness[n], then support different ways of assigning the demo values, including assigning a specific value (e.g., thickness3=50.0), assigning a new value to all (e.g., thickness=50.0) or assigning values using list notation.


Return True if the object is a string.


Extract the model definition from the loaded kernel module.

Fill in default values for parts of the module that are not provided.

Note: vectorized Iq and Iqac/Iqabc functions will be created for python models when the model is first called, not when the model is loaded.


Construct a parameter table from a list of parameter definitions.

This is used by the module processor to convert the parameter block into the parameter table seen in the ModelInfo for the module.

sasmodels.modelinfo.parse_parameter(name, units='', default=nan, user_limits=None, ptype='', description='')[source]

Parse an individual parameter from the parameter definition block.

This does type and value checking on the definition, leading to early failure in the model loading process and easier debugging.

sasmodels.modelinfo.prefix_parameter(par, prefix)[source]

Return a copy of the parameter with its name prefixed.

sasmodels.modelinfo.suffix_parameter(par, suffix)[source]

Return a copy of the parameter with its name prefixed.

sasmodels.multiscat module

Multiple scattering calculator

Calculate multiple scattering using 2D FFT convolution.


-p, –probability: the scattering probability -q, –qmax: that max q that you care about -w, –window: the extension window (q is calculated for qmax*window) -n, –nq: the number of mesh points (dq = qmax*window/nq) -r, –random: generate a random parameter set -2, –2d: perform the calculation for an oriented pattern model_name model_par=value ...

Assume the probability of scattering is \(p\). After each scattering event, \(1-p\) neutrons will leave the system and go to the detector, and the remaining \(p\) will scatter again.

Let the scattering probability for \(n\) scattering event at \(q\) be \(f_n(q)\), where .. math:: f_1(q) = frac{I_1(q)}{int I_1(q) dq} for \(I_1(q)\), the single scattering from the system. After two scattering events, the scattering probability will be the convolution of the first scattering and itself, or \(f_2(q) = (f_1*f_1)(q)\). After \(n\) events it will be \(f_n(q) = (f_1 * \cdots * f_1)(q)\). The total scattering is calculated as the weighted sum of \(f_k\), with weights following the Poisson distribution .. math:: P(k; lambda) = frac{lambda^k e^{-lambda}}{k!} for \(\lambda\) determined by the total thickness divided by the mean free path between scattering, giving .. math:

I(q) = \sum_{k=0}^\infty P(k; \lambda) f_k(q)

The \(k=0\) term is ignored since it involves no scattering. We cut the series when cumulative probability is less than cutoff \(C=99\%\), which is \(\max n\) such that .. math:

\frac{\sum_{k=1}^n \frac{P(k; \lambda)}{1 - P(0; \lambda)} < C

Using the convolution theorem, where \(F = \mathcal{F}(f)\) is the Fourier transform, .. math:: f * g = mathcal{F}^{-1}{mathcal{F}{f} cdot mathcal{F}{g}} so .. math:: f * ldots * f = mathcal{F}^{-1}{ F^n } Since the Fourier transform is a linear operator, we can move the polynomial expression for the convolution into the transform, giving .. math:

I(q) = \mathcal{F}^{-1}\left\{ \sum_{k=1}^{n} P(k; \lambda) F^k \right\}

In the dilute limit \(L \rightarrow 0\) only the \(k=1\) term is active, and so .. math:

P(1; \lambda) = \lambda e{-\lambda} = \int I_1(q) dq

therefore we compute .. math:

I(q) = \int I_1(q) dq \mathcal{F}^{-1}\left\{
    \sum_{l=1}^{n} \frac{P(k; \lambda)}{P(1; \lambda))} F^k \right\}

For speed we may use the fast fourier transform with a power of two. The resulting \(I(q)\) will be linearly spaced and likely heavily oversampled. The usual pinhole or slit resolution calculation can performed from these calculated values.

By default single precision OpenCL is used for the calculation. Set the environment variable SAS_OPENCL=none to use double precision numpy FFT instead. The OpenCL versions is about 10x faster on an elderly Mac with Intel HD 4000 graphics. The single precision numerical artifacts don’t seem to seriously impact overall accuracy, though they look pretty bad.


alias of NumpyCalculator

class sasmodels.multiscat.ICalculator[source]

Multiple scattering calculator


Compute the forward FFT for an image, real -> complex.


Compute the inverse FFT for an image, complex -> complex.


Compute multiple scattering for I(q) given scattering probability p.

Given a probability p of scattering with the thickness, the expected number of scattering events, \(\lambda\) is \(-\log(1 - p)\), giving a Poisson weighted sum of single, double, triple, etc. scattering patterns. The number of patterns used is based on coverage (default 99%).

class sasmodels.multiscat.MultipleScattering(qmin=None, qmax=None, nq=None, window=2, probability=None, coverage=0.99, is2d=False, resolution=None, dtype=dtype('float64'))[source]

Bases: sasmodels.resolution.Resolution

Compute multiple scattering using Fourier convolution.

The fourier steps are determined by qmax, the maximum \(q\) value desired, nq the number of \(q\) steps and window, the amount of padding around the circular convolution. The \(q\) spacing will be \(\Delta q = 2 q_\mathrm{max} w / n_q\). If nq is not given it will use \(n_q = 2^k\) such that \(\Delta q < q_\mathrm{min}\).

probability is related to the expected number of scattering events in the sample \(\lambda\) as \(p = 1 - e^{-\lambda}\). coverage determines how many scattering steps to consider. The default is 0.99, which sets \(n\) such that \(1 \ldots n\) covers 99% of the Poisson probability mass function.

is2d is True then 2D scattering is used, otherwise it accepts and returns 1D scattering.

resolution is the resolution function to apply after multiple scattering. If present, then the resolution \(q\) vectors will provide default values for qmin, qmax and nq.


Compute that radial profile for the given Iqxy grid. The grid should be defined as for

class sasmodels.multiscat.NumpyCalculator(dims=None, dtype=dtype('float64'))[source]

Bases: sasmodels.multiscat.ICalculator

Multiple scattering calculator using numpy fft.

multiple_scattering(Iq, p, coverage=0.99)[source]
class sasmodels.multiscat.OpenclCalculator(dims, dtype=dtype('float64'))[source]

Bases: sasmodels.multiscat.ICalculator

Multiple scattering calculator using OpenCL via pyfft.

multiple_scattering(Iq, p, coverage=0.99)[source]
polyval1d = None
polyval1f = None
sasmodels.multiscat.annular_average(qxy, Iqxy, qbins)[source]

Compute annular average of points in Iqxy at qbins. The \(q_x\), \(q_y\) coordinates for Iqxy are given in qxy.

sasmodels.multiscat.parse_pars(model, opts)[source]

Parse par=val arguments from the command line.

sasmodels.multiscat.plot_and_save_powers(res, theory, result, plot=True, outfile='', background=0.0)[source]
sasmodels.multiscat.plotxy(q, Iq)[source]
sasmodels.multiscat.rebin(x, I, xo)[source]

Rebin from edges x, bins I into edges xo.

x and xo should be monotonically increasing.

If x has duplicate values, then all corresponding values at I(x) will be effectively summed into the same bin. If xo has duplicate values, the first bin will contain the entire contents and subsequent bins will contain zeros.

sasmodels.multiscat.scattering_coeffs(p, coverage=0.99)[source]

Return the coefficients of the scattering powers for transmission probability p. This is just the corresponding values for the Poisson distribution for \(\lambda = -\ln(1-p)\) such that \(\sum_{k = 0 \ldots n} P(k; \lambda)\) is larger than coverage.

sasmodels.multiscat.scattering_powers(Iq, n, dtype='f', transform=None)[source]

Calculate the scattering powers up to n.

This includes 1 even though it should just be Iq itself

The frames are unweighted; to weight scale by \(\lambda^k e^{-\lambda}/k!\).

sasmodels.multiscat.truncated_poisson_invcdf(coverage, L)[source]

Return smallest k such that cdf(k; L) > coverage from the truncated Poisson probability excluding k=0

sasmodels.product module

Product model

The product model multiplies the structure factor by the form factor, modulated by the effective radius of the form. The resulting model has a attributes of both the model description (with parameters, etc.) and the module evaluator (with call, release, etc.).

To use it, first load form factor P and structure factor S, then create make_product_info(P, S).

class sasmodels.product.ProductKernel(model_info, p_kernel, s_kernel)[source]

Bases: sasmodels.kernel.Kernel

class sasmodels.product.ProductModel(model_info, P, S)[source]

Bases: sasmodels.kernel.KernelModel

P = None

Form factor modelling individual particles.

S = None

Structure factor modelling interaction between particles.

dtype = None

Model precision. This is not really relevant, since it is the individual P and S models that control the effective dtype, converting the q-vectors to the correct type when the kernels for each are created. Ideally this should be set to the more precise type to avoid loss of precision, but precision in q is not critical (single is good enough for our purposes), so it just uses the precision of the form factor.

info = None

Combined info plock for the product model


Free resources associated with the model.

sasmodels.product.calc_er_vr(model_info, call_details, values)[source]
sasmodels.product.make_product_info(p_info, s_info)[source]

Create info block for product model.

sasmodels.resolution module

Define the resolution functions for the data.

This defines classes for 1D and 2D resolution calculations.

class sasmodels.resolution.Resolution[source]

Bases: object

Abstract base class defining a 1D resolution function.

q is the set of q values at which the data is measured.

q_calc is the set of q values at which the theory needs to be evaluated. This may extend and interpolate the q values.

apply is the method to call with I(q_calc) to compute the resolution smeared theory I(q).


Smear theory by the resolution function, returning Iq.

q = None
q_calc = None
class sasmodels.resolution.Perfect1D(q)[source]

Bases: sasmodels.resolution.Resolution

Resolution function to use when there is no actual resolution smearing to be applied. It has the same interface as the other resolution functions, but returns the identity function.

class sasmodels.resolution.Pinhole1D(q, q_width, q_calc=None, nsigma=(2.5, 3.0))[source]

Bases: sasmodels.resolution.Resolution

Pinhole aperture with q-dependent gaussian resolution.

q points at which the data is measured.

q_width gaussian 1-sigma resolution at each data point.

q_calc is the list of points to calculate, or None if this should be estimated from the q and q_width.

nsigma is the width of the resolution function. Should be 2.5. See pinhole_resolution() for details.

class sasmodels.resolution.Slit1D(q, qx_width, qy_width=0.0, q_calc=None)[source]

Bases: sasmodels.resolution.Resolution

Slit aperture with resolution function.

q points at which the data is measured.

qx_width slit width in qx

qy_width slit height in qy

q_calc is the list of points to calculate, or None if this should be estimated from the q and q_width.

The weight_matrix is computed by slit1d_resolution()

sasmodels.resolution.apply_resolution_matrix(weight_matrix, theory)[source]

Apply the resolution weight matrix to the computed theory function.

sasmodels.resolution.pinhole_resolution(q_calc, q, q_width, nsigma=(2.5, 3.0))[source]

Compute the convolution matrix W for pinhole resolution 1-D data.

Each row W[i] determines the normalized weight that the corresponding points q_calc contribute to the resolution smeared point q[i]. Given W, the resolution smearing can be computed using dot(W,q).

Note that resolution is limited to \(\pm 2.5 \sigma\).[1] The true resolution function is a broadened triangle, and does not extend over the entire range \((-\infty, +\infty)\). It is important to impose this limitation since some models fall so steeply that the weighted value in gaussian tails would otherwise dominate the integral.

q_calc must be increasing. q_width must be greater than zero.

[1] Barker, J. G., and J. S. Pedersen. 1995. Instrumental Smearing Effects in Radially Symmetric Small-Angle Neutron Scattering by Numerical and Analytical Methods. Journal of Applied Crystallography 28 (2): 105–14.

sasmodels.resolution.slit_resolution(q_calc, q, width, height, n_height=30)[source]

Build a weight matrix to compute I_s(q) from I(q_calc), given \(q_\perp\) = width and \(q_\parallel\) = height. n_height is is the number of steps to use in the integration over \(q_\parallel\) when both \(q_\perp\) and \(q_\parallel\) are non-zero.

Each \(q\) can have an independent width and height value even though current instruments use the same slit setting for all measured points.

If slit height is large relative to width, use:

\[I_s(q_i) = \frac{1}{\Delta q_\perp} \int_0^{\Delta q_\perp} I\left(\sqrt{q_i^2 + q_\perp^2}\right) \,dq_\perp\]

If slit width is large relative to height, use:

\[I_s(q_i) = \frac{1}{2 \Delta q_\parallel} \int_{-\Delta q_\parallel}^{\Delta q_\parallel} I\left(|q_i + q_\parallel|\right) \,dq_\parallel\]

For a mixture of slit width and height use:

\[I_s(q_i) = \frac{1}{2 \Delta q_\parallel \Delta q_\perp} \int_{-\Delta q_\parallel}^{\Delta q_\parallel} \int_0^{\Delta q_\perp} I\left(\sqrt{(q_i + q_\parallel)^2 + q_\perp^2}\right) \,dq_\perp dq_\parallel\]


We are using the mid-point integration rule to assign weights to each element of a weight matrix \(W\) so that

\[I_s(q) = W\,I(q_\text{calc})\]

If q_calc is at the mid-point, we can infer the bin edges from the pairwise averages of q_calc, adding the missing edges before q_calc[0] and after q_calc[-1].

For \(q_\parallel = 0\), the smeared value can be computed numerically using the \(u\) substitution

\[u_j = \sqrt{q_j^2 - q^2}\]

This gives

\[I_s(q) \approx \sum_j I(u_j) \Delta u_j\]

where \(I(u_j)\) is the value at the mid-point, and \(\Delta u_j\) is the difference between consecutive edges which have been first converted to \(u\). Only \(u_j \in [0, \Delta q_\perp]\) are used, which corresponds to \(q_j \in \left[q, \sqrt{q^2 + \Delta q_\perp}\right]\), so

\[W_{ij} = \frac{1}{\Delta q_\perp} \Delta u_j = \frac{1}{\Delta q_\perp} \left( \sqrt{q_{j+1}^2 - q_i^2} - \sqrt{q_j^2 - q_i^2} \right) \ \text{if}\ q_j \in \left[q_i, \sqrt{q_i^2 + q_\perp^2}\right]\]

where \(I_s(q_i)\) is the theory function being computed and \(q_j\) are the mid-points between the calculated values in q_calc. We tweak the edges of the initial and final intervals so that they lie on integration limits.

(To be precise, the transformed midpoint \(u(q_j)\) is not necessarily the midpoint of the edges \(u((q_{j-1}+q_j)/2)\) and \(u((q_j + q_{j+1})/2)\), but it is at least in the interval, so the approximation is going to be a little better than the left or right Riemann sum, and should be good enough for our purposes.)

For \(q_\perp = 0\), the \(u\) substitution is simpler:

\[u_j = \left|q_j - q\right|\]


\[W_{ij} = \frac{1}{2 \Delta q_\parallel} \Delta u_j = \frac{1}{2 \Delta q_\parallel} (q_{j+1} - q_j) \ \text{if}\ q_j \in \left[q-\Delta q_\parallel, q+\Delta q_\parallel\right]\]

However, we need to support cases were \(u_j < 0\), which means using \(2 (q_{j+1} - q_j)\) when \(q_j \in \left[0, q_\parallel-q_i\right]\). This is not an issue for \(q_i > q_\parallel\).

For both \(q_\perp > 0\) and \(q_\parallel > 0\) we perform a 2 dimensional integration with

\[u_{jk} = \sqrt{q_j^2 - (q + (k\Delta q_\parallel/L))^2} \ \text{for}\ k = -L \ldots L\]

for \(L\) = n_height. This gives

\[W_{ij} = \frac{1}{2 \Delta q_\perp q_\parallel} \sum_{k=-L}^L \Delta u_{jk} \left(\frac{\Delta q_\parallel}{2 L + 1}\right)\]
sasmodels.resolution.pinhole_extend_q(q, q_width, nsigma=(2.5, 3.0))[source]

Given q and q_width, find a set of sampling points q_calc so that each point \(I(q)\) has sufficient support from the underlying function.

sasmodels.resolution.slit_extend_q(q, width, height)[source]

Given q, width and height, find a set of sampling points q_calc so that each point I(q) has sufficient support from the underlying function.


Determine bin edges from bin centers, assuming that edges are centered between the bins.

Note: this uses the arithmetic mean, which may not be appropriate for log-scaled data.

sasmodels.resolution.interpolate(q, max_step)[source]

Returns q_calc with points spaced at most max_step apart.

sasmodels.resolution.linear_extrapolation(q, q_min, q_max)[source]

Extrapolate q out to [q_min, q_max] using the step size in q as a guide. Extrapolation below uses about the same size as the first interval. Extrapolation above uses about the same size as the final interval.

Note that extrapolated values may be negative.

sasmodels.resolution.geometric_extrapolation(q, q_min, q_max, points_per_decade=None)[source]

Extrapolate q to [q_min, q_max] using geometric steps, with the average geometric step size in q as the step size.

if q_min is zero or less then q[0]/10 is used instead.

points_per_decade sets the ratio between consecutive steps such that there will be \(n\) points used for every factor of 10 increase in q.

If points_per_decade is not given, it will be estimated as follows. Starting at \(q_1\) and stepping geometrically by \(\Delta q\) to \(q_n\) in \(n\) points gives a geometric average of:

\[\log \Delta q = (\log q_n - \log q_1) / (n - 1)\]

From this we can compute the number of steps required to extend \(q\) from \(q_n\) to \(q_\text{max}\) by \(\Delta q\) as:

\[n_\text{extend} = (\log q_\text{max} - \log q_n) / \log \Delta q\]


\[n_\text{extend} = (n-1) (\log q_\text{max} - \log q_n) / (\log q_n - \log q_1)\]

sasmodels.resolution2d module

#This software was developed by the University of Tennessee as part of the #Distributed Data Analysis of Neutron Scattering Experiments (DANSE) #project funded by the US National Science Foundation. #See the license text in license.txt

class sasmodels.resolution2d.Pinhole2D(data=None, index=None, nsigma=3.0, accuracy='Low', coords='polar')[source]

Bases: sasmodels.resolution.Resolution

Gaussian Q smearing class for SAS 2d data

class sasmodels.resolution2d.Slit2D(q, qx_width, qy_width=0.0, q_calc=None, accuracy='low')[source]

Bases: sasmodels.resolution.Resolution

Slit aperture with resolution function on an oriented sample.

q points at which the data is measured.

qx_width slit width in qx

qy_width slit height in qy; current implementation requires a fixed qy_width for all q points.

q_calc is the list of q points to calculate, or None if this should be estimated from the q and qx_width.

accuracy determines the number of qy points to compute for each q. The values are stored in sasmodels.resolution2d.N_SLIT_PERP. The default values are: low=101, med=401, high=1001, xhigh=2001


sasmodels.rst2html module

Convert a restructured text document to html.

Inline math markup can uses the math directive, or it can use latex style $expression$. Math can be rendered using simple html and unicode, or with mathjax.


Return True if QWebView exists.

Checks first in PyQt5 then in PyQt4

sasmodels.rst2html.qtview(html, url='')[source]

Convert frac12 to frac{1}{2} for broken latex parsers


Convert dollar signs to inline math markup in rst.

sasmodels.rst2html.rst2html(rst, part='whole', math_output='mathjax')[source]

Convert restructured text into simple html.

Valid math_output formats for formulas include: - html - mathml - mathjax See for details.

The following part choices are available: - whole: the entire html document - html_body: document division with title and contents and footer - body: contents only

There are other parts, but they don’t make sense alone:

subtitle, version, encoding, html_prolog, header, meta, html_title, title, stylesheet, html_subtitle, html_body, body, head, body_suffix, fragment, docinfo, html_head, head_prefix, body_prefix, footer, body_pre_docinfo, whole
sasmodels.rst2html.suppress_html_errors(*args, **kwds)[source]

Context manager for keeping error reports out of the generated HTML.

Within the context, system message nodes in the docutils parse tree will be ignored. After the context, the usual behaviour will be restored.


Test substitution of dollar signs with equivalent RST math markup

sasmodels.rst2html.view_help(filename, qt=False)[source]
sasmodels.rst2html.view_html(html, url='')
sasmodels.rst2html.view_html_qtapp(html, url='')[source]
sasmodels.rst2html.view_html_wxapp(html, url='')[source]
sasmodels.rst2html.wxview(html, url='', size=(850, 540))[source]

sasmodels.sasview_model module

Sasview model constructor.

Given a module defining an OpenCL kernel such as sasmodels.models.cylinder, create a sasview model class to run that kernel as follows:

from sasmodels.sasview_model import load_custom_model
CylinderModel = load_custom_model('sasmodels/models/')
sasmodels.sasview_model.MODELS = {}

set of defined models (standard and custom)

sasmodels.sasview_model.MODEL_BY_PATH = {}

custom model {path: model} mapping so we can check timestamps

sasmodels.sasview_model.MultiplicationModel(form_factor, structure_factor)[source]

Returns a constructed product model from form_factor and structure_factor.

class sasmodels.sasview_model.MultiplicityInfo(number, control, choices, x_axis_label)

Bases: tuple


Alias for field number 2


Alias for field number 1


Alias for field number 0


Alias for field number 3

sasmodels.sasview_model.SUPPORT_OLD_STYLE_PLUGINS = True

True if pre-existing plugins, with the old names and parameters, should continue to be supported.

class sasmodels.sasview_model.SasviewModel(multiplicity=None)[source]

Bases: object

Sasview wrapper for opencl/ctypes model.


returns parts of the composition model or None if not a composition model.


Calculate the effective radius for P(q)*S(q)

Returns:the value of the effective radius
calculate_Iq(qx, qy=None)[source]

Calculate Iq for one set of q with the current parameters.

If the model is 1D, use q. If 2D, use qx, qy.

This should NOT be used for fitting since it copies the q vectors to the card for each evaluation.


Calculate the volf ratio for P(q)*S(q)

Returns:the value of the volf ratio
category = None

default model category


Return a identical copy of self

cutoff = 1e-05

default cutoff for polydispersity

description = None

short model description

details = None

units and limits for each parameter

dispersion = None

values for dispersion width, npts, nsigmas and type


Evaluate a distribution of q-values.

Parameters:qdist – array of q or a list of arrays [qx,qy]
  • For 1D, a numpy array is expected as input

where *q* is a numpy array.
  • For 2D, a list of [qx,qy] is expected with 1D arrays as input
qx = [ qx[0], qx[1], qx[2], ....]
qy = [ qy[0], qy[1], qy[2], ....]

If the model is 1D only, then

\[q = \sqrt{q_x^2+q_y^2}\]
fixed = None

names of the fittable parameters


Return a list of polydispersity parameters for the model


Set the value of a model parameter

Parameters:name – name of the parameter

Return a list of all available parameters for the model


Get SLD profile

: return: (z, beta) where z is a list of depth of the transition points
beta is a list of the corresponding SLD values
id = None

load/save name for the model

input_name = 'Q'
input_unit = 'A^{-1}'

Check if a given parameter is fittable or not

Parameters:par_name – the parameter name to check
is_form_factor = False

True if model should appear as a form factor

is_multiplicity_model = False

True if model has multiplicity

is_structure_factor = False

True if model should appear as a structure factor

magnetic_params = None

names of the magnetic parameters in the order they appear

multiplicity = None

multiplicity value, or None if no multiplicity on the model

multiplicity_info = None

Multiplicity information

name = None

display name for the model

non_fittable = ()

parameters that are not fitted

orientation_params = None

names of the orientation parameters in the order they appear

output_name = 'Intensity'
output_unit = 'cm^{-1}'
params = None

parameter {name: value} mapping


Evaluate the model

Parameters:x – input q, or [q,phi]
Returns:scattering function P(q)

DEPRECATED: use calculate_Iq instead

classmethod runTests()[source]

Run any tests built into the model and captures the test output.

Returns success flag and output


Evaluate the model in cartesian coordinates

Parameters:x – input q, or [qx, qy]
Returns:scattering function P(q)

DEPRECATED: use calculate_Iq instead

setParam(name, value)[source]

Set the value of a model parameter

  • name – name of the parameter
  • value – value of the parameter
set_dispersion(parameter, dispersion)[source]

Set the dispersion object for a model parameter

  • parameter – name of the parameter [string]
  • dispersion – dispersion object of type Dispersion

Find a model by name. If the model name ends in py, try loading it from custom models, otherwise look for it in the list of builtin models.


Load a custom model given the model path.


Load and return the list of predefined models.

If there is an error loading a model, then a traceback is logged and the model is not returned.


Convert model_info into a SasView model wrapper.


Clear the compute engine context so that the GUI can change devices.

This removes all compiled kernels, even those that are active on fit pages, but they will be restored the next time they are needed.


Test that the cylinder model runs, returning the value at [0.1,0.1].


Make sure that sasmodels returns NaN when there are no polydispersity points


Make sure that all models build as sasview models


Load and run cylinder model as sas-models-CylinderModel


Test that 2-D hardsphere model runs and doesn’t produce NaN.


Test that the 2-D RPA model runs


Test that 2-D hardsphere model runs and doesn’t produce NaN.

sasmodels.sesans module

Conversion of scattering cross section from SANS (I(q), or rather, ds/dO) in absolute units (cm-1)into SESANS correlation function G using a Hankel transformation, then converting the SESANS correlation function into polarisation from the SESANS experiment

Everything is in units of metres except specified otherwise (NOT TRUE!!!) Everything is in conventional units (nm for spin echo length)

Wim Bouwman (, June 2013

class sasmodels.sesans.SesansTransform(z, SElength, lam, zaccept, Rmax)[source]

Bases: object

Spin-Echo SANS transform calculator. Similar to a resolution function, the SesansTransform object takes I(q) for the set of q_calc values and produces a transformed dataset

SElength (A) is the set of spin-echo lengths in the measured data.

zaccept (1/A) is the maximum acceptance of scattering vector in the spin echo encoding dimension (for ToF: Q of min(R) and max(lam)).

Rmax (A) is the maximum size sensitivity; larger radius requires more computation time.

q = None

SElength from the data in the original data units; not used by transform but the GUI uses it, so make sure that it is present.

q_calc = None

q values to calculate when computing transform

sasmodels.special module

Special Functions

This following standard C99 math functions are available:

M_PI, M_PI_2, M_PI_4, M_SQRT1_2, M_E:
\(\pi\), \(\pi/2\), \(\pi/4\), \(1/\sqrt{2}\) and Euler’s constant \(e\)
exp, log, pow(x,y), expm1, log1p, sqrt, cbrt:
Power functions \(e^x\), \(\ln x\), \(x^y\), \(e^x - 1\), \(\ln 1 + x\), \(\sqrt{x}\), \(\sqrt[3]{x}\). The functions expm1(x) and log1p(x) are accurate across all \(x\), including \(x\) very close to zero.
sin, cos, tan, asin, acos, atan:
Trigonometry functions and inverses, operating on radians.
sinh, cosh, tanh, asinh, acosh, atanh:
Hyperbolic trigonometry functions.
Angle from the \(x\)-axis to the point \((x,y)\), which is equal to \(\tan^{-1}(y/x)\) corrected for quadrant. That is, if \(x\) and \(y\) are both negative, then atan2(y,x) returns a value in quadrant III where atan(y/x) would return a value in quadrant I. Similarly for quadrants II and IV when \(x\) and \(y\) have opposite sign.
fabs(x), fmin(x,y), fmax(x,y), trunc, rint:
Floating point functions. rint(x) returns the nearest integer.
NaN, Not a Number, \(0/0\). Use isnan(x) to test for NaN. Note that you cannot use x == NAN to test for NaN values since that will always return false. NAN does not equal NAN! The alternative, x != x may fail if the compiler optimizes the test away.
\(\infty, 1/0\). Use isinf(x) to test for infinity, or isfinite(x) to test for finite and not NaN.
erf, erfc, tgamma, lgamma: do not use
Special functions that should be part of the standard, but are missing or inaccurate on some platforms. Use sas_erf, sas_erfc and sas_gamma instead (see below). Note: lgamma(x) has not yet been tested.

Some non-standard constants and functions are also provided:

M_PI_180, M_4PI_3:
\(\frac{\pi}{180}\), \(\frac{4\pi}{3}\)
SINCOS(x, s, c):
Macro which sets s=sin(x) and c=cos(x). The variables c and s must be declared first.
\(\sin(x)/x\), with limit \(\sin(0)/0 = 1\).
powr(x, y):
\(x^y\) for \(x \ge 0\); this is faster than general \(x^y\) on some GPUs.
pown(x, n):
\(x^n\) for \(n\) integer; this is faster than general \(x^n\) on some GPUs.

The number of bytes in a floating point value. Even though all variables are declared double, they may be converted to single precision float before running. If your algorithm depends on precision (which is not uncommon for numerical algorithms), use the following:

... code for double precision ...
... code for single precision ...
A replacement for double so that the declared variable will stay double precision; this should generally not be used since some graphics cards do not support double precision. There is no provision for forcing a constant to stay double precision.

The following special functions and scattering calculations are defined. These functions have been tuned to be fast and numerically stable down to \(q=0\) even in single precision. In some cases they work around bugs which appear on some platforms but not others, so use them where needed. Add the files listed in source = ["lib/file.c", ...] to your file in the order given, otherwise these functions will not be available.

polevl(x, c, n):

Polynomial evaluation \(p(x) = \sum_{i=0}^n c_i x^i\) using Horner’s method so it is faster and more accurate.

\(c = \{c_n, c_{n-1}, \ldots, c_0 \}\) is the table of coefficients, sorted from highest to lowest.

p1evl(x, c, n):

Evaluate normalized polynomial \(p(x) = x^n + \sum_{i=0}^{n-1} c_i x^i\) using Horner’s method so it is faster and more accurate.

\(c = \{c_{n-1}, c_{n-2} \ldots, c_0 \}\) is the table of coefficients, sorted from highest to lowest.


Gamma function \(\text{sas_gamma}(x) = \Gamma(x)\).

The standard math function, tgamma(x) is unstable for \(x < 1\) on some platforms.


log gamma function sas_gammaln\((x) = \log \Gamma(|x|)\).

The standard math function, lgamma(x), is incorrect for single precision on some platforms.

sas_gammainc(a, x), sas_gammaincc(a, x):
Incomplete gamma function sas_gammainc\((a, x) = \int_0^x t^{a-1}e^{-t}\,dt / \Gamma(a)\) and complementary incomplete gamma function sas_gammaincc\((a, x) = \int_x^\infty t^{a-1}e^{-t}\,dt / \Gamma(a)\)
sas_erf(x), sas_erfc(x):

Error function \(\text{sas_erf}(x) = \frac{2}{\sqrt\pi}\int_0^x e^{-t^2}\,dt\) and complementary error function \(\text{sas_erfc}(x) = \frac{2}{\sqrt\pi}\int_x^{\infty} e^{-t^2}\,dt\).

The standard math functions erf(x) and erfc(x) are slower and broken on some platforms.


Bessel function of the first kind \(\text{sas_J0}(x)=J_0(x)\) where \(J_0(x) = \frac{1}{\pi}\int_0^\pi \cos(x\sin(\tau))\,d\tau\).

The standard math function j0(x) is not available on all platforms.


Bessel function of the first kind \(\text{sas_J1}(x)=J_1(x)\) where \(J_1(x) = \frac{1}{\pi}\int_0^\pi \cos(\tau - x\sin(\tau))\,d\tau\).

The standard math function j1(x) is not available on all platforms.

sas_JN(n, x):

Bessel function of the first kind and integer order \(n\): \(\text{sas_JN}(n, x)=J_n(x)\) where \(J_n(x) = \frac{1}{\pi}\int_0^\pi \cos(n\tau - x\sin(\tau))\,d\tau\). If \(n\) = 0 or 1, it uses sas_J0(x) or sas_J1(x), respectively.

The standard math function jn(n, x) is not available on all platforms.


Sine integral \(\text{Si}(x) = \int_0^x \tfrac{\sin t}{t}\,dt\).

This function uses Taylor series for small and large arguments:

For large arguments,

\[\text{Si}(x) \sim \frac{\pi}{2} - \frac{\cos(x)}{x} \left(1 - \frac{2!}{x^2} + \frac{4!}{x^4} - \frac{6!}{x^6} \right) - \frac{\sin(x)}{x} \left(\frac{1}{x} - \frac{3!}{x^3} + \frac{5!}{x^5} - \frac{7!}{x^7}\right)\]

For small arguments,

\[\text{Si}(x) \sim x - \frac{x^3}{3\times 3!} + \frac{x^5}{5 \times 5!} - \frac{x^7}{7 \times 7!} + \frac{x^9}{9\times 9!} - \frac{x^{11}}{11\times 11!}\]

Spherical Bessel form \(\text{sph_j1c}(x) = 3 j_1(x)/x = 3 (\sin(x) - x \cos(x))/x^3\), with a limiting value of 1 at \(x=0\), where \(j_1(x)\) is the spherical Bessel function of the first kind and first order.

This function uses a Taylor series for small \(x\) for numerical accuracy.

Bessel form \(\text{sas_J1c}(x) = 2 J_1(x)/x\), with a limiting value of 1 at \(x=0\), where \(J_1(x)\) is the Bessel function of first kind and first order.
gauss76.n, gauss76.z[i], gauss76.w[i]:

Points \(z_i\) and weights \(w_i\) for 76-point Gaussian quadrature, respectively, computing \(\int_{-1}^1 f(z)\,dz \approx \sum_{i=1}^{76} w_i\,f(z_i)\). When translating the model to C, include ‘lib/gauss76.c’ in the source and use GAUSS_N, GAUSS_Z, and GAUSS_W.

Similar arrays are available in gauss20 for 20-point quadrature and gauss150.c for 150-point quadrature. By using import gauss76 as gauss it is easy to change the number of points in the integration.

class sasmodels.special.Gauss(w, z)[source]

return sin(x), cos(x)


return x^3

sasmodels.special.p1evl(x, c, n)[source]

return x^n + p(x) for polynomial p of degree n-1 with coefficients c

sasmodels.special.polevl(x, c, n)[source]

return p(x) for polynomial p of degree n-1 with coefficients c

sasmodels.special.pown(x, n)[source]

return x^n for n integer

sasmodels.special.powr(x, y)[source]

return x^y for x>0


return 2*J1(x)/x


return 3*j1(x)/x


return Si(x)


return j1(x)


return sin(x)/x


return sin(x), cos(x)


return x^2

sasmodels.weights module

SAS distributions for polydispersity.

class sasmodels.weights.ArrayDispersion(npts=None, width=None, nsigmas=None)[source]

Bases: sasmodels.weights.Dispersion

Empirical dispersion curve.

Use set_weights() to set \(w = f(x)\).

default = {'width': 0, 'nsigmas': 1, 'npts': 35}
set_weights(values, weights)[source]

Set the weights for the given x values.

type = 'array'
class sasmodels.weights.BoltzmannDispersion(npts=None, width=None, nsigmas=None)[source]

Bases: sasmodels.weights.Dispersion

Boltzmann dispersion, with \(\sigma=k T/E\).

\[w = \exp\left( -|x - c|/\sigma\right)\]
default = {'width': 0, 'nsigmas': 3, 'npts': 35}
type = 'boltzmann'
class sasmodels.weights.Dispersion(npts=None, width=None, nsigmas=None)[source]

Bases: object

Base dispersion object.

Subclasses should define _weights(center, sigma, lb, ub) which returns the x points and their corresponding weights.

default = {'width': 0, 'nsigmas': 3, 'npts': 35}

Return the parameters to the disperser as a dictionary.

get_weights(center, lb, ub, relative)[source]

Return the weights for the distribution.

center is the center of the distribution

lb, ub are the min and max allowed values

relative is True if the distribution width is proportional to the center value instead of absolute. For polydispersity use relative. For orientation parameters use absolute.

set_weights(values, weights)[source]

Set the weights on the disperser if it is ArrayDispersion.

type = 'base disperser'
class sasmodels.weights.GaussianDispersion(npts=None, width=None, nsigmas=None)[source]

Bases: sasmodels.weights.Dispersion

Gaussian dispersion, with 1-\(\sigma\) width.

\[w = \exp\left(-\tfrac12 (x - c)^2/\sigma^2\right)\]
default = {'width': 0, 'nsigmas': 3, 'npts': 35}
type = 'gaussian'
class sasmodels.weights.LogNormalDispersion(npts=None, width=None, nsigmas=None)[source]

Bases: sasmodels.weights.Dispersion

log Gaussian dispersion, with 1-\(\sigma\) width.

\[w = \frac{\exp\left(-\tfrac12 (\ln x - c)^2/\sigma^2\right)}{x\sigma}\]
default = {'width': 0, 'nsigmas': 8, 'npts': 80}
type = 'lognormal'
class sasmodels.weights.RectangleDispersion(npts=None, width=None, nsigmas=None)[source]

Bases: sasmodels.weights.Dispersion

Uniform dispersion, with width \(\sqrt{3}\sigma\).

\[w = 1\]
default = {'width': 0, 'nsigmas': 1.73205, 'npts': 35}
type = 'rectangle'
class sasmodels.weights.SchulzDispersion(npts=None, width=None, nsigmas=None)[source]

Bases: sasmodels.weights.Dispersion

Schultz dispersion, with 1-\(\sigma\) width.

\[w = \frac{z^z\,R^{z-1}}{e^{Rz}\,c \Gamma(z)}\]

where \(c\) is the center of the distribution, \(R = x/c\) and \(z=(c/\sigma)^2\).

This is evaluated using logarithms as

\[w = \exp\left(z \ln z + (z-1)\ln R - Rz - \ln c - \ln \Gamma(z) \right)\]
default = {'width': 0, 'nsigmas': 8, 'npts': 80}
type = 'schulz'
class sasmodels.weights.UniformDispersion(npts=None, width=None, nsigmas=None)[source]

Bases: sasmodels.weights.Dispersion

Uniform dispersion, with width \(\sigma\).

\[w = 1\]
default = {'width': 0, 'nsigmas': None, 'npts': 35}
type = 'uniform'
sasmodels.weights.get_weights(disperser, n, width, nsigmas, value, limits, relative)[source]

Return the set of values and weights for a polydisperse parameter.

disperser is the name of the disperser.

n is the number of points in the weight vector.

width is the width of the disperser distribution.

nsigmas is the number of sigmas to span for the dispersion convolution.

value is the value of the parameter in the model.

limits is [lb, ub], the lower and upper bound on the possible values.

relative is true if width is defined in proportion to the value of the parameter, and false if it is an absolute width.

Returns (value, weight), where value and weight are vectors.

sasmodels.weights.plot_weights(model_info, mesh)[source]

Plot the weights returned by get_weights().

model_info defines model parameters, etc.

mesh is a list of tuples containing (value, dispersity, weights) for each parameter, where (dispersity, weights) pairs are the distributions to be plotted.

Module contents


sasmodels is a package containing models for small angle neutron and xray scattering. Models supported are the one dimensional circular average and two dimensional oriented patterns. As well as the form factor calculations for the individual shapes sasmodels also provides automatic shape polydispersity, angular dispersion and resolution convolution. SESANS patterns can be computed for any model.

Models can be written in python or in C. C models can run on the GPU if OpenCL drivers are available. See generate for details on defining new models.


Return the data files to be installed with the package.

The format is a list of (directory, [files...]) pairs which can be used directly in setup(...,data_files=...) for