C $Header: /u/gcmpack/MITgcm/pkg/exf/exf_getffieldrec.F,v 1.29 2017/02/21 01:04:26 jmc Exp $
C $Name:  $

#include "EXF_OPTIONS.h"

CBOP
C     !ROUTINE: EXF_GetFFieldRec
C     !INTERFACE:
      SUBROUTINE EXF_GETFFIELDREC(
     I               fldStartTime, fldPeriod, fldRepeatCycle,
     I               fldName, usefldyearlyfields,
     O               fac, first, changed,
     O               count0, count1, year0, year1,
     I               myTime, myIter, myThid )

C     !DESCRIPTION: \bv
C     *==========================================================*
C     | SUBROUTINE EXF_GetFFieldRec
C     | o Get flags, counters, and the linear interpolation
C     |   factor for a given field.
C     *==========================================================*
C     \ev

C     !USES:
      IMPLICIT NONE

C     == Global variables ==
#include "SIZE.h"
#include "EEPARAMS.h"
#include "PARAMS.h"
#include "EXF_PARAM.h"
#ifdef ALLOW_CAL
# include "cal.h"
#endif

C     !INPUT PARAMETERS:
C     fldStartTime       :: time in seconds of first fld record from the
C                           beginning of the model integration or, if
C                           usefldyearlyfields, from the beginning of year
C     fldPeriod          :: period between forcing field records
C     fldRepeatCycle     :: time duration of a repeating cycle
C     fldName            :: field short name (to print mesg)
C     usefldyearlyfields :: when set, use yearly forcing files
C     myTime             :: current time in simulation
C     myIter             :: current iteration number in simulation
C     myThid             :: my thread identification number
      _RL     fldStartTime, fldPeriod, fldRepeatCycle
      CHARACTER*(*) fldName
      LOGICAL usefldyearlyfields
      _RL     myTime
      INTEGER myIter, myThid

C     !OUTPUT PARAMETERS:
C     fac     :: weight of record count0 for linear interpolation purposes
C     first   :: model initialization flag: read two forcing records
C     changed :: flag indicating that a new forcing record must be read
C     count0  :: record number for forcing field preceding myTime
C     count1  :: record number for forcing field following myTime
C     year0   :: year of forcing file for record preceding myTime
C     year1   :: year of forcing file for record following myTime
      _RL     fac
      LOGICAL first, changed
      INTEGER count0, count1, year0, year1

C     !FUNCTIONS:
#ifdef ALLOW_CAL
      INTEGER  cal_IsLeap
      EXTERNAL 
#endif

C     !LOCAL VARIABLES:
C     mydate        :: model date of current time step
C     yearStartDate :: start of year date for flux record just before mydate
C     difftime      :: time difference between yearStartDate and mydate
C     fldsectot     :: time in seconds from fldStartTime to mydate
C     fldsecs       :: time from start of current forcing period to mydate
C     fldsecs0      :: time from start of repeat period to mydate
C     fldsecs1      :: time from end of current forcing period to mydate
C     secondsInYear :: seconds in the flux year just before mydate
C     myDateSeconds :: seconds from beginning of year to mydate
#ifdef ALLOW_CAL
      INTEGER mydate(4)
      INTEGER yearStartDate(4)
      INTEGER difftime(4)
      _RL fldsectot, fldsecs, fldsecs0, fldsecs1
      _RL secondsInYear, myDateSeconds
#endif
       INTEGER intimeP, intime0, intime1
       _RL locTime, aWght, bWght
      CHARACTER*(MAX_LEN_MBUF) msgBuf
CEOP

#ifdef ALLOW_CAL
      IF ( useCAL ) THEN

C     Set some default values.
       first = ((myTime - modelstart) .lt. 0.5*modelstep)
       changed = .FALSE.

       if ( fldPeriod .eq. 0. _d 0 ) then
C     Read field only once in the beginning. Hack: count1=count0 causes
C     the model to read the first record twice, but since this this is
C     done only the first time around it is not too much of an overhead.
        first   = ((myTime - modelstart) .lt. 0.5*modelstep)
        changed = .FALSE.
        fac     = 1. _d 0
        count0  = 1
        count1  = count0
C     Give these variables some unproblematic values although they are
C     never used in this context.
        year0   = 0
        year1   = year0
       else
C       fldPeriod .ne. 0
        if (.not.usefldyearlyfields) then

C     Determine offset in seconds from beginning of input data
C     to current date.
         fldsectot = myTime - fldStartTime

C     Determine the flux records just before and after mycurrentdate.
         if ( fldRepeatCycle .eq. 0. _d 0 ) then

          if ( fldsectot .lt. 0. _d 0 ) then
           WRITE(msgBuf,'(4A,1P1E17.10,A)') 'EXF_GetFFieldRec ',
     &       'for field "', fldName, '": myTime=', myTime, ' earlier'
           CALL PRINT_ERROR( msgBuf, myThid )
           WRITE(msgBuf,'(2A,1P1E18.10,A)') 'EXF_GetFFieldRec: ',
     &       'than 1rst reccord (field-startdate=', fldStartTime, ')'
           CALL PRINT_ERROR( msgBuf, myThid )
           STOP 'ABNORMAL END: S/R EXF_GetFFieldRec'
          endif
          count0       = INT((fldsectot+0.5)/fldPeriod) + 1
          count1       = count0 + 1
          fldsecs      = MOD(fldsectot,fldPeriod)

         else
C        if ( fldRepeatCycle .gt. 0. )

C     If using repeating data then make fldsectot cycle around.
          if (fldsectot.lt.0. _d 0)
     &        fldsectot = fldsectot + fldRepeatCycle
          fldsecs0     = MOD(fldsectot,fldRepeatCycle)
          count0       = INT((fldsecs0+0.5)/fldPeriod) + 1
          fldsecs1     = MOD(fldsectot+fldPeriod,fldRepeatCycle)
          count1       = INT((fldsecs1+0.5)/fldPeriod) + 1
          fldsecs      = MOD(fldsecs0,fldPeriod)

         endif

C     Weight belonging to count0 for linear interpolation purposes.
         fac = 1. - fldsecs/fldPeriod

        else
C       if (usefldyearlyfields)

C     Determine seconds from beginning of year to model current time.
         CALL CAL_GETDATE( myIter, myTime, mydate, myThid )
         year0            = INT(mydate(1)/10000.)
         yearStartDate(1) = year0 * 10000 + 101
         yearStartDate(2) = 0
         yearStartDate(3) = mydate(3)
         yearStartDate(4) = mydate(4)
         CALL CAL_TIMEPASSED(yearStartDate,mydate,difftime,myThid)
         CALL CAL_TOSECONDS (difftime,myDateSeconds,myThid)

C     Determine the flux year just before mycurrentdate.
         if ( myDateSeconds .lt. fldStartTime ) year0 = year0 - 1

C     Determine seconds in the flux year just before mycurrentdate.
         secondsInYear = ndaysnoleap * secondsperday
         if ( cal_IsLeap(year0,myThid) .eq. 2)
     &       secondsInYear = ndaysleap * secondsperday

C     Determine the record just before mycurrentdate.
         if ( myDateSeconds .lt. fldStartTime )
     &       myDateSeconds = myDateSeconds + secondsInYear
         fldsectot = myDateSeconds - fldStartTime
         count0    = INT((fldsectot+0.5)/fldPeriod) + 1

C     Determine the flux year and record just after mycurrentdate.
         year1  = year0
         count1 = count0 + 1
         if ( (fldStartTime+count0*fldPeriod) .ge. secondsInYear ) then
          year1  = year0 + 1
          count1 = 1
         endif

C     Weight belonging to count0 for linear interpolation purposes.
         fldsecs = MOD(fldsectot,fldPeriod)
         fac     = 1. - fldsecs/fldPeriod
         if ( year0 .ne. year1 )
     &       fac = 1. - fldsecs/(secondsInYear-(count0-1)*fldPeriod)

       endif
C      if (usefldyearlyfields)

C     Set switch for reading new record.
       if ( fldsecs - modelstep .lt. 0. _d 0 ) changed = .TRUE.

       endif
C      if (fldPeriod .eq. 0.)

      ELSE
#else /* ALLOW_CAL */
      IF ( .TRUE. ) THEN
#endif /* ALLOW_CAL */

       year0 = 0
       year1 = 0

       IF ( fldPeriod .EQ. 0. _d 0 ) THEN
        fac     = 1. _d 0
        first   = ( myIter.EQ.nIter0 )
        changed = .FALSE.
C     Read field only once in the beginning. Hack: count1=count0 causes
C     the model to read the first record twice, but since this this is
C     done only the first time around it is not too much of an overhead.
        count0  = 1
        count1  = 1

       ELSE
        locTime = myTime - fldStartTime + fldPeriod*halfRL
        CALL GET_PERIODIC_INTERVAL(
     O                  intimeP, intime0, intime1, bWght, aWght,
     I                  fldRepeatCycle, fldPeriod,
     I                  deltaTClock, locTime, myThid )

C      Fld @ t = bWght*Fld(intime0) + aWght*Fld(intime1)
        fac     =  bWght
        first   = ( myIter .EQ.nIter0 )
        changed = ( intime0.NE.intimeP )
        count0  = intime0
        count1  = intime1

        IF ( intime0 .LE. 0 ) THEN
           WRITE(msgBuf,'(3A,I10,A,1P1E17.10)')
     &       'EXF_GetFFieldRec: for field "', fldName,
     &       '" @ Iter=', myIter, ' , myTime=', myTime
           CALL PRINT_MESSAGE( msgBuf, errorMessageUnit,
     &                         SQUEEZE_RIGHT, myThid )
           WRITE(msgBuf,'(2(A,1P1E18.10))')
     &       'EXF_GetFFieldRec:  fldRepeatCycle=', fldRepeatCycle,
     &                            ' , fldPeriod=', fldPeriod
           CALL PRINT_MESSAGE( msgBuf, errorMessageUnit,
     &                         SQUEEZE_RIGHT, myThid )
           WRITE(msgBuf,'(3(A,I8))') 'EXF_GetFFieldRec:  intimeP=',
     &       intimeP, ', intime0=', intime0, ', intime1=', intime1
           CALL PRINT_MESSAGE( msgBuf, errorMessageUnit,
     &                         SQUEEZE_RIGHT, myThid )
           WRITE(msgBuf,'(2(A,1P1E14.7),A,1P1E16.9)')
     &      'EXF_GetFFieldRec:  bWght,aWght=', bWght, ',', aWght,
     &      ' @ locTime=', locTime
           CALL PRINT_MESSAGE( msgBuf, errorMessageUnit,
     &                         SQUEEZE_RIGHT, myThid )
           WRITE(msgBuf,'(2A)') 'EXF_GetFFieldRec: ',
     &        'Reccord number "intime0" not valid ; possible cause:'
           CALL PRINT_ERROR( msgBuf, myThid )
           WRITE(msgBuf,'(2A,1P2E18.10)') 'EXF_GetFFieldRec: ',
     &        ' myTime earlier than field-StartTime=', fldStartTime
           CALL PRINT_ERROR( msgBuf, myThid )
           STOP 'ABNORMAL END: S/R EXF_GetFFieldRec'
        ENDIF

C-     end if fldPeriod=0
       ENDIF

C--   end if/else useCAL
      ENDIF

      RETURN
      END