Previous: The Model Base Class, Up: Implementing Models [Contents]
The only thing the Model
class does not do for you is
calculating the observables for given values of the
parameters. Derived classes must implement this by overloading the
virtual method
virtual int calc()
This method should use the current values of the parameters, as
returned by Model::parameter(int i)
, compute the
observables and assign them to the elements of the protected member
ObservableVector observables_
The type ObservableVector
is a synonym for
boost::numeric::ublas::vector<double>
and documented in the
Boost uBLAS library. For most purposes,
you only need to know that the elements of observables_
can be
accessed like those of a normal C array or std::vector<double>
,
i.e. with observables_[i]
. The calc()
method
should return zero when the computation was successful and a non-zero
value otherwise. To avoid computing the observables repeatedly with
the same parameter values, the Model
class has a protected
boolean member
bool needs_update_
which is set to true
whenever a parameter value is changed. You
can check the value of needs_update_
at the start of your
calc()
implementation and you should set it to
false
after a successful computation of the observables. The
default implementation of Model::calc()
only sets
needs_update_
to false
and returns zero.
When you write your own Model
classes, you should observe few
guidelines which will make your life easier in the long run. A
typical declaration of a model class will look like this:
#include <myfitter/model.hpp> using namespace myfitter; class MyModel : public Model { private: ... protected: MyModel(int npar, int nobs) : Model(npar, nobs) { ... } ... public: // parameters enum {P_FIRSTPAR, P_SECONDPAR, ... , P_LASTPAR}; static const int NPAR = P_LASTPAR+1; // observables enum {O_FIRSTOBS, O_SECONDOBS, ... , O_LASTOBS}; static const int NOBS = P_LASTOBS+1; // constructors MyModel() : Model(NPAR, NOBS) { ... } MyModel(const MyModel& m) : Model(m) { ... } // assignment operator virtual const MyModel& operator=(const MyModel& m) { Model::operator=(m); ... return *this; } ... virtual int calc(); };
First of all, note that parameters and observables are identified in
myFitter by integer numbers starting from zero. Since you probably
don’t want to remember the integer assignments for all parameters and
observables in all your models, you should define enum
types
that give intuitive names to the integers associated with your
parameters and observables. As the assignments are specific to each
model class, you should make the enum
types members of the
corresponding model class. Using prefixes ‘P_’ and ‘O_’ for
the names of parameters and observables, respectively, will avoid name
clashes in cases where a parameter is at the same time an
observable. In addition, each model class should define static integer
constants NPAR
and NOBS
which keep information about the
number of parameters and observables defined in that model.
It is also a good idea to define a default constructor, a copy
constructor and a virtual assignment operator for your model. This
will allow you to save and restore the state of a model object in a
single line. Furthermore, you should re-define the constructor with
the two integer arguments from the Model
class as a protected
constructor. This will allow you to write derived classes of
MyModel
with additional parameters or observables. This is how
the declaration of a derived class could look like:
class MyOtherModel : public MyModel { private: ... protected: MyOtherModel(int npar, int nobs) : MyModel(npar, nobs) { ... } ... public: // parameters enum {P_FIRSTNEWPAR=MyModel::NPAR, ... , P_LASTNEWPAR}; static const int NPAR = P_LASTNEWPAR+1; // observables enum {O_FIRSTNEWOBS=MyModel::NOBS, ... , O_LASTNEWOBS}; static const int NOBS = P_LASTNEWOBS+1; // constructors MyOtherModel() : MyModel(NPAR, NOBS) { ... } MyOtherModel(const MyOtherModel& m) : MyModel(m) { ... } // assignment operator virtual const MyOtherModel& operator=(const MyOtherModel& m) { MyModel::operator=(m); ... return *this; } ... virtual int calc() { int status; if((status = MyModel::calc())) return status; // calculate new observables ... } };
Note that the definitions for NPAR
and NOBS
in
MyOtherModel
shadow the ones in MyModel
.
Previous: The Model Base Class, Up: Implementing Models [Contents]