Next: , Up: Implementing Models   [Contents]


2.1 The Model Base Class

The Model class provides the following functionality:

Constructors

The Model provides a copy constructor and an assignment operator, but no default constructor. The default constructors of derived classes should call the constructor

Model(int npar, int nobs)

which initialises a model with npar parameters and nobs observables. The values of the parameters and observables as well as their scales and upper and lower limits (see below) are initialised to NaN. This way, if you forget to initialise a parameter correctly, you will probably notice it.

Parameters

An object of type Model stores the “current” values of the parameters of the model. The number of parameters is fixed in the constructor and returned by the function nparameters(). Parameter values can be read out and set with the methods

double parameter(int ipar)
const ParameterVector& parameters()
void parameter(int ipar, double value)

where the parameter index ipar runs from zero to nparameters()-1. The type ParameterVector is a synonym for boost::numeric::ublas::vector<double>. You can find more information about uBLAS vectors in the documentation of the Boost uBLAS library.

Observables

A Model object stores the “current” values of the observables. The number of observables is fixed in the constructor and returned by the function nobservables(). The values of the observables can be accessed with the methods

double observable(int iobs)
const ObservableVector& observables()

where the index iobs runs from zero to nobservables()-1. The type ObservableVector is another synonym for boost::numeric::ublas::vector<double>.

Scales of Parameters

You can read and set the scale of each parameter with

double scale(int ipar)
void scale(int ipar, double value)

For all internal computations, parameters are normalised to their scale. In particular, the chi-square function is not minimized with respect to the parameters p_i set by the user via Model::parameter, but with respect to p_i/s_i, where s_i are the scales of the parameters. Ideally, the scales of the parameters should be chosen so that the second derivative of the chi-square function with respect to p_i at the minimum is of the same order as s_i. In other words, they should be your best guess for the errors of the parameters when fitting the model to data. You can set the value and scale of a parameter in one go with

void parameter(int ipar, double value, double scale)
Bounded Parameters

You can set the ranges in which parameters are allowed to float with

void upper_limit(int ipar, double value)
void lower_limit(int ipar, double value)
void set_range(int ipar, double upper_lim, double lower_lim)

and obtain the current upper and lower limit of a parameter with

double upper_limit(int ipar)
double lower_limit(int ipar)

Initially, all parameters are unbounded. In this case, the two functions above return NaN. Conversely, you can remove an upper or lower limit on a parameter by setting the limit to NaN. To do this, you should use the static method

static double Model::nan()

which just returns NaN. To check if a certain parameter currently has an upper or lower limit you can use the methods

bool has_upper_limit(int ipar)
bool has_lower_limit(int ipar)

You can set the value, scale, lower and upper limit of a parameter in one go with

void parameter(int ipar, double value, double scale,
               double lower_limit, double lower_limit)
Fixing Parameters

You can fix a parameter to its current value or release it with the methods

void fix(int ipar)
void release(int ipar)

A fixed parameter does not float in a fit. To check if a parameter is currently fixed, use the method

bool fixed(int ipar)
Calculating Derivatives

The derivatives at the current point in parameter space can be calculated with

virtual int calc_deriv()

which returns zero if the calculation was successful and a non-zero value otherwise. The derivative matrix can be accessed with the method

const Matrix& derivatives()

The type Matrix is a synonym for boost::numeric::ublas::matrix<double>. You can find more information about uBLAS matrices in the documentation of the Boost uBLAS library. To access the elements of a Matrix object, just call the object with two integer arguments. For the matrix returned by derivatives(), the first index is a parameter index and the second an observable index.

The derivatives are calculated numerically by varying the parameters by small amounts proportional to their scale (as returned by scale(ipar)). The proportionality factor can be read and modified with the methods

double derivative_epsilon()
void derivative_epsilon(double value)

Derived classes may overload the calc_deriv() method, for example to implement analytical formulae for the derivatives with respect to some parameters. Your own implementation should assign the values of the derivatives to the protected member derivatives_, which is of type Matrix. If you do not want to implement all derivatives yourself the derivatives with respect to a certain parameter ipar can be be calculated numerically with the protected method

int numerical_derivative_(int ipar)

This method fills the corresponding row of derivatives_ and returns zero on success and a non-zero value on failure. Finally, you can check your own implementation of derivatives with the method

bool check_derivatives(double rel_prec, double abs_prec)

This method checks if your results for the derivatives agree with the numerical derivatives with a relative precision rel_prec. Any derivatives which are smaller than abs_prec in magnitude are regarded as exactly zero.

The smallrange Flags

You can read and set the smallrange flag for each parameter with the methods

bool smallrange(int ipar)
void smallrange(int ipar, bool value)

When the smallrange flag is set, the parameter is considered fixed for the purpose of determining the model’s hyperplane before a p-value integration (see [arXiv:1207.1446v2] for details), but floats in any fits performed during the p-value integration. The right combination of smallrange flags can significantly increase the efficiency of p-value integrations. The flag should be set if a parameter is only allowed to vary in a small range or if the dependence of all observables on that parameter is very weak.

Sampling the Parameter Space

You can randomly sample the parameter space and build up a dictionary of parameter values and the corresponding observable values. This dictionary can then be used by the fit functions to find good starting points for minimising the chi-square. The ranges in which the parameters are scanned can be read with the methods

double scan_min(int ipar)
double scan_max(int ipar)

and set with

void scan_min(int ipar, double value)
void scan_max(int ipar, double value)
void scan_range(int ipar, double min_val, double max_val)

If you are lazy you can also set the scan ranges of all parameters at once with

void set_scan_ranges(double factor)

which sets the scan range of each parameter i to the interval from parameter(i)-factor*scale(i) to parameter(i)+factor*scale(i). To sample the parameter space with n points, call

void scan(int n)

If you want more sample points in a specific part of the parameter space you can change the scan ranges and call scan() again. The old data will be kept. To clear the dictionary, call

void clear()
Chi-square values and constraint penalty

Each Model object stores a chi-square value which can be accessed with the methods

double chisquare()
void chisquare(double chisq)

When you fit your model to some data using the Fitter::global_fit or Fitter::local_fit methods (see Minimising the chi-square Function) they will set the chisquare member of your Model object to the minimum chi-square value found in the fit. Usually you should not have to modify the chisquare member yourself.

Non-linear constraints on your model’s parameter space are handled in myFitter by adding penalty terms to the chi-square function which become large when the constraints are violated (see Non-linear Constraints). After calling Fitter::global_fit or Fitter::local_fit the contribution of these penalty terms is stored in the constraint_penalty member of the Model class:

double constraint_penalty()
void constraint_penalty(double p)

As with the chisquare member, you will usually not have to modify the constraint_penalty member yourself. The value stored in the chisquare member never includes the contribution from the penalty terms.


Next: , Up: Implementing Models   [Contents]