# 3.9.2.2.3 Fit on one data two peaks with Gauss function with parameters W and A are shared

## Version Info

Minimum Origin Version Required: Origin 8 SR0

## Examples

// before running this function, import \Samples\Curve Fitting\Multiple Peaks.dat to worksheet.

#include <Origin.h>
#include <FDFTree.h>
#include <ONLSF.h>

void	NLFit_example3()
{
string			strFDF = okutil_get_origin_path(ORIGIN_PATH_SYSTEM, "FitFunc") + "Gauss.FDF";
Tree			trFF;
if( !nlsf_FDF_to_tree( strFDF, &trFF ))
{
out_str("Fail to load FDF function file");
return;
}

//////////////////////////////////////////////////////////////////////////////
// 1. Setting the fitting function and parameter sharing for multipeak fit  //
// The fit object:
NLFit			fit;

// We will fit two peaks using the same fitting function. We call this "one-replica" case.
// This means that in addition to one full set of paramaters for the first peak, there are
// also additional paramaters, but only those within the "replicas unit", for the second peak.
// Only the fitting functions that allow replicas in its .FDF file can be used for multipeak fitting.
// The [CONTROLS] section of the .FDF file must contain the following two entries to enable replicas:
//		Duplicate Offset=2
//		Duplicate Unit=3
// (the actual values may be different for different functions). The value Duplicate Offset is the 1-offset index
// of the first function paramater which belongs to the replicas unit. Duplicate Unit is the size of the replicas
// unit. The following must hold for all such functions:
//		total number of parameters for the function = Duplicate Offset - 1 + Duplicate Unit
// If the above two entries are not present, then the following two entries must be present to allow
// multipeak fitting:
//		Replicas Offset=2
//		Replicas Unit=3
// The meanings are the same as described above. If you create your own fitting function that you wish
// to use for multipeak fitting, you MUST use the latter entries.

//
// The multiplicity of the function is equal to the number of peaks.
int				nFitFunctionMultiplicity = 2;

// We want also to specify parameter sharing between peaks. This is accomplished via the following array:
vector<int>		vnSharingGroups(7);
// The size of this vector for specifying sharing between peaks must be equal to:
// 		replicas Offset - 1 + nFitFunctionMultiplicity * replicas unit
// In the case of the Gauss function with one replica (i.e. with two peaks) this is:
//		2 - 1 + 2 * 3 = 7
// This means that in the vector vnSharingGroups there is one element for each function parameter, including
// replicas, if any: first all the function parameters for the first peak, followed by only the replicated
// parameters (i.e. those in the replicas unit) for the additional peaks.
// The meaning of the array vnSharingGroups: for each function paramater including replicas the value
// says whether the argument is shared or not, and if shared, how it is shared.
//		If the value for a particular argument is 0 or less, the parameter is not shared between replicas.
//		If the value is greater than 0, it is shared with all the other paramaters whose value in this vector
//		is the same. This value is the so-called group index. The concrete value is not important, as long as
//		it is greater than 0.

// We will share paramaters w and A (they are offset 2 and offset 3 in the parameter list for the Gauss function)
// respectively, that is: w from the first peak will be the same as w for the second peak, whereas
// A for the first peak will be the same as A for the second peak:
vnSharingGroups[0] = 0;			// y0 ("baseline"), not shared
vnSharingGroups[1] = 0;			// xc for the first peak, not shared
vnSharingGroups[2] = 1;			// w, shared (group index 1) with vnSharingGroups[5]
vnSharingGroups[3] = 2;			// A, shared (group index 2) with vnSharingGroups[6]
vnSharingGroups[4] = 0;			// xc for the second peak (i.e. for the first replica), not shared
vnSharingGroups[5] = 1;			// w, shared (group index 1) with vnSharingGroups[2]
vnSharingGroups[6] = 2;			// A, shared (group index 2) with vnSharingGroups[3]
// Set the fitting function with the multiplicity of 2 (i.e. one replica).
int				nn = fit.SetFunction(trFF, nFitFunctionMultiplicity, -1, vnSharingGroups, vnSharingGroups.GetSize());
if (nn <= 0)
{
out_str("Failed setting fitting function!");
return;
}

///////////////////////////////////////////////////////////////////////////
// 2. Setting data for fitting ////////////////////////////////////////////
Worksheet 	wks = Project.ActiveLayer();
if( !wks )
{
out_str("No active worksheet to get input data");
return;
}

DataRange 	dr;
dr.Add(wks, 4, "Y"); // Y data from 5th column (Column E) has two peaks

DWORD 		dwRules = DRR_GET_DEPENDENT | DRR_NO_FACTORS;
int 		nNumData = dr.GetNumData(dwRules);
ASSERT( 1 == nNumData );
if( nNumData <= 0 || nNumData > 1)
{
out_str("Not proper input data to do fit");
return;
}

DWORD			dwPlotID;
vector			vX, vY;
dr.GetData( dwRules, 0, &dwPlotID, NULL, &vY, &vX);

NLSFONEDATA		stDep, stIndep;
stIndep.pdData = vX;
stIndep.nSize = vX.GetSize();
stDep.pdData = vY;
stDep.nSize = vY.GetSize();

nn = fit.SetData(1, &stDep, &stIndep);
if (nn != 0)
{
out_str("SetData() failed!");
return;
}

///////////////////////////////////////////////////////////////////////////
// 3. Setting paramaters //////////////////////////////////////////////////

// Total number of fitting parameters is 5, which is 7 (see above) reduced by two due to two
// shared paramaters.
int				nNumParams = 5;

vector			vParams(nNumParams);			// this vector should be initialized to the total number of paramaters
// This vector will be used both to set initial paramater values, and
// to receive the parameter values after fitting:
vParams[0] = 1.66;				// y0, not shared
vParams[1] = 2.5;				// xc, not shared
vParams[2] = 0.3;				// w, shared (group 1)
vParams[3] = 50;				// A, shared (group 2)
vParams[4] = 7.5;				// xc for the second peak, not shared
nn = fit.SetParams(nNumParams, vParams);
if ( 0 != nn )
{
out_str("Invalid paramater setting!");
return;
}

///////////////////////////////////////////////////////////////////////////
// 4. Fitting /////////////////////////////////////////////////////////////
int				nMaxNumIterations = 100;
nn = fit.Fit(nMaxNumIterations);
printf("Fit(%ld) returned: %ld\n", nMaxNumIterations, nn);
if( 0 == nn )
printf("Fit Done!\n");

///////////////////////////////////////////////////////////////////////////
// 5. Dump all the results and compare with what was expected /////////////
for (int iparam = 0; iparam < nNumParams; iparam++)
{
printf("param index = %d   value obtained = %lf\n", iparam + 1, vParams[iparam]);
}

return;

}