C-PLOT

Scientific Graphics and Data Analysis

12.21.11. - Optimizing



In version 4 of the C-PLOT package, there is a second variation on the fitting algorithm. This second variation is only relevant when you do not provide analytic derivatives for all the fitted parameters. For certain fitting functions you may be able to make your calculations more efficient with this new variation (at the expense of much more memory usage). Both variations produce the same fit results.

The differences relate to the order in which the model() function is called. While doing the fit iterations in the original method, for each data point in turn, the model() equation is called once with the current parameter set and then an extra time for each parameter that did not have analytic derivatives provided.

The new method always calls model() for all the data points each time there is a change of parameter values. During a fit iteration, model() will be called for each data point in turn with the current parameter set. Then, for each fitted parameter that does not have analytic derivatives provided, model() will be called for each data point in turn with the varied value of the fitted parameter. For users who need to do lengthy calculations that change for each parameter set but are the same for each data point, this new method makes it possible to speed the fitting process.

The only drawback to the new method is that it allocates additional memory equal to MAXPTS * MAXPAR * sizeof(double).

The default behavior is to use the old calling sequence. To use the new calling sequence, add the line:
#define VECTORIZE 1
to your prototype before p_fitsize.h is included.

In order to take advantage of the new variation, you need to know at what point in the fitting algorithm the model() function is being called. That information can determined from the arguments to model().

The model() function is called with four integer arguments:
model(deriv_flag, m_mode, par_num, point_num)
The argument deriv_flag has already been described. It is set if model() must calculate the analytic derivatives during this call.

The argument m_mode is set to one of the constants defined in p_fitsize.h to indicate from where in the code model() is being called. These constants are:
                          /* Called from ... */
#define FIT_VALUE       2 /* ... "fi" during fitting */
#define FIT_PARTIAL     3 /* ... "fi" to calculate partial */
#define FIT_SUMSQ       4 /* ... "fc" or "ch" */
#define CALC_DATA       5 /* ... "sa" */
#define MAKE_RESIDUALS  6 /* ... "mr" */
#define MAKE_DATA       7 /* ... "md" */
The argument par_num is normally -1. When model() is called with m_mode equal to FIT_PARTIAL, the parameter described by fpar[par_num] has been incremented (for calculating the partial derivative) from its value when model() was last called with mode equal to FIT_VALUE.

The argument point_num is the index into the f_data array. If the fit range does not include all the data, point_num will not necessarily have a value of zero at any time. Use code similar to the following to check for the first point:
model(deriv_flag, m_mode, par_num, point_num) {
        static  int     prev_point = 32000;  /* a large number */
        int     first;

        if (point_num < prev_point)
                first = 1;      /* first in loop */
        else
                first = 0;      /* not so */
        prev_point = point_num;
        ...
}
Note that if you can't provide analytic derivatives, you could still improve the performance of the computations by calculating the partial derivatives yourself. When deriv_flag is set, find the value of the fitting function at
y0 = f(a[j] = v)
and at
y1 = f(a[j] = v + del)
and set the parameter's derivative to (y1 - y0) / del. By calculating the derivatives for all the parameters within model(), you can avoid redundant computations and speed up the fitting substantially.