FORTRAN 90 standards
When programming in any program language it is important to avoid obsolete, undesired and unnecssarily
complicated constructions, to have well documented codes and codes with a well-defined layout to support
easy understanding and desk checking. By satisfying the proposed rules as outlined below, the code
will be easier to transfer to other programmers. Rules will help the programmer to develop and maintain
the source code.
The following rules should be consider for developing and extending the SWAN source code.
- Code needs to be written in accordance with ANSI FORTRAN 90 standards.
Good texts on programming in FORTRAN 90 are [1] and [2].
- Modular programming is strongly recommended.
- The program code is subdivided into program units or segments of a maximum of 500 source statements.
- Only one statement per line is allowed.
- The first line of every program unit is a PROGRAM, SUBROUTINE, FUNCTION or MODULE.
The PROGRAM statement is obligatory for a main program, and is followed by the comments as described
in Chapter 5.
- Every new program unit needs to be written in free format. Fixed format in the existing program units
is acceptable for the time being. Note that an include file in free format cannot be included in a
fixed form subroutine.
- New program units are given the '.f90' file extension and existing program units retain the '.f' extension
(Linux/Unix) or the '.for' extension (Windows/DOS).
- An exclamation mark (!) is used in the column to indicate a comment line.
- It is preferably to use columns 1 to 5 for labels and columns 7 to 72 for statements (cf. FORTRAN 77).
- Every line contains a maximum of 80 characters. Insert an ampersand (&) as a follow-on mark in the
column, and on the following line in the column.
- Parameter transfer between subroutines takes place preferably via a parameter list and otherwise
via modules. Common blocks are not acceptable.
- All variables in a program unit need to be declared explicitly and be given the INTENT attribute
with the exception of pointers. The first declaration always needs to be the mandatory statement
IMPLICIT NONE. The implicit FORTRAN standard is still used for the purpose of clarity, i.e. integer
names start with i up to and including n, complex variables with c or z,
and all remaining letters are reserved for reals.
- Each variable must be declared in a separate statement.
- Always use the sign :: in the declaration list.
- Use the option as little as possible for array declaration, and define the actual length by means
of parameters wherever possible. This enables good functioning of array bound checkers.
- Variable names have to be distinguishable in the first few characters.
- The meanings of names only apply within a program. They need to be as long as possible and have a logical structure,
i.e. they should indicate their functions, preferably in English.
- Variables need to be given in alphabetical order.
- Use the type declaration instead of the dimension statement to declare local variables:
INTEGER IARRAY (100)
instead of
DIMENSION IARRAY (100).
Never use real expressions in array dimensions.
- Mixed-mode expressions (single-precision/double-precision) are not used.
- Always initialize pointers with the NULLIFY instruction.
- Use as many allocatable arrays as possible, and as little automatic arrays or fixed-length arrays as
possible. The reason is that automatic arrays are placed on the stack, which has a limited size,
so that large arrays can easily cause stack overflow. By contrast, allocatable arrays are always
stored in the heap memory.
- If allocatable arrays are no longer used, they must always be deallocated at the end of the subroutine.
- For validity checks, preference is given to the STAT= attribute for the purpose of array allocation/deallocation.
- Use POINTER and TARGET for very large data sets or linked lists for which the length
is not known beforehand.
- Always end a do loop with END DO instead of CONTINUE. In the case of nested do loops, every do
loop must end with its own END DO statement.
- Use labels to identify the structure of do loops since, this will improve the readability of the
code.
- A combination of upper case and lower case may improve readability, but is not a standard for
fixed-format (cf. FORTRAN 77). In general small letters are recommended.
- Make ample use of spaces, comment blocks and extra space between lines.
- Use multi-dimensional arrays where they match the logical structure, unless this leads to a
considerable increase in memory required. Do not use special auxiliary variables for the purpose
of efficient programming. The compilers achieve this anyway, and the special variables do not
improve readability.
- Use the SAVE attribute (not the SAVE statement!) when the value of a variable
must be retained in the next call of a subroutine.
- Use the parameter statement to define values for constants. This should be done for the logical
unit numbers, array dimensions and physical and numerical constants. The numbers are defined
on just one place in the program (e.g. module), so that changing the value can be done once.
Some constants should not be parameterised, such as which can be calculated with an
intrinsic function: PI = 4.*ATAN(1.).
- Statement labels need to meet the following conditions:
- They are used exclusively for FORMAT statements.
- They are used in ascending order.
- Character strings need to meet the following conditions:
- A string which enters a subroutine via the argument list, must be dimensioned
as a variable in that subroutine: CHARACTER (LEN=*).
- The string length may not be transferred via the argument list. The length is
determined via intrinsic function LEN.
- Strings should not be used as operands in relational operators, such as
.LT., .GT., .EQ., .NE., .LE., .GE.. Use
FORTRAN functions LGE, LGT, LLE, LLT instead.
- ICHAR and CHAR must not be used in a way that makes the code dependent on the
underlying character set (ASCII, EBCDIC). Use the IACHAR and ACHAR statements to
obtain an ASCII number of a specific character or to do the reverse.
- Do not use free format output, i.e. , but always use FORMAT statements. This
facilitates the comparison of the output obtained on various computers. The use of a format
in the WRITE statement itself is not recommended, since it does not improve the
readableness.
- Use arrays as units in expressions to improve readability. This means that the arrays can be treated
as scalar quantities, and can therefore be subject to practically all scalar operations and functions.
- Avoid data-dependency in array expressions.
- Initialize every variable in a subroutine and never assume the compiler sets any value at 0. Avoid saving
a local variable value as much as possible. If this value does need to be saved, then a SAVE attribute
must be used.
- Do not use the following, obsolete, standard FORTRAN 77 statements:
- Statement functions, i.e. a function in one line within a different routine.
- Assigned goto.
- Named common en blank common.
- Arithmetic if (IF ... 100, 200, 300).
- EQUIVALENCE
- ENTRY
- ERR= and END= in read instructions; use IOSTAT specifier instead.
- PAUSE
- More than one entry or output per module (ENTRY, alternate RETURN).
- Jump to ENDIF from outside IF block.
- Non-integer index in a do loop.
- The H edit descriptor.
- Always use the generic name for intrinsic functions, so ABS instead of CABS or DABS.
- Use the following operators in subroutines to be generated: >, >=, <, =<, == and
/=. Using the former style, such as .GT. and .NE., is acceptable in existing subroutines.
- Do not use a STOP except in the following cases:
- an error subroutine after printing of a fatal error,
- in an explicit lockup routine
- Use the SELECT CASE construct in the case of more than two mutually exclusive choices.
- Do not use WHERE statements, as these generally have a negative effect on performance.
- Do not use BLAS routines.
- Do not use a GOTO statement except for error handling. Jump to a CONTINUE statement with a
numerical label (usually 9999), after which the error can be dealt with.
- Develop the code such that it may improve the performance. This means that clean do loops
should be used and, that IF THEN ELSE constructions should be placed outside the do loops,
if appropriate. See also Chapter 9 for more details on how to optimize the code.
- Do not write intermediate results to background memory unless there is a very good reason to
do so. I/O is very expensive and must therefore be avoided wherever possible. It is often much
more favorable to save the intermediate results in an array or, if not enough memory is available,
to recompute them.
- In the case of multi-dimensional arrays applied in nested do loops, it is preferred to use the
inner loop for the first index. On vector computers and machines containing a cache memory, this
approach results in a considerably higher efficiency.
The SWAN team 2022-08-10