This topic is well-named, since it involves a kludge (an ugly potentially dangerous workaround) for a problem that surfaces in certain Fortran90 compilers.
One function of the mediation layer in WRF is to convert the collection of state data stored as a domain object (defined in module_domain.F) at the driver layer into individual arrays and variables that are passed to the model layer. There are two reasons for doing this conversion at a high level in the model call tree, rather than allowing access to domain objects at the model layer. First, since WRF is designed to allow interchangeability of driver layers at the framework level and alternative frameworks may be written in a different language that represents domain objects differently so that they could not be used by Fortran90 model layer routines. Breaking these objects up into simple data types for the model layer ensures this interoperability and flexibility with other community infrastructure software. Second, state arrays in domain objects in the current Fortran90 implementation of the infrastructure are represented as F90 assumed-shape arrays and, for performance reasons, these must be converted to F77 style assumed-size arrays before they are passed to the model layer.
The difference between F90 and F77 arrays is that F90 arrays, while allowed to be dynamically allocatable fields pointed to from a Fortran90 derived data type (ie. a domain object), are not guaranteed to store sequentially indexed array elements contiguously in memory. This property of an array, called contiguity, is relied upon by many compilers to fully optimize loops that contain statements accessing the arrays.
The WRF mediation layer effects the dereferencing of individual fields from the domain object and the conversion of F90 style to F77 style arrays through subroutine calls within the mediation layer. There are a number of examples of this conversion in the WRF code, principal of which is the call between solve_interface and solve_em.
Call in solve_interface (mediation layer):
CALL solve_em ( grid ,
config_flags , &
!
# include <em_actual_args.inc
>
!
)
Subroutine definition in solve_em (lowest level of mediation layer; below here model layer routines are called):
SUBROUTINE solve_em
( grid , config_flags , &
!
#include "em_dummy_args.inc"
!
)
The actual argument list for the call to solve_em #included from a Registry-generated file, em_actual_args.inc, and contains the list fields being dereferences from fields in the grid data structure:
. . ., grid%em_u_1,grid%em_u_2,grid%em_ru, . . .
which correspond to the dummy arguments #included into the definition of solve_em from the Registry-generated file, em_dummy_args.inc:
. . ., u_1,u_2,ru, . . .
Because of the way u_1, u_2, ru, and so on are declared in solve_em they are automatically Fortran77 style assumed-size arrays, and therefore have contiguity. The conversion from Fortran90 assumed-shape arrays in the actual argument list to Fortran77 assumed size arrays in the called subroutine is performed automatically, and is Fortran standard compliant.
A difficult arises on certain compilers, however, and it is called the “copy-in/copy-out” problem. The Fortran standard permits a compiler to handle this conversion using a copy to a temporary data structure. Specifically in the example above, the compiler allocates a temporary Fortran77 array the same size as grid%em_u_1, copies the data from grid%em_u_1 into this temporary array, and then passes the temporary array as the argument. When solve_em returns, the data in the temporary array (possibly modified by solve_em) is copied back into grid%em_u_1. This ensures correct program behavior, but it is also involves an unacceptably high amount of extra memory use and inefficient copying. This is also unnecessary, insofar as the problematic compilers happen to store the Fortran90 arrays with contiguity anyway. No conversion is necessary.
DEREF_KLUDGE, then, is a way of tricking problematic compilers into not performing this copy-in/copy-out conversion. It involves adding indices to array arguments in the CALL statement. It has the effect of passing in only the first element of the array, rather than the entire array. This causes the compiler to use “pass by reference” for the arguments – that is, pass the memory address of the first element rather than the element itself (this was the standard mode in Fortran77). Since the Fortran90 assumed-shape arrays have contiguity, this is functionally correct and avoids a copy.
Note, there are some other compilers that handle the F90/F77 array conversion efficiently that may not accept –DDEREF_KLUDGE. These may complain of an argument type/number mismatch between the actual argument and the corresponding dummy argument in the called routine.
The DEREF_KLUDGE in the WRF software is specified by adding –DDEREF_KLUDGE to ARCHFLAGS in the configure.wrf file. The compile-time settings stored in arch/configure.defaults already contain this setting for the problematic compilers. The DEREF_KLUDGE setting will have the following effects on the WRF compilation:
#ifdef DEREF_KLUDGE
INTEGER :: sm31 , em31 , sm32 , em32 , sm33 , em33
INTEGER :: sm31x, em31x, sm32x, em32x, sm33x, em33x
INTEGER :: sm31y, em31y, sm32y, em32y, sm33y, em33y
#endif
#include "deref_kludge.h"
Note that the Registry generates this file; its contents will set the indices if –DDEREF_KLUDGE.
Also
note the assignments assume that the name of the domain object is grid. If the
domain object is named something else, a pointer to TYPE(domain) named grid
should be declared and set prior to this #include. An example of this occurs in the mediation routine med_nest_move.