Package park :: Package modelling :: Module model

Module model

source code

Define a park fitting model.

Usage

The simplest sort of fitting model is something like the following:

import numpy
import park
def G(x,mu,sigma):
    return numpy.exp(-0.5*(x-mu)**2/sigma**2)

class Gauss(park.Model):
    parameters = ['center','width','scale']
    def eval(self,x):
        return self.scale * G(x,self.center,self.width)

It has a function which is evaluated at a series of x values and a set of adjustable parameters controlling the shape of f(x).

You can check your module with something like the following:

$ ipython -pylab

from gauss import Gauss

g = Gauss(center=5,width=1,scale=10)
x = asarray([1,2,3,4,5])
y = g(x)
plot(x,y)

This should produce a plot of the Gaussian peak.

You will then want to try your model with some data. Create a file with some dummy data, such as gauss.dat:

# x y
4 2
5 6
6 7
7 3

In order to match the model to data, you need to define a fitness object. This shows the difference between the model and the data, which you can then plot or sum to create a weighted chisq value:

f = park.Fitness(g, 'gauss.dat')
plot(f.data.fit_x, f.residuals())

The data file can have up to four columns, either x,y or x,y,dy or x,dx,y,dy where x,y are the measurement points and values, dx is the instrument resolution in x and dy is the uncertainty in the measurement value y. You can pass any keyword arguments to data.load that are accepted by numpy.loadtxt. For example, you can reorder columns or skip rows. Additionally, you can modify data attributes directly x,y,dx,dy and calc_x. See help on park.Data1D for details.

Once you have your model debugged you can use it in a fit:

g = Gauss(center=[3,5],scale=7.2,width=[1,3])
result = park.fit((g, 'gauss.dat'))
result.plot()

In this example, center and width are allowed to vary but scale is fixed.

Existing models can be readily adapted to Park:

class Gauss(object):
    "Existing model"
    center,width,scale = 0,1,1
    def __init__(self,**kw):
        for k,v in kw.items(): setattr(self,k,v)
    def eval(self,x):
        return self.scale *G(x,self.center,self.width)

class GaussAdaptor(Gauss,Model):
    "PARK adaptor"
    parameters = ['center','width','scale']
    def __init__(self,*args,**kw):
        Model.__init__(self,*args)
        Gauss.__init__(self,**kw)

g = GaussAdaptor(center=[3,5],scale=7.2,width=[1,3])
result = park.fit((g, 'gauss.dat'))
result.plot()

Models can become much more complex than the ones described above, including multilevel models where fitting parameters can be added and removed dynamically.

You can access model parameters directly:

M1 = Gauss('M1',center=[3,5],scale=7.2,width=[1,3])
print M1.center           # Access the value for parameter 'center'
M1.center = 7             # Set the value for parameter 'center'
M1.center = [5,9]         # Set the fit range for parameter 'center'
M1.center = "2*M1.scale"  # Set parameter 'center' to an expression

Note that a strange side-effect of the convenience functions used to access model parameters is that assignment statements do not act like you expect. The following sets the initial value of the parameter to 7 then sets the range to [5,9]:

M1.center = 7             # Set the value for parameter 'center'
M1.center = [5,9]         # Set the fit range for parameter 'center'

If these statements were reversed, the initial value would still be 7 and the range [5,9] but the parameter would be set to 'fixed' rather than 'fitted'. True global optimizers will not care what the initial value is, so from the perspective of the fit this should not change the results. Most optimizers will however use the initial value as part of the search.

Since we may choose to improve this interface in future, programmatic access to models should go through parameter sets:

M1.parameterset['center'].value
M1.parameterset['center'].range
...

Once models are defined they can be used in a variety of contexts, such as simultaneous fitting with constraints between the parameters. With some care in defining the model, computationally intensive fits can be distributed across multiple processors. We provide a simple user interface for interacting with the model parameters and managing fits. This can be extended with model specialized model editors which format the parameters in a sensible way for the model, or allow direct manipulation of the model structure. The underlying fitting engine can also be used directly from your own user interface.

For those situations where the properties are dynamic or programmatically generated the meta class machinery which translates parameters into properties is likely not going to be useful. In this case you can inherit directly from park.model.BaseModel, or simply define the required API by hand.

Classes
  Model
Model definition.