/*------------------------------------------------------------------------------*
 *	File Name: 	ONLSF.h								 							*
 *	Purpose:	Nonlinear fitter's constants, enumerations, and other things	*
 *				This header is used in VC ONLSF8.DLL, as well as in OC files	*
 *  Creation:	10/4/2004														* 
 *  	Copyright Originlab Corp. 2004-2010										*
 *	Modification log	                                                        *
 *	ML 11/23/2005 QA70-8365 PFM_SPECIAL_PEAK_CENTERS_HANDLING					*
 *	ML 8/25/2006 NLFIT_MULTIDEPS_WEIGHTS_OC_WORK								*
 *	ML 10/2/2006 NLFIT_CURVES_CLEANUP											*
 *	ML 12/7/2006 NLFIT_RETURN_WEIGHTING_ERRORS									*
 *	ML 2/6/2007 QA70-9343 INCESANT_FAILED_ATTEMPTS_TO_COMPILE_BAD_FITTING_FUNCTION_BODY
 *	Cheney 2007-4-2 USE_SHORT_STRING_IN_STATISTIC_COLUMN						*
 *	ML 5/4/2007 QA70-8886 ONLSF8_RETURN_VAR_COVAR_MATRIX						*
 *	Arvin 05/08/07 QA70-9498 ONLSF8_GET_VAR_CORRE_MATRIX						*
 *	ML 5/10/2007 GETTING_DERIVATIVES_FROM_NUMERICFUNCTION_CLASS_NUMERICALLY		*
 *	ML 6/1/2007 GENERAL_LINEAR_CONSTRAINTS_MOVING_FROM_OLD_FITTER				*
 *	ML 6/12/2007 ONLSF8_SIMPLEX													*
 *	ML 6/18/2007 SETTING_GLCS_FROM_OC											*
 *	Arvin 07/04/07 QA70-10019 INTEGRAl_OF_NUMERIC_FUNCTION						* 
 *	Arvin 07/12/07 QA70-10019 PEAK_MOMENT_CALCULATION							*
 *	ML 7/19/2007 ONLSF8_ERROR_CODES_FOR_NEGATIVE_ERRORS_WEIGHTS					*
 *	ML 10/16/2007 QA70-10543 SETTING_UP_FUNCTIONS_SHARING_ETC_FOR_MULTIPEAK_FITTING
 *	Arvin 01/11/08 QA70-10923 CALC_CONFIDENCE_AND_PREDICTION_BANDS				*
 *	ML 3/26/2008 QA70-11314 CHANGING_MULTIPLICITY_ONLY							*
 *	ML 4/20/2008 QA70-11061 GETTING_CURRENT_FIT_INFO							*
 *	Folger 05/06/08 ADD_SET_FUNCTIONS_METHOD_TO_OCNLFIT							*
 *	Folger 05/06/08 ADD_SET_PARAMS_METHOD_WITH_NLPARAMETERMANAGER_TO_OCNLFIT	*
 *	ML 5/15/2008 ALLOW_PASSING_PRECISION_FOR_MOMENTS_COMPUTATION				*
 *	ML 5/16/2008 QA70-11552 ANALYTICALLY_COMPUTING_FF_MOMENTS					*
 *	ML 5/21/2008 NUMERICFUNCTION_CLASS_ACCESS_TO_PEAK_PARAMETER_INDICES			*
 *	ML 5/22/2008 PARAMETER_VALUE_DEPENDENT_INFO_ABOUT_WHETHER_THE_FUNCTION_HAS_COMPUTABLE_MOMENTS
 *	Folger 08/09/08 QA80-11816 SUPPORT_AUTO_PARAMETER_INITIALIZATION_FOR_MULTIPLE_INDEPENDNTS_AND_MULTIPLE_DEPENDENTS
 *	Jack 08/07/2008 ADD_STATISTICAL_WEIGHT_WITH_CUTOFF							*
 *	Jack 08/14/2008 SHOW_ERR_MESSAGE_FOR_INVALID_CONSTRAINTS					*
 *	ML 9/18/2008 QA70-12199 FASTER_FIT_LABTALK_CALL								*
 *	Folger 10/10/08 GET_ALL_NON_TRIMMED_PARAMETERS_RESULTS_FOR_MULTIPLE_PEAKS_FITTING
 *	Folger 10/15/08 MOVE_COMPUTE_CONFIDENCE_LIMITS_METHODS_INTO_VC				*
 *	Jack 10/16/08 QA70-10923 CALC_CONFIDENCE_AND_PREDICTION_BANDS_FOR_GLOBAL_FIT*
 *	Folger 11/11/08 v8.0968 UPDATE_PARAMETERS_LINKING_IN_NLFIT_OBJECT			*
 *	Folger 12/10/08 QA80-12751 v8.0984d SUPPORT_ALWAYS_GENERATE_OUTPUTS_REGARDLESS_OF_INTERATION_IN_PA_FITTING
 *	Folger 02/09/09 QA80-13085 MORE_CLEAR_WAY_TO_INDICATE_MISSING_PARAMETERS_INSTEAD_OF_DISABLE_ITERATION
 *	Kyle 08/06/2009 QA80-14077 ADD_UNIT_FOR_PARAMETER_SETTINGS					*
 *	Folger 08/11/10 ORG-756-P3 BETTER_CHECKING_FOR_VALID_EQUATIONS				*
 *	Folger 08/16/10 ORG-756-P1-P2 BETTER_ERROR_CHECKING_FOR_FITTING_FUNCTION_LT_EVALUATION
 *	Folger 08/16/10 ORG-762-P2 MORE_ERROR_CHECKING_ON_DERIVED_PARAMS_EQUATIONS	*
 *------------------------------------------------------------------------------*/

#ifndef		__ONLSF_H__
#define		__ONLSF_H__
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

/// ML 5/16/2008 QA70-11552 ANALYTICALLY_COMPUTING_FF_MOMENTS
#define			ONLSF8_MOMENT_VALUE_NOT_APPLICABLE			(1.23456789E-300)
/// end ANALYTICALLY_COMPUTING_FF_MOMENTS


/////////////////////////////////////////
// Common to Origin C and VC

enum {
	ONLSF8RESET_ALL						= 0,
	ONLSF8RESET_FUNCTIONS,
	ONLSF8RESET_DATA,
	ONLSF8RESET_PARAMETERS,
};


typedef			double	ONLSFD,	*PONLSFD,	*LPONLSFD;

typedef	struct	tagNLSFONEDATA
{
	PONLSFD					pdData;		// pointer to an arrays of values
	int						nSize;		// size of pdData array 
} NLSFONEDATA,	*PNLSFONEDATA;


/// ML 4/20/2008 QA70-11061 GETTING_CURRENT_FIT_INFO
typedef struct tagNLSFCURRINFO
{
	BOOL	bNewParamValues;		// the same flag is the one returned from  NLFitContext::IsNewParamValues()
	int		nCurrSet;				// the current dataset set being fitted.
	int		nCurrDataIndex;			// the index of the current datapoint being evaluated
} NLSFCURRINFO, *PNLSFCURRINFO;
/// end GETTING_CURRENT_FIT_INFO

/// ML 5/21/2008 NUMERICFUNCTION_CLASS_ACCESS_TO_PEAK_PARAMETER_INDICES
// Peak parameter indices from FDF file:
struct	NLPEAKPARAMS
{
	int		nIndexAmplitude;
	int		nIndexCenter;
	int		nIndexWidth;
	int		nIndexCenter2;
	int		nIndexWidth2;
};
/// end NUMERICFUNCTION_CLASS_ACCESS_TO_PEAK_PARAMETER_INDICES



/// ML 11/23/2005 QA70-8365 PFM_SPECIAL_PEAK_CENTERS_HANDLING
// Possible bits for the property MultipeakOptions: 
enum {
	PEAKSMODE_MULTIPEAK_CENTERS_HANDLING		= 0x00010000UL,
	PEAKSMODE_SKIP_FIRST_FUNCTION				= 0x00020000UL,
/// Jack 08/04/2008 QA70-11463 POSTFIX_FOR_LINEAR_CONSTRAINTS_PARA_TOKENS
//  This bit is to indicate that linear constraints for PA will be used
	PEAKSMODE_MULTIFUNC_GLC							= 0x00040000UL,
///	End POSTFIX_FOR_LINEAR_CONSTRAINTS_PARA_TOKENS
};
/// end PFM_SPECIAL_PEAK_CENTERS_HANDLING

///Arvin 07/12/07 QA70-10019 PEAK_MOMENT_CALCULATION 
enum
{
	PEAK_ZERO_POINT_MOMENT = 0,
	PEAK_CENTRAL_MOMENT,
};

//Error message for peak moments calculation
enum
{
	PEAKMOMENT_GET_NF_VALUE_FROM_X_FAILED				= -1,
	PEAKMOMENT_ORDER_LESS_THAN_ZERO						= -2,
	PEAKMOMENT_ORDER_LESS_THAN_TWO_FOR_CENTRAL_MOMENT	= -3,
	PEAKMOMENT_UNDEFINED_MOMENT_TYPE					= -4,
	PEAKMOMENT_0TH_MOMENT_IS_ZERO						= -5,
};
///END PEAK_MOMENT_CALCULATION


/// ML 5/22/2008 PARAMETER_VALUE_DEPENDENT_INFO_ABOUT_WHETHER_THE_FUNCTION_HAS_COMPUTABLE_MOMENTS
enum
{
	MOMENTEXISTS_0			= 0x00000001,
	MOMENTEXISTS_1			= 0x00000002,
	MOMENTEXISTS_2			= 0x00000004,
	MOMENTEXISTS_3			= 0x00000008,
	MOMENTEXISTS_4			= 0x00000010,
};
/// end PARAMETER_VALUE_DEPENDENT_INFO_ABOUT_WHETHER_THE_FUNCTION_HAS_COMPUTABLE_MOMENTS


///Arvin 01/18/2008 QA70-8365 SUPPORT_2D_PEAK_CENTERS_HANDLING	
//Used to improve speed of 2D peak fitting
typedef struct tagNLSF8DATASTEP
{
	long lStep;
} NLSF8DATASTEP, *PNLSF8DATASTEP;

typedef struct tagNLSF8ITERATIONSETTINGS
{
	int	nNumIterationsWithFixedCenters;
}NLSF8ITERATIONSETTINGS, *PNLSF8ITERATIONSETTINGS;
///end 	SUPPORT_2D_PEAK_CENTERS_HANDLING

//////////////////////////////////////////////////////////////////
// Constants and enums
//////////////////////////////////////////////////////////////////
/// ML 5/22/2008 PARAMETER_VALUE_DEPENDENT_INFO_ABOUT_WHETHER_THE_FUNCTION_HAS_COMPUTABLE_MOMENTS
//enum ONLSFWEIGHTMETHOD {
typedef enum _ONLSFWEIGHTMETHOD {
/// end PARAMETER_VALUE_DEPENDENT_INFO_ABOUT_WHETHER_THE_FUNCTION_HAS_COMPUTABLE_MOMENTS
	WEIGHT_NONE												= 0,
	WEIGHT_INSTRUMENTAL,													// requires additional dataset
	WEIGHT_STATISTICAL,
	WEIGHT_ARBITRARY_DATASET,												// requires additional dataset
	WEIGHT_DIRECT,															// requires additional dataset

	/////////////////////////////////////////////////
	// http://www.boomer.org/c/p3/c13/c1305.html
	// 13.5.2.:
	WEIGHT_INVERSE_DATA_SQUARED,
	// weight is inverse square of data values (note that 13.5.1. from http://www.boomer.org/c/p3/c13/c1305.html is WEIGHT_STATISTICAL)

	// http://www.boomer.org/c/p3/c13/c1305.html
	// 13.5.3.:
	WEIGHT_INVERSE_DATA_VALUE_A_B,
	// weight is the inverse of a*datavalue^b where a and b are two user-supplied values (a presumably must be positive)

	// http://www.boomer.org/c/p3/c13/c1305.html
	// 13.5.4.:
	WEIGHT_INVERSE_DATA_VALUE_A_B_WITH_ASSAY_SENSITIVITY_TERM,
	// weight is the inverse of c^b + a*datavalue^b where c, a, and b are three user-supplied values (a and c presumably must be positive)

	// http://www.boomer.org/c/p3/c13/c1305.html
	// 13.5.5.:
	WEIGHT_INVERSE_DATA_VALUE_A_B_C_WITH_TIME_INFORMATION,
	// weight is the inverse of a*datavalue^b*c^(tlast - t); c, a, and b are three user-supplied values (a and c presumably must be positive),
	// and the method requires an additional dataset holding times in ascending order (see the "calculator" at the bottom of http://www.boomer.org/c/p3/c13/c1305.html).

	
	///////////////////////
	// For all the WEIGHT_IRWLS weighting methods see http://www.boomer.org/c/p3/c13/c1306.html
	// (QA70-6018)
	// There is also this reference:
	// Peck, C.C., Sheiner, L.B. and Nichols, A.I. 1984 "The Problem of Choosing Weights in Nonlinear Regression Analysis of Pharmacokinetic Data", Drug Metabolism Reviews, 15, pp 133-148 

	// 13.6.1 (from http://www.boomer.org/c/p3/c13/c1306.html):
	WEIGHT_IRWLS_INVERSE_FUNC_VALUE,
	// weight is the function value 
	
	// 13.6.2 (from http://www.boomer.org/c/p3/c13/c1306.html):
	WEIGHT_IRWLS_INVERSE_FUNC_VALUE_SQUARED,
	// weight is inverse of the square of the function value

	// 13.6.3 (from http://www.boomer.org/c/p3/c13/c1306.html):
	WEIGHT_IRWLS_INVERSE_FUNC_VALUE_A_B,
	// weight is the inverse of a*funcvalue^b where a and b are two user-supplied values (a presumably must be positive)

	// 13.6.4 (from http://www.boomer.org/c/p3/c13/c1306.html):
	WEIGHT_IRWLS_INVERSE_FUNC_VALUE_A_B_WITH_ASSAY_SENSITIVITY_TERM,
	// weight is the inverse of c^b + a*funcvalue^b where c, a, and b are three user-supplied values (a and c presumably must be positive)

	// 13.6.5 (from http://www.boomer.org/c/p3/c13/c1306.html):
	// (See also http://www.boomer.org/c/p3/c13/c1305.html where it appears that the same thing can be done with data values instead
	// of with function values)
	WEIGHT_IRWLS_INVERSE_FUNC_VALUE_A_B_C_WITH_TIME_INFORMATION,
	// weight is the inverse of a*funcvalue^b*c^(tlast - t); c, a, and b are three user-supplied values (a and c presumably must be positive),
	// and the method requires an additional dataset holding times in ascending order (see the "calculator" at the bottom of http://www.boomer.org/c/p3/c13/c1305.html).
/// ML 5/22/2008 PARAMETER_VALUE_DEPENDENT_INFO_ABOUT_WHETHER_THE_FUNCTION_HAS_COMPUTABLE_MOMENTS
//};
/// Jack 08/07/2008 ADD_STATISTICAL_WEIGHT_WITH_CUTOFF
	WEIGHT_STATISTICAL_WITH_CUTOFF,
	// The weight method is added to deal with those measured signal data with zero and negative value 
	// which leads to problem of zero division and others like how to weight negative signal
	// The weight formula is w = 1/ max(yi, yc)^b  yi is dependant data (or the measured data), yc=a is the cutoff
	// b is the power, default set as 1, to mean that it is a statistical weight 
/// End ADD_STATISTICAL_WEIGHT_WITH_CUTOFF
} ONLSFWEIGHTMETHOD;
/// end PARAMETER_VALUE_DEPENDENT_INFO_ABOUT_WHETHER_THE_FUNCTION_HAS_COMPUTABLE_MOMENTS


// one dataset weight descriptor:
typedef	struct tagONEDATAWEIGHT {
	ONLSFWEIGHTMETHOD		method;
	NLSFONEDATA				stWeightData;		// optional (only certain weight methods require data)
	ONLSFD					a;					// optional
	ONLSFD					b;					// optional
	ONLSFD					c;					// optional
} ONEDATAWEIGHT,	*PONEDATAWEIGHT;


// The Fit iterations outcome code:
enum FITITER {
	///Cheney 2007-4-2 USE_SHORT_STRING_IN_STATISTIC_COLUMN
	//if converge, code will begining from 100, then 101, 102, etc
	//if not converge, code will begining from -100, then -101, -102, etc
	//use 0 for abort, 1-99 for others like reduced chi-sq
	//FITITER_FAILED								= 0,
	FITITER_FAILED				= -100,
	FITTTER_FAILED_FROM_FUNC	= -101,				// during mrqmin, function evaluation returns error, indicating invalid parameters
	/// Jack 08/14/2008 SHOW_ERR_MESSAGE_FOR_INVALID_CONSTRAINTS
	FITITER_FAILED_GENERAL_LINEAR_CONSTRAINTS	= -102,
	///	End SHOW_ERR_MESSAGE_FOR_INVALID_CONSTRAINTS
	FITITER_FAILED_MISSING_PARAMS = -103,			///------ Folger 02/09/09 QA80-13085 MORE_CLEAR_WAY_TO_INDICATE_MISSING_PARAMETERS_INSTEAD_OF_DISABLE_ITERATION
	FITITER_REACHED_TOLERANCE	= 100,				// reduced chi-sq so that the tolerance was reached
	FITITER_REDUCED_CHISQ		= 1,				// reduced chi-sq, but the tolerance was not reached
	FITITER_COULD_NOT_REDUCE_CHISQ_AT_LAST_ITER = 101,// at the last of possibly many iterations it could not further reduce chi-sq
	FITITER_ABORT_BY_USER		= 0,				//------ CPY 3/16/2007 QA70-9473 NLFIT_NEEDS_FEEDBACK_TO_USER_AND_ESC_TO_ABORT_FITTING
	//FITTTER_FAILED_FROM_FUNC,						// during mrqmin, function evaluation returns error, indicating invalid parameters
	//FITITER_REACHED_TOLERANCE,					// reduced chi-sq so that the tolerance was reached
	//FITITER_REDUCED_CHISQ,						// reduced chi-sq, but the tolerance was not reached
	//FITITER_COULD_NOT_REDUCE_CHISQ_AT_LAST_ITER,	// at the last of possibly many iterations it could not further reduce chi-sq
//
	//FITITER_ABORT_BY_USER,						//------ CPY 3/16/2007 QA70-9473 NLFIT_NEEDS_FEEDBACK_TO_USER_AND_ESC_TO_ABORT_FITTING
	///end USE_SHORT_STRING_IN_STATISTIC_COLUMN
};

//------ CPY 3/16/2007 QA70-9473 NLFIT_NEEDS_FEEDBACK_TO_USER_AND_ESC_TO_ABORT_FITTING
enum {
	NLFI_BEGIN,
	NLFI_END,
	NLFI_NEW_ITERATION,
	NLFI_ON_ABORT,

	NLFI_OPTIONAL_MSG = 100,
	NLFI_INV_MAT,
	NLFI_CHISQR,
	NLFI_INTERNAL, // whatever else that we don't need to give msg string but to still check break


};
//------ end

/// ML 6/12/2007 ONLSF8_SIMPLEX
enum {
	FITMETH_LEVENBERG_MARQUARDT				= 0,
	FITMETH_SIMPLEX,
};
/// end ONLSF8_SIMPLEX


/// ML 10/16/2007 QA70-10543 SETTING_UP_FUNCTIONS_SHARING_ETC_FOR_MULTIPEAK_FITTING
enum {
	ONLSF8MLTPEAKSPROP_VALUE				= 2,
	ONLSF8MLTPEAKSPROP_SHARED,
	ONLSF8MLTPEAKSPROP_FIXED,
	ONLSF8MLTPEAKSPROP_LOWERBOUND,
	ONLSF8MLTPEAKSPROP_UPPERBOUND,
	ONLSF8MLTPEAKSPROP_LOWERBOUNDEXCL,
	ONLSF8MLTPEAKSPROP_UPPERBOUNDEXCL,

};

enum {
	ONLSF8MLTPEAKSMSG_SET					= 0,		// the same as when pst is NULL
	ONLSF8MLTPEAKSMSG_EDIT,
	ONLSF8MLTPEAKSMSG_GETPARAMRESULTS,
};

#ifdef _MSC_VER		// VC
struct	tagFitParameter;
#endif // _MSC_VER	// VC

#define	ONLSF8MLTPEAKS_MAX_LENGTH_FF_NAME			31
#define	ONLSF8MLTPEAKS_MAX_LENGTH_PARAM_NAME		15
/// ML 5/22/2008 PARAMETER_VALUE_DEPENDENT_INFO_ABOUT_WHETHER_THE_FUNCTION_HAS_COMPUTABLE_MOMENTS
//struct	ONLSF8MLTPEAKPARAMINFO
//{
//	char		szFF[ONLSF8MLTPEAKS_MAX_LENGTH_FF_NAME + 1];				// name
//	char		szParamName[ONLSF8MLTPEAKS_MAX_LENGTH_PARAM_NAME + 1];		// param name
//	int			nPeakIndex;
//};
typedef	struct	_ONLSF8MLTPEAKPARAMINFO
{
	char		szFF[ONLSF8MLTPEAKS_MAX_LENGTH_FF_NAME + 1];				// name
	char		szParamName[ONLSF8MLTPEAKS_MAX_LENGTH_PARAM_NAME + 1];		// param name
	int			nPeakIndex;
} ONLSF8MLTPEAKPARAMINFO;
/// end PARAMETER_VALUE_DEPENDENT_INFO_ABOUT_WHETHER_THE_FUNCTION_HAS_COMPUTABLE_MOMENTS


struct	ONLSF8MLTPEAKS
{
	UINT					msg;			// possible values are ONLSF8MLTPEAKSMSG_* 
	int						nRow;
	int						nProp;			// possible values are ONLSF8MLTPEAKSPROP_* and indicate what was edited if msg == ONLSF8MLTPEAKSMSG_EDIT  

	BOOL					bModifed;		// [output] the function will set it to TRUE if it has modified the tree in any way
#ifdef _MSC_VER		// VC
	struct	tagFitParameter		*pstResults;
#else // _MSC_VER	// OC
	FitParameter			*pstResults;	// used only with the message ONLSF8MLTPEAKSMSG_GETPARAMRESULTS. It should be set to NULL to retrieve nTotalAbsParams.
											// then call it again, but with allocated array of FitParameter structure of size nTotalAbsParams.
#endif // _MSC_VER	// OC
	ONLSF8MLTPEAKPARAMINFO	*pstParamsInfo;	// used only with the message ONLSF8MLTPEAKSMSG_GETPARAMRESULTS. If not NULL, it must have the same size as pstResults (nTotalAbsParams).
	int					nTotalAbsParams;
};
/// end SETTING_UP_FUNCTIONS_SHARING_ETC_FOR_MULTIPEAK_FITTING

//------ Folger 10/15/08 MOVE_COMPUTE_CONFIDENCE_LIMITS_METHODS_INTO_VC
enum
{
	CONF_LIMIT_METHOD_AS_BASED = 0,
	CONF_LIMIT_METHOD_MODLE_COMP_BASED,
	
	CONF_LIMIT_METHOD_TOTAL
};
//------ End MOVE_COMPUTE_CONFIDENCE_LIMITS_METHODS_INTO_VC

//------ Folger 12/10/08 QA80-12751 v8.0984d SUPPORT_ALWAYS_GENERATE_OUTPUTS_REGARDLESS_OF_INTERATION_IN_PA_FITTING
enum
{
	NLSFFIT_GENERATE_OUTPUTS_WITHOUT_ITERATION		= 0x00010000,
};
//------ End SUPPORT_ALWAYS_GENERATE_OUTPUTS_REGRADLESS_OF_INTERATION_IN_PA_FITTING

///------ Folger 08/16/10 ORG-756-P1-P2 BETTER_ERROR_CHECKING_FOR_FITTING_FUNCTION_LT_EVALUATION
enum
{
	NLSFEVALUATE_CHECK_LT_VARS_FULLY_USED		= 0x00010000,
};
///------ End BETTER_ERROR_CHECKING_FOR_FITTING_FUNCTION_LT_EVALUATION


//CPY 8/30/05
#define NLF_MUTUALDEPEND 28050
// Warning! Mutual dependency exists between parameters %s. 
//You may have overparameterized the fitting function. Fixing one of them may eliminate this problem.

/// ML 12/7/2006 NLFIT_RETURN_WEIGHTING_ERRORS

// Can be produced by weighting methods WEIGHT_INSTRUMENTAL and WEIGHT_ARBITRARY_DATASET
// when the error data value is 0 or to small.
#define NLF_ZERO_ERROR_NOT_CONSISTENT 28052

// Can be produced by weighting methods WEIGHT_STATISTICAL and WEIGHT_INVERSE_DATA_SQUARED
// when the dependent data value is too small or 0.
#define NLF_ZERO_YVALUE_NOT_CONSISTENT 28053

// Can be produced by most other weigthing methods when some value is inconsistent
// with the weighting method chosen.
#define NLF_VALUE_NOT_CONSISTENT_WITH_WEIGHTING_METHOD 28056

/// ML 7/19/2007 ONLSF8_ERROR_CODES_FOR_NEGATIVE_ERRORS_WEIGHTS
#define	NLF_NEGATIVE_ERROR_FOR_WEIGHT					28057

// It is caused if the weight is negative. For example if for WEIGHT_DIRECT
// the datapoint of the weight dataset itself is negative.
#define	NLF_NEGATIVE_WEIGHT								28058
/// end ONLSF8_ERROR_CODES_FOR_NEGATIVE_ERRORS_WEIGHTS

// Can be produced by the parser of NLFIT constraints
/// Jack QA70-11463 08/15/2008 ONLSF8_ERROR_CODES_FOR_PARSE_CONSTRAINTS
#define	NLF_BADCNSTRVAR									28027
#define NLF_CONSTRBAD									28026									
/// End ONLSF8_ERROR_CODES_FOR_PARSE_CONSTRAINTS

///------ Folger 02/09/09 QA80-13085 MORE_CLEAR_WAY_TO_INDICATE_MISSING_PARAMETERS_INSTEAD_OF_DISABLE_ITERATION
#define NLF_BADINITPARA									28051
///------ End MORE_CLEAR_WAY_TO_INDICATE_MISSING_PARAMETERS_INSTEAD_OF_DISABLE_ITERATION


/// end NLFIT_RETURN_WEIGHTING_ERRORS

/// ML 5/10/2007 GETTING_DERIVATIVES_FROM_NUMERICFUNCTION_CLASS_NUMERICALLY
/// ML 5/22/2008 PARAMETER_VALUE_DEPENDENT_INFO_ABOUT_WHETHER_THE_FUNCTION_HAS_COMPUTABLE_MOMENTS
//struct	ONLSFNUMERICDERIVSSETTINGS
//{
//	BOOL				bFixedDerivStepSize;			// whether, when numerically computing derivatives, the parameter step should be fixed (otheriwise it scales with the parameter value) 
//	ONLSFD				rDerivStepSize;					// when numerically computing derivatives, the paramater step
//	ONLSFD				rMinDerivStepSize;				// when numerically computing derivatives, the minimum parameter step if the step is not fixed 
//	ONLSFD				rMaxDerivStepSize;				// when numerically computing derivatives, the maximum parameter step if the step is not fixed
//};
typedef	struct	_ONLSFNUMERICDERIVSSETTINGS
{
	BOOL				bFixedDerivStepSize;			// whether, when numerically computing derivatives, the parameter step should be fixed (otheriwise it scales with the parameter value) 
	ONLSFD				rDerivStepSize;					// when numerically computing derivatives, the paramater step
	ONLSFD				rMinDerivStepSize;				// when numerically computing derivatives, the minimum parameter step if the step is not fixed 
	ONLSFD				rMaxDerivStepSize;				// when numerically computing derivatives, the maximum parameter step if the step is not fixed
} ONLSFNUMERICDERIVSSETTINGS;
/// end PARAMETER_VALUE_DEPENDENT_INFO_ABOUT_WHETHER_THE_FUNCTION_HAS_COMPUTABLE_MOMENTS
/// end GETTING_DERIVATIVES_FROM_NUMERICFUNCTION_CLASS_NUMERICALLY

struct	ONLSFSETTINGS 
{
	/// ML 5/10/2007 GETTING_DERIVATIVES_FROM_NUMERICFUNCTION_CLASS_NUMERICALLY
	//BOOL				bFixedDerivStepSize;			// whether, when numerically computing derivatives, the parameter step should be fixed (otheriwise it scales with the parameter value) 
	//ONLSFD				rDerivStepSize;					// when numerically computing derivatives, the paramater step
	//ONLSFD				rMinDerivStepSize;				// when numerically computing derivatives, the minimum parameter step if the step is not fixed 
	//ONLSFD				rMaxDerivStepSize;				// when numerically computing derivatives, the maximum parameter step if the step is not fixed
	ONLSFNUMERICDERIVSSETTINGS	stNumericDerivsSettings;
	/// end GETTING_DERIVATIVES_FROM_NUMERICFUNCTION_CLASS_NUMERICALLY
	ONLSFD				rSingularCriterion;				// when doing matrix inversion via singular value decomposition, the threshold below which the value is considered as producing singularity
	ONLSFD				rTolerance;						// the absolute value of the relative change of the sum of squares between succesive iterations below which the Levenber-Marquardt iterative procedure is considered to have converged.
	ONLSFD				rConfidence;					// the confidence (typically 0.95) when computing parameter confidence intervals 
	BOOL				bErrorsWithChisq;
};


/// ML 9/18/2008 QA70-12199 FASTER_FIT_LABTALK_CALL
struct NLFITCURVEEVALINIT
{
	int				nSets;
	int				nPeaks;
	// Only one of nSets or nPeaks can be > 0.
	// Inside pParams all the params are lined up in sequence of either sets or peaks
	// (depending on what, nSets or nPeaks, is > 0), with *pnParams containing
	// the offsets from the beginning of pParams into each set/peak by index, plus the last one containing
	// the total size. So, the size of pnParams is (nSets or nPeaks) + 1, since the first
	// element of pParams is always 0. 
	const	double	*pParams;
	const	int		*pnParams;

	double			dBaseline;
};
/// end FASTER_FIT_LABTALK_CALL



// END Common to Origin C and VC 
/////////////////////////////////////////

#ifndef _MSC_VER	// Not Origin C
/////////////////////////////////////////
// Origin C only: 
#include	<stats_types.h>



//Comment last udpated by Iris 04/09/07
/**# >Analysis
	The NumericFunction class provides methods and properties for non-linear curve and surface fitting.
	Levenberg-Marquardt algorithm is used for the fitting. A typical procedure will include: SetFunction, SetData, SetParams, Fit,
	GetParameterResults, GetSummaryFitResults. Class NumericFunction may be used for numerical calcation of the fitting function.
	
	Example1:
			
			/////////////////////////////////////////////////
			// This is a self-contained example of the fitting of data to a fitting function
			// with one replica (i.e. multipeak fitting).
			// The example creates its own data, then sets the fitting function with the appropriately
			// set replicas number and paramater sharing between peaks, then sets the data, paramaters,
			// fits, and dumps the obtained parameter values.
			#include <origin.h>
			
            #include <FDFTree.h>
            #include <ONLSF.h>
            
			void	NLFit_ex1()
			{
				string			strFDF = okutil_get_origin_path(ORIGIN_PATH_SYSTEM, "FitFunc") + "Gauss.FDF";
				Tree			trFF;
				if( !nlsf_FDF_to_tree( strFDF, &trFF ))
					return;
				
			
				//////////////////////////////////////////////////////////////////////
				// 1. Generating data values to be later used for fitting ////////////
				
				// We use the function itself with certain paramater values to generate
				// the dependent data so we can later test to see
				// if the fitting proceeded correctly:
				NumericFunction	NF;
				NF.SetTree(trFF);
			
				// The total number of points:
				int				nPts = 1000;
				
				// Initalize the independent data values:
				vector			vX(nPts);
				for (int ii = 0; ii < nPts; ii++)
				{
					double		x = ii;
					vX[ii] = x;
				}
			
				vector			vParams1(4);		// 4 is the number of params in the function
				// y0,xc,w,A are parameters for Gauss.
				
				// Two auxiliary vectors for the dependent data, each for one peak:
				vector			vY1(nPts), vY2(nPts);
				vParams1[0] = 5;		// y0
				vParams1[1] = 250;		// xc
				vParams1[2] = 40;		// w
				vParams1[3] = 7;		// A
				// get the values for the first peak plus base (vParams1[0] = 5)
				// (for each element of vX one values will be generated in vY1):
				BOOL			bb = NF.Evaluate(vParams1, vY1, vX, NULL, nPts);
				if (!bb)
				{
					out_str("Failed!");
					return;
				}
				
				// Set the base to 0 for the second peak (it will anyhow later be added to the first peak):
				vParams1[0] = 0.;
				// Set different center:
				vParams1[1] = 800;		// xc
				// For the second peak:
				bb = NF.Evaluate(vParams1, vY2, vX, NULL, nPts);
				if (!bb)
				{
					out_str("Failed!");
					return;
				}
			
				// Add the two up to form vY:
				// Dependent data values vector:
				vector			vY(nPts);
				vY = vY1 + vY2;
				
				// Now vX and vY contain the data values which we will use for fitting.
				
				
				//////////////////////////////////////////////////////////////////////////////
				// 2. 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;
				}
				
				
				///////////////////////////////////////////////////////////////////////////
				// 3. Setting data for fitting ////////////////////////////////////////////
				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;
				}
			
				///////////////////////////////////////////////////////////////////////////
				// 4. 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] = 4;					// y0, not shared 
				vParams[1] = 150;				// xc, not shared
				vParams[2] = 60;				// w, shared (group 1)
				vParams[3] = 5;					// A, shared (group 2)
				vParams[4] = 750;				// xc for the second peak, not shared
				nn = fit.SetParams(nNumParams, vParams);
				if ( 0 != nn )
				{
					out_str("Invalid paramater setting!");
					return;
				}
			
				// These are the expected paramater values based on the initialization in step 1.
				// (we'll use them after the fitting to compare with the obtained values):
				vector			vParamsExpected(nNumParams);
				vParamsExpected[0] = 5;					// y0, not shared 
				vParamsExpected[1] = 250;				// xc, not shared
				vParamsExpected[2] = 40;				// w, shared (group 1)
				vParamsExpected[3] = 7;					// A, shared (group 2)
				vParamsExpected[4] = 800;				// xc for the second peak, not shared
			
			
				///////////////////////////////////////////////////////////////////////////
				// 5. Fitting /////////////////////////////////////////////////////////////
				int				nMaxNumIterations = 100;
				nn = fit.Fit(nMaxNumIterations);
				printf("Fit(%ld) returned: %ld\n", nMaxNumIterations, nn);
				
				///////////////////////////////////////////////////////////////////////////
				// 6. Dump all the results and compare with what was expected /////////////
				for (int iparam = 0; iparam < nNumParams; iparam++)
				{
					printf("param index = %d   value expected = %lf   value obtained = %lf\n", iparam + 1, vParamsExpected[iparam], vParams[iparam]);
				}
				
				return;
				
			}

		
		Example2:
			/////////////////////////////////////////////////
			// This is a self-contained example of the fitting of data to two fitting functions
			// with one replica for each function (i.e. multipeak fitting with a total of 4 peaks).
			// The example creates its own data, then sets the fitting functions with the appropriately
			// set replicas number and paramater sharing between peaks, then sets the data, paramaters,
			// fits, and dumps the obtained parameter values.
			#include <origin.h>

			#include <FDFTree.h>
            #include <ONLSF.h>
            
			void	NLFit_ex2()
			{
				// Two functions:
				// (1) Gauss
				string			strFDF1 = okutil_get_origin_path(ORIGIN_PATH_SYSTEM, "FitFunc") + "Gauss.FDF";
				Tree			trFF1;
				if( !nlsf_FDF_to_tree( strFDF1, &trFF1 ))
					return;
				
				// (2) Lorentz
				string			strFDF2 = okutil_get_origin_path(ORIGIN_PATH_SYSTEM, "FitFunc") + "Lorentz.FDF";
				Tree			trFF2;
				if( !nlsf_FDF_to_tree( strFDF2, &trFF2 ))
					return;
				
				
				//////////////////////////////////////////////////////////////////////
				// 1. Generating data values to be later used for fitting ////////////
			
				// The total number of points:
				int				nPts = 1000;
				
				// Initalize the independent data values:
				vector			vX(nPts);
				for (int ii = 0; ii < nPts; ii++)
				{
					double		x = ii;
					vX[ii] = x;
				}
				
				vector			vParams1(4);		// 4 is the number of params in each function.
													// The parameters in both Gauss and Lorentz have the same names:
													// y0,xc,w,A 
				
				// We use the functions themselves with certain paramater values to generate
				// the dependent data so we can later test to see if the fitting proceeded correctly:
				NumericFunction	NFGauss;
				NFGauss.SetTree(trFF1);
				
				// Two auxiliary vectors for the dependent data, each for one Gauss peak:
				vector			vY1(nPts), vY2(nPts);
				vParams1[0] = 3;		// y0
				vParams1[1] = 150;		// xc
				vParams1[2] = 40;		// w
				vParams1[3] = 7;		// A
				// get the values for the first Gauss peak plus base (vParams1[0] = 3)
				// (for each element of vX one values will be generated in vY1):
				BOOL			bb = NFGauss.Evaluate(vParams1, vY1, vX, NULL, nPts);
				if (!bb)
				{
					out_str("Failed!");
					return;
				}
				
				// Set the base to 0 for the second Gauss peak (it will anyhow later be added to the first peak):
				vParams1[0] = 0.;
				// Set different center:
				vParams1[1] = 550;		// xc
				// And different width:
				vParams1[2] = 60;		// w
				// And different height:
				vParams1[3] = 5;		// A
				// For the second Gauss peak:
				bb = NFGauss.Evaluate(vParams1, vY2, vX, NULL, nPts);
				if (!bb)
				{
					out_str("Failed!");
					return;
				}
				// Add the two up to form vY:
				// Dependent data values vector:
				vector			vY(nPts);
				vY = vY1 + vY2;
			
				// Now we'll add two Lorentz peaks.
				NumericFunction	NFLorentz;
				NFLorentz.SetTree(trFF2);
				
				// Set the base to 0 for the Lorentz (it will anyhow later be added to the Gauss peaks which already
				// have the baseline accounted for):
				vParams1[0] = 0.;
				vParams1[1] = 350;		// xc, new center
				vParams1[2] = 60;		// w, the width the same as for the second Gauss peak
				vParams1[3] = 7;		// A, the same as for the first Gauss peak
				// The first Lorentz peak:
				bb = NFLorentz.Evaluate(vParams1, vY1, vX, NULL, nPts);
				if (!bb)
				{
					out_str("Failed!");
					return;
				}
				
				// The second Lorentz peak:
				vParams1[1] = 800;		// xc, new center
				vParams1[2] = 40;		// w, the width the same as for the first Gauss peak
				vParams1[3] = 5;		// A, the same as for the second Gauss peak
				// The second Lorentz peak:
				bb = NFLorentz.Evaluate(vParams1, vY2, vX, NULL, nPts);
				if (!bb)
				{
					out_str("Failed!");
					return;
				}
				
				// Add Lorentz peaks:
				vY += vY1 + vY2;
				
				// Now vX and vY contain the data values which we will use for fitting.
				
				
				//////////////////////////////////////////////////////////////////////////////
				// 2. Setting the fitting function and parameter sharing for multipeak fit  //
			
				// The fit object:
				NLFit			fit;
				
				// We will fit to a total of four peaks, two Gaussian and two Lorentzian peaks,
				// with some parameter sharing between peaks.
				// Each function will therefore have the multiplicity of 2 (i.e. one replica in each function).
				// For the conditions which the fitting functions must satisfy in order to be eligible for
				// multipeak fitting, see the sample test_NLSF_replicas().
				//
				// The first function has 4 original paramaters, 3 of which are in replicas unit.
				// Since the function will have multiplicity of 2, this means that per function
				// (i.e. for its two peaks) there are 7 paramaters:
				//		7 = replicas Offset - 1 + nFitFunctionMultiplicity * replicas unit
				// since for both Gauss and Lorentz replicas Offset = 2, replicas unit = 3
				// and we use nFitFunctionMultiplicity = 2.
				int				nFitFunctionMultiplicity = 2;
				
				// To set up parameter sharing between peaks, we use an auxiliary vector of integers:
				// First we will set the first function (Gauss).
				// The first function has 7 parameters
				vector<int>		vnSharingGroupsGauss(7);
				vnSharingGroupsGauss[0] = 0;			// y0 (baseline), not shared
				vnSharingGroupsGauss[1] = 0;			// xc for the first Gauss peak, not shared
				vnSharingGroupsGauss[2] = 1;			// w for the first Gauss peak, shared with vnSharingGroupsLorentz[4] (see below) 
				vnSharingGroupsGauss[3] = 2;			// A for the first Gauss peak, shared with vnSharingGroupsLorentz[2] (see below)
				
				vnSharingGroupsGauss[4] = 0;			// xc for the second Gauss peak, not shared
				vnSharingGroupsGauss[5] = 3;			// w for the second Gauss peak, shared with vnSharingGroupsLorentz[1] (see below)
				vnSharingGroupsGauss[6] = 4;			// A for the second Gauss peak, shared with vnSharingGroupsLorentz[5] (see below)
				// Set the Gauss fitting function with the multiplicity of 2 (i.e. one replica).
				int				nn = fit.SetFunction(trFF1, nFitFunctionMultiplicity, -1, vnSharingGroupsGauss, vnSharingGroupsGauss.GetSize());
				if (nn <= 0)
				{
					out_str("Failed setting fitting function!");
					return;
				}
				
				// The second function does not have the baseline parameter y0 (the baseline parameters are those that
				// do not belong to ther replicas unit, both Gauss and Lorentz have exactly one such paramater - y0).
				// (only one baseline makes sense and it is always associated with the first function)
				// so the total number of params for this function is 6.
				// This is the auxiliary vector of integers for specifying the parameter sharing
				// for the Lorentz peaks:
				// The
				vector<int>		vnSharingGroupsLorentz(6);
				vnSharingGroupsLorentz[0] = 0;			// xc for the first Lorentx peak, not shared
				vnSharingGroupsLorentz[1] = 3;			// w for the first Lorentz peak, shared with vnSharingGroupsGauss[5]
				vnSharingGroupsLorentz[2] = 2;			// A for the first Lorentz peak, shared with vnSharingGroupsGauss[3]
				
				vnSharingGroupsLorentz[3] = 0;			// xc for the second Lorentz peak, not shared
				vnSharingGroupsLorentz[4] = 1;			// w for the second Lorentz peak, shared with vnSharingGroupsGauss[2]
				vnSharingGroupsLorentz[5] = 4;			// A for the second Lorentz peak, shared with vnSharingGroupsGauss[6]
				// Append the Lorentz fitting function with the multiplicity of 2 (i.e. one replica).
				nn = fit.SetFunction(trFF2, nFitFunctionMultiplicity, -1, vnSharingGroupsLorentz, vnSharingGroupsLorentz.GetSize());
				if (nn <= 0)
				{
					out_str("Failed setting fitting function!");
					return;
				}
				
				
				///////////////////////////////////////////////////////////////////////////
				// 3. Setting data for fitting ////////////////////////////////////////////
				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;
				}
			
				
				///////////////////////////////////////////////////////////////////////////
				// 4. Setting paramaters //////////////////////////////////////////////////
			
				// Total number of fitting parameters is dependent on the parameter sharing between peaks.
				// It is crucial that the number of parameters as specifed
				// in the SetParams() call below agrees with the numbers of parameters in the functions and with the parameter
				// sharing as specifed in step 2.
				//
				// This is how the parameters are lined up:
				// First all the parameters for the first function. Their total number is the same as the total
				// number of parameters for one Gauss function with one replica, which is, as explained above, 7. Note
				// that there is no paramater sharing between paramaters within Gauss function peaks alone, since all
				// the values in the vector vnSharingGroupsGauss are different (with the exception of 0, which, by
				// denition, means that those parameters are not shared).
				// Now we need to add the parameters for Lorentz. The vector vnSharingGroupsLorentz has 6 elements,
				// but 4 of the 6 have nonzero values which have already appeared in vnSharingGroupsGauss (which means they
				// are shared with some paramaters in Gauss), so only 2 more parameters (vnSharingGroupsLorentz[0]
				// and vnSharingGroupsLorentz[3]) are contributed by Lorentz peaks.
				// That amounts to a total of 9.
				int				nNumParams = 9;
				
				vector			vParams(nNumParams);			// this vector should be initialized to the total number of paramaters
				// The vector vParams will be used to supply the initial values of parameters, and it will also receive
				// the parameter values after fitting.
				// The paramaters are lined up in this vector such that the first come all the parameters for the Gauss, and
				// then the additional ones for the Lorentz:
				vParams[0] = 5;			// the baseline y0 (vnSharingGroupsGauss[0])
				vParams[1] = 100;		// xc for the first Gauss peak (vnSharingGroupsGauss[1])
				vParams[2] = 60;		// w for the first Gauss peak (vnSharingGroupsGauss[2]) and for the second Lorentz peak (vnSharingGroupsLorentz[4]).
				vParams[3] = 10;		// A for the first Gauss peak (vnSharingGroupsGauss[3]) and for the first Lorentz peak (vnSharingGroupsLorentz[2]).
				vParams[4] = 500;		// xc for the second Gauss peak (vnSharingGroupsGauss[4])
				vParams[5] = 90;		// w for the second Gauss peak (vnSharingGroupsGauss[5]) and for the first Lorentz peak (vnSharingGroupsLorentz[1]).
				vParams[6] = 8;			// A for the second Gauss peak (vnSharingGroupsGauss[6]) and for the second Lorentz peak (vnSharingGroupsLorentz[5]).
				vParams[7] = 300;		// xc for the first Lorentz peak (vnSharingGroupsLorentz[0])
				vParams[8] = 700;		// xc for the second Lorentz peak (vnSharingGroupsLorentz[3])
				
				nn = fit.SetParams(nNumParams, vParams);
				if ( 0 != nn )
				{
					out_str("Invalid paramater setting!");
					return;
				}
				
				// These are the expected paramater values based on the initialization in step 1.
				// (we'll use them after the fitting to compare with the obtained values):
				vector			vParamsExpected(nNumParams);
				vParamsExpected[0] = 3;					// the baseline y0 
				vParamsExpected[1] = 150;				// xc for the first Gauss peak
				vParamsExpected[2] = 40;				// w for the first Gauss peak and for the second Lorentz peak
				vParamsExpected[3] = 7;					// A for the first Gauss peak and for the first Lorentz peak
				vParamsExpected[4] = 550;				// xc for the second Gauss peak
				vParamsExpected[5] = 60;				// w for the second Gauss peak and for the first Lorentz peak
				vParamsExpected[6] = 5;					// A for the second Gauss peak and for the second Lorentz peak
				vParamsExpected[7] = 350;				// xc for the first Lorentz peak
				vParamsExpected[8] = 800;				// xc for the second Lorentz peak
			
			
				///////////////////////////////////////////////////////////////////////////
				// 5. Fitting /////////////////////////////////////////////////////////////
				int				nMaxNumIterations = 100;
				nn = fit.Fit(nMaxNumIterations);
				printf("Fit(%ld) returned: %ld\n", nMaxNumIterations, nn);
				
				
				///////////////////////////////////////////////////////////////////////////
				// 6. Dump all the results and compare with what was expected /////////////
				for (int iparam = 0; iparam < nNumParams; iparam++)
				{
					printf("param index = %d   value expected = %lf   value obtained = %lf\n", iparam + 1, vParamsExpected[iparam], vParams[iparam]);
				}
				
				return;


*/ 
class	NLFit
{
public:
	NLFit();
	~NLFit();
	
public:
	/**
			Gets various settings that determine the behavior of the fitting procedure
		Parameters:
			pst=[output] the pointer to the structure which will receive the settings
		Returns:
			TRUE if OK, otheriwse FALSE.
	*/
	BOOL		GetSettings(ONLSFSETTINGS *pst);

	/**
			Sets various settings that determine the behavior of the fitting procedure
		Parameters:
			pst=[input] the pointer to the structure which has the settings values
		Returns:
			TRUE if OK, otheriwse FALSE.
	*/
	BOOL		SetSettings(ONLSFSETTINGS *pst);
	
	//comments last updated by Cheney on 03/27/06
	/**
			Sets the function to be fitted. Multiple functions can be set by calling the method more than once,
			but all the functions must have the same number of dependent and independent variables.
		Parameters:
			trFF=[input]the tree loaded from an .FDF file.
			nMultiplicity=[input]the multiplicity of the function (in case of replicas).
			nIndex=[input]it must be -1.
			pnSharing=[input][optional]the pointer to an array of integers of the size nCountSharing representing group index
						values for each parameter. The size must be equal to the number of paramaters of the function plus,
						optionally, the size of replica unit (if supported) times (nMultiplicity - 1), which means to
						the total number of parameters of this function including all the replicas.
						If the group index (the value of an elemant of the array) is <= 0, the corresponding parameter
						is not shared. Otherwise, it is shared with all the paramaters that have the same group index,
						whether from this or from another function (that may have already been added or will be added).
			nCountSharing=[input][optional]the size of the array pointer to by pnSharing (if any).
		Returns:
			the total number of functions (if OK), or a nonegative value if error.
		Example1:
			
			/////////////////////////////////////////////////
			// This is a self-contained example of the fitting of data to a fitting function
			// with one replica (i.e. multipeak fitting).
			// The example creates its own data, then sets the fitting function with the appropriately
			// set replicas number and paramater sharing between peaks, then sets the data, paramaters,
			// fits, and dumps the obtained parameter values.
			#include <origin.h>
			
            #include <FDFTree.h>
            #include <ONLSF.h>
            
			void	NLSF_SetFunction_ex1()
			{
				string			strFDF = okutil_get_origin_path(ORIGIN_PATH_SYSTEM, "FitFunc") + "Gauss.FDF";
				Tree			trFF;
				if( !nlsf_FDF_to_tree( strFDF, &trFF ))
					return;
				
			
				//////////////////////////////////////////////////////////////////////
				// 1. Generating data values to be later used for fitting ////////////
				
				// We use the function itself with certain paramater values to generate
				// the dependent data so we can later test to see
				// if the fitting proceeded correctly:
				NumericFunction	NF;
				NF.SetTree(trFF);
			
				// The total number of points:
				int				nPts = 1000;
				
				// Initalize the independent data values:
				vector			vX(nPts);
				for (int ii = 0; ii < nPts; ii++)
				{
					double		x = ii;
					vX[ii] = x;
				}
			
				vector			vParams1(4);		// 4 is the number of params in the function
				// y0,xc,w,A are parameters for Gauss.
				
				// Two auxiliary vectors for the dependent data, each for one peak:
				vector			vY1(nPts), vY2(nPts);
				vParams1[0] = 5;		// y0
				vParams1[1] = 250;		// xc
				vParams1[2] = 40;		// w
				vParams1[3] = 7;		// A
				// get the values for the first peak plus base (vParams1[0] = 5)
				// (for each element of vX one values will be generated in vY1):
				BOOL			bb = NF.Evaluate(vParams1, vY1, vX, NULL, nPts);
				if (!bb)
				{
					out_str("Failed!");
					return;
				}
				
				// Set the base to 0 for the second peak (it will anyhow later be added to the first peak):
				vParams1[0] = 0.;
				// Set different center:
				vParams1[1] = 800;		// xc
				// For the second peak:
				bb = NF.Evaluate(vParams1, vY2, vX, NULL, nPts);
				if (!bb)
				{
					out_str("Failed!");
					return;
				}
			
				// Add the two up to form vY:
				// Dependent data values vector:
				vector			vY(nPts);
				vY = vY1 + vY2;
				
				// Now vX and vY contain the data values which we will use for fitting.
				
				
				//////////////////////////////////////////////////////////////////////////////
				// 2. 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;
				}
				
				
				///////////////////////////////////////////////////////////////////////////
				// 3. Setting data for fitting ////////////////////////////////////////////
				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;
				}
			
				///////////////////////////////////////////////////////////////////////////
				// 4. 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] = 4;					// y0, not shared 
				vParams[1] = 150;				// xc, not shared
				vParams[2] = 60;				// w, shared (group 1)
				vParams[3] = 5;					// A, shared (group 2)
				vParams[4] = 750;				// xc for the second peak, not shared
				nn = fit.SetParams(nNumParams, vParams);
				if ( 0 != nn )
				{
					out_str("Invalid paramater setting!");
					return;
				}
			
				// These are the expected paramater values based on the initialization in step 1.
				// (we'll use them after the fitting to compare with the obtained values):
				vector			vParamsExpected(nNumParams);
				vParamsExpected[0] = 5;					// y0, not shared 
				vParamsExpected[1] = 250;				// xc, not shared
				vParamsExpected[2] = 40;				// w, shared (group 1)
				vParamsExpected[3] = 7;					// A, shared (group 2)
				vParamsExpected[4] = 800;				// xc for the second peak, not shared
			
			
				///////////////////////////////////////////////////////////////////////////
				// 5. Fitting /////////////////////////////////////////////////////////////
				int				nMaxNumIterations = 100;
				nn = fit.Fit(nMaxNumIterations);
				printf("Fit(%ld) returned: %ld\n", nMaxNumIterations, nn);
				
				///////////////////////////////////////////////////////////////////////////
				// 6. Dump all the results and compare with what was expected /////////////
				for (int iparam = 0; iparam < nNumParams; iparam++)
				{
					printf("param index = %d   value expected = %lf   value obtained = %lf\n", iparam + 1, vParamsExpected[iparam], vParams[iparam]);
				}
				
				return;
				
			}

		
		Example2:
			/////////////////////////////////////////////////
			// This is a self-contained example of the fitting of data to two fitting functions
			// with one replica for each function (i.e. multipeak fitting with a total of 4 peaks).
			// The example creates its own data, then sets the fitting functions with the appropriately
			// set replicas number and paramater sharing between peaks, then sets the data, paramaters,
			// fits, and dumps the obtained parameter values.
			#include <origin.h>

			#include <FDFTree.h>
            #include <ONLSF.h>
            
			void	NLSF_SetFunction_ex2()
			{
				// Two functions:
				// (1) Gauss
				string			strFDF1 = okutil_get_origin_path(ORIGIN_PATH_SYSTEM, "FitFunc") + "Gauss.FDF";
				Tree			trFF1;
				if( !nlsf_FDF_to_tree( strFDF1, &trFF1 ))
					return;
				
				// (2) Lorentz
				string			strFDF2 = okutil_get_origin_path(ORIGIN_PATH_SYSTEM, "FitFunc") + "Lorentz.FDF";
				Tree			trFF2;
				if( !nlsf_FDF_to_tree( strFDF2, &trFF2 ))
					return;
				
				
				//////////////////////////////////////////////////////////////////////
				// 1. Generating data values to be later used for fitting ////////////
			
				// The total number of points:
				int				nPts = 1000;
				
				// Initalize the independent data values:
				vector			vX(nPts);
				for (int ii = 0; ii < nPts; ii++)
				{
					double		x = ii;
					vX[ii] = x;
				}
				
				vector			vParams1(4);		// 4 is the number of params in each function.
													// The parameters in both Gauss and Lorentz have the same names:
													// y0,xc,w,A 
				
				// We use the functions themselves with certain paramater values to generate
				// the dependent data so we can later test to see if the fitting proceeded correctly:
				NumericFunction	NFGauss;
				NFGauss.SetTree(trFF1);
				
				// Two auxiliary vectors for the dependent data, each for one Gauss peak:
				vector			vY1(nPts), vY2(nPts);
				vParams1[0] = 3;		// y0
				vParams1[1] = 150;		// xc
				vParams1[2] = 40;		// w
				vParams1[3] = 7;		// A
				// get the values for the first Gauss peak plus base (vParams1[0] = 3)
				// (for each element of vX one values will be generated in vY1):
				BOOL			bb = NFGauss.Evaluate(vParams1, vY1, vX, NULL, nPts);
				if (!bb)
				{
					out_str("Failed!");
					return;
				}
				
				// Set the base to 0 for the second Gauss peak (it will anyhow later be added to the first peak):
				vParams1[0] = 0.;
				// Set different center:
				vParams1[1] = 550;		// xc
				// And different width:
				vParams1[2] = 60;		// w
				// And different height:
				vParams1[3] = 5;		// A
				// For the second Gauss peak:
				bb = NFGauss.Evaluate(vParams1, vY2, vX, NULL, nPts);
				if (!bb)
				{
					out_str("Failed!");
					return;
				}
				// Add the two up to form vY:
				// Dependent data values vector:
				vector			vY(nPts);
				vY = vY1 + vY2;
			
				// Now we'll add two Lorentz peaks.
				NumericFunction	NFLorentz;
				NFLorentz.SetTree(trFF2);
				
				// Set the base to 0 for the Lorentz (it will anyhow later be added to the Gauss peaks which already
				// have the baseline accounted for):
				vParams1[0] = 0.;
				vParams1[1] = 350;		// xc, new center
				vParams1[2] = 60;		// w, the width the same as for the second Gauss peak
				vParams1[3] = 7;		// A, the same as for the first Gauss peak
				// The first Lorentz peak:
				bb = NFLorentz.Evaluate(vParams1, vY1, vX, NULL, nPts);
				if (!bb)
				{
					out_str("Failed!");
					return;
				}
				
				// The second Lorentz peak:
				vParams1[1] = 800;		// xc, new center
				vParams1[2] = 40;		// w, the width the same as for the first Gauss peak
				vParams1[3] = 5;		// A, the same as for the second Gauss peak
				// The second Lorentz peak:
				bb = NFLorentz.Evaluate(vParams1, vY2, vX, NULL, nPts);
				if (!bb)
				{
					out_str("Failed!");
					return;
				}
				
				// Add Lorentz peaks:
				vY += vY1 + vY2;
				
				// Now vX and vY contain the data values which we will use for fitting.
				
				
				//////////////////////////////////////////////////////////////////////////////
				// 2. Setting the fitting function and parameter sharing for multipeak fit  //
			
				// The fit object:
				NLFit			fit;
				
				// We will fit to a total of four peaks, two Gaussian and two Lorentzian peaks,
				// with some parameter sharing between peaks.
				// Each function will therefore have the multiplicity of 2 (i.e. one replica in each function).
				// For the conditions which the fitting functions must satisfy in order to be eligible for
				// multipeak fitting, see the sample test_NLSF_replicas().
				//
				// The first function has 4 original paramaters, 3 of which are in replicas unit.
				// Since the function will have multiplicity of 2, this means that per function
				// (i.e. for its two peaks) there are 7 paramaters:
				//		7 = replicas Offset - 1 + nFitFunctionMultiplicity * replicas unit
				// since for both Gauss and Lorentz replicas Offset = 2, replicas unit = 3
				// and we use nFitFunctionMultiplicity = 2.
				int				nFitFunctionMultiplicity = 2;
				
				// To set up parameter sharing between peaks, we use an auxiliary vector of integers:
				// First we will set the first function (Gauss).
				// The first function has 7 parameters
				vector<int>		vnSharingGroupsGauss(7);
				vnSharingGroupsGauss[0] = 0;			// y0 (baseline), not shared
				vnSharingGroupsGauss[1] = 0;			// xc for the first Gauss peak, not shared
				vnSharingGroupsGauss[2] = 1;			// w for the first Gauss peak, shared with vnSharingGroupsLorentz[4] (see below) 
				vnSharingGroupsGauss[3] = 2;			// A for the first Gauss peak, shared with vnSharingGroupsLorentz[2] (see below)
				
				vnSharingGroupsGauss[4] = 0;			// xc for the second Gauss peak, not shared
				vnSharingGroupsGauss[5] = 3;			// w for the second Gauss peak, shared with vnSharingGroupsLorentz[1] (see below)
				vnSharingGroupsGauss[6] = 4;			// A for the second Gauss peak, shared with vnSharingGroupsLorentz[5] (see below)
				// Set the Gauss fitting function with the multiplicity of 2 (i.e. one replica).
				int				nn = fit.SetFunction(trFF1, nFitFunctionMultiplicity, -1, vnSharingGroupsGauss, vnSharingGroupsGauss.GetSize());
				if (nn <= 0)
				{
					out_str("Failed setting fitting function!");
					return;
				}
				
				// The second function does not have the baseline parameter y0 (the baseline parameters are those that
				// do not belong to ther replicas unit, both Gauss and Lorentz have exactly one such paramater - y0).
				// (only one baseline makes sense and it is always associated with the first function)
				// so the total number of params for this function is 6.
				// This is the auxiliary vector of integers for specifying the parameter sharing
				// for the Lorentz peaks:
				// The
				vector<int>		vnSharingGroupsLorentz(6);
				vnSharingGroupsLorentz[0] = 0;			// xc for the first Lorentx peak, not shared
				vnSharingGroupsLorentz[1] = 3;			// w for the first Lorentz peak, shared with vnSharingGroupsGauss[5]
				vnSharingGroupsLorentz[2] = 2;			// A for the first Lorentz peak, shared with vnSharingGroupsGauss[3]
				
				vnSharingGroupsLorentz[3] = 0;			// xc for the second Lorentz peak, not shared
				vnSharingGroupsLorentz[4] = 1;			// w for the second Lorentz peak, shared with vnSharingGroupsGauss[2]
				vnSharingGroupsLorentz[5] = 4;			// A for the second Lorentz peak, shared with vnSharingGroupsGauss[6]
				// Append the Lorentz fitting function with the multiplicity of 2 (i.e. one replica).
				nn = fit.SetFunction(trFF2, nFitFunctionMultiplicity, -1, vnSharingGroupsLorentz, vnSharingGroupsLorentz.GetSize());
				if (nn <= 0)
				{
					out_str("Failed setting fitting function!");
					return;
				}
				
				
				///////////////////////////////////////////////////////////////////////////
				// 3. Setting data for fitting ////////////////////////////////////////////
				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;
				}
			
				
				///////////////////////////////////////////////////////////////////////////
				// 4. Setting paramaters //////////////////////////////////////////////////
			
				// Total number of fitting parameters is dependent on the parameter sharing between peaks.
				// It is crucial that the number of parameters as specifed
				// in the SetParams() call below agrees with the numbers of parameters in the functions and with the parameter
				// sharing as specifed in step 2.
				//
				// This is how the parameters are lined up:
				// First all the parameters for the first function. Their total number is the same as the total
				// number of parameters for one Gauss function with one replica, which is, as explained above, 7. Note
				// that there is no paramater sharing between paramaters within Gauss function peaks alone, since all
				// the values in the vector vnSharingGroupsGauss are different (with the exception of 0, which, by
				// denition, means that those parameters are not shared).
				// Now we need to add the parameters for Lorentz. The vector vnSharingGroupsLorentz has 6 elements,
				// but 4 of the 6 have nonzero values which have already appeared in vnSharingGroupsGauss (which means they
				// are shared with some paramaters in Gauss), so only 2 more parameters (vnSharingGroupsLorentz[0]
				// and vnSharingGroupsLorentz[3]) are contributed by Lorentz peaks.
				// That amounts to a total of 9.
				int				nNumParams = 9;
				
				vector			vParams(nNumParams);			// this vector should be initialized to the total number of paramaters
				// The vector vParams will be used to supply the initial values of parameters, and it will also receive
				// the parameter values after fitting.
				// The paramaters are lined up in this vector such that the first come all the parameters for the Gauss, and
				// then the additional ones for the Lorentz:
				vParams[0] = 5;			// the baseline y0 (vnSharingGroupsGauss[0])
				vParams[1] = 100;		// xc for the first Gauss peak (vnSharingGroupsGauss[1])
				vParams[2] = 60;		// w for the first Gauss peak (vnSharingGroupsGauss[2]) and for the second Lorentz peak (vnSharingGroupsLorentz[4]).
				vParams[3] = 10;		// A for the first Gauss peak (vnSharingGroupsGauss[3]) and for the first Lorentz peak (vnSharingGroupsLorentz[2]).
				vParams[4] = 500;		// xc for the second Gauss peak (vnSharingGroupsGauss[4])
				vParams[5] = 90;		// w for the second Gauss peak (vnSharingGroupsGauss[5]) and for the first Lorentz peak (vnSharingGroupsLorentz[1]).
				vParams[6] = 8;			// A for the second Gauss peak (vnSharingGroupsGauss[6]) and for the second Lorentz peak (vnSharingGroupsLorentz[5]).
				vParams[7] = 300;		// xc for the first Lorentz peak (vnSharingGroupsLorentz[0])
				vParams[8] = 700;		// xc for the second Lorentz peak (vnSharingGroupsLorentz[3])
				
				nn = fit.SetParams(nNumParams, vParams);
				if ( 0 != nn )
				{
					out_str("Invalid paramater setting!");
					return;
				}
				
				// These are the expected paramater values based on the initialization in step 1.
				// (we'll use them after the fitting to compare with the obtained values):
				vector			vParamsExpected(nNumParams);
				vParamsExpected[0] = 3;					// the baseline y0 
				vParamsExpected[1] = 150;				// xc for the first Gauss peak
				vParamsExpected[2] = 40;				// w for the first Gauss peak and for the second Lorentz peak
				vParamsExpected[3] = 7;					// A for the first Gauss peak and for the first Lorentz peak
				vParamsExpected[4] = 550;				// xc for the second Gauss peak
				vParamsExpected[5] = 60;				// w for the second Gauss peak and for the first Lorentz peak
				vParamsExpected[6] = 5;					// A for the second Gauss peak and for the second Lorentz peak
				vParamsExpected[7] = 350;				// xc for the first Lorentz peak
				vParamsExpected[8] = 800;				// xc for the second Lorentz peak
			
			
				///////////////////////////////////////////////////////////////////////////
				// 5. Fitting /////////////////////////////////////////////////////////////
				int				nMaxNumIterations = 100;
				nn = fit.Fit(nMaxNumIterations);
				printf("Fit(%ld) returned: %ld\n", nMaxNumIterations, nn);
				
				
				///////////////////////////////////////////////////////////////////////////
				// 6. Dump all the results and compare with what was expected /////////////
				for (int iparam = 0; iparam < nNumParams; iparam++)
				{
					printf("param index = %d   value expected = %lf   value obtained = %lf\n", iparam + 1, vParamsExpected[iparam], vParams[iparam]);
				}
				
				return;
			}

	*/
	int			SetFunction(TreeNode &trFF, int nMultiplicity = 1, int nIndex = -1, int *pnSharing = NULL, int nCountSharing = 0);

	/// ML 3/26/2008 QA70-11314 CHANGING_MULTIPLICITY_ONLY
	/**$
			It sets the multiplicity and sharing groups of a function which has previously been added. It will work only
			if the current number of functions set is 1.
			Parameters have the meanings as the corresposning parameters in the method SetFunction().
			Note that the method resets the parameters which may have been set previously. So, the caller will
			have to set parameters again after calling this method.
		Returns:
			0 if OK, otherwise it returns an error value as a nagative number.
	*/
	int			SetFunctionMultiplicity(int nMultiplicity = 1, int *pnSharing = NULL, int nCountSharing = 0);
	/// end CHANGING_MULTIPLICITY_ONLY

	//------ Folger 05/06/08 ADD_SET_FUNCTIONS_METHOD_TO_OCNLFIT
	int			SetFunctions(NLParametersManager &mngr);
	//------

	//------ Folger 05/06/08 ADD_SET_PARAMS_METHOD_WITH_NLPARAMETERMANAGER_TO_OCNLFIT
	int			SetParams(NLParametersManager &mngr, bool bLoadBoundsFromFunctions = true);
	//------

	//------ Folger 11/11/08 v8.0968 UPDATE_PARAMETERS_LINKING_IN_NLFIT_OBJECT
	/**
		One NLParametersManager object can only have one NLFit object, however, during fitting, more than one NLFit objects can be used for
		multiple datas case. After switch NLFit objects in NLParametersManager to do fitting, the internal linking between them will be broken.

		Report generation needs to get proper parameters settings(values, fixed, shared), so, UpdateParamsLinking will establish correct
		linking between NLFit and NLParametersManager, make sure NLFit object "has" proper parameter settings.

		See Hong 11/10/08 QA80-12329 FIX_CONFIDENCE_BAND_ONLY_ONE_RESULT_FOR_SEPARATE_FIT_CONSOLIDATE_REPORT
	*/
	int			UpdateParamsLinking(NLParametersManager &mngr);
	//------

	/// ML 10/16/2007 QA70-10543 SETTING_UP_FUNCTIONS_SHARING_ETC_FOR_MULTIPEAK_FITTING
	/**$
			Sets up multiple fitting functions for multipeak fitting via tree. It also fills the vectors of parameter values and of
			the array of fixed bools by taking values from the tree.
			Optionally, it performs necessary updated on editing events.
		Parameters:
			tree=[input]the tree to set
			vrValues=[output] it will contain on output the parameter values from the tree. The size will be equal to the actual number
						of parameters after taking into account sharing groups between peaks.
			vbFixed=[output]the vector of the same size as vrValues, indicating which parameters should be fixed.
			pst=[input,output]if editing event or another type of information retrieval needed, it provides addtionla information.
		Returns:
			0 if OK, otherwise it returns an error value as a nagative number.
	*/
	int			SetFunctionsMultipeakFitting(TreeNode &tree, vector &vrValues, vector<bool> &vbFixed, ONLSF8MLTPEAKS *pst = NULL,
							vector *pvrLowerBounds = NULL, vector *pvrUpperBounds = NULL, vector<bool> *pvbLowerBoundsExcl = NULL, vector<bool> *pvbUpperBoundsExcl = NULL);
	/// end SETTING_UP_FUNCTIONS_SHARING_ETC_FOR_MULTIPEAK_FITTING

	
	/// TD 3-13-07 QA70-9473 OC_CALLBACK_FOM_NLFIT
	/**
		Sets a call back object for NLFit, wich  receives calls from the fitter.
 		Parameters:
			objCallBack= holds the object which handles the call
	*/
	void		SetCallback(ClassObject objCallBack);
	/// end OC_CALLBACK_FOM_NLFIT
	//comments last updated by Cheney on 03/27/06
	/**
			Sets the data - dependent, independent and, optionally, weights, The number of each type of variables
			must be consistent with the fitting functions previously set.
		Parameters:
			nNumberDatasetSets=[input]number of dataset sets. One dataset set is comprised of all the dependent and all the dependent variables
								supported by the fitting functions currently in the object. Example: if the function is Gauss (comes
								from Gauss.fdf), which has one dependent and one independent variable, then one dataset set has
								one data for dependent, one data for independent, and, (optionally) one weight specification.
			pstDependentData=[input]points to an array of nNumberDatasetSets*numberoffunctiondependents NLSFONEDATA structures holding pointers
								to data for all the dependents.
			pstdIndependentData=[input]points to an array of nNumberDatasetSets*numberoffunctionIndependents NLSFONEDATA structures holding pointers
								to data for all the independents.
			pWeightDesc=[input][optional] points to an array of nNumberDatasetSets*numberoffunctiondependents ONEDATAWEIGHT structures that describe the
								weighting for each dependent. If NULL, there are no weights.
		Returns:
			0 if OK, otherwise nonzero.
		Example1:
			// The example demonstrates fitting of TWO datasets simultaneously
			// with some shared paramaters.
			// The example first generates data using the function later used for fitting, so
			// that the fitting results can be checked against the expected values.
			// The function in the example, Gauss2D, has ONE dependent and TWO independent variables.
			// It has SIX paramaters. Three of those SIX paramaters are set as being shared during
			// the fitting, making the total number of fitting paramaters to NINE.
			// Since each dataset has 2500 points, the example may take a few minutes to execute.
			#include <origin.h>
			
			#include <FDFTree.h>
			#include <ONLSF.h>
			
			
			void	NLFit_SetData_ex1()
			{
				string			strFDF = okutil_get_origin_path(ORIGIN_PATH_SYSTEM, "FitFunc")+"Gauss2D.FDF";
				Tree			trFF;
				if( !nlsf_FDF_to_tree( strFDF, &trFF ))
					return;
				
				////////////////////////////////////////////////////////////////////
				// 1. Generate data values to be later used for fitting:
				
				// We use the function itself with certain paramater values so we can later test to see
				// if the fitting proceeded correctly:
				NumericFunction	NF;
				NF.SetTree(trFF);
			
				// Initalize the independent data values for both dataset sets:
				int			nXDirPts = 50, nYDirPts = 50;
				int			nTotalPts = nXDirPts * nYDirPts;
			
				// vx1 and vy1 are the indepedent data for the first set, vx2 and vy2 are independent data
				// for the second set.
				// vz1 is the dependent data for the first set, vz2 is the dependent data for the second set.  
				vector		vz1, vy1, vx1, vz2, vy2, vx2;
				vx1.SetSize(nTotalPts);
				vy1.SetSize(nTotalPts);
				
				vx2.SetSize(nTotalPts);
				vy2.SetSize(nTotalPts);
			
				for (int row = 0, ipt = 0; row < nXDirPts; row++)
				{
					double			rX = row / 5.;
					for (int col = 0; col < nYDirPts; col++, ipt++)
					{
						double		rY = col / 5.;
						vx1[ipt] = rX;
						vy1[ipt] = rY;
						
						vx2[ipt] = rX + 5.;
						vy2[ipt] = rY - 5.;
					}
				}
				
				// Prepare the buffer to receive the z data values (it should have the same number of points
				// as vx and vy)
				vz1.SetSize(nTotalPts);
				vz2.SetSize(nTotalPts);
			
				int			numParamsInFunction = 6;		// there are this many paramaters in the function
				
				// Parameter values for generating x,y,z data values
				// for the first dataset set (i.e. for the first dependent)
				vector		vParams1;
				vParams1.SetSize(numParamsInFunction);
				// Names = z0,A,xc,w1,yc,w2
				vParams1[0] = 3.;		// z0
				vParams1[1] = 3.;		// A
				vParams1[2] = 5.;		// xc
				vParams1[3] = 1.;		// w1
				vParams1[4] = 5.;		// yc
				vParams1[5] = 3.;		// w2
				
				// Initialize the z-values for the first set:
				BOOL			bb = NF.Evaluate(vParams1, vz1, vx1, vy1, nTotalPts);
				if (!bb)
				{
					out_str("Failed!");
					return;
				}
			
				// Parameter values for generating x,y,z data values
				// for the second dataset set (i.e. for the second dependent)
				vector		vParams2;
				vParams2.SetSize(numParamsInFunction);
				// Names = z0,A,xc,w1,yc,w2
				vParams2[0] = 4.;		// z0
				vParams2[1] = 3.;		// A
				vParams2[2] = 8.;		// xc
				vParams2[3] = 1.;		// w1
				vParams2[4] = 1.;		// yc
				vParams2[5] = 3.;		// w2
			
				// Initialize the z-values for the second set:
				bb = NF.Evaluate(vParams2, vz2, vx2, vy2, nTotalPts);
				if (!bb)
				{
					out_str("Failed!");
					return;
				}
				
				/////////////////////////////////////////////////////////////////////////////
				// 2. Fitting:
				
				NLFit			fit;
				
				//// 2.1. Setting the function:
				int				nn = fit.SetFunction(trFF);
				out_int("SetFunction() returned: ", nn);
			
				//// 2.2 Setting the data:
				// 2.2.1. The number of dataset sets:
				int				nNumDatasetSets = 2;
				
				// 2.2.2. The dependent:
				NLSFONEDATA		arrstDep[2];
				// First set:
				arrstDep[0].pdData = vz1;
				arrstDep[0].nSize = vz1.GetSize();
				// Second set:
				arrstDep[1].pdData = vz2;
				arrstDep[1].nSize = vz2.GetSize();
			
				// 2.2.3. The independents:
				NLSFONEDATA		arrstIndep[4];
				// First set:
				arrstIndep[0].pdData = vx1;
				arrstIndep[0].nSize = vx1.GetSize();
				arrstIndep[1].pdData = vy1;
				arrstIndep[1].nSize = vy1.GetSize();
				// Second set:
				arrstIndep[2].pdData = vx2;
				arrstIndep[2].nSize = vx2.GetSize();
				arrstIndep[3].pdData = vy2;
				arrstIndep[3].nSize = vy2.GetSize();
				
				nn = fit.SetData(nNumDatasetSets, arrstDep, arrstIndep);
				out_int("SetData() returned: ", nn);
				if (nn != 0)
				{
					out_str("SetData() failed!");
					return;
				}
				
				//// 2.3. Initial paramater values:
				vector			vParams;			// this array should be initialized to the total number of paramaters
													// in the fit, taking into account paramater sharing (if any)
													
				// We will set three paramaters, A, w1 and w2, as being shared. First prepare the vector of bools which
				// we will use to tell the NLFit object which parameters of the function are shared (note that
				// if there were no shared paramaters, then this vector wouldn't be needed):
				vector<bool>	vbSharing;
				vbSharing.SetSize(numParamsInFunction);
				vbSharing[0] = false;
				vbSharing[1] = true;
				vbSharing[2] = false;
				vbSharing[3] = true;
				vbSharing[4] = false;
				vbSharing[5] = true;
				
				// The total number of parameters
				// in the fit should be the first term are all the parameters for the first set, including
				// both shared and nonshared, followed by nonshared paramaters for the remaining set(s)):
				int				nTotalParams = numParamsInFunction + (numParamsInFunction - 3);
				vParams.SetSize(nTotalParams);
				// First set all the values from the first set:
				for (int iparam = 0; iparam < numParamsInFunction; iparam++)
				{
					vParams[iparam] = vParams1[iparam];
				}
				
				// Now set the remaining nonshared from the second set (those for which vbSharing is false):
				vParams[numParamsInFunction] = vParams2[0];			// z0 of the second set
				vParams[numParamsInFunction + 1] = vParams2[2];		// xc of the second set
				vParams[numParamsInFunction + 2] = vParams2[4];		// yc of the second set
			
				// We will use vParams as a reference vector so we can after fitting compare the obtained
				// parameter values with the desired paramater values. We will use vector vFitParams
				// to pass the initial paramater values, as well as the receive the paramater results:
				vector			vFitParams;
				vFitParams.SetSize(nTotalParams);
				// Since there is no call to paramater initialization code here, use the above parameter
				// values with some perturbation as the initial values:
				double			rPerturbFactor = 0.2;		// 30%
				for (iparam = 0; iparam < nTotalParams; iparam++)
				{
					int			nPerturbationSign = (iparam % 2) ? 1 : -1;
					vFitParams[iparam] = vParams[iparam] * (1. + nPerturbationSign * rPerturbFactor);
				}
			
				// Set the initial paramater values and the sharing information:
				nn = fit.SetParams(nTotalParams, vFitParams, vbSharing);
				out_int("SetParams() returned: ", nn);
				if ( 0 != nn )
				{
					out_str("Invalid paramater setting!");
					return;
				}
			
				//// 2.4. Perform fitting:
				int				nMaxNumIterations = 100;
				nn = fit.Fit(nMaxNumIterations);
				printf("Fit(%ld) returned: %ld\n", nMaxNumIterations, nn);
				
				/////////////////////////////////////////////////////////////////////////////
				// 3. Dump results:
				for (iparam = 0; iparam < nTotalParams; iparam++)
				{
					printf("param index = %d   value should be = %lf  value is = %lf\n", iparam + 1, vParams[iparam], vFitParams[iparam]);
				}
				
				return;
			}
	*/
	int			SetData(int nNumberDatasetSets, NLSFONEDATA *pstDependentData, NLSFONEDATA *pstdIndependentData, ONEDATAWEIGHT *pWeightDesc = NULL);
	
	/**
			Sets initial paramater values, parameter sharing and fixing.
		Parameters:
			nNumParamValues=[input]total number of paramaters. This number must agree with the the number of paramaters in the functions
							currently held by the object, and the paramater sharing (see pbShared argument).
			pdParamValues=[input]pointer to nNumParamValues initial paramater values. The paramater are arranged like this: first all the
							parameters (both nonshared and shared) for the first dataset set (in the order of appearance in the 
							functions held in the object), followed by nonshared paramaters for additional dataset sets (if any).
			pbShared=[input][optional] pointer to an array of bool's whose size is equal to the total number of all function (one set) paramaters,
							which specifies which paramaters should be shared. If NULL, no paramaters are shared.
			pbFixed=[input][optional] pointer to an array of bool's whose size is equal to nNumParamValues, specifying which paramaters should be kept
							fixed during fitting. If NULL, no parameters are fixed.
			bLoadBoundsFromFunctions=[input][optional]whether to load the lower and upper bounds from the previously set functions automatically.
		Returns:
			0 if OK, otherwise nonzero.
	*/
	int			SetParams(int nNumParamValues, double *pdParamValues, bool *pbShared = NULL, bool *pbFixed = NULL, bool bLoadBoundsFromFunctions = true);
	
	/**
			Sets parameters bounds. The parameters bounds are arranged in the same order as in in the call to SetParams. Note that if this
			function is not called, the bounds values will be those from the function definition file (tree).
		Parameters:
			bUpper=[input]TRUE for upper bounds, FALSE for lower bounds.
			pdBoundsValues=[input]pointer to nNumBounds doubles holding bounds values. If a bound is absent, the corresponding value should be NANUM.
			pbExclusive=[input]an array of nNumBounds bool values. For each bound it is true if exclusive, otherwise false.
			nNumBounds=[input]total number of bounds in the arrays pdBoundsValues and pbExclusive. It can be less then the total number of
						parameters. In that case, the bounds beyond nNumBounds will be treated as absent (not set).
		Returns:
			TRUE if OK, otherwise FALSE.
	*/
	BOOL		SetParametersBounds(BOOL bUpper, double *pdBoundsValues, bool *pbExclusive, int nNumBounds);
	/**
			Gets parameters bounds. The parameters bounds will be arranged in the same order as in in the call to SetParams.
		Paramaters:
			bUpper=TRUE for upper bounds, FALSE for lower bounds.
			pdBoundsValues=[output]pointer to nNumBounds doubles to receive bounds values. If a bound is absent, the corresponding value will be NANUM.
			pbExclusive=[output]an array of nNumBounds bool values to receive exclusive setting. For each bound it will be true if exclusive, otherwise false.
			nNumBounds=total size of buffers pdBoundsValues and pbExclusive. It can be less then the total number of
						parameters.
		Returns:
			TRUE if OK, otherwise FALSE.
	*/
	BOOL		GetParametersBounds(BOOL bUpper, double *pdBoundsValues, bool *pbExclusive, int nNumBounds);
	
	/**
			Runs at most nMaxNumIterations Levenberg-Marquardt iterations.
		Parameters
			nMaxNumIterations=the maximum number of iterations to run.
			pnNumberItersPerformed=[output,optional]it receives the actual number of iteratons performed.
			pnIterOutcome=[output,optional]it receives the code describing the outcome of the iterative procedure.
							Possible values are from the FITITER enumeration. 
			objCallBack = [optional]contains a reference to the Object which must receive calls back from the fitter
			nMethod=[optional]which iterative procedure to use:
					FITMETH_LEVENBERG_MARQUARDT = Levenberg-Marquardt
					FITMETH_SIMPLEX = Simplex
		Returns:
			0 if OK.
	*/
	//------ Folger 12/10/08 QA80-12751 v8.0984d SUPPORT_ALWAYS_GENERATE_OUTPUTS_REGARDLESS_OF_INTERATION_IN_PA_FITTING
	//int			Fit(int nMaxNumIterations, int *pnNumberItersPerformed = NULL, int *pnIterOutcome = NULL, ClassObject &objCallBack = NULL, int nMethod = FITMETH_LEVENBERG_MARQUARDT);
	int			Fit(int nMaxNumIterations, int *pnNumberItersPerformed = NULL, int *pnIterOutcome = NULL, ClassObject &objCallBack = NULL, int nMethod = FITMETH_LEVENBERG_MARQUARDT, DWORD dwOption = 0);
	//------
	
	/**
			Retrieves the paramater results of the fitting.
		Paramaters:
			pvValues=[output][optional]receives the paramater values.
			pvErrors=[output][optional]receives the paramater error values.
			pvConfLimits=[output][optional]receives the paramater confidence limits.
			pvDependencies=[output][optional]receives the paramater dependencies.
		Returns:
			0 if OK.
	*/
	int			GetParameterResults(vector *pvValues, vector *pvErrors = NULL, vector *pvConfLimits = NULL, vector *pvDependencies = NULL);
	
	/**
				Computer the upper and lower confidence limits .
		Parameters:
			pvConfLower=[output]pointer to a vector receives the lower confidence limits.
			pvConfUpper=[output]pointer to a vector receives the upper confidence limits.
			nMethod=[input]method to compute confidence limits, enumerated as CONF_LIMIT_METHOD_AS_BASED, CONF_LIMIT_METHOD_MODLE_COMP_BASED, etc
		Returns:
			0 if OK.
	*/
	//------ Folger 10/15/08 MOVE_COMPUTE_CONFIDENCE_LIMITS_METHODS_INTO_VC
	//int			ComputeParametersConfidenceLimits(vector *pvConfLower, vector *pvConfUpper);
	int			ComputeParametersConfidenceLimits(vector *pvConfLower, vector *pvConfUpper, int nMethod = CONF_LIMIT_METHOD_AS_BASED);
	//------ End MOVE_COMPUTE_CONFIDENCE_LIMITS_METHODS_INTO_VC

	/**
			Retrieves the paramater results of the fitting. The method will also compute the lower and upper paramater confidence,
			which may be slow.
		Paramaters:
			pstParametersResults=[output]pointer to an array of FitParameter structures (the size must not be smaller than the total
									number of parameters). If NULL, it will only compute the lower and upper confidence of parameters. So,
									the method has to be called at least once with this argument being NULL (in which case
									the second argument does not matter) in order to evaluate lower and upper confidence of parameters.
			nSetIndex=[input]the set index whose results are to be retrieved, or -1 to retrieve all.
		Returns:
			0 if OK.
	*/
	//------ Folger 10/10/08 GET_ALL_NON_TRIMMED_PARAMETERS_RESULTS_FOR_MULTIPLE_PEAKS_FITTING
	//int			GetParameterResults(FitParameter *pstParametersResults, int nSetIndex = -1);
	int			GetParameterResults(FitParameter *pstParametersResults, int nSetIndex = -1, BOOL bTrimShareMultiPeaks = TRUE);
	//------

	/**
			Retrieves the summary fit results.
		Paramaters:
			pstRegStats=[output]pointer to the structure RegStats which will receive a part of results.
			pstNLSFFitInfo=[output]pointer to the structure NLSFFitInfo which will receive a part of results
		Returns:
			0 if OK.
	*/
	int			GetSummaryFitResults(RegStats *pstRegStats, NLSFFitInfo *pstNLSFFitInfo);

	/**
			Retrieves the fit statistics per dataset
		Paramaters:
			pstRegStatsPerDataset=[output]pointer to the structure RegStatsPerDataset which will receive the results.
			nSetIndex=[input]the index of the dataset set
			nDepIndex=[input]the index of the dependent variable
		Returns:
			0 if OK.
	*/
	int			GetFitResultsPerDataset(RegStatsPerDataset *pstRegStatsPerDataset, int nSetIndex, int nDepIndex);
	
	/// Arvin 03/30/07 GET_ANOVA_RESULT_WITH_DIFF_WEIGHT_METHOD
	/**
			Get the ANOVA results.
		Paramaters:
			pstRegANOVA = [output]pointer to the structure RegANOVA which will receive a part of results.
			psCorrTotal = [output]pointer to the structure RegANOVARow which will receive the correct total row.
			nSetIndex = [input]the set index whose results are to be retrieved
			nDepIndex = [input] the dependent variable index 
		Returns:
			0 if OK.
	*/
	int			GetANOVAResults(RegANOVA *pstRegANOVA, RegANOVARow *psCorrTotal, int nSetIndex, int nDepIndex = 0);
	/// end  GET_ANOVA_RESULT_WITH_DIFF_WEIGHT_METHOD

	/**
			Retrieves the names and/or values of optional derived parameters according to their definitions in
			the FDF files of the fitting function(s) uses in fitting. The derived parameters must depend
			on the values of the actual fitting parameters and can be evaluated successfully only after
			the fitting has been completed.
			The derived parameter names and formulas for their evaluation should be specified in the
			"Derived Parameters" section of the FDF file. Example:
				[Derived Parameters]
				firstder=10.*xc
				secondder=w/10.
		Parameters:
			nSetIndex=[input]the dataset set index for which the derived parameter values are evaluated.
			pvstrNames=[ouput][optional] the vector of strings to receive the names of the derived parameters
			pvValues=[output][optional] the vector of doubles to receive the evaluated values of derived parameters.
		Returns:
			If failure, it returns a negative number, otherwise it returns the total number of derived
			parameters. If both pvstrNames and pvValues are NULL, then that's all the function does,
			in which case it is sufficient to call the function only once, with nSetIndex = 0, since
			the total number of derived parameters does not depend on the set index.

	*/
	///Kyle 08/06/2009 QA80-14077 ADD_UNIT_FOR_PARAMETER_SETTINGS
	//int			GetDerivedParameters(int nSetIndex, vector<string> *pvstrNames, vector *pvValues = NULL);
	int			GetDerivedParameters(int nSetIndex, vector<string> *pvstrNames, vector *pvValues = NULL, vector<string> *pvstrUnits = NULL);
	///End ADD_UNIT_FOR_PARAMETER_SETTINGS
	
	
	/**
			It resets the object.
		Paramaters:
			nWhat=what to reset. The values are taken from the enumeration:
				enum {
					ONLSF8RESET_ALL						= 0,		// reset everything
					ONLSF8RESET_FUNCTIONS,							// reset everything
					ONLSF8RESET_DATA,								// reset paramaters and data
					ONLSF8RESET_PARAMETERS,							// reset paramaters
				};
		Returns:
			None

	*/
	void		Reset(int nWhat = ONLSF8RESET_ALL);


	/**
			It sets/gets various options that affect multipeak fitting.
		Parameters:
			the value is drawn from the enumeration:
			enum {
				PEAKSMODE_MULTIPEAK_CENTERS_HANDLING,			// it makes the fitting routine employ a special peak center bounds
																// adjustment during iterative procedure.
																// For this to work properly, each fitting function that is responsible
																// for peaks must designate in its .FDF file the parameters for the peak
																// center and for the peak width. They should in the [CONTROLS] section
																// be designated like this:
																Peak Center=2
																Peak Width=3
																// where the numbers indicate the parameter indices for the center and the with
																// of a peak. If these entries are absent from the .FDF file, the default
																// values 2 and 3 are assumed for the center and the width.
				PEAKSMODE_SKIP_FIRST_FUNCTION				= 0x00020000UL,	// used only if PEAKSMODE_MULTIPEAK_CENTERS_HANDLING is on.
																			// if on, then the first function added (see the method SetFunction())
																			// is not considered to provide a peak, which means its
																			// parameters are ignored when doing special peak center bounds
																			// adjustment. This bit would normally be used if the first
																			// function is a baseline.
			};

	*/
	DWORD		MultipeakOptions;


	/// ML 8/25/2006 NLFIT_MULTIDEPS_WEIGHTS_OC_WORK
	/**
			It returns the number of dependent variables in the currently set fitting function(s).
		Parameters:
			psarrNames=[output][optional]it receives the variable names
		Return:
			The number of dependent variables
	*/
	int			GetNumDependents(StringArray *psarrNames = NULL);

	/**
			It returns the number of independent variables in the currently set fitting function(s).
		Parameters:
			psarrNames=[output][optional]it receives the variable names
		Return:
			The number of independent variables
	*/
	int			GetNumIndependents(StringArray *psarrNames = NULL);
	/// end NLFIT_MULTIDEPS_WEIGHTS_OC_WORK

	/// ML 5/4/2007 QA70-8886 ONLSF8_RETURN_VAR_COVAR_MATRIX
	/**
			It provides the variance-covariance matrix.
		Parameters:
			pmVarCovar=[output]it receives the values of the variance-covariance matrix
			bScaleWithChiSq=[input,optional]whether to scale elements of the matrix with chi-sq or not.
		Return:
			0 if OK.
	*/
	int			GetVarCovarMatrix(matrix *pmVarCovar, BOOL bScaleWithChiSq = FALSE);
	/// end ONLSF8_RETURN_VAR_COVAR_MATRIX

	///Arvin 05/08/07 QA70-9498 ONLSF8_GET_VAR_CORRE_MATRIX
	/**
			It provides the variance-correlation matrix.
		Parameters:
			pmVarCorr=[output]it receives the values of the variance-correlation matrix
			bScaleWithChiSq=[input,optional]whether to scale elements of the covariance matrix with chi-sq or not.
		Return:
			0 if OK.
	*/
	int			GetVarCorrMatrix(matrix *pmVarCorr, BOOL bScaleWithChiSq = FALSE);
	/// end ONLSF8_GET_VAR_CORRE_MATRIX


	/// ML 6/1/2007 GENERAL_LINEAR_CONSTRAINTS_MOVING_FROM_OLD_FITTER
	/**
			Used to enable/disable the usage of general linear constraints (GLC) in fitting.
			GLCs will be used if they are present and enabled in the fitting function (.FDF file) and this property is TRUE.
			If GLCs are either not present or are not enabled in the fitting function, then this property is not used.
			By default it is TRUE.
	*/
	BOOL		m_bGLCsEnabled;
	/// end GENERAL_LINEAR_CONSTRAINTS_MOVING_FROM_OLD_FITTER


	/// ML 6/18/2007 SETTING_GLCS_FROM_OC
	/**
			Sets the General Linear Constraints string into the fitting function inside the object.
			It must be called after the fitting function has already been set.
		Parameters:
			lpcszGLCs=the pointer to the string containing the General Linear Constraints to set.
		Returns:
			TRUE if OK, otherwise FALSE.
	*/
	BOOL		SetGLCs(LPCSTR lpcszGLCs);
	/// end SETTING_GLCS_FROM_OC

	///Arvin 01/11/08 QA70-10923 CALC_CONFIDENCE_AND_PREDICTION_BANDS
	///Jack 10/16/08 QA70-10923 CALC_CONFIDENCE_AND_PREDICTION_BANDS_FOR_GLOBAL_FIT
	//BOOL		CalcConfAndPredBands(NLSFONEDATA* pstIndep, int nNumIndep, double rPerc, double *pLower, double *pUpper, BOOL bConf = TRUE, int iDep = 0);
	BOOL		CalcConfAndPredBands(NLSFONEDATA* pstIndep, int nNumIndep, double rPerc, double *pLower, double *pUpper, BOOL bConf = TRUE, int iDep = 0, int iSet = 0);
	///End CALC_CONFIDENCE_AND_PREDICTION_BANDS_FOR_GLOBAL_FIT
	///end 	 CALC_CONFIDENCE_AND_PREDICTION_BANDS

	///Arvin 01/18/2008 QA70-8365 SUPPORT_2D_PEAK_CENTERS_HANDLING
	BOOL		SetDataSteps(NLSF8DATASTEP* pstDataSteps, int nNumDataSet);
	BOOL		SetIterationSettings(PNLSF8ITERATIONSETTINGS pst);
	///end 	SUPPORT_2D_PEAK_CENTERS_HANDLING

};

// Comments last updated by Joseph	on 04/09/07
/**# >Analysis
	The NumericFunction class provides methods and properties for numerical calculation of a function which 
	is converted from a FDF tree. This class is often used together with the NLFit class.

	Example1:
		#include <origin.h>

		#include <FDFTree.h>
        #include <ONLSF.h>
        
		void NumericFunction_ex1()
		{
			string		strFDF = okutil_get_origin_path(ORIGIN_PATH_SYSTEM, "FitFunc")+"Gauss.FDF";
			Tree tr;
			if( !nlsf_FDF_to_tree( strFDF, &tr ))
				return;
			
			NumericFunction	NF;
			if(!NF.SetTree(tr))
			{
				out_str("Invalid function");
				return;
			}
			
			vector vx, vy, vParas;
			vParas.SetSize(4);
			vParas[0] = 3.;		// y0
			vParas[1] = 5.;		// xc
			vParas[2] = 2.5;	// w
			vParas[3] = 2.;		// A
			
			vx.Data(0., 10., 0.1);
		
			int				nNumPts = vx.GetSize();
			// Prepare the buffer to receive the results (it should have the same number of points
			// as vx)
			vy.SetSize(nNumPts);
			
			BOOL			bb = NF.Evaluate(vParas, vy, vx, NULL, nNumPts);
			if (!bb)
			{
				out_str("Failed!");
				return;
			}
		
			// Create the worksheet which is to receive the results:
			Worksheet		wks;
			wks.Create("Origin");
		
			// Put the X and the Y values into the worksheet:
			
			DataRange dr;
			dr.Add("", wks, 0, 0, -1, 0);
			dr.Add("", wks, 0, 1, -1, 1);
			
			dr.SetData(vx, false, 0);
			dr.SetData(vy, false, 1);
		}
	
	Example2:
		#include <origin.h>
		
		#include <ONLSF.h>
		#include <fdftree.h>
		
		void NumericFunction_ex2(string strFunctionName = "Gauss")
		{
			// first we need to use some data, assume A(x) B(y) of
			// active wks to test function for param init
			Worksheet wks = Project.ActiveLayer();
			if(!wks)
			{
				out_str("No active wks");
				return;
			}
		
			DataRange dr;
			dr.Add("X", wks, 0, 0, -1, 0); 
			dr.Add("Y", wks, 0, 1, -1, 1); 
			// we will copy into vector, so we know for sure it works with just vectors
			vector vX , vY ;
			dr.GetData(vX, 0);
			dr.GetData(vY, 1);
			
			
			string strCategoryName;
			string strFullPath;
			string strFDF = nlf_get_fdf_filename(strFunctionName, &strCategoryName, NULL, &strFullPath);
			if(strFDF.IsEmpty())
			{
				out_str("failed to find FDF");
				return;
			}
			Tree trFDF;
			if( !nlsf_FDF_to_tree( strFullPath, &trFDF ))
			{
				out_str("failed to load FDF");
				return;
			}
			//success in getting FDF tree
			NumericFunction fn;
			fn.SetTree(trFDF);
			
			vector vParams;
			int nErr;
			if(!fn.ParamInit(vParams, vX, vY, nErr))
				out_int("err code = ", nErr);
			else
				out_str("done");
			
		}
*/ 

class	NumericFunction
{
public:
	NumericFunction();
	NumericFunction(TreeNode &trFF);
	
public:
	
	//comments last updated by Cheney on 03/27/06
	//comments last updated by Roy on 02/21/06
	/**
		It initializes a function according to the tree obtained from an .FDF file.
	Paramaters:
		tr=[input]the function tree.
	Returns:
		TRUE for success, otherwise FALSE.
	Example1:
		#include <origin.h>

		#include <FDFTree.h>
        #include <ONLSF.h>
        
		void		NumericFunction_SetTree_ex1()
		{
			// Here put the correct pathname of the .FDF file:
			string			strFile = okutil_get_origin_path(ORIGIN_PATH_SYSTEM, "FitFunc")+"Gauss.FDF";
			Tree			trFF;
			if( !nlsf_FDF_to_tree(strFile, &trFF) )
			{
				out_str("Invalid function file");
				return;
			}
			
			NumericFunction	func;
			if (!func.SetTree(trFF))
			{
				out_str("Invalid function");
				return;
			}
		}
	*/
	BOOL			SetTree(TreeNode &tr);
	
	//comments last updated by Cheney on 03/27/06
	//comments last updated by Roy on 02/21/06
	/**
		Evaluates one function value for the function of one independent and one
		dependent variable..
	Paramaters:
		x=[input]the value of the independent variable.
		params=[input]the vector of parameter values. It must have the size equal to the number of paramaters
		of the function.
	Returns:
		the dependent value of the function.
	Example1:
	    #include <origin.h>

		#include <FDFTree.h>
        #include <ONLSF.h>
        
		void		NumericFunction_Evaluate_ex1()
		{
			// Here put the correct pathname of the .FDF file:
			string			strFile = okutil_get_origin_path(ORIGIN_PATH_SYSTEM, "FitFunc")+"Gauss.FDF";
			Tree			trFF;
			if( !nlsf_FDF_to_tree(strFile, &trFF) )
			{
				out_str("Invalid function file");
				return;
			}
			
			NumericFunction	func;
			if (!func.SetTree(trFF))
			{
				out_str("Invalid function");
				return;
			}
			
			int				nNumParams = func.NP;
			out_int("Number of paramaters = ", nNumParams);
			
			vector			vParams(nNumParams);
			
			vParams[0] = 7.5;	// y0
			vParams[1] = 0.15;	// xc
			vParams[2] = 5.5;	// w
			vParams[3] = 3;		// A
			
			double			valX = 0.15;
			double			valResult = func.Evaluate(valX, vParams);
			
			printf("indep. value = %lf\tdep. value = %lf\n", valX, valResult);
			
		}
	*/
	double			Evaluate(double x, vector& params);
	
	//comments last updated by Cheney on 03/27/06
	//comments last updated by Roy on 02/21/06
	/**
		Evaluates a vector of function values for the function of one independent and one
		dependent variable. The value is computed for each element of the input vector vx and results
		are put into the return vector.
	Parameters:
		vx=[input]vector of value of independent variables.
		params=[input]the vector of parameter values. It must have the size equal to the number of paramaters
		of the function.
	Returns:
		the vector of dependent values of the function.
	Example1:
		#include <origin.h>

		#include <FDFTree.h>
        #include <ONLSF.h>
        
		void		NumericFunction_Evaluate_ex1()
		{
			string			strFile = okutil_get_origin_path(ORIGIN_PATH_SYSTEM, "FitFunc")+"Gauss.FDF";
			
			Tree			trFF;
			if( !nlsf_FDF_to_tree(strFile, &trFF) )
			{
				out_str("Invalid function file");
				return;
			}
			
			NumericFunction	func;
			if (!func.SetTree(trFF))
			{
				out_str("Invalid function");
				return;
			}
			
			int				nNumParams = func.NP;
			out_int("Number of paramaters = ", nNumParams);
			
			vector			vParams(nNumParams);
			
			vParams[0] = 7.5;	// y0
			vParams[1] = 0.15;	// xc
			vParams[2] = 5.5;	// w
			vParams[3] = 3;		// A
			
			// Independent values:			
			vector			vx;
			vx.Data(-10., 10, 1.0);
			
			vector			vy;
			
			vy = func.Evaluate(vx, vParams);
		
			int				nSize = vy.GetSize();
			for (int ii = 0; ii < nSize; ii++)
			{
				printf("%lf\t%lf\n", vx[ii], vy[ii]);
			}
		}
	*/
	vector			Evaluate(vector& vx, vector& params);

	//comments last updated by Cheney on 03/27/06
	//comments last updated by Roy on 02/21/06
	/**
		It evaluates multiple function values with, possibly, multiple independent variables.
	Paramaters:
		params=[input]the vector of parameter values. It must have the size equal to the number of paramaters
				of the function.
		py=[output]pointer to the buffer of doubles which will on return receive the function values. It's size must
				be at least nPts.
		px1=[input]pointer to an array of doubles holding the independent data values (if there are multiple independent
				variables in the function, this corresponds to the first independent variable). Its size must be at
				least nPts. 
		px2=[input]pointer to an array of doubles holding the data values for the second indepedent variable (must be NULL
				if the function has less than 2 independent variables). Its size must be at
				least nPts.
		nPts=[input][optional]the number of points in data arrays. By default it is 1.
		px3=[input][optional]pointer to an array of doubles holding the data values for the third indepedent variable (must be NULL
				if the function has less than 3 independent variables). Its size must be at
				least nPts.
		px4=[modify]pointer to an array of doubles holding the data values for the fourth indepedent variable (must be NULL
				if the function has less than 4 independent variables). Its size must be at
				least nPts.
	Returns:
		TRUE if success, otherwise FALSE.
	Example1:
		#include <origin.h>

		#include <FDFTree.h>
        #include <ONLSF.h>
        
		void NumericFunction_Evaluate_ex1()
		{
			string		strFDF = okutil_get_origin_path(ORIGIN_PATH_SYSTEM, "FitFunc")+"Gauss.FDF";
			Tree tr;
			if( !nlsf_FDF_to_tree( strFDF, &tr ))
				return;
			
			NumericFunction	NF;
			if(!NF.SetTree(tr))
			{
				out_str("Invalid function");
				return;
			}
			
			vector vx, vy, vParas;
			vParas.SetSize(4);
			vParas[0] = 3.;		// y0
			vParas[1] = 5.;		// xc
			vParas[2] = 2.5;	// w
			vParas[3] = 2.;		// A
			
			vx.Data(0., 10., 0.1);
		
			int				nNumPts = vx.GetSize();
			// Prepare the buffer to receive the results (it should have the same number of points
			// as vx)
			vy.SetSize(nNumPts);
			
			BOOL			bb = NF.Evaluate(vParas, vy, vx, NULL, nNumPts);
			if (!bb)
			{
				out_str("Failed!");
				return;
			}
		
			// Create the worksheet which is to receive the results:
			Worksheet		wks;
			wks.Create("Origin");
		
			// Put the X and the Y values into the worksheet:
			
			DataRange dr;
			dr.Add("", wks, 0, 0, -1, 0);
			dr.Add("", wks, 0, 1, -1, 1);
			
			dr.SetData(vx, false, 0);
			dr.SetData(vy, false, 1);
		}
	Example2:
		#include <origin.h>

		#include <FDFTree.h>
		#include <ONLSF.h>
		#include <wks2mat.h>
		// This sample will first create XY gridding and then 
		// evaluate Z by using gauss2d surface fitting functions, 
		// finally draw a 3D wireframe plot.
		void NumericFunction_Evaluate_ex2(double dXMin = -1.5, double dYMin = -1.5, double dXMax = 1.5, double dYMax = 1.5, int nRows = 50, int nCols = 50)
		{
			string		strFDF = okutil_get_origin_path(ORIGIN_PATH_SYSTEM, "FitFunc")+"Gauss2D.FDF";
			Tree tr;
			if( !nlsf_FDF_to_tree( strFDF, &tr ))
				return;
			
			NumericFunction	NF;
			NF.SetTree(tr);
			
			int	nNumParams = NF.NP;
			out_int("Number of paramaters = ", nNumParams);
			
			vector vParams(nNumParams);
			vParams[0] = 0;		// z0
			vParams[1] = 100;	// A
			vParams[2] = 0;		// xc
			vParams[3] = 0.5;	// w1
			vParams[4] = 0;		// yc
			vParams[5] = 0.5;	// w2
		
			vector vX(nRows*nCols), vY(nRows*nCols);
			MatrixLayer ml;
			ml.Create();
			MatrixObject mo = ml.MatrixObjects(0);
			mo.SetXY(dXMin, dYMin, dXMax, dYMax);
			mo.SetNumRows(nRows);
			mo.SetNumCols(nCols);
			
			Matrix& mat = mo.GetDataObject();
		
			int nRet = ocmath_mat_to_regular_xyz(NULL, nRows, nCols, dXMin, dXMax, dYMin, dYMax, vX, vY, NULL, true);
			
			if (nRet < 0)
			{
				printf("Error to create XY gridding!\n");
				return;
			}
			
			double	valResult = NF.Evaluate(vParams, mat, vX, vY, nRows*nCols);
			
			GraphPage gp;
			gp.Create("wirefrm");
			
			GraphLayer gl = gp.Layers();
			
			int nPlot = gl.AddPlot(mo, IDM_PLOT_3D_MESH);
			
			gl.Rescale();
		}		
	*/
	BOOL			Evaluate(vector& params, double* py, double* px1, double* px2 = NULL, uint nPts = 1, double* px3 = NULL, double* px4 = NULL);

	/// ML 10/2/2006 NLFIT_CURVES_CLEANUP
	/**
		It evaluates function values for the general case of any number of dependents and of independents
	Parameters:
		params=[input]the vector of parameter values. It must have the size equal to the number of paramaters
				of the function.
		nPts=[input]the total number of rows in the row-major matrices pDeps and pIndeps (each row corresponds to
				one "point" at which the dependent values should be evaluated).
		pDeps=[output]the pointer to a row-major buffer of a matrix, which is to receive the dependent values.
				The size of each column in the matrix is assumed to equal the total number of dependent variables
				in the function.
		pIndeps=[input]the pointer to a row-major array of a matrix, which contains the idependent values.
				The size of each column in the matrix is assumed to equal the total number of independent variables
				in the function.
	Returns:
		TRUE if success, otherwise FALSE.
	*/
	///------ Folger 08/16/10 ORG-756-P1-P2 BETTER_ERROR_CHECKING_FOR_FITTING_FUNCTION_LT_EVALUATION
	//BOOL			Evaluate(vector& params, uint nPts, double* pDeps, double* pIndeps);
	BOOL			Evaluate(vector& params, uint nPts, double* pDeps, double* pIndeps, DWORD dwCntrl = 0);
	///------ End BETTER_ERROR_CHECKING_FOR_FITTING_FUNCTION_LT_EVALUATION
	/// end NLFIT_CURVES_CLEANUP

	//comments last updated by Cheney on 03/27/06
	/**
		It evaluates analytically partial derivatives of the function with respect to its
		parameters (assuming the function supports analytical derivatives).
	Parameters:
		params=[input]the vector of parameter values. It must have the size equal to the number of paramaters of the function.
		pPartialDerivs=[output]pointer to a buffer of doubles to receive the values of the partial derivatives. Its size must be at least
				the same as the number of paramaters of the function.
		x1=[input]the value of the independent variable at which the partial derivatives need to be evaluated (or the value
				of the first independent variables if the function has more than one independent variable).
		x2=[input][optional] the value of the second independent variable (not used if the function has fewer than 2
				independent variables).
		x3=[input][optional] the value of the third independent variable (not used if the function has fewer than 3
				independent variables).
		x4=[input][optional]the value of the fourth independent variable (not used if the function has fewer than 4
				independent variables).
	Return:
		TRUE if success, otherwise FALSE.
	Example1:
	    #include <origin.h>

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

		void NumericFunction_EvalPartialDerivatives_ex1()
		{
			string		strFDF = okutil_get_origin_path(ORIGIN_PATH_SYSTEM, "FitFunc")+"Gauss.FDF";
			Tree tr;
			if( !nlsf_FDF_to_tree( strFDF, &tr ))
				return;
			
			NumericFunction	NF;
			NF.SetTree(tr);
			
			vector		vParas;
			vParas.SetSize(4);
			vParas[0] = 3.;		// y0
			vParas[1] = 5.;		// xc
			vParas[2] = 2.5;	// w
			vParas[3] = 2.;		// A
			
			// Create the worksheet which is to receive the results:
			Worksheet		wks;
			wks.Create("Origin");
			
			// Delete all the columns from the worksheet first:
			while ( 0 < wks.GetNumCols() )
				wks.DeleteCol(0);
			
			wks.AddCol("X");
	        wks.AddCol("y0");
	        wks.AddCol("xc");
	        wks.AddCol("w");
	        wks.AddCol("A");
		
			// Add columns for x 
			DataRange dr;
			dr.Add("X", wks, 0, 0, -1, 0);
			
			// X-values:
			vector vTempX={0., 10., 0.1};
			dr.SetData(vTempX, FALSE ,0);
			
		
			int				nNumPts = vTempX.GetSize();
		
			for (int ipt = 0; ipt < nNumPts; ipt++)
			{
				double			arrPartialDerivs[4];
				BOOL			bb = NF.EvalPartialDerivatives(vParas, arrPartialDerivs, vTempX[ipt]);
				if (!bb)
				{
					out_str("Failed!");
					return;
				}
				
				
				wks.SetCell( ipt,1, arrPartialDerivs[0] );
				wks.SetCell( ipt,2, arrPartialDerivs[1] );
				wks.SetCell( ipt,3, arrPartialDerivs[2] );
				wks.SetCell( ipt,4, arrPartialDerivs[3] );
			}
			
			// y0,xc,w,A
			dr.Add("y0", wks, 0, 1, -1, 1);
			dr.Add("xc", wks, 0, 2, -1, 2);
			dr.Add("w", wks, 0, 3, -1, 3);
			dr.Add("A", wks, 0, 4, -1, 4);			
	
		}

	SeeAlso:
		NumericFunction, SetTree, Evaluate, ParamInit

	*/
	BOOL			EvalPartialDerivatives(vector& params, double* pPartialDerivs, double x1, double x2 = 0., double x3 = 0., double x4 = 0.);
	
	///Arvin 01/31/07 EVAL_PARTIALDERIVATIVES_FOR_MORE_THAN_ONE_POINTS
	/**
		It evaluates analytically partial derivatives of the function with respect to its
		parameters (assuming the function supports analytical derivatives) for more than one points.
	Parameters:
		params=[input]the vector of parameter values. It must have the size equal to the number of paramaters of the function.
		nPts = [input] the number of points (also is the number of rows of matrix pPartialDerivs)
		pPartialDerivs=[output]pointer to a buffer of double matrix to receive the values of the partial derivatives. Its size must be at least
				nPts rows and nParam columns, where nParam is the number of parameters of the the function, and nPts is the number of points.
		px1=[input]the values of the independent variable at which the partial derivatives need to be evaluated (or the values
				of the first independent variable if the function has more than one independent variable).
		px2=[input][optional] the values of the second independent variable (not used if the function has fewer than 2
				independent variables).
		px3=[input][optional] the values of the third independent variable (not used if the function has fewer than 3
				independent variables).
		px4=[input][optional]the values of the fourth independent variable (not used if the function has fewer than 4
				independent variables).
	Return:
		TRUE if success, otherwise FALSE.
	Example1:
	    #include <origin.h>

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

		void NumericFunction_EvalVectorPartialDerivatives_ex1()
		{
			string		strFDF = okutil_get_origin_path(ORIGIN_PATH_SYSTEM, "FitFunc")+"Gauss.FDF";
			Tree tr;
			if( !nlsf_FDF_to_tree( strFDF, &tr ))
				return;
			
			NumericFunction	NF;
			NF.SetTree(tr);
			
			vector		vParas;
			vParas.SetSize(4);
			vParas[0] = 3.;		// y0
			vParas[1] = 5.;		// xc
			vParas[2] = 2.5;	// w
			vParas[3] = 2.;		// A
			
			// Create the worksheet which is to receive the results:
			Worksheet		wks;
			wks.Create("Origin");
			
			// Delete all the columns from the worksheet first:
			while ( 0 < wks.GetNumCols() )
				wks.DeleteCol(0);
			
			wks.AddCol("X");
	        wks.AddCol("y0");
	        wks.AddCol("xc");
	        wks.AddCol("w");
	        wks.AddCol("A");
		
			// Add columns for x 
			DataRange dr;
			dr.Add("X", wks, 0, 0, -1, 0);
			
			// X-values:
			vector vTempX={0., 10., 0.1};
			dr.SetData(vTempX, FALSE ,0);
			
		
			int				nNumPts = vTempX.GetSize();
			int 			nParam = vParas.GetSize();
			matrix 			mPartialDerives(nNumPts, nParam);
			BOOL			bb = NF.EvalVectorPartialDerivatives(vParas,nNumPts, mPartialDerives, vTempX);
			if (!bb)
			{
				out_str("Failed!");
				return;
			}
			
			for (int ipt = 0; ipt < nNumPts; ipt++)
			{
				double			arrPartialDerivs[4];
				bb = NF.EvalPartialDerivatives(vParas, arrPartialDerivs, vTempX[ipt]);
				if (!bb)
				{
					out_str("Failed!");
					return;
				}
				
				vector v;
				mPartialDerives.GetRow(v, ipt);
				for(int ii = 0; ii < nParam; ii++)
				{
					if(!is_equal(round(v[ii], 10),  round(arrPartialDerivs[ii], 10)))
					{
						printf("Warning: Partial derivatives evaluate by EvalVectorPartialDerivatives" 
								"is different from EvalPartialDerivatives in cell(%d, %d)\n, please check the two function.", ipt, ii);  
						return;
					}
					wks.SetCell( ipt,ii, arrPartialDerivs[ii] );
				}
			}
			
			// y0,xc,w,A
			dr.Add("y0", wks, 0, 1, -1, 1);
			dr.Add("xc", wks, 0, 2, -1, 2);
			dr.Add("w", wks, 0, 3, -1, 3);
			dr.Add("A", wks, 0, 4, -1, 4);			
	
		}

	SeeAlso:
		NumericFunction, EvalPartialDerivatives
	*/

	BOOL			EvalVectorPartialDerivatives(vector& params, uint nPts, double* pPartialDerivs, double* px1, double* px2 = NULL, double* px3 = NULL, double* px4 = NULL);
	///end 	EVAL_PARTIALDERIVATIVES_FOR_MORE_THAN_ONE_POINTS

	//comments last updated by Zachary on 01/03/07
	/**
		 Parameter initialization for non-linear curve fitting, which will call parameter initialization route of FDF file to do the initializtion.
	Parameters:
		vParams = [output] result from parameter initialization
		vIndependent = [input] X data vector
		vDependent = [input] Y data vector
		nErr = [output] error code (none-zero)
	Return:
		TRUE if success, otherwise FALSE.
	Example1:
		#include <origin.h>
		
		#include <ONLSF.h>
		#include <fdftree.h>
		
		void NumericFunction_ParamInit_ex1(string strFunctionName = "Gauss")
		{
			// first we need to use some data, assume A(x) B(y) of
			// active wks to test function for param init
			Worksheet wks = Project.ActiveLayer();
			if(!wks)
			{
				out_str("No active wks");
				return;
			}
		
			DataRange dr;
			dr.Add("X", wks, 0, 0, -1, 0); 
			dr.Add("Y", wks, 0, 1, -1, 1); 
			// we will copy into vector, so we know for sure it works with just vectors
			vector vX , vY ;
			dr.GetData(vX, 0);
			dr.GetData(vY, 1);
			
			
			string strCategoryName;
			string strFullPath;
			string strFDF = nlf_get_fdf_filename(strFunctionName, &strCategoryName, NULL, &strFullPath);
			if(strFDF.IsEmpty())
			{
				out_str("failed to find FDF");
				return;
			}
			Tree trFDF;
			if( !nlsf_FDF_to_tree( strFullPath, &trFDF ))
			{
				out_str("failed to load FDF");
				return;
			}
			//success in getting FDF tree
			NumericFunction fn;
			fn.SetTree(trFDF);
			
			vector vParams;
			int nErr;
			if(!fn.ParamInit(vParams, vX, vY, nErr))
				out_int("err code = ", nErr);
			else
				out_str("done");
			
		}
	*/
	BOOL			ParamInit(vector& vParams, vector& vIndependent, vector& vDependent, int& nErr = NULL);
	
	//comments last updated by Zachary on 01/03/07
	/**
		 Parameter initialization for surface fitting, which will call parameter initialization route of FDF file to do the initializtion.
	Parameters:
		vParams = [output] result of parameter initialization
		vX = [input] X data vector
		vY = [input] Y data vector
		vZ = [input] Z data vector
		nErr = [output] error code (none-zero)
	Return:
		TRUE if success, otherwise FALSE.
	Example1:
		#include <origin.h>
		
		#include <ONLSF.h>
		#include <fdftree.h>

		void NumericFunction_ParamInit_ex1()
		{
			string strFunctionName = "Gauss2D";
			string strCategoryName;
			string strFullPath;
			string strFDF = nlf_get_fdf_filename(strFunctionName, &strCategoryName, NULL, &strFullPath);
			if(strFDF.IsEmpty())
			{
				out_str("failed to find FDF");
				return;
			}
			Tree trFDF;
			if( !nlsf_FDF_to_tree( strFullPath, &trFDF ))
			{
				out_str("failed to load FDF");
				return;
			}
			
			NumericFunction fn;
			fn.SetTree(trFDF);
			
			vector vParams;
			vector vX;
			vector vY;
			vector vZ;
			vX.Data(0, 10);
			vY.Data(10, 20);
			vZ.Data(20, 30);
			fn.ParamInit(vParams, vX, vY, vZ);
		}

	SeeAlso: 
		NumericFunction, SetTree, Evaluate, EvalPartialDerivatives
	*/
	///Arvin  03/08/08 ADD_PARAM_INIT_CONTEXT_CLASS as Marko said
	//BOOL			ParamInit(vector& vParams, vector& vX, vector& vY, vector& vZ, int& nErr = NULL);
	BOOL			ParamInit(vector& vParams, vector& vX, vector& vY, vector& vZ, int& nErr = NULL, ParamInitContext& ctxt = NULL);
	///end 	 ADD_PARAM_INIT_CONTEXT_CLASS

	//------ Folger 08/09/08 QA80-11816 SUPPORT_AUTO_PARAMETER_INITIALIZATION_FOR_MULTIPLE_INDEPENDNTS_AND_MULTIPLE_DEPENDENTS
	BOOL			ParamInit(vector& vParams, vector *pvIndeps, vector *pvDeps, int& nErr = NULL);
	//------
	
	/// ML 2/6/2007 QA70-9343 INCESANT_FAILED_ATTEMPTS_TO_COMPILE_BAD_FITTING_FUNCTION_BODY
	/**
			Compiles if needed an OC-based user-defined fitting function. If not a user-defined function
			which needs OC compilation, or if already compiled, it does nothing.
		Parameters:
			None
		Returns:
			FALSE if it fails to compile. TRUE in all other circumstances.
			If the method returns FALSE, it means that the OC compilation has failed, and that it should not
			be called again until the fitting function is fixed. It is safe to call the method on the functions
			which do not require OC compilation (the method will always return TRUE for such fitting functions).
			Also, if the OC compilation succeeds once, subsequent calls to this method will do nothing and return TRUE.
	*/
	BOOL			CheckCompileOC();
	/// end INCESANT_FAILED_ATTEMPTS_TO_COMPILE_BAD_FITTING_FUNCTION_BODY

	///Arvin 07/04/07 QA70-10019 INTEGRAl_OF_NUMERIC_FUNCTION
	/**
		Numeric function definite integral in a interval [dFrom, dTo].
	Parameters:
		dFrom		 = [input] lower bound for definite integral
		dTo			 = [input] upper bound for definite integral
		vParamValues = [input] function parameters
		rPrecision	 = [input] precision of integral calculation
	Return:
		definite integral result if success, otherwise NANUM.
	Example1:
		#include <FDFTree.h>
		#include <ONLSF.h>

		void NumericFunction_Integral_ex1()
		{
			string		strFDF = okutil_get_origin_path(ORIGIN_PATH_SYSTEM, "FitFunc")+"Gauss.FDF";
			Tree tr;
			if( !nlsf_FDF_to_tree( strFDF, &tr ))
			{
				printf("Load FDF failed!");
				return;
			}
	
			NumericFunction	NF;
			NF.SetTree(tr);
			
			vector		vParas;
			vParas.SetSize(4);
			vParas[0] = 3.;		// y0
			vParas[1] = 5.;		// xc
			vParas[2] = 2.5;	// w			   
			vParas[3] = 2.;		// A
			
			int 			nParam = vParas.GetSize();
			double			dIntegResult = NF.Integral(4.5, 10.6, vParas);
			if(is_missing_value(dIntegResult))
			{
				printf("Integral failed!");
				return;
			}
		
			printf("Integral result is: %f", dIntegResult);
		} 
	*/
	/// ML 5/15/2008 ALLOW_PASSING_PRECISION_FOR_MOMENTS_COMPUTATION
	//double			Integral(double dFrom, double dTo, vector& vParamValues);
	double			Integral(double dFrom, double dTo, vector& vParamValues, double rPrecision = 1.e-8);
	/// end ALLOW_PASSING_PRECISION_FOR_MOMENTS_COMPUTATION
	///end 	   INTEGRAl_OF_NUMERIC_FUNCTION
	
	///Arvin 07/12/07 QA70-10019 PEAK_MOMENT_CALCULATION 
	/**
		Peak moment calculation by numeric function in a interval [dFrom, dTo].
	Parameters:
		dFrom		 = [input] lower bound 
		dTo			 = [input] upper bound 
		vParamValues = [input] function parameters
		nMomentOrder = [input] peak moment order( >= 0 ), nMomentOrder >= 0 while nMomentType == INTEG_ZERO_POINT_MOMENT
							   nMomentOrder >= 2 while nMomentType == INTEG_CENTRAL_MOMENT

		nMomentType	 = [input] peak moment type. PEAK_ZERO_POINT_MOMENT, zero point moment; 
												 PEAK_CENTRAL_MOMENT, central moment
		nErr		 = [input] Error message, 0 if success, otherwise less than 0
		rPrecision	 = [input] precision of integral calculation
	Return:
		peak moments if success, otherwise NANUM.
	Example1:
		#include <FDFTree.h>
		#include <ONLSF.h>

		void NumericFunction_CalcPeakMoment_ex1()
		{
			string		strFDF = okutil_get_origin_path(ORIGIN_PATH_SYSTEM, "FitFunc")+"Gauss.FDF";
			Tree tr;
			if( !nlsf_FDF_to_tree( strFDF, &tr ))
			{
				printf("Load FDF failed!");
				return;
			}
		
			NumericFunction	NF;
			NF.SetTree(tr);
		  
			vector		vParas;
			vParas.SetSize(4);
			vParas[0] = 3.;		// y0
			vParas[1] = 5.;		// xc
			vParas[2] = 2.5;	// w			   
			vParas[3] = 2.;		// A
			
			int 			nParam = vParas.GetSize();
			int				nErr = 0;
			int				nMomentOrder = 4;
			int				nMomentType = PEAK_CENTRAL_MOMENT;
			double			dPeakMoments = NF.CalcPeakMoment(4.5, 10.6, vParas, nMomentOrder, nMomentType, nErr);
			if(nErr < 0)
			{
				printf("Error code %d", nErr);
				return;
			}
			  
			printf("Peak moments Result is: %f", dPeakMoments);
		} 
	*/
	/// ML 5/15/2008 ALLOW_PASSING_PRECISION_FOR_MOMENTS_COMPUTATION
	//double			CalcPeakMoment(double dFrom, double dTo, vector& vParamValues, int nMomentOrder = 0, int nMomentType = PEAK_ZERO_POINT_MOMENT, int& nErr = NULL);
	double			CalcPeakMoment(double dFrom, double dTo, vector& vParamValues, int nMomentOrder = 0, int nMomentType = PEAK_ZERO_POINT_MOMENT, int& nErr = NULL, double rPrecision = 1.e-8);
	/// end ALLOW_PASSING_PRECISION_FOR_MOMENTS_COMPUTATION
	///end 	 PEAK_MOMENT_CALCULATION

	/// ML 5/16/2008 QA70-11552 ANALYTICALLY_COMPUTING_FF_MOMENTS
	/**
			It computes moments from expressions in the [Moments] section of FDF file using the supplied parameter values.
			The section can have any number of expressions.
			[Moments]
			M0=some expresions
			M1=some other expression
			etc.
		Parameters:
			vResults=[output]the vector to receive the computed values. Its size will be the same as the size of the input array arrMomentNames.
							If a moment is not available in the .FDF file, the value will be NANUM. If the expression is the string "N.A.",
							the value will be ONLSF8_MOMENT_VALUE_NOT_APPLICABLE.
			arrMomentNames=[input]moment names which need to be evaluated. For all those for which the expression is the [Moments]
							section does not exist, the value will be NANUM.
			pParams=[input]the pointer to the array of parameter values. Its size must be nParams.
			nParams=[input]the number of parameters in pParams. It must be equal to the number of parameters in the function (the property NP).
		Returns:
			0 if OK, or a negative value if error.
	*/
	int				EvaluateMomentsAnalytically(vector& vResults, StringArray &arrMomentNames, double *pParams, int nParams);
	/// end ANALYTICALLY_COMPUTING_FF_MOMENTS

	/// ML 5/21/2008 NUMERICFUNCTION_CLASS_ACCESS_TO_PEAK_PARAMETER_INDICES
	/**
			It returns parameter indices of various peak-specific parameters, as indicated in the FDF.
		Parameters:
			pst=[output]*pst receives the indices of peak-specific parameters, as indicated in the FDF file. If any of them is not indicated in the
					FDF file, the corresposnding value will be negative.

	*/
	BOOL			GetPeakParametersIndices(NLPEAKPARAMS *pst);
	/// end NUMERICFUNCTION_CLASS_ACCESS_TO_PEAK_PARAMETER_INDICES

	/// ML 5/22/2008 PARAMETER_VALUE_DEPENDENT_INFO_ABOUT_WHETHER_THE_FUNCTION_HAS_COMPUTABLE_MOMENTS
	/**
			It provides the information from the fitting function whether the moments are in principle calculable, i.e. whether corresponding integrals are convergent.
		Parameters:
			pdw=[input]*pdw receives the bits MOMENTEXISTS_* for every moment that can be calculated.
			pParams=[input]the parameter values for which the moments existence should be checked.
			nParams=[inout] the number of parameters pointed to by pParams. It must be equal to the number of
					parameters of the function.
		Example:
			void	test_MomentsExist()
			{
				string			strFDF1 = okutil_get_origin_path(ORIGIN_PATH_SYSTEM, "FitFunc") + "Pearson7.FDF";
				Tree			trFF1;
				if( !nlsf_FDF_to_tree( strFDF1, &trFF1 ))
					return;


				NumericFunction	NF;
				NF.SetTree(trFF1);

				vector			vParams = {6., 7., 8., 9., 2.};
				DWORD			dwMoments;
				if ( NF.MomentsExist(&dwMoments, vParams, vParams.GetSize()) )
				{
					if ( MOMENTEXISTS_0 & dwMoments )
						out_str("0 moment exists");
					
					if ( MOMENTEXISTS_1 & dwMoments )
						out_str("1 moment exists");
					
					if ( MOMENTEXISTS_2 & dwMoments )
						out_str("2 moment exists");
					
					if ( MOMENTEXISTS_3 & dwMoments )
						out_str("3 moment exists");
					
					if ( MOMENTEXISTS_4 & dwMoments )
						out_str("4 moment exists");
				}
				else
					out_str("The function body does not provide information whether moments exist or not.");

			}
	*/
	BOOL			MomentsExist(DWORD *pdw, double *pParams, int nParams);
	/// end PARAMETER_VALUE_DEPENDENT_INFO_ABOUT_WHETHER_THE_FUNCTION_HAS_COMPUTABLE_MOMENTS


	///------ Folger 08/11/10 ORG-756-P3 BETTER_CHECKING_FOR_VALID_EQUATIONS
	/**$
	*/
	BOOL			CheckEquations(LPCTSTR lpcszFormula, string* pstrErrMsg = NULL);
	///------ End BETTER_CHECKING_FOR_VALID_EQUATIONS

	///------ Folger 08/16/10 ORG-762-P2 MORE_ERROR_CHECKING_ON_DERIVED_PARAMS_EQUATIONS
	/**$
	*/
	BOOL			CheckDerivedParamEquations(LPCTSTR lpcszFormula, StringArray& arrNames, string* pstrErrMsg = NULL);
	///------ End MORE_ERROR_CHECKING_ON_DERIVED_PARAMS_EQUATIONS

	/**
		read-only property: number of parameters.
	*/
	uint			NP;

};

///Arvin  03/08/08 ADD_PARAM_INIT_CONTEXT_CLASS as Marko said
/**# >Analysis
*/
class ParamInitContext
{
public:
	/**
	*/
	BOOL			ParamInitContext(DataRange& dr);
	
	/**
	*/
	DataRange		*GetInput();
};
///end ADD_PARAM_INIT_CONTEXT_CLASS


/// ML 4/20/2008 QA70-11061 GETTING_CURRENT_FIT_INFO
/**+
http://ocwiki.originlab.com/index.php?title=OriginC:NLFitContext_(class)
*/
class	NLFitContext
{
public:
	/**+
	http://ocwiki.originlab.com/index.php?title=OriginC:NLFitContext-NLFitContext
	*/
	NLFitContext();
	/**+
	http://ocwiki.originlab.com/index.php?title=OriginC:NLFitContext-~NLFitContext
	*/
	~NLFitContext();

public:
	/**+
	http://ocwiki.originlab.com/index.php?title=OriginC:NLFitContext-IsNewParamValues
	*/
	BOOL				IsNewParamValues();

	/**+
	http://ocwiki.originlab.com/index.php?title=OriginC:NLFitContext-GetFitCurrInfo
	*/
	BOOL				GetFitCurrInfo(NLSFCURRINFO *pCurrInfo);

	/**+
	http://ocwiki.originlab.com/index.php?title=OriginC:NLFitContext-GetNumDatasetSets
	*/
	int					GetNumDatasetSets();

	/**+
	http://ocwiki.originlab.com/index.php?title=OriginC:NLFitContext-GetIndepData
	*/
	int					GetIndepData(vector *vData, int iiSet = 0, int iiIndep = 0);


};
/// end GETTING_CURRENT_FIT_INFO



// END Origin C only
/////////////////////////////////////////
#endif // !_MSC_VER






/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
#endif		// __ONLSF_H__










