| Syntax C/C++ | #include <MFstd.h>
float MF_multiNonlinfit( fVector A, iVector AStatus, unsigned npars,
MF_EXPERIMENT *ListOfExperiments, unsigned nexperiments,
void (*modelfunc)(fMatrix ZModel, ui htZ, ui lenZ, fVector X, fVector Y, unsigned iexperiment),
void (*derivatives)(fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, unsigned iexperiment),
VF_NONLINFITOPTIONS *FitOpts,
MF_NONLINFITWORKSPACE *WorkSpace );
float MF_multiNonlinfitwW( fVector A, fMatrix Covar, iVector AStatus, unsigned npars,
MF_EXPERIMENT *ListOfExperiments, unsigned nexperiments,
void (*modelfunc)(fMatrix ZModel, ui htZ, ui lenZ, fVector X, fVector Y, unsigned iexperiment ),
void (*derivatives)(fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, unsigned iexperiment),
VF_NONLINFITOPTIONS *FitOpts,
MF_NONLINFITWORKSPACE *WorkSpace ); |
| Syntax C/C++ simplified | #include <MFstd.h>
float MF_multiNonlinfit( fVector A, iVector AStatus, unsigned npars,
MF_EXPERIMENT *ListOfExperiments, unsigned nexperiments,
void (*modelfunc)(fMatrix ZModel, ui htZ, ui lenZ, fVector X, fVector Y, unsigned iexperiment),
void (*derivatives)(fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, unsigned iexperiment) );
float MF_multiNonlinfitwW( fVector A, fMatrix Covar, iVector AStatus, unsigned npars,
MF_EXPERIMENT *ListOfExperiments, unsigned nexperiments,
void (*modelfunc)(fMatrix ZModel, ui htZ, ui lenZ, fVector X, fVector Y, unsigned iexperiment ),
void (*derivatives)(fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, unsigned iexperiment) ); |
| Pascal/Delphi | uses MFmnlfit;
function MF_multiNonlinfit( A: fVector; AStatus: iVector; nParameters: UInt;
ListOfExperiments: PMF_EXPERIMENT; nexperiments: UInt;
ModelFunc, Derivatives: Pointer;
FitOpts: PVF_NONLINFITOPTIONS; WorkSpace: PMF_NONLINFITWORKSPACE ): Single;
function MF_multiNonlinfitwW( A: fVector; Covar: fMatrix; AStatus: iVector; nParameters: UInt;
ListOfExperiments: PMF_EXPERIMENT; nexperiments: UInt;
ModelFunc, Derivatives: Pointer;
FitOpts: PVF_NONLINFITOPTIONS; WorkSpace: PMF_NONLINFITWORKSPACE ): Single; |
| Pascal/Delphi simplified | uses MFmnlfit;
function MF_multiNonlinfit( A: fVector; AStatus: iVector; nParameters: UInt;
ListOfExperiments: PMF_EXPERIMENT; nexperiments: UInt;
ModelFunc, Derivatives: Pointer ): Single;
function MF_multiNonlinfitwW( A: fVector; Covar: fMatrix; AStatus: iVector; nParameters: UInt;
ListOfExperiments: PMF_EXPERIMENT; nexperiments: UInt;
ModelFunc, Derivatives: Pointer ): Single; |
|
| Description | The input data, contained in ListOfExperiments, are used to evaluate the parameter array A with npars elements ai of an arbitrary model function z = f(x, y).
Arguments:
| A | vector of size npars; returns the coefficients |
| Covar | matrix of dimensions [npars, npars]; returns the covariances of the coefficients |
| AStatus | vector of size npars; decides which parameters are treated as free or as fixed |
| npars | total number of parameters |
| ListOfExperiments | input data, see chap. 13.4 |
| nexperiments | number of data sets in ListOfExperiments |
| modelfunc | user-defined model function |
| derivatives | user-defined function, calculating the partial derivatives with respect to all parameters |
| FitOpts | pointer to a structure containing options, see chap. 13.3 |
| WorkSpace | pointer to a structure holding internal variables, see chap. 13.3 |
The model function (and, consequently, the vector A as well) may actually contain more parameters than you wish to treat as adjustable. This is why you have to provide an additional vector, AStatus, which contains the necessary information about which parameters are to be held fixed at their input values (AStatus[i] = 0) and which are free (AStatus[i] = 1). All parameters must be initialized in A prior to calling MF_multiNonlinfit. The better your initial guess of the parameters, the faster MF_multiNonlinfit shall converge. The argument npars denotes the total number of parameters in A (not only the free parameters!).
The input data must be combined into sets of the type MF_EXPERIMENT. Let us assume you have two sets of X-Y-Z data, each with the vectors X and Y for the independent variables, the matrix MZ for the z=f(x,y) values and, for MF_multiLinfitwW, the weights of all points in MInvVar. The matrix dimensions are htZ (equal to sizeY) and lenZ (equal to sizeX). Now you have to construct a list of experiments as in the following example:
| | Constructing list of experiments in C/C++ |
MF_EXPERIMENT ExpList[2];
ExpList[0].X = X1; ExpList[0].Y = Y1;
ExpList[0].MZ = MZ1;
ExpList[0].htZ = htZ1; ExpList[0].lenZ = lenZ1;
ExpList[1].X = X1; ExpList[1].Y = Y2;
ExpList[1].MZ = MZ2;
ExpList[1].htZ = htZ2; ExpList[1].lenZ = lenZ2;
/* for the weighted variant, set additionally: */
ExpList[0].MInvVar = MInvVar1;
ExpList[0].WeightOfExperiment = wt1;
ExpList[1].MInvVar = MInvVar2;
ExpList[1].WeightOfExperiment = wt2;
| | Constructing list of experiments in Pascal/Delphi |
var ExpList: array[0..1] of MF_EXPERIMENT;
begin
...
ExpList[0].X := X1; ExpList[0].Y := Y1;
ExpList[0].MZ := MZ1;
ExpList[0].htZ := htZ1; ExpList[0].lenZ := lenZ1;
ExpList[1].X := X2; ExpList[1].Y := Y2;
ExpList[1].MZ := MZ2;
ExpList[1].htZ := htZ2; ExpList[1].lenZ := lenZ2;
/* for the weighted variant, set additionally: */
ExpList[0].MInvVar := MInvVar1;
ExpList[0].WeightOfExperiment := wt1;
ExpList[1].MInvVar := MInvVar2;
ExpList[1].WeightOfExperiment := wt2;
...
end;
| | Both C/C++ and Pascal/Delphi |
You must provide a model function "modelfunc" which, for a given pair of X, Y vectors, must calculate the corresponding "theoretical" z-values. In C/C++, it has to be defined as
| | Model function for C/C++ |
void _cdecl MyFunc( fMatrix Z, ui htZ, ui lenZ, fVector X, fVector Y, unsigned iexperiment )
{
for (ui i=0; i<htZ; i++ )
for (ui j=0; j<lenZ; j++ )
MZ[i][j] = f( X[j], Y[i] );
}
f( X[j], Y[i] ) is any arbitrary function, which may be as complicated as you like and your application needs. The only condition is that it have no singularities, at least within the parameter space specified by upper and lower boundaries (see NONLINFITOPTIONS).
The argument iexperiment with which MyFunc shall be called by MF_multiNonlinfit allows to distinguish between parameters that are common to all experiments and others that belong to individual experiments. For example, each experiment's MZ values might be scaled by an individual constant C. In this case, A has to contain as many scales C as there are experiments. In MyFunc, you would have to code this as something like:
if( iexperiment == 0 ) MZ[i][j] *= A[5]; else MZ[i][j] *= A[6];
In addition to the model function, MF_multiNonlinfit needs the partial derivatives of MZ with respect to all parameters A[ipar], according to your model. If you know them analytically, you should write a function MyDerivs. If you happen to know only some, but not all of the partial derivatives, you may rely on MF_multiNonlinfit_autoDeriv to calculate the unknown derivatives numerically.
| | Partial derivatives coded for C/C++ |
MF_NONLINFITWORKSPACE WorkSpace; /* this should be a global variable, the same as passed to MF_multiNonlinfit */
void _cdecl MyDerivs( fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, unsigned iexperiment )
{
ui i;
switch( ipar )
{
case 0:
for(i=0; i<htZ; i++ )
for( j=0; j<lenZ; j++ )
dZdAi[i][j] = part_derv_MZ_w_resp_to_A0( X[j], Y[i] );
break;
case 1:
for(i=0; i<htZ; i++ )
for( j=0; j<lenZ; j++ )
dZdAi[i][j] = part_derv_MZ_w_resp_to_A1( X[j], Y[i] );
break;
default: /* for all derivatives we don't know: */
MF_multiNonlinfit_autoDeriv( dZdAi, htZ, lenZ, X, Y, ipar, iexperiment, &WorkSpace );
}
}
Again, the argument iexperiment allows you to treat "private" parameters of the individual experiments differently from the shared parameters.
A call to MF_multiNonlinfit will look like:
MF_multiNonlinfit( A, AStatus, npars, ExpList, 2, MyFunc, MyDerivs, &FitOpts, &WorkSpace );
or, with simplified syntax:
MF_multiNonlinfit( A, AStatus, npars, ExpList, 2, MyFunc, MyDerivs );
In case you do not know any of the partial derivatives, do not define MyDerivs, but call MF_multiNonlinfit with derivatives = NULL:
MF_multiNonlinfit( A, AStatus, npars, ExpList, 2, MyFunc, NULL );
| | Model function for Pascal/Delphi |
In Pascal/Delphi, the model function has to be defined as
procedure MyFunc( MZ:fMatrix; htZ, lenZ:UIntSize; X, Y:fVector; iexperiment:UInt );
var i, j:UIntSize;
begin
for i:=0 to htZ-1 do
for j:=0 to lenZ-1 do
MF_Pelement( MZ, htZ, lenZ, i, j )^ :=
f( VF_element( X, j ), VF_element( Y, i ) );
end;
f( Xj, Yi ) is any arbitrary function, which may be as complicated as you like and your application needs. The only condition is that it have no singularities, at least within the parameter space specified by upper and lower boundaries (see NONLINFITOPTIONS).
The argument iexperiment with which MyFunc shall be called by MF_multiNonlinfit allows to distinguish between parameters that are common to all experiments and others that belong to individual experiments. For example, each experiment's MZ values might be scaled by an individual constant C. In this case, A has to contain as many scales C as there are experiments. In MyFunc, you would have to code this as something like:
if iexperiment = 0 then
MF_Pelement(MZ, htZ, lenZ, i, j)^ :=
MF_element(MZ, htZ, lenZ, i, j) * VF_element(A,5)
else MF_Pelement(MZ, htZ, lenZ, i, j)^ :=
MF_element(MZ, htZ, lenZ, i, j) * VF_element(A,6);
In addition to the model function, MF_multiNonlinfit needs the partial derivatives of MZ with respect to all parameters A[ipar], according to your model. If you know them analytically, you should write a function MyDerivs. If you happen to know only some, but not all of the partial derivatives, you may rely on MF_multiNonlinfit_autoDeriv to calculate the unknown derivatives numerically.
| | Partial derivatives coded for Pascal/Delphi |
var WorkSpace: MF_NONLINFITWORKSPACE; (* this should be a global variable, the same as passed to MF_multiNonlinfit *)
procedure MyDerivs( dZdAi:fMatrix; htZ, lenZ:UIntSize; X, Y:fVector; ipar, iexperiment:UInt );
var i, j:UIntSize;
begin
case ipar of
0: begin
for i:=0 to htZ-1 do
for j:=0 to lenZ-1 do
MF_Pelement( dZdAi, htZ, lenZ, i, j )^ := part_derv_MZ_w_resp_to_A0(VF_element( X, j ), VF_element( Y, i ));
end;
1: begin
for i:=0 to htZ-1 do
for j:=0 to lenZ-1 do
MF_Pelement( dZdAi, htZ, lenZ, i, j )^ := part_derv_MZ_w_resp_to_A1(VF_element( X, j ), VF_element( Y, i ));
end;
else (* for all derivatives we don't know: *)
MF_multiNonlinfit_autoDeriv( dZdAi, htZ, lenZ, X, Y, ipar, @WorkSpace );
end;
end;
Again, the argument iexperiment allows you to treat "private" parameters of the individual experiments differently from the shared parameters.
A call to MF_multiNonlinfit will look like:
MF_multiNonlinfit( A, AStatus, npars, @ExpList, 2, @MyFunc, @MyDerivs, @FitOpts, @WorkSpace );
or, in simplified syntax,
MF_multiNonlinfit( A, AStatus, npars, @ExpList, 2, @MyFunc, @MyDerivs );
Note the address-of operator in front of "ExpList", "MyFunc.", and "MyDerivs". In case you do not know any of the partial derivatives, do not define MyDerivs, but call MF_multiNonlinfit with derivatives = nil:
MF_multiNonlinfit( A, AStatus, npars, @ExpList, 2, @MyFunc, nil );
In the weighted variant, MF_multiNonlinfitwW, the matrix ExpList[i].MInvVar of each experiment has to contain the inverse of the variances of the individual X-Y-Z data points, and the matrix MCovar will be filled with the covariances of the parameters ai on output: MCovari,j = covariance( ai, aj ).
| | Both C/C++ and Pascal/Delphi: |
For the many different options controlling nonlinear data-fitting functions, please consult chapter 13.3. Helper functions for breaking off excessively long fitting runs and for the monitoring of these often very time-consuming procedures are summarized in chapter 13.5 and, in the special case of MF_multiNonlinfit, described here.
|
|