This input parser reads and analyzes an input file according to predefined syntactical rules. It is written in Fortran. The idea is to make the input file readable for the human eye.
The main idea is to realize a tool, which enables the user to write position independent (as far as possible) input files. The input files can be changed without recompiling the parser. The parser checks the input file for syntactical correctness, for the presence of required input and for correctness of the data types of the given variable values.
Additionally, functions and variables are supported.
The input parser can be read in several times during a program run, i.e. it is possible to read in an input file which was modified and generated by the program running it.
Any input must be given according to predefined syntactical rules. These rules utilize keywords and specifiers, defined in a file, currently named keywords.val. The name of this file is specified in module parameters in the parser source code. New keywords and specifiers can be added without the need of recompilation. The general syntax to define keywords and specifiers in keywords.val is as follows:
!------------------------
! Syntax definition file
!------------------------
keyword
specifier1 data_type required
specifier2 data_type optional
specifier3 data_type optional
... ... ...
end_keyword
Limitations for keywords and specifiers
Special characters used to identify a keyword are defined in module parameters.
keyword
Each keyword must start with a predefined special character.
This special character is currently set to $
(but can be changed) and is allowed only as the first character of a keyword.
Otherwise, the keyword is an arbitrary string, containing no blanks and no =
signs.
specifier
Arbitrary string, containing no blanks, no $
(which is the special character of the keyword), and no =
sign.
end_keyword
Must match the starting keyword as follows: $keyword
==> $end_keyword
data_type
Each specifier has a fixed data type.
This data type must be defined by a string in the keyword definition file at the position of data_type
.
The following data types are supported:
integer: integer number
integer_array: array of integer numbers
real: single precision real number
real_array: array of single precision real numbers
double: double precision real number
double_array: array of double precision real numbers
character: character string
logical: boolean (.TRUE./.FALSE.)
Instead of logical
we recommend using yes
or no
instead as this is more readable to the human eye.
optional / required
Defines specifier to be optional input or required input.
optional: specifier is optional input (meaning .FALSE.)
required: specifier is required input (meaning .TRUE.)
Example
!-----------------------------------------------------------------------------!
$magnetic-field optional !
magnetic-field-on character required CHOICE[yes,no]
magnetic-field-strength double required !
magnetic-field-direction integer_array required CHOICE[1 0 0,0 1 0,0 0 1]
$end_magnetic-field optional !
!-----------------------------------------------------------------------------!
!-----------------------------------------------------------------------------!
$material required !
material-number integer required ! first entry is separator for new input sequence
cluster-numbers integer_array required !
material-name character required !
alloy-function character optional CHOICE[constant,linear]
alloy-concentration double optional !
band-gaps double_array optional !
crystal-type character optional CHOICE[zincblende,wurtzite]
use-material-parameters-from-database logical optional CHOICE[.TRUE.,.FALSE.]
$end_material required !
!-----------------------------------------------------------------------------!
$
: special sign indicating a keyword ($ can be replaced by the user with a user-defined symbol)!
: special sign indicating a comment (! can be replaced by the user with a user-defined symbol)%
: special sign indicating a variable (% can be replaced by the user with a user-defined symbol)
Note: The first specifier after the starting keyword must be required input. Additionally, it acts as the separator for the new input sequence within a keyword.
An input file looks like this:
#++++++++++++++++++
# Variable section
#++++++++++++++++++
#----------------------------------------------------------------
# By default, we do not evaluate functions.
# Everything is just a simple "Find & Replace String" operation.
#----------------------------------------------------------------
# The % sign indicates that you define a variable which is case-sensitive.
%Material_1 = AlAs # a string variable
%ClusterNumbers = 7 8 # another string variable containing '7 8' including the blank
%Temperature = 300.0 # temperature (DisplayUnit:K)
%alpha = 0.5405e-3 # Varshni parameter alpha (DisplayUnit:eV/K)
%beta = 204.0 # Varshni parameter beta (DisplayUnit:K)
%BandGap_0K = 1.519 # band gap at 0 K (DisplayUnit:eV)
%Include_InAs = .TRUE. # if .TRUE., include material InAs
#%Include_InAs = .FALSE. # if .FALSE., do not include material InAs
# The statement '%FunctionParser = yes' switches the function parser on (default: off).
!-----------------------------
%FunctionParser = yes # needed to evaluate functions (DoNotShowInUserInterface)
!-----------------------------
# Choose GaAs or AlAs
#%Include_GaAs = 1 # if 1 (=true), include material GaAs
%Include_GaAs = 0 # if 0 (=false), do not include material GaAs
%Include_AlAs = 1 - %Include_GaAs # if 1 (=true), include material AlAs, else 0 (=false)
%BandGap_300K = %BandGap_0K - %alpha * %Temperature^2 / ( %Temperature + %beta ) # band gap at 300 K (DisplayUnit:eV)
%Material_2 = 'GaAs' # a string variable after '%FunctionParser = yes' needs quotations marks
%TWO = 2.0
%SEVEN = INT( 5.0 + %TWO ) # INT(...) must be used to convert a float to an integer
!---------------------------------------------------------------------!
$magnetic-field !
magnetic-field-on = yes ! 'yes'/'no'
magnetic-field-strength = 5.0 ! 5.0 T ==> T = [Tesla]
magnetic-field-direction = 0 0 1 ! for [001] direction
$end_magnetic-field !
!---------------------------------------------------------------------!
!---------------------------------------------------------------------!
! You can write comments.
# This is also a comment.
// This is also a comment.
/* This is also a comment. */
// Note: No line breaks are allowed for the comments /* ... */.
< This is also a comment. >
!TEXT
This is a multi-
line comment.
!ENDTEXT
!---------------------------------------------------------------------!
$material ! begin of input sequence for this keyword
material-number = 1 ! material no. 1
cluster-numbers = 1 3 5 6 ! an array of integers
material-name = Al(x)Ga(1-x)As ! a string
alloy-function = constant ! a string
alloy-concentration = 0.3 ! You can write 0.3, 0.3d0 or 0.3e0. It will always be treated as double.
band-gaps = 1.4 2.0 3.0 ! an array of double values
crystal-type = zincblende ! a string
use-material-parameters-from-database = .TRUE. ! a boolean
!-----------------------------------------------------------------------------------
! Now we define material no. 2.
! The first specifier 'material-number' acts as a separator for new input sequence.
!-----------------------------------------------------------------------------------
material-number = 2 ! separator for new input sequence
cluster-numbers = 2 4
material-name = GaAs
material-number = 3 ! material no. 3
cluster-numbers = %ClusterNumbers
material-name = %Material_1
material-number = 4 cluster-numbers = 9 material-name = %Material_2 ! This is a comment. You can specify several specifiers in one line.
material-number = 5 cluster-numbers = 10 material-name = AlAs
material-number = 6 cluster-numbers = 11 material-name = GaAs band-gaps = %BandGap_300K 1.9 2.1
material-number = %SEVEN cluster-numbers = 11 material-name = GaAs
#---------------------------------------------------------
# Conditional IF/WHEN statements are supported like this:
#---------------------------------------------------------
#IF %Include_InAs material-number = 8 cluster-numbers = 12 material-name = InAs
#WHEN %Include_GaAs material-number = 9 cluster-numbers = 13 material-name = GaAs # '#WHEN' has the same effect as '#IF'.
#WHEN %Include_AlAs material-number = 9 cluster-numbers = 13 material-name = AlAs # '#WHEN' has the same effect as '#IF'.
$end_material ! This is matching end keyword.
!---------------------------------------------------------------------!
#------------------------------------------------------------------------
# Here, a batch file in the output folder is generated.
#------------------------------------------------------------------------
!---------------------------------------------------------------------!
$command-line !
execute-command-line = yes ! 'yes'/'no'
!execute-command-line = no ! 'yes'/'no'
$end_command-line !
!---------------------------------------------------------------------!
!DATA
pwd
ls
!ENDDATA
Note: The sum of all specifiers corresponding to one keyword is referred to as input sequence in the following.
Note: The = sign after each specifier is required. You can use another special character instead of this. The special character used is defined in MODULE parameters. The number of input values for array valued specifiers is arbitrary. If the same specifier appears twice or more within one input sequence, the last value is used for single valued input. For array valued input, the additional values are added. However, for the separation specifiers (for a definition see below), this rule does not apply by definition.
You can define predefined options using the optional argument CHOICE
e.g. CHOICE[.TRUE.,.FALSE.]
, CHOICE[1 0 0,0 1 0,0 0 1]
or CHOICE.[zincblende,wurtzite]
.
If the executable with the option -debuglevel 1000, then the file keywords.xml is generated which includes all allowed keywords, specifiers and choices which are used by nextnanomat for its auto completion feature.
- In the input file, the first specifier after the starting keyword must be the same as the first specifier after the starting keyword in the definition file
keywords_inputfile.val
. Due to this limitation, this specifier can be used as a separator for a new input sequence within a start and end keyword structure. Each time, this specifier appears, the beginning of a new input sequence is assumed. These special specifiers are named separation specifiers. Otherwise, the ordering is arbitrary. - Keywords and specifiers may be in the same line or spread over multiple input lines.
- Line breaks are allowed before and after any data value, the = signs and before and after keywords and specifiers.
- Blanks at the beginning of a line are not significant.
- For input of array type, the numbers must be separated by blanks.
- Keywords and specifiers are case-sensitive.
- The
%
sign indicates that that you define a variable. - When the input file is processed, all occurrences of
%variable_name
are replaced by the according strings. - A comment sign
!
is allowed in this line. - Blanks are allowed within the string which is useful for reading in arrays of numbers, e.g.
%variable1 = %xmin %xmax
- Variables and their definitions are case sensitive.
- A variable name must not contain a
-
sign, e.g.%effective-mass = 0.5
is not allowed. - In one line only one variable can be initialized.
To read and analyze the input file, a call to SUBROUTINE read_and_analyze_input
is required.
No argument list is required.
Data value extraction
To extract data for a given specifier, a generic subroutine get_from_inputfile(...)
is supplied.
SUBROUTINE get_from_inputfile(keywordC,newL,specifierC,continueL,value,presentL,line,lastL)
Examples
CALL get_from_inputfile('$material',newL,'material-number',continueL,value%int,presentL,line,lastL)
IF (presentL) THEN
material_number = value%int
ELSE
! e.g. error message or use default value
END IF
CALL get_from_inputfile('$magnetic-field',newL,'magnetic-field-strength',continueL,value%double,presentL,line,lastL)
IF (presentL) THEN
magnetic_field = value%double
ELSE
! e.g. error message or use default value
END IF
keywordC = '$magnetic-field'
specifierC = 'magnetic-field-strength'
CALL get_from_inputfile(keywordC,newL,specifierC,continueL,value%double,presentL,line,lastL)
IF (presentL) THEN
IF ( value%double < 0d0 ) THEN
WRITE(my_output_unit,'(A)') " Error: "//TRIM(specifierC)//" must be a positive value."
CALL Print_Keyword_Specifier_Line(keywordC,specifierC,line,STOP_L=.TRUE.)
ELSE
magnetic_field = value%double
END IF
ELSE
! e.g. use default value
END IF
In the calling subroutine, this module must be included by the USE statement:
USE generic_inputfile,ONLY:get_from_inputfile ! interface to generic subroutine get_from_inputfile(...)
Argument list: Input variables
LOGICAL :: newL
LOGICAL :: continueL
CHARACTER(len=:),ALLOCATABLE :: keywordC
CHARACTER(len=:),ALLOCATABLE :: specifierC
newL
At first entry in subroutine get_from_inputfile
newL
must be set to .TRUE.
.
newL: .TRUE. start new search for keyword
newL: .FALSE. stay at actual keyword
continueL
.TRUE. search for specifier in next input sequence
.FALSE. search in actual input sequence
keywordC
String, containing keyword to be searched for. A keyword can contain up to 100 characters. This should be large enough. It can be adjusted by modifying this variable: char_length_keyword_name = 100
specifierC
String, containing specifier, for which data value is requested. A specifier can contain up to 100 characters. This should be large enough. It can be adjusted by modifying this variable: char_length_specifier_name = 100
Informative output variables
INTEGER :: line
LOGICAL :: presentL
LOGICAL :: lastL
line
line number in input file, where value was found.
presentL
.TRUE.
if a value for actual specifier was found, .FALSE.
otherwise.
lastL
.TRUE.
if last input sequence for given keyword was read, .FALSE.
otherwise.
Generic output
The variable data
in the argument list is representative for one of the possible data type listed beneath for a generic call.
INTEGER,PARAMETER :: char_length_specifier_content = 267 ! A specifier content can contain up to 267 characters.
TYPE :: type_data
INTEGER :: int
INTEGER,DIMENSION(:),POINTER :: int_arrayV
REAL(4) :: single
REAL(4),DIMENSION(:),POINTER :: single_arrayV
REAL(8) :: double
REAL(8),DIMENSION(:),POINTER :: double_arrayV
LOGICAL :: booleanL
CHARACTER(char_length_specifier_content) :: stringC ! to allow for long strings, e.g. long directory names
! CHARACTER(len=:),ALLOCATABLE :: stringC ! to allow for long strings, e.g. long directory names <= does not work
END TYPE_data
The generic argument must be of the same type as the data type of the requested specifier.
This is a description how the main driving routine (MODULE input_driver_module) works which is used for reading input parameters and database information as well as processing and checking the corresponding quantities. The main driving routine for reading input parameters, database information as well as processing and checking the corresponding quantities is input_driver.f90.
CALL InputDriver( InputFilenameC , SetInputFileViaCommandLineL, &
DatabaseFilenameC , SetDatabaseViaCommandLineL )
CALL Collect_Database_Entries
CALL Collect_Inputfile_Entries
The specification of the input filename is done as a first entry in file keywords_inputfile.val
.
It must be the first entry sequence in this validation file.
Example
!-----------------------------------------------------------------------------!
! This must be the first keyword. Do not change the order.
!-----------------------------------------------------------------------------!
$input_filename optional ! Do not change this. This must be the first keyword in this file. Do not change the order.
inputfile.in character optional ! Do not change this. This must be the first specifier in case no input file is specified.
$end_input_filename optional !
!-----------------------------------------------------------------------------!
! End of first keyword. Now the order does not matter.
!-----------------------------------------------------------------------------!
Using !DATA
, a list of commands can be written that are executed during runtime
using a batch script (.bat
on Windows and .sh
on Linux/macOS).
Example
!DATA
pwd
ls *.md
!ENDDATA