Skip to content

Fortran

Fortran (formerly FORTRAN) is a high-performance programming language that has been the backbone of scientific computing for decades.

Compiler Support

Multiple Fortran compilers are available on NERSC systems.

Vendor PrgEnv Base Compiler Wrapper
LLVM PrgEnv-llvm flang mpif90
GNU PrgEnv-gnu gfortran ftn
NVIDIA PrgEnv-nvidia nvfortran ftn
Cray PrgEnv-cray crayftn ftn
Intel PrgEnv-intel ifx ftn
AOCC PrgEnv-aocc flang ftn

For detailed information about each compiler, see the base compilers and compiler wrappers documentation.

Using Fortran at NERSC

The recommended way to compile Fortran code on NERSC systems is to use the appropriate compiler wrapper for the toolchain (ftn or mpif90).

Parallel (shared memory, CPU, GPU)

A variety of APIs which support shared memory style programming of CPUs and GPUs are available in Fortran:

Parallel (distributed)

MPI

There are official language bindings for MPI in Fortran. Generally, it is recommended to use mpi_f08 when possible for the safest, most modern version of that API.

Use of mpi_f08 with NVIDIA compilers

use mpi_f08 is not currently supported by the combination of MPICH derivatives (i.e. cray-mpich) and nvfortran.

Multi-image / Coarrays

Fortran has built-in support for a SPMD parallel programming model through the use of multiple images (Fortran processes). These images communicate using a PGAS feature named coarrays, and/or through language intrinsics supporting collective operations and various forms of image synchronization. The one-sided put/get RMA semantics of coarrays and integration with the language enable compact and expressive high-performance code.

To illustrate the difference from MPI consider a 1d ring exchange:

! MPI: Ring exchange
integer :: my_val, recv_val, left, right, req(2), stat(MPI_STATUS_SIZE,2)

call MPI_Comm_rank(MPI_COMM_WORLD, rank, ierr)
call MPI_Comm_size(MPI_COMM_WORLD, nprocs, ierr)

left  = mod(rank - 1 + nprocs, nprocs)
right = mod(rank + 1, nprocs)
my_val = rank * 10

call MPI_Isend(my_val,   1, MPI_INTEGER, right, 0, MPI_COMM_WORLD, req(1), ierr)
call MPI_Irecv(recv_val, 1, MPI_INTEGER, left,  0, MPI_COMM_WORLD, req(2), ierr)
call MPI_Waitall(2, req, stat, ierr)

A similar motif with coarrays:

! Multi-image Fortran: Ring exchange using coarrays
integer :: val[*], left, nbr_val

val = this_image() * 10  ! each image initializes its coarray element
sync all   ! barrier synchronization after initialization
left = merge(num_images(), this_image()-1, this_image()==1)
nbr_val = val[left]   ! read from left neighbor (wraps around)

Support for Fortran's multi-image features varies by system and compiler. On Perlmutter the most mature implementation is available from PrgEnv-cray. Multi-image Fortran programs need not run across separate nodes (it can also be used for intra-node parallelism), but job execution generally requires the use of SLURM srun within an appropriate compute node allocation.

See Also