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:
ProtocolKernel calculator takes par=value keyword arguments.
- __abstractmethods__ = frozenset({})¶
- __call__(**par: float) ndarray¶
Call self as a function.
- __class__¶
alias of
_ProtocolMeta
- classmethod __class_getitem__(params)¶
Parameterizes a generic class.
At least, parameterizing a generic class is the main thing this method does. For example, for some generic class Foo, this is called when we do Foo[int] - there, with cls=Foo and params=int.
However, note that this method is also called when defining generic classes in the first place with class Foo(Generic[T]): ….
- __delattr__(name, /)¶
Implement delattr(self, name).
- __dict__ = mappingproxy({'__module__': 'sasmodels.compare', '__doc__': 'Kernel calculator takes *par=value* keyword arguments.', '__call__': <function Calculator.__call__>, '__dict__': <attribute '__dict__' of 'Calculator' objects>, '__weakref__': <attribute '__weakref__' of 'Calculator' objects>, '__parameters__': (), '_is_protocol': True, '__subclasshook__': <function Protocol.__init_subclass__.<locals>._proto_hook>, '__init__': <function _no_init_or_replace_init>, '__abstractmethods__': frozenset(), '_abc_impl': <_abc._abc_data object>, '__annotations__': {}})¶
- __dir__()¶
Default dir() implementation.
- __doc__ = 'Kernel calculator takes *par=value* keyword arguments.'¶
- __eq__(value, /)¶
Return self==value.
- __format__(format_spec, /)¶
Default object formatter.
- __ge__(value, /)¶
Return self>=value.
- __getattribute__(name, /)¶
Return getattr(self, name).
- __getstate__()¶
Helper for pickle.
- __gt__(value, /)¶
Return self>value.
- __hash__()¶
Return hash(self).
- __init__(*args, **kwargs)¶
- classmethod __init_subclass__(*args, **kwargs)¶
This method is called when a class is subclassed.
The default implementation does nothing. It may be overridden to extend subclasses.
- __le__(value, /)¶
Return self<=value.
- __lt__(value, /)¶
Return self<value.
- __module__ = 'sasmodels.compare'¶
- __ne__(value, /)¶
Return self!=value.
- classmethod __new__(*args, **kwargs)¶
- __parameters__ = ()¶
- __reduce__()¶
Helper for pickle.
- __reduce_ex__(protocol, /)¶
Helper for pickle.
- __repr__()¶
Return repr(self).
- __setattr__(name, value, /)¶
Implement setattr(self, name, value).
- __sizeof__()¶
Size of object in memory, in bytes.
- __slots__ = ()¶
- __str__()¶
Return str(self).
- __subclasshook__()¶
Abstract classes can override this to customize issubclass().
This is invoked early on by abc.ABCMeta.__subclasscheck__(). It should return True, False or NotImplemented. If it returns NotImplemented, the normal algorithm is used. Otherwise, it overrides the normal algorithm (and the outcome is cached).
- __weakref__¶
list of weak references to the object
- _abc_impl = <_abc._abc_data object>¶
- _is_protocol = True¶
- _is_runtime_protocol = False¶
- class sasmodels.compare.Explore(opts: Dict[str, Any])¶
Bases:
objectBumps 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.
- __class__¶
alias of
type
- __delattr__(name, /)¶
Implement delattr(self, name).
- __dict__ = mappingproxy({'__module__': 'sasmodels.compare', '__doc__': '\n Bumps wrapper for a SAS model comparison.\n\n The resulting object can be used as a Bumps fit problem so that\n parameters can be adjusted in the GUI, with plots updated on the fly.\n ', '__init__': <function Explore.__init__>, 'revert_values': <function Explore.revert_values>, 'model_update': <function Explore.model_update>, 'numpoints': <function Explore.numpoints>, 'parameters': <function Explore.parameters>, 'nllf': <function Explore.nllf>, 'plot': <function Explore.plot>, '__dict__': <attribute '__dict__' of 'Explore' objects>, '__weakref__': <attribute '__weakref__' of 'Explore' objects>, '__annotations__': {}})¶
- __dir__()¶
Default dir() implementation.
- __doc__ = '\n Bumps wrapper for a SAS model comparison.\n\n The resulting object can be used as a Bumps fit problem so that\n parameters can be adjusted in the GUI, with plots updated on the fly.\n '¶
- __eq__(value, /)¶
Return self==value.
- __format__(format_spec, /)¶
Default object formatter.
- __ge__(value, /)¶
Return self>=value.
- __getattribute__(name, /)¶
Return getattr(self, name).
- __getstate__()¶
Helper for pickle.
- __gt__(value, /)¶
Return self>value.
- __hash__()¶
Return hash(self).
- classmethod __init_subclass__()¶
This method is called when a class is subclassed.
The default implementation does nothing. It may be overridden to extend subclasses.
- __le__(value, /)¶
Return self<=value.
- __lt__(value, /)¶
Return self<value.
- __module__ = 'sasmodels.compare'¶
- __ne__(value, /)¶
Return self!=value.
- classmethod __new__(*args, **kwargs)¶
- __reduce__()¶
Helper for pickle.
- __reduce_ex__(protocol, /)¶
Helper for pickle.
- __repr__()¶
Return repr(self).
- __setattr__(name, value, /)¶
Implement setattr(self, name, value).
- __sizeof__()¶
Size of object in memory, in bytes.
- __str__()¶
Return str(self).
- classmethod __subclasshook__()¶
Abstract classes can override this to customize issubclass().
This is invoked early on by abc.ABCMeta.__subclasscheck__(). It should return True, False or NotImplemented. If it returns NotImplemented, the normal algorithm is used. Otherwise, it overrides the normal algorithm (and the outcome is cached).
- __weakref__¶
list of weak references to the object
- model_update() None¶
Respond to signal that model parameters have been changed.
- nllf() float¶
Return cost.
- numpoints() int¶
Return the number of points.
- 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>, '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>, '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._format_par(name: str, value: float = 0.0, pd: float = 0.0, n: int = 0, nsigma: float = 3.0, pdtype: str = 'gaussian', relative_pd: bool = False, M0: float = 0.0, mphi: float = 0.0, mtheta: float = 0.0) str¶
- sasmodels.compare._print_stats(label: str, err: np.ma.ndarray) None¶
- sasmodels.compare._random_pd(model_info: ModelInfo, pars: Dict[str, float], is2d: bool) None¶
Generate a random dispersity distribution for the model.
1% no shape dispersity 85% single shape parameter 13% two shape parameters 1% three shape parameters
If oriented, then put dispersity in theta, add phi and psi dispersity with 10% probability for each.
- sasmodels.compare._randomize_one(model_info: ModelInfo, name: str, value: float) float¶
Randomize a single parameter.
- sasmodels.compare._show_invalid(data: Data, theory: np.ma.ndarray) None¶
Display a list of the non-finite values in theory.
- sasmodels.compare._swap_pars(pars: ModelInfo, a: str, b: str) None¶
Swap polydispersity and magnetism when swapping parameters.
Assume the parameters are of the same basic type (volume, sld, or other), so that if, for example, radius_pd is in pars but radius_bell_pd is not, then after the swap radius_bell_pd will be the old radius_pd and radius_pd will be removed.
- 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.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_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:
objectSet 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:
- seedint 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
- __class__¶
alias of
type
- __delattr__(name, /)¶
Implement delattr(self, name).
- __dict__ = mappingproxy({'__module__': 'sasmodels.compare', '__doc__': '\n Set the seed value for the random number generator.\n\n When used in a with statement, the random number generator state is\n restored after the with statement is complete.\n\n :Parameters:\n\n *seed* : int or array_like, optional\n Seed for RandomState\n\n :Example:\n\n Seed can be used directly to set the seed::\n\n >>> from numpy.random import randint\n >>> push_seed(24)\n <...push_seed object at...>\n >>> print(randint(0,1000000,3))\n [242082 899 211136]\n\n Seed can also be used in a with statement, which sets the random\n number generator state for the enclosed computations and restores\n it to the previous state on completion::\n\n >>> with push_seed(24):\n ... print(randint(0,1000000,3))\n [242082 899 211136]\n\n Using nested contexts, we can demonstrate that state is indeed\n restored after the block completes::\n\n >>> with push_seed(24):\n ... print(randint(0,1000000))\n ... with push_seed(24):\n ... print(randint(0,1000000,3))\n ... print(randint(0,1000000))\n 242082\n [242082 899 211136]\n 899\n\n The restore step is protected against exceptions in the block::\n\n >>> with push_seed(24):\n ... print(randint(0,1000000))\n ... try:\n ... with push_seed(24):\n ... print(randint(0,1000000,3))\n ... raise Exception()\n ... except Exception:\n ... print("Exception raised")\n ... print(randint(0,1000000))\n 242082\n [242082 899 211136]\n Exception raised\n 899\n ', '__init__': <function push_seed.__init__>, '__enter__': <function push_seed.__enter__>, '__exit__': <function push_seed.__exit__>, '__dict__': <attribute '__dict__' of 'push_seed' objects>, '__weakref__': <attribute '__weakref__' of 'push_seed' objects>, '__annotations__': {}})¶
- __dir__()¶
Default dir() implementation.
- __doc__ = '\n Set the seed value for the random number generator.\n\n When used in a with statement, the random number generator state is\n restored after the with statement is complete.\n\n :Parameters:\n\n *seed* : int or array_like, optional\n Seed for RandomState\n\n :Example:\n\n Seed can be used directly to set the seed::\n\n >>> from numpy.random import randint\n >>> push_seed(24)\n <...push_seed object at...>\n >>> print(randint(0,1000000,3))\n [242082 899 211136]\n\n Seed can also be used in a with statement, which sets the random\n number generator state for the enclosed computations and restores\n it to the previous state on completion::\n\n >>> with push_seed(24):\n ... print(randint(0,1000000,3))\n [242082 899 211136]\n\n Using nested contexts, we can demonstrate that state is indeed\n restored after the block completes::\n\n >>> with push_seed(24):\n ... print(randint(0,1000000))\n ... with push_seed(24):\n ... print(randint(0,1000000,3))\n ... print(randint(0,1000000))\n 242082\n [242082 899 211136]\n 899\n\n The restore step is protected against exceptions in the block::\n\n >>> with push_seed(24):\n ... print(randint(0,1000000))\n ... try:\n ... with push_seed(24):\n ... print(randint(0,1000000,3))\n ... raise Exception()\n ... except Exception:\n ... print("Exception raised")\n ... print(randint(0,1000000))\n 242082\n [242082 899 211136]\n Exception raised\n 899\n '¶
- __enter__() None¶
- __eq__(value, /)¶
Return self==value.
- __format__(format_spec, /)¶
Default object formatter.
- __ge__(value, /)¶
Return self>=value.
- __getattribute__(name, /)¶
Return getattr(self, name).
- __getstate__()¶
Helper for pickle.
- __gt__(value, /)¶
Return self>value.
- __hash__()¶
Return hash(self).
- __init__(seed: int | None = None) None¶
- classmethod __init_subclass__()¶
This method is called when a class is subclassed.
The default implementation does nothing. It may be overridden to extend subclasses.
- __le__(value, /)¶
Return self<=value.
- __lt__(value, /)¶
Return self<value.
- __module__ = 'sasmodels.compare'¶
- __ne__(value, /)¶
Return self!=value.
- classmethod __new__(*args, **kwargs)¶
- __reduce__()¶
Helper for pickle.
- __reduce_ex__(protocol, /)¶
Helper for pickle.
- __repr__()¶
Return repr(self).
- __setattr__(name, value, /)¶
Implement setattr(self, name, value).
- __sizeof__()¶
Size of object in memory, in bytes.
- __str__()¶
Return str(self).
- classmethod __subclasshook__()¶
Abstract classes can override this to customize issubclass().
This is invoked early on by abc.ABCMeta.__subclasscheck__(). It should return True, False or NotImplemented. If it returns NotImplemented, the normal algorithm is used. Otherwise, it overrides the normal algorithm (and the outcome is cached).
- __weakref__¶
list of weak references to the object
- 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.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.