1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
|
FDF stands for Flexible Data Format, designed within the Siesta
project to simplify the handling of input options. It is based on
a keyword/value paradigm (including physical units when relevant), supplemented by
blocks for arbitrarily complex blobs of data and lists.
LibFDF is the official implementation of the FDF specifications for use in client codes.
At present the FDF format is used extensively by Siesta, and it has
been an inspiration for several other code-specific input formats.
New input options can be implemented very easily. When a keyword is not present
in the FDF file the corresponding program variable is assigned a
pre-programmed default value. This enables programmers of client codes
to insert new input statements anywhere in the code, without taking
care of ``reserving a slot'' in a possibly already crowded
fixed-format input file.
Documentation can be found at [https://siesta-project.github.io/fdf-docs/](https://siesta-project.github.io/fdf-docs/)
### Example
The typical use of FDF in a program is exemplified by the following snippet:
```fortran
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`:
```fortran
...
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
```fortran
...
#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)
### Installation of libFDF with CMake
```
cmake -S. -B_build -DCMAKE_INSTALL_PREFIX=/path/to/install/directory
cmake --build _build
cmake --build _build --target test # To run a simple test
cmake --install _build
```
### Installation of libFDF with autotools
```
./configure --prefix=/path/to/install/directory
make
make check
make install
```
### Compiling user programs with CMake
Just use the standard CMake idiom in your CMakeLists.txt file:
```
add_executable(your_program your_sources)
find_package(libfdf REQUIRED)
target_link_libraries(your_program libfdf::libfdf)
```
The above assumes that the installation directory for libfdf can be
found by CMake. This can be achieved by adding it to the
CMAKE_PREFIX_PATH CMake or enviroment variable:
```
cmake -S. -B_your_build -DCMAKE_PREFIX_PATH="$FDF_ROOT" .......
CMAKE_PREFIX_PATH=$FDF_ROOT cmake -S. -B_your_build .......
```
### Compiling user programs using pkg-config
Both the CMake and the autotools building systems install a libfdf.pc
file in the installation hierarchy. This file can be used by
pkg-config to determine the libfdf module path and the appropriate
link incantation. For autotools the modules will be in
`$FDF_ROOT/include` and the library files in `$FDF_ROOT/lib`, but with
CMake this might vary. In all cases, assuming that PKG_CONFIG_PATH is
set correctly,
```
pkg-config --cflags libfdf
pkg-config --libs libfdf
```
will produce the appropriate include and link strings.
|