Fortran-90 MODULE M3UTILIO

Summary

Fortran-90 style MODULE M3UTILIO does the "proper F90 way" of encapsulating the Models-3 I/O API parameter, data structure, and function-declarations, in a way that nested Fortran USE <module> constructs do not interact with older Fortran INCLUDE statements to generate multiple-declaration errors at compile time.

The issue is that when one has two or more Fortran-90 MODULEs, say MODULE A that USEs MODULE B, where both of these need access to facilities provded by the standard I/O API INCLUDE files PARMS3.EXT, FDESC3.EXT, and/or IODECL3.EXT, there is a problem: if MODULE B INCLUDEs these, it introduces an artificial dependency of MODULE A upon MODULE B: where should the INCLUDE statements be placed (if they appear in both MODULEs, the compiler will complain that variables and functions have repeated declarations, which is illegal. The problem is even worse if MODULE A USEs a third MODULE C, independent of B, that also needs I/O API INCLUDE files: one can't necessarily make C USE B, or vice versa.

However, the Fortran-90 USE construct does not have this problem: MODULEs A, B, and C can all have statements USE M3UTILIO without causing multiple-declaration problems: the recognition that these statements provide one common set of declarations is now built into the Fortran-90 (and later) language, in a way not possible at all for Fortran-77 (and that must be managed manually by the programmer with #ifdefs for the corresponding C #include construct).

Note that to retro-fit MODULE M3UTILIO into existing codes, one must not only remove all of the INCLUDE statements associated with the standard I/O API PARMS3.EXT, FDESC3.EXT, and/or IODECL3.EXT, one must also remove any (now extra, duplicate) declarations and EXTERNAL statements for I/O API functions that now have explicit INTERFACEs in MODULE M3UTILIO (the list being basically the full set of public I/O API functions). (If you get a "duplicate definition" compile-error, you probably missed one ;-( )


Contents of MODULE M3UTILIO

MODULE M3UTILIO itself includes, and therefore USE M3UTILIO replaces the INCLUDE statements for the following Models-3 I/O API INCLUDE files:
PARMS3.EXT
FDESC3.EXT
IODECL3.EXT
It further provides Fortran-90 style INTERFACE blocks for, basically, all of the public routines in the I/O API whose usage does not require F77 / "void pointer" arguments—for example, note that the BUFFER argument for WRITE3() does not have a single specified type; it may be INTEGER, REAL, DOUBLE PRECISION, or INTEGER*8 (M3INT, M3REAL, M3DBLE,, or M3INT8, respectively) and may have an arbitrary number of dimensions, instead of being restricted (as an INTERFACE would require) to one single possibility like a 3-D REAL BUFFER(:,:,:), or requiring over three thousand lines of "wrapper" code to support the implied polymorphism. (IODECL3.EXT is invoked from this MODULE to provide the EXTERNAL declarations for these F77-style routines, but not full interface blocks.)

It provides Fortran-90 "generic" (polymorphic) INTERFACEs for a number of routines:

SUBROUTINE BILIN()
Use 4-band interpolation matrix from SUBROUTINE UNGRIDB() (below) to do bilinear interpolation from 2-D or 3-D gridded data to vector, layered-vector, 2D grid or 3D grid locations.

SUBROUTINE BMATVEC()
Use 4-band interpolation matrix from SUBROUTINE UNGRIDB() to do bilinear interpolation-and-transpose from 2-D or 3-D gridded data to vector, layered-vector, 2D grid or 3D grid locations.

SUBROUTINE ENVLIST()
Get a list of INTEGERs, REALs, or CHARACTER strings from the environment

SUBROUTINE ENVGET()
Get a single value of type INTEGERs, LOGICALs, REALs, REAL*8s, or CHARACTER strings from the environment, with default-value and optional LOVAL, HIVAL ranges for the numeric-type versions.

INTEGER FUNCTION FINDKEY()
Find a key-tuple of CHARACTER strings, INTEGERs, INTEGER*8s, or REALs in a key-tuple table.

<type> FUNCTION GETVAL()
Prompt for a numeric (INTEGER, REAL, DOUBLE, or LOGICAL) value, with optional LO, HI bounds or menu of CHOICES, and DEFAULT response.

INTEGER FUNCTION LOCATE()
Find the insertion-point fdor a key-tuple of CHARACTER strings, INTEGERs, INTEGER*8s, or REALs in a key-tuple table (i.e., a table currently under construction).

SUBROUTINE PMATVEC()
Aply an incidence matrix from SUBROUTINE UNGRIDI() (below) to do mapping from 1-D or 2-D input data arrays to 1-D or 2-D output arrays.

SUBROUTINE SORTI()
Perform an indirect quicksort relative to a table of keytuples of CHARACTER strings, INTEGERs, INTEGER*8s, or REALs (i.e., sort an index-table INDX(1:N) so that the values <table-variable>(INDX(1:N)) are in sorted order).

SUBROUTINE UNGRIDB()
Construct 4-band interpolation matrix from REAL or REAL*8 1-D (vector) or 2-D (gridded) locations to be used by SUBROUTINE BILIN() or SUBROUTINE BMATVEC() (above).

SUBROUTINE UNGRIDI()
Construct aan incidence matrix from REAL or REAL*8 1-D (vector) or 2-D (gridded) locations, for use by SUBROUTINE PMATVEC().

It also provides four cleanly-coded public parsing-utility routines SUBROUTINE FIXFIELD(), FUNCTION KEYVAL(), and SUBROUTINE KEYSTR() that replace various less-well-conceived SMOKE 1.x library-routines; SUBROUTINE FIXNULLS() that replaces trailing ASCII-nulls with blanks (to deal with problems caused by the lack of sophistication of netCDF's Fortran bindings), especially for MPAS-format netCDEF; as well as SUBROUTINE LASTTIME() that robustly computes the last date&time in a time step sequence (even for millenia-long runs, without INTEGER overflow).


To: Models-3/EDSS I/O API: The Help Pages

Send comments to

Carlie J. Coats, Jr.
carlie@jyarborough.com