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


// 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");
	// 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!");

	// 2. Setting data for fitting ////////////////////////////////////////////
	Worksheet 	wks = Project.ActiveLayer();
	if( !wks )
		out_str("No active worksheet to get input data");
	DataRange 	dr;
	dr.Add(wks, 0, "X");
	dr.Add(wks, 4, "Y"); // Y data from 5th column (Column E) has two peaks
	int 		nNumData = dr.GetNumData(dwRules);
	ASSERT( 1 == nNumData );
	if( nNumData <= 0 || nNumData > 1)
		out_str("Not proper input data to do fit");
	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!");
	// 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!");
	// 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]);