The typical use of FDF in a program is exemplified by the following snippet:
use precision, only : dp
use fdf, only: fdf_init, fdf_get
use units, only: eV ! approx 1.0/13.6
integer :: npts
logical :: debug
real :: energy_tol
call fdf_init("sample.fdf","fdf-log.out")
npts = fdf_get("NumberOfPoints",100)
debug = fdf_get("Debug",.false.)
energy_tol = fdf_get("energy-tolerance",0.01*eV,"Ry")
...
If the contents of sample.fdf
are
number-of-points 200
energy-tolerance 0.001 eV
the variables npts
, debug
, and energy_tol
will be assigned the values
200, .false.
, and 0.001/13.6 (0.001 eV in Ry), respectively.
In the absence of the debug
label in the fdf file, the variable has
taken its default value as specified in the program.
The case of energy_tol
merits a special discussion. It is an example of a magnitude with units.
Here, the program works internally in Rydberg (Ry) units. The energy tolerance variable has to
store a Ry value, and this is specified by the last argument in the call to fdf_get
. The default
value in this case is set to 0.01 eV by making use of a parameter eV
exported by a units
module.
These unit conversions work out of the box in the current fdf implementation, through the use by default of
a legacy unit handler and table appropriate for the domain of materials physics. For general use, a
client program should set its own table and handler. This is exemplified in the file tests/test-units.f90
:
...
use units_m, only: inquire_unit
...
! Initialize
call fdf_init('units-test.fdf', 'units-test.out')
call fdf_set_unit_handler(inquire_unit)
...
The handler inquire_unit
is passed to fdf after fdf initialization
with the call to fdf_set_unit_handler
. From then on, fdf will set
the (astrophysics-related) units table for the conversions.
When working in parallel, there is an extra step in the initialization phase
...
#ifdef MPI
use mpi
#endif
use fdf
use units_m, only: inquire_unit
...
if (Node .eq. 0) then
call fdf_init(filein, fileout)
else
! Non-root ranks will need an extra step endif
!
#ifdef MPI
call broadcast_fdf_struct(0,mpi_comm_world)
#endif
call fdf_set_unit_handler(inquire_unit)
!! call fdf_set_unit_handler(fdf_legacy_unit_handler)
...
to broadcast the FDF database object to all the processors. The
routine broadcast_fdf_struct
can be found in file
broadcast_fdf_struct.F90
in the doc
subdirectory of the libFDF
distribution. It should be general enough for most codes. Note that
the unit handler should be set AFTER the broadcast operation. If no
custom handler is available, and the legacy units are appropriate, the
second (commented out) form of the call should be used.
(This is different in MPI operation due to the danger of setting different handlers for the root and non-root ranks: forgetting the call after the broadcast would leave the root rank with the default handler, and no handler for the rest)