Fortran examples¶
The ADIOS2 Fortran bindings are documented in https://adios2.readthedocs.io/en/latest/api_full/api_full.html#fortran-bindings.
When writing Fortran code, it comes handy to look at the source code of the Fortran bindings directly to find the possible signatures of each function, and especially at the ADIOS2 constants.
Including ADIOS2 in a Fortran application¶
ADIOS2 is using a Fortran 90 interface, so it cannot be directly used in an F77 code base. Files that include adios calls, should be named *.F90 (capital F) so that macros are pre-processed by the Fortran compiler.
Since ADIOS2 is object-oriented and is implemented in C++, there is a need to use global variables in Fortran to initialize an adios
object and to keep it alive (“in scope”) as long as it is needed. Usually, the adios object is created after MPI is initialized and destroyed before MPI is finalized. An io
object is used to define all variables, attributes and runtime parameters for an input or output. Finally, an engine
object needed to call the actual operations on the input or output (open, close and read/write-related calls).
The easiest way to manage the objects is to put them into a new module for ADIOS I/O. The example is in source/fortran/adios-module/adiosio.F90
Assuming you have the MPI communicator in another module name mpivars, and the communicator is named app_comm:
module adiosio
use adios2
implicit none
type(adios2_adios) :: adios2obj
type(adios2_io) :: io_diag
type(adios2_engine) :: engine_diag
contains
subroutine init_adiosio()
use mpivars
use adios2
implicit none
integer*4 :: err
call adios2_init(adios2obj, app_comm, err)
if (.not.adios2obj%valid) then
write(*,*) "Error when creating ADIOS2 object"
endif
end subroutine init_adiosio
subroutine finalize_adiosio()
use adios2
implicit none
integer*4 :: err
! close the engine now if it was not closed yet
if (engine_diag%valid) then
call adios2_close(engine_diag, err)
endif
if (adios2obj%valid) then
call adios2_finalize(adios2obj, err)
endif
end subroutine finalize_adiosio
end module adiosio
Note
The example above adds an IO and an Engine object to the module, which is not required if you write an output or read an input in a single subroutine and do so only once. However, if you want to refer to them in multiple subroutines, or you want to read/write multiple steps, you need to keep these objects (technically, object references) alive to avoid premature destruction of the C++ objects behind.
Note
The example above also closes the engine object in the finalization. This is an example to follow if you want to open an output somewhere else in the code, and output new data (new steps) regularly until the end. This usage is not encouraged here. It is cleaner if you manage the (single) open and (single) close of your outputs and the (multiple) output steps yourself. However, in existing large applications with many optional modules it may be difficult to find the exact spot where the output stream actually ends. This subroutine is the last point where the output must be closed.
In the main program, include these snippets of code:
program adios2_module_example
use mpivars
#ifdef ADIOS2
use adiosio
#endif
implicit none
...
! After call MPI_Init()
#ifdef ADIOS2
call init_adiosio()
#endif
...
! Before call MPI_Finalize()
#ifdef ADIOS2
call finalize_adiosio()
#endif
Note
We are using the ADIOS2 macro everywhere to allow for building the application with or without ADIOS2. If you make ADIOS2 a required dependency, there is no need for this macro.