- 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. Derived classes should implement a
default constructor which calls Model(int, int)
to initialise
themselves.
- 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)
The scale of a parameter should be your best guess for the size of
fluctuations in that parameter, which are allowed when the model is
fitted to data. You can also 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.1446] 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^2. 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 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()