1.12.6 Using NAG Functions

Header Files

To call any NAG function, you need to include the header file or files where the NAG function is declared.

A single header file, which includes all the commonly used NAG header files, is provided below. Usually, you can just include this header file in your code.

#include <OC_nag.h> // includes all common NAG header files

If only a single NAG function or just a few are used, you can also just include its (their) own individual NAG header file(s). For example, if the NAG function f02abc is called in the code, then two related NAG header files need to be included.

#include <NAG\nag.h>    // NAG struct and type definitions
#include <NAG\nagf02.h> // contains the f02 function declarations

Error Structure

All NAG functions accept one argument, which is a pointer of NagError structure. This structure is used to test whether the NAG function is executing successfully or not.

The example below shows whether the NAG function f02abc works successfully.

NagError err;                    // Declare an error structure
f02abc(n, mx, n, r, v, n, &err); // Call NAG f02abc function
if( err.code != NE_NOERROR )     // If an error occurred
    printf(err.message);         // Output error message

If you don't need to know whether the call is successful or not, the error structure declaration is not needed. And the NAGERR_DEFAULT macro can be passed instead. This macro is a NULL pointer. To ensure compatibility with future versions of NAG functions, it will be better to use this macro if you can work without error structure.

f02abc(n, mx, n, r, v, n, NAGERR_DEFAULT);

Callback Functions

In the NAG Library, most of the routines involve callback functions. Before defining a callback function, you need to know the return type and argument types of the callback function that NAG will expect when calling it.

Take the NAG function d01ajc for example. In the header file nagd01.h, we can see that the first argument is NAG_D01AJC_FUN f. This argument is a callback function. Then in nag_types.h, we find that NAG_D01AJC_FUN is a type of NAG_D01_FUN, which is defined as:

typedef double (NAG_CALL * NAG_D01_FUN)(double);

Then we can define the callback function as follows:

double NAG_CALL myFunc(double x)
{
    double result;
    // Do processing on 'x'
    return result;
}

When calling the NAG function d01ajc, myFunc (defined above) can be passed as the first argument.

Calling c05adc Example

This example will show how to call the NAG function c05adc, the fourth argument of which is the callback function argument. This callback function of type NAG_C05ADC_FUN is defined in nag_types.h.

typedef double (NAG_CALL * NAG_C05ADC_FUN)(double);

From the definition, we know that both the return type and the only argument type are double. So we define the callback function as follows:

double NAG_CALL myC05ADCfunc(double x)
{
    return exp(-x)-x;
}

The following code shows how to call the c05adc function by passing the myC05ADCfunc callback function.

double a = 0.0, b = 1.0, x, ftol = 0.0, xtol = 1e-05;
NagError err;

c05adc(a, b, &x, myC05ADCfunc, xtol, ftol, &err);

NAG Get Data From Origin

Many NAG functions take a pointer to an array of numeric data. Both Origin worksheets and matrix sheets allow getting a pointer to their data. This pointer can be passed to NAG functions. In Origin C, data is commonly passed using Dataset or DataRange objects. The sections below will show how to pass data from a worksheet by using Dataset and DataRange. The DataRange way is recommended.

Dataset

A Dataset object can be passed to a NAG function as long as the Dataset is of the data type expected by the NAG function. The data type of an Origin worksheet column is Text & Numeric by default. For most, but not all, NAG functions, this data type is not allowed to be passed, because NAG functions expect floating or integer pointers.

If you make sure that the Dataset is of the type expected by the NAG function, the following code can be used to pass a Dataset object to a NAG function.

// Get access to the active worksheet.
Worksheet wks = Project.ActiveLayer();

// Construct Datasets to get access to the wks data.
Dataset dsX, dsY;
dsX.Attach(wks, 0);
dsY.Attach(wks, 1);

// Call NAG's nag_1d_spline_interpolant(e01bac) function.
NagError err;
Nag_Spline spline;
e01bac(m, dsX, dsY, &spline, &err);

DataRange

The DataRange class provides the GetData method for getting data from a worksheet into a vector, even if the worksheet columns are of the Text & Numeric data type. The GetData method can also ignore the rows with missing values easily, which is very important when passing data to NAG functions.

Using DataRange to pass data from Origin to NAG functions is much safer, and is recommended. The following example demonstrates how to do that.

void call_NAG_example()
{
	int i, numPoints = 5;

	// Create a new worksheet page.
	WorksheetPage pg;
	pg.Create("origin");

	// Get access to the active worksheet and add two more columns.
	Worksheet wks = Project.ActiveLayer();
	// Add X2 column
	i = wks.AddCol();
	Column col(wks, i);
	col.SetType(OKDATAOBJ_DESIGNATION_X);
	// Add Y2 column
	wks.AddCol();

	// Create some starting XY values in first two columns
	Dataset dsX, dsY;
	dsX.Attach(wks, 0);
	dsY.Attach(wks, 1);
	for (i = 0; i < numPoints; i++)
	{
		int r = rnd(0) * 10;
		if (r < 1)
			r = 1;
		if (i > 0)
			r += dsX[i - 1];
		dsX.Add(r);
		dsY.Add(rnd(0));
	}

	// Create data range object.
	DataRange dr;
	dr.Add(wks, 0, "X");
	dr.Add(wks, 1, "Y");

	// Copy data from wks to vector using data range.
	// This copy will ignore rows with missing values.
	vector vX1, vY1;
	dr.GetData(DRR_GET_DEPENDENT, 0, NULL, NULL, &vY1, &vX1);

	// Call NAG to calculate coefficients.
	NagError err;
	Nag_Spline spline;
	e01bac(vX1.GetSize(), vX1, vY1, &spline, &err);

	// Get the spline's XY values
	vector vX2, vY2;
	double fit, xarg;
	for (i = 0; i < vX1.GetSize(); i++)
	{
		vX2.Add(vX1[i]);
		vY2.Add(vY1[i]);
		if (i < vX1.GetSize() - 1)
		{
			xarg = (vX1[i] + vX1[i + 1]) * 0.5;
			e02bbc(xarg, &fit, &spline, &err);
			vX2.Add(xarg);
			vY2.Add(fit);
		}
	}

	// Free memory allocated by NAG
	NAG_FREE(spline.lamda);
	NAG_FREE(spline.c);

	// Copy spline values to worksheet
	dsX.Attach(wks, 2);
	dsX = vX2;

	dsY.Attach(wks, 3);
	dsY = vY2;
}

How to Call NAG e04 Functions

The following example will show how to call the NAG function, nag_opt_simplex_easy, safely. And the results will output to a file.

#include <OC_nag.h>

#define NULLFN NULL

void text_e04cbc()
{
        double objf;
	double x[2];
	Integer maxcal, n;
        NagError fail; 

	printf("\ne04cbc example: \n");

        maxcal = 100;
	n = 2;
	x[0] = 0.4;
	x[1] = -0.8;
        tolf = sqrt(nag_machine_precision);
	tolx = sqrt(tolf);
	try
	{
		// call the NAG function, e04cbc = nag_opt_simplex_easy
		nag_opt_simplex_easy(n, x, &objf, tolf, tolx, funct, NULLFN, maxcal, NAGCOMM_NULL, &fail);  
	}
	catch(int err)
	{
		printf("\nerror = %d\n", err);  // if there is an exception
	}
	printf("fail->code = %d\n", fail.code);  // error code
	printf("fail->message = %s\n", fail.message);  // error message

        printf("The final function value is %12.4f\n", objf);
	printf("at the point");
	for (int ii = 1; ii <= n; ++ii)
	{
		printf(" %12.4f", x[ii-1]);
	}
	printf("\n");
}

// call back function for nag_opt_simplex_easy
void NAG_CALL funct(Integer n, double* xc, double* objf, Nag_Comm* comm)
{
	*objf = exp(xc[0])*(xc[0]*4.0*(xc[0]+xc[1])+xc[1]*2.0*(xc[1]+1.0)+1.0);
}