NERSCPowering Scientific Discovery Since 1974

Interlanguage Programming

This page provides examples of compilation and running scripts when mixing C/C++ with Fortran codes.

C/MPI Main Calling Fortran Subroutine

Here is a full example of a parallel C code using MPI which calls a Fortran subroutine. The Fortran subroutine sets a number of data values based on the MPI task ID. The code is compiled and run using the batch system.

C Source Code

% cat cmainmpi.c

#include "mpi.h"

int main(int argc, char* argv[]) {
   char bool1, letter1;
   int numint1, numint2;
   float numfloat1;
   double numdoub1;
   short numshor1;
   extern void forts_();
   int myid, numprocs;
 
   MPI_Init(&argc,&argv);
   MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
   MPI_Comm_rank(MPI_COMM_WORLD,&myid); 

   forts_(&bool1, &letter1, &numint1, &numint2, &numfloat1,
          &numdoub1, &numshor1, &myid, 1);

   printf(" Hello from proc %d of %d; data values: %s %c %d %d %3.1f %.0f %d\n",
      myid, numprocs, bool1?"TRUE":"FALSE", letter1, numint1,
      numint2, numfloat1, numdoub1, numshor1); 

   MPI_Finalize();
}

Fortran Source Code

% cat forts.f

      subroutine forts(bool1,letter1,numint1,numint2,numfloat1,
    &                      numdoub1,numshor1,numtask)
      logical*1 bool1
      character letter1
      integer numint1, numint2, numtask
      double precision numdoub1
      real numfloat1
      integer*2 numshor1
      
      bool1 = .true.
      if (numtask .ne. 2*(numtask/2)) bool1 = .false.
      letter1 = "y"
      numint1 = 11*numtask
      numint2 = numtask
      numdoub1 = 902
      numfloat1 = 39.6 + (0.1*numtask)
      numshor1 = 299
      
      return
      end

Batch Job Script

% cat runhello

#PBS -N hellojob
#PBS -q debug
#PBS -l mppwidth=4
#PBS -l walltime=00:05:00
#PBS -e hellojob.out
#PBS -j eo

cd $PBS_O_WORKDIR

cc -c cmainmpi.c
ftn -o cftnmpi -Mnomain cmainmpi.o forts.f
aprun -n 4 ./cftnmpi

Output File

 

% cat hellojob.out
Warning: no access to tty (Bad file descriptor).
Thus no job control in this shell.
forts.f:
Hello from proc 0 of 4; data values: TRUE y 0 0 39.6 902 299
Hello from proc 3 of 4; data values: FALSE y 33 3 39.9 902 299
Hello from proc 2 of 4; data values: TRUE y 22 2 39.8 902 299
Hello from proc 1 of 4; data values: FALSE y 11 1 39.7 902 299
Application 8551030 resources: utime ~0s, stime ~0s

C++/MPI Main Calling Fortran Subroutine

Here is a full example of a parallel C++ code using MPI which calls a Fortran subroutine. The Fortran subroutine sets a number of data values based on the MPI task ID. The code is compiled and run using the batch system.

C++ Source Code

% cat cpmain.C

#include <mpi.h>
#include <iostream>
using namespace std;

extern "C" { extern void forts_(char *,char *,int *,int *,
            float *,double *,short *); }

int main (int argc, char* argv[])
{
 char bool1, letter1;
 int numprocs, myid;
 float numfloat1;
 double numdoub1;
 short numshor1;

 MPI_Init(&argc, &argv);
 MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
 MPI_Comm_rank(MPI_COMM_WORLD,&myid);

 forts_(&bool1,&letter1,&myid,&numprocs,&numfloat1,&numdoub1,&numshor1);

 cout << " bool1 = ";
 bool1?cout << "TRUE ":cout << "FALSE ";
 cout << "; letter1 = " << letter1 << "; myid = " << myid << " numprocs = " << numprocs;
 cout << " myid/numprocs  = " << numfloat1 << endl;
 cout << " numdoub1 = " << numdoub1 << " numshor1 = " << numshor1 << endl;

 MPI_Finalize();
}

Fortran Source Code

% cat forts.f

       subroutine forts
     &    (bool1,letter1,numint1,numint2,numfloat1,numdoub1,numshor1)

       logical*1 bool1
       character letter1
       integer numint1, numint2
       double precision numdoub1
       real numfloat1
       integer*2 numshor1

       bool1 = .true. 
       if (numint1 .ne. 2*(numint1/2)) bool1 = .false.
       letter1 = "v" 
       numdoub1 = 902
       numfloat1 = (1.0*numint1)/(1.0*numint2)
       numshor1 = 299

       return
       end

Batch Job Script

% cat runftncpp

#PBS -N ftncpp
#PBS -q debug
#PBS -l mppwidth=4
#PBS -l walltime=00:01:00
#PBS -e ftncpp.out
#PBS -j eo

cd $PBS_O_WORKDIR

ftn -c forts.f
CC -o cppftn forts.o cpmain.C

aprun -n 4 ./cppftn

Output File

% cat ftncpp.out

Warning: no access to tty (Bad file descriptor).
Thus no job control in this shell.
cpmain.C:
bool1 = TRUE ; letter1 = v; myid = 0 numprocs = 4 myid/numprocs = 0
bool1 = FALSE ; letter1 = v; myid = 1 numprocs = 4 myid/numprocs = 0.25
bool1 = FALSE ; letter1 = v; myid = 3 numprocs = 4 myid/numprocs = 0.75
bool1 = TRUE ; letter1 = v; myid = 2 numprocs = 4 myid/numprocs = 0.5
numdoub1 = 902 numshor1 = 299
numdoub1 = 902 numshor1 = 299
numdoub1 = 902 numshor1 = 299
numdoub1 = 902 numshor1 = 299
Application 8551267 resources: utime ~0s, stime ~0s

C/MPI Main Calling Fortran/OpenMP Subroutine

Here is a full example of a parallel C code using MPI which calls a Fortran subroutine. The Fortran subroutine includes a multi-threaded parallel segment and sets a number of data values based on the MPI task ID and number of OpenMP threads. The code is compiled and run using the batch system.

The environment variable OMP_NUM_THREADS is used to control the number of threads in the OpenMP segment.

Use of OpenMP requires a particular set of options on the Fortran compiler line: ftn -mp=nonuma -Minfo=mp ....

The source code for the C main program is the same as shown above. The Fortran routine, the batch script, and the output for the mixed C/Fortran and mixed MPI/OpenMP example are shown below.

Fortran Source Code

% cat forts.f

      subroutine forts2(bool1,letter1,numint1,numint2,numfloat1,
    &                      numdoub1,numshor1,numtask)
      logical*1 bool1
      character letter1
      integer numint1, numint2, numtask
      integer nthreads, tid
      integer  OMP_GET_NUM_THREADS, OMP_GET_THREAD_NUM
      double precision numdoub1
      real numfloat1
      integer*2 numshor1

      bool1 = .true.
      if (numtask .ne. 2*(numtask/2)) bool1 = .false.
      letter1 = "y"
      numint1 = 11*numtask
      numint2 = numtask
      numdoub1 = 902
      numfloat1 = 39.6 + (0.1*numtask)
!$OMP PARALLEL PRIVATE(nthreads, tid)
       tid = OMP_GET_THREAD_NUM()
       IF (tid .EQ. 0) THEN
          nthreads = OMP_GET_NUM_THREADS()
          numshor1 = nthreads
       ENDIF
!$OMP END PARALLEL
      
      return
      end

Batch Job Script

% cat runhello2

#PBS -N hellojob2
#PBS -q debug
#PBS -l mppwidth=24
#PBS -l walltime=00:05:00
#PBS -e hellojob2.out
#PBS -j eo

cd $PBS_O_WORKDIR

cc -c cmainmpi.c
ftn -o cftnmpi -Mnomain -mp=nonuma -Minfo=mp cmainmpi.o forts.f

setenv OMP_NUM_THREADS 6
aprun -n 4 -N 4 -S 1 -d 6 ./cftnmpi

Output File

% cat hellojob2.out
Warning: no access to tty (Bad file descriptor).
Thus no job control in this shell.
forts.f:
forts:
19, Parallel region activated
24, Parallel region terminated
Hello from proc 3 of 4; data values: FALSE y 33 3 39.9 902 6
Hello from proc 1 of 4; data values: FALSE y 11 1 39.7 902 6
Hello from proc 0 of 4; data values: TRUE y 0 0 39.6 902 6
Hello from proc 2 of 4; data values: TRUE y 22 2 39.8 902 6
Application 8551213 resources: utime ~0s, stime ~0s