# 3. Compare models on different compute engines

## `sasmodels.compare`

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 “./sascomp -h” in the sasmodels root to see the command line options. To run from from an installed version of sasmodels, use “python -m sasmodels.compare -h”.

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 SAS_OPENCL environment variable. Start a python interpreter and enter:

    import pyopencl as cl
    cl.create_some_context()

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

class sasmodels.compare.Calculator(*args, **kwargs)

  Bases: `Protocol`

  Kernel calculator takes par=value keyword arguments.

class sasmodels.compare.Explore(opts: Dict[str, Any])

  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.

  model_update() → None

    Respond to signal that model parameters have been changed.

  nllf() → float

    Return cost.

  numpoints() → int

    Return the number of points.

  parameters() → Any

    Return a dictionary of parameters.

  plot(view: str = 'log') → None

    Plot the data and residuals.

  revert_values() → None

    Restore starting values of the parameters.

sasmodels.compare.MATH = {'acos': <built-in function acos>, 'acosh': <built-in function acosh>, 'asin': <built-in function asin>, 'asinh': <built-in function asinh>, 'atan': <built-in function atan>, 'atan2': <built-in function atan2>, 'atanh': <built-in function atanh>, 'cbrt': <built-in function cbrt>, 'ceil': <built-in function ceil>, 'comb': <built-in function comb>, 'copysign': <built-in function copysign>, 'cos': <built-in function cos>, 'cosh': <built-in function cosh>, 'degrees': <built-in function degrees>, 'dist': <built-in function dist>, 'e': 2.718281828459045, 'erf': <built-in function erf>, 'erfc': <built-in function erfc>, 'exp': <built-in function exp>, 'exp2': <built-in function exp2>, 'expm1': <built-in function expm1>, 'fabs': <built-in function fabs>, 'factorial': <built-in function factorial>, 'floor': <built-in function floor>, 'fma': <built-in function fma>, 'fmod': <built-in function fmod>, 'frexp': <built-in function frexp>, 'fsum': <built-in function fsum>, 'gamma': <built-in function gamma>, 'gcd': <built-in function gcd>, 'hypot': <built-in function hypot>, 'inf': inf, 'isclose': <built-in function isclose>, 'isfinite': <built-in function isfinite>, 'isinf': <built-in function isinf>, 'isnan': <built-in function isnan>, 'isqrt': <built-in function isqrt>, 'lcm': <built-in function lcm>, 'ldexp': <built-in function ldexp>, 'lgamma': <built-in function lgamma>, 'log': <built-in function log>, 'log10': <built-in function log10>, 'log1p': <built-in function log1p>, 'log2': <built-in function log2>, 'modf': <built-in function modf>, 'nan': nan, 'nextafter': <built-in function nextafter>, 'perm': <built-in function perm>, 'pi': 3.141592653589793, 'pow': <built-in function pow>, 'prod': <built-in function prod>, 'radians': <built-in function radians>, 'remainder': <built-in function remainder>, 'sin': <built-in function sin>, 'sinh': <built-in function sinh>, 'sqrt': <built-in function sqrt>, 'sumprod': <built-in function sumprod>, 'tan': <built-in function tan>, 'tanh': <built-in function tanh>, 'tau': 6.283185307179586, 'trunc': <built-in function trunc>, 'ulp': <built-in function ulp>}

  list of math functions for use in evaluating parameters

sasmodels.compare.build_math_context() → Dict[str, Callable]

  build dictionary of functions from math module

sasmodels.compare.columnize(items: List[str], indent: str = '', width: int = None) → str

  Format a list of strings into columns.

  Returns a string with carriage returns ready for printing.

sasmodels.compare.compare(opts: Dict[str, Any], limits: Tuple[float, float] | None = None, maxdim: float | None = None) → Tuple[float, float]

  Preform a comparison using options from the command line.

  limits are the display limits on the graph, 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 DEPRECATED Use opts[‘maxdim’] instead.

sasmodels.compare.constrain_pars(model_info: ModelInfo, pars: Mapping[str, float]) → None

  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.

sasmodels.compare.delay(dt)

  Return number date-time delta as number seconds

sasmodels.compare.explore(opts: Dict[str, Any]) → None

  explore the model using the bumps gui.

sasmodels.compare.get_pars(model_info: ModelInfo) → Mapping[str, float]

  Extract default parameters from the model definition.

sasmodels.compare.isnumber(s: str) → bool

  Return True if string contains an int or float

sasmodels.compare.limit_dimensions(model_info: ModelInfo, pars: Mapping[str, float], maxdim: float) → None

  Limit parameters of units of Ang to maxdim.

sasmodels.compare.main(*argv: str) → None

  Main program.

sasmodels.compare.make_data(opts: Dict[str, Any]) → Tuple[Data, np.ndarray]

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

  opts contains the options, with ‘qmax’, ‘nq’, ‘sesans’, ‘res’, ‘accuracy’, ‘is2d’ and ‘view’ parsed from the command line.

sasmodels.compare.make_engine(model_info: ModelInfo, data: Data1D | Data2D | SesansData, dtype: str, cutoff: float, ngauss: int = 0) → Calculator

  Generate the appropriate calculation engine for the given datatype.

  Datatypes with ‘!’ appended are evaluated using external C DLLs rather than OpenCL.

sasmodels.compare.parameter_range(p: str, v: float) → Tuple[float, float]

  Choose a parameter range based on parameter name and initial value.

sasmodels.compare.parlist(model_info: ModelInfo, pars: Mapping[str, float], is2d: bool) → str

  Format the parameter list for printing.

sasmodels.compare.parse_opts(argv: List[str]) → Dict[str, Any]

  Parse command line options.

sasmodels.compare.parse_pars(opts: Dict[str, Any], maxdim: float = None) → Tuple[Dict[str, float], Dict[str, float]]

  Generate parameter sets for base and comparison models.

  Returns a pair of parameter dictionaries.

  The default parameter 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.

  Note: When generating random parameters, the seed must already be set with a call to np.random.seed(opts[‘seed’]).

  opts controls the parameter generation:

      opts = {
          'info': (model_info 1, model_info 2),
          'seed': -1,         # if seed>=0 then randomize parameters
          'mono': False,      # force monodisperse random parameters
          'magnetic': False,  # force nonmagetic random parameters
          'maxdim': np.inf,   # limit particle size to maxdim for random pars
          'values': ['par=expr', ...],  # override parameter values in model
          'show_pars': False, # Show parameter values
          'is2d': False,      # Show values for orientation parameters
      }

  The values of par=expr are evaluated approximately as:

      import numpy as np
      from math import *
      from parameter_set import *

      parameter_set.par = eval(expr)

  That is, you can use arbitrary python math expressions including the functions defined in the math library and the numpy library. You can also use the existing parameter values, which will either be the model defaults or the randomly generated values if seed is non-negative.

  To compare different values of the same parameter, use par=expr,expr. The first parameter set will have the values from the first expression and the second parameter set will have the values from the second expression. Note that the second expression is evaluated using the values from the first expression, which allows things like:

      length=2*radius,length+3

  which will compare length to length+3 when length is set to 2*radius.

  maxdim DEPRECATED Use opts[‘maxdim’] instead.

sasmodels.compare.plot_models(opts: Dict[str, Any], result: Dict[str, Any], limits: Tuple[float, float] | None = None, setnum: int = 0) → Tuple[float, float]

  Plot the results from `run_models()`.

sasmodels.compare.plot_profile(model_info: ModelInfo, label: List[Tuple[float, np.ndarray, np.ndarray]] = 'base', **args: float) → None

  Plot the profile returned by the model profile method.

  model_info defines model parameters, etc.

  label is the legend label for the plotted line.

  args are parameter=value pairs for the model profile function.

sasmodels.compare.print_models(kind=None)

  Print the list of available models in columns.

class sasmodels.compare.push_seed(seed: int | None = None)

  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.

  Parameters:

  seed int or array_like, optional

    Seed for RandomState

  Example:

  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
      [242082    899 211136]
      899

  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
      [242082    899 211136]
      Exception raised
      899

sasmodels.compare.randomize_pars(model_info: ModelInfo, pars: Mapping[str, float], maxdim: float = inf, is2d: bool = False) → Mapping[str, float]

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

sasmodels.compare.run_models(opts: Dict[str, Any], verbose: bool = False) → Dict[str, Any]

  Process a parameter set, return calculation results and times.

sasmodels.compare.set_beam_stop(data: Data, radius: float, outer: float = None) → None

  Add a beam stop of the given radius. If outer, make an annulus.

sasmodels.compare.set_spherical_integration_parameters(opts: Dict[str, Any], steps: int) → None

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

sasmodels.compare.show_docs(opts: Dict[str, Any]) → None

  show html docs for the model

sasmodels.compare.suppress_magnetism(pars: Mapping[str, float]) → Mapping[str, float]

  Complete eliminate magnetism of the model to test models more quickly.

sasmodels.compare.suppress_pd(pars: Mapping[str, float]) → Mapping[str, float]

  Complete eliminate polydispersity of the model to test models more quickly.

sasmodels.compare.tic() → Callable[[], float]

  Timer function.

  Use “toc=tic()” to start the clock and “toc()” to measure a time interval.

sasmodels.compare.time_calculation(calculator: Calculator, pars: Mapping[str, float], evals: int = 1)

  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.