The sherpa.models.model module
Allow models to be defined and combined.
A single model is defined by the parameters of the model - stored
as sherpa.models.parameter.Parameter
instances - and the function that
takes the parameter values along with an array of grid values. The
main classes are:
Model
which is the base class and defines most of the interfaces.ArithmeticConstantModel
andArithmeticFunctionModel
for representing a constant value or a function.ArithmeticModel
is the main base class for deriving user models since it supports combining models (e.g. by addition or multiplication) and a cache to reduce evaluation time at the expense of memory use.RegriddableModel
builds on ArithmeticModel to allow a model to be evaluated on a different grid to that requested: most model classes are derived from the 1D (RegriddableModel1D
) and 2D (RegriddableModel2D
) variants of RegriddableModel.CompositeModel
which is used to represent a model expression, that is combined models, such asm1 * (m2 + m3)
UnaryOpModel
for model expressions such as-m1
.BinaryOpModel
for model expressions such asm1 + m2
.NestedModel
for applying one model to another.
SimulFitModel
for fitting multiple models and datasets.
Creating a model
Models can be created with an optional name, which is useful for identifying a component in an expression:
>>> from sherpa.models.basic import Gauss1D
>>> m1 = Gauss1D()
>>> m2 = Gauss1D('gmdl')
>>> print(m1)
gauss1d
Param Type Value Min Max Units
----- ---- ----- --- --- -----
gauss1d.fwhm thawed 10 1.17549e-38 3.40282e+38
gauss1d.pos thawed 0 -3.40282e+38 3.40282e+38
gauss1d.ampl thawed 1 -3.40282e+38 3.40282e+38
>>> print(m2)
gmdl
Param Type Value Min Max Units
----- ---- ----- --- --- -----
gmdl.fwhm thawed 10 1.17549e-38 3.40282e+38
gmdl.pos thawed 0 -3.40282e+38 3.40282e+38
gmdl.ampl thawed 1 -3.40282e+38 3.40282e+38
Changing parameters
The parameters are the model values that control the output of the model. A particular model has a fixed set of parameters that can be inspected with print or the pars attribute:
>>> print(m2)
gmdl
Param Type Value Min Max Units
----- ---- ----- --- --- -----
gmdl.fwhm thawed 10 1.17549e-38 3.40282e+38
gmdl.pos thawed 0 -3.40282e+38 3.40282e+38
gmdl.ampl thawed 1 -3.40282e+38 3.40282e+38
>>> print(m2.pars)
(<Parameter 'fwhm' of model 'gmdl'>, <Parameter 'pos' of model 'gmdl'>, <Parameter 'ampl' of model 'gmdl'>)
The parameters are instances of the sherpa.models.parameter.Parameter
class:
>>> print(m2.fwhm)
val = 10.0
min = 1.1754943508222875e-38
max = 3.4028234663852886e+38
units =
frozen = False
link = None
default_val = 10.0
default_min = 1.1754943508222875e-38
default_max = 3.4028234663852886e+38
>>> print(m2.fwhm.val)
10.0
Setting the model parameter does not require going through the val attribute as you can say:
>>> m2.fwhm = 20
Accessing parameter values
The model class is set up so that any attribute access is case
insensitive, so the following are all ways to change the fwhm
parameter:
>>> m2.fwhm = 10
>>> m2.FWHM = 10
>>> m2.FwHm = 10
Linking parameters
One parameter can be made to reference one or more other parameters, a process called “linking”. The linked parameter is no-longer considered a free parameter in a fit since its value is derived from the other parameters. This link can be a simple one-to-one case, such as ensuring the fwhm parameter of one model is the same as the other:
>>> m2.fwhm = m1.fwhm
It can be more complex, such as ensuring the position of one line is a fixed distance from another:
>>> m2.pos = m1.pos + 23.4
It can even include multiple parameters:
>>> m3 = Gauss1D("m3")
>>> m3.ampl = (m1.ampl + m2.ampl) / 2
Requesting the parameter value will return the evaluated expression, and the expression is stored in the link attribute:
>>> m1.ampl = 10
>>> m2.ampl = 12
>>> print(m3.ampl.val)
11.0
>>> m3.ampl.link
<BinaryOpParameter '(gauss1d.ampl + gmdl.ampl) / 2'>
The string representation of the model changes for linked parameters to indicate the expression:
>>> print(m3)
m3
Param Type Value Min Max Units
----- ---- ----- --- --- -----
m3.fwhm thawed 10 1.17549e-38 3.40282e+38
m3.pos thawed 0 -3.40282e+38 3.40282e+38
m3.ampl linked 11 expr: (gauss1d.ampl + gmdl.ampl) / 2
Model evaluation
With a sherpa.data.Data
instance a model can be evaluated with the
eval_model method of the object. For example:
>>> import numpy as np
>>> from sherpa.data import Data1D
>>> from sherpa.models.basic import Gauss1D
>>> x = np.asarray([4000, 4100, 4250, 4300, 4400])
>>> y = np.asarray([10, 20, 50, 40, 30])
>>> d = Data1D('example', x, y)
>>> mdl = Gauss1D()
>>> mdl.pos = 4200
>>> mdl.fwhm = 200
>>> mdl.ampl = 50
>>> ymdl1 = d.eval_model(mdl)
>>> print(ymdl1)
[ 3.125 25. 42.04482076 25. 3.125 ]
The model can also be evaluated directly with the independent axis values:
>>> ymdl2 = mdl(x)
>>> print(ymdl2)
[ 3.125 25. 42.04482076 25. 3.125 ]
Integrated bins
If given the low and high edges of the bins then the model will - if supported - evaluate the integral of the model across the bins:
>>> xlo = np.asarray([4180, 4190, 4195, 4200, 4210])
>>> xhi = np.asarray([4190, 4194, 4200, 4210, 4220])
>>> y = mdl(xlo, xhi)
>>> print(y)
[491.98725233 199.0964993 249.85566938 498.847153 491.98725233]
Note that the bins are expected to be in ascending order and do not overlap, but they do not need to be consecutive.
The behavior of a model when given low and high edges depends on
whether the model is written to support this mode - that is,
integrating the model across the bin - and the setting of the
integrate flag of the model. For example, the
sherpa.models.basic.Gauss1D
model will, by default, integrate the
model across each bin when given the bin edges, but if the flag is set
to False
then just the first array (here xlo
) is used:
>>> print(mdl.integrate)
True
>>> mdl.integrate = False
>>> y2 = mdl(xlo, xhi)
>>> print(y2)
[48.63274737 49.65462477 49.91343163 50. 49.65462477]
>>> y3 = mdl(xlo)
>>> y2 == y3
array([ True, True, True, True, True])
Direct access
The calc method of a model can also be used to evaluate the model, and this requires a list of the parameters and the independent axes:
>>> pars = [200, 4200, 50]
>>> y4 = mdl.calc(pars, x)
>>> y5 = mdl.calc(pars, xlo, xhi)
The parameter order matches the pars attribute of the model:
>>> print([p.fullname for p in mdl.pars])
['gauss1d.fwhm', 'gauss1d.pos', 'gauss1d.ampl']
Model expressions
The CompositeModel
class is the base class for creating model
expressions - that is the overall model that is combined of one or
more model objects along with possible numeric terms, such as a
model containing two gaussians and a polynomial:
>>> from sherpa.models.basic import Gauss1D, Polynom1D
>>> l1 = Gauss1D('l1')
>>> l2 = Gauss1D('l2')
>>> l1.pos = 5
>>> l2.pos = 20
>>> l2.ampl = l1.ampl
>>> c = Polynom1D('c')
>>> mdl = l1 + (0.5 * l2) + c
The resulting model can be evaluated just like an individual component:
>>> x = np.arange(-10, 40, 2)
>>> y = mdl(x)
This model is written so that the amplitude of the l2
component is
half the l1
component by linking the two ampl
parameters and then
including a scaling factor in the model expression for l2
. An
alternative would have been to include this scaling factor in the link
expression:
>>> l2.ampl = l1.ampl / 2
Model cache
The ArithmeticModel
class and modelCacher1d
decorator provide basic
support for caching one-dimensional model evaluations - that is, to
avoid re-calculating the model. The idea is to save the results of the
latest calls to a model and return the values from the cache,
hopefully saving time at the expense of using more memory. This is
most effective when the same model is used with multiple datasets
which all have the same grid.
The _use_caching
attribute of the model is used to determine whether
the cache is used, but this setting can be over-ridden by the startup
method, which is automatically called by the fit and est_errors
methods of a sherpa.fit.Fit
object.
The cache_clear
and cache_status
methods of the ArithmeticModel
and CompositeModel
classes allow you to clear the cache and display
to the standard output the cache status of each model component.
Examples
The following class implements a simple scale model which has a single
parameter (scale
) which defaults to 1. It can be used for both
non-integrated and integrated datasets of any dimensionality (see
sherpa.models.basic.Scale1D
and sherpa.models.basic.Scale2D
):
class ScaleND(ArithmeticModel):
'''A constant value per element.'''
def __init__(self, name='scalend'):
self.scale = Parameter(name, 'scale', 1)
self.integrate = False
pars = (self.scale, )
ArithmeticModel.__init__(self, name, pars)
def calc(self, p, *args, **kwargs):
return p[0] * np.ones_like(args[0])
Classes
|
The base class for Sherpa models. |
|
Represent a constant value, or values. |
|
Represent a callable function. |
|
Support combining model expressions and caching results. |
|
Represent a model with composite parts. |
|
Combine two model expressions. |
|
|
|
|
|
Apply a model to the results of a model. |
|
Support models that can be evaluated on a different grid. |
|
Allow 1D models to be regridded. |
|
Allow 2D models to be regridded. |
|
Store multiple models. |
|
Apply an operator to a model expression. |
Functions
|
A decorator to cache 1D ArithmeticModel evaluations. |