Sick and tired using temporary variables to read nml files into members of derived types? I know I am. Well, the pain ends here…
The built-in namelist (nml
) reader of Fortran is quite nice and capable. It does, however, have certain drawbacks. For example, it is difficult to read the full list of variables from an nml
group into members of a derived type object. The technical reason for this is that the language does not allow reading into an nml
defined from a polymorphic type.
Don’t believe me? Try to write an nml
reader where you pass your data type in as class(*)
. Go on…give it a try! What’s that? You want to extend your data type into a nml_readable
type and pass that in instead? Well, try it! Are you now mumbling something about using an association
block? Won’t work. How about pointer association, type check, and a block
? Still no.
Practically, what this means is that a bunch of temporary variables have to be defined to read the nml
variables before copying them into the appropriate members of some derived type object. It gets pretty tedious pretty quickly…
Here, I pass the name of the group, the name of the object (obj
), the name of the parent nml
file, and a result child nml
file to the subroutine get_group_nml_file
. Note that the parent file can contain many nml
groups. The subroutine uses awk
and sed
to pull from the parent file the specied group and creates a child file containing just that group. It then prepends <obj>%
before all the elements of the group in that child file. Now the child file can be used to read the nml
for the object in one fell swoop.
The client side code can then look like the following:
subroutine read_from_input(this, parent_nml_file)
type(data), intent(inout) :: this
character(*), intent(in) :: parent_nml_file
integer :: ifile
character(:), allocatable :: group_nml_file
namelist /params/ this
call get_group_nml_file(group = 'params', obj = 'this', &
parent_nml_file = parent_nml_file, &
child_nml_file = group_nml_file)
open(newunit = ifile, file = group_nml_file, &
status = 'old', action = 'read')
read(ifile, nml = params)
close(ifile)
end subroutine read_from_input
To build and install the library, and to run the example client app showing the usage of the library, say
fpm install; fpm run
The library is a single file, which, if you want, you can simply place in your own (GPL3+ compatible) project. Or you can specify the dependency to this git repo in your fpm.toml
file.
Are you disgusted by regular expressions and find awk
and sed
headache inducing? Do you have a more elegant solution to this problem? Are you a functional warrior and by Tour de Force wrote an I/O monad in Fortran that solves this issue? Well, I’d love to hear about your solution, genius!