I had a number of issues with the provided lufrac program. I’ve had a look, and drafted what should in the long run be a better version, together with I/O API compatible Makefile. Note that these are drafts; I don’t have input files to use to test them. Also, this forum-software will probably mess up the tabs in the Makefile ;-(
For whatever reason, this reply-panel is not giving me an “attach” option, so here are these file,
in-line:
---------------------- lufrac.f90 ------------------------------------------------------------------------
PROGRAM lugrid
USE M3UTILIO
!!***************************************************************
!! Version "$Id: lugrid.f90 242 2023-04-10 14:59:56Z coats $"
!! add lufrac info from LUFRAC_CRO file with INGRID data to combined OUTGRID.
!! this PROGRAM assumes:
!! REVISION HISTORY:
!! 1. only one variable on input LUFRAC file called LUFRAC with units=percent and var_desc="fractional land use"
!! 2. each timestep in LUFRAC is the same data as each other timestep's data, so only one timestep is read for inputs.
!! 3. only one level input for the ingrid file
!! Revision 4/2023 by CJC: Many I/O API / Standards compliance items.
!!***************************************************************
USE M3UTILIO
IMPLICIT NONE
CHARACTER*16, PARAMETER :: PNAME = 'LUGRID'
!! atmos intel17.0.3 netcdf4.4.1 ioapi3.2:
!!17 ifort -fPIC -check -traceback -extend_source -zero -O3 -mp1 -o lugrid.exe.atm lugrid.f -L/home/local-rhel7/apps/netcdf-4.4.1/intel-17.0/lib -lnetcdf -lnetcdff -L/home/local-rhel7/apps/ioapi-3.2/intel-17.0/lib -lioapi -module /home/local-rhel7/apps/ioapi-3.2/intel-17.0/Linux2_x86_64ifort
real, ALLOCATABLE :: lufrac(:, :) ! x, y lufrac of LUFRAC_CRO 1st timestep, layer-n going to lufrac_n in GRIDCRO2D.
character*16 :: luvar(MXVARS3), ingridvar(MXVARS3), outgridvar(MXVARS3)
character*16 :: luuni(MXVARS3), ingriduni(MXVARS3), outgriduni(MXVARS3)
character*80 :: ludes(MXVARS3), ingriddes(MXVARS3), outgriddes(MXVARS3)
integer k, n, nfrac, nvars3, LOGUNIT, ISTAT
character*16 vname
CHARACTER*256 MESG
LOGICAL :: EFLAG = .FALSE.
!!........ LUFRAC_CRO file parameters (must match INGRID parameters)
integer FTYPE1
integer NTHIK1
integer NCOLS1
integer NROWS1
integer NLAYS1
integer GDTYP1
real*8 P_ALP1
real*8 P_BET1
real*8 P_GAM1
real*8 XCENT1
real*8 YCENT1
real*8 XORIG1
real*8 YORIG1
real*8 XCELL1
real*8 YCELL1
integer NVARS2
LOGUNIT = INIT3( )
!!........ open "LUFRAC" input file and get its dimensions and variable attributes
IF ( .not. OPEN3( 'LUFRAC', FSREAD3, PNAME ) ) THEN
CALL M3EXIT( PNAME, 0,0, 'OPEN3( LUFRAC,... ) failure', 2 )
ELSE IF ( .not. DESC3( 'LUFRAC' ) ) THEN
CALL M3EXIT( PNAME, 0,0, 'DESC3( LUFRAC,... ) failure', 2 )
ELSE IF ( NVARS3D .NE. 1 ) THEN
CALL M3EXIT( PNAME, 0,0, 'LUFRAC input must have just one variable', 2 )
ELSE IF ( TSTEP3D .NE. 0 ) THEN
CALL M3EXIT( PNAME, 0,0, 'LUFRAC input must be time independent', 2 )
ELSE IF ( vtype3d(1) .NE. M3REAL ) THEN
CALL M3EXIT( PNAME, 0,0, 'LUFRAC input must be of type REAL', 2 )
ELSE !! save lufrac input file description
FTYPE1 = FTYPE3D
NTHIK1 = NTHIK3D
NCOLS1 = NCOLS3D
NROWS1 = NROWS3D
NLAYS1 = NLAYS3D
GDTYP1 = GDTYP3D
P_ALP1 = P_ALP3D
P_BET1 = P_BET3D
P_GAM1 = P_GAM3D
XCENT1 = XCENT3D
YCENT1 = YCENT3D
XORIG1 = XORIG3D
YORIG1 = YORIG3D
XCELL1 = XCELL3D
YCELL1 = YCELL3D
NFRAC = NLAYS3D
luvar(1) = vname3d(1)
luuni(1) = units3d(1)
ludes(1) = vdesc3d(1)
END IF
!!........ open ingrid values input file and get its dimensions and variable attributes
IF ( .not. OPEN3( 'INGRID', FSREAD3, PNAME ) ) THEN
CALL M3EXIT( PNAME, 0,0, 'OPEN3( INGRID,... ) failure', 2 )
ELSE IF ( .not. DESC3( 'INGRID' ) ) THEN
CALL M3EXIT( PNAME, 0,0, 'DESC3( INGRID,... ) failure', 2 )
ELSE IF ( .NOT.FILCHK3( 'INGRID', FTYPE1, NCOLS1, NROWS1, NLAYS1, NTHIK1 ) ) THEN
CALL M3EXIT( PNAME, 0,0, 'Dimension mismatch: "LUFRAC" vs "INGRID"', 2 )
ELSE IF ( .NOT.GRDCHK3( 'INGRID', &
P_ALP1, P_BET1, P_GAM1, XCENT1, YCENT1, &
XORIG1, YORIG1, XCELL1, YCELL1, &
NLAYS3D, VGTYP3D, VGTOP3D, VGLVS3D ) ) THEN
CALL M3EXIT( PNAME, 0,0, 'Grid parameter mismatch: "LUFRAC" vs "INGRID"', 2 )
ELSE IF ( TSTEP3D .NE. 0 ) THEN
CALL M3EXIT( PNAME, 0,0, 'INGRID input must be time independent', 2 )
ELSE !! save lufrac input file description
NVARS2 = NVARS3D
ingridvar(1:nvars2) = vname3d(1:nvars2)
ingriduni(1:nvars2) = units3d(1:nvars2)
ingriddes(1:nvars2) = vdesc3d(1:nvars2)
DO n = 1,nvars2
IF ( vtype3d(n).NE.M3REAL ) THEN
MESG = 'INGRID: variable "'//TRIM( vname3d(n) )//'" must be of type REAL'
CALL M3EXIT( PNAME, 0,0, MESG, 2 )
END IF
END DO
END IF
!!........ create output arrays
ALLOCATE ( lufrac(ncols1,nrows1), STAT = ISTAT )
IF ( ISTAT .NE. 0 ) THEN
WRITE( MESG, '( A, I10)' ) 'Buffer allocation failed: STAT=', ISTAT
CALL M3EXIT( PNAME, 0, 0, MESG, 2 )
END IF
nvars3 = nvars2 + nfrac ! ingrid + lufrac
outgridvar(1:nvars2) = ingridvar(1:nvars2)
outgriduni(1:nvars2) = ingriduni(1:nvars2)
outgriddes(1:nvars2) = ingriddes(1:nvars2)
outgriduni(nvars2+1:nvars3) = luuni(1) ! assumes just one lufrac file var input
outgriddes(nvars2+1:nvars3) = ludes(1)
DO n = 1, nfrac
k = nvars2 + n
write(outgridvar(k), '(A,i2)') 'LUFRAC_', n ! should range from 0-99
END DO
nvars3d = nvars3
vname3d(1:nvars3) = outgridvar(1:nvars3)
units3d(1:nvars3) = outgriduni(1:nvars3)
vdesc3d(1:nvars3) = outgriddes(1:nvars3)
vtype3d(1:nvars3) = M3REAL
IF ( .not. OPEN3( 'OUTGRID', FSUNKN3, PNAME ) ) THEN
CALL M3EXIT( PNAME, 0,0, 'OPEN3( OUTGRID,... ) failure', 2 )
END IF
DO k = 1, nvars2
vname = ingridvar(k)
IF ( .not. read3('INGRID' , ingridvar(k), 1,0,0, lufrac) ) THEN
EFLAG = .TRUE.
ELSE IF ( .not. write3('OUTGRID', ingridvar(k), 0,0, lufrac) ) THEN
EFLAG = .TRUE.
END IF
END DO
DO n = 1, nfrac
k = nvars2 + n
IF ( .not. read3('LUFRAC', luvar(1), n,0,0, lufrac) ) THEN
EFLAG = .TRUE.
ELSE IF ( .not. write3('OUTGRID', outgridvar(k), 0,0, lufrac) ) THEN
EFLAG = .TRUE.
END IF
END DO
IF ( EFLAG ) THEN
MESG = 'Failure in program'
ISTAT = 2
ELSE
MESG = 'Success in program'
ISTAT = 0
END IF
CALL M3EXIT( PNAME, 0, 0, MESG, ISTAT )
END PROGRAM lugrid
---------------------- Makefile ------------------------------------------------------------------------
#
#.........................................................................
# Version "$Id: Makefile 236 2023-04-10 19:40:25Z coats $"
#.........................................................................
# Environment Variables:
# BIN machine/OS/compiler/mode type. Shows up as suffix
# for "Makeinclude.${BIN}" to determine compilation
# flags, and in ${OBJDIR} and $(INSTALL) to determine
# binary directories
# INSTALL installation-directory root, used for "make install"
#.........................................................................
# Directories:
# $(SRCDIR) is the source directory for this program
# ${IOAPI} is the root directory for the I/O API library source
# ${OBJDIR} is the current machine/compiler/flag-specific
# build-directory
#.........................................................................
#
# --------------- Definitions: -------------------------
.SUFFIXES: .m4 .c .F .f .f90 .F90
SRCDIR = ${HOME}/tmp/lugrid
IOAPI = ${HOME}/ioapi-3.2
BLDDIR = ${SRCDIR}/${BIN}
IOSRC = ${IOAPI}/ioapi
IOLIB = ${IOAPI}/${BIN}
# Architecture dependent stuff
# Assumes FC is an f90
include ${IOSRC}/Makeinclude.${BIN}
FFLAGS = ${MODI}$(IOLIB) $(ARCHFLAGS) $(PARFLAGS) $(FOPTFLAGS) $(ARCHFLAGS)
LDFLAGS = -I$(IODIR) $(DEFINEFLAGS) $(ARCHFLAGS)
# Incompatibility between netCDF versions before / after v4.1.1:
# For netCDF v4 and later, you may also need the extra libraries
# given by netCDF commands
#
# nc-config --libs
# nf-config --libs
#
# Cygwin libraries need "-lnetcdff.dll -lnetcdf.dll" below
#
LIBS = -L${IOLIB} -lioapi -lnetcdff -lnetcdf $(OMPLIBS) $(ARCHLIB) $(ARCHLIBS)
#LIBS = -L${IOLIB} -lioapi -lnetcdf $(OMPLIBS) $(ARCHLIB) $(ARCHLIBS)
#LIBS = -L${IOLIB} -lioapi `nf-config --libs` `nc-config --libs` $(OMPLIBS) $(ARCHLIB) $(ARCHLIBS)
VPATH = ${OBJDIR}:${IOLIB}
f90SRC = lugrid.f90
OBJ = $(f90SRC:.f90=.o)
EXE = lugrid
all: $(EXE)
clean:
cd ${OBJDIR}; rm $(EXE) $(OBJ)
install:
echo "Installing M3TOOLS in ${INSTDIR}"
cd ${OBJDIR}; cp $(EXE) $(INSTDIR)
rmexe:
cd ${OBJDIR}; rm ${EXE}
relink:
make BIN=${BIN} -i rmexe ; make BIN=${BIN} all
bins:
make BIN=Linux2_x86_64
make BIN=Linux2_x86_64sun
make BIN=Linux2_x86_64ifort
make BIN=Linux2_x86_64dbg
make BIN=Linux2_x86_64sundbg
make BIN=Linux2_x86_64ifortdbg
binclean:
make -i BIN=Linux2_x86_64 clean
make -i BIN=Linux2_x86_64sun clean
make -i BIN=Linux2_x86_64ifort clean
make -i BIN=Linux2_x86_64dbg clean
make -i BIN=Linux2_x86_64sundbg clean
make -i BIN=Linux2_x86_64ifortdbg clean
binrelink:
make BIN=Linux2_x86_64 relink
make BIN=Linux2_x86_64sun relink
make BIN=Linux2_x86_64ifort relink
make BIN=Linux2_x86_64dbg relink
make BIN=Linux2_x86_64sundbg relink
make BIN=Linux2_x86_64ifortdbg relink
# ----------------------- RULES: -------------------------
%.o : %.mod # Disable "gmake"s obnoxious implicit Modula-2 rule !!
.f90.o:
if [ ! -d ${BLDDIR} ]; then mkdir -p ${BLDDIR}; fi
cd ${BLDDIR}; $(FC) $(FFLAGS) -c $(SRCDIR)/$<
# --------------------------- Dependencies: --------------------
lugrid.o : m3utilio.mod
# --------------------------- $(EXE) Program builds: -----------------
lugrid: lugrid.o
cd ${BLDDIR}; $(FC) ${LFLAGS} $^ ${LIBS} -o $@
---------------------- README ------------------------------------------------------------------------
ON A NEW VERSION OF PROGRAM "LUGRID"
-- Carlie J. Coats, Jr., Ph.D.
There were a number of things wrong with the old program-version
“lugrid.f”:
-
I/O API based programs should use M3EXIT for program termination.
They should not use “STOP”.
-
Grid consistency checks depend upon exact match of all the (REAL*8)
grid parameters. This has been shown repeatedly to be incorrect.
One needs instead to use checks which allow for reasonable round-off
error; ideally, the checks should use standard library routines
FILCHK3() and GRDCHK3().
-
The author does not understand the OPEN3 I/O APU call. In EVERY
instance, the third argument is incorrect.
-
Error-checking is inadequate, particularly as regards ALLOCATE.
-
The author does not understand the concept of a time independent
file (see Dates and Time Conventions), and
introduces much unneeded complexity as a result.
-
There are a number of errors regarding arrays and array-sections,
and how they should appear in argument-lists. Fortunately, many
compilers “do the right thing” anyway (this is NOT true of recent
"gfortran"s, however!)
-
The compile instructions are messy, at best, and it is difficult
to ensure that they are compatible with the libraries used.
-
There is a lot of unnecessary complexity and redundancy.
It might be good for the author to read both the relevant conding
standards document (at M3IO Software Development Standards),
and possibly “Optimizing Environmental Models for Microprocessor Based
Systems”, an updated version for a 2002 seminar at EPA ORD, found at
Environmental Model Optimization.
IN THIS TAR-BALL:
README,txt -- this file
lugrid.f90 -- new version of the program, with the above corrected,
and in (current) free-format (".f90") Fortran source form. Note
that in spite of muc additional error-checking, it is only about
3/4 the size of its predecessor...
Makefile -- to build the program, compatibly with a standard
I/O API installation (in multiple versions, compatible with
I/O API library versions).
TO BUILD THE PROGRAM:
Save these files to a new directory *lugrid* (I did it under my *$HOME/tmp*...)
Edit the "Makefile" so that make-variables
`IOAPI` is the "root" of the current I/O API installation
`SRCDIR` is the source directory of the program
Optionally, `BLDDIR` is the build-directory
"cd" to the program's source-directory
"make" will build the program in `BLDDIR (=$SRCDIR/$BIN` unless
you changed it).