Fortran's command-line parameter input made simple.
This Fortran library provides a simple framework to handle input parameters
given by command-line arguments, like ./a.out a=1 dt=0.01 method=rk45.
These parameters can also be read from specified input files as ./a.out input.txt.
program demo
use, intrinsic :: iso_fortran_env, only: dp => real64
use paramcard, only: paramcard_get, paramcard_summary
implicit none
integer :: a, b
real(dp) :: x, y
character(:), allocatable :: msg
call paramcard_get('a', a, 1)
call paramcard_get('b', b, 2)
call paramcard_get('x', x, 0.3_dp)
call paramcard_get('y', y, 0.4_dp)
call paramcard_get('msg', msg, '')
call paramcard_summary
print *, 'a + b = ', a + b
print *, 'x + y = ', x + y
if (msg /= '') print *, msg
end program demoThe paramcard_get subroutine takes 3 arguments: name, variable and default_value.
They specify the parameter name, the destination variable to store the parameter value
and the (optional) default value, respectively.
The paramcard_summary subroutine prints the summary of the input parameters and
checks if there are any given parameters that are actually unused in the program.
The compiled program will accept command-line arguments like
./demo a=101 x=0.6 msg='Hello, World!', where parameters are overridden in the form of
name=value. Parameter names are case- and space-insensitive.
It is also possible to pass parameters via input text files like
./demo input.txt.
An example of an input file is as follows:
# Comment lines start with "#" or "!".
a = 101
x = 0.6
msg = Hello, World!The output of the above example looks as follows:
a = 101 (default: 1)
b = 2
x = 0.59999999999999998 (default: 0.29999999999999999)
y = 0.40000000000000002
msg = Hello, World! (default: )
a + b = 103
x + y = 1.0000000000000000
Hello, World!
The library works with Fortran 2008 compliant compilers.
Because this is a single-file library, one can just copy a MIT-licensed file
paramcard.f90
to one's project:
curl -O https://raw.githubusercontent.com/tueda/paramcard/v0.2.3/src/paramcard.f90Alternatively, one can use this repository as a submodule of one's Git repository:
git submodule add https://github.com/tueda/paramcard.git extern/paramcard
git -C extern/paramcard checkout v0.2.3which makes the library source available at extern/paramcard/src/paramcard.f90.
Integration with fpm (v0.8.0+) is also available:
[dependencies]
paramcard = { git = "https://github.com/tueda/paramcard", tag = "v0.2.3" }CMake (v3.14+) integration with the FetchContent module:
include(FetchContent)FetchContent_Declare(
paramcard
GIT_REPOSITORY https://github.com/tueda/paramcard.git
GIT_TAG v0.2.3
)
FetchContent_MakeAvailable(paramcard)
if(paramcard_POPULATED)
add_library(paramcard STATIC ${paramcard_SOURCE_DIR}/src/paramcard.f90)
endif()target_link_libraries(main PRIVATE paramcard)Integration with CPM.cmake:
CPMAddPackage(
NAME paramcard
GIT_REPOSITORY https://github.com/tueda/paramcard
VERSION 0.2.3
DOWNLOAD_ONLY YES
)
if (paramcard_ADDED)
add_library(paramcard STATIC ${paramcard_SOURCE_DIR}/src/paramcard.f90)
endif()target_link_libraries(main PRIVATE paramcard)In the paramcard module, the following procedures are available.
Read a parameter specified by name into variable.
character(len=*), intent(in) :: name
character(len=:), intent(out), allocatable :: variable
character(len=*), intent(in), optional :: default_valuecharacter(len=*), intent(in) :: name
integer(kind=int8/int16/int32/int64), intent(out) :: variable
integer(kind=int8/int16/int32/int64), intent(in), optional :: default_valuecharacter(len=*), intent(in) :: name
real(kind=real32/real64), intent(out) :: variable
real(kind=real32/real64), intent(in), optional :: default_valuename: the name of the parameter.variable: the variable to store the parameter value.default_value: the value to be used when the specified parameter is not defined from the input. If the default value is not given, then an undefined parameter leads to an error.
Set (overwrite) a parameter specified by name as value for later use.
character(len=*), intent(in) :: name
character(len=*), intent(in) :: value
logical, intent(in), optional :: consumedcharacter(len=*), intent(in) :: name
integer(kind=int8/int16/int32/int64), intent(in) :: value
logical, intent(in), optional :: consumedcharacter(len=*), intent(in) :: name
integer(kind=real32/real64), intent(in) :: value
logical, intent(in), optional :: consumedname: the name of the parameter.value: the value to be associated with the parameter.consumed: whether this parameter should be considered consumed (used) or not. (Default:.true.)
Set a parameter by parsing a string containing NAME = VALUE.
character(len=*), intent(in) :: strstr: the string to be parsed.
Print the summary of input parameters.
integer, optional, intent(in) :: unit
logical, optional, intent(in) :: only_changed
logical, optional, intent(in) :: show_default
logical, optional, intent(in) :: check_unused
character(len=*), optional, intent(in) :: prefixunit: the unit number for the output. (Default:output_unit)only_changed: print only parameters that are changed from those default values. (Default:.false.)show_default: print the default values. (Default:.true.)check_unused: check unused (not-consumed) parameters and raise an error if found. (Default:.true.)prefix: the prefix to each line in the output. (Default:'')
Perform a string formatting (interpolation) operation.
character(len=*), intent(in) :: fmt
character(len=:), allocatable :: resultfmt: the format to be used. Parameters are substituted by braces, for example,'I have {n} apples.'- Return
result: the formatted string.
Write output to a file with a format.
The output file name and the format are specified by parameters.
The output is constructed by using paramcard_format.
This subroutine does nothing if the file name or the format is empty.
character(len=*), intent(in), optional :: file_param
character(len=*), intent(in), optional :: format_paramfile_param: the parameter to specify the output file. (Default:'output_file')format_param: the parameter to specify the output format. (Default:'output_format')
We also provide old-fashioned procedures (with some limitations) that can be used without using the module.
PROGRAM DEMO77
INTEGER A, B
DOUBLE PRECISION X, Y
CHARACTER*40 MSG
C
CALL PARAMCARD_GET_I('A', A, 1)
CALL PARAMCARD_GET_I('B', B, 2)
CALL PARAMCARD_GET_D('X', X, 0.3D0)
CALL PARAMCARD_GET_D('Y', Y, 0.4D0)
CALL PARAMCARD_GET_S('MSG', MSG, '')
CALL PARAMCARD_SUMMARY
C
WRITE (*,*) 'A + B = ', A + B
WRITE (*,*) 'X + Y = ', X + Y
IF (MSG .NE. '') WRITE (*,*) MSG
C
STOP
ENDcharacter(len=*), intent(in) :: name
character(len=*), intent(out) :: variable
character(len=*), intent(in) :: default_valuecharacter(len=*), intent(in) :: name
integer, intent(out) :: variable
integer, intent(in) :: default_valuecharacter(len=*), intent(in) :: name
real, intent(out) :: variable
real, intent(in) :: default_valuecharacter(len=*), intent(in) :: name
double precision, intent(out) :: variable
double precision, intent(in) :: default_valuecharacter(len=*), intent(in) :: name
character(len=*), intent(in) :: valuecharacter(len=*), intent(in) :: name
integer, intent(in) :: valuecharacter(len=*), intent(in) :: name
real, intent(in) :: valuecharacter(len=*), intent(in) :: name
double precision, intent(in) :: valuecharacter(len=*), intent(in) :: file_param
character(len=*), intent(in) :: format_parambrew install ford gcc git lcov pre-commit python fortran-lang/fortran/fpmpre-commit installpre-commit run --all-file # linter, formatter and preprocessor
fpm test # testing
GCOV=gcov-12 ./scripts/gen-coverage.sh # coverage report
ford API-doc-FORD-file.md # documentation