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.