#include <ESMF_TimeMgr.inc> #include <ESMF.inc> ! Factor so abs(Sn) < Sd and ensure that signs of S and Sn match. ! Also, enforce consistency. ! YR and MM fields are ignored. SUBROUTINE normalize_basetime( basetime ) 4,4 USE ESMF_BaseMod USE ESMF_BaseTimeMod IMPLICIT NONE TYPE(ESMF_BaseTime), INTENT(INOUT) :: basetime !PRINT *,'DEBUG: BEGIN normalize_basetime()' ! Consistency check... IF ( basetime%Sd < 0 ) THEN CALL wrf_error_fatal( & 'normalize_basetime: denominator of seconds cannot be negative' ) ENDIF IF ( ( basetime%Sd == 0 ) .AND. ( basetime%Sn .NE. 0 ) ) THEN CALL wrf_error_fatal( & 'normalize_basetime: denominator of seconds cannot be zero when numerator is non-zero' ) ENDIF ! factor so abs(Sn) < Sd IF ( basetime%Sd > 0 ) THEN IF ( ABS( basetime%Sn ) .GE. basetime%Sd ) THEN !PRINT *,'DEBUG: normalize_basetime() A1: S,Sn,Sd = ',basetime%S,basetime%Sn,basetime%Sd basetime%S = basetime%S + ( basetime%Sn / basetime%Sd ) basetime%Sn = mod( basetime%Sn, basetime%Sd ) !PRINT *,'DEBUG: normalize_basetime() A2: S,Sn,Sd = ',basetime%S,basetime%Sn,basetime%Sd ENDIF ! change sign of Sn if it does not match S IF ( ( basetime%S > 0 ) .AND. ( basetime%Sn < 0 ) ) THEN !PRINT *,'DEBUG: normalize_basetime() B1: S,Sn,Sd = ',basetime%S,basetime%Sn,basetime%Sd basetime%S = basetime%S - 1_ESMF_KIND_I8 basetime%Sn = basetime%Sn + basetime%Sd !PRINT *,'DEBUG: normalize_basetime() B2: S,Sn,Sd = ',basetime%S,basetime%Sn,basetime%Sd ENDIF IF ( ( basetime%S < 0 ) .AND. ( basetime%Sn > 0 ) ) THEN !PRINT *,'DEBUG: normalize_basetime() C1: S,Sn,Sd = ',basetime%S,basetime%Sn,basetime%Sd basetime%S = basetime%S + 1_ESMF_KIND_I8 basetime%Sn = basetime%Sn - basetime%Sd !PRINT *,'DEBUG: normalize_basetime() C2: S,Sn,Sd = ',basetime%S,basetime%Sn,basetime%Sd ENDIF ENDIF !PRINT *,'DEBUG: END normalize_basetime()' END SUBROUTINE normalize_basetime ! A normalized time has time%basetime >= 0, time%basetime less than the current ! year expressed as a timeInterval, and time%YR can take any value SUBROUTINE normalize_time( time ) 2,6 USE ESMF_BaseMod USE ESMF_BaseTimeMod USE ESMF_TimeMod IMPLICIT NONE TYPE(ESMF_Time), INTENT(INOUT) :: time INTEGER(ESMF_KIND_I8) :: nsecondsinyear ! locals TYPE(ESMF_BaseTime) :: cmptime, zerotime INTEGER :: rc LOGICAL :: done ! first, normalize basetime ! this will force abs(Sn) < Sd and ensure that signs of S and Sn match CALL normalize_basetime( time%basetime ) !$$$ add tests for these edge cases ! next, underflow negative seconds into YEARS ! time%basetime must end up non-negative !$$$ push this down into ESMF_BaseTime constructor zerotime%S = 0 zerotime%Sn = 0 zerotime%Sd = 0 DO WHILE ( time%basetime < zerotime ) time%YR = time%YR - 1 !$$$ push this down into ESMF_BaseTime constructor cmptime%S = nsecondsinyear( time%YR ) cmptime%Sn = 0 cmptime%Sd = 0 time%basetime = time%basetime + cmptime ENDDO ! next, overflow seconds into YEARS done = .FALSE. DO WHILE ( .NOT. done ) !$$$ push this down into ESMF_BaseTime constructor cmptime%S = nsecondsinyear( time%YR ) cmptime%Sn = 0 cmptime%Sd = 0 IF ( time%basetime >= cmptime ) THEN time%basetime = time%basetime - cmptime time%YR = time%YR + 1 ELSE done = .TRUE. ENDIF ENDDO END SUBROUTINE normalize_time SUBROUTINE normalize_timeint( timeInt ) 6,6 USE ESMF_BaseTimeMod USE ESMF_TimeIntervalMod USE ESMF_CalendarMod USE ESMF_BaseMod IMPLICIT NONE TYPE(ESMF_TimeInterval), INTENT(INOUT) :: timeInt INTEGER :: nfeb ! normalize basetime ! this will force abs(Sn) < Sd and ensure that signs of S and Sn match ! YR and MM are ignored CALL normalize_basetime( timeInt%basetime ) ! Rollover months to years IF ( abs(timeInt%MM) .GE. MONTHS_PER_YEAR ) THEN timeInt%YR = timeInt%YR + timeInt%MM/MONTHS_PER_YEAR timeInt%MM = mod(timeInt%MM,MONTHS_PER_YEAR) ENDIF ! For 365-day calendar, immediately convert years to days since we know ! how to do it in this case. !$$$ replace this hack with something saner... IF ( nfeb( 2004 ) == 28 ) THEN timeint%basetime%S = timeint%basetime%S + & ( 365_ESMF_KIND_I8 * & INT( timeint%YR, ESMF_KIND_I8 ) * SECONDS_PER_DAY ) timeint%YR = 0 ENDIF END SUBROUTINE normalize_timeint FUNCTION signnormtimeint ( timeInt ) 1,4 ! Compute the sign of a time interval. ! YR and MM fields are *IGNORED*. ! returns 1, 0, or -1 or exits if timeInt fields have inconsistent signs. USE ESMF_BaseMod USE ESMF_BaseTimeMod USE ESMF_TimeIntervalMod IMPLICIT NONE TYPE(ESMF_TimeInterval), INTENT(IN) :: timeInt INTEGER :: signnormtimeint LOGICAL :: positive, negative positive = .FALSE. negative = .FALSE. signnormtimeint = 0 ! Note that Sd is required to be non-negative. This is enforced in ! normalize_timeint(). ! Note that Sn is required to be zero when Sd is zero. This is enforced ! in normalize_timeint(). IF ( ( timeInt%basetime%S > 0 ) .OR. & ( timeInt%basetime%Sn > 0 ) ) THEN positive = .TRUE. ENDIF IF ( ( timeInt%basetime%S < 0 ) .OR. & ( timeInt%basetime%Sn < 0 ) ) THEN negative = .TRUE. ENDIF IF ( positive .AND. negative ) THEN CALL wrf_error_fatal( & 'signnormtimeint: signs of fields cannot be mixed' ) ELSE IF ( positive ) THEN signnormtimeint = 1 ELSE IF ( negative ) THEN signnormtimeint = -1 ENDIF END FUNCTION signnormtimeint ! added from share/module_date_time in WRF. FUNCTION nfeb ( year ) RESULT (num_days) 10 ! Compute the number of days in February for the given year IMPLICIT NONE INTEGER :: year INTEGER :: num_days #ifdef NO_LEAP_CALENDAR num_days = 28 ! By default, February has 28 days ... #else num_days = 28 ! By default, February has 28 days ... IF (MOD(year,4).eq.0) THEN num_days = 29 ! But every four years, it has 29 days ... IF (MOD(year,100).eq.0) THEN num_days = 28 ! Except every 100 years, when it has 28 days ... IF (MOD(year,400).eq.0) THEN num_days = 29 ! Except every 400 years, when it has 29 days. END IF END IF END IF #endif END FUNCTION nfeb FUNCTION ndaysinyear ( year ) RESULT (num_diy) 1,1 ! Compute the number of days in the given year IMPLICIT NONE INTEGER, INTENT(IN) :: year INTEGER :: num_diy INTEGER :: nfeb IF ( nfeb( year ) .EQ. 29 ) THEN num_diy = 366 ELSE num_diy = 365 ENDIF END FUNCTION ndaysinyear FUNCTION nsecondsinyear ( year ) RESULT (numseconds) 4,2 ! Compute the number of seconds in the given year USE ESMF_BaseMod IMPLICIT NONE INTEGER, INTENT(IN) :: year INTEGER(ESMF_KIND_I8) :: numseconds INTEGER :: ndaysinyear numseconds = SECONDS_PER_DAY * INT( ndaysinyear(year) , ESMF_KIND_I8 ) END FUNCTION nsecondsinyear SUBROUTINE initdaym 1,3 USE ESMF_BaseMod USE ESMF_BaseTimeMod USE ESMF_CalendarMod IMPLICIT NONE INTEGER i,j,m m = 1 mdaycum(0) = 0 !$$$ push this down into ESMF_BaseTime constructor monthbdys(0)%S = 0 monthbdys(0)%Sn = 0 monthbdys(0)%Sd = 0 DO i = 1,MONTHS_PER_YEAR DO j = 1,mday(i) daym(m) = i m = m + 1 ENDDO mdaycum(i) = mdaycum(i-1) + mday(i) !$$$ push this down into ESMF_BaseTime constructor monthbdys(i)%S = SECONDS_PER_DAY * INT( mdaycum(i), ESMF_KIND_I8 ) monthbdys(i)%Sn = 0 monthbdys(i)%Sd = 0 ENDDO ! End of month seconds, day before the beginning of next month DO i = 0,MONTHS_PER_YEAR j = i + 1 if ( i == MONTHS_PER_YEAR ) j = 0 monthedys(i) = monthbdys(j) monthedys(i)%S = monthedys(i)%S - SECONDS_PER_DAY ENDDO m = 1 mdayleapcum(0) = 0 !$$$ push this down into ESMF_BaseTime constructor monthbdysleap(0)%S = 0 monthbdysleap(0)%Sn = 0 monthbdysleap(0)%Sd = 0 DO i = 1,MONTHS_PER_YEAR DO j = 1,mdayleap(i) daymleap(m) = i m = m + 1 ENDDO mdayleapcum(i) = mdayleapcum(i-1) + mdayleap(i) !$$$ push this down into ESMF_BaseTime constructor monthbdysleap(i)%S = SECONDS_PER_DAY * INT( mdayleapcum(i), ESMF_KIND_I8 ) monthbdysleap(i)%Sn = 0 monthbdysleap(i)%Sd = 0 ENDDO ! End of month seconds, day before the beginning of next month DO i = 0,MONTHS_PER_YEAR j = i + 1 if ( i == MONTHS_PER_YEAR ) j = 0 monthedysleap(i) = monthbdysleap(j) monthedysleap(i)%S = monthedysleap(i)%S - SECONDS_PER_DAY ENDDO END SUBROUTINE initdaym !$$$ useful, but not used at the moment... SUBROUTINE compute_dayinyear(YR,MM,DD,dayinyear),2 use ESMF_CalendarMod IMPLICIT NONE INTEGER, INTENT(IN) :: YR,MM,DD ! DD is day of month INTEGER, INTENT(OUT) :: dayinyear INTEGER i integer nfeb dayinyear = 0 DO i = 1,MM-1 if (i.eq.2) then dayinyear = dayinyear + nfeb(YR) else dayinyear = dayinyear + mday(i) endif ENDDO dayinyear = dayinyear + DD END SUBROUTINE compute_dayinyear SUBROUTINE timegetmonth( time, MM ) 4,6 USE ESMF_BaseMod USE ESMF_BaseTimeMod USE ESMF_TimeMod USE ESMF_CalendarMod IMPLICIT NONE TYPE(ESMF_Time), INTENT(IN) :: time INTEGER, INTENT(OUT) :: MM ! locals INTEGER :: nfeb INTEGER :: i TYPE(ESMF_BaseTime), POINTER :: MMbdys(:) IF ( nfeb(time%YR) == 29 ) THEN MMbdys => monthbdysleap ELSE MMbdys => monthbdys ENDIF MM = -1 DO i = 1,MONTHS_PER_YEAR IF ( ( time%basetime >= MMbdys(i-1) ) .AND. ( time%basetime < MMbdys(i) ) ) THEN MM = i EXIT ENDIF ENDDO IF ( MM == -1 ) THEN CALL wrf_error_fatal( 'timegetmonth: could not extract month of year from time' ) ENDIF END SUBROUTINE timegetmonth !$$$ may need to change dependencies in Makefile... SUBROUTINE timegetdayofmonth( time, DD ) 2,6 USE ESMF_BaseMod USE ESMF_BaseTimeMod USE ESMF_TimeMod USE ESMF_CalendarMod IMPLICIT NONE TYPE(ESMF_Time), INTENT(IN) :: time INTEGER, INTENT(OUT) :: DD ! locals INTEGER :: nfeb INTEGER :: MM TYPE(ESMF_BaseTime), POINTER :: MMbdys(:) TYPE(ESMF_BaseTime) :: tmpbasetime !$$$ fix this so init just points MMbdys to the one we want for this calendar? IF ( nfeb(time%YR) == 29 ) THEN MMbdys => monthbdysleap ELSE MMbdys => monthbdys ENDIF CALL timegetmonth( time, MM ) tmpbasetime = time%basetime - MMbdys(MM-1) DD = ( tmpbasetime%S / SECONDS_PER_DAY ) + 1 END SUBROUTINE timegetdayofmonth ! Increment Time by number of seconds between start of year and start ! of month MM. ! 1 <= MM <= 12 ! Time is NOT normalized. SUBROUTINE timeaddmonths( time, MM, ierr ) 1,6 USE ESMF_BaseMod USE ESMF_BaseTimeMod USE ESMF_TimeMod USE ESMF_CalendarMod IMPLICIT NONE TYPE(ESMF_Time), INTENT(INOUT) :: time INTEGER, INTENT(IN) :: MM INTEGER, INTENT(OUT) :: ierr ! locals INTEGER :: nfeb TYPE(ESMF_BaseTime), POINTER :: MMbdys(:) ierr = ESMF_SUCCESS ! PRINT *,'DEBUG: BEGIN timeaddmonths()' IF ( ( MM < 1 ) .OR. ( MM > MONTHS_PER_YEAR ) ) THEN CALL wrf_message( 'ERROR timeaddmonths(): MM out of range' ) ierr = ESMF_FAILURE ENDIF ! PRINT *,'DEBUG: timeaddmonths(): MM = ',MM !$$$ fix this so init just points MMbdys to the one we want for this calendar? ! PRINT *,'DEBUG: timeaddmonths(): time%YR = ',time%YR ! PRINT *,'DEBUG: timeaddmonths(): time%basetime%S = ',time%basetime%S ! PRINT *,'DEBUG: timeaddmonths(): time%basetime%Sn = ',time%basetime%Sn ! PRINT *,'DEBUG: timeaddmonths(): time%basetime%Sd = ',time%basetime%Sd IF ( nfeb(time%YR) == 29 ) THEN ! PRINT *,'DEBUG: timeaddmonths(): leap year' MMbdys => monthbdysleap ELSE ! PRINT *,'DEBUG: timeaddmonths(): not leap year' MMbdys => monthbdys ENDIF ! PRINT *,'DEBUG: timeaddmonths(): done pointing to MMbdys' ! PRINT *,'DEBUG: timeaddmonths(): MMbdys(',MM-1,')%S = ',MMbdys(MM-1)%S ! PRINT *,'DEBUG: timeaddmonths(): MMbdys(',MM-1,')%Sn = ',MMbdys(MM-1)%Sn ! PRINT *,'DEBUG: timeaddmonths(): MMbdys(',MM-1,')%Sd = ',MMbdys(MM-1)%Sd !$$$ dumps core here... time%basetime = time%basetime + MMbdys(MM-1) ! PRINT *,'DEBUG: END timeaddmonths()' END SUBROUTINE timeaddmonths ! spaceship operator for Times SUBROUTINE timecmp(time1, time2, retval ) 6,4 USE ESMF_BaseMod USE ESMF_BaseTimeMod USE ESMF_TimeMod IMPLICIT NONE INTEGER, INTENT(OUT) :: retval ! ! !ARGUMENTS: TYPE(ESMF_Time), INTENT(IN) :: time1 TYPE(ESMF_Time), INTENT(IN) :: time2 IF ( time1%YR .GT. time2%YR ) THEN ; retval = 1 ; RETURN ; ENDIF IF ( time1%YR .LT. time2%YR ) THEN ; retval = -1 ; RETURN ; ENDIF CALL seccmp( time1%basetime%S, time1%basetime%Sn, time1%basetime%Sd, & time2%basetime%S, time2%basetime%Sn, time2%basetime%Sd, & retval ) END SUBROUTINE timecmp ! spaceship operator for TimeIntervals SUBROUTINE timeintcmp(timeint1, timeint2, retval ) 6,5 USE ESMF_BaseMod USE ESMF_BaseTimeMod USE ESMF_TimeIntervalMod IMPLICIT NONE INTEGER, INTENT(OUT) :: retval ! ! !ARGUMENTS: TYPE(ESMF_TimeInterval), INTENT(IN) :: timeint1 TYPE(ESMF_TimeInterval), INTENT(IN) :: timeint2 ! Compare seconds for interval CALL seccmp( timeint1%basetime%S, timeint1%basetime%Sn, & timeint1%basetime%Sd, & timeint2%basetime%S, timeint2%basetime%Sn, & timeint2%basetime%Sd, retval ) ! If intervals only have months IF ( (retval == 0) .AND. (timeint1%basetime%S == timeint2%basetime%S) .AND. & (timeint1%basetime%Sn == timeint2%basetime%Sn) .AND. & (timeint1%basetime%Sn == 0) .AND. & (timeint1%basetime%S == 0) .AND. & (timeint1%YR == timeint2%YR) .AND. & (timeint1%YR == 0) ) THEN IF ( timeint1%MM .GT. timeint2%MM )THEN retval = 1 ELSE IF ( timeint1%MM .LT. timeint2%MM )THEN retval = -1 ELSE IF ( timeint1%MM .EQ. timeint2%MM )THEN retval = 0 END IF ! If intervals have months or years, but they are identical, let the second comparision stand ! If not, then abort with an error... ELSE IF ( (timeint1%MM /= timeint2%MM) .OR. (timeint1%YR /= timeint2%YR) )THEN CALL wrf_error_fatal( & 'timeintcmp: Can not compare two intervals with different months and years' ) END IF END SUBROUTINE timeintcmp ! spaceship operator for seconds + Sn/Sd SUBROUTINE seccmp(S1, Sn1, Sd1, S2, Sn2, Sd2, retval ) 8,2 USE ESMF_BaseMod IMPLICIT NONE INTEGER, INTENT(OUT) :: retval ! ! !ARGUMENTS: INTEGER(ESMF_KIND_I8), INTENT(IN) :: S1, Sn1, Sd1 INTEGER(ESMF_KIND_I8), INTENT(IN) :: S2, Sn2, Sd2 ! local INTEGER(ESMF_KIND_I8) :: lcd, n1, n2 n1 = Sn1 n2 = Sn2 if ( ( n1 .ne. 0 ) .or. ( n2 .ne. 0 ) ) then CALL compute_lcd( Sd1, Sd2, lcd ) if ( Sd1 .ne. 0 ) n1 = n1 * ( lcd / Sd1 ) if ( Sd2 .ne. 0 ) n2 = n2 * ( lcd / Sd2 ) endif if ( S1 .GT. S2 ) retval = 1 if ( S1 .LT. S2 ) retval = -1 IF ( S1 .EQ. S2 ) THEN IF (n1 .GT. n2) retval = 1 IF (n1 .LT. n2) retval = -1 IF (n1 .EQ. n2) retval = 0 ENDIF END SUBROUTINE seccmp SUBROUTINE c_esmc_basetimeeq (time1, time2, outflag) 1,9 USE ESMF_AlarmMod USE ESMF_BaseMod USE ESMF_BaseTimeMod USE ESMF_CalendarMod USE ESMF_ClockMod USE ESMF_FractionMod USE ESMF_TimeIntervalMod USE ESMF_TimeMod IMPLICIT NONE logical, intent(OUT) :: outflag type(ESMF_Time), intent(in) :: time1 type(ESMF_Time), intent(in) :: time2 integer res CALL timecmp(time1,time2,res) outflag = (res .EQ. 0) END SUBROUTINE c_esmc_basetimeeq SUBROUTINE c_esmc_basetimege(time1, time2, outflag) 1,9 USE ESMF_AlarmMod USE ESMF_BaseMod USE ESMF_BaseTimeMod USE ESMF_CalendarMod USE ESMF_ClockMod USE ESMF_FractionMod USE ESMF_TimeIntervalMod USE ESMF_TimeMod logical, intent(OUT) :: outflag type(ESMF_Time), intent(in) :: time1 type(ESMF_Time), intent(in) :: time2 integer res CALL timecmp(time1,time2,res) outflag = (res .EQ. 1 .OR. res .EQ. 0) END SUBROUTINE c_esmc_basetimege SUBROUTINE c_esmc_basetimegt(time1, time2, outflag) 1,9 USE ESMF_AlarmMod USE ESMF_BaseMod USE ESMF_BaseTimeMod USE ESMF_CalendarMod USE ESMF_ClockMod USE ESMF_FractionMod USE ESMF_TimeIntervalMod USE ESMF_TimeMod IMPLICIT NONE logical, intent(OUT) :: outflag type(ESMF_Time), intent(in) :: time1 type(ESMF_Time), intent(in) :: time2 integer res CALL timecmp(time1,time2,res) outflag = (res .EQ. 1) END SUBROUTINE c_esmc_basetimegt SUBROUTINE c_esmc_basetimele(time1, time2, outflag) 1,9 USE ESMF_AlarmMod USE ESMF_BaseMod USE ESMF_BaseTimeMod USE ESMF_CalendarMod USE ESMF_ClockMod USE ESMF_FractionMod USE ESMF_TimeIntervalMod USE ESMF_TimeMod IMPLICIT NONE logical, intent(OUT) :: outflag type(ESMF_Time), intent(in) :: time1 type(ESMF_Time), intent(in) :: time2 integer res CALL timecmp(time1,time2,res) outflag = (res .EQ. -1 .OR. res .EQ. 0) END SUBROUTINE c_esmc_basetimele SUBROUTINE c_esmc_basetimelt(time1, time2, outflag) 1,9 USE ESMF_AlarmMod USE ESMF_BaseMod USE ESMF_BaseTimeMod USE ESMF_CalendarMod USE ESMF_ClockMod USE ESMF_FractionMod USE ESMF_TimeIntervalMod USE ESMF_TimeMod IMPLICIT NONE logical, intent(OUT) :: outflag type(ESMF_Time), intent(in) :: time1 type(ESMF_Time), intent(in) :: time2 integer res CALL timecmp(time1,time2,res) outflag = (res .EQ. -1) END SUBROUTINE c_esmc_basetimelt SUBROUTINE c_esmc_basetimene(time1, time2, outflag) 1,9 USE ESMF_AlarmMod USE ESMF_BaseMod USE ESMF_BaseTimeMod USE ESMF_CalendarMod USE ESMF_ClockMod USE ESMF_FractionMod USE ESMF_TimeIntervalMod USE ESMF_TimeMod IMPLICIT NONE logical, intent(OUT) :: outflag type(ESMF_Time), intent(in) :: time1 type(ESMF_Time), intent(in) :: time2 integer res CALL timecmp(time1,time2,res) outflag = (res .NE. 0) END SUBROUTINE c_esmc_basetimene SUBROUTINE c_esmc_basetimeinteq(timeint1, timeint2, outflag) 1,2 USE ESMF_TimeIntervalMod IMPLICIT NONE LOGICAL, INTENT(OUT) :: outflag TYPE(ESMF_TimeInterval), INTENT(IN) :: timeint1 TYPE(ESMF_TimeInterval), INTENT(IN) :: timeint2 INTEGER :: res CALL timeintcmp(timeint1,timeint2,res) outflag = (res .EQ. 0) END SUBROUTINE c_esmc_basetimeinteq SUBROUTINE c_esmc_basetimeintne(timeint1, timeint2, outflag) 1,2 USE ESMF_TimeIntervalMod IMPLICIT NONE LOGICAL, INTENT(OUT) :: outflag TYPE(ESMF_TimeInterval), INTENT(IN) :: timeint1 TYPE(ESMF_TimeInterval), INTENT(IN) :: timeint2 INTEGER :: res CALL timeintcmp(timeint1,timeint2,res) outflag = (res .NE. 0) END SUBROUTINE c_esmc_basetimeintne SUBROUTINE c_esmc_basetimeintlt(timeint1, timeint2, outflag) 1,2 USE ESMF_TimeIntervalMod IMPLICIT NONE LOGICAL, INTENT(OUT) :: outflag TYPE(ESMF_TimeInterval), INTENT(IN) :: timeint1 TYPE(ESMF_TimeInterval), INTENT(IN) :: timeint2 INTEGER :: res CALL timeintcmp(timeint1,timeint2,res) outflag = (res .LT. 0) END SUBROUTINE c_esmc_basetimeintlt SUBROUTINE c_esmc_basetimeintgt(timeint1, timeint2, outflag) 1,2 USE ESMF_TimeIntervalMod IMPLICIT NONE LOGICAL, INTENT(OUT) :: outflag TYPE(ESMF_TimeInterval), INTENT(IN) :: timeint1 TYPE(ESMF_TimeInterval), INTENT(IN) :: timeint2 INTEGER :: res CALL timeintcmp(timeint1,timeint2,res) outflag = (res .GT. 0) END SUBROUTINE c_esmc_basetimeintgt SUBROUTINE c_esmc_basetimeintle(timeint1, timeint2, outflag) 1,2 USE ESMF_TimeIntervalMod IMPLICIT NONE LOGICAL, INTENT(OUT) :: outflag TYPE(ESMF_TimeInterval), INTENT(IN) :: timeint1 TYPE(ESMF_TimeInterval), INTENT(IN) :: timeint2 INTEGER :: res CALL timeintcmp(timeint1,timeint2,res) outflag = (res .LE. 0) END SUBROUTINE c_esmc_basetimeintle SUBROUTINE c_esmc_basetimeintge(timeint1, timeint2, outflag) 1,2 USE ESMF_TimeIntervalMod IMPLICIT NONE LOGICAL, INTENT(OUT) :: outflag TYPE(ESMF_TimeInterval), INTENT(IN) :: timeint1 TYPE(ESMF_TimeInterval), INTENT(IN) :: timeint2 INTEGER :: res CALL timeintcmp(timeint1,timeint2,res) outflag = (res .GE. 0) END SUBROUTINE c_esmc_basetimeintge SUBROUTINE compute_lcd( e1, e2, lcd ) 2,1 USE ESMF_BaseMod IMPLICIT NONE INTEGER(ESMF_KIND_I8), INTENT(IN) :: e1, e2 INTEGER(ESMF_KIND_I8), INTENT(OUT) :: lcd INTEGER, PARAMETER :: nprimes = 9 INTEGER(ESMF_KIND_I8), DIMENSION(nprimes), PARAMETER :: primes = (/2,3,5,7,11,13,17,19,23/) INTEGER i INTEGER(ESMF_KIND_I8) d1, d2, p d1 = e1 ; d2 = e2 IF ( d1 .EQ. 0 .AND. d2 .EQ. 0 ) THEN ; lcd = 1 ; RETURN ; ENDIF IF ( d1 .EQ. 0 ) d1 = d2 IF ( d2 .EQ. 0 ) d2 = d1 IF ( d1 .EQ. d2 ) THEN ; lcd = d1 ; RETURN ; ENDIF lcd = d1 * d2 DO i = 1, nprimes p = primes(i) DO WHILE (lcd/p .NE. 0 .AND. & mod(lcd/p,d1) .EQ. 0 .AND. mod(lcd/p,d2) .EQ. 0) lcd = lcd / p END DO ENDDO END SUBROUTINE compute_lcd SUBROUTINE simplify( ni, di, no, do ) 1,1 USE ESMF_BaseMod IMPLICIT NONE INTEGER(ESMF_KIND_I8), INTENT(IN) :: ni, di INTEGER(ESMF_KIND_I8), INTENT(OUT) :: no, do INTEGER, PARAMETER :: nprimes = 9 INTEGER(ESMF_KIND_I8), DIMENSION(nprimes), PARAMETER :: primes = (/2,3,5,7,11,13,17,19,23/) INTEGER(ESMF_KIND_I8) :: pr, d, n INTEGER :: np LOGICAL keepgoing IF ( ni .EQ. 0 ) THEN do = 1 no = 0 RETURN ENDIF IF ( mod( di , ni ) .EQ. 0 ) THEN do = di / ni no = 1 RETURN ENDIF d = di n = ni DO np = 1, nprimes pr = primes(np) keepgoing = .TRUE. DO WHILE ( keepgoing ) keepgoing = .FALSE. IF ( d/pr .NE. 0 .AND. n/pr .NE. 0 .AND. MOD(d,pr) .EQ. 0 .AND. MOD(n,pr) .EQ. 0 ) THEN d = d / pr n = n / pr keepgoing = .TRUE. ENDIF ENDDO ENDDO do = d no = n RETURN END SUBROUTINE simplify !$$$ this should be named "c_esmc_timesum" or something less misleading SUBROUTINE c_esmc_basetimesum( time1, timeinterval, timeOut ) 1,10 USE ESMF_BaseMod USE ESMF_BaseTimeMod USE ESMF_CalendarMod USE ESMF_TimeIntervalMod USE ESMF_TimeMod IMPLICIT NONE TYPE(ESMF_Time), INTENT(IN) :: time1 TYPE(ESMF_TimeInterval), INTENT(IN) :: timeinterval TYPE(ESMF_Time), INTENT(INOUT) :: timeOut ! locals INTEGER :: m INTEGER :: nfeb INTEGER(ESMF_KIND_I8) :: years INTEGER :: MM_start INTEGER :: MM_final TYPE(ESMF_BaseTime), POINTER :: MMbdys(:) TYPE(ESMF_BaseTime), POINTER :: MMedys(:) timeOut = time1 timeOut%basetime = timeOut%basetime + timeinterval%basetime ! For 365-day calendar, take years out timeinterval seconds since we know ! how to do it in this case. !$$$ replace this hack with something saner... IF ( nfeb( 2004 ) == 28 ) THEN years = timeinterval%basetime%S / ( 365_ESMF_KIND_I8 * SECONDS_PER_DAY ) timeOut%YR = timeOut%YR + years timeOut%basetime%S = timeOut%basetime%S - years * ( 365_ESMF_KIND_I8 * SECONDS_PER_DAY ) ENDIF IF ( (timeinterval%MM /= 0) .OR. (timeinterval%YR /= 0) )THEN CALL timegetmonth( time1, MM_start ) IF ( nfeb(time1%YR) == 29 ) THEN MMbdys => monthbdysleap ELSE MMbdys => monthbdys ENDIF ! Subtract out the basetime of the beginning of the current month timeOut%basetime = timeOut%basetime - MMBdys(MM_start-1) MM_final = MM_start + timeinterval%MM IF ( MM_final < 1 )THEN timeOut%YR = timeOut%YR - 1 MM_final = MONTHS_PER_YEAR + MM_final END IF timeOut%YR = timeOut%YR + timeinterval%YR + (MM_final-1) / MONTHS_PER_YEAR IF ( nfeb(timeOut%YR) == 29 ) THEN MMbdys => monthbdysleap MMedys => monthedysleap ELSE MMbdys => monthbdys MMedys => monthedys ENDIF MM_final = MOD( MM_final, MONTHS_PER_YEAR ) IF ( MM_final == 0 ) MM_final = MONTHS_PER_YEAR ! Add in the basetime of the beginning of the new month timeOut%basetime = timeOut%basetime + MMBdys(MM_final-1) ! Restrict the total exchange to the end of the new month if ( timeOut%basetime > MMedys(MM_final-1) ) timeOut%basetime = MMedys(MM_final-1) END IF CALL normalize_time( timeOut ) END SUBROUTINE c_esmc_basetimesum !$$$ this should be named "c_esmc_timedec" or something less misleading SUBROUTINE c_esmc_basetimedec( time1, timeinterval, timeOut ) 1,4 USE ESMF_BaseMod USE ESMF_BaseTimeMod USE ESMF_TimeIntervalMod USE ESMF_TimeMod IMPLICIT NONE TYPE(ESMF_Time), INTENT(IN) :: time1 TYPE(ESMF_TimeInterval), INTENT(IN) :: timeinterval TYPE(ESMF_Time), INTENT(OUT) :: timeOut ! locals TYPE (ESMF_TimeInterval) :: neginterval neginterval = timeinterval !$$$push this down into a unary negation operator on TimeInterval neginterval%basetime%S = -neginterval%basetime%S neginterval%basetime%Sn = -neginterval%basetime%Sn neginterval%YR = -neginterval%YR neginterval%MM = -neginterval%MM timeOut = time1 + neginterval END SUBROUTINE c_esmc_basetimedec !$$$ this should be named "c_esmc_timediff" or something less misleading SUBROUTINE c_esmc_basetimediff( time1, time2, timeIntOut ) 1,8 USE ESMF_BaseMod USE ESMF_BaseTimeMod USE ESMF_TimeIntervalMod USE ESMF_TimeMod IMPLICIT NONE TYPE(ESMF_Time), INTENT(IN) :: time1 TYPE(ESMF_Time), INTENT(IN) :: time2 TYPE(ESMF_TimeInterval), INTENT(OUT) :: timeIntOut ! locals INTEGER(ESMF_KIND_I8) :: nsecondsinyear INTEGER :: yr CALL ESMF_TimeIntervalSet( timeIntOut ) timeIntOut%basetime = time1%basetime - time2%basetime ! convert difference in years to basetime... IF ( time1%YR > time2%YR ) THEN DO yr = time2%YR, ( time1%YR - 1 ) timeIntOut%basetime%S = timeIntOut%basetime%S + nsecondsinyear( yr ) ENDDO ELSE IF ( time2%YR > time1%YR ) THEN DO yr = time1%YR, ( time2%YR - 1 ) timeIntOut%basetime%S = timeIntOut%basetime%S - nsecondsinyear( yr ) ENDDO ENDIF !$$$ add tests for multi-year differences CALL normalize_timeint( timeIntOut ) END SUBROUTINE c_esmc_basetimediff ! some extra wrf stuff ! Convert fraction to string with leading sign. ! If fraction simplifies to a whole number or if ! denominator is zero, return empty string. ! INTEGER*8 interface. SUBROUTINE fraction_to_stringi8( numerator, denominator, frac_str ) 1,1 USE ESMF_basemod IMPLICIT NONE INTEGER(ESMF_KIND_I8), INTENT(IN) :: numerator INTEGER(ESMF_KIND_I8), INTENT(IN) :: denominator CHARACTER (LEN=*), INTENT(OUT) :: frac_str IF ( denominator > 0 ) THEN IF ( mod( numerator, denominator ) /= 0 ) THEN IF ( numerator > 0 ) THEN WRITE(frac_str,FMT="('+',I2.2,'/',I2.2)") abs(numerator), denominator ELSE ! numerator < 0 WRITE(frac_str,FMT="('-',I2.2,'/',I2.2)") abs(numerator), denominator ENDIF ELSE ! includes numerator == 0 case frac_str = '' ENDIF ELSE ! no-fraction case frac_str = '' ENDIF END SUBROUTINE fraction_to_stringi8 ! Convert fraction to string with leading sign. ! If fraction simplifies to a whole number or if ! denominator is zero, return empty string. ! INTEGER interface. SUBROUTINE fraction_to_string( numerator, denominator, frac_str ),2 USE ESMF_basemod IMPLICIT NONE INTEGER, INTENT(IN) :: numerator INTEGER, INTENT(IN) :: denominator CHARACTER (LEN=*), INTENT(OUT) :: frac_str ! locals INTEGER(ESMF_KIND_I8) :: numerator_i8, denominator_i8 numerator_i8 = INT( numerator, ESMF_KIND_I8 ) denominator_i8 = INT( denominator, ESMF_KIND_I8 ) CALL fraction_to_stringi8( numerator_i8, denominator_i8, frac_str ) END SUBROUTINE fraction_to_string SUBROUTINE print_a_time( time ) 1,3 use ESMF_basemod use ESMF_Timemod IMPLICIT NONE type(ESMF_Time) time character*128 :: s integer rc CALL ESMF_TimeGet( time, timeString=s, rc=rc ) print *,'Print a time|',TRIM(s),'|' write(0,*)'Print a time|',TRIM(s),'|' return END SUBROUTINE print_a_time SUBROUTINE print_a_timeinterval( time ) 1,3 use ESMF_basemod use ESMF_TimeIntervalmod IMPLICIT NONE type(ESMF_TimeInterval) time character*128 :: s integer rc CALL ESMFold_TimeIntervalGetString( time, s, rc ) print *,'Print a time interval|',TRIM(s),'|' write(0,*)'Print a time interval|',TRIM(s),'|' return END SUBROUTINE print_a_timeinterval