4.2.2.12 Fitting Integral Function with parametric limit using NAG Library


Summary

Before you start delving into this tutorial, you are recommended to read the relevant tutorial in Fitting with Integral using NAG Library. And as far as programming is concerned, the two tutorials are basically the same, except that here you will learn to define Origin C fitting function with fitting parameters in the integral limit, while in the previous tutorial we in fact define a fitting independent variable in the integral limit. Also note that a different NAG integrator is used here.

Minimum Origin Version Required: Origin 8.0 SR6

What you will learn

This tutorial will show you how to:

  • Create a fitting function with Definite Integral using the NAG integration routine
  • Create a fitting function with a parametric integral limit
  • Use a log function to scale a large return value from the fitting function

Example and Steps

For example, we will fit the sample data at the bottom of this page with the following model:

y=\int_{c}^{d} \frac { \cosh { ((x_i + b^2 \cdot x^2) /(b + x))}}{a+(x_i^2+x^2)}\, dx_i

Note that we use x_i \, to indicate the integral independent variable while x \, indicates the fitting independent variable. The model parameters a, b, c, and d are fitted parameters we want to obtain from the sample data. To prepare the data, you just need to copy the sample data to an Origin Work sheet. The fitting procedure is similar to the previous tutorial:

Define Fitting Function in Fitting Function Organizer

Press F9 to open the Fitting Function Organizer and add the User-Defined integral fitting function nag_integration_fitting_cosh to the Category FittingWithIntegral, similar to the first tutorial.

Function Name: nag_integration_fitting_cosh
Function Type: User-Defined
Independent Variables: x
Dependent Variables: y
Parameter Names: a, b, c, d
Function Form: Origin C
Function:

Click the button Open Code Builder Dialog in FFO.png beside the Function box to open the code builder and define and compile the fitting function as follows: (Note: Remember to save the Function after compiling it and returning to the Function Organizer Dialog):

#include <origin.h>
// Add your special include files here.
// For example, if you want to fit with functions from the NAG library, 
// add the header file for the NAG functions here.
#include <OC_nag.h>


// Add code here for other Origin C functions that you want to define in this file,
// and access in your fitting function.
struct user
{
	double a, b, fitX;  // fitX the independent variable of fitting function
 
};
static double NAG_CALL f_callback(double x, Nag_User *comm)  // x is the independent variable of the integrand
{
 
	struct user *sp = (struct user *)(comm->p);
 
        double aa, bb, fitX; // temp variable to accept the parameters in the Nag_User communication struct
        aa = sp->a;
        bb = sp->b;
        fitX = sp->fitX;
 
        return cosh((x*x+bb*bb*fitX*fitX)/(bb+fitX))/(aa+(x*x+fitX*fitX));
}

// You can access C functions defined in other files, if those files are loaded and compiled 
// in your workspace, and the functions have been prototyped in a header file that you have
// included above. 

// You can access NLSF object methods and properties directly in your function code.

// You should follow C-language syntax in defining your function. 
// For instance, if your parameter name is P1, you cannot use p1 in your function code. 
// When using fractions, remember that integer division such as 1/2 is equal to 0, and not 0.5
// Use 0.5 or 1/2.0 to get the correct value.

// For more information and examples, please refer to the "User-Defined Fitting Function" 
// section of the Origin Help file.

//----------------------------------------------------------
// 
void _nlsfnag_integration_fitting_cosh(
// Fit Parameter(s):
double a, double b, double c, double d,
// Independent Variable(s):
double x,
// Dependent Variable(s):
double& y)
{
	// Beginning of editable part
	double epsabs = 0.00001, epsrel = 0.0000001, result, abserr;
	Integer max_num_subint = 500;  
        // you may use epsabs and epsrel and this quantity to enhance your desired precision 
        // when not enough precision encountered

	Nag_QuadProgress qp;
	static NagError fail;
	
	// the parameters parameterize the integrand can be input to the call_back function
        // through the Nag_User communication struct 
        Nag_User comm;	
	struct user s;
	s.a = a;
	s.b = b;
	s.fitX = x;
        comm.p = (Pointer)&s;

	d01sjc(f_callback, c, d, epsabs, epsrel, max_num_subint, &result, &abserr, &qp, &comm, &fail);
	

        // you may want to exam the error by printing out error message, just uncomment the following lines
	// if (fail.code != NE_NOERROR)
        // printf("%s\n", fail.message);


	// For the error other than the following three errors which are due to bad input parameters 
	// or allocation failure  NE_INT_ARG_LT  NE_BAD_PARAM   NE_ALLOC_FAIL
	// You will need to free the memory allocation before calling the integration routine again to 
        // avoid memory leakage
	if (fail.code != NE_INT_ARG_LT && fail.code != NE_BAD_PARAM && fail.code != NE_ALLOC_FAIL)
	{
		NAG_FREE(qp.sub_int_beg_pts);
		NAG_FREE(qp.sub_int_end_pts);
		NAG_FREE(qp.sub_int_result);
		NAG_FREE(qp.sub_int_error);
	}
	
	
	y = log(result); 
        // note use log of the integral result as return as the integral result is large, 
        // you are not necessary to do so 

	// End of editable part
}

In the above code, we define the integrand as a callback function f_callback just outside the fitting function body _nlsfnag_integration_fitting_cosh. Note that we parametrize the integrand function with the variables a, b and fitX, and pass them into the callback funtion through the Nag_User struct. After that we perform the integration using NAG integrator d01sjc. Besides, you can also use other Quadrature Routines as you want. In the current example, we also use a log scale for the fitting function. (The sample data are already scaled by a log function)

Compile the code, return to the dialog and then Save the fitting function in the function Organizer and open the Nonlinear Curve Fit dialog in the Analysis-Fitting menu. You can then select this user-defined fitting function in the Function Selection page under Setting Tab.

Set the Initial Values for the Parameters

Similarly, as it is a user-defined fitting function, you have to supply the initial guess values for the parameters. You may manually set them in the Parameter tab in Nonlinear Curve Fit dialog. For current example, you can just set the initial values for the parameters a=1 , b=10, c=3 , d=4. After the parameters are initialized, you can perform the fitting to obtain the fitting result, as shown in the following.

Sample Data

Sample Data Results
X Y FitResultCosh.PNG
-5 498.19046
-4.33333 329.43196
-3.66667 210.28005
-3 126.55799
-2.33333 69.01544
-1.66667 31.3555
-1 9.1393
-0.33333 -0.84496
0.33333 -0.99914
1 6.86736