Skip to content

Latest commit

 

History

History
457 lines (337 loc) · 19 KB

Documentation.md

File metadata and controls

457 lines (337 loc) · 19 KB

Fortran Input Parser - Manual

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.

Rules

  • 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.

Rules for variables

  • 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.

Parser usage

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.

Input parser: General program flow

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

Input file name

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.
!-----------------------------------------------------------------------------!

Execute a batch file defined in the input file

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