NAG C Header Files

Calling NAG Fortran Library Routines from C Language Programs
Using the NAG C Header Files

Ian Hounam

NAG Ltd, Oxford

© The Numerical Algorithms Group Ltd, Oxford UK. 1998

19 March 1998

Modified version for the Cray T3E

Bo Einarsson

NSC, Linköping

31 October 2000

Please contact Bo Einarsson if you experience any problem with these header files.
Some further information is available in the NAG C Header Files FAQ.

Please note that the Header Files discussed in sections 1 to 13 are for the NAG Fortran Library at Mark 18 and not for Mark 19.
They can be used for both marks, provided that the routine of Mark 19 is not new to that mark.
Both marks are presently available at NSC, you have to explicitly link with -lnag18
instead of with -lnag if you wish to use Mark 18 of the library, since Mark 19 is the default.

The header files for Mark 19 are now available, see section 14.

1 Introduction

A great number of systems allow the C programmer to call other language routines. Indeed the ANSI standard definition of C provides a powerful argument checking facility that, given the correct definition of function prototypes, can facilitate cross language communication between C and, say, Fortran.

A header file containing the function prototypes can be included in the user's program to allow the C compiler to check argument passage. Such a header file has been created for the current NAG Fortran Library and the current NAG Graphics Library. This was done automatically from the Library source code in order to ensure its correctness. The T3E version nagmk18_t3e.h has however been modified manually from the original. This document explains how to call Fortran routines from C using the NAG header file. It is in most cases also possible to call the Fortran routines from C++.

This document describes how this is achieved on the Cray T3E. For all other computers you are referred to the original NAG version of this document.

In addition to the NAG produced header file we also present a locally produced header file with many advantages. See Section 13.

The two different header files are located on the area /usr/include/ on our Cray T3E, but this is a standard area for include files, and the directory does not have to given by the user.

2 Argument Types

The table below lists the mapping between relevant Fortran and C argument and function types on the T3E.
   REAL D                   double d;
   INTEGER I                int i;
   LOGICAL L                int l;
   CHARACTER*n S            char s[n];
   COMPLEX Z                struct {double re,im;} z;
All arguments are passed as pointers to a variable; this means that a constant must first be assigned to a variable and then the address of the variable passed.

As Fortran stores multi-dimension arrays in column major order whereas C stores in row major order, either

  1. the C routine must store and manipulate the transpose of the problem matrix, or
  2. the C routine must transpose the matrix before and after calling the Fortran routine.
Fortran CHARACTER type is different to C null terminated strings so that the actual length of the string must be passed as an extra argument. For example the Fortran subroutine
         SUBROUTINE X00XXE(D1,S,D2)
where the arguments are declared
         REAL D1,D2
         CHARACTER*5 S
would, with an f77 compatible compiler, be called from C thus
         X00XXE(&d1,s,&d2,length_of_s);
where the arguments are declared
         double d1,d2;
         char s[5];
         int length_of_s = 5;
(length_of_s is the length of the string s)

If there is more than one string argument, further extra length arguments are appended, in order, to the end of the argument list.

3 Subroutines and Functions

Fortran subroutines are declared as void functions in C.

Procedure arguments, i.e. function or subroutine names, are passed by address in the normal C manner.

4 Complex functions

The original of this document was for DOUBLE PRECISION code in Fortran, which has the awkward feature that the concept DOUBLE PRECISION COMPLEX does not exist in the standard, and various non-standard extensions had to be used. Since this document is for single precision Fortran on the T3E (which corresponds to double precsion C on the T3E), most of this section has been removed.

The Fortran type COMPLEX is provided in the NAG header files by the typedef "Complex", which expands to "struct {double re,im;}"

5 Character functions

A character function is implemented as a void function with two extra arguments added to the start of the argument list, the first is a pointer to the returned string and the second its length.

e.g.

      CHARACTER*10 FUNCTION F(I)
is called thus:
      extern void F(char *,int,int *);
      char c[10];
      int clen = 10,i;
      F(&c,clen,&i)
This method does not work on the Cray T3E, because of a conflict between the Fortran CHARACTER and the C char.

I therefore recommend the Cray approach where char strings from C are explicitly translated into Fortran CHARACTER strings. The process is documented in the Cray C/C++ Reference Manual, 004-2179-003, Section 8.1.2, Calling Fortran functions and subroutines from a C or C++ function. See Example 2 in section 12.2 below.

Cray also suggests that LOGICAL variables are explicitly translated to 0 and 1 in a similar way. This is necessary on the C90, where .TRUE. is represented by a negative number, but on the T3E the logical representation is normal, so the NAG method works.

6 Routine Names

Some Unix systems require the addition of an underscore to the name of Fortran routines called from C. e.g. X01AAF becomes x01aaf_. This is not the case for T3E, but all Fortran NAG routine names have to be given with upper case letters also in C, and the last letter has to be E. The example above therefore becomes X01AAE.

7 Multi-Dimension Arrays

There is no syntax in the C language to specify an arbitrary array dimension and it is not possible to know in advance the dimensions of the arrays in your program. The best that the C Header Files can do is to declare the multi-dimensional arrays as one dimension arrays with a comment stating the actual number of dimensions, e.g. for 2 dimensions:
int array[] /* 2 dimension */

and for 3 dimensions:

double array[] /* 3 dimension */
The prototype for a hypothetical NAG Fortran routine with a 2 dimensional DOUBLE PRECISION array argument would look like this:
extern void NAGSUB(double[] /* 2 dimensions */);
A simple program to call this routine might look like this:
main ()
{
  double p[2][2];
  NAGSUB((double *)p);
}
Note that we need to cast the 2 dimensional C array actual argument to (double *).

The example prototype below shows how to call a hypothetical NAG routine that takes a single subroutine argument. This user supplied subroutine takes a 2 dimension DOUBLE PRECISION array and an integer which specifies the leading dimension of the Fortran array.

extern void NAGSUB(void (*f) (double[] /* 2 dimension */, int *));

The C code for the user supplied function is listed below. The 2 dimension array is passed as a pointer to double and the code must carry out array indexing using the dimension information passed from Fortran. In this case, the macro P uses the leading dimension of the Fortran array, which is the trailing dimension of the C array, to index into the array p. The array p is only referenced through this macro.

void fun(double p[], int *tdp)
{
#define P(I,J) p[(I)*(*tdp) + (J)]
  P(0,0) = 0.0;
  P(1,1) = 1.0;
}
The main function looks like this:
main ()
{
  void fun(double p[], int *tdp);
  NAGSUB(fun);
}
Example 3 below shows a complete example program that illustrates these concepts.

8 Non-ANSI compliant Compilers

The NAG C header files can be used with compilers that do not support the ANSI Standard function prototypes. On these systems the conditional compilation preprocessor directives present in the header files result in a normal Kernighan and Ritchie function definition. Note that with such a compiler no argument checking will be carried out.

9 Which Version of the NAG C Header Files Should I Use?

On the T3E you have to use the special T3E version.

10 Linking your program

It is always necessary to link your program with the Fortran run time library routines. This can most easily be achieved by linking using the f90 command, not cc or cld. For example,
cc  -c myprog.c
f90 -o myprog myprog.o -L/usr/local/lib -lnag
Note that the location of the library has to be given with the -L switch on the T3E.

If you use C++ it has been recommended by Anton Starikov to use compilation and linking with the same command:

CC -o myprog mprog.c -L/usr/local/lib -lnag
This worked fine with the examples 1 and 3 below. With separate compilation and linking it did not work at all:
CC -c nag1.c
f90 nag1.o -L/usr/local/lib -lnag
cld-404 cld: WARNING 
  The symbol `_main' referenced in relocatable object 
  `nag1.o:nag1$c' is not defined.
cld-431 cld: WARNING 
  The resulting output file `a.out' is not executable 
  because of previous WARNING messages.
Compilation with CC failed on example 2 since I do not use any header file in that case. At least those routines that are used explicitly have to be specified in some way.

11 VMS

Not relevant here.

12 Examples

12.1 Example 1

This example shows how to call C05AJF/E using a procedure parameter, the function "f". The example is a translation of the Fortran Library example program into C.

Note that the values of eps are different from those in the NAG manual and the official NAG Fortran example.

#include <math.h>
#include <stdio.h>
#include <nagmk18_t3e.h>

main()
{
  double eps, eta, x;
  int ifail, k, nfmax;
  double f(double *);

  printf("C05AJF/E Example Program Results\n\n");
  for (k=1; k<=2; k++)
    {
      eps = k==1 ? 0.1e-3 : 0.1e-4;
      x = 1.0;
      eta = 0.0;
      nfmax = 200;
      ifail = 1;
 
      C05AJE(&x,&eps,&eta,f,&nfmax,&ifail);

      if (ifail==0)
        printf("With eps = %e   root = %f\n",eps,x);
      else
        {
          printf("ifail = %d\n",ifail);
          if (ifail==3 | ifail==4)
            printf("With eps = %e final value = %f\n",eps,x);
        }
     }
}
double f(double *x)
{
  return exp(-*x) - *x;
}

12.2 Example 2

This is a simplified version of the NAG Fortran Library example program for F01QDF/E. Array sizes have been chosen to be the same as the problem size to illustrate better the use of two dimensional arrays.

Regrettably, I have not gotten this program to work with the NAG C Header Files, because of a conflict between the Fortran CHARACTER and the C char.

I have therefore instead used the Cray approach, documented in in the Cray C/C++ Reference Manual, 004-2179-003, Section 8.1.2, Calling Fortran functions and subroutines from a C or C++ function.

Also note that F01QDF/E is officially withdrawn from the present Mark 18 of the library, but the routines are still available.

The example is available in the file nag2.c. Note that the words "Transpose" and "Separate" are explicitly translated into Fortran CHARACTER strings with the Cray provided functions _cptofcd and strlen.

#include <stdio.h>
#include <fortran.h>

/* Simplified example program for F01QDF/E */

main()
{
  int i,ifail,j,m = 5,n = 3,ncolb = 2;
  int lda = m,ldb = m;
  _fcd ftnstring1, ftnstring2;

  /* Initialise arrays in column major order */
  static double a[3][5] =
    {
      2.0, 2.0, 1.6, 2.0, 1.2,
      2.5, 2.5, -0.4, -0.5, -0.3,
      2.5, 2.5, 2.8, 0.5, -2.9
    };
  static double b[2][5] =
    {
      1.1, 0.9, 0.6, 0.0, -0.8,
      0.0, 0.0, 1.32, 1.1, -0.26
    };
  double work[2],zeta[3];

  printf("F01QDF/E Example Program Results\n\n");
  ifail = 0;
  F01QCE(&m,&n,(double *)a,&lda,zeta,&ifail);
  ifail = 0;

  ftnstring1 = _cptofcd("Transpose", strlen("Transpose"));
  ftnstring2 = _cptofcd("Separate", strlen("Separate"));

  F01QDE(ftnstring1,ftnstring2,&m,&n,(double *)a,&lda,zeta,&ncolb,
          (double *)b,&ldb,work,&ifail);
  printf("Matrix  Q'*B\n");
  for (i=0; i<m; i++)
    {
      for (j=0; j<ncolb; j++)
        {
          printf("%f ",b[j][i]);
        }
      printf("\n");
    }
}

12.3 Example 3

This example illustrates the use of multi-dimension arrays in user supplied functions. It is a translation of the NAG Fortran Library example program for D03PCF/E. Please refer to the NAG Fortran Library documentation for details of this program.
/* D03PCF/E Example Program
   C Version. NAG Copyright 1997. */

#include <stdio.h>
#include <math.h>

/* Include the appropriate NAG C Header File */
#include <nagmk18_t3e.h>

/* Global data */
double alpha;

/* Routine for PDE initial condition */
void uinit(double u[20][2], double *x, int npts)
{
  int i;
  for (i=0; i<npts; i++)
    {
      u[i][0] = 2.0*alpha*x[i];
      u[i][1] = 1.0;
    }
}

/* Define the system of PDEs */
void pdedef(int *npde, double *t, double *x, double *u, double dudx[],
            double p[], double q[], double r[], int *ires)
{
/* Macro to do subscripting into 2 dimensional array p, which
   is passed as double p[]. */
#define P(I,J) p[(I)*(*npde) + (J)]
  q[0] = 4.0*alpha*(u[1] + *x * dudx[1]);
  q[1] = 0.0;
  r[0] = *x * dudx[0];
  r[1] = dudx[1] - u[0]*u[1];
  P(0,0) = 0.0;
  P(0,1) = 0.0;
  P(1,0) = 0.0;
  P(1,1) = 1.0 - (*x)*(*x);
}

void bndary(int *npde, double *t, double u[], double *ux, int *ibnd,
            double beta[], double gamma[], int *ires)
{
  if (*ibnd==0)
    {
      beta[0] = 0.0;
      beta[1] = 1.0;
      gamma[0] = u[0];
      gamma[1] = -u[0]*u[1];
    }
  else
    {
      beta[0] = 1.0;
      beta[1] = 0.0;
      gamma[0] = -u[0];
      gamma[1] = u[1];
    }
}

main()
{
  const int npde=2, npts=20, intpts=6, itype=1, neqn=40, niw=64, nw=1128;
  const double acc = 1.0e-4;
  double hx, pi, piby2, tout, ts;
  const m = 1, itask = 1, itrace = 0;
  int i, ifail, ind, it, j;
  /* u[npts][npde], uout[itype][intpts][npde], w[nw], x[npts] */
  double u[20][2], uout[1][6][2], w[1128], x[20];
  /* xout[intpts] */
  double xout[] = {0.0,0.4,0.6,0.8,0.9,1.0};
  int iw[64];
  void bndary(int *npde, double *t, double *u, double *ux, int *ibnd,
              double *beta, double *gamma, int *ires);
  void pdedef(int *npde, double *t, double *x, double *u, double *dudx,
              double p[], double *q, double *r, int *ires);
  void uinit(double u[20][2], double *x, int npts);

  printf("D03PCF/E Example Program Results\n\n");
  alpha = 1.0;
  ind = 0;

  /* Set spatial mesh points */

  piby2 = 0.5*X01AAE(&pi);
  hx = piby2/(npts-1);
  x[0] = 0.0;
  x[npts-1] = 1.0;
  for (i=1; i<=npts-2; i++)
    x[i] = sin(hx*i);

  /* Set initial conditions */

  ts = 0.0;
  tout = 0.1e-4;
  printf("Accuracy requirement = %lf\n",acc);
  printf("Parameter alpha = %lf\n\n",alpha);
  printf("  T  /  X  ");
  for (i=0; i<=5; i++)
    printf("%8.4lf",xout[i]);
  printf("\n");

  /* Set the initial values */

  uinit(u,x,npts);
  for (i=0; i<=4; i++)
    {
      ifail = -1;
      tout = 10.0*tout;
      /* Cast 2-D array u to double * to match prototype */
      D03PCE(&npde,&m,&ts,&tout,pdedef,bndary,(double *)u,&npts,x,&acc,w,
              &nw,iw,&niw,&itask,&itrace,&ind,&ifail);

      /* Interpolate at required spatial points */

      /* Cast 2-D array u and 3-D array uout
         to double * to match prototypes */
      D03PZE(&npde,&m,(double *)u,&npts,x,xout,&intpts,&itype,
              (double *)uout,&ifail);
      printf("%6.4lf U(1)",tout);
      for (j=0; j<intpts; j++)
        printf("%8.4lf",uout[0][j][0]);
      printf("\n       U(2)");
      for (j=0; j<intpts; j++)
        printf("%8.4lf",uout[0][j][1]);
      printf("\n");
    }
  printf("\n");

  /* Print integration statistics */

  printf("Number of integration steps in time                    %d\n",iw[0]);
  printf("Number of residual evaluations of resulting ODE system %d\n",iw[1]);
  printf("Number of Jacobian evaluations                         %d\n",iw[2]);
  printf("Number of iterations of nonlinear solver               %d\n",iw[4]);
}

12.4 Example 4

This example illustrates the specification of two dimensional arrays in column major order in the C translation of the E04NFF/E example program. It also illustrates that some auxiliary routine names are switched in the single precion version, E04NFU is switched to NFUE04. Results are printed by the NAG routine.

E04NFF/E Example Program

The routine NFUE04 is missing from the NAG header file in Mark 18, therefore I had to write a special short header file for it, see the NFUE04 Header File. As a separate file it has to be referenced with the correct path. In the example it is assumed that the short header file is on the same directory as the example file.

The example worked fine with both the C compiler and the C++ compiler.

12.5 Example 5

The Fortran Library routine F01CTF/E is called with the matrices in the natural C row major order. The arguments TRANSA and TRANSB are used to specify that the matrices should be transposed. The result matrix is then transposed back to row major order using F01CRF. This example also illustrates character string arguments.

F01CTF/E Example Program

This program which does not use the NAG header files works fine with the C compiler but not with the C++ compiler.

12.6 Example 6

F07BEF/E is called with one matrix specified in column major order. Another matrix is loaded with its data using a macro to define the Fortran matrix ordering. Results are printed using X04CAF/E. This example also illustrates character string arguments.

F07BEF/E Example Program

This program which does not use the NAG header files works fine with the C compiler but not with the C++ compiler.

13 Alternative header file

Anton Starikov of Linköping University has revised the NAG header file for easier use on the T3E. There are two main diffferences:

I have run all the six examples above with this header file, and it works with both the C and the C++ compiler. Use the commands

cc -o myprog myprog.c -L/usr/local/lib -lnag
or
CC -o myprog myprog.c -L/usr/local/lib -lnag

The examples have to be slightly modified, and are available as nag1_as.c, nag2_as.c, nag3_as.c, nag4_as.c, nag5_as.c, and nag6_as.c.

There are also two variants of the first example, in order to test the use of complex variables in C and C++, see nag1_as_cc.c for the C version, and nag1_as_CC.c for the C++ version.

14 NAG Mark 19 header file

NAG has revised their header files using the advice (from section 13 above) of Anton Starikov of Linköping University and made them available to NSC. It has the name nagmk19_t3e.h on the T3E area /usr/include and is used with the simple statement
    #include <nagmk19_t3e.h>

This version is recommended for the NAG Library at Mark 19.

I have run all the six examples above with this header file, and it works with both the C and the C++ compiler. Use the commands

cc -o myprog myprog.c -L/usr/local/lib -lnag
or
CC -o myprog myprog.c -L/usr/local/lib -lnag

The examples had to be slightly modified, and are available as nag1_19.c, nag2_19.c, nag3_19.c, nag4_19.c, nag5_19.c, and nag6_19.c.

There are also two variants of the first example, in order to test the use of complex variables in C and C++, see nag1_cc_19.c for the C version, and nag1_CC_19.c for the C++ version.


© The Numerical Algorithms Group Ltd, Oxford UK. 1998/1999