Next: Writing your own Model Class, Up: Implementing Models [Contents]
Model
Base ClassThe Model
class provides the following functionality:
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.
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.
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>
.
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)
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)
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)
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.
smallrange
FlagsYou 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.
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()
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: Writing your own Model Class, Up: Implementing Models [Contents]