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"); 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, 0, "X"); 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; }