C$Procedure ZZGETELM ( Get the components from two-line elements)

      SUBROUTINE ZZGETELM ( FRSTYR, LINES, EPOCH, ELEMS, OK, ERROR )

C$ Abstract
C
C    Given a the "lines" of a two-line element set, parse the
C    lines and return the elements in units suitable for use
C    in SPICE software.
C
C$ Disclaimer
C
C     THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE
C     CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S.
C     GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE
C     ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE
C     PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS"
C     TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY
C     WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A
C     PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC
C     SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE
C     SOFTWARE AND RELATED MATERIALS, HOWEVER USED.
C
C     IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA
C     BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT
C     LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND,
C     INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS,
C     REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE
C     REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY.
C
C     RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF
C     THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY
C     CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE
C     ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE.
C
C$ Required_Reading
C
C     None.
C
C$ Keywords
C
C     PARSING
C
C$ Declarations

      IMPLICIT NONE

      INTEGER               FRSTYR
      CHARACTER*(*)         LINES ( 2 )
      DOUBLE PRECISION      EPOCH
      DOUBLE PRECISION      ELEMS ( * )
      LOGICAL               OK
      CHARACTER*(*)         ERROR

C$ Brief_I/O
C
C     VARIABLE  I/O  DESCRIPTION
C     --------  ---  --------------------------------------------------
C     FRSTYR     I   year of earliest representable two-line elements
C     LINES      I   a pair of "lines" containing two-line elements
C     EPOCH      O   The epoch of the elements in seconds past J2000
C     ELEMS      O   The elements converted to SPICE units.
C     OK         O   Boolean indicating error state.
C     ERROR      O   String describing error.
C
C$ Detailed_Input
C
C     FRSTYR    is the first year possible for two line elements.
C               Since two line elements allow only two digits for
C               the year, some conventions must be followed concerning
C               which century the two digits refer to .  FRSTYR
C               is the year of the earliest representable elements.
C               The two-digit year is mapped to the year in
C               the interval from FRSTYR to FRSTYR + 99 that
C               has the same last two digits as the two digit
C               year in the element set.  For example if FRSTYR
C               is set to 1960  then the two digit years are mapped
C               as shown in the table below:
C
C               Two-line         Maps to
C               element year
C                  00            2000
C                  01            2001
C                  02            2002
C                   .              .
C                   .              .
C                   .              .
C                  58            2058
C                  59            2059
C                 --------------------
C                  60            1960
C                  61            1961
C                  62            1962
C                   .              .
C                   .              .
C                   .              .
C                  99            1999
C
C                Note that if Space Command should decide to represent
C                years in 21st century as 100 + the last two digits
C                of the year (for example: 2015 is represented as 115)
C                instead of simply dropping the first two digits of
C                the year, this routine will correctly map the year
C                as long as you set FRSTYR to some value between 1900
C                and 1999.
C
C     LINES      is a pair of lines of text that comprise a Space
C                command ``two-line element'' set.  These text lines
C                should be the same as they are presented in the
C                two-line element files available from Space Command
C                (formerly NORAD). Below is an example of a two-line
C                set for TOPEX.
C
C  TOPEX
C  1 22076U 92052A   97173.53461370 -.00000038  00000-0  10000-3 0   594
C  2 22076  66.0378 163.4372 0008359 278.7732  81.2337 12.80930736227550
C
C
C$ Detailed_Output
C
C     EPOCH      is the epoch of the two line elements supplied via
C                the input array LINES.  Epoch is returned in TDB
C                seconds past J2000.
C
C     ELEMS      is an array containing the elements from the two line
C                set supplied via the array LINES.  The elements are
C                in units suitable for use by the SPICE routine
C                EV2LIN.
C
C                Also note that the elements XNDD6O and BSTAR
C                incorporate the exponential factor present in the
C                input two line elements in LINES.  (See particulars
C                below.
C
C                    ELEMS (  1 ) = XNDT2O in radians/minute**2
C                    ELEMS (  2 ) = XNDD6O in radians/minute**3
C                    ELEMS (  3 ) = BSTAR
C                    ELEMS (  4 ) = XINCL  in radians
C                    ELEMS (  5 ) = XNODEO in radians
C                    ELEMS (  6 ) = EO
C                    ELEMS (  7 ) = OMEGAO in radians
C                    ELEMS (  8 ) = XMO    in radians
C                    ELEMS (  9 ) = XNO    in radians/minute
C                    ELEMS ( 10 ) = EPOCH of the elements in seconds
C                                   past ephemeris epoch J2000.
C
C     OK         a boolean flag indicating whether an error occured
C                while processing the TLE. Processing errors include
C                incorrect format for TLEs, angular values beyond
C                allowed range.
C
C     ERROR      a string containing a description of any TLE
C                processing error.
C
C$ Parameters
C
C     None.
C
C$ Files
C
C     You must have loaded a SPICE leapseconds kernel into the
C     kernel pool prior to caling this routine.
C
C$ Exceptions
C
C     This routine does not signal errors, rather it returns an
C     error flag and description to the calling program. Errors
C     reported:
C
C     1) TLE line has incorrect format.
C
C     2) A TLE '2' line has a different vehicle tag than the
C         corresponding '1' line.
C
C     3) TLE data length more than 69 characters, or less than 68
C        characters.
C
C     4) An NPARS* routine cannot parse a string to a numeric value.
C
C     5) The value of an angular measure, NODE0, OMEGA, MO, or INCL
C        fails to lie within the expected numerical bounds.
C
C$ Particulars
C
C     This routine parses a Space Command Two-line element set and
C     returns the orbital elements properly scaled and in units
C     suitable for use by other SPICE software.  Input elements
C     have the form:
C
C  1 22076U 92052A   97173.53461370 -.00000038  00000-0  10000-3 0   594
C  2 22076  66.0378 163.4372 0008359 278.7732  81.2337 12.80930736227550
C  ^
C  123456789012345678901234567890123456789012345678901234567890123456789
C           1         2         3         4         5         6
C
C     The ``raw'' elements in the first  and second lines are marked
C     below.  Note that in several instances exponents and decimal
C     points are implied.  Also note that
C     input units are degrees, degrees/day**n and revolutions/day.
C
C
C                      DAY OF YEAR             NDD60    BSTAR
C                      vvvvvvvvvvvv            vvvvvv   vvvvvv
C  ---------------------------------------------------------------------
C  1 22076U 92052A   97173.53461370 -.00000038  00000-0  10000-3 0   594
C  ---------------------------------------------------------------------
C                    ^^             ^^^^^^^^^^       ^^       ^^
C                    YEAR             NDT20          IEXP     IBEXP
C
C
C
C     The ``raw'' elements in the second line are marked below
C                   NODE0            OMEGA             N0
C                   vvvvvvvv         vvvvvvvv          vvvvvvvvvvv
C  ---------------------------------------------------------------------
C  2 22076  66.0378 163.4372 0008359 278.7732  81.2337 12.80930736227550
C  ---------------------------------------------------------------------
C          ^^^^^^^^          ^^^^^^^          ^^^^^^^^
C          Inclination       Eccentricity     M0
C
C     This routine extracts these values ``inserts'' the implied
C     decimal points and exponents and then converts the inputs
C     to units of radians, radians/minute, radians/minute**2, and
C     radians/minute**3
C
C$ Examples
C
C     Suppose you have a set of two-line elements and an array
C     containing the related geophysical constants necessary
C     to evaluate a state.  The example below shows how you
C     can use this routine together with the routine EV2LIN to
C     propagate a state to an epoch of interest.
C
C
C        The parameters below will make it easier to make assignments
C        to the array GEOPHS required by EV2LIN.
C
C        J2  --- location of J2
C        J3  --- location of J3
C        J4  --- location if J4
C        KE  --- location of KE = sqrt(GM) in eart-radii**1.5/MIN
C        QO  --- location of upper bound of atmospheric model in KM
C        SO  --- location of lower bound of atmospheric model in KM
C        ER  --- location of earth equatorial radius in KM.
C        AE  --- location of distance units/earth radius
C
C        PARAMETER           ( J2 = 1 )
C        PARAMETER           ( J3 = 2 )
C        PARAMETER           ( J4 = 3 )
C        PARAMETER           ( KE = 4 )
C        PARAMETER           ( QO = 5 )
C        PARAMETER           ( SO = 6 )
C        PARAMETER           ( ER = 7 )
C        PARAMETER           ( AE = 8 )
C
C
C        We set the lower bound for the years to be the beginning
C        of the space age.
C
C        FRSTYR = 1957
C
C        Read in the next two lines from the text file that contains
C        the two-line elements.  We assume that file has been opened
C        properly and that we have set the ``file pointer'' to the
C        correct location for reading the next set of elements.
C
C        READ  (UNIT,FMT='(A)' ) LINE(1)
C        READ  (UNIT,FMT='(A)' ) LINE(2)
C
C        CALL ZZGETELM ( FRSTYR, LINE, EPOCH, ELEMS, OK, ERROR )
C
C        Set up the geophysical quantities.  At last check these
C        were the values used by Space Command.
C
C        GEOPHS( J2 ) =    1.082616D-3
C        GEOPHS( J3 ) =   -2.53881D-6
C        GEOPHS( J4 ) =   -1.65597D-6
C        GEOPHS( KE ) =    7.43669161D-2
C        GEOPHS( QO ) =  120.0D0
C        GEOPHS( SO ) =   78.0D0
C        GEOPHS( ER ) = 6378.135D0
C        GEOPHS( AE ) =    1.0D0
C
C        Now propagate the state using EV2LIN to the epoch of
C        interest.
C
C        CALL EV2LIN ( ET, GEOPHS, ELEMS, STATE )
C
C
C$ Restrictions
C
C    The format of the two-line elements suffer from a "millenium"
C    problem---only two digits are used for the year of the elements.
C    It is not clear how Space Command will deal with this problem
C    as the year 2000 comes and goes.  We hope that by adjusting
C    the input FRSTYR you should be able to use this
C    routine well into the 21st century.  However, since we can't
C    predict how others will resolve the millenium problem we
C    can't be sure that our approach will be addequate to deal with
C    the problem.
C
C    The approach taken to mapping the two-digit year to the
C    full year is given by the code below. Here, YR is the
C    integer obtained by parsing the two-digit year from the first
C    line of the elements.
C
C        BEGYR = (FRSTYR/100)*100
C        YEAR  = BEGYR + YR
C
C        IF ( YEAR .LT. FRSTYR ) THEN
C           YEAR = YEAR + 100
C        END IF
C
C     This mapping will be changed if future two-line element
C     representations make this method of computing the full year
C     inaccurate.
C
C$ Author_and_Institution
C
C     W.L. Taber      (JPL)
C     E.D. Wright     (JPL)
C
C$ Literature_References
C
C     None.
C
C$ Version
C
C
C-    SPICELIB Version 1.0.0, 26-APR-2004 (EDW)
C
C        Modified routine GETELM to confirm
C        acceptable range for angular measures and exponents.
C        The routine does not signal errors,it returns an error
C        flag and error string to the calling program.
C
C        Routine named ZZGETELM from GETELM.
C
C-&

C$ Index_Entries
C
C     Parse two-line elements
C
C-&

C
C     Spicelib functions
C
      DOUBLE PRECISION      RPD
      DOUBLE PRECISION      TWOPI
      LOGICAL               RETURN
      INTEGER               LASTNB

C
C     An enumeration of the various components of the
C     elements array---ELEMS
C
C        KNDT20
C        KNDD60
C        KBSTAR
C        KINCL
C        KNODE0
C        KECC
C        KOMEGA
C        KMO
C        KNO
C

      INTEGER               START
      PARAMETER           ( START = 0 )

      INTEGER               KNDT20
      PARAMETER           ( KNDT20 = START  + 1 )

      INTEGER               KNDD60
      PARAMETER           ( KNDD60 = KNDT20 + 1 )

      INTEGER               KBSTAR
      PARAMETER           ( KBSTAR = KNDD60 + 1 )

      INTEGER               KINCL
      PARAMETER           ( KINCL  = KBSTAR + 1 )

      INTEGER               KNODE0
      PARAMETER           ( KNODE0 = KINCL  + 1 )

      INTEGER               KECC
      PARAMETER           ( KECC   = KNODE0 + 1 )

      INTEGER               KOMEGA
      PARAMETER           ( KOMEGA = KECC   + 1 )

      INTEGER               KMO
      PARAMETER           ( KMO    = KOMEGA + 1 )

      INTEGER               KNO
      PARAMETER           ( KNO    = KMO    + 1 )

      INTEGER               KEPOCH
      PARAMETER           ( KEPOCH = KNO    + 1 )

      INTEGER               NELEMS
      PARAMETER           ( NELEMS = KEPOCH )

C
C     Character string lengths
C
      INTEGER               WDSIZE
      PARAMETER           ( WDSIZE = 32 )

      INTEGER               LNSIZE
      PARAMETER           ( LNSIZE = 160 )

C
C     Maximum exponent (base 10)
C
      INTEGER               MAXP
      PARAMETER           ( MAXP =     37     )

      INTEGER               MINP
      PARAMETER           ( MINP =  -MAXP     )

C
C     Double precision constants.
C
      DOUBLE PRECISION      ONE
      PARAMETER           ( ONE  =      1.0D0 )

      DOUBLE PRECISION      TEN
      PARAMETER           ( TEN  =     10.0D0 )

C
C     Minutes/day
C
      DOUBLE PRECISION      MNPDAY
      PARAMETER           ( MNPDAY = 1440.0D0 )

C
C     Local variables
C
      CHARACTER*(LNSIZE)    ERRPRS ( 13 )
      CHARACTER*(LNSIZE)    TERM  ( 13 )

      CHARACTER*(WDSIZE)    CYEAR
      CHARACTER*(WDSIZE)    CDAY
      CHARACTER*(WDSIZE)    CNDT20
      CHARACTER*(WDSIZE)    CNDD60
      CHARACTER*(WDSIZE)    CIEXP
      CHARACTER*(WDSIZE)    CBSTAR
      CHARACTER*(WDSIZE)    CIBEXP
      CHARACTER*(WDSIZE)    CINCL
      CHARACTER*(WDSIZE)    CNODE0
      CHARACTER*(WDSIZE)    CECC
      CHARACTER*(WDSIZE)    COMEGA
      CHARACTER*(WDSIZE)    CMO
      CHARACTER*(WDSIZE)    CNO

      DOUBLE PRECISION      BSTAR
      DOUBLE PRECISION      DAY
      DOUBLE PRECISION      ECC
      DOUBLE PRECISION      INCL
      DOUBLE PRECISION      MO
      DOUBLE PRECISION      NDD60
      DOUBLE PRECISION      NDT20
      DOUBLE PRECISION      NO
      DOUBLE PRECISION      NODE0
      DOUBLE PRECISION      OMEGA
      DOUBLE PRECISION      D2R
      DOUBLE PRECISION      PI2
      DOUBLE PRECISION      POWER  ( MINP:MAXP )
      DOUBLE PRECISION      TVEC   ( 8 )

      INTEGER               BEXP
      INTEGER               BEGYR
      INTEGER               I
      INTEGER               NEXP
      INTEGER               PTR
      INTEGER               YEAR
      INTEGER               YR
      INTEGER               K

      LOGICAL               FIRST

      SAVE

      DATA                  FIRST / .TRUE. /

C
C     Standard SPICE error handling.
C
      IF ( RETURN() ) THEN
         RETURN
      END IF

      CALL CHKIN ( 'ZZGETELM' )

C
C     Initialize the error indicators and the elements to zero.
C
      OK               = .TRUE.
      ERROR            = ' '
      ELEMS ( KNDT20 ) = 0.D0
      ELEMS ( KNDD60 ) = 0.D0
      ELEMS ( KBSTAR ) = 0.D0
      ELEMS ( KINCL  ) = 0.D0
      ELEMS ( KNODE0 ) = 0.D0
      ELEMS ( KECC   ) = 0.D0
      ELEMS ( KOMEGA ) = 0.D0
      ELEMS ( KMO    ) = 0.D0
      ELEMS ( KNO    ) = 0.D0
      ELEMS ( KEPOCH ) = 0.D0
      EPOCH            = 0.D0

C
C     First entry initialization.
C
      IF ( FIRST ) THEN

C
C        Define two constants. This initialization proves the most
C        useful when processing thousands of TLE sets.
C
         D2R = RPD()
         PI2 = TWOPI()

         FIRST    = .FALSE.

         POWER(0) =  ONE

         DO I = 1, MAXP
            POWER(I)  = TEN * POWER(I-1)
            POWER(-I) = ONE / POWER(I  )
         END DO

         TERM( 1) = '"YEAR" (characters 19 to 20 of the first line '
     .   //         'of a two-line element set)'

         TERM( 2) = '"DAY" (characters 21 to 32 of the first line o'
     .   //         'f a two-line element set)'

         TERM( 3) = '"NDT20" (characters 34 to 43 of the first line'
     .   //         ' of a two-line element set)'

         TERM( 4) = '"NDD60" (characters 45 to 45 of the first line'
     .   //         ' of a two-line element set)'

         TERM( 5) = '"IEXP" (characters 51 to 52 of the first line '
     .   //         'of a two-line element set)'

         TERM( 6) = '"BSTAR" (characters 54 to 54 of the first line'
     .   //         ' of a two-line element set)'

         TERM( 7) = '"IBEXP" (characters 60 to 61 of the first line'
     .   //         ' of a two-line element set)'

         TERM( 8) = '"INCL" (characters 9 to 16 of the second line o'
     .   //         'f a two-line element set)'

         TERM( 9) = '"NODE0" (characters 18 to 25 of the second line'
     .   //         ' of a two-line element set)'

         TERM(10) = '"ECC" (characters 27 to 33 of the second line o'
     .   //         'f a two-line element set)'

         TERM(11) = '"OMEGA" (characters 35 to 42 of the second line'
     .   //         ' of a two-line element set)'

         TERM(12) = '"MO" (characters 44 to 51 of the second line of'
     .   //         ' a two-line element set)'

         TERM(13) = '"NO" (characters 53 to 63 of the second line of'
     .   //         ' a two-line element set)'

      END IF

C
C     Ensure the vehicle IDs match in each line.
C
      IF ( LINES(1)(2:7) .NE. LINES(2)(2:7) ) THEN

C
C        Vehicle IDs do not match. Flag an error.
C
         ERROR = 'Line 1 of the TLE pair tagged with vehicle ID #1,'
     .      //   '  line 2 of TLE pair tagged with vehicle ID #2'
         CALL REPMC ( ERROR, '#1', LINES(1)(2:7), ERROR )
         CALL REPMC ( ERROR, '#2', LINES(2)(2:7), ERROR )

         OK = .FALSE.

         CALL CHKOUT ( 'ZZGETELM' )
         RETURN
      END IF

C
C    Check line format and length.
C
      DO K = 1, 2

         IF ( LASTNB( LINES(K) ) .NE. 68 .AND.
     .        LASTNB( LINES(K) ) .NE. 69 ) THEN

C
C          The TLE data line was not 68 or 69 characters long (ignoring
C          trailing whitespace). Flag an error.
C
            ERROR = 'Line #1 of the TLE has incorrect data length.'
     .         //   ' Expected length 68 or 69 elements, '
     .         //   'actual length: #2. TLE line value: #3'
            CALL REPMI ( ERROR, '#1', K                 , ERROR )
            CALL REPMI ( ERROR, '#2', LASTNB( LINES(K) ), ERROR )
            CALL REPMC ( ERROR, '#3', LINES(K)          , ERROR )

            OK = .FALSE.

            CALL CHKOUT ( 'ZZGETELM' )
            RETURN
         END IF

      END DO

C
C     This isn't particularly pretty, but it is straight
C     forward.  According to the documentation on the two line
C     element sets, (as well as what's indicated by the program
C     driver that is documented in SPACETRACK REPORT NO.3
C     we can simply pick out the various components of the
C     elements from the input lines 1 and 2.
C
C     For the record we include the DECODE statement in DRIVER
C     for fetching the data out of lines one and two (after a bit
C     of pretty printing).  Note that some of these formats have
C     and implied decimal point.  In particular f6.5 and f7.7  in
C     all other cases the decimal points seem to be given explicitely.
C
C     decode (abuf,702) epoch,     xndt20,                       ...
C                       xndd60,    iexp,        bstar,    ibexp, ...
C                       xincl,     xnodeo,                       ...
C                       eo,        omegao,     xmo,       xno
C     format(      18x, d14.8, 1x, f10.8,
C                   1x, f6.5,      i2,     1x, f6.5,      i2,    /,
C                   8x, f8.4,  1x, f8.4,
C                   1x, f7.7,  1x, f8.4,   1x, f8.4   1x, f11.8 )
C
C     Note that in the two-line element sets, the epoch is read
C     as a single number.  However the documentation that describes
C     this data (as well as the code in THETAG) show that it's a lot
C     easier to capture the year and day of year separately.
C
      CYEAR  = LINES(1)(19:20)
      CDAY   = LINES(1)(21:32)
      CNDT20 = LINES(1)(34:43)
      CNDD60 = LINES(1)(45:45) // '.' // LINES(1)(46:50)
      CIEXP  = LINES(1)(51:52)
      CBSTAR = LINES(1)(54:54) // '.' // LINES(1)(55:59)
      CIBEXP = LINES(1)(60:61)

      CINCL  = LINES(2)( 9:16)
      CNODE0 = LINES(2)(18:25)
      CECC   = '0.'            // LINES(2)(27:33)
      COMEGA = LINES(2)(35:42)
      CMO    = LINES(2)(44:51)
      CNO    = LINES(2)(53:63)

C
C     Parse the numerical values from the data string.
C
      CALL NPARSI ( CYEAR,  YR,     ERRPRS(1),  PTR )
      CALL NPARSD ( CDAY,   DAY,    ERRPRS(2),  PTR )
      CALL NPARSD ( CNDT20, NDT20,  ERRPRS(3),  PTR )
      CALL NPARSD ( CNDD60, NDD60,  ERRPRS(4),  PTR )
      CALL NPARSI ( CIEXP,  NEXP,   ERRPRS(5),  PTR )
      CALL NPARSD ( CBSTAR, BSTAR,  ERRPRS(6),  PTR )
      CALL NPARSI ( CIBEXP, BEXP,   ERRPRS(7),  PTR )
      CALL NPARSD ( CINCL,  INCL,   ERRPRS(8),  PTR )
      CALL NPARSD ( CNODE0, NODE0,  ERRPRS(9),  PTR )
      CALL NPARSD ( CECC,   ECC,    ERRPRS(10), PTR )
      CALL NPARSD ( COMEGA, OMEGA,  ERRPRS(11), PTR )
      CALL NPARSD ( CMO,    MO,     ERRPRS(12), PTR )
      CALL NPARSD ( CNO,    NO,     ERRPRS(13), PTR )

C
C     Check for parse errors.
C
      DO I = 1, 13

         IF ( ERRPRS(I) .NE. ' ' ) THEN

C
C           Something could not parse. Set the error message then
C           return.
C
            ERROR = 'An error occurred while trying to '
     .      //      'parse the term #. The diagnostic was:  # '
            CALL REPMC ( ERROR, '#', TERM(I)  , ERROR )
            CALL REPMC ( ERROR, '#', ERRPRS(I), ERROR )

            OK = .FALSE.

            CALL CHKOUT ( 'ZZGETELM' )
            RETURN
         END IF

      END DO

C
C     Check for reasonable exponets; a single digit. These should
C     probably be LE 0.
C
      IF ( ABS(NEXP) .GT. 9 ) THEN

            ERROR = 'NEXP (exponent) not a single digit. '
     .              //'Actual value #1'
            CALL REPMI ( ERROR, '#1', NEXP, ERROR )

            OK = .FALSE.

            CALL CHKOUT ( 'ZZGETELM' )
            RETURN

         END IF

      IF ( ABS(BEXP) .GT. 9 ) THEN

            ERROR = 'BEXP (exponent) not a single digit. '
     .              //'Actual value #1'
            CALL REPMI ( ERROR, '#1', BEXP, ERROR )

            OK = .FALSE.

            CALL CHKOUT ( 'ZZGETELM' )
            RETURN

      END IF

C
C     Confirm correct bounds on angular values.
C
C     NODE0 - right ascension of the ascending node, [0,360)
C
      IF ( NODE0 .LT. 0.D0 .OR. NODE0 .GE. 360.D0 ) THEN

            ERROR = 'NODE0 (RA acend node) expected bounds [0,360). '
     .              //'Actual value #1'
            CALL REPMD ( ERROR, '#1', NODE0, 4, ERROR )

            OK = .FALSE.

            CALL CHKOUT ( 'ZZGETELM' )
            RETURN

         END IF

C
C     OMEAGA - argument of the periapsis, [0,360)
C
      IF ( OMEGA .LT. 0.D0 .OR. OMEGA .GE. 360.D0 ) THEN

            ERROR = 'OMEGA (arg periap) expected bounds [0,360). '
     .              //'Actual value #1'
            CALL REPMD ( ERROR, '#1', OMEGA, 4, ERROR )

            OK = .FALSE.

            CALL CHKOUT ( 'ZZGETELM' )
            RETURN
         END IF

C
C     MO - mean anomoly, [0,360)
C
      IF ( MO .LT. 0.D0 .OR. MO .GE. 360.D0 ) THEN

            ERROR = 'MO (mean anomoly) expected bounds [0,360). '
     .              //'Actual value #1'
            CALL REPMD ( ERROR, '#1', MO, 4, ERROR )

            OK = .FALSE.

            CALL CHKOUT ( 'ZZGETELM' )
            RETURN
         END IF

C
C     INCL - inclination, [0,180]
C
      IF ( INCL .LT. 0.D0 .OR. INCL .GT. 180.D0 ) THEN

            ERROR = 'INCL (inclination) expected bounds [0,180). '
     .              //'Actual value #1'
            CALL REPMD ( ERROR, '#1', INCL, 4, ERROR )

            OK = .FALSE.

            CALL CHKOUT ( 'ZZGETELM' )
            RETURN
         END IF

C
C     NO - mean motion (0,20) (Earth orbiter).
C
      IF ( NO .GT. 20.D0 .OR. NO .LT. 0.D0 ) THEN

            ERROR = 'NO (mean motion) expected bounds (0,20). '
     .              //'Actual value #1'
            CALL REPMD ( ERROR, '#1', NO, 4, ERROR )

            OK = .FALSE.

            CALL CHKOUT ( 'ZZGETELM' )
            RETURN
         END IF

C
C     Finish up the computation of NDD60 and BSTAR
C
      NDD60 = NDD60 * POWER(NEXP)
      BSTAR = BSTAR * POWER(BEXP)

C
C     Convert everything from degrees to radians ...
C
      NODE0 = NODE0  * D2R
      OMEGA = OMEGA  * D2R
      MO    = MO     * D2R
      INCL  = INCL   * D2R

C
C     ... and from revolutions/day**n to radians/minutes**n
C
      NO    =  NO    * PI2/MNPDAY
      NDT20 =  NDT20 * PI2/MNPDAY/MNPDAY
      NDD60 =  NDD60 * PI2/MNPDAY/MNPDAY/MNPDAY

C
C     Finally, we need to convert the input epoch to
C     seconds past 2000. First let's adjust the year.
C     Add to YR the largest multiple of 100 that is
C     less than or equal to FRSTYR
C
      BEGYR = (FRSTYR/100)*100
      YEAR  = BEGYR + YR

      IF ( YEAR .LT. FRSTYR ) THEN
         YEAR = YEAR + 100
      END IF

C
C     Compute the epoch of the year and date.
C
      TVEC(1) = DBLE(YEAR)
      TVEC(2) = DAY

      CALL TTRANS ( 'YD.D', 'TDB', TVEC )

      EPOCH = TVEC(1)

C
C     That's it.  Load ELEMS with the elements and ship them
C     back to the calling routine.
C
      ELEMS ( KNDT20 ) = NDT20
      ELEMS ( KNDD60 ) = NDD60
      ELEMS ( KBSTAR ) = BSTAR
      ELEMS ( KINCL  ) = INCL
      ELEMS ( KNODE0 ) = NODE0
      ELEMS ( KECC   ) = ECC
      ELEMS ( KOMEGA ) = OMEGA
      ELEMS ( KMO    ) = MO
      ELEMS ( KNO    ) = NO
      ELEMS ( KEPOCH ) = EPOCH

      CALL CHKOUT ( 'ZZGETELM' )
      RETURN
      END


!--------------------------------------------------------
!> Variables which control the overall GENIE configuration.
!!
!> This Fortran90 module contains variables which pertain
!> to the overall GENIE configuration.  For example, the
!> various grid sizes and LOGICAL flags specifying which
!> components are used.
!--------------------------------------------------------

MODULE genie_control

  ! ======================================================================
  ! Grid dimension variables for tracer (1), u (2) and v (3) points
  ! Atmosphere
  INTEGER :: ilon1_atm, ilat1_atm
  INTEGER :: ilon2_atm, ilat2_atm
  INTEGER :: ilon3_atm, ilat3_atm
  INTEGER :: inl1_atm

  ! Ocean
  INTEGER :: ilon1_ocn, ilat1_ocn
  INTEGER :: ilon2_ocn, ilat2_ocn
  INTEGER :: ilon3_ocn, ilat3_ocn
  INTEGER :: inl1_ocn, inl2_ocn
  INTEGER :: intrac_ocn

  ! For c-GOLDSTEIN sea-ice
  INTEGER :: ilon1_sic, ilat1_sic
  INTEGER :: ilon2_sic, ilat2_sic
  INTEGER :: ilon3_sic, ilat3_sic

  ! For ice sheets in EMBM and ENTS
  INTEGER :: ilon1_lic, ilat1_lic

  ! For ENTS
  INTEGER :: ilon1_lnd, ilat1_lnd

  ! For sediments
  INTEGER :: ilon1_sed, ilat1_sed

  ! For weathering
  INTEGER :: ilon1_rok, ilat1_rok

  ! Coordinate definitions.
  INTEGER :: dim_GENIENL, dim_GENIENX, dim_GENIENY
  INTEGER :: dim_GOLDSTEINNLONS, dim_GOLDSTEINNLATS
  INTEGER :: dim_GOLDSTEINNLEVS, dim_GOLDSTEINNTRACS
  INTEGER :: dim_SEDGEMNLONS, dim_SEDGEMNLATS
  INTEGER :: dim_ROKGEMNLONS, dim_ROKGEMNLATS

  ! ======================================================================
  ! Miscellaneous control variables

  ! Used for NetCDF output in various places
  INTEGER, PARAMETER :: BUFSIZ = 1024  !< to hold CHARACTER strings
  INTEGER, PARAMETER :: nfiles=4, nmaxdims=4, nall=100

  ! Biogeochemistry time stepping ratios -- loop modifiers (relative
  ! to ocean loop)
  INTEGER :: conv_kocn_katchem  !< atchem
  INTEGER :: conv_kocn_ksedgem  !< sedgem
  INTEGER :: conv_kocn_kbiogem  !< biogem
  INTEGER :: conv_kocn_krokgem  !< rokgem
  INTEGER :: kgemlite

  ! Total defined tracer numbers
  ! WARNING: parameter information duplicated in gem_cmn.f90
  INTEGER, PARAMETER :: intrac_atm_max=19, intrac_ocn_max=95, intrac_sed_max=79

  ! Others
  INTEGER(KIND=8) :: koverall_total
  INTEGER(KIND=8) :: katm_loop, ksic_loop, kocn_loop, klnd_loop

  ! .TRUE. indicates that component is included in model 'recipe'
  LOGICAL :: flag_ebatmos          !< EMBM
  LOGICAL :: flag_igcmatmos        !< IGCM
  LOGICAL :: flag_fixedocean       !< prescribed ocean
  LOGICAL :: flag_slabocean        !< slab ocean
  LOGICAL :: flag_goldsteinocean   !< GOLDSTEIN ocean

  LOGICAL :: flag_fixedseaice, flag_slabseaice, flag_goldsteinseaice
  LOGICAL :: flag_icesheet, flag_fixedicesheet
  LOGICAL :: flag_fixedatmos, flag_fakeatmos
  LOGICAL :: flag_land, flag_ents, flag_fixedland
  LOGICAL :: flag_fixedchem, flag_atchem
  LOGICAL :: flag_biogem, flag_sedgem, flag_rokgem, flag_gemlite
  LOGICAL :: flag_checkfluxes_sic, flag_checkfluxes_ocn, flag_checkfluxes_surf
  LOGICAL :: flag_checkfluxes_atlantic, flag_ichem, flag_wind
  INTEGER :: debug_init, debug_end, debug_loop

  LOGICAL :: write_flag_atm, write_flag_ocn, write_flag_sic
  CHARACTER(LEN=BUFSIZ) :: outputdir_name, fname_restart_main, fname_fluxrestart
  CHARACTER(LEN=6) :: fname_topo
  INTEGER(KIND=8) :: dt_write

  ! Days per year.
  REAL, PARAMETER :: global_daysperyear = 365.25

END MODULE genie_control


!***********************************************************************
! Defines the computational sequence, valid modules, and dimensions
! mm, PJT modifications made
!***********************************************************************
      MODULE PRMS_MODULE
      IMPLICIT NONE
      INTEGER, PARAMETER :: MAXFILE_LENGTH = 256, MAXCONTROL_LENGTH = 32
      INTEGER, PARAMETER :: MAXDIM = 500
      CHARACTER(LEN=68), PARAMETER :: &
     &  EQULS = '===================================================================='
      CHARACTER(LEN=11), PARAMETER :: MODNAME = 'gsflow_prms'
      CHARACTER(LEN=24), PARAMETER :: PRMS_VERSION = 'Version 4.0.3 06/01/2017'
      CHARACTER(LEN=8), SAVE :: Process
      CHARACTER(LEN=80), SAVE :: PRMS_versn
      INTEGER, SAVE :: Model, Process_flag, Call_cascade, Ncascade, Ncascdgw
      INTEGER, SAVE :: Nhru, Nssr, Ngw, Nsub, Nhrucell, Nlake, Ngwcell, Nlake_hrus
      INTEGER, SAVE :: Ntemp, Nrain, Nsol, Nsegment, Ndepl, Nobs, Nevap, Ndeplval
      INTEGER, SAVE :: NmaxPrecipObs                                                                                ! PJT - 2018Jan03 - Sub-daily precip inputs
      INTEGER, SAVE :: Ndscn, Ninfstor                                                                                ! mm
      INTEGER, SAVE :: Starttime(6), Endtime(6)
      INTEGER, SAVE :: Start_year, Start_month, Start_day, End_year, End_month, End_day
      INTEGER, SAVE :: Transp_flag, Sroff_flag, Surban_flag, Solrad_flag, Et_flag, Gw_flag                                  ! mm
      INTEGER, SAVE :: Climate_temp_flag, Climate_precip_flag, Climate_potet_flag, Climate_transp_flag
      INTEGER, SAVE :: Lake_route_flag, Nratetbl, Strmflow_flag, Stream_order_flag
      INTEGER, SAVE :: Temp_flag, Precip_flag, Climate_hru_flag, Climate_swrad_flag
      INTEGER, SAVE :: Precip_combined_flag, Temp_combined_flag
      INTEGER, SAVE :: Inputerror_flag, Timestep
      INTEGER, SAVE :: Humidity_cbh_flag, Windspeed_cbh_flag
      INTEGER, SAVE :: Grid_flag, Logunt, First_timestep
      INTEGER, SAVE :: Kper_mfo, Kkstp_mfo, PRMS_flag
      INTEGER, SAVE :: PRMS_output_unit, Restart_inunit, Restart_outunit
      INTEGER, SAVE :: Elapsed_time_start(8), Elapsed_time_end(8), Elapsed_time_minutes
      REAL, SAVE :: Execution_time_start, Execution_time_end, Elapsed_time
      INTEGER, SAVE :: Kkiter
!   Declared Parameters
      INTEGER, SAVE :: Mxsziter
      INTEGER, SAVE, ALLOCATABLE :: Gvr_cell_id(:)
      REAL, SAVE, ALLOCATABLE :: Gvr_cell_pct(:)
! Precip_flag (1=precip_1sta; 2=precip_laps; 3=precip_dist2; 5=ide_dist; 6=xyz_dist; 7=climate_hru
! Temp_flag (1=temp_1sta; 2=temp_laps; 3=temp_dist2; 5=ide_dist; 6=xyz_dist; 7=climate_hru
! Control parameters
      INTEGER, SAVE :: Print_debug, MapOutON_OFF, CsvON_OFF, Dprst_flag, Subbasin_flag, Parameter_check_flag
      INTEGER, SAVE :: Init_vars_from_file, Save_vars_to_file, Orad_flag, Cascade_flag, Cascadegw_flag
      INTEGER, SAVE :: NhruOutON_OFF, Gwr_swale_flag, NsubOutON_OFF, BasinOutON_OFF, NsegmentOutON_OFF
      CHARACTER(LEN=MAXFILE_LENGTH), SAVE :: Model_output_file, Var_init_file, Var_save_file
      CHARACTER(LEN=MAXFILE_LENGTH), SAVE :: Csv_output_file, Model_control_file, Param_file
      CHARACTER(LEN=MAXCONTROL_LENGTH), SAVE :: Temp_module, Srunoff_module, Et_module
      CHARACTER(LEN=MAXCONTROL_LENGTH), SAVE :: Strmflow_module, Transp_module, Gw_module                                   ! mm
      CHARACTER(LEN=MAXCONTROL_LENGTH), SAVE :: Model_mode, Precip_module, Solrad_module
      CHARACTER(LEN=8), SAVE :: Soilzone_module
      END MODULE PRMS_MODULE

!***********************************************************************
      INTEGER FUNCTION call_modules(Arg)
      USE PRMS_MODULE
      IMPLICIT NONE
! Arguments
      CHARACTER(LEN=*), INTENT(IN) :: Arg
! Functions
      INTRINSIC :: DATE_AND_TIME, INT
      INTEGER, EXTERNAL :: check_dims, basin, climateflow, prms_time
      INTEGER, EXTERNAL :: cascade, obs, soltab, transp_tindex
      INTEGER, EXTERNAL :: transp_frost, frost_date, routing
      INTEGER, EXTERNAL :: temp_1sta_laps, temp_dist2
      INTEGER, EXTERNAL :: precip_1sta_laps, climate_hru
      INTEGER, EXTERNAL :: precip_dist2, xyz_dist, ide_dist
      INTEGER, EXTERNAL :: ddsolrad, ccsolrad
      INTEGER, EXTERNAL :: potet_pan, potet_jh, potet_hamon, potet_hs, potet_pt, potet_pm
      INTEGER, EXTERNAL :: intcp, snowcomp, gwflow
      INTEGER, EXTERNAL :: srunoff, srunoff_urban, soilzone                                                                 ! mm
      INTEGER, EXTERNAL :: strmflow, subbasin, basin_sum, map_results, write_climate_hru
      INTEGER, EXTERNAL :: strmflow_in_out, muskingum, potet_pm_sta
      EXTERNAL :: module_doc, nsub_summary, nsegment_summary, basin_summary
      INTEGER, EXTERNAL :: gsflow_modflow, gsflow_prms2mf, gsflow_mf2prms, gsflow_budget, gsflow_sum
      INTEGER, EXTERNAL :: declvar, declparam, getparam, numchars
      EXTERNAL :: module_error, read_error, print_module, PRMS_open_output_file
      EXTERNAL :: call_modules_restart, check_nhru_params, water_balance, nhru_summary
! Local Variables
      INTEGER :: i, iret, nc
!***********************************************************************
      call_modules = 1

      Process = Arg

      IF ( Process(:3)=='run' ) THEN
        Process_flag = 0 !(0=run, 1=declare, 2=init, 3=clean, 4=setdims)

      ELSEIF ( Process(:4)=='decl' ) THEN
        IF ( Model==1 ) THEN
          CALL DATE_AND_TIME(VALUES=Elapsed_time_start)
          Execution_time_start = Elapsed_time_start(5)*3600 + Elapsed_time_start(6)*60 + &
     &                           Elapsed_time_start(7) + Elapsed_time_start(8)*0.001
        ENDIF
        Process_flag = 1

        PRMS_versn = 'gsflow_prms_gu.f90 2018-12-08 15:20:00Z'

        IF ( check_dims()/=0 ) STOP

        IF ( Print_debug>-1 ) PRINT 10, PRMS_VERSION
        WRITE ( Logunt, 10 ) PRMS_VERSION
        WRITE ( PRMS_output_unit, 10 ) PRMS_VERSION
  10  FORMAT (/, 15X, 'Precipitation-Runoff Modeling System (PRMS)', /, 23X, A)
  15  FORMAT (/, 8X, 'Process',  12X, 'Available Modules', /, 68('-'), /, &
     &        '  Basin Definition: basin', /, &
     &        '    Cascading Flow: cascade', /, &
     &        '  Time Series Data: obs', /, &
     &        '   Potet Solar Rad: soltab', /, &
     &        '  Temperature Dist: temp_1sta, temp_laps, temp_dist2, climate_hru', /, &
     &        '       Precip Dist: precip_1sta, precip_laps, precip_dist2,', /, &
     &        '                    climate_hru', /, &
     &        'Temp & Precip Dist: xyz_dist, ide_dist', /, &
     &        '    Solar Rad Dist: ccsolrad, ddsolrad, climate_hru', /, &
     &        'Transpiration Dist: transp_tindex, climate_hru, transp_frost', /, &
     &        '      Potential ET: potet_hamon, potet_jh, potet_pan, climate_hru,', /, &
     &        '                    potet_hs, potet_pt, potet_pm, potet_pm_sta', /, &
     &        '      Interception: intcp', /, &
     &        '     Snow Dynamics: snowcomp', /, &
     &        '    Surface Runoff: srunoff_smidx, srunoff_carea, srunoff_scscn,', /, &                                      ! mm
     &        '                    srunoff_grnampt, srunoff_urban', /, &                                                    ! mm
     &        '         Soil Zone: soilzone', /, &
     &        '       Groundwater: gwflow, gw_topmodel', /, &                                                               ! mm
     &        'Streamflow Routing: strmflow, strmflow_in_out, muskingum', /, &
     &        '    Output Summary: basin_sum, subbasin, map_results, nhru_summary', /, &
     &        '                    nsub_summary, basin_summary, water_balance', /, &
     &        '     Preprocessing: write_climate_hru, frost_date', /, 68('-'))
  16  FORMAT (//, 4X, 'Active modules listed in the order in which they are called', //, 8X, 'Process', 19X, &
     &        'Module', 16X, 'Version Date', /, A)

        IF ( Model==0 ) THEN
          call_modules = gsflow_modflow()
          IF ( call_modules/=0 ) CALL module_error(MODNAME, Arg, call_modules)
        ENDIF

        IF ( Print_debug>-1 ) THEN
          PRINT 15
          PRINT 9002
          PRINT 16, EQULS
        ENDIF
        WRITE ( Logunt, 15 )
        WRITE ( Logunt, 16 ) EQULS
        WRITE ( PRMS_output_unit, 15 )
        WRITE ( PRMS_output_unit, 16 ) EQULS
        CALL print_module(PRMS_versn, 'GSFLOW Computation Order    ', 90)

        IF ( Model==0 .OR. Model==99 ) THEN
          IF ( declvar(MODNAME, 'KKITER', 'one', 1, 'integer', &
     &         'Current iteration in GSFLOW simulation', 'none', KKITER)/=0 ) CALL read_error(3, 'KKITER')
          IF ( declparam(MODNAME, 'mxsziter', 'one', 'integer', &
     &         '0', '0', '5000', &
     &         'Maximum number of iterations soilzone states are computed', &
     &         'Maximum number of iterations soilzone states are computed', &
     &         'none')/=0 ) CALL read_error(1, 'mxsziter')
          ALLOCATE ( Gvr_cell_pct(Nhrucell) )
          IF ( Nhru/=Nhrucell ) THEN
            IF ( declparam(MODNAME, 'gvr_cell_pct', 'nhrucell', 'real', &
     &           '0.0', '0.0', '1.0', &
     &           'Proportion of the grid cell associated with each GVR', &
     &           'Proportion of the grid cell area associated with each gravity reservoir', &
     &           'decimal fraction')/=0 ) CALL read_error(1, 'gvr_cell_pct')
          ENDIF
        ENDIF
        IF ( MapOutON_OFF>0 .AND. ( Model==0 .OR. Model==99) ) THEN                                                         ! mm bug fix
          ALLOCATE ( Gvr_cell_id(Nhrucell) )
          IF ( declparam(MODNAME, 'gvr_cell_id', 'nhrucell', 'integer', &
     &         '-1', '-1', '999999999', &
     &         'Corresponding grid cell id associated with each GVR', &
     &         'Index of the grid cell associated with each gravity reservoir', &
     &         'none')/=0 ) CALL read_error(1, 'gvr_cell_id')
        ENDIF

        Kkiter = 1 ! set for PRMS-only mode

        IF ( Init_vars_from_file==0 ) THEN
          Timestep = 0
        ELSE
          CALL call_modules_restart(1)
        ENDIF
        First_timestep = Timestep

      ELSEIF ( Process(:4)=='init' ) THEN
        Process_flag = 2

        Grid_flag = 0
        IF ( Nhru==Nhrucell ) Grid_flag = 1
        IF ( Model==0 ) THEN
          IF ( Nhru==Nhrucell ) THEN
            Gvr_cell_pct = 1.0
          ELSE
            IF ( getparam(MODNAME, 'gvr_cell_pct', Nhrucell, 'real', &
     &           Gvr_cell_pct)/=0 ) CALL read_error(2, 'gvr_cell_pct')
          ENDIF
          IF ( getparam(MODNAME, 'mxsziter', 1, 'integer', Mxsziter)/=0 ) CALL read_error(2, 'mxsziter')
        ENDIF
        IF ( MapOutON_OFF>0 .AND. Model==0 ) THEN                                                                           ! mm bug fux
          IF ( getparam(MODNAME, 'gvr_cell_id', Nhrucell, 'integer', &
     &         Gvr_cell_id)/=0 ) CALL read_error(2, 'gvr_cell_id')
          IF ( Gvr_cell_id(1)==-1 ) THEN
            IF ( Nhru==Nhrucell ) THEN
              IF ( Print_debug>-1 ) THEN
                PRINT *, 'WARNING, HRUs are assumed to be numbered from upper left corner'
                PRINT *, '         gvr_cell_id values are set to 1 through nhru'
              ENDIF
              DO i = 1, Nhrucell
                Gvr_cell_id(i) = i
              ENDDO
            ELSE
              STOP 'ERROR, gvr_cell_id must be specified'
            ENDIF
          ENDIF
        ENDIF
        IF ( Model==0 ) THEN
          call_modules = gsflow_modflow()
          IF ( call_modules/=0 ) CALL module_error(MODNAME, Arg, call_modules)
        ENDIF

        nc = numchars(Model_control_file)
        IF ( Print_debug>-1 ) PRINT 9004, 'Using Control File: ', Model_control_file(:nc)
        WRITE ( PRMS_output_unit, 9004 ) 'Using Control File: ', Model_control_file(:nc)
        WRITE ( Logunt, 9004 ) 'Using Control File: ', Model_control_file(:nc)

        nc = numchars(Param_file)
        IF ( Print_debug>-1 ) PRINT 9004, 'Using Parameter File: ', Param_file(:nc)
        WRITE ( PRMS_output_unit, 9004 ) 'Using Parameter File: ', Param_file(:nc)
        WRITE ( Logunt, 9004 ) 'Using Parameter File: ', Param_file(:nc)

        IF ( Init_vars_from_file==1 ) THEN
          nc = numchars(Var_init_file)
          IF ( Print_debug>-1 ) PRINT 9004, 'Using var_init_file: ', Var_init_file(:nc)
          WRITE ( Logunt, 9004 ) 'Writing var_init_file: ', Var_init_file(:nc)
        ENDIF
        IF ( Save_vars_to_file==1 ) THEN
          nc = numchars(Var_save_file)
          IF ( Print_debug>-1 ) PRINT 9004, 'Using var_save_file: ', Var_save_file(:nc)
          WRITE ( Logunt, 9004 ) 'Writing var_save_file: ', Var_save_file(:nc)
        ENDIF

        nc = numchars(Model_output_file)
        IF ( Print_debug>-1 ) PRINT 9004, 'Writing PRMS Water Budget File: ', Model_output_file(:nc)
        WRITE ( Logunt, 9004 ) 'Writing PRMS Water Budget File: ', Model_output_file(:nc)

      ELSEIF ( Process(:7)=='setdims' ) THEN
        Process_flag = 4

      ELSE  !IF ( Process(:5)=='clean' ) THEN
        Process_flag = 3
        IF ( Init_vars_from_file==1 ) CLOSE ( Restart_inunit )
        IF ( Save_vars_to_file==1 ) THEN
          nc = numchars(Var_save_file)
          CALL PRMS_open_output_file(Restart_outunit, Var_save_file(:nc), 'var_save_file', 1, iret)
          IF ( iret/=0 ) STOP
          CALL call_modules_restart(0)
        ENDIF
        IF ( Model==0 ) THEN
          call_modules = gsflow_modflow()
          IF ( call_modules/=0 ) CALL module_error(MODNAME, Arg, call_modules)
        ENDIF
      ENDIF

      IF ( Model==99 ) THEN
        IF ( Process_flag==4 .OR. Process_flag<2 ) THEN
          Init_vars_from_file = 0 ! make sure this is set so all variables and parameters are declared
          CALL module_doc()
          call_modules = 0
          RETURN
        ELSE
          STOP
        ENDIF
      ENDIF

! All modules must be called for setdims, declare, initialize, and cleanup
      IF ( Process_flag/=0 ) THEN
        call_modules = basin()
        IF ( call_modules/=0 ) CALL module_error('basin', Arg, call_modules)

        IF ( Call_cascade==1 ) THEN
          call_modules = cascade()
          IF ( call_modules/=0 ) CALL module_error('cascade', Arg, call_modules)
        ENDIF

        call_modules = climateflow()
        IF ( call_modules/=0 ) CALL module_error('climateflow', Arg, call_modules)

        call_modules = soltab()
        IF ( call_modules/=0 ) CALL module_error('soltab', Arg, call_modules)
      ENDIF

      call_modules = prms_time()
      IF ( call_modules/=0 ) CALL module_error('prms_time', Arg, call_modules)

      call_modules = obs()
      IF ( call_modules/=0 ) CALL module_error('obs', Arg, call_modules)

      IF ( Climate_hru_flag==1 ) THEN
        call_modules = climate_hru()
        IF ( call_modules/=0 ) CALL module_error('climate_hru', Arg, call_modules)
      ENDIF

      IF ( Climate_temp_flag==0 ) THEN
        IF ( Temp_combined_flag==1 ) THEN
          call_modules = temp_1sta_laps()
        ELSEIF ( Temp_flag==6 ) THEN
          call_modules = xyz_dist()
        ELSEIF ( Temp_flag==3 ) THEN
          call_modules = temp_dist2()
        ELSE !IF ( Temp_flag==5 ) THEN
          call_modules = ide_dist()
        ENDIF
        IF ( call_modules/=0 ) CALL module_error(Temp_module, Arg, call_modules)
      ENDIF

      IF ( Climate_precip_flag==0 ) THEN
        IF ( Precip_combined_flag==1 ) THEN
          call_modules = precip_1sta_laps()
        ELSEIF ( Precip_flag==3 ) THEN
          call_modules = precip_dist2()
        ENDIF
        IF ( call_modules/=0 ) CALL module_error(Precip_module, Arg, call_modules)
      ENDIF

! frost_date is a pre-process module
      IF ( Model==9 ) THEN
        call_modules = frost_date()
        IF ( call_modules/=0 ) CALL module_error('frost_date', Arg, call_modules)
        IF ( Process_flag==0 ) RETURN
        IF ( Process_flag==3 ) STOP
      ENDIF

      IF ( Climate_swrad_flag==0 ) THEN
        IF ( Solrad_flag==1 ) THEN
          call_modules = ddsolrad()
        ELSE !IF ( Solrad_flag==2 ) THEN
          call_modules = ccsolrad()
        ENDIF
        IF ( call_modules/=0 ) CALL module_error(Solrad_module, Arg, call_modules)
      ENDIF

      IF ( Transp_flag==1 ) THEN
        call_modules = transp_tindex()
      ELSEIF ( Transp_flag==2 ) THEN
        call_modules = transp_frost()
      ENDIF
      IF ( call_modules/=0 ) CALL module_error(Transp_module, Arg, call_modules)

      IF ( Climate_potet_flag==0 ) THEN
        IF ( Et_flag==1 ) THEN
          call_modules = potet_jh()
        ELSEIF ( Et_flag==2 ) THEN
          call_modules = potet_hamon()
        ELSEIF ( Et_flag==4 ) THEN
          call_modules = potet_pan()
        ELSEIF ( Et_flag==5 ) THEN
          call_modules = potet_pt()
        ELSEIF ( Et_flag==6 ) THEN
          call_modules = potet_pm_sta()
        ELSEIF ( Et_flag==11 ) THEN
          call_modules = potet_pm()
        ELSE !IF ( Et_flag==10 ) THEN
          call_modules = potet_hs()
        ENDIF
        IF ( call_modules/=0 ) CALL module_error(Et_module, Arg, call_modules)
      ENDIF

      IF ( Model==4 ) THEN
        call_modules = write_climate_hru()
        IF ( call_modules/=0 ) CALL module_error('write_climate_hru', Arg, call_modules)
        IF ( Process_flag==0 ) RETURN
      ENDIF

      call_modules = intcp()
      IF ( call_modules/=0 ) CALL module_error('intcp', Arg, call_modules)

      call_modules = snowcomp()
      IF ( call_modules/=0 ) CALL module_error('snowcomp', Arg, call_modules)

      call_modules = srunoff()
      IF ( call_modules/=0 ) CALL module_error(Srunoff_module, Arg, call_modules)

      IF ( Surban_flag/=0 ) THEN                                                                                ! mm
        call_modules = srunoff_urban()                                                                                !
        IF ( call_modules/=0 ) CALL module_error('srunoff_urban', Arg, call_modules)                                        !
      ENDIF                                                                                ! mm

! for PRMS-only simulations
      IF ( PRMS_flag==1 ) THEN
        call_modules = soilzone()
        IF ( call_modules/=0 ) CALL module_error(Soilzone_module, Arg, call_modules)

        call_modules = gwflow()
        IF ( call_modules/=0 ) CALL module_error('gwflow', Arg, call_modules)

        IF ( Stream_order_flag==1 ) THEN
          call_modules = routing()
          IF ( call_modules/=0 ) CALL module_error('routing', Arg, call_modules)
        ENDIF

        IF ( Strmflow_flag==1 ) THEN
          call_modules = strmflow()
        ELSEIF ( Strmflow_flag==4 ) THEN
          call_modules = muskingum()
        ELSE !IF ( Strmflow_flag==5 ) THEN
          call_modules = strmflow_in_out()
        ENDIF
        IF ( call_modules/=0 ) CALL module_error(Strmflow_module, Arg, call_modules)

        call_modules = basin_sum()
        IF ( call_modules/=0 ) CALL module_error('basin_sum', Arg, call_modules)

        IF ( Print_debug==1 ) CALL water_balance()

! for GSFLOW simulations
      ELSEIF ( Model==0 ) THEN

        IF ( Process_flag==0 ) THEN
          call_modules = gsflow_modflow()
          IF ( call_modules/=0 ) CALL module_error(MODNAME, Arg, call_modules)

! The following modules are in the MODFLOW iteration loop
! (contained in gsflow_modflow.f).
! They still need to be called for declare, initialize and cleanup
        ELSE !IF ( Process_flag/=0 ) THEN

! SOILZONE for GSFLOW is in the MODFLOW iteration loop,
! only call for declare, initialize, and cleanup.
          call_modules = soilzone()
          IF ( call_modules/=0 ) CALL module_error(Soilzone_module, Arg, call_modules)

          call_modules = gsflow_prms2mf()
          IF ( call_modules/=0 ) CALL module_error('gsflow_prms2mf', Arg, call_modules)

          call_modules = gsflow_mf2prms()
          IF ( call_modules/=0 ) CALL module_error('gsflow_mf2prms', Arg, call_modules)
        ENDIF

        call_modules = gsflow_budget()
        IF ( call_modules/=0 ) CALL module_error('gsflow_budget', Arg, call_modules)

        call_modules = gsflow_sum()
        IF ( call_modules/=0 ) CALL module_error('gsflow_sum', Arg, call_modules)
      ENDIF

      IF ( MapOutON_OFF>0 ) THEN
        call_modules = map_results()
        IF ( call_modules/=0 ) CALL module_error('map_results', Arg, call_modules)
      ENDIF

      IF ( NhruOutON_OFF>0 ) CALL nhru_summary()

      IF ( NsubOutON_OFF==1 ) CALL nsub_summary()

      IF ( BasinOutON_OFF==1 ) CALL basin_summary()

      IF ( NsegmentOutON_OFF==1 ) CALL nsegment_summary()

      IF ( Subbasin_flag==1 ) THEN
        call_modules = subbasin()
        IF ( call_modules/=0 ) CALL module_error('subbasin', Arg, call_modules)
      ENDIF

      IF ( Process_flag==3 ) THEN
        IF ( Model==1 ) THEN
          CALL DATE_AND_TIME(VALUES=Elapsed_time_end)
          PRINT 9001
          PRINT 9003, 'start', (Elapsed_time_start(i),i=1,3), (Elapsed_time_start(i),i=5,7)
          PRINT 9003, 'end  ', (Elapsed_time_end(i),i=1,3), (Elapsed_time_end(i),i=5,7)
          Execution_time_end = Elapsed_time_end(5)*3600 + Elapsed_time_end(6)*60 + &
     &                         Elapsed_time_end(7) + Elapsed_time_end(8)*0.001
          Elapsed_time = Execution_time_end - Execution_time_start
          Elapsed_time_minutes = INT(Elapsed_time/60.0)
          PRINT '(A,I5,A,F6.2,A,/)', 'Execution elapsed time', Elapsed_time_minutes, ' minutes', &
     &                               Elapsed_time - Elapsed_time_minutes*60.0, ' seconds'
          WRITE ( PRMS_output_unit,'(A,I5,A,F6.2,A,/)') 'Execution elapsed time', Elapsed_time_minutes, ' minutes', &
     &                                                  Elapsed_time - Elapsed_time_minutes*60.0, ' seconds'
          WRITE ( Logunt,'(A,I5,A,F6.2,A,/)') 'Execution elapsed time', Elapsed_time_minutes, ' minutes', &
     &                                        Elapsed_time - Elapsed_time_minutes*60.0, ' seconds'
        ENDIF
        CLOSE ( Logunt )
      ELSEIF ( Process_flag==1 ) THEN
        IF ( Model==1 ) THEN
          PRINT '(A)', EQULS
          WRITE ( PRMS_output_unit, '(A)' ) EQULS
          WRITE ( Logunt, '(A)') EQULS
        ENDIF
      ELSEIF ( Process_flag==2 ) THEN
        IF ( Parameter_check_flag>0 ) CALL check_nhru_params()
        IF ( Inputerror_flag==1 ) THEN
          PRINT '(//,A,//,A,/,A,/,A)', '**Fix input errors in your Parameter File to continue**', &
     &          '  Set control parameter parameter_check_flag to 0 after', &
     &          '  all parameter values are valid.'
          PRINT '(/,A,/,A,/,A,/,A,/,A,/)', &
     &          'If input errors are related to paramters used for automated', &
     &          'calibration processes, with CAUTION, set control parameter', &
     &          'parameter_check_flag to 0. After calibration set the', &
     &          'parameter_check_flag to 1 to verify that those calibration', &
     &          'parameters have valid and compatible values.'
          STOP
        ENDIF
        IF ( Parameter_check_flag==2 ) STOP
        PRINT 4, 'Simulation time period:', Start_year, Start_month, Start_day, ' -', End_year, End_month, End_day, EQULS
        WRITE ( Logunt, 4 ) 'Simulation time period:', Start_year, Start_month, Start_day, ' -', End_year, End_month, End_day, EQULS
      ENDIF
    4 FORMAT (/, 2(A, I5, 2('/',I2.2)), //, A, /)
 9001 FORMAT (/, 26X, 27('='), /, 26X, 'Normal completion of GSFLOW', /, 26X, 27('='), /)
 9002 FORMAT (//, 74('='), /, 'Please give careful consideration to fixing all ERROR and WARNING messages', /, 74('='))
 9003 FORMAT ('Execution ', A, ' date and time (yyyy/mm/dd hh:mm:ss)', I5, 2('/',I2.2), I3, 2(':',I2.2), /)
 9004 FORMAT (/, 2A)

      END FUNCTION call_modules

!***********************************************************************
!     declare the dimensions
!***********************************************************************
      INTEGER FUNCTION setdims()
      USE PRMS_MODULE
      USE GLOBAL, ONLY: NSTP, NPER
      IMPLICIT NONE
! Functions
      INTEGER, EXTERNAL :: decldim, declfix, call_modules, control_integer_array, control_file_name
      INTEGER, EXTERNAL :: control_string, control_integer, gsflow_modflow
      EXTERNAL :: read_error, PRMS_open_output_file, PRMS_open_input_file, check_module_names, module_error
! Local Variables
      ! Maximum values are no longer limits
! Local Variables
      INTEGER :: idim, iret, j
      INTEGER :: test, mf_timestep
!***********************************************************************
      setdims = 1

      Inputerror_flag = 0

      CALL PRMS_open_output_file(Logunt, 'gsflow.log', 'gsflow.log', 0, iret)
      IF ( iret/=0 ) STOP

      PRINT 3
      WRITE ( Logunt, 3 )
    3 FORMAT (//, 26X, 'U.S. Geological Survey', /, 8X, &
     &        'Coupled Groundwater and Surface-water FLOW model (GSFLOW)', /, &
     &        25X, 'Version 1.2.2 02/23/2018', //, &
     &        '    An integration of the Precipitation-Runoff Modeling System (PRMS)', /, &
     &        '    and the Modular Groundwater Model (MODFLOW-NWT and MODFLOW-2005)', /)

      PRINT 4
      WRITE ( Logunt, 4 )
    4 FORMAT (/, 19X, 'Urban hydrology edition (GSFLOWurban)', /, &
     &        26X, 'Version 0.4 12/07/2018', /, &
     &        26X, 'copyright M.Marchildon', /)

      ! debug print flag:
      ! -1=quiet - reduced screen output
      ! 0=none; 1=water balances; 2=basin;
      ! 4=basin_sum; 5=soltab; 7=soil zone;
      ! 9=snowcomp; 13=cascade; 14=subbasin tree
      IF ( control_integer(Print_debug, 'print_debug')/=0 ) Print_debug = 0

      IF ( control_integer(Parameter_check_flag, 'parameter_check_flag')/=0 ) Parameter_check_flag = 1

      IF ( control_string(Model_mode, 'model_mode')/=0 ) CALL read_error(5, 'model_mode')
      PRMS_flag = 1
!     Model (0=GSFLOW; 1=PRMS; 2=MODFLOW)
      IF ( Model_mode(:6)=='GSFLOW' .OR. Model_mode(:4)=='    ') THEN
        Model = 0
        PRMS_flag = 0
      ELSEIF ( Model_mode(:4)=='PRMS' .OR. Model_mode(:5)=='DAILY' )THEN
        Model = 1
      ELSEIF ( Model_mode(:7)=='MODFLOW' ) THEN
        Model = 2
        PRMS_flag = 0
      ELSEIF ( Model_mode(:5)=='FROST' ) THEN
        Model = 9
      ELSEIF ( Model_mode(:13)=='WRITE_CLIMATE' ) THEN
        Model = 4
      ELSEIF ( Model_mode(:13)=='DOCUMENTATION' ) THEN
        Model = 99
      ELSE
        PRINT '(/,2A)', 'ERROR, invalid model_mode value: ', Model_mode
        STOP
      ENDIF

      ! get simulation start_time and end_time
      Starttime = -1
      DO j = 1, 6
        IF ( control_integer_array(Starttime(j), j, 'start_time')/=0 ) THEN
          PRINT *, 'ERROR, start_time, index:', j, 'value: ', Starttime(j)
          STOP
        ENDIF
      ENDDO
      Start_year = Starttime(1)
      IF ( Start_year<0 ) STOP 'ERROR, control parameter start_time must be specified'
      Start_month = Starttime(2)
      Start_day = Starttime(3)
      Endtime = -1
      DO j = 1, 6
        IF ( control_integer_array(Endtime(j), j, 'end_time')/=0 ) THEN
          PRINT *, 'ERROR, end_time, index:', j, 'value: ', Endtime(j)
          STOP
        ENDIF
      ENDDO
      End_year = Endtime(1)
      IF ( End_year<0 ) STOP 'ERROR, control parameter start_time must be specified'
      End_month = Endtime(2)
      End_day = Endtime(3)

      IF ( control_integer(Init_vars_from_file, 'init_vars_from_file')/=0 ) Init_vars_from_file = 0
      IF ( control_integer(Save_vars_to_file, 'save_vars_to_file')/=0 ) Save_vars_to_file = 0

      IF ( Model==2 ) THEN
! for MODFLOW-only simulations
        Kper_mfo = 1
        mf_timestep = 1
        Process_flag = 1
        test = gsflow_modflow()
        IF ( test/=0 ) CALL module_error(MODNAME, 'declare', test)
        Process_flag = 2
        test = gsflow_modflow()
        IF ( test/=0 ) CALL module_error(MODNAME, 'initialize', test)
        PRINT *, ' '
        WRITE (Logunt, '(1X)')
        Process_flag = 0
        DO WHILE ( Kper_mfo<=Nper )
          test = gsflow_modflow()
          IF ( test/=0 ) CALL module_error(MODNAME, 'run', test)
          IF ( mf_timestep==NSTP(Kper_mfo) ) THEN
              Kper_mfo = Kper_mfo + 1
              mf_timestep = 0
          END IF
          mf_timestep = mf_timestep + 1
        ENDDO
        Process_flag = 3
        test = gsflow_modflow()
        IF ( test/=0 ) CALL module_error(MODNAME, 'clean', test)
        STOP
      ENDIF

      ! Open PRMS module output file
      IF ( control_string(Model_output_file, 'model_output_file')/=0 ) CALL read_error(5, 'model_output_file')
      CALL PRMS_open_output_file(PRMS_output_unit, Model_output_file, 'model_output_file', 0, iret)
      IF ( iret/=0 ) STOP
      IF ( control_file_name(Model_control_file)/=0 ) CALL read_error(5, 'control_file_name')
      IF ( control_string(Param_file, 'param_file')/=0 ) CALL read_error(5, 'param_file')

      ! Check for restart files
      IF ( Init_vars_from_file==1 ) THEN
        IF ( control_string(Var_init_file, 'var_init_file')/=0 ) CALL read_error(5, 'var_init_file')
        CALL PRMS_open_input_file(Restart_inunit, Var_init_file, 'var_init_file', 1, iret)
        IF ( iret/=0 ) STOP
      ENDIF
      IF ( Save_vars_to_file==1 ) THEN
        IF ( control_string(Var_save_file, 'var_save_file')/=0 ) CALL read_error(5, 'var_save_file')
      ENDIF

      Temp_module = ' '
      IF ( control_string(Temp_module, 'temp_module')/=0 ) CALL read_error(5, 'temp_module')
      Precip_module = ' '
      IF ( control_string(Precip_module, 'precip_module')/=0 ) CALL read_error(5, 'precip_module')
      Transp_module = ' '
      IF ( control_string(Transp_module, 'transp_module')/=0 ) CALL read_error(5, 'transp_module')
      Et_module = ' '
      IF ( control_string(Et_module, 'et_module')/=0 ) CALL read_error(5, 'et_module')
      Srunoff_module = ' '
      IF ( control_string(Srunoff_module, 'srunoff_module')/=0 ) CALL read_error(5, 'srunoff_module')
      Solrad_module = ' '
      IF ( control_string(Solrad_module, 'solrad_module')/=0 ) CALL read_error(5, 'solrad_module')
      Strmflow_module = 'strmflow'
      IF ( control_string(Strmflow_module, 'strmflow_module')/=0 ) CALL read_error(5, 'strmflow_module')

      IF ( Parameter_check_flag>0 ) CALL check_module_names()

      Climate_precip_flag = 0
      Climate_temp_flag = 0
      Climate_transp_flag = 0
      Climate_potet_flag = 0
      Climate_swrad_flag = 0

      IF ( Precip_module(:11)=='precip_1sta' .OR. Precip_module(:11)=='precip_prms') THEN
        Precip_flag = 1
      ELSEIF ( Precip_module(:11)=='precip_laps' ) THEN
        Precip_flag = 2
      ELSEIF ( Precip_module(:12)=='precip_dist2' ) THEN
        Precip_flag = 3
      ELSEIF ( Precip_module(:8)=='ide_dist' ) THEN
        Precip_flag = 5
      ELSEIF ( Precip_module(:11)=='climate_hru' ) THEN
        Precip_flag = 7
        Climate_precip_flag = 1
      ELSEIF ( Precip_module(:8)=='xyz_dist' ) THEN
        Precip_flag = 6
      ELSE
        PRINT '(/,2A)', 'ERROR: invalid precip_module value: ', Precip_module
        Inputerror_flag = 1
      ENDIF
      Precip_combined_flag = 0
      IF ( Precip_flag==1 .OR. Precip_flag==2 ) Precip_combined_flag = 1

      IF ( Temp_module(:9)=='temp_1sta' ) THEN
        Temp_flag = 1
      ELSEIF ( Temp_module(:9)=='temp_laps' ) THEN
        Temp_flag = 2
      ELSEIF ( Temp_module(:10)=='temp_dist2' ) THEN
        Temp_flag = 3
      ELSEIF ( Temp_module(:8)=='ide_dist' ) THEN
        Temp_flag = 5
      ELSEIF ( Temp_module(:11)=='climate_hru' ) THEN
        Temp_flag = 7
        Climate_temp_flag = 1
      ELSEIF ( Temp_module(:8)=='xyz_dist' ) THEN
        Temp_flag = 6
      ELSE
        PRINT '(/,2A)', 'ERROR, invalid temp_module value: ', Temp_module
        Inputerror_flag = 1
      ENDIF
      Temp_combined_flag = 0
      IF ( Temp_flag==1 .OR. Temp_flag==2 ) Temp_combined_flag = 1

      IF ( Transp_module(:13)=='transp_tindex' ) THEN
        Transp_flag = 1
      ELSEIF ( Transp_module(:12)=='transp_frost' ) THEN
        Transp_flag = 2
      ELSEIF ( Transp_module(:11)=='climate_hru' ) THEN
        Transp_flag = 3
        Climate_transp_flag = 1
      ELSE
        PRINT '(/,2A)', 'ERROR, invalid transp_module value: ', Transp_module
        Inputerror_flag = 1
      ENDIF

      IF ( Et_module(:8)=='potet_jh' ) THEN
        Et_flag = 1
      ELSEIF ( Et_module(:11)=='potet_hamon' ) THEN
        Et_flag = 2
      ELSEIF ( Et_module(:11)=='climate_hru' ) THEN
        Et_flag = 7
        Climate_potet_flag = 1
      ELSEIF ( Et_module(:8)=='potet_hs' ) THEN
        Et_flag = 10
      ELSEIF ( Et_module(:12)=='potet_pm_sta' ) THEN
        Et_flag = 6
      ELSEIF ( Et_module(:8)=='potet_pm' ) THEN
        Et_flag = 11
      ELSEIF ( Et_module(:8)=='potet_pt' ) THEN
        Et_flag = 5
      ELSEIF ( Et_module(:9)=='potet_pan' ) THEN
        Et_flag = 4
      ELSE
        PRINT '(/,2A)', 'ERROR, invalid et_module value: ', Et_module
        Inputerror_flag = 1
      ENDIF
      Humidity_cbh_flag = 0
      Windspeed_cbh_flag = 0
      IF ( Et_flag==11 .OR. Et_flag==5 ) Humidity_cbh_flag = 1
      IF ( Et_flag==11 ) Windspeed_cbh_flag = 1

      Surban_flag = 0                                                                                ! mm
      IF ( Srunoff_module(:13)=='srunoff_smidx' ) THEN
        Sroff_flag = 1
      ELSEIF ( Srunoff_module(:13)=='srunoff_carea' ) THEN
        Sroff_flag = 2
      ELSEIF ( Srunoff_module(:13)=='srunoff_scscn' ) THEN                                                                  ! mm begin
        Sroff_flag = 3
      ELSEIF ( Srunoff_module(:15)=='srunoff_grnampt' ) THEN
        Sroff_flag = 4
      ELSEIF ( Srunoff_module(:19)=='srunoff_smidx_urban' ) THEN
        Surban_flag = 1
        Sroff_flag = 1
      ELSEIF ( Srunoff_module(:19)=='srunoff_carea_urban' ) THEN
        Surban_flag = 1
        Sroff_flag = 2
      ELSEIF ( Srunoff_module(:19)=='srunoff_scscn_urban' ) THEN
        Surban_flag = 1
        Sroff_flag = 3
      ELSEIF ( Srunoff_module(:21)=='srunoff_grnampt_urban' ) THEN
        Surban_flag = 1
        Sroff_flag = 4                                                                                ! mm end
      ELSEIF ( Srunoff_module(:13)/='srunoff_smidx' ) THEN
        PRINT '(/,2A)', 'ERROR, invalid srunoff_module value: ', Srunoff_module
        Inputerror_flag = 1
      ENDIF

      Soilzone_module = 'soilzone'

      IF ( PRMS_flag==1 ) THEN                                                                                ! mm begin
        !Gw_module = ' '           !PJT - 2019Jan14 - Add control string in setup_cont.c for the PRMS groundwater module, default value of 'gwflow' (EXE won't crash when gw_module is not specified in the control file)
        IF ( control_string(Gw_module, 'gw_module')/=0 ) CALL read_error(5, 'gw_module')
          Gw_flag = 1 ! gwflow (native PRMS grounwater reservoir)
        IF ( Gw_module(:11)=='gw_topmodel' ) THEN
          Gw_flag = 2
        ELSEIF ( Gw_module(:6)/='gwflow' ) THEN
          PRINT '(/,2A)', 'ERROR, invalid gw_module value: ', Gw_module
          Inputerror_flag = 1
        ENDIF
      ENDIF                                                                                ! mm end

      IF ( control_integer(Orad_flag, 'orad_flag')/=0 ) Orad_flag = 0
      IF ( Solrad_module(:8)=='ddsolrad' ) THEN
        Solrad_flag = 1
      ELSEIF ( Solrad_module(:11)=='climate_hru' ) THEN
        Solrad_flag = 7
        Climate_swrad_flag = 1
      ELSEIF ( Solrad_module(:8)=='ccsolrad' ) THEN
        Solrad_flag = 2
      ELSE
        PRINT '(/,2A)', 'ERROR, invalid solrad_module value: ', Solrad_module
        Inputerror_flag = 1
      ENDIF

      Climate_hru_flag = 0
      IF ( Climate_temp_flag==1 .OR. Climate_precip_flag==1 .OR. Climate_potet_flag==1 .OR. &
     &     Climate_swrad_flag==1 .OR. Climate_transp_flag==1 .OR. &
     &     Humidity_cbh_flag==1 .OR. Windspeed_cbh_flag==1 ) Climate_hru_flag = 1

      IF ( Strmflow_module(:15)=='strmflow_in_out' ) THEN
        Strmflow_flag = 5
      ELSEIF ( Strmflow_module(:13)=='strmflow_lake' ) THEN
        PRINT '(/,2A)', 'ERROR, invalid strmflow_module value; lakes are not simulated: ', Strmflow_module
        Inputerror_flag = 1
      ELSEIF ( Strmflow_module(:8)=='strmflow' ) THEN
        Strmflow_flag = 1
      ELSEIF ( Strmflow_module(:9)=='muskingum' ) THEN
        Strmflow_flag = 4
      ELSE
        PRINT '(/,2A)', 'ERROR, invalid strmflow_module value: ', Strmflow_module
        Inputerror_flag = 1
      ENDIF

! cascade dimensions
      IF ( decldim('ncascade', 0, MAXDIM, &
     &     'Number of HRU links for cascading flow')/=0 ) CALL read_error(7, 'ncascade')
      IF ( decldim('ncascdgw', 0, MAXDIM, &
     &     'Number of GWR links for cascading flow')/=0 ) CALL read_error(7, 'ncascdgw')

! nsegment dimension
      IF ( decldim('nsegment', 0, MAXDIM, 'Number of stream-channel segments')/=0 ) CALL read_error(7, 'nsegment')

! subbasin dimensions
      IF ( control_integer(Subbasin_flag, 'subbasin_flag')/=0 ) Subbasin_flag = 1
      IF ( decldim('nsub', 0, MAXDIM, 'Number of internal subbasins')/=0 ) CALL read_error(7, 'nsub')

      IF ( control_integer(Dprst_flag, 'dprst_flag')/=0 ) Dprst_flag = 0
      IF ( control_integer(CsvON_OFF, 'csvON_OFF')/=0 ) CsvON_OFF = 0

! map results dimensions
      IF ( control_integer(MapOutON_OFF, 'mapOutON_OFF')/=0 ) MapOutON_OFF = 0
      idim = 0
      IF ( Model==0 .OR. MapOutON_OFF==1 ) idim = 1
      IF ( decldim('nhrucell', idim, MAXDIM, &
     &     'Number of unique intersections between HRUs and spatial units of a target map for mapped results')/=0 ) &
     &     CALL read_error(7, 'nhrucell')
      IF ( decldim('ngwcell', 0, MAXDIM, &
     &     'Number of spatial units in the target map for mapped results')/=0 ) CALL read_error(7, 'ngwcell')
      IF ( decldim('nreach', idim, MAXDIM, 'Number of reaches on all stream segments')/=0 ) CALL read_error(7, 'nreach')

      IF ( control_integer(Gwr_swale_flag, 'gwr_swale_flag')/=0 ) Gwr_swale_flag = 0

! nhru_summary
      IF ( control_integer(NhruOutON_OFF, 'nhruOutON_OFF')/=0 ) NhruOutON_OFF = 0

! nsub_summary
      IF ( control_integer(NsubOutON_OFF, 'nsubOutON_OFF')/=0 ) NsubOutON_OFF = 0

! basin_summary
      IF ( control_integer(BasinOutON_OFF, 'basinOutON_OFF')/=0 ) BasinOutON_OFF = 0
! nsegment_summary
      IF ( control_integer(NsegmentOutON_OFF, 'nsegmentOutON_OFF')/=0 ) NsegmentOutON_OFF = 0

! cascade
      IF ( control_integer(Cascade_flag, 'cascade_flag')/=0 ) Cascade_flag = 1
      ! if cascadegw_flag = 2, use same cascades as HRUs
      IF ( control_integer(Cascadegw_flag, 'cascadegw_flag')/=0 ) Cascadegw_flag = 1

! spatial units
      IF ( decldim('ngw', 1, MAXDIM, 'Number of GWRs')/=0 ) CALL read_error(7, 'ngw')
      IF ( decldim('nhru', 1, MAXDIM, 'Number of HRUs')/=0 ) CALL read_error(7, 'nhru')
      IF ( decldim('nssr', 1, MAXDIM, 'Number of subsurface reservoirs')/=0 ) CALL read_error(7, 'nssr')
      IF ( decldim('nlake', 0, MAXDIM, 'Number of lakes')/=0 ) CALL read_error(7, 'nlake')
      ! nlake_hrus to be added in 5.0.1
!      IF ( decldim('nlake_hrus', 0, MAXDIM, 'Number of lake HRUs')/=0 ) CALL read_error(7, 'nlake_hrus')

! Time-series data stations, need to know if in Data File
      IF ( decldim('nrain', 0, MAXDIM, 'Number of precipitation-measurement stations')/=0 ) CALL read_error(7, 'nrain')
      IF ( decldim('nsol', 0, MAXDIM, 'Number of solar-radiation measurement stations')/=0 ) CALL read_error(7, 'nsol')
      IF ( decldim('ntemp', 0, MAXDIM, 'Number of air-temperature-measurement stations')/=0 ) CALL read_error(7, 'ntemp')
      IF ( decldim('nobs', 0, MAXDIM, 'Number of streamflow-measurement stations')/=0 ) CALL read_error(7, 'nobs')
      IF ( decldim('nevap', 0, MAXDIM, 'Number of pan-evaporation data sets')/=0 ) CALL read_error(7, 'nevap')
!      IF ( decldim('nratetbl', 0, MAXDIM, 'Number of rating-table data sets for lake elevations') &
!     &     /=0 ) CALL read_error(7, 'nratetbl')

! If the Green&Ampt Module is Active, allow for hourly precipitation inputs                                                                     ! PJT - 2018Jan03 - Sub-daily precip inputs
     IF ( Sroff_flag == 4 ) THEN                                                                                ! mm: this is safer
        IF ( decldim('nmaxprecipobs', 0, MAXDIM, 'Maximum number of sub-daily precip observations')/=0 ) CALL read_error(7, 'nmaxprecipobs')    ! PJT - 2018Jan03 - Sub-daily precip inputs
     ENDIF

! depletion curves
      IF ( decldim('ndepl', 1, MAXDIM, 'Number of snow-depletion curves')/=0 ) CALL read_error(7, 'ndelp')
      IF ( decldim('ndeplval', 11, MAXDIM, 'Number of values in all snow-depletion curves (set to ndepl*11)')/=0 ) &
     &     CALL read_error(7, 'ndelplval')

! urban storage facilities                                                                                ! mm
      IF ( decldim('ndscn', 1, MAXDIM, 'Number of disconnected reservoirs')/=0 ) CALL read_error(7, 'ndscn')                !
      IF ( decldim('ninfstor', 1, MAXDIM, 'Number of infiltration storage reservoirs')/=0 ) CALL read_error(7, 'ninfstor')  !

! fixed dimensions
      IF ( declfix('ndays', 366, 366, 'Maximum number of days in a year ')/=0 ) CALL read_error(7, 'ndays')
      IF ( declfix('nmonths', 12, 12, 'Number of months in a year')/=0 ) CALL read_error(7, 'nmonths')
      IF ( declfix('one', 1, 1, 'Number of values for scaler array')/=0 ) CALL read_error(7, 'one')

      IF ( call_modules('setdims')/=0 ) STOP 'ERROR, in setdims'

      IF ( Inputerror_flag==1 ) THEN
        PRINT '(//,A,/,A)', '**FIX input errors in your Control File to continue**', &
     &        'NOTE: some errors may be due to use of defalut values'
        STOP
      ENDIF

      setdims = 0
      END FUNCTION setdims

!***********************************************************************
!     Get and check consistency of dimensions with flags
!***********************************************************************
      INTEGER FUNCTION check_dims()
      USE PRMS_MODULE
      IMPLICIT NONE
! Functions
      INTEGER, EXTERNAL :: getdim
      EXTERNAL :: check_dimens
!***********************************************************************

      Nhru = getdim('nhru')
      IF ( Nhru==-1 ) CALL read_error(7, 'nhru')

      Nssr = getdim('nssr')
      IF ( Nssr==-1 ) CALL read_error(7, 'nssr')

      Ngw = getdim('ngw')
      IF ( Ngw==-1 ) CALL read_error(7, 'ngw')

      Ntemp = getdim('ntemp')
      IF ( Ntemp==-1 ) CALL read_error(6, 'ntemp')

      Nrain = getdim('nrain')
      IF ( Nrain==-1 ) CALL read_error(6, 'nrain')

      ! If the Green&Ampt Module is Active, call for the max number of observations                                         ! PJT - 2018Jan03 - Sub-daily precip inputs
      IF ( Sroff_flag == 4 ) THEN                                                                                ! mm: this is safer
        NmaxPrecipObs = getdim('nmaxprecipobs')                                                                             ! PJT - 2018Jan03 - Sub-daily precip inputs
        IF ( NmaxPrecipObs==-1 ) CALL read_error(6, 'nmaxprecipobs')                                                        ! PJT - 2018Jan03 - Sub-daily precip inputs
      ELSE                                                                                ! PJT - 2018Jan03 - Sub-daily precip inputs
         NmaxPrecipObs=0        !Still a dimension, set to zero to ensure there are no 'accidents'                          ! PJT - 2018Jan03 - Sub-daily precip inputs
      ENDIF                                                                                ! PJT - 2018Jan03 - Sub-daily precip inputs

      Nsol = getdim('nsol')
      IF ( Nsol==-1 ) CALL read_error(6, 'nsol')

      Nobs = getdim('nobs')
      IF ( Nobs==-1 ) CALL read_error(6, 'nobs')

      Nevap = getdim('nevap')
      IF ( Nevap==-1 ) CALL read_error(6, 'nevap')

      Ncascade = getdim('ncascade')
      IF ( Ncascade==-1 ) CALL read_error(7, 'ncascade')
      Ncascdgw = getdim('ncascdgw')
      IF ( Ncascdgw==-1 ) CALL read_error(7, 'ncascdgw')
      IF ( Cascadegw_flag==2 ) Ncascdgw = Ncascade
      IF ( Ncascade==0 ) Cascade_flag = 0
      IF ( Ncascdgw==0 .OR. Model==0 .OR. Model==2 ) Cascadegw_flag = 0
      IF ( Cascade_flag==1 .OR. Cascadegw_flag>0 ) THEN
        Call_cascade = 1
      ELSE
        Call_cascade = 0
      ENDIF

      Nlake = getdim('nlake')
      IF ( Nlake==-1 ) CALL read_error(7, 'nlake')

      ! Nlake_hrus will be added in version 5.0.1
!      Nlake_hrus = getdim('nlake_hrus')
!      IF ( Nlake_hrus==-1 ) CALL read_error(7, 'nlake_hrus')
!      IF ( Nlake>0 .AND. Nlake_hrus==0 ) Nlake_hrus = Nlake
      Nlake_hrus = Nlake

      Ndepl = getdim('ndepl')
      IF ( Ndepl==-1 ) CALL read_error(7, 'ndepl')

      Ndeplval = getdim('ndeplval')
      IF ( Ndeplval==-1 ) CALL read_error(7, 'ndeplval')

      Nsub = getdim('nsub')
      IF ( Nsub==-1 ) CALL read_error(7, 'nsub')
      ! default = 1, turn off if no subbasins
      IF ( Subbasin_flag==1 .AND. Nsub==0 ) Subbasin_flag = 0

      Nsegment = getdim('nsegment')
      IF ( Nsegment==-1 ) CALL read_error(7, 'nsegment')

      Nhrucell = getdim('nhrucell')
      IF ( Nhrucell==-1 ) CALL read_error(6, 'nhrucell')

      Ngwcell = getdim('ngwcell')
      IF ( Ngwcell==-1 ) CALL read_error(6, 'ngwcell')

!      Nratetbl = getdim('nratetbl')
!      IF ( Nratetbl==-1 ) CALL read_error(6, 'nratetbl')
      Nratetbl = 0

      Ndscn = getdim('ndscn')                                                                                ! mm begin
      IF ( Ndscn==-1 ) CALL read_error(7, 'ndscn')

      Ninfstor = getdim('ninfstor')
      IF ( Ninfstor==-1 ) CALL read_error(7, 'ninfstor')

      IF ( Model/=0 ) THEN
        IF ( Ndscn==0 ) Ndscn = 1
        IF ( Ninfstor==0 ) Ninfstor = 1
      ENDIF                                                                                ! mm end

      Stream_order_flag = 0
      IF ( Nsegment>0 .AND. Strmflow_flag>1 .AND. Model/=0 ) THEN
        Stream_order_flag = 1 ! strmflow_in_out or muskingum
      ENDIF

      IF ( Nsegment<1 .AND. Model/=99 ) THEN
        IF ( Stream_order_flag==1 .OR. Call_cascade==1 ) THEN
          PRINT *, 'ERROR, streamflow and cascade routing require nsegment > 0, specified as:', Nsegment
          STOP
        ENDIF
      ENDIF

      Lake_route_flag = 0
      IF ( Nlake>0 .AND. Strmflow_flag==3 .AND. Model/=0 ) Lake_route_flag = 1 ! muskingum_lake

      IF ( NsubOutON_OFF==1 .AND. Nsub==0 ) THEN
        NsubOutON_OFF = 0
        PRINT *, 'nsubOutON_OFF = 1 and nsub = 0, thus nsub_summary not used'
      ENDIF

      IF ( Model==99 .OR. Parameter_check_flag>0 ) CALL check_dimens()

      check_dims = Inputerror_flag
      END FUNCTION check_dims

!***********************************************************************
!     Check consistency of dimensions with flags
!***********************************************************************
      SUBROUTINE check_dimens()
      USE PRMS_MODULE
      IMPLICIT NONE
! Local Variables
      INTEGER :: ierr
!***********************************************************************
      ierr = 0
      IF ( Nhru==0 .OR. Nssr==0 .OR. Ngw==0 ) THEN
        PRINT *, 'ERROR, nhru, nssr, and ngw must be > 0: nhru=', Nhru, ', nssr=', Nssr, ', ngw=', Ngw
        ierr = 1
      ELSEIF ( Nssr/=Nhru .OR. Ngw/=Nhru ) THEN
        PRINT *, 'ERROR, nhru, nssr, and ngw must equal: nhru=', Nhru, ', nssr=', Nssr, ', ngw=', Ngw
        ierr = 1
      ENDIF
      IF ( Ndepl==0 ) THEN
        PRINT *, 'ERROR, ndepl must be > 0: ndepl=', Ndepl
        ierr = 1
      ENDIF
      IF ( Ndeplval/=Ndepl*11 ) THEN
        PRINT *, 'ERROR, ndeplval must be = ndepl*11: ndeplval:', Ndeplval, ', ndepl=', Ndepl
        ierr = 1
      ENDIF

      IF ( ierr==1 ) STOP

      IF ( Model==99 ) THEN
        IF ( Ntemp==0 ) Ntemp = 1
        IF ( Nrain==0 ) Nrain = 1
        IF ( Nlake==0 ) Nlake = 1
        IF ( Nlake_hrus==0 ) Nlake_hrus = 1
        IF ( Nsol==0 ) Nsol = 1
        IF ( Nobs==0 ) Nobs = 1
        IF ( Ncascade==0 ) Ncascade = 1
        IF ( Ncascdgw==0 ) Ncascdgw = 1
        IF ( Nsub==0 ) Nsub = 1
        IF ( Nevap==0 ) Nevap = 1
        IF ( Nhrucell==0 ) Nhrucell = 1
        IF ( Ngwcell==0 ) Ngwcell = 1
        IF ( Nsegment==0 ) Nsegment = 1
!        IF ( Nratetbl==0 ) Nratetbl = 4
        Subbasin_flag = 1
        Cascade_flag = 1
        Cascadegw_flag = 1
        Call_cascade = 1
        Stream_order_flag = 1
        Climate_hru_flag = 1
        Lake_route_flag = 1
      ENDIF

      END SUBROUTINE check_dimens

!**********************************************************************
!     Module documentation
!**********************************************************************
      SUBROUTINE module_doc()
      IMPLICIT NONE
! Functions
      INTEGER, EXTERNAL :: basin, climateflow, prms_time
      INTEGER, EXTERNAL :: cascade, obs, soltab, transp_tindex
      INTEGER, EXTERNAL :: transp_frost, frost_date, routing
      INTEGER, EXTERNAL :: temp_1sta_laps, temp_dist2
      INTEGER, EXTERNAL :: precip_1sta_laps, climate_hru
      INTEGER, EXTERNAL :: precip_dist2, xyz_dist, ide_dist
      INTEGER, EXTERNAL :: ddsolrad, ccsolrad
      INTEGER, EXTERNAL :: potet_pan, potet_jh, potet_hamon, potet_hs, potet_pt, potet_pm
      INTEGER, EXTERNAL :: intcp, snowcomp, gwflow, srunoff, soilzone
      INTEGER, EXTERNAL :: strmflow, subbasin, basin_sum, map_results, strmflow_in_out
      INTEGER, EXTERNAL :: write_climate_hru, muskingum, potet_pm_sta
      INTEGER, EXTERNAL :: gsflow_prms2mf, gsflow_mf2prms, gsflow_budget, gsflow_sum
      EXTERNAL :: nhru_summary, water_balance, nsub_summary, basin_summary, nsegment_summary
! Local variable
      INTEGER :: test
!**********************************************************************
      test = basin()
      test = cascade()
      test = climateflow()
      test = soltab()
      test = prms_time()
      test = obs()
      test = temp_1sta_laps()
      test = temp_dist2()
      test = xyz_dist()
      test = ide_dist()
      test = climate_hru()
      test = precip_1sta_laps()
      test = precip_dist2()
      test = ddsolrad()
      test = ccsolrad()
      test = transp_tindex()
      test = frost_date()
      test = transp_frost()
      test = potet_jh()
      test = potet_hamon()
      test = potet_pan()
      test = potet_hs()
      test = potet_pt()
      test = potet_pm()
      test = potet_pm_sta()
      test = write_climate_hru()
      test = intcp()
      test = snowcomp()
      test = srunoff()
      test = soilzone()
      test = gsflow_prms2mf()
      test = gsflow_mf2prms()
      test = gsflow_budget()
      test = gsflow_sum()
      test = gwflow()
      test = routing()
      test = strmflow()
      test = strmflow_in_out()
      test = muskingum()
      test = basin_sum()
      test = map_results()
      CALL nhru_summary()
      CALL nsub_summary()
      CALL basin_summary()
      CALL nsegment_summary()
      CALL water_balance()
      test = subbasin()

      PRINT 9001
 9001 FORMAT (//, ' All available modules have been called.', /, &
     &        ' All parameters have been declared.', /, &
     &        ' Note, no simulation was computed.', /)

      END SUBROUTINE module_doc

!***********************************************************************
!     check module names
!***********************************************************************
      SUBROUTINE check_module_names()
      USE PRMS_MODULE, ONLY: Temp_module, Precip_module, Et_module, Solrad_module, &
     &    Transp_module, Srunoff_module, Strmflow_module
      IMPLICIT NONE
! Local Variables
      INTEGER :: ierr
!***********************************************************************
      ierr = 0
      IF ( Temp_module(:14)=='temp_1sta_prms' ) THEN
        PRINT *, 'WARNING, deprecated temp_module value, change temp_1sta_prms to temp_1sta'
        Temp_module = 'temp_1sta'
      ELSEIF ( Temp_module(:14)=='temp_laps_prms' ) THEN
        PRINT *, 'WARNING, deprecated temp_module value, change temp_laps_prms to temp_laps'
        Temp_module = 'temp_laps'
      ELSEIF ( Temp_module(:15)=='temp_dist2_prms' ) THEN
        PRINT *, 'WARNING, deprecated temp_module value, change temp_dist2_prms to temp_dist2'
        Temp_module = 'temp_dist2'
      ELSEIF ( Temp_module(:9)=='temp_2sta' ) THEN
        PRINT *, 'ERROR, module temp_2sta_prms not available, use a different temp_module'
        ierr = 1
      ENDIF

      IF ( Precip_module(:11)=='precip_prms' ) THEN
        PRINT *, 'WARNING, deprecated precip_module value, change precip_prms to precip_1sta'
        Precip_module = 'precip_1sta'
      ELSEIF ( Precip_module(:16)=='precip_laps_prms' ) THEN
        PRINT *, 'WARNING, deprecated precip_module value, change precip_laps_prms to precip_laps'
        Precip_module = 'precip_laps'
      ELSEIF ( Precip_module(:17)=='precip_dist2_prms' ) THEN
        PRINT *, 'WARNING, deprecated precip_module value, change precip_dist2_prms to precip_dist2'
        Precip_module = 'precip_dist2'
      ENDIF

      IF ( Temp_module(:8)=='ide_dist' .AND. Precip_module(:8)/='ide_dist') THEN
        PRINT '(/,A,/,2A)', 'ERROR, if ide_dist is specified for temp_module,', &
     &        'it also must be specified for precip_module: ', Precip_module
        ierr = 1
      ELSEIF ( Precip_module(:8)=='ide_dist' .AND. Temp_module(:8)/='ide_dist') THEN
        PRINT '(/,A,/,2A)', 'ERROR, if ide_dist is specified for precip_module,', &
     &        'it also must be specified for temp_module: ', Temp_module
        ierr = 1
      ELSEIF ( Temp_module(:8)=='xyz_dist' .AND. Precip_module(:8)/='xyz_dist') THEN
        PRINT '(/,A,/,2A)', 'ERROR, if xyz_dist is specified for temp_module,', &
     &        'it also must be specified for precip_module: ', Precip_module
        ierr = 1
      ELSEIF ( Precip_module(:8)=='xyz_dist' .AND. Temp_module(:8)/='xyz_dist') THEN
        PRINT '(/,A,/,2A)', 'ERROR, if xyz_dist is specified for precip_module,', &
     &        'it also must be specified for temp_module: ', Temp_module
        ierr = 1
      ENDIF

      IF ( Transp_module(:18)=='transp_tindex_prms' ) THEN
        PRINT *, 'WARNING, deprecated transp_module value, change transp_tindex_prms to transp_tindex'
        Transp_module = 'transp_tindex'
      ENDIF

      IF ( Et_module(:13)=='potet_jh_prms' ) THEN
        PRINT *, 'WARNING, deprecated et_module value, change potet_jh_prms to potet_jh'
        Et_module = 'potet_jh'
      ELSEIF ( Et_module(:14)=='potet_pan_prms' ) THEN
        PRINT *, 'WARNING, deprecated et_module value, change potet_pan_prms to potet_pan'
        Et_module = 'potet_pan'
      ELSEIF ( Et_module(:15)=='potet_epan_prms' ) THEN
        PRINT *, 'ERROR, deprecated et_module value, change potet_epan_prms to potet_pan'
        ierr = 1
      ELSEIF ( Et_module(:20)=='potet_hamon_hru_prms' ) THEN
        PRINT *, 'WARNING, deprecated et_module value, change potet_hamon_hru_prms to potet_hamon_hru'
        Et_module = 'potet_hamon'
      ELSEIF ( Et_module(:16)=='potet_hamon_prms' ) THEN
        PRINT *, 'WARNING, deprecated et_module value, change potet_hamon_prms to potet_hamon'
        Et_module = 'potet_hamon'
      ENDIF

      IF ( Solrad_module(:17)=='ddsolrad_hru_prms' ) THEN
        PRINT *, 'WARNING, deprecated solrad_module value, change ddsolrad_hru_prms to ddsolrad'
        solrad_module = 'ddsolrad'
      ELSEIF ( Solrad_module(:17)=='ccsolrad_hru_prms' ) THEN
        PRINT *, 'WARNING, deprecated solrad_module value, change ccsolrad_hru_prms to ccsolrad'
        solrad_module = 'ccsolrad'
      ELSEIF ( Solrad_module(:13)=='ddsolrad_prms' ) THEN
        PRINT *, 'WARNING, deprecated solrad_module value, change ddsolrad_prms to ddsolrad'
        solrad_module = 'ddsolrad'
      ELSEIF ( Solrad_module(:13)=='ccsolrad_prms' ) THEN
        PRINT *, 'WARNING, deprecated solrad_module value, change ccsolrad_prms to ccsolrad'
        solrad_module = 'ccsolrad'
      ENDIF

      IF ( Srunoff_module(:18)=='srunoff_carea_prms' ) THEN
        PRINT *, 'WARNING, deprecated srunoff_module value, change srunoff_carea_prms to srunoff_carea'
        srunoff_module = 'srunoff_carea'
      ELSEIF ( Srunoff_module(:18)=='srunoff_smidx_prms' ) THEN
        PRINT *, 'WARNING, deprecated srunoff_module value, change srunoff_smidx_prms to srunoff_smidx'
        srunoff_module = 'srunoff_smidx'
      ENDIF

      IF ( Strmflow_module(:13)=='strmflow_prms' ) THEN
        PRINT *, 'WARNING, deprecated strmflow_module value, change strmflow_prms to strmflow'
        strmflow_module = 'strmflow'
      ELSEIF ( Strmflow_module(:13)=='strmflow_lake' ) THEN
        PRINT *, 'ERROR, module strmflow_lake not available, use a different strmflow_module'
        ierr = 1
      ENDIF
      IF ( ierr==1 ) STOP
      END SUBROUTINE check_module_names

!***********************************************************************
!     call_modules_restart - write or read restart file
!***********************************************************************
      SUBROUTINE call_modules_restart(In_out)
      USE PRMS_MODULE
      IMPLICIT NONE
      ! Argument
      INTEGER, INTENT(IN) :: In_out
      EXTERNAL check_restart, check_restart_dimen
      ! Functions
      INTRINSIC TRIM
      ! Local Variables
      INTEGER :: nhru_test, dprst_test, nsegment_test, temp_test, et_test, ierr
      INTEGER :: cascade_test, cascdgw_test, nhrucell_test, nlake_test
      CHARACTER(LEN=MAXCONTROL_LENGTH) :: model_test
      CHARACTER(LEN=11) :: module_name
!***********************************************************************
      IF ( In_out==0 ) THEN
        WRITE ( Restart_outunit ) MODNAME
        WRITE ( Restart_outunit ) Timestep, Nhru, Dprst_flag, Nsegment, Temp_flag, Et_flag, &
     &          Cascade_flag, Cascadegw_flag, Nhrucell, Nlake, Model_mode
      ELSE
        ierr = 0
        READ ( Restart_inunit ) module_name
        CALL check_restart(MODNAME, module_name)
        READ ( Restart_inunit ) Timestep, nhru_test, dprst_test, nsegment_test, temp_test, et_test, &
     &         cascade_test, cascdgw_test, nhrucell_test, nlake_test, model_test
        IF ( TRIM(Model_mode)/=TRIM(model_test) ) THEN
          PRINT *, 'ERROR, Initial Conditions File saved for model_mode=', model_test
          PRINT *, '       Current model has model_mode=', Model_mode, ' they must be equal'
          ierr = 1
        ENDIF
        CALL check_restart_dimen('nhru', nhru_test, Nhru, ierr)
        CALL check_restart_dimen('nhrucell', nhrucell_test, Nhrucell, ierr)
        CALL check_restart_dimen('nlake', nlake_test, Nlake, ierr)
        IF ( Dprst_flag/=dprst_test ) THEN
          PRINT *, 'ERROR, Initial Conditions File saved for model with dprst_flag=', dprst_test
          PRINT *, '       Current model has dprst_flag=', Dprst_flag, ' they must be equal'
          ierr = 1
        ENDIF
        IF ( Cascade_flag/=cascade_test ) THEN
          PRINT *, 'ERROR, Initial Conditions File saved for model with cascade_flag=', cascade_test
          PRINT *, '       Current model has cascade_flag=', Cascade_flag, ' they must be equal'
          ierr = 1
        ENDIF
        IF ( Cascadegw_flag/=cascdgw_test ) THEN
          PRINT *, 'ERROR, Initial Conditions File saved for model with cascadegw_flag=', cascdgw_test
          PRINT *, '       Current model has cascadegw_flag=', Cascadegw_flag, ' they must be equal'
          ierr = 1
        ENDIF
        CALL check_restart_dimen('nsegment', nsegment_test, Nsegment, ierr)
        IF ( Temp_flag/=temp_test ) THEN
          PRINT *, 'ERROR, Initial Conditions File saved for model with different temperature'
          PRINT *, '       module than current model, they must use the same module'
          ierr = 1
        ENDIF
        IF ( Et_flag/=et_test ) THEN
          IF ( Et_flag==4 ) THEN
            PRINT *, 'ERROR, Initial Conditions File saved for model using potet_pan module'
            PRINT *, '       current model also must use potet_pan'
            ierr = 1
          ELSEIF ( Et_flag==6 ) THEN
            PRINT *, 'ERROR, Initial Conditions File saved for model using potet_pm_sta module'
            PRINT *, '       current model also must use potet_pm_sta'
            ierr = 1
          ELSEIF ( Et_flag==5 ) THEN
            PRINT *, 'ERROR, Initial Conditions File saved for model using potet_pt module'
            PRINT *, '       current model also must use potet_pt'
            ierr = 1
          ELSEIF ( Et_flag==11 ) THEN
            PRINT *, 'ERROR, Initial Conditions File saved for model using potet_pm module'
            PRINT *, '       current model also must use potet_pm'
            ierr = 1
          ENDIF
        ENDIF
        IF ( ierr==1 ) STOP
      ENDIF
      END SUBROUTINE call_modules_restart


      subroutine partffordepth(ntau,temp,molname,fpartition)
*
      implicit none
      integer j,ntau,k,molindex,maxim
      parameter (maxim=1000)
      real temp(ntau),exponent(maxim),g0(100),g1(100),g2(100),g3(100),
     &          fpartition(ntau)
      doubleprecision qcoeff(10,maxim),qc(10),qq,logt
      doubleprecision dpartf,dtemp
      character mol(maxim)*20,molname*20
      logical switer,found(maxim),Ames,first,scan2001,oldscan,Barber
      integer nelem(5,maxim),natom(5,maxim),mmax(maxim),nimax,
     &        nelemx(100),
     &        nmetal,nmol,idumb,nqcoeff(maxim),nq
* may become dbleprec
      doubleprecision ip(100),kp(100),uiidui(100),eps,fp(100),
     &     ppmol(maxim),apm(maxim),c(maxim,5),ccomp(100),p(100),
     &     ipp(100),ippp(100),d00(maxim),qmol(maxim),
     &     dissoc,reducedmass15(maxim),ndensity,molweight,d00hm
      character*20     molcode(maxim)
       character*2 elem(100)
       common/comfh1/c,nelem,natom,mmax,ppmol,d00,qmol,apm,mol,ip,
     &            ipp,ippp,g0,g1,g2,g3,ccomp,exponent,reducedmass15,
     &            uiidui,p,fp,kp,eps,nelemx,nimax,nmetal,nmol,switer,
     &            molcode,elem
       common/h2ochoice/Ames,scan2001,oldscan,Barber
       data first/.true./

      if (molname.eq.'H O H               ') then
        if (Ames) then
          print*,'partffordepth: using Ames partf.'
          do k=1,ntau
            dtemp=temp(k)
            call partfAmesH2O(dtemp,dpartf)
            fpartition(k)=dpartf
          enddo
        else if (scan2001) then
          print*,'Using SCAN 2001 partition function for H2O'
          call h2opartf2001(ntau,temp,fpartition)
        else if (oldscan) then
          print*,'partffordepth: using uffe partf.'
          call h2opartf(ntau,temp,fpartition)
        else if (Barber) then
          do k=1,ntau
            dtemp=temp(k)
            call partfBarberH2O(dtemp,dpartf)
            fpartition(k)=dpartf
          enddo
        else
          print*,'No partition function for the H2O line list!'
          stop
        endif
*
        return
*
      endif

* One call to molecpartf to initiate arrays (some molecules sorted out).
      if (first) then
        call molecpartf(temp(1),found)
        first=.false.
      endif

      do j=1,nmol
        if (molname.eq.mol(j)) then
          molindex=j
          goto 1
        endif
      enddo
1     continue

      do k=1,ntau
        call molecpartf(temp(k),found)
        if (.not.found(molindex)) stop
     &            'partffordepth: molecule not found'
        fpartition(k)=qmol(molindex)
      enddo

      return
      end