WRF - Errors in INTENT Declarations
INTENT Violations in WRF - The Issue
An INTENT (IN) violation occurs when an argument declared INTENT (IN) is written to.
In both WRF version 3.4.1 and version 3.6.1 there are 138 occurrences.
The Fortran INTENT Declaration
The Fortran INTENT declaration specifies that an argument to a subroutine or function is:
(Note that there are other possible intents. An argument may be a sub-program, or it may be a variable which is used to supply attributes such as array bounds but which is neither read no written. No explicit INTENT specification is available for these.)
INTENT Violations and Compiler Error Detection
A simple INTENT (IN) violation is shown below:
SUBROUTINE s (a)
REAL, INTENT (IN) :: a
END SUBROUTINE s
The argument a is declared INTENT (IN) and cannot therefore be written to. We write to it explicitly across an = sign. This is an error and is detected by all compilers which we have tested (gfortran, g95, ifort, ftn95, Compaq Visual Fortran).
INTENT (IN) violations may also be created indirectly, by passing an INTENT (IN) argument down to a second routine which writes to it, for example:
SUBROUTINE s1 (a)
REAL, INTENT (IN) :: a
CALL s2 (a)
END SUBROUTINE s1
SUBROUTINE s2 (b)
END SUBROUTINE s2
This error is detected by only one of the compilers which we have tested, ftn95, and even this compiler misses the error if the subroutines s1 and s2 are written within a Fortran module. The error is not detected by either gfortran or ifort which are commonly used to build WRF.
An INTENT (OUT) violation is shown below:
SUBROUTINE s (x,px,v,dt)
REAL, INTENT (OUT) :: x, px
REAL, INTENT (IN) :: v, dt
px = x
x = x + v * dt
END SUBROUTINE s
The variable x is declared INTENT (OUT) but it is copied before it is written to. Clear errors like this do not occur in WRF.
Finding INTENT Errors in WRF
The read and write access to variables is traced by fpt down through sub-program calls. The procedure to assess the number of INTENT errors in WRF is:
All of the INTENT (IN) and potential INTENT (OUT) violations will be reported. The report ends with the summary, for example for WRF V3.4.1:
Total number of arguments 55908
Declared INTENT(IN) 28974
Declared INTENT(OUT) 6196
Declared INTENT(INOUT) 5395
No INTENT declaration 15318
Sub-program formal arguments 25
INTENT(IN) Violations 138 0.5%
INTENT(OUT) Violations 0 0.0%
Additional possible INTENT(OUT) Violations 1685 27.2%
The possible INTENT (OUT) violations are situations where the program flow may be such that an INTENT (OUT) argument is read before it is written.
The number of INTENT (IN) violations is a concern. The problem is that the Fortran standard explicitly states that the INTENT specification may be used to control code generation. If an argument is INTENT (IN) the sub-program need not export it. If an argument is INTENT (OUT) a sub-program need not import it. This could be significant in a multi-processor environment where inport or export may be expensive.
Do Compilers Use the INTENT Declarations?
There is a command in fpt to remove almost all of the INTENT declarations in a program. The arguments then default to INTENT (INOUT) and are always imported and exported. A small number of INTENT declarations are required by the language. These occur in the interfaces to overloaded operators and in functions with the attributes PURE and ELEMENTAL. There are a small number of these in WRF (For example, one overloaded operator and one ELEMENTAL routine in WRF V3.4.1). All other INTENT declarations can be removed.
The script tools/WRFV3_fpt_experient.csh has been set up to run an experiment as follows:
This process is described in more detail in the wrf_experiments page.
Run the experiment remove_intent:
$ tools/WRFV3_fpt_experiment.csh WRFV3.6.1 remove_intent
$ tools/WRFV3_fpt_experiment.csh WRFV3.4.1 remove_intent
The WRF Fortran files built for this experiment are copied to the directories, e.g. WRFV3.6.1_remove_intent/WRFV3/... . Compare these files with the original UCAR sources, and with WRFV3.6.1_vanilla/WRFV3... or with WRFV3.4.1_vanilla/WRFV3... if you have already made the vanilla (Unchanged) run. We strongly recommend Beyond Compare from Scooter Software to make this comparison. Specify the rule that Fortran comments are delimited by "!" and that comments are unimportant differences.
In our runs, with gfortran and ifort, the wrfout output files are identical to those generated by a standard UCAR build. The compilers tested do not use the INTENT declarations to control code generation. Note that we have just removed about 35,000 INTENT declarations from the code without affecting the behaviour in any way! However, compilers may exist which do make use of INTENT declarations, and if WRF is built with these compilers the results might change.
Enforcing INTENT (IN) as Declared
There is a command in fpt to re-engineer code so as to enforce the declared INTENT (IN) (Please see ENFORCE INTENT (IN) AS DECLARED). Wherever an INTENT (IN) violation is detected fpt declares a new temporary variable with the same attributes as the argument concerned and copies the argument to it. This temporary variable is then used in the code of the sub-program instead of the argument. For example, in the file WRFV3/frame/md_calls.inc , in the subroutine:
CHARACTER*(*),INTENT(IN) :: element
the variable element is written to in the routine ext_ncd_put_dom_td_char. The declaration is therefore added:
The argument is copied to the temporary:
element_copy = element
and the calls are modified to use the temporary variable, e.g.
CALL ext_ncd_put_dom_td_char(hndl,element_copy,datestr_copy,data, &
To test the effect of enforcing the INTENT (IN) as declared:
(Please see the notes above on the script WRFV3_fpt_experiment.csh).
In the tests which we have made, the output files generated by running wrf_enforce_intent_in.exe are identical to those produced by a standard UCAR build. The 138 INTENT (IN) violations do not affect the results. However, many more tests are required to be confident that this is always the case.
The Implications for WRF
For the most part, the news is good:
However, the situation is not entirely satisfactory because some compilers may make use of the INTENT declarations. The options are:
Option 1 is unsatisfactory because WRF is under continuous development. The large number of violations in the code suggest that the INTENT construct cannot be maintained by hand.
Option 2 removes the risk of compilers mis-interpreting the code, It also removes the risk that maintainers will rely on the INTENT declarations and will inject errors as a result. However, the INTENT declarations are valuable documentation, and compilers may produce code to check them in the future (ftn95 already does so in most cases).
Option 3 depends on the continued availability of tools which can read the WRF source, and this cannot be guaranteed indefinitely.
The Implications For The Fortran Language
Experience of WRF (and of other codes) suggests that the INTENT construct cannot be maintained safely and reliably by hand.
A potential problem arises because the Fortran Standard states that INTENT declarations may be used to control code generation.
It is propsed that the standard should be changed to state that INTENT declarations may NOT be used to control code generation
unless they are checked for correctness by the system. Incorrect INTENT declarations could still mislead maintainers of a code,
but this problem may disappear if the checks made by compilers are improved.
Copyright ©1995 to 2018 Software Validation Ltd. All rights reserved.