Fortran

AMReX has Fortran interfaces to its core data structures, so that a whole application can be written in Fortran. The Fortran tutorials run on CPUs, with MPI and OpenMP, and need a Fortran compiler. They are built only with -DAMReX_FORTRAN_INTERFACES=ON and are skipped in GPU builds. With GNU Make, USE_F_INTERFACES = TRUE and the Src/F_Interfaces/Base package are set in the GNUmakefile. Build only this topic with -DAMReXTutorials_TOPICS=Fortran; see Getting Started.

HeatEquation

Level:

★

Source:

Fortran/HeatEquation

Key APIs:

amrex_base_module, amrex_init, amrex_parmparse, amrex_boxarray, amrex_distromap, amrex_geometry, amrex_multifab, amrex_mfiter, dataptr, fill_boundary, amrex_parallel_reduce_max, amrex_write_plotfile

The problem of HeatEquation written in Fortran: forward Euler for \(\partial\phi/\partial t = D\nabla^2\phi\) on the periodic unit domain, checked against the exact solution.

The main program sets up the grids and the data like its C++ counterpart. The physical domain and the periodicity are given to amrex_geometry through the geometry.* runtime parameters:

! amrex_geometry takes the physical domain and periodicity from the
! geometry.* parameters, so set them before building it.
call amrex_geometry_set_prob_domain([0.0_amrex_real, 0.0_amrex_real, 0.0_amrex_real], &
                                    [1.0_amrex_real, 1.0_amrex_real, 1.0_amrex_real])
call amrex_geometry_set_periodic([.true., .true., .true.])

! Indices are zero-based cell indices, as in C++.
domain = amrex_box([0, 0, 0], [n_cell-1, n_cell-1, n_cell-1])
call amrex_boxarray_build(ba, domain)
call ba%maxSize(max_grid_size)
call amrex_distromap_build(dm, ba)
call amrex_geometry_build(geom, domain)

! One component and one ghost cell for the 2*dim+1 point stencil
call amrex_multifab_build(phi_old, ba, dm, 1, 1)
call amrex_multifab_build(phi_new, ba, dm, 1, 1)

Kernels loop over tiles with an amrex_mfiter in an OpenMP parallel region. dataptr returns a pointer p(i,j,k,n) to the data of a box, indexed by AMReX’s cell indices, which is passed to a plain Fortran loop. Indices beyond amrex_spacedim are 1, so the same code works in 1D, 2D and 3D:

! Fill ghost cells, here all from periodic images and neighbors.
call phi_old%fill_boundary(geom)

dxinv = 1.0_amrex_real / geom%dx

!$omp parallel private(mfi, bx, po, pn)
call amrex_mfiter_build(mfi, phi_new, tiling=.true.)
do while (mfi%next())
   bx = mfi%tilebox()
   po => phi_old%dataptr(mfi)
   pn => phi_new%dataptr(mfi)
   ! phi_old and phi_new have the same boxes and ghost cells.
   call advance_tile(bx%lo, bx%hi, po, pn, lbound(po), ubound(po), &
                     dxinv, dt*diffusion_coef)
end do
call amrex_mfiter_destroy(mfi)
!$omp end parallel

Fortran objects such as amrex_multifab own C++ objects. They are built with amrex_*_build and freed with amrex_*_destroy, and those in the main program must be destroyed before amrex_finalize.

Configure from the repository root, build and run:

cmake -S . -B build -DAMReXTutorials_TOPICS=Fortran -DAMReX_FORTRAN_INTERFACES=ON
cmake --build build --target Fortran_HeatEquation -j 8
cd build/Fortran/HeatEquation
mpiexec -n 2 ./HeatEquation inputs
Finished 69 steps at time 1.0000000000E-02, mode amplitude = 3.0594420565E-01
Max error = 1.9528508660E-03, tolerance = 8.6145674863E-03
PASSED