libFDF User Guide

Example

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.

Units handling

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.

Parallel operation

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)