next up previous
Next: Cut classes Up: CLHEP Generic Functions Package Previous: Parameter to Argument Adaptors

How to extend the Generic Functions package with your own function

Creating a function for the Generic Function package or inserting an existing function into the framework has low work overhead. Of course if the function is complicated and hard to write, this the framework does not make it easier! However there are only a small number of steps involved in creating a one- or multi-dimensional function and endowing it with parameters that control its shape. We present this procedure as a checklist:

  1. Derive your function publically as a subclass of AbsFunction.

  2. What is the dimensionality of your function? If the answer is "one", then you don't need to override the method
    
      virtual unsigned int dimensionality() const;
    
    because the base class provides a default implementation which returns the value 1. Otherwise, if your function has two or more dimensions, you will need to override the method.

  3. Which parameters (if any) does your function depend on? For each parameter you need to add a Parameter data member for that parameter, and initialize it with its default value and range in the constructor. Also you will want a way of getting a reference to the parameter-and actually you will want two methods, overloaded on const. The purpose of having both methods is so that you will get back a parameter that you can modify if the function itself is modifiable, and a read-only parameter if the function is readonly. If overloading on const is strange to you, you can read up on it in Meyers; or you can just adapt both of these example lines:
    
      Parameter & parm();
      const Parameter & parm() const;
    
    which shows, for example how to retrieve a parameter called "parm" from a function. This is important and the compiler errors may appear very mysterious if you don't write your parameter accessors this way.

  4. You must provide an implementation of these two functions which are pure abstract in the base class:
    
      virtual double operator() (double) const;   
      virtual double operator() (const Argument &) const;
    
    These operators are what your function "does" so how you go about doing this is your business. But typically, for one dimensional functions the second form of the function just calls the first; while for multidimensional functions the first form generates a run-time error and the second form checks the dimension of the argument before evaluating it.

  5. The composition operator, operator()( const AbsFunction &) is overloaded in the base class and you don't want to hide it in the subclass, so put the line using AbsFunction::operator() in the header file of your derived class.

  6. Copy constructors are required for the proper operation of your function within the framework. You can use the compiler-generated copy of this constructor if you wish; the usual caveats about dynamically allocated memory apply here as with any class. The assignment operator is confusing because it only allows one to assign Gaussians to Gaussians, exponentials to exponentials, et cetera, so this function should be turned off. The way to do this is to a) declare the assignment operator, b) make it private, and c) do not provide an implementation.

  7. You will need to declare and define the method:
    
       virtual SubClass  * clone() const;
    
    where SubClass is your new class. This construction uses the covariant return type mechanism, since the function in the base class returns an AbsFunction *. The purpose of the routine is of course to return a pointer to a newly allocated object. The easiest way of implementing this function is to use the copy constructor that you wrote (if you wrote one, otherwise you can take the default copy constructor that the compiler wrote for you).

  8. Optional If you will be providing an analytic derivative for your new function, then override the method
    	
      Derivative partial (unsigned int) const;
    

    The function Sin provides a good example of how to do this. Should you choose to provide an analytic derivative, you should also then override the method

    
     bool hasAnalyticDerivative() const
    
    so that it returns true. Our preference is to put the implementation right in the header file since it provides useful information (``yes, this class has an analtyic derivative'') for users.


next up previous
Next: Cut classes Up: CLHEP Generic Functions Package Previous: Parameter to Argument Adaptors