diff --git a/src/Infrastructure/TimeMgr/doc/Alarm_rest.tex b/src/Infrastructure/TimeMgr/doc/Alarm_rest.tex index 80e17ed337..aca44671c6 100644 --- a/src/Infrastructure/TimeMgr/doc/Alarm_rest.tex +++ b/src/Infrastructure/TimeMgr/doc/Alarm_rest.tex @@ -7,21 +7,11 @@ This constant is defined in both Fortran and C++ with a \#define for ease of modification. -\item {\bf Sticky alarm end times in reverse} For sticky alarms, there is -an implicit limitation that in order to properly reverse timestep through a -ring end time, that time must have already been traversed in the forward -direction. This is due to the fact that the Time Manager cannot predict -when user code will call {\tt ESMF\_AlarmRingerOff()}. An error message -will be logged when this limitation is not satisfied. +\item {\bf Alarm ringInterval } The alarm ring interval must be greater +than or equal to clock time step. This is consistent with physical clock and +alarm behavior. -\item {\bf Sticky alarm ring interval in reverse} -\begin{sloppypar} -For repeating sticky alarms, -it is currently assumed that the ringInterval is constant, so that only the -time of the last call to {\tt ESMF\_AlarmRingerOff()} is saved. In -{\tt ESMF\_DIRECTION\_REVERSE}, this information is used to turn sticky alarms -back on. In a future release, ringIntervals will be allowed to be variable, -by saving alarm state at every timestep. -\end{sloppypar} +\item {\bf Alarm ring time} An alarm will only ring if its ring time matches +exactly the clock's current time. \end{enumerate} diff --git a/src/Infrastructure/TimeMgr/examples/ESMF_AlarmEx.F90 b/src/Infrastructure/TimeMgr/examples/ESMF_AlarmEx.F90 index b15e818c30..228d1e88ab 100644 --- a/src/Infrastructure/TimeMgr/examples/ESMF_AlarmEx.F90 +++ b/src/Infrastructure/TimeMgr/examples/ESMF_AlarmEx.F90 @@ -31,22 +31,23 @@ program ESMF_AlarmEx implicit none ! instantiate time_step, start, stop, and alarm times - type(ESMF_TimeInterval) :: timeStep, alarmInterval - type(ESMF_Time) :: alarmTime, startTime, stopTime + type(ESMF_TimeInterval) :: timeStep, alarmInterval, ringTimeInterval + type(ESMF_Time) :: alarmTime, startTime, stopTime, ringTime + logical :: ringing, enabled, sticky ! instantiate a clock type(ESMF_Clock) :: clock ! instantiate Alarm lists integer, parameter :: NUMALARMS = 2 - type(ESMF_Alarm) :: alarm(NUMALARMS) + type(ESMF_Alarm) :: alarms(NUMALARMS), alarm ! local variables for Get methods integer :: ringingAlarmCount ! at any time step (0 to NUMALARMS) ! name, loop counter, result code character (len=ESMF_MAXSTR) :: name - integer :: i, rc, result + integer :: i, n, nrings, rc, result, status !EOC ! result code @@ -127,7 +128,7 @@ program ESMF_AlarmEx if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT) !BOC - alarm(1) = ESMF_AlarmCreate(clock, & + alarms(1) = ESMF_AlarmCreate(clock, & ringTime=alarmTime, name="Example alarm 1", rc=rc) !EOC @@ -149,7 +150,7 @@ program ESMF_AlarmEx !BOC ! Alarm gets default name "Alarm002" - alarm(2) = ESMF_AlarmCreate(clock=clock, ringTime=alarmTime, & + alarms(2) = ESMF_AlarmCreate(clock=clock, ringTime=alarmTime, & ringInterval=alarmInterval, rc=rc) !EOC @@ -189,13 +190,13 @@ program ESMF_AlarmEx print *, "number of ringing alarms = ", ringingAlarmCount do i = 1, NUMALARMS - if (ESMF_AlarmIsRinging(alarm(i), rc=rc)) then + if (ESMF_AlarmIsRinging(alarms(i), rc=rc)) then !EOC if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT) !BOC - call ESMF_AlarmGet(alarm(i), name=name, rc=rc) + call ESMF_AlarmGet(alarms(i), name=name, rc=rc) print *, trim(name), " is ringing!" !EOC @@ -203,7 +204,7 @@ program ESMF_AlarmEx !BOC ! after processing alarm, turn it off - call ESMF_AlarmRingerOff(alarm(i), rc=rc) + call ESMF_AlarmRingerOff(alarms(i), rc=rc) !EOC if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT) @@ -215,6 +216,7 @@ program ESMF_AlarmEx end do ! timestep clock !EOC +!------------------------------------------------------------------------------ !BOE !\subsubsection{Alarm and Clock destruction} @@ -222,13 +224,13 @@ program ESMF_AlarmEx !EOE !BOC - call ESMF_AlarmDestroy(alarm(1), rc=rc) + call ESMF_AlarmDestroy(alarms(1), rc=rc) !EOC if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT) !BOC - call ESMF_AlarmDestroy(alarm(2), rc=rc) + call ESMF_AlarmDestroy(alarms(2), rc=rc) !EOC if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT) @@ -239,6 +241,505 @@ program ESMF_AlarmEx if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT) +!------------------------------------------------------------------------------ +!------------------------------------------------------------------------------ +!------------------------------------------------------------------------------ + +!BOE +!\subsubsection{One shot Alarm} + +! This example shows how to set up an one shot alarm that will ring exactly at +! the ringtime specified during alarmCreate but not at any other time. +! +! To specify such an alarm, do not use the ringInterval argument during AlarmCreate. +!EOE +!BOE + +! A clock is set up to run from 0h0m0s to 1h0m0s; One shot ring time is set to 0h30m0s. + +!EOE +!BOC + call ESMF_TimeSet(startTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOC + call ESMF_TimeSet(stopTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOC + call ESMF_TimeSet(ringTime,yy=1,mm=1,dd=1,h=0,m=30,s=0,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + +!BOE + +! The clock advances by 10 minutes. + +!EOE +!BOC + call ESMF_TimeIntervalSet(timeStep,S=600, sN=0, sD=1,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + nrings = 0 +!BOE + +! Create the clock from the specified start time, stop time and time step. + +!EOE +!BOC + clock = ESMF_ClockCreate(timeStep=timeStep,startTime=startTime,stopTime=stopTime,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOE + +! Create the alarm from the specified ring time (0h0m0s) only. This is how one shot alarm +! is created. +! This alarm is enabled upon creation and non sticky. + +!EOE +!BOC + alarm = ESMF_AlarmCreate(clock, ringTime=ringTime, enabled=.true., sticky=.false., name='alarm', rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + +!BOE + +! Query the alarm to check if it's ringing, enabled and sticky. In this case, we expect +! the alarm to return ringing=true, enabled=true, sticky=false. + +!EOE +!BOC + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + !print *, 'Ex: ringing = ', ringing +!BOE + +! Advance the clock 6 times to move from 0h0m0s to 1h0m0s. + +!EOE +!BOC + do n = 1, 6 + call ESMF_ClockAdvance(clock,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOE + +! Query the alarm to check if it's ringing, enabled and sticky. In this case, we expect +! the alarm only return ringing=true at 0h 30m 0s. + +!EOE +!BOC + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + !print *, ' Ex: ringing = ', ringing + enddo + +!BOE + +! Destroy the alarm and clock created for this example. + +!EOE +!BOC + call ESMF_AlarmDestroy(alarm, rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOC + call ESMF_ClockDestroy(clock, rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + +!------------------------------------------------------------------------------ +!------------------------------------------------------------------------------ +!------------------------------------------------------------------------------ +!BOE +!\subsubsection{Using Alarm in clock running forward} + +! This example shows how to set up an alarm in conjuction with a reverse +! running clock. +!EOE +!BOE + +! A clock is set up to run from 0h0m0s to 1h0m0s; Initial ring time is set to 0h0m0s. + +!EOE +!BOC + call ESMF_TimeSet(startTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOC + call ESMF_TimeSet(stopTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOC + call ESMF_TimeSet(ringTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + +!BOE + +! The clock advances by 10 minutes and the alarm rings every 10 minutes as well. + +!EOE +!BOC + call ESMF_TimeIntervalSet(timeStep,S=600, sN=0, sD=1,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOC + call ESMF_TimeIntervalSet(ringTimeInterval,S=600, sN=0, sD=1,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + nrings = 0 +!BOE + +! Create the clock from the specified start time, stop time and time step. + +!EOE +!BOC + clock = ESMF_ClockCreate(timeStep=timeStep,startTime=startTime,stopTime=stopTime,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOE + +! Create the alarm from the specified ring time (0h0m0s), ring interval (10 minutes). +! This alarm is enabled upon creation and non sticky. + +!EOE +!BOC + alarm = ESMF_AlarmCreate(clock, ringTime=ringTime, ringInterval=ringTimeInterval, enabled=.true., sticky=.false., name='alarm', rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + +!BOE + +! Query the alarm to check if it's ringing, enabled and sticky. In this case, we expect +! the alarm to return ringing=true, enabled=true, sticky=false. + +!EOE +!BOC + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if(ringing) nrings = nrings + 1 + !print *, 'Ex: ringing = ', ringing +!BOE + +! Advance the clock 6 times to move from 0h0m0s to 1h0m0s. + +!EOE +!BOC + do n = 1, 6 + call ESMF_ClockAdvance(clock,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOE + +! Query the alarm to check if it's ringing, enabled and sticky. In this case, we expect +! the alarm should return ringing=true, enabled=true, sticky=false every clock time step +! because the alarm and the clock have identical time step (or interval). + +!EOE +!BOC + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + !print *, ' Ex: ringing = ', ringing + if(ringing) nrings = nrings + 1 + enddo + +!BOE + +! Destroy the alarm and clock created for this example. + +!EOE +!BOC + call ESMF_AlarmDestroy(alarm, rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOC + call ESMF_ClockDestroy(clock, rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + +!------------------------------------------------------------------------------ +!------------------------------------------------------------------------------ +!------------------------------------------------------------------------------ +!BOE +!\subsubsection{Using Alarm in clock running reverse} + +! This example shows how to set up an alarm in conjuction with a reverse +! running clock. +!EOE +!BOE + +! A clock is set up to run from 1h0m0s to 0h0m0s; Initial ring time is set to 1h0m0s. +! For clock running in reverse direction, the start time should still be in the past +! compared with the stoptime. This example shows the start time is 0h0m0s, the stop +! time is 1h0m0s. We will set the current time to 1h0m0s and set the clock to run +! in reverse direction. + +!EOE +!BOC + call ESMF_TimeSet(startTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOC + call ESMF_TimeSet(stopTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOC + call ESMF_TimeSet(ringTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + +!BOE + +! The clock advances by 10 minutes and the alarm rings every 10 minutes as well. + +!EOE +!BOC + call ESMF_TimeIntervalSet(timeStep,S=600, sN=0, sD=1,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOC + call ESMF_TimeIntervalSet(ringTimeInterval,S=600, sN=0, sD=1,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + nrings = 0 +!BOE + +! Create the clock from the specified start time, stop time and time step. + +!EOE +!BOC + clock = ESMF_ClockCreate(timeStep=timeStep,startTime=startTime,stopTime=stopTime,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOE + +! Here we set the current time on the clock to stop time 1h0m0s and set the clock to run in +! reverse direction. + +!EOE + +!BOC + call ESMF_ClockSet(clock, currTime = stopTime, direction=ESMF_DIRECTION_REVERSE, rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOE + +! Create the alarm from the specified ring time (0h0m0s), ring interval (10 minutes). +! This alarm is enabled upon creation and non sticky. + +!EOE +!BOC + alarm = ESMF_AlarmCreate(clock, ringTime=ringTime, ringInterval=ringTimeInterval, enabled=.true., sticky=.false., name='alarm', rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + +!BOE + +! Query the alarm to check if it's ringing, enabled and sticky. In this case, we expect +! the alarm to return ringing=true, enabled=true, sticky=false. + +!EOE +!BOC + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if(ringing) nrings = nrings + 1 + !print *, 'Ex: ringing = ', ringing +!BOE + +! Advance the clock 6 times to move from 0h0m0s to 1h0m0s. + +!EOE +!BOC + do n = 1, 6 + call ESMF_ClockAdvance(clock,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOE + +! Query the alarm to check if it's ringing, enabled and sticky. In this case, we expect +! the alarm should return ringing=true, enabled=true, sticky=false every clock time step +! because the alarm and the clock have identical time step (or interval). + +!EOE +!BOC + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + !print *, ' Ex: ringing = ', ringing + if(ringing) nrings = nrings + 1 + enddo + +!BOE + +! Destroy the alarm and clock created for this example. + +!EOE +!BOC + call ESMF_AlarmDestroy(alarm, rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOC + call ESMF_ClockDestroy(clock, rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + +!------------------------------------------------------------------------------ +!------------------------------------------------------------------------------ +!------------------------------------------------------------------------------ +!BOE +!\subsubsection{Using Alarm in clock runs forward then reverse} + +! This example shows how to set up an alarm in conjuction with a reverse +! running clock. +!EOE + +!BOE + +! A clock is set up to run from 0h0m0s to 1h0m0s; Initial ring time is set to 0h0m0s. + +!EOE +!BOC + call ESMF_TimeSet(startTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOC + call ESMF_TimeSet(stopTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOC + call ESMF_TimeSet(ringTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + +!BOE + +! The clock advances by 10 minutes and the alarm rings every 10 minutes as well. + +!EOE +!BOC + call ESMF_TimeIntervalSet(timeStep,S=600, sN=0, sD=1,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOC + call ESMF_TimeIntervalSet(ringTimeInterval,S=600, sN=0, sD=1,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + nrings = 0 +!BOE + +! Create the clock from the specified start time, stop time and time step. + +!EOE +!BOC + clock = ESMF_ClockCreate(timeStep=timeStep,startTime=startTime,stopTime=stopTime,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOE + +! Create the alarm from the specified ring time (0h0m0s), ring interval (10 minutes). +! This alarm is enabled upon creation and non sticky. + +!EOE +!BOC + alarm = ESMF_AlarmCreate(clock, ringTime=ringTime, ringInterval=ringTimeInterval, enabled=.true., sticky=.false., name='alarm', rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + +!BOE + +! Query the alarm to check if it's ringing, enabled and sticky. In this case, we expect +! the alarm to return ringing=true, enabled=true, sticky=false. + +!EOE +!BOC + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if(ringing) nrings = nrings + 1 + !print *, 'Ex: ringing = ', ringing +!BOE + +! Advance the clock 6 times to move from 0h0m0s to 1h0m0s. + +!EOE +!BOC + do n = 1, 6 + call ESMF_ClockAdvance(clock,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOE + +! Query the alarm to check if it's ringing, enabled and sticky. In this case, we expect +! the alarm should return ringing=true, enabled=true, sticky=false every clock time step +! because the alarm and the clock have identical time step (or interval). + +!EOE +!BOC + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + !print *, ' Ex: ringing = ', ringing + if(ringing) nrings = nrings + 1 + enddo +!BOE + +! Reverse the direction of the clock, since the clock's current time is 1h0m0s, the clock +! now runs backward to 0h50m0s, 0h40m0s, etc. + +!EOE +!BOC + call ESMF_ClockSet(clock, direction = ESMF_DIRECTION_REVERSE, rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOE + +! Advance the clock 6 times to move from 1h0m0s to 0h0m0s. + +!EOE +!BOC + do n = 1, 6 + call ESMF_ClockAdvance(clock,rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOE + +! Query the alarm to check if it's ringing, enabled and sticky. In this case, we expect +! the alarm should return ringing=true, enabled=true, sticky=false every clock time step +! because the alarm and the clock have identical time step (or interval). + +!EOE +!BOC + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if(ringing) nrings = nrings + 1 + !print *, ' Ex: ringing = ', ringing + enddo +!BOE + +! Destroy the alarm and clock created for this example. + +!EOE +!BOC + call ESMF_AlarmDestroy(alarm, rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() +!BOC + call ESMF_ClockDestroy(clock, rc=status) +!EOC + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + ! IMPORTANT: ESMF_STest() prints the PASS string and the # of processors in the log ! file that the scripts grep for. call ESMF_STest((finalrc.eq.ESMF_SUCCESS), testname, failMsg, result, ESMF_SRCLINE) diff --git a/src/Infrastructure/TimeMgr/include/ESMCI_Alarm.h b/src/Infrastructure/TimeMgr/include/ESMCI_Alarm.h index 19f75b874a..251fcffe00 100644 --- a/src/Infrastructure/TimeMgr/include/ESMCI_Alarm.h +++ b/src/Infrastructure/TimeMgr/include/ESMCI_Alarm.h @@ -28,6 +28,7 @@ #include "ESMCI_Util.h" #include "ESMCI_Macros.h" #include "ESMF_TimeMgr.inc" +#include //------------------------------------------------------------------------- //BOP @@ -126,12 +127,6 @@ class Alarm { // number of time steps. bool ringing; // (TMG 4.4) currently ringing - bool ringingOnCurrTimeStep; // was ringing immediately after - // current clock timestep. - // (could have been turned off - // later due to RingerOff or - // Disable commands or - // non-sticky alarm expiration). bool ringingOnPrevTimeStep; // was ringing immediately after // previous clock timestep. bool userChangedRingTime; // true if changed via Set(), @@ -139,6 +134,7 @@ class Alarm { // to adjust alarm on timeStep // direction (sign) change bool enabled; // able to ring (TMG 4.5.3) + bool ringerIsOn; // whether ringer is on or off bool sticky; // must be turned off via // Alarm::ringerOff(), // otherwise will turn self off after @@ -164,37 +160,25 @@ class Alarm { // accessor methods - int set(int nameLen, + int set(int nameLen, const char *name=0, - Clock **clock=0, - Time *ringTime=0, - TimeInterval *ringInterval=0, - Time *stopTime=0, - TimeInterval *ringDuration=0, - int *ringTimeStepCount=0, - Time *refTime=0, + Clock **clock=0, + Time *ringTime=0, + TimeInterval *ringInterval=0, bool *ringing=0, bool *enabled=0, // (TMG 4.1, 4.7) bool *sticky=0); - int get(int nameLen, + int get(int nameLen, int *tempNameLen, char *tempName=0, - Clock **clock=0, - Time *ringTime=0, - Time *prevRingTime=0, - TimeInterval *ringInterval=0, - Time *stopTime=0, - TimeInterval *ringDuration=0, - int *ringTimeStepCount=0, - int *timeStepRingingCount=0, - Time *ringBegin=0, - Time *ringEnd=0, - Time *refTime=0, + Clock **clock=0, + Time *ringTime=0, + TimeInterval *ringInterval=0, bool *ringing=0, - bool *ringingOnPrevTimeStep=0, bool *enabled=0, // (TMG 4.1, 4.7) - bool *sticky=0); + bool *sticky=0, + bool *ringerIsOn=0); int enable(void); // TMG4.5.3 int disable(void); @@ -218,6 +202,8 @@ class Alarm { // Check for crossing ringTime in either positive or // negative direction // Can be basis for asynchronous alarm reporting + void updateRingTime(int *rc=0); + void clockChangeDirection(const ESMC_Direction & old_direction, const ESMC_Direction & new_direction, int *rc=0); bool operator==(const Alarm &) const; bool operator!=(const Alarm &) const; @@ -246,8 +232,7 @@ class Alarm { // friend to allocate and initialize alarm from heap friend Alarm *ESMCI_alarmCreate(int, const char*, Clock*, - Time*, TimeInterval*, Time*, - TimeInterval*, int*, Time*, bool*, + Time*, TimeInterval*, bool*, bool*, int*); // friend function to copy an alarm @@ -266,20 +251,31 @@ class Alarm { // // < declare private interface methods here > - // check if time to turn on alarm - bool checkTurnOn(bool timeStepPositive); - // reconstruct ringBegin during ESMF_DIRECTION_REVERSE int resetRingBegin(bool timeStepPositive); + // enable Sticky + void enableSticky(void); + + bool canRingAtTime(const Clock & clock) ; + bool canRingAtNextTime(Clock & clock, TimeInterval *timeStep) const; + // friend class alarm friend class Clock; + // Keep track of 2 states for ringing calculation + // 0: saved current, 1: previous, 2, previous-previous .... + // saved current becomes previous, current becomes saved current as state evolves. + // It's possible to have more saved previous states + std::vector alarms; + std::vector clocks; // //EOP //------------------------------------------------------------------------- }; // end class Alarm + const int SAVEDCURRENT=0; + const int SAVESIZE=2; // Note: though seemingly redundant with the friend declarations within // the class definition above, the following declarations are necessary @@ -288,13 +284,9 @@ class Alarm { Alarm *ESMCI_alarmCreate(int nameLen, const char* name=0, - Clock* clock=0, - Time* ringTime=0, - TimeInterval* ringInterval=0, - Time* stopTime=0, - TimeInterval* ringDuration=0, - int* ringTimeStepCount=0, - Time* refTime=0, + Clock* clock=0, + Time* ringTime=0, + TimeInterval* ringInterval=0, bool* enabled=0, bool* sticky=0, int* rc=0); diff --git a/src/Infrastructure/TimeMgr/include/ESMCI_Clock.h b/src/Infrastructure/TimeMgr/include/ESMCI_Clock.h index 3023d5f0cd..7d6bcd1787 100644 --- a/src/Infrastructure/TimeMgr/include/ESMCI_Clock.h +++ b/src/Infrastructure/TimeMgr/include/ESMCI_Clock.h @@ -197,7 +197,7 @@ namespace ESMCI{ int syncToRealTime(void); // TMG3.4.5 // (see Time::SyncToRealTime() - // to suuport copying of the alarmList + // to support copying of the alarmList Clock& operator=(const Clock &); bool operator==(const Clock &) const; @@ -241,8 +241,8 @@ namespace ESMCI{ // friend to allocate and initialize alarm from heap // (needs access to clock current time to initialize alarm ring time) friend Alarm *ESMCI_alarmCreate(int, const char*, Clock*, - Time*, TimeInterval*, Time*, - TimeInterval*, int*, Time*, bool*, + Time*, + TimeInterval*, bool*, bool*, int*); // friend function to copy an alarm diff --git a/src/Infrastructure/TimeMgr/interface/ESMCI_Alarm_F.C b/src/Infrastructure/TimeMgr/interface/ESMCI_Alarm_F.C index 590d2add4f..eca99a410d 100644 --- a/src/Infrastructure/TimeMgr/interface/ESMCI_Alarm_F.C +++ b/src/Infrastructure/TimeMgr/interface/ESMCI_Alarm_F.C @@ -41,8 +41,6 @@ extern "C" { void FTN_X(c_esmc_alarmcreatenew)(Alarm **ptr, int *nameLen, const char *name, Clock **clock, Time *ringTime, TimeInterval *ringInterval, - Time *stopTime, TimeInterval *ringDuration, - int *ringTimeStepCount, Time *refTime, bool *enabled, bool *sticky, int *status, ESMCI_FortranStrLenArg name_l) { *ptr = ESMCI_alarmCreate( @@ -52,10 +50,6 @@ extern "C" { *clock, // required. ESMC_NOT_PRESENT_FILTER(ringTime), ESMC_NOT_PRESENT_FILTER(ringInterval), - ESMC_NOT_PRESENT_FILTER(stopTime), - ESMC_NOT_PRESENT_FILTER(ringDuration), - ESMC_NOT_PRESENT_FILTER(ringTimeStepCount), - ESMC_NOT_PRESENT_FILTER(refTime), ESMC_NOT_PRESENT_FILTER(enabled), ESMC_NOT_PRESENT_FILTER(sticky), ESMC_NOT_PRESENT_FILTER(status) ); @@ -77,8 +71,6 @@ extern "C" { void FTN_X(c_esmc_alarmset)(Alarm **ptr, int *nameLen, const char *name, Clock **clock, Time *ringTime, TimeInterval *ringInterval, - Time *stopTime, TimeInterval *ringDuration, - int *ringTimeStepCount, Time *refTime, bool *ringing, bool *enabled, bool *sticky, int *status, ESMCI_FortranStrLenArg name_l) { @@ -90,28 +82,33 @@ extern "C" { ESMC_NOT_PRESENT_FILTER(clock), ESMC_NOT_PRESENT_FILTER(ringTime), ESMC_NOT_PRESENT_FILTER(ringInterval), - ESMC_NOT_PRESENT_FILTER(stopTime), - ESMC_NOT_PRESENT_FILTER(ringDuration), - ESMC_NOT_PRESENT_FILTER(ringTimeStepCount), - ESMC_NOT_PRESENT_FILTER(refTime), ESMC_NOT_PRESENT_FILTER(ringing), ESMC_NOT_PRESENT_FILTER(enabled), ESMC_NOT_PRESENT_FILTER(sticky) ); if (ESMC_PRESENT(status)) *status = rc; } + int get(int nameLen, + int *tempNameLen, + char *tempName=0, + Clock **clock=0, + Time *ringTime=0, + TimeInterval *ringInterval=0, + bool *ringing=0, + bool *enabled=0, // (TMG 4.1, 4.7) + bool *sticky=0, + bool *ringerIsOn=0); void FTN_X(c_esmc_alarmget)(Alarm **ptr, int *nameLen, int *tempNameLen, char *tempName, Clock **clock, - Time *ringTime, Time *prevRingTime, - TimeInterval *ringInterval, Time *stopTime, - TimeInterval *ringDuration, int *ringTimeStepCount, - int *timeStepRingingCount, Time *ringBegin, - Time *ringEnd, Time *refTime, bool *ringing, - bool *ringingOnPrevTimeStep, bool *enabled, bool *sticky, + Time *ringTime, + TimeInterval *ringInterval, + bool *ringing, + bool *enabled, bool *sticky, bool *ringerIsOn, int *status, ESMCI_FortranStrLenArg tempName_l) { ESMF_CHECK_POINTER(*ptr, status) + //if(sticky != 0) printf("ptr address %x => %d \n", sticky, (int)*sticky); int rc = (*ptr)->Alarm::get( // always presnet internal arguments *nameLen, @@ -119,19 +116,29 @@ extern "C" { tempName, ESMC_NOT_PRESENT_FILTER(clock), ESMC_NOT_PRESENT_FILTER(ringTime), - ESMC_NOT_PRESENT_FILTER(prevRingTime), ESMC_NOT_PRESENT_FILTER(ringInterval), - ESMC_NOT_PRESENT_FILTER(stopTime), - ESMC_NOT_PRESENT_FILTER(ringDuration), - ESMC_NOT_PRESENT_FILTER(ringTimeStepCount), - ESMC_NOT_PRESENT_FILTER(timeStepRingingCount), - ESMC_NOT_PRESENT_FILTER(ringBegin), - ESMC_NOT_PRESENT_FILTER(ringEnd), - ESMC_NOT_PRESENT_FILTER(refTime), ESMC_NOT_PRESENT_FILTER(ringing), - ESMC_NOT_PRESENT_FILTER(ringingOnPrevTimeStep), ESMC_NOT_PRESENT_FILTER(enabled), - ESMC_NOT_PRESENT_FILTER(sticky) ); + ESMC_NOT_PRESENT_FILTER(sticky), + ESMC_NOT_PRESENT_FILTER(ringerIsOn) ); + if(sticky != 0) { + if(*sticky) *(int *)sticky = 1; + else *(int *)sticky = 0; + //printf("ptr address %x => %d \n", sticky, *(int *)sticky); + } + if(ringing != 0) { + if(*ringing) *(int *)ringing = 1; + else *(int *)ringing = 0; + //printf("ptr address %x => %d \n", ringing, *(int *)ringing); + } + if(enabled != 0) { + if(*enabled) *(int *)enabled = 1; + else *(int *)enabled = 0; + } + if(ringerIsOn != 0) { + if(*ringerIsOn) *(int *)ringerIsOn = 1; + else *(int *)ringerIsOn = 0; + } if (ESMC_PRESENT(status)) *status = rc; } diff --git a/src/Infrastructure/TimeMgr/interface/ESMF_Alarm.F90 b/src/Infrastructure/TimeMgr/interface/ESMF_Alarm.F90 index 574f609b69..5071c6e479 100644 --- a/src/Infrastructure/TimeMgr/interface/ESMF_Alarm.F90 +++ b/src/Infrastructure/TimeMgr/interface/ESMF_Alarm.F90 @@ -296,8 +296,8 @@ module ESMF_AlarmMod ! !INTERFACE: ! Private name; call using ESMF_AlarmCreate() function ESMF_AlarmCreateNew(clock, keywordEnforcer, & - ringTime, ringInterval, stopTime, ringDuration, ringTimeStepCount, & - refTime, enabled, sticky, name, rc) + ringTime, ringInterval, & + enabled, sticky, name, rc) ! !RETURN VALUE: type(ESMF_Alarm) :: ESMF_AlarmCreateNew @@ -307,10 +307,6 @@ function ESMF_AlarmCreateNew(clock, keywordEnforcer, & type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below type(ESMF_Time), intent(in), optional :: ringTime type(ESMF_TimeInterval), intent(in), optional :: ringInterval - type(ESMF_Time), intent(in), optional :: stopTime - type(ESMF_TimeInterval), intent(in), optional :: ringDuration - integer, intent(in), optional :: ringTimeStepCount - type(ESMF_Time), intent(in), optional :: refTime logical, intent(in), optional :: enabled logical, intent(in), optional :: sticky character (len=*), intent(in), optional :: name @@ -336,33 +332,15 @@ function ESMF_AlarmCreateNew(clock, keywordEnforcer, & ! \item[{[ringTime]}] ! The ring time for a one-shot alarm or the first ring time for a ! repeating (interval) alarm. Must specify at least one of ringTime -! or ringInterval. +! or ringInterval. ringTime defaults to clock's current time if +! not specified. ! \item[{[ringInterval]}] -! The ring interval for repeating (interval) alarms. If -! {\tt ringTime} is not also specified (first ring time), it will be -! calculated as the {\tt clock}'s current time plus {\tt ringInterval}. -! Must specify at least one of ringTime or ringInterval. -! \item[{[stopTime]}] -! The stop time for repeating (interval) alarms. If not -! specified, an interval alarm will repeat forever. -! \item[{[ringDuration]}] -! The absolute ring duration. If not sticky (see argument below), -! alarms rings for ringDuration, then turns itself off. Default is -! zero (unused). Mutually exclusive with ringTimeStepCount (below); -! used only if set to a non-zero duration and ringTimeStepCount is 1 -! (see below). -! See also {\tt ESMF\_AlarmSticky()}, {\tt ESMF\_AlarmNotSticky()}. -! \item[{[ringTimeStepCount]}] -! The relative ring duration. If not sticky (see argument below), -! alarms rings for ringTimeStepCount, then turns itself off. -! Default is 1: a non-sticky alarm will ring for one clock time step. -! Mutually exclusive with ringDuration (above); used if -! ringTimeStepCount > 1. If ringTimeStepCount is 1 (default) and -! ringDuration is non-zero, ringDuration is used (see above), otherwise -! ringTimeStepCount is used. -! See also {\tt ESMF\_AlarmSticky()}, {\tt ESMF\_AlarmNotSticky()}. -! \item[{[refTime]}] -! The reference (i.e. base) time for an interval alarm. +! The ring interval for repeating (interval) alarms. +! Must specify at least one of ringTime or ringInterval. If ringInterval +! is not specified, the alarm will only ring at ringTime effectively +! making the alarm a one shot alarm. When both ringTime and ringInterval +! are specified, alarm rings intermittently starting at ringTime every +! ringInterval. ! \item[{[enabled]}] ! Sets the enabled state; default is on (true). If disabled, ! an alarm will not function at all. @@ -406,9 +384,6 @@ function ESMF_AlarmCreateNew(clock, keywordEnforcer, & ESMF_INIT_CHECK_DEEP(ESMF_ClockGetInit,clock,rc) ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,ringTime,rc) ESMF_INIT_CHECK_SHALLOW(ESMF_TimeIntervalGetInit,ringInterval,rc) - ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,stopTime,rc) - ESMF_INIT_CHECK_SHALLOW(ESMF_TimeIntervalGetInit,ringDuration,rc) - ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,refTime,rc) ! get length of given name for C++ validation if (present(name)) then @@ -417,8 +392,7 @@ function ESMF_AlarmCreateNew(clock, keywordEnforcer, & ! invoke C to C++ entry point to allocate and initialize new alarm call c_ESMC_AlarmCreateNew(ESMF_AlarmCreateNew, nameLen, name, clock, & - ringTime, ringInterval, stopTime, & - ringDuration, ringTimeStepCount, refTime, & + ringTime, ringInterval, & enabled, sticky, localrc) if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, & ESMF_CONTEXT, rcToReturn=rc)) return @@ -660,28 +634,19 @@ end subroutine ESMF_AlarmEnable ! !INTERFACE: subroutine ESMF_AlarmGet(alarm, keywordEnforcer, & - clock, ringTime, prevRingTime, ringInterval, stopTime, ringDuration, & - ringTimeStepCount, timeStepRingingCount, ringBegin, ringEnd, & - refTime, ringing, ringingOnPrevTimeStep, enabled, sticky, name, rc) + clock, ringTime, ringInterval, & + ringing, enabled, sticky, ringerIsOn, name, rc) ! !ARGUMENTS: type(ESMF_Alarm), intent(in) :: alarm type(ESMF_KeywordEnforcer), optional:: keywordEnforcer ! must use keywords below type(ESMF_Clock), intent(out), optional :: clock type(ESMF_Time), intent(out), optional :: ringTime - type(ESMF_Time), intent(out), optional :: prevRingTime type(ESMF_TimeInterval), intent(out), optional :: ringInterval - type(ESMF_Time), intent(out), optional :: stopTime - type(ESMF_TimeInterval), intent(out), optional :: ringDuration - integer, intent(out), optional :: ringTimeStepCount - integer, intent(out), optional :: timeStepRingingCount - type(ESMF_Time), intent(out), optional :: ringBegin - type(ESMF_Time), intent(out), optional :: ringEnd - type(ESMF_Time), intent(out), optional :: refTime logical, intent(out), optional :: ringing - logical, intent(out), optional :: ringingOnPrevTimeStep logical, intent(out), optional :: enabled logical, intent(out), optional :: sticky + logical, intent(out), optional :: ringerIsOn character (len=*), intent(out), optional :: name integer, intent(out), optional :: rc @@ -701,51 +666,21 @@ subroutine ESMF_AlarmGet(alarm, keywordEnforcer, & ! \item[{[clock]}] ! The associated clock. ! \item[{[ringTime]}] -! The ring time for a one-shot alarm or the next repeating alarm. -! \item[{[prevRingTime]}] -! The previous ring time. +! The associated clock's time at which the alarm is ringing. ! \item[{[ringInterval]}] ! The ring interval for repeating (interval) alarms. -! \item[{[stopTime]}] -! The stop time for repeating (interval) alarms. -! \item[{[ringDuration]}] -! The ring duration. Mutually exclusive with -! ringTimeStepCount (see below). -! \item[{[ringTimeStepCount]}] -! The number of time steps comprising the ring duration. Mutually -! exclusive with ringDuration (see above). -! \item[{[timeStepRingingCount]}] -! The number of time steps for which the alarm has been ringing thus -! far. Used internally for tracking ringTimeStepCount ring -! durations (see above). Mutually exclusive with ringBegin -! (see below). Increments in {\tt ESMF\_DIRECTION\_FORWARD} and -! decrements in {\tt ESMF\_DIRECTION\_REVERSE}; -! see Section~\ref{sec:Clock}. -! \item[{[ringBegin]}] -! The time when the alarm began ringing. Used internally for tracking -! ringDuration (see above). Mutually exclusive with -! timeStepRingingCount (see above). -! \item[{[ringEnd]}] -! \begin{sloppypar} -! The time when the alarm ended ringing. Used internally for -! re-ringing alarm in {\tt ESMF\_DIRECTION\_REVERSE}. -! \end{sloppypar} -! \item[{[refTime]}] -! The reference (i.e. base) time for an interval alarm. ! \item[{[ringing]}] ! The current ringing state. ! See also {\tt ESMF\_AlarmRingerOn()}, {\tt ESMF\_AlarmRingerOff()}. -! \item[{[ringingOnPrevTimeStep]}] -! \begin{sloppypar} -! The ringing state upon the previous time step. Same as -! {\tt ESMF\_AlarmWasPrevRinging()}. -! \end{sloppypar} ! \item[{[enabled]}] ! The enabled state. ! See also {\tt ESMF\_AlarmEnable()}, {\tt ESMF\_AlarmDisable()}. ! \item[{[sticky]}] ! The sticky state. ! See also {\tt ESMF\_AlarmSticky()}, {\tt ESMF\_AlarmNotSticky()}. +! \item[{[ringerIsOn]}] +! The ringer state. +! See also {\tt ESMF\_AlarmRingerOn()}, {\tt ESMF\_AlarmRingerOff()}. ! \item[{[name]}] ! The name of this alarm. ! \item[{[rc]}] @@ -779,10 +714,8 @@ subroutine ESMF_AlarmGet(alarm, keywordEnforcer, & ! invoke C to C++ entry point call c_ESMC_AlarmGet(alarm, nameLen, tempNameLen, tempName, clock, & - ringTime, prevRingTime, ringInterval, stopTime, & - ringDuration, ringTimeStepCount, & - timeStepRingingCount, ringBegin, ringEnd, refTime, & - ringing, ringingOnPrevTimeStep, enabled, sticky, localrc) + ringTime, ringInterval, & + ringing, enabled, sticky, ringerIsOn, localrc) if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, & ESMF_CONTEXT, rcToReturn=rc)) return @@ -795,13 +728,7 @@ subroutine ESMF_AlarmGet(alarm, keywordEnforcer, & ! mark outputs as successfully initialized call ESMF_ClockSetInitCreated(clock) call ESMF_TimeInit(ringTime) - call ESMF_TimeInit(prevRingTime) call ESMF_TimeIntervalInit(ringInterval) - call ESMF_TimeInit(stopTime) - call ESMF_TimeIntervalInit(ringDuration) - call ESMF_TimeInit(ringBegin) - call ESMF_TimeInit(ringEnd) - call ESMF_TimeInit(refTime) ! Return success if (present(rc)) rc = ESMF_SUCCESS @@ -1340,8 +1267,8 @@ end subroutine ESMF_AlarmRingerOn ! !INTERFACE: subroutine ESMF_AlarmSet(alarm, keywordEnforcer, & - clock, ringTime, ringInterval, stopTime, ringDuration, & - ringTimeStepCount, refTime, ringing, enabled, sticky, name, rc) + clock, ringTime, ringInterval, & + ringing, enabled, sticky, name, rc) ! !ARGUMENTS: type(ESMF_Alarm), intent(inout) :: alarm @@ -1349,10 +1276,6 @@ subroutine ESMF_AlarmSet(alarm, keywordEnforcer, & type(ESMF_Clock), intent(in), optional :: clock type(ESMF_Time), intent(in), optional :: ringTime type(ESMF_TimeInterval), intent(in), optional :: ringInterval - type(ESMF_Time), intent(in), optional :: stopTime - type(ESMF_TimeInterval), intent(in), optional :: ringDuration - integer, intent(in), optional :: ringTimeStepCount - type(ESMF_Time), intent(in), optional :: refTime logical, intent(in), optional :: ringing logical, intent(in), optional :: enabled logical, intent(in), optional :: sticky @@ -1446,9 +1369,6 @@ subroutine ESMF_AlarmSet(alarm, keywordEnforcer, & ESMF_INIT_CHECK_DEEP(ESMF_ClockGetInit,clock,rc) ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,ringTime,rc) ESMF_INIT_CHECK_SHALLOW(ESMF_TimeIntervalGetInit,ringInterval,rc) - ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,stopTime,rc) - ESMF_INIT_CHECK_SHALLOW(ESMF_TimeIntervalGetInit,ringDuration,rc) - ESMF_INIT_CHECK_SHALLOW(ESMF_TimeGetInit,refTime,rc) ! get length of given name for C++ validation if (present(name)) then @@ -1457,8 +1377,7 @@ subroutine ESMF_AlarmSet(alarm, keywordEnforcer, & ! invoke C to C++ entry point call c_ESMC_AlarmSet(alarm, nameLen, name, clock, ringTime, & - ringInterval, stopTime, ringDuration, & - ringTimeStepCount, refTime, ringing, & + ringInterval, ringing, & enabled, sticky, localrc) if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, & ESMF_CONTEXT, rcToReturn=rc)) return diff --git a/src/Infrastructure/TimeMgr/interface/ESMF_Clock.F90 b/src/Infrastructure/TimeMgr/interface/ESMF_Clock.F90 index 9bd932cd17..e7f2053388 100644 --- a/src/Infrastructure/TimeMgr/interface/ESMF_Clock.F90 +++ b/src/Infrastructure/TimeMgr/interface/ESMF_Clock.F90 @@ -51,7 +51,8 @@ module ESMF_ClockMod use ESMF_TimeMod use ESMF_TimeTypeMod use ESMF_AlarmTypeMod - + use ESMF_AlarmMod + use ESMF_VMMod ! type definition for this module use ESMF_ClockTypeMod @@ -113,6 +114,11 @@ module ESMF_ClockMod private ESMF_ClockCreateNew private ESMF_ClockCreateCopy +! !PUBLIC MEMBER FUNCTIONS: + public ESMF_TimeDebug + public ESMF_TimeIntervalDebug + public ESMF_AlarmDebug + public ESMF_ClockDebug !------------------------------------------------------------------------------ ! The following line turns the CVS identifier string into a printable variable. character(*), parameter, private :: version = & @@ -2062,5 +2068,141 @@ impure elemental function ESMF_ClockNE(clock1, clock2) end function ESMF_ClockNE !------------------------------------------------------------------------------ +#undef ESMF_METHOD +#define ESMF_METHOD "ESMF_TimeIntervalDebug()" + + subroutine ESMF_TimeIntervalDebug(TimeIV, name, rc) + type (ESMF_TimeInterval), intent(in) :: TimeIV + character(len=*), intent(in) :: name + integer, intent(out) :: rc + + type (ESMF_VM) :: vm + integer :: lpet, npet, yy, mm, dd, d, h, m, s + + rc = ESMF_SUCCESS + call ESMF_VMGetCurrent(vm, rc=rc) + if (ESMF_LogFoundError(rc, ESMF_ERR_PASSTHRU, & + ESMF_CONTEXT, rcToReturn=rc)) return + + call ESMF_VMGet(vm, localpet =lpet, petcount=npet, rc=rc) + if (ESMF_LogFoundError(rc, ESMF_ERR_PASSTHRU, & + ESMF_CONTEXT, rcToReturn=rc)) return + + call ESMF_TimeIntervalGet(TimeIV, yy=yy, mm=mm, d=d, h=h, m=m, s=s, rc=rc) + if (ESMF_LogFoundError(rc, ESMF_ERR_PASSTHRU, & + ESMF_CONTEXT, rcToReturn=rc)) return + + if(lpet == 0) then + write(*, '(A, A, 2I4, I10, 3I4)') 'TimeInterval Debug Printout: ', name, yy, mm, d, h, m, s + endif + + end subroutine ESMF_TimeIntervalDebug + +#undef ESMF_METHOD +#define ESMF_METHOD "ESMF_TimeDebug()" + subroutine ESMF_TimeDebug(Time, name, rc) + type (ESMF_Time), intent(in) :: Time + character(len=*), intent(in) :: name + integer, intent(out) :: rc + + type (ESMF_VM) :: vm + integer :: lpet, npet, yy, mm, dd, d, h, m, s + + rc = ESMF_SUCCESS + call ESMF_VMGetCurrent(vm, rc=rc) + if (ESMF_LogFoundError(rc, ESMF_ERR_PASSTHRU, & + ESMF_CONTEXT, rcToReturn=rc)) return + + call ESMF_VMGet(vm, localpet =lpet, petcount=npet, rc=rc) + if (ESMF_LogFoundError(rc, ESMF_ERR_PASSTHRU, & + ESMF_CONTEXT, rcToReturn=rc)) return + + call ESMF_TimeGet(Time, yy=yy, mm=mm, dd=dd, h=h, m=m, s=s, rc=rc) + if (ESMF_LogFoundError(rc, ESMF_ERR_PASSTHRU, & + ESMF_CONTEXT, rcToReturn=rc)) return + + if(lpet == 0) then + write(*, '(A, A, 6I4)') 'Time Debug Printout: ', name, yy, mm, dd, h, m, s + endif + + end subroutine ESMF_TimeDebug + +#undef ESMF_METHOD +#define ESMF_METHOD "ESMF_AlarmDebug()" + subroutine ESMF_AlarmDebug(alarm, name, rc) + type (ESMF_Alarm), intent(in) :: alarm + character(len=*), intent(in) :: name + integer, intent(out) :: rc + + type (ESMF_VM) :: vm + integer :: lpet, npet + logical :: ringing, enabled, sticky, ringerIsOn + type (ESMF_Time) :: ringTime + type (ESMF_TimeInterval) :: ringInterval + + rc = ESMF_SUCCESS + + call ESMF_VMGetCurrent(vm, rc=rc) + if (ESMF_LogFoundError(rc, ESMF_ERR_PASSTHRU, & + ESMF_CONTEXT, rcToReturn=rc)) return + + call ESMF_VMGet(vm, localpet =lpet, petcount=npet, rc=rc) + if (ESMF_LogFoundError(rc, ESMF_ERR_PASSTHRU, & + ESMF_CONTEXT, rcToReturn=rc)) return + + ringing = .false. + enabled = .false. + sticky = .false. + ringerIsOn = .false. + + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, ringerIsOn=ringerIsOn, & + ringTime=ringTime, ringInterval=ringInterval, rc=rc) + if (ESMF_LogFoundError(rc, ESMF_ERR_PASSTHRU, & + ESMF_CONTEXT, rcToReturn=rc)) return + + if(lpet == 0) then + write(*, '(A,A)') 'Alarm Debug Printout: ', name + print *, 'ringing = ', ringing + print *, 'enabled = ', enabled + print *, 'sticky = ' , sticky + print *, 'ringerIsOn = ' , ringerIsOn + call ESMF_TimeDebug(ringTime, ' ringTime = ', rc=rc) + call ESMF_TimeIntervalDebug(ringInterval, 'ringInterval', rc=rc) + print *, '' + endif + end subroutine ESMF_AlarmDebug + + subroutine ESMF_ClockDebug(clock, name, rc) + type (ESMF_Clock), intent(in) :: clock + character(len=*), intent(in) :: name + integer, intent(out) :: rc + + type (ESMF_VM) :: vm + integer :: lpet, npet, alarmCount + logical :: ringing, enabled, sticky, ringingOnPrevTimeStep, alarmRinging + type (ESMF_Time) :: currTime, ringTime, prevRingTime, stopTime, ringBegin, ringEnd, ringRef + type (ESMF_TimeInterval) :: ringInterval, ringDuration + + rc = ESMF_SUCCESS + + call ESMF_VMGetCurrent(vm, rc=rc) + if (ESMF_LogFoundError(rc, ESMF_ERR_PASSTHRU, & + ESMF_CONTEXT, rcToReturn=rc)) return + + call ESMF_VMGet(vm, localpet =lpet, petcount=npet, rc=rc) + if (ESMF_LogFoundError(rc, ESMF_ERR_PASSTHRU, & + ESMF_CONTEXT, rcToReturn=rc)) return + + call ESMF_ClockGet(clock, currTime=currTime, alarmCount=alarmCount, rc=rc) + if (ESMF_LogFoundError(rc, ESMF_ERR_PASSTHRU, & + ESMF_CONTEXT, rcToReturn=rc)) return + + if(lpet == 0) then + write(*, '(A, A)') 'Clock Debug Printout: ', name + write(*, *) 'AlarmCount = ', alarmCount + call ESMF_TimeDebug(currTime, ' currTime = ', rc=rc) + write(*, *) '' + endif +end subroutine ESMF_ClockDebug end module ESMF_ClockMod diff --git a/src/Infrastructure/TimeMgr/src/ESMCI_Alarm.C b/src/Infrastructure/TimeMgr/src/ESMCI_Alarm.C index 6959336cd2..702b483e3e 100644 --- a/src/Infrastructure/TimeMgr/src/ESMCI_Alarm.C +++ b/src/Infrastructure/TimeMgr/src/ESMCI_Alarm.C @@ -27,9 +27,12 @@ #include #include #include +#include #include "ESMCI_LogErr.h" #include "ESMCI_Clock.h" +#include "ESMCI_Util.h" +#include "ESMCI_Macros.h" //------------------------------------------------------------------------- // leave the following line as-is; it will insert the cvs ident string @@ -64,13 +67,9 @@ int Alarm::count=0; // !ARGUMENTS: int nameLen, // in const char *name, // in - Clock *clock, // in - Time *ringTime, // in - TimeInterval *ringInterval, // in - Time *stopTime, // in - TimeInterval *ringDuration, // in - int *ringTimeStepCount, // in - Time *refTime, // in + Clock *clock, // in + Time *ringTime, // in + TimeInterval *ringInterval, // in bool *enabled, // in bool *sticky, // in int *rc ) { // out - return code @@ -129,59 +128,61 @@ int Alarm::count=0; sprintf(alarm->name, "Alarm%3.3d", alarm->id); } - if (ringTime != ESMC_NULL_POINTER) { - alarm->ringTime = alarm->prevRingTime = alarm->firstRingTime = *ringTime; - } + if (ringTime != ESMC_NULL_POINTER) + alarm->ringTime = *ringTime; + else + alarm->ringTime = clock->currTime; + if (ringInterval != ESMC_NULL_POINTER) { - alarm->ringInterval = *ringInterval; + TimeInterval zeroTimeInterval(0,0,1,0,0,0); + if(*ringInterval < zeroTimeInterval){ + ESMC_LogDefault.MsgFoundError(ESMC_RC_ARG_BAD, + "; Cannot set negative ringInterval", ESMC_CONTEXT, rc); + return 0; + } - // if ringTime not specified, calculate - // ringTime from the current clock time + if(*ringInterval < clock->timeStep) { + ESMC_LogDefault.MsgFoundError(ESMC_RC_ARG_BAD, + "; alarm Interval cannot be less than clock interval", ESMC_CONTEXT, rc); + return 0; + } - // TODO: handle case where *ringTime < clock->currTime; - // same or similar to refTime - - if (ringTime == ESMC_NULL_POINTER) { - // works for positive or negative ringInterval - alarm->ringTime = clock->currTime + alarm->ringInterval; - alarm->prevRingTime = alarm->firstRingTime = alarm->ringTime; + if( ( *ringInterval == clock->timeStep) ){ + int n = (alarm->ringTime - clock->currTime)/(*ringInterval); + //std::cout << n << std::endl; + //ringTime->print(); + //clock->currTime.print(); + //ringInterval->print(); + if(alarm->ringTime != (clock->currTime + n*(*ringInterval)) ){ + ESMC_LogDefault.MsgFoundError(ESMC_RC_ARG_BAD, + "; alarm Interval is the same as clock interval, ringTime cannot be misaligned with clock time, alarm will never ring", ESMC_CONTEXT, rc); + return 0; + } } + + // We do not check LCM because any two rational numbers are guranteed to have + // LCM albeit it may be very large. + alarm->ringInterval = *ringInterval; + + }else{ + // A negative ringInterval indicates a one shot alarm at ringTime only + TimeInterval zeroTimeInterval(0,0,1,0,0,0); + if(clock->timeStep < zeroTimeInterval) + alarm->ringInterval = clock->timeStep; + alarm->ringInterval = -clock->timeStep; } - if (stopTime != ESMC_NULL_POINTER) { - alarm->stopTime = *stopTime; - } - if (ringDuration != ESMC_NULL_POINTER) { - alarm->ringDuration = *ringDuration; - } - if (ringTimeStepCount != ESMC_NULL_POINTER) { - alarm->ringTimeStepCount = *ringTimeStepCount; - } - if (refTime != ESMC_NULL_POINTER) { - alarm->refTime = *refTime; - // TODO: for ringInterval, calculate 1st ringTime > clock->currTime, - // (&& > ringTime, if specified), using refTime as the base. - } else { - // TODO: default to clock's current time (or ringTime, if specified?) - } + if (enabled != ESMC_NULL_POINTER) { alarm->enabled = *enabled; } if (sticky != ESMC_NULL_POINTER) { alarm->sticky = *sticky; } - - // TODO: invoke private method, shared with Alarm::set(), to calculate - // first ringTime for interval alarms, given ringInterval and none, - // one or both of refTime and ringTime. Will replace logic in - // corresponding above sections. - // this->ringTime > clock->currTime && - // this->ringTime > (passed in) ringTime + alarm->ringerIsOn = true; returnCode = alarm->Alarm::validate(); if (ESMC_LogDefault.MsgFoundError(returnCode, ESMCI_ERR_PASSTHRU, ESMC_CONTEXT, rc)) { - // TODO: distinguish non-fatal rc's (warnings, info) at this level (C++), - // and at the F90 level, so isInit flag can be set to usable value. delete alarm; return(ESMC_NULL_POINTER); } else { @@ -191,7 +192,12 @@ int Alarm::count=0; ESMC_LogDefault.MsgFoundError(returnCode, ESMCI_ERR_PASSTHRU, ESMC_CONTEXT, rc); } - + + for (int i = 0; i < SAVESIZE; i ++){ + alarm->alarms.push_back(*alarm); + alarm->clocks.push_back(*clock); + } + return(alarm); } // end ESMCI_alarmCreate (new) @@ -317,13 +323,9 @@ int Alarm::count=0; // !ARGUMENTS: int nameLen, // in const char *name, // in - Clock **clock, // in - Time *ringTime, // in - TimeInterval *ringInterval, // in - Time *stopTime, // in - TimeInterval *ringDuration, // in - int *ringTimeStepCount, // in - Time *refTime, // in + Clock **clock, // in + Time *ringTime, // in + TimeInterval *ringInterval, // in bool *ringing, // in bool *enabled, // in bool *sticky) { // in @@ -392,23 +394,17 @@ int Alarm::count=0; } } if (ringInterval != ESMC_NULL_POINTER) { + TimeInterval zeroTimeInterval(0,0,1,0,0,0); + if(*ringInterval < zeroTimeInterval){ + ESMC_LogDefault.MsgFoundError(ESMC_RC_ARG_BAD, + "; Cannot set negative ringInterval", ESMC_CONTEXT, &rc); + return 0; + } if (this->ringInterval != *ringInterval) { this->ringInterval = *ringInterval; this->userChangedRingInterval = true; } } - if (stopTime != ESMC_NULL_POINTER) { - this->stopTime = *stopTime; - } - if (ringDuration != ESMC_NULL_POINTER) { - this->ringDuration = *ringDuration; - } - if (ringTimeStepCount != ESMC_NULL_POINTER) { - this->ringTimeStepCount = *ringTimeStepCount; - } - if (refTime != ESMC_NULL_POINTER) { - this->refTime = *refTime; - } if (ringing != ESMC_NULL_POINTER) { this->ringing = *ringing; } @@ -417,8 +413,10 @@ int Alarm::count=0; } if (sticky != ESMC_NULL_POINTER) { this->sticky = *sticky; + if(*sticky) enableSticky(); } - + + // Looks like this implementation is not complete. // TODO: invoke private method, shared with ESMCI_alarmCreate(), to // calculate next ringTime for interval alarms, given ringInterval // and none, one or both of refTime and ringTime. Will replace @@ -438,6 +436,12 @@ int Alarm::count=0; } // end Alarm::set +void Alarm::enableSticky(void){ + // 1/100th of a second granuality to ensure integer return when being divided by + //this->ringInterval=TimeInterval(0, 1, 100, 0, 0, 0); + this->ringInterval=TimeInterval(1, 0, 1, 0, 0, 0); +} + //------------------------------------------------------------------------- //BOP // !IROUTINE: Alarm::get - Gets an alarm's properties @@ -454,19 +458,11 @@ int Alarm::count=0; char *tempName, // out Clock **clock, // out Time *ringTime, // out - Time *prevRingTime, // out TimeInterval *ringInterval, // out - Time *stopTime, // out - TimeInterval *ringDuration, // out - int *ringTimeStepCount, // out - int *timeStepRingingCount, // out - Time *ringBegin, // out - Time *ringEnd, // out - Time *refTime, // out bool *ringing, // out - bool *ringingOnPrevTimeStep, // out bool *enabled, // out - bool *sticky) { // out + bool *sticky, // out + bool *ringerIsOn) { // out // // !DESCRIPTION: // Gets {\tt ESMC\_Alarm} property values; @@ -513,45 +509,21 @@ int Alarm::count=0; if (ringTime != ESMC_NULL_POINTER) { *ringTime = this->ringTime; } - if (prevRingTime != ESMC_NULL_POINTER) { - *prevRingTime = this->prevRingTime; - } if (ringInterval != ESMC_NULL_POINTER) { *ringInterval = this->ringInterval; } - if (stopTime != ESMC_NULL_POINTER) { - *stopTime = this->stopTime; - } - if (ringDuration != ESMC_NULL_POINTER) { - *ringDuration = this->ringDuration; - } - if (ringTimeStepCount != ESMC_NULL_POINTER) { - *ringTimeStepCount = this->ringTimeStepCount; - } - if (timeStepRingingCount != ESMC_NULL_POINTER) { - *timeStepRingingCount = this->timeStepRingingCount; - } - if (ringBegin != ESMC_NULL_POINTER) { - *ringBegin = this->ringBegin; - } - if (ringEnd != ESMC_NULL_POINTER) { - *ringEnd = this->ringEnd; - } - if (refTime != ESMC_NULL_POINTER) { - *refTime = this->refTime; - } if (ringing != ESMC_NULL_POINTER) { *ringing = this->ringing; } - if (ringingOnPrevTimeStep != ESMC_NULL_POINTER) { - *ringingOnPrevTimeStep = this->ringingOnPrevTimeStep; - } if (enabled != ESMC_NULL_POINTER) { *enabled = this->enabled; } if (sticky != ESMC_NULL_POINTER) { *sticky = this->sticky; } + if (ringerIsOn != ESMC_NULL_POINTER) { + *ringerIsOn = this->ringerIsOn; + } rc = ESMF_SUCCESS; return(rc); @@ -712,6 +684,7 @@ int Alarm::count=0; return(ESMF_FAILURE); } + ringerIsOn = true; ringing = true; rc = ESMF_SUCCESS; @@ -752,6 +725,7 @@ int Alarm::count=0; // turn alarm off ringing = false; + ringerIsOn = false; timeStepRingingCount = 0; if (clock->direction == ESMF_DIRECTION_FORWARD) { @@ -800,7 +774,7 @@ int Alarm::count=0; // bool is ringing or not // // !ARGUMENTS: - int *rc) const { // out - error return code + int *rc) const { // out - error return code // // !DESCRIPTION: // Checks if {\tt ESMC\_Alarm}'s ringing state is set. @@ -823,6 +797,9 @@ int Alarm::count=0; // Initialize return code; assume routine not implemented if (rc != ESMC_NULL_POINTER) *rc = ESMF_SUCCESS; + //Time clockTime = clock->currTime; + + //return(enabled && ringerIsOn && canRingAtTime(clockTime)); return(enabled && ringing); } // end Alarm::isRinging @@ -877,26 +854,8 @@ int Alarm::count=0; } // get clock's next time - Time clockNextTime; - clock->Clock::getNextTime(&clockNextTime, timeStep); - - // if specified, use passed-in timestep, otherwise use clock's - TimeInterval tStep = (timeStep != ESMC_NULL_POINTER) ? - *timeStep : clock->timeStep; - - // get timestep direction: positive or negative - bool positive = tStep.TimeInterval::absValue() == tStep ? true : false; - - // check if alarm will turn on - bool willRing = false; - if (enabled) { - willRing = (positive) ? - clockNextTime >= ringTime && clock->currTime < ringTime : - clockNextTime <= ringTime && clock->currTime > ringTime; - } - if (rc != ESMC_NULL_POINTER) *rc = ESMF_SUCCESS; - return(willRing); + return canRingAtNextTime(*clock, timeStep); } // end Alarm::willRingNext @@ -939,7 +898,10 @@ int Alarm::count=0; if (rc != ESMC_NULL_POINTER) *rc = ESMF_SUCCESS; - return(ringingOnPrevTimeStep); + // get clock's prev time + // Time clockTime = clock->currTime - clock->timeStep; + // return canRingAtTime(clockTime); + return ringingOnPrevTimeStep; } // end Alarm::wasPrevRinging @@ -1077,6 +1039,54 @@ int Alarm::count=0; } // end Alarm::isSticky +#define DEBUG 1 +bool Alarm::canRingAtTime(const Clock & clock) { + bool retval = false; + + // If clock's current time is ahead of alarm->ringTime, adjust alarm->ringTime until + // either ringTime equals clockTime or ringTime is greater than clockTime when + // clock runs forward; Or ringTime is less than clockTime when clock runs reverse. + + // Note ringInterval > 0 is a magnitude + Time clockTime = clock.currTime; + + // One shot alarm that can only ring at ringTime + TimeInterval zeroTimeInterval(0,0,1,0,0,0); + if( this->ringInterval < zeroTimeInterval){ + if(this->ringTime == clockTime ) + return true; + else + return false; + } + + if(clock.direction == ESMF_DIRECTION_FORWARD) { + while (this->ringTime < clockTime){ + this->ringTime = this->ringTime + this->ringInterval; + } + }else if(clock.direction == ESMF_DIRECTION_REVERSE){ + while (this->ringTime > clockTime){ + this->ringTime = this->ringTime - this->ringInterval; + } + } + + if(this->ringTime == clockTime) + retval = true; + + return retval; +} + +bool Alarm::canRingAtNextTime(Clock & clock, TimeInterval * timeStep) const { + bool retval = false; + + Time clockNextTime; + clock.Clock::getNextTime(&clockNextTime, timeStep); + + if(this->ringTime == clockNextTime) + retval = true; + + return retval; +} + //------------------------------------------------------------------------- //BOP // !IROUTINE: Alarm::checkRingTime - check if time to ring @@ -1117,320 +1127,85 @@ int Alarm::count=0; ESMC_LogDefault.Write(logMsg, ESMC_LOGMSG_WARN,ESMC_CONTEXT); return(false); } + bool canRing = canRingAtTime(*clock); // Check if the alarm can ring when time matches. - // get clock's timestep direction: positive or negative - bool positive = (clock->currAdvanceTimeStep.absValue() == - clock->currAdvanceTimeStep) ? true : false; - - if (clock->direction == ESMF_DIRECTION_FORWARD) { + if(sticky) { - // carry previous flag forward - ringingOnPrevTimeStep = ringingOnCurrTimeStep; - - // perform pre-checks first ... - - if (enabled) { - if (userChangedRingInterval) { - // check that user's new ringInterval is same sign as timeStep - TimeInterval zeroTimeStep; - if ((ringInterval > zeroTimeStep && - clock->currAdvanceTimeStep < zeroTimeStep) || - (ringInterval < zeroTimeStep && - clock->currAdvanceTimeStep > zeroTimeStep) ) { - ESMC_LogDefault.MsgFoundError(ESMC_RC_VAL_WRONG, - "; user changed alarm ringInterval, " - "which is not same sign as clock timeStep.", ESMC_CONTEXT, rc); - return(false); - } - } - if (userChangedRingTime) { - // check that user's new ringTime is within ringable range - if (positive ? clock->currTime > ringTime : - clock->currTime < ringTime) { - ESMC_LogDefault.MsgFoundError(ESMC_RC_VAL_OUTOFRANGE, - "; user changed alarm ringTime, " - "which is not within clock ringable range", ESMC_CONTEXT, rc); - return(false); - } - } - // if clock timeStep sign changed, adjust ringInterval accordingly - TimeInterval zeroTimeStep; - bool userChangedTimeStepSign = - ( (clock->currAdvanceTimeStep < zeroTimeStep && - clock->prevAdvanceTimeStep > zeroTimeStep) || - (clock->currAdvanceTimeStep > zeroTimeStep && - clock->prevAdvanceTimeStep < zeroTimeStep) ); - if (userChangedTimeStepSign) { - if (!userChangedRingInterval) { - // change sign to match clock timeStep - ringInterval *= -1; - ringDuration *= -1; - } - } - // if either clock timeStep sign changed or clock direction mode - // changed, pull back ringTime into ringable range - if (userChangedTimeStepSign || clock->userChangedDirection) { - if (!userChangedRingTime) { - bool stopTimeEnabled = - stopTime.Time::validate("initialized") == ESMF_SUCCESS; - while (positive ? clock->prevTime >= ringTime : - clock->prevTime <= ringTime) { - // check if ringing stopTime limit reached, TODO: test - if (stopTimeEnabled) { - if (positive ? ringTime >= (stopTime - ringInterval) : - ringTime <= (stopTime - ringInterval) ) break; - } - // otherwise increment it - prevRingTime = ringTime; - ringTime += ringInterval; - } - } - } - // done processing changed flags, reset if necessary - if (userChangedRingTime) userChangedRingTime = false; - if (userChangedRingInterval) userChangedRingInterval = false; - if (clock->userChangedDirection) clock->userChangedDirection = false; - } - - // ... then check if time to turn on alarm - if (!ringing && enabled) - Alarm::checkTurnOn(positive); - - // else if not sticky, check if time to turn off alarm - // (user is responsible for turning off sticky alarms via RingerOff()) - // TODO: maybe should not be else clause, just an "if" on its own, since - // ringTimeStepCount=0 would imply turning off in the same timeStep? But - // would need to move timeStepRingingCount++ up. - else if (!sticky && ringing && enabled) { - - // first check if next alarm time has been reached, - // then check if time to turn off alarm. - if (!Alarm::checkTurnOn(positive)) { - TimeInterval zeroTimeInterval(0,0,1,0,0,0); - if (ringTimeStepCount == 1 && - ringDuration != zeroTimeInterval) { // use ringDuration ... - TimeInterval cumulativeRinging; - cumulativeRinging = clock->currTime - ringBegin; - if (cumulativeRinging.TimeInterval::absValue() >= - ringDuration.TimeInterval::absValue()) { - ringingOnCurrTimeStep = ringing = false; - timeStepRingingCount = 0; - } - // ... otherwise use ringTimeStepCount - } else if (ringTimeStepCount >= 1) { - if (timeStepRingingCount >= ringTimeStepCount) { - ringingOnCurrTimeStep = ringing = false; - timeStepRingingCount = 0; - } - } // TODO: else error, ringTimeStepCount <= 0 (ringing counter is - // always positive) Validate() ? - } - } - - // count for how many clock time steps the alarm is ringing - if (ringing) timeStepRingingCount++; - - // ensure a sticky repeatable alarm's ringTime remains in ringable range, - // in case it is not turned off for a while, or if - // clock->timeStep >= ringInterval - TimeInterval zeroTimeInterval(0,0,1,0,0,0); - if (sticky && ringInterval != zeroTimeInterval && - clock->advanceCount != 0) { - //printf("ringTime before:\n"); - //print("ringTime string"); - bool stopTimeEnabled = - stopTime.Time::validate("initialized") == ESMF_SUCCESS; - // works for positive and negative ringIntervals TODO: test negative - while (positive ? clock->currTime >= ringTime : - clock->currTime <= ringTime) { - // check if ringing stopTime limit reached, TODO: test - if (stopTimeEnabled) { - if (positive ? ringTime >= (stopTime - ringInterval) : - ringTime <= (stopTime - ringInterval) ) break; - } - // otherwise increment it - prevRingTime = ringTime; - ringTime += ringInterval; - // TODO: if in practice, users use a timeStep which is much, much - // greater than ringInterval, then a single-step calculated - // approach to updating the ringTime, rather than a loop - // approach, may be more efficient. - } - //printf("ringTime after:\n"); - //print("ringTime string"); + /* A sticky alarm can ring for two reasons + * 1) it rang previously + * 2) it didn't ring but now it's the time to ring + */ + if(ringing || canRing){ // Set ringing true either because it's a sticky ringing alarm or time matches. + ringingOnPrevTimeStep = ringing; + ringing = true; + if (canRing) updateRingTime(rc); // If the alarm's time match clock time, advance ringTime + if (rc != ESMC_NULL_POINTER) *rc = ESMF_SUCCESS; + return (ringing && enabled); } + } - } else { // ESMF_DIRECTION_REVERSE - - // TODO: Make more robust by removing the following simplifying - // assumptions: - // - // 1) timeSteps are constant throughout clock run (including sign). - // 2) ringInterval, ringDuration are constant throughout clock run. - // 3) sticky alarms must have traversed through at least one alarm - // (to save the ringEnd time) in order to reverse. For - // repeating sticky alarms, previous ringEnds are assumed to be - // equally spaced by a constant ringInterval. - // - // The solution will involve saving clock and alarm state at every - // timeStep, which means dynamically allocated stacks (stacks of - // clock and alarm objects). These stacks can be - // initially sized at Create() time, then reallocated as necessary - // (upon those advance() calls which would require more space). - // Will need flag upon Create() for user to hint at need for - // this extra overhead for reversible clocks and alarms. - - // Note: Sticky alarms need to have been traversed forward in order - // to be reversed (to save ringEnd upon user RingerOff() event). - // In contrast, non-sticky alarms can be reversed without first - // having been traversed forward. This implies that the logic - // cannot use prev* state variables in order to step back; all - // state variables must be reconstructed from timeStep, - // ringInterval, and ringDuration. Hence the use of ringTimeEnd - // below. - - // if sticky alarm, must have traversed forward far enough to have - // called RingerOff(), causing the ringEnd time to be saved. - if(sticky && ringEnd.Time::validate("initialized") != ESMF_SUCCESS) { - char logMsg[2*ESMF_MAXSTR]; - sprintf(logMsg, "Sticky alarm %s cannot be reversed since it has " - "not been traversed forward and turned off via " - "a user call to ESMF_AlarmRingerOff(), thereby " - "enabling Time Manager to know the time to turn it " - "back on in reverse.", name); - ESMC_LogDefault.Write(logMsg, ESMC_LOGMSG_WARN,ESMC_CONTEXT); - return(false); - } + // Non-sticky one shot alarms, time must match + if (canRing){ + ringingOnPrevTimeStep = ringing; + ringing = true; + updateRingTime(rc); // If the alarm's time match clock time, advance ringTime + }else{ + ringing = false; + } - // adjust ring state variables if needed - // (pull back ringTime, etc. into ringable range if necessary) - - // ... adjust if sticky alarm ... - if (sticky) { - while ( ((positive && ringEnd > clock->currTime) || - (!positive && ringEnd < clock->currTime)) && - (ringTime != firstRingTime)) { - ringEnd -= ringInterval; - ringTime = prevRingTime; - prevRingTime -= ringInterval; - } - } - // ... or non-sticky alarm, if user just changed clock direction to - // REVERSE ... - if (clock->userChangedDirection) { - clock->userChangedDirection = false; // reset changed flag - if (!sticky) { - if (((positive && ringTime > (clock->currTime + clock->timeStep)) || - (!positive && ringTime < (clock->currTime + clock->timeStep))) && - (ringTime != firstRingTime)) { - ringTime = prevRingTime; - prevRingTime -= ringInterval; - Alarm::resetRingBegin(positive); - } - } - } + if (rc != ESMC_NULL_POINTER) *rc = ESMF_SUCCESS; - // ... then determine when alarm ended ringing in forward mode ... - Time ringTimeEnd; - if (enabled) { - if (sticky) { - ringTimeEnd = ringEnd; - } else { // non-sticky - TimeInterval zeroTimeInterval(0,0,1,0,0,0); - if (ringTimeStepCount == 1 && - ringDuration != zeroTimeInterval) { // use ringDuration ... - ringTimeEnd = ringBegin + ringDuration; - // ... otherwise use ringTimeStepCount - } else if (ringTimeStepCount >= 1) { - // If ringBegin hasn't been initialized, set ringBegin to clock's startTime - if(ringBegin.getCalendar() == NULL){ - ringBegin = clock->startTime; - } - ringTimeEnd = ringBegin + ringTimeStepCount * clock->timeStep; - } // TODO: else error, ringTimeStepCount <= 0 (ringing counter is - // always positive) Validate() ? - } - } + return(ringing && enabled); - // ... and use it to check if time to turn alarm back *on* in reverse mode - if (!ringing && enabled) { - if (sticky) { - ringingOnCurrTimeStep = ringing = (clock->currTime == ringTimeEnd); - } else { - ringingOnCurrTimeStep = ringing = (positive) ? - (clock->currTime < ringTimeEnd) && - (clock->currTime + clock->timeStep) >= ringTimeEnd : - // (negative) - (clock->currTime > ringTimeEnd) && - (clock->currTime + clock->timeStep) <= ringTimeEnd; - } + } // end Alarm::checkRingTime - // if just turned on, reconstruct the rest of the state of this - // alarm event - if (ringing) { - // determine what ringBegin was for this alarm event TODO:sticky only? - //Alarm::resetRingBegin(positive); +//------------------------------------------------------------------------- +//BOP +// !IROUTINE: Alarm::updateRingTime - update Alarm Ring Time +// +// !INTERFACE: + void Alarm::updateRingTime( +// +// !RETURN VALUE: +// bool is ringing or not +// +// !ARGUMENTS: + int *rc) { // out - error return code - // determine what the ending timeStepRingingCount was - // for this alarm event - timeStepRingingCount = - (int) ((clock->currTime - ringBegin) / clock->timeStep) + 1; - } +// !DESCRIPTION: +// Update ringTime and prevRingTime +// +//EOP +// !REQUIREMENTS: TMG4.4, 4.6 - // otherwise check if time to turn *non-sticky* alarm back *off* in - // reverse mode (user is responsible for turning off *sticky* alarms via - // RingerOff()) - } else if (!sticky && ringing && enabled) { - if (timeStepRingingCount <= 1) { // if count down to last one - - // turn alarm off - ringingOnCurrTimeStep = ringing = false; - timeStepRingingCount = 0; - - // look back and reset ringing times for previous alarm event, - // if not past firstRingTime - // TODO: remove assumption of constant ringInterval; allow for - // variable ringIntervals - if (ringTime != firstRingTime) { - ringTime = prevRingTime; - prevRingTime -= ringInterval; - TimeInterval zeroTimeInterval(0,0,1,0,0,0); - if (ringTimeStepCount == 1 && - ringDuration != zeroTimeInterval) { // use ringDuration ... - ringTimeEnd = ringTime + ringDuration; - // ... otherwise use ringTimeStepCount - } else if (ringTimeStepCount >= 1) { - ringTimeEnd = ringTime + ringTimeStepCount * clock->timeStep; - } // TODO: else error, ringTimeStepCount <= 0 (ringing counter is - // always positive) Validate() ? - } else { // reset to initial condition - prevRingTime = ringTime; - } - - // determine what ringBegin was for *previous* alarm event - Alarm::resetRingBegin(positive); - - } else { // keep alarm ringing - // reverse count for how many clock time steps the alarm was ringing - timeStepRingingCount--; - } + #undef ESMC_METHOD + #define ESMC_METHOD "ESMCI::Alarm::updateRingTime()" - } // if (!sticky) + if(ringing){ + prevRingTime = ringTime; - // reconstruct whether alarm was ringing on previous timeStep - if (enabled) { - ringingOnPrevTimeStep = (positive) ? - clock->prevTime >= ringTime && clock->prevTime < ringTimeEnd : - clock->prevTime <= ringTime && clock->prevTime > ringTimeEnd; - } + //if(clock->direction == ESMF_DIRECTION_FORWARD) + // ringTime = ringTime + ringInterval; + //else + // ringTime = ringTime - ringInterval; + } +} - } // end if ESMF_DIRECTION_REVERSE +void Alarm::clockChangeDirection(const ESMC_Direction & old_direction, + const ESMC_Direction & new_direction, + int * rc) { - if (rc != ESMC_NULL_POINTER) *rc = ESMF_SUCCESS; + #undef ESMC_METHOD + #define ESMC_METHOD "ESMCI::Alarm::clockChangeDirection()" - return(ringing && enabled); + // If the direction didn't change, do nothing + if(old_direction == new_direction ) return; - } // end Alarm::checkRingTime + if(old_direction == ESMF_DIRECTION_FORWARD) + ringTime = ringTime - ringInterval; // ringTime goes backward by 1 interval + else + ringTime = ringTime + ringInterval; // ringTime goes forward by 1 interval +} //------------------------------------------------------------------------- //BOP @@ -1731,14 +1506,6 @@ int Alarm::count=0; prevRingTime.Time::print(); } } - else if (strncmp(opts, "stoptime", 8) == 0) { - printf("stopTime = \n"); - if (strstr(opts, "string") != ESMC_NULL_POINTER) { - stopTime.Time::print("string"); - } else { - stopTime.Time::print(); - } - } else if (strncmp(opts, "ringbegin", 9) == 0) { printf("ringBegin = \n"); if (strstr(opts, "string") != ESMC_NULL_POINTER) { @@ -1755,17 +1522,6 @@ int Alarm::count=0; ringEnd.Time::print(); } } - else if (strncmp(opts, "reftime", 7) == 0) { - printf("refTime = \n"); - if (strstr(opts, "string") != ESMC_NULL_POINTER) { - refTime.Time::print("string"); - } else { - refTime.Time::print(); - } - } - else if (strncmp(opts, "timestepringingcount", 20) == 0) { - printf("timeStepRingingCount = %d\n", timeStepRingingCount); - } else if (strncmp(opts, "ringingonprevtimestep", 21) == 0) { printf("ringingOnPrevTimeStep = %s\n", ringingOnPrevTimeStep ? "true" : "false"); @@ -1787,14 +1543,11 @@ int Alarm::count=0; printf("name = %s\n", name); printf("ringInterval = \n"); ringInterval.TimeInterval::print(options); - printf("ringDuration = \n"); ringDuration.TimeInterval::print(options); printf("ringTime = \n"); ringTime.Time::print(options); printf("firstRingTime = \n"); firstRingTime.Time::print(options); printf("prevRingTime = \n"); prevRingTime.Time::print(options); - printf("stopTime = \n"); stopTime.Time::print(options); printf("ringBegin = \n"); ringBegin.Time::print(options); printf("ringEnd = \n"); ringEnd.Time::print(options); - printf("refTime = \n"); refTime.Time::print(options); printf("ringTimeStepCount = %d\n", ringTimeStepCount); printf("timeStepRingingCount = %d\n", timeStepRingingCount); printf("ringing = %s\n", ringing ? "true" : "false"); @@ -1842,7 +1595,7 @@ int Alarm::count=0; clock = ESMC_NULL_POINTER; ringTimeStepCount = 1; timeStepRingingCount = 0; - ringing = ringingOnCurrTimeStep = ringingOnPrevTimeStep = false; + ringing = ringingOnPrevTimeStep = false; userChangedRingTime = false; userChangedRingInterval = false; enabled = true; @@ -1920,72 +1673,6 @@ int Alarm::count=0; // Private methods //------------------------------------------------------------------------- -//------------------------------------------------------------------------- -//BOPI -// !IROUTINE: Alarm::checkTurnOn - check if time to turn on alarm -// -// !INTERFACE: - bool Alarm::checkTurnOn( -// -// !RETURN VALUE: -// bool whether to turn on alarm -// -// !ARGUMENTS: - bool timeStepPositive) { // in - sign of clock's timeStep, -// // true: positive, false: negative -// -// !DESCRIPTION: -// Checks whether alarm should be ringing -// -//EOPI -// !REQUIREMENTS: - - #undef ESMC_METHOD - #define ESMC_METHOD "ESMCI::Alarm::checkTurnOn()" - - // The original comment few lines below indicates that the ringing state - // would be turned off elsewhere. However, it is initialized (turn off) - // here for the sake of X1 compiler. That may be taken off later. - ringingOnCurrTimeStep = false; - - bool checkRinging; - - if (clock->advanceCount != 0) { // clock has been advanced; use prevTime - checkRinging = (timeStepPositive) ? - clock->currTime >= ringTime && clock->prevTime < ringTime : - clock->currTime <= ringTime && clock->prevTime > ringTime; - } else { // clock in initial state; don't use prevTime since - // it equals currTime - checkRinging = (timeStepPositive) ? - clock->currTime >= ringTime : - clock->currTime <= ringTime ; - } - - if (checkRinging) { - // if so, refresh ringing state; if not, leave previous state alone: - // turn off determined elsewhere. - ringingOnCurrTimeStep = ringing = true; - - // note time, - ringBegin = clock->currTime; - - // and update next ringing time - bool updateNextRingingTime = true; - if (stopTime.Time::validate("initialized") == ESMF_SUCCESS) { - updateNextRingingTime = (timeStepPositive) ? - clock->currTime < (stopTime - ringInterval): - clock->currTime > (stopTime - ringInterval); - } - if (updateNextRingingTime) { - prevRingTime = ringTime; - ringTime += ringInterval; - } - } - - return(checkRinging); - -} // end Alarm::checkTurnOn - //------------------------------------------------------------------------- //BOPI // !IROUTINE: Alarm::resetRingBegin - reset ringBegin during ESMF_DIRECTION_REVERSE diff --git a/src/Infrastructure/TimeMgr/src/ESMCI_Clock.C b/src/Infrastructure/TimeMgr/src/ESMCI_Clock.C index 875dba9fd4..c23b33acd6 100644 --- a/src/Infrastructure/TimeMgr/src/ESMCI_Clock.C +++ b/src/Infrastructure/TimeMgr/src/ESMCI_Clock.C @@ -365,6 +365,12 @@ int Clock::count=0; if (advanceCount != ESMC_NULL_POINTER) this->advanceCount = *advanceCount; if (direction != ESMC_NULL_POINTER) { + // traverse alarm list (i) to update ringTime + for(int i=0; iAlarm::clockChangeDirection(this->direction, *direction, &rc); + } + this->direction = *direction; this->userChangedDirection = true; } diff --git a/src/Infrastructure/TimeMgr/tests/ESMF_AlarmUTest.F90 b/src/Infrastructure/TimeMgr/tests/ESMF_AlarmUTest.F90 index d5882e08d9..5c2e30c801 100644 --- a/src/Infrastructure/TimeMgr/tests/ESMF_AlarmUTest.F90 +++ b/src/Infrastructure/TimeMgr/tests/ESMF_AlarmUTest.F90 @@ -86,7 +86,6 @@ program ESMF_AlarmTest ! instantiate timestep, start and stop times type(ESMF_TimeInterval) :: TIMEINTERVAL_HISTORY, alarmStep, alarmStep2 - type(ESMF_TimeInterval) :: runDuration, ringDuration type(ESMF_Time) :: currentTime, currTime, afterAlarmTime, beforeAlarmTime type(ESMF_Time) :: alarmStopTime, nextTime, prevTime, currentTime2, time1 @@ -114,6 +113,9 @@ program ESMF_AlarmTest esmf_360dayCalendar = ESMF_CalendarCreate(ESMF_CALKIND_360DAY, & name="360Day", rc=rc) + call ESMF_CalendarSetDefault ( ESMF_CALKIND_GREGORIAN, rc=rc ) + if(rc /= ESMF_SUCCESS) call ESMF_Finalize() + !------------------------------------------------------------------------------- ! The unit tests are divided into Sanity and Exhaustive. The Sanity tests are ! always run. When the environment variable, EXHAUSTIVE, is set to ON then @@ -507,26 +509,6 @@ program ESMF_AlarmTest ! ---------------------------------------------------------------------------- - !EX_UTest - !Test if destroyed Alarm Previously ringing - write(failMsg, *) " Did not return ESMF_RC_OBJ_DELETED" - write(name, *) "Destroyed Alarm Was Previously ringing Test" - bool = ESMF_AlarmWasPrevRinging(alarm1, rc=rc) - call ESMF_Test((rc.eq.ESMF_RC_OBJ_DELETED), & - name, failMsg, result, ESMF_SRCLINE) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test if non-created Alarm Previously ringing - write(failMsg, *) " Did not return ESMF_RC_OBJ_NOT_CREATED" - write(name, *) "Non-created Alarm Was Previously ringing Test" - bool = ESMF_AlarmWasPrevRinging(alarm6, rc=rc) - call ESMF_Test((rc.eq.ESMF_RC_OBJ_NOT_CREATED), & - name, failMsg, result, ESMF_SRCLINE) - - ! ---------------------------------------------------------------------------- - !EX_UTest write(failMsg, *) " Did not return ESMF_RC_OBJ_DELETED" write(name, *) "Turn off Ringing on destroyed Alarm " @@ -543,25 +525,6 @@ program ESMF_AlarmTest call ESMF_Test((rc.eq.ESMF_RC_OBJ_NOT_CREATED), & name, failMsg, result, ESMF_SRCLINE) - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test destroyed Alarm will ring next - write(failMsg, *) " Did not return ESMF_RC_OBJ_DELETED" - write(name, *) "Destroyed Alarm will ring next Test" - willRingNext = ESMF_AlarmWillRingNext(alarm1, timeStep=timeStep, rc=rc) - call ESMF_Test((rc.eq.ESMF_RC_OBJ_DELETED), & - name, failMsg, result, ESMF_SRCLINE) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test non-created Alarm will ring next - write(failMsg, *) " Did not return ESMF_RC_OBJ_NOT_CREATED" - write(name, *) "Non-created Alarm will ring next Test" - willRingNext = ESMF_AlarmWillRingNext(alarm6, timeStep=timeStep, rc=rc) - call ESMF_Test((rc.eq.ESMF_RC_OBJ_NOT_CREATED), & - name, failMsg, result, ESMF_SRCLINE) ! ---------------------------------------------------------------------------- @@ -1043,7 +1006,7 @@ program ESMF_AlarmTest ! Test Setting the Alarm Time write(failMsg, *) " Returned ESMF_FAILURE" write(name, *) "Set Alarm Time Initialization Test" - call ESMF_TimeSet(alarmTime, yy=2003, mm=3, dd=13, h=5, & + call ESMF_TimeSet(alarmTime, yy=2003, mm=3, dd=13, h=5, m=45, s=27, & calkindflag=ESMF_CALKIND_GREGORIAN, rc=rc) call ESMF_Test((rc.eq.ESMF_SUCCESS), & name, failMsg, result, ESMF_SRCLINE) @@ -1077,2444 +1040,447 @@ program ESMF_AlarmTest call ESMF_Test((rc.eq.ESMF_SUCCESS), & name, failMsg, result, ESMF_SRCLINE) - ! ---------------------------------------------------------------------------- + call ESMF_AlarmDestroy (alarm, rc=rc) + call ESMF_ClockDestroy (clock, rc=rc) - !EX_UTest - !Test Alarm will ring next - call ESMF_ClockAdvance(clock, rc=rc) - call ESMF_ClockAdvance(clock, rc=rc) - write(failMsg, *) " Did not return ESMF_SUCCESS or returned wrong state" - write(name, *) "Alarm will ring next Test" - willRingNext = ESMF_AlarmWillRingNext(alarm, timeStep=timeStep, rc=rc) - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(.not.willRingNext), & - name, failMsg, result, ESMF_SRCLINE) - ! ---------------------------------------------------------------------------- !EX_UTest - !Test Get Clock Next Time - write(failMsg, *) " Did not return ESMF_SUCCESS)" - write(name, *) "Get Clock Next Time Test" - call ESMF_ClockGetNextTime(clock, nextTime, timeStep=timeStep, rc=rc) + write(failMsg, *) " Did not return ESMF_SUCCESS" + write(name, *) "Forward Alarm Test Case 1" + call ForwardAlarm_Test1(rc=rc) call ESMF_Test((rc.eq.ESMF_SUCCESS), & name, failMsg, result, ESMF_SRCLINE) - + ! ---------------------------------------------------------------------------- !EX_UTest - !Test Alarm will ring next - call ESMF_ClockAdvance(clock, rc=rc) - write(failMsg, *) " Did not return ESMF_SUCCESS or returned wrong state" - write(name, *) "Alarm will ring next Test" - willRingNext = ESMF_AlarmWillRingNext(alarm, timeStep=timeStep, rc=rc) - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(willRingNext), & + write(failMsg, *) " Did not return ESMF_SUCCESS" + write(name, *) "Forward Alarm Test Case 2" + call ForwardAlarm_Test2(rc=rc) + call ESMF_Test((rc.eq.ESMF_SUCCESS), & name, failMsg, result, ESMF_SRCLINE) - + ! ---------------------------------------------------------------------------- !EX_UTest - !Test Get Time from clock write(failMsg, *) " Did not return ESMF_SUCCESS" - write(name, *) "Get Clock Current Time Test" - call ESMF_ClockGet(clock, currTime=currentTime, rc=rc) + write(name, *) "Forward Alarm Test Case 3" + call ForwardAlarm_Test3(rc=rc) call ESMF_Test((rc.eq.ESMF_SUCCESS), & name, failMsg, result, ESMF_SRCLINE) - + ! ---------------------------------------------------------------------------- !EX_UTest - !Test that Clock Get Next Time Passed - !Testing ESMF_TimeOperator(==)(time1,time2) - write(failMsg, *) " Next Time not equal to current Time" - write(name, *) "Get Clock Next Time Test" - bool = (nextTime == currentTime) ! exercising Time == operator - call ESMF_Test((bool), & + write(failMsg, *) " Did not return ESMF_SUCCESS" + write(name, *) "Forward Alarm Test Case 4" + call ForwardAlarm_Test4(rc=rc) + call ESMF_Test((rc.eq.ESMF_SUCCESS), & name, failMsg, result, ESMF_SRCLINE) - + ! ---------------------------------------------------------------------------- !EX_UTest - !Test Alarm ringing - call ESMF_ClockAdvance(clock, rc=rc) - write(failMsg, *) " Did not return ESMF_SUCCESS or returned wrong state" - write(name, *) "Alarm is ringing Test" - bool = ESMF_AlarmIsRinging(alarm, rc=rc) - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(bool), & + write(failMsg, *) " Did not return ESMF_SUCCESS" + write(name, *) "Forward Alarm Test Case 5" + call ForwardAlarm_Test5(rc=rc) + call ESMF_Test((rc.eq.ESMF_SUCCESS), & name, failMsg, result, ESMF_SRCLINE) - + ! ---------------------------------------------------------------------------- !EX_UTest - !Test Alarm still ringing - call ESMF_ClockAdvance(clock, rc=rc) - write(failMsg, *) " Did not return ESMF_SUCCESS or returned wrong state" - write(name, *) "Alarm is still ringing Test" - bool = ESMF_AlarmIsRinging(alarm, rc=rc) - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(bool), & + write(failMsg, *) " Did not return ESMF_SUCCESS" + write(name, *) "Forward Alarm Test Case 6" + call ForwardAlarm_Test6(rc=rc) + call ESMF_Test((rc.eq.ESMF_SUCCESS), & name, failMsg, result, ESMF_SRCLINE) - + ! ---------------------------------------------------------------------------- !EX_UTest - !Test Alarm Previously ringing - write(failMsg, *) " Did not return ESMF_SUCCESS or returned wrong state" - write(name, *) "Alarm Was Previously ringing Test" - bool = ESMF_AlarmWasPrevRinging(alarm, rc=rc) - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(bool), & + write(failMsg, *) " Did not return ESMF_SUCCESS" + write(name, *) "Forward Alarm Test Case 7" + call ForwardAlarm_Test7(rc=rc) + call ESMF_Test((rc.eq.ESMF_SUCCESS), & name, failMsg, result, ESMF_SRCLINE) - !print *, "bool is ", bool ! ---------------------------------------------------------------------------- !EX_UTest - !Test Alarm Previously ringing - call ESMF_ClockAdvance(clock, rc=rc) - write(failMsg, *) " Did not return ESMF_SUCCESS or returned wrong state" - write(name, *) "Alarm Was Previously ringing Test" - bool = ESMF_AlarmWasPrevRinging(alarm, rc=rc) - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(bool), & + write(failMsg, *) " Did not return ESMF_SUCCESS" + write(name, *) "Reverse Alarm Test Case 1" + call ReverseAlarm_Test1(rc=rc) + call ESMF_Test((rc.eq.ESMF_SUCCESS), & name, failMsg, result, ESMF_SRCLINE) ! ---------------------------------------------------------------------------- !EX_UTest - !Test Alarm still ringing - call ESMF_ClockAdvance(clock, rc=rc) - call ESMF_ClockAdvance(clock, rc=rc) - call ESMF_ClockAdvance(clock, rc=rc) - call ESMF_ClockAdvance(clock, rc=rc) - call ESMF_ClockAdvance(clock, rc=rc) - call ESMF_ClockAdvance(clock, rc=rc) - call ESMF_ClockAdvance(clock, rc=rc) - call ESMF_ClockAdvance(clock, rc=rc) - write(failMsg, *) " Did not return ESMF_SUCCESS or returned wrong state" - write(name, *) "Alarm is still ringing Test" - bool = ESMF_AlarmIsRinging(alarm, rc=rc) - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(bool), & + write(failMsg, *) " Did not return ESMF_SUCCESS" + write(name, *) "Reverse Alarm Test Case 2" + call ReverseAlarm_Test2(rc=rc) + call ESMF_Test((rc.eq.ESMF_SUCCESS), & name, failMsg, result, ESMF_SRCLINE) ! ---------------------------------------------------------------------------- !EX_UTest write(failMsg, *) " Did not return ESMF_SUCCESS" - write(name, *) "Turn off Ringing Alarm " - call ESMF_AlarmRingerOff(alarm, rc=rc) + write(name, *) "Reverse Alarm Test Case 3" + call ReverseAlarm_Test3(rc=rc) call ESMF_Test((rc.eq.ESMF_SUCCESS), & name, failMsg, result, ESMF_SRCLINE) ! ---------------------------------------------------------------------------- !EX_UTest - write(failMsg, *) " Did not return ESMF_SUCCESS or its ringing" - write(name, *) "Check if Alarm is not ringing Test" - isringing = ESMF_AlarmIsRinging(alarm, rc=rc) - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(.not.isringing), & + write(failMsg, *) " Did not return ESMF_SUCCESS" + write(name, *) "Reverse Alarm Test Case 4" + call ReverseAlarm_Test4(rc=rc) + call ESMF_Test((rc.eq.ESMF_SUCCESS), & name, failMsg, result, ESMF_SRCLINE) ! ---------------------------------------------------------------------------- !EX_UTest - !Test Alarm Previously ringing - write(failMsg, *) " Did not return ESMF_SUCCESS or returned wrong state" - write(name, *) "Alarm Was Previously ringing Test" - bool = ESMF_AlarmWasPrevRinging(alarm, rc=rc) - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(bool), & + write(failMsg, *) " Did not return ESMF_SUCCESS" + write(name, *) "Reverse Alarm Test Case 5" + call ReverseAlarm_Test5(rc=rc) + call ESMF_Test((rc.eq.ESMF_SUCCESS), & name, failMsg, result, ESMF_SRCLINE) ! ---------------------------------------------------------------------------- !EX_UTest - !Test Alarm Previously ringing - call ESMF_ClockAdvance(clock, rc=rc) - write(failMsg, *) " Did not return ESMF_SUCCESS or returned wrong state" - write(name, *) "Alarm Was Previously ringing Test" - bool = ESMF_AlarmWasPrevRinging(alarm, rc=rc) - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(bool), & + write(failMsg, *) " Did not return ESMF_SUCCESS" + write(name, *) "Reverse Alarm Test Case 6" + call ReverseAlarm_Test6(rc=rc) + call ESMF_Test((rc.eq.ESMF_SUCCESS), & name, failMsg, result, ESMF_SRCLINE) ! ---------------------------------------------------------------------------- !EX_UTest - !Test Alarm Previously ringing - call ESMF_ClockAdvance(clock, rc=rc) - write(failMsg, *) " Did not return ESMF_SUCCESS or returned wrong state" - write(name, *) "Alarm Was Previously ringing Test" - bool = ESMF_AlarmWasPrevRinging(alarm, rc=rc) - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(.not.bool), & + write(failMsg, *) " Did not return ESMF_SUCCESS" + write(name, *) "Forward then Reverse Alarm Test Case 1" + call ForwardReverseAlarm_Test1(rc=rc) + call ESMF_Test((rc.eq.ESMF_SUCCESS), & name, failMsg, result, ESMF_SRCLINE) - call ESMF_AlarmDestroy (alarm, rc=rc) - call ESMF_ClockDestroy (clock, rc=rc) ! ---------------------------------------------------------------------------- - ! Initialize clock !EX_UTest - write(name, *) "Clock Initialization Test" - write(failMsg, *) " Did not return ESMF_SUCCESS" - clock = ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & - name="Clock 1", rc=rc) - call ESMF_Test((rc.eq.ESMF_SUCCESS), & - name, failMsg, result, ESMF_SRCLINE) + write(failMsg, *) " Did not return ESMF_SUCCESS" + write(name, *) "Forward then Reverse Alarm Test Case 2" + call ForwardReverseAlarm_Test2(rc=rc) + call ESMF_Test((rc.eq.ESMF_SUCCESS), & + name, failMsg, result, ESMF_SRCLINE) ! ---------------------------------------------------------------------------- !EX_UTest write(failMsg, *) " Did not return ESMF_SUCCESS" - write(name, *) "Non-Sticky Alarm Time Initialization Test" - alarm = ESMF_AlarmCreate(name="alarm1", clock=clock, & - ringTime=alarmTime, sticky=.FALSE., rc=rc) + write(name, *) "Forward then Reverse Alarm Test Case 3" + call ForwardReverseAlarm_Test3(rc=rc) call ESMF_Test((rc.eq.ESMF_SUCCESS), & name, failMsg, result, ESMF_SRCLINE) - ! ---------------------------------------------------------------------------- - !EX_UTest - !Test Alarm will ring next - call ESMF_ClockAdvance(clock, rc=rc) - call ESMF_ClockAdvance(clock, rc=rc) - write(failMsg, *) " Did not return ESMF_SUCCESS or returned wrong state" - write(name, *) "Alarm will ring next Test" - willRingNext = ESMF_AlarmWillRingNext(alarm, timeStep=timeStep, rc=rc) - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(.not.willRingNext), & - name, failMsg, result, ESMF_SRCLINE) - ! ---------------------------------------------------------------------------- !EX_UTest - !Test Alarm will ring next - call ESMF_ClockAdvance(clock, rc=rc) - write(failMsg, *) " Did not return ESMF_SUCCESS or returned wrong state" - write(name, *) "Alarm will ring next Test" - willRingNext = ESMF_AlarmWillRingNext(alarm, timeStep=timeStep, rc=rc) - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(willRingNext), & - name, failMsg, result, ESMF_SRCLINE) - - ! ---------------------------------------------------------------------------- + write(failMsg, *) " Alarms with ClockSet... " + write(name, *) "Test ClockSet after alarm attached to clock, forward time " + call Test_ClockSet(doReverse=.false., testPass=testPass, rc=rc) + if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. + if (.not. testPass) print *, 'bad return codes discovered' + call ESMF_Test (testPass, name, failMsg, result, ESMF_SRCLINE) - !EX_UTest - !Test Alarm ringing - call ESMF_ClockAdvance(clock, rc=rc) - write(failMsg, *) " Did not return ESMF_SUCCESS or returned wrong state" - write(name, *) "Alarm is ringing Test" - bool = ESMF_AlarmIsRinging(alarm, rc=rc) - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(bool), & - name, failMsg, result, ESMF_SRCLINE) - ! ---------------------------------------------------------------------------- !EX_UTest - !Test Alarm still ringing - call ESMF_ClockAdvance(clock, rc=rc) - write(failMsg, *) " Did not return ESMF_SUCCESS or returned wrong state" - write(name, *) "Alarm is still ringing Test" - bool = ESMF_AlarmIsRinging(alarm, rc=rc) - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(.not.bool), & - name, failMsg, result, ESMF_SRCLINE) - + write(failMsg, *) " Alarms with ClockSet... " + write(name, *) "Test ClockSet after alarm attached to clock, reverse time " + call Test_ClockSet(doReverse=.true., testPass=testPass, rc=rc) + if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. + if (.not. testPass) print *, 'bad return codes discovered' + call ESMF_Test (testPass, name, failMsg, result, ESMF_SRCLINE) + ! ---------------------------------------------------------------------------- !EX_UTest - !Test Alarm Previously ringing - write(failMsg, *) " Did not return ESMF_SUCCESS or returned wrong state" - write(name, *) "Alarm Was Previously ringing Test" - bool = ESMF_AlarmWasPrevRinging(alarm, rc=rc) - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(bool), & - name, failMsg, result, ESMF_SRCLINE) - - !print *, "bool is ", bool + ! The following tests are from Ben@NASA's support ticket 3614994 + write(failMsg, *) " Alarms did not rewind correct number of times " + write(name, *) "Test multiple alarms rewind correct number of times " + call Test_ReverseAlarms(testPass, rc) + if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. + if (.not. testPass) print *, 'bad return codes discovered' + call ESMF_Test (testPass, name, failMsg, result, ESMF_SRCLINE) ! ---------------------------------------------------------------------------- !EX_UTest - !Test Alarm Previously ringing - call ESMF_ClockAdvance(clock, rc=rc) - write(failMsg, *) " Did not return ESMF_SUCCESS or returned wrong state" - write(name, *) "Alarm Was Previously ringing Test" - bool = ESMF_AlarmWasPrevRinging(alarm, rc=rc) - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(.not.bool), & - name, failMsg, result, ESMF_SRCLINE) - + write(failMsg, *) " Alarms hang... " + write(name, *) "Test multiple alarms replay without hanging " + call Test_AlarmHang(testPass, rc) + if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. + if (.not. testPass) print *, 'bad return codes discovered' + call ESMF_Test (testPass, name, failMsg, result, ESMF_SRCLINE) ! ---------------------------------------------------------------------------- !EX_UTest - !Test destroying alarm - write(failMsg, *) " Did not return ESMF_SUCCESS" - write(name, *) "Destroying alarm test" - call ESMF_AlarmDestroy (alarm, rc=rc) - call ESMF_Test(rc == ESMF_SUCCESS, name, failMsg, result, ESMF_SRCLINE) + write(failMsg, *) " Alarms with ring intervals equal to clock interval, incorrect behavior " + write(name, *) "Test running an alarms forward-reverse-forward with ring interval equal to clock interval " + call Test_AlarmAdvRewind(testPass, rc) + if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. + if (.not. testPass) print *, 'bad return codes discovered' + call ESMF_Test (testPass, name, failMsg, result, ESMF_SRCLINE) ! ---------------------------------------------------------------------------- !EX_UTest - !Test destroying clock after alarm - write(failMsg, *) " Did not return ESMF_SUCCESS" - write(name, *) "Destroying clock after alarm test" - call ESMF_ClockDestroy (clock, rc=rc) - call ESMF_Test(rc == ESMF_SUCCESS, name, failMsg, result, ESMF_SRCLINE) + write(failMsg, *) " Alarms with getPrevRingTime... " + write(name, *) "Test getPrevRingTime... after alarm attached to clock " + call Test_GetPrevRingTime(testPass, rc) + if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. + if (.not. testPass) print *, 'bad return codes discovered' + call ESMF_Test (testPass, name, failMsg, result, ESMF_SRCLINE) ! ---------------------------------------------------------------------------- + ! ---------------------------------------------------------------------------- +#endif - !EX_UTest - !Test Non-Sticky Alarms 1 - ! from Chris Hill via support issue 988241, bug 996229 - write(failMsg, *) " Did not return nstep=48, sstep=73, i=144, and ESMF_SUCCESS" - write(name, *) "Non-Sticky Alarm Test 1" - call ESMF_TimeIntervalSet(timeStep, s=100, rc=rc) - call ESMF_TimeIntervalSet(alarmStep, s=150, rc=rc) - call ESMF_TimeSet(startTime, yy=1999, mm=12, dd=31, h=23, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeSet(stopTime, yy=2000, mm=1, dd=1, h=3, & - calendar=gregorianCalendar, rc=rc) - clock2=ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & - name="Clock 2", rc=rc) - call ESMF_TimeSet(alarmTime, yy=2000, mm=1, dd=1, h=1, & - calendar=gregorianCalendar, rc=rc) - alarm4 = ESMF_AlarmCreate(clock=clock2, ringTime=alarmTime, & - ringInterval=alarmStep, sticky=.false., rc=rc) - ! number of clock time steps alarm rings for - nstep = 0 + ! destroy calendars + call ESMF_CalendarDestroy(esmf_360dayCalendar, rc=rc) + call ESMF_CalendarDestroy(no_leapCalendar, rc=rc) + call ESMF_CalendarDestroy(julianCalendar, rc=rc) + call ESMF_CalendarDestroy(gregorianCalendar, rc=rc) - ! starting time step number for first alarm ring - sstep = 0 + ! finalize ESMF framework + call ESMF_TestEnd(ESMF_SRCLINE) - ! total clock time steps - i = 0 + contains - ! run the clock - do while (.not. ESMF_ClockIsStopTime(clock2, rc=rc)) - i = i + 1 - call ESMF_ClockGetAlarmList(clock2, ESMF_ALARMLIST_RINGING, & - alarmList=alarmList, & - alarmCount=alarmCount, rc=rc) - if (alarmCount .gt. 0) then - if (sstep .eq. 0) sstep = i - nstep = nstep + 1 - endif - call ESMF_ClockAdvance(clock2, rc=rc) - enddo + subroutine test_ReverseAlarms(testPass, rc) + implicit none - call ESMF_Test((rc.eq.ESMF_SUCCESS) & - .and.(nstep.eq.48).and.(sstep.eq.73).and.(i.eq.144), & - name, failMsg, result, ESMF_SRCLINE) + logical, intent(out) :: testPass + integer, intent(out) :: rc + integer :: status - call ESMF_AlarmDestroy(alarm4, rc=rc) - call ESMF_ClockDestroy(clock2, rc=rc) + type(ESMF_TimeInterval) :: dt + type(ESMF_Time) :: start_time, clock_start, clock_end + type(ESMF_Clock) :: clock - ! ---------------------------------------------------------------------------- - !EX_UTest - !Test Non-Sticky Alarms 2 - ! Test ringDuration and stopTime - write(failMsg, *) " Did not return nstep=12 and ESMF_SUCCESS" - write(name, *) "Non-Sticky Alarm Test 2" - call ESMF_TimeIntervalSet(timeStep, m=15, rc=rc) - call ESMF_TimeSet(startTime, yy=1999, mm=12, dd=31, h=23, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeSet(stopTime, yy=2000, mm=1, dd=1, h=23, & - calendar=gregorianCalendar, rc=rc) - clock2 = ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & - name="Clock 2", rc=rc) - call ESMF_TimeSet(alarmTime, yy=2000, mm=1, dd=1, h=1, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeIntervalSet(alarmStep, h=2, rc=rc) - call ESMF_TimeIntervalSet(ringDuration, m=30, rc=rc) - call ESMF_TimeSet(alarmStopTime, yy=2000, mm=1, dd=1, h=13, & - calendar=gregorianCalendar, rc=rc) - alarm4 = ESMF_AlarmCreate(clock=clock2, ringTime=alarmTime, & - ringInterval=alarmStep, & - ringDuration=ringDuration, & - stopTime=alarmStopTime, sticky=.false., rc=rc) - ! number of clock time steps alarm rings for - nstep = 0 - - ! run the clock - do while (.not. ESMF_ClockIsStopTime(clock2, rc=rc)) - if (ESMF_AlarmIsRinging(alarm4)) then - nstep = nstep + 1 - endif - call ESMF_ClockAdvance(clock2, rc=rc) - enddo + type(ESMF_TimeInterval) :: tint + type(ESMF_Alarm) :: esmfalarm, firstalarm - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(nstep.eq.12), & - name, failMsg, result, ESMF_SRCLINE) + integer :: i,nstep - call ESMF_AlarmDestroy(alarm4, rc=rc) - call ESMF_ClockDestroy(clock2, rc=rc) + type(ESMF_Time) :: time + logical :: esmfalarm_ring, firstalarm_ring + logical :: allCorrect - ! ---------------------------------------------------------------------------- + rc = ESMF_SUCCESS + testPass = .false. + allCorrect = .true. - !EX_UTest - !Test Non-Sticky Alarms 3 - ! Test ringTimeStepCount and stopTime - write(failMsg, *) " Did not return nstep=18 and ESMF_SUCCESS" - write(name, *) "Non-Sticky Alarm Test 3" - call ESMF_TimeIntervalSet(timeStep, m=15, rc=rc) - call ESMF_TimeSet(startTime, yy=1999, mm=12, dd=31, h=23, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeSet(stopTime, yy=2000, mm=1, dd=1, h=23, & - calendar=gregorianCalendar, rc=rc) - clock2=ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & - name="Clock 2", rc=rc) - call ESMF_TimeSet(alarmTime, yy=2000, mm=1, dd=1, h=1, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeIntervalSet(alarmStep, h=2, rc=rc) - call ESMF_TimeSet(alarmStopTime, yy=2000, mm=1, dd=1, h=13, & - calendar=gregorianCalendar, rc=rc) - alarm4 = ESMF_AlarmCreate(clock=clock2, ringTime=alarmTime, & - ringInterval=alarmStep, & - ringTimeStepCount=3, & - stopTime=alarmStopTime, sticky=.false., rc=rc) - ! number of clock time steps alarm rings for - nstep = 0 - - ! run the clock - do while (.not. ESMF_ClockIsStopTime(clock2, rc=rc)) - if (ESMF_AlarmIsRinging(alarm4)) then - nstep = nstep + 1 - endif - call ESMF_ClockAdvance(clock2, rc=rc) - enddo + call ESMF_CalendarSetDefault ( ESMF_CALKIND_GREGORIAN, rc=status ) + call verify_(status) + call ESMF_TimeSet(clock_start,yy=2000,mm=1,dd=1,h=21,m=0,s=0,rc=status) + call verify_(status) + call ESMF_TimeSet(clock_end,yy=2000,mm=12,dd=1,h=21,m=0,s=0,rc=status) + call verify_(status) + call ESMF_TimeSet(start_time,yy=2000,mm=10,dd=1,h=21,m=0,s=0,rc=status) + call verify_(status) + call ESMF_TimeIntervalSet(dt,S=900, sN=0, sD=1,rc=status) + call verify_(status) + clock= ESMF_ClockCreate(timeStep=dt,startTime=clock_start,stopTime=clock_end,rc=status) + call verify_(status) + call ESMF_ClockSet(clock,currTime=start_time,rc=status) + call verify_(status) - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(nstep.eq.18), & - name, failMsg, result, ESMF_SRCLINE) + call ESMF_TimeIntervalSet(tint,h=2,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + firstalarm = ESMF_AlarmCreate(clock=clock,ringInterval=tint,ringTime=start_time,sticky=.false.,name="alarm1",rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + firstalarm_ring = ESMF_AlarmIsRinging(firstalarm,rc=status) + call verify_(status) + if (.not. firstalarm_ring) then + allCorrect = .false. + end if - call ESMF_AlarmDestroy(alarm4, rc=rc) - call ESMF_ClockDestroy(clock2, rc=rc) + call ESMF_ClockGet(clock,currtime=start_time,rc=status) + call verify_(status) + call ESMF_TimeIntervalSet(tint,h=1,rc=status) + call verify_(status) + esmfalarm = ESMF_AlarmCreate(clock=clock,ringInterval=tint,ringTime=start_time,sticky=.false.,name="alarm2",rc=status) + call verify_(status) + esmfalarm_ring = ESMF_AlarmIsRinging(esmfalarm,rc=status) + call verify_(status) + if (.not. esmfalarm_ring) then + allCorrect = .false. + end if + nstep=47 + do i=1,nstep + call ESMF_ClockAdvance(clock,rc=status) + call verify_(status) + !call ESMF_ClockDebug(clock, 'forward clock', rc=status) + !call verify_(status) + !call ESMF_AlarmDebug(esmfalarm, 'forward esmfalarm', rc=status) + !call verify_(status) + + esmfalarm_ring = ESMF_AlarmIsRinging(esmfalarm,rc=status) + call verify_(status) + if (modulo(i,4) == 0) then + ! Time step of 15 minutes, alarm rings every hour, so alarm should ring every 4th time step + if (.not. esmfalarm_ring) then + allCorrect = .false. + end if + else + if (esmfalarm_ring) then + allCorrect = .false. + end if + end if - ! ---------------------------------------------------------------------------- + firstalarm_ring = ESMF_AlarmIsRinging(firstalarm,rc=status) + call verify_(status) + if (modulo(i,8) == 0) then + ! Time step of 15 minutes, alarm rings every two hours, so alarm should ring every 8th time step + if (.not. firstalarm_ring) then + allCorrect = .false. + end if + else + if (firstalarm_ring) then + allCorrect = .false. + end if + end if + enddo - !EX_UTest - !Test Non-Sticky Alarms 4 - ! Test ringTimeStepCount precedence over ringDuration - write(failMsg, *) " Did not return nstep=18 and ESMF_SUCCESS" - write(name, *) "Non-Sticky Alarm Test 4" - call ESMF_TimeIntervalSet(timeStep, m=15, rc=rc) - call ESMF_TimeSet(startTime, yy=1999, mm=12, dd=31, h=23, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeSet(stopTime, yy=2000, mm=1, dd=1, h=23, & - calendar=gregorianCalendar, rc=rc) - clock2=ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & - name="Clock 2", rc=rc) - call ESMF_TimeSet(alarmTime, yy=2000, mm=1, dd=1, h=1, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeIntervalSet(alarmStep, h=2, rc=rc) + call ESMF_ClockSet(clock, direction=ESMF_DIRECTION_REVERSE, rc=status) + call verify_(status) + i = 0 + do + i = i + 1 + call ESMF_ClockAdvance(clock,rc=status) + call verify_(status) + !call ESMF_ClockDebug(clock, 'reverse clock', rc=status) + !call verify_(status) + !call ESMF_AlarmDebug(esmfalarm, 'reverse esmfalarm', rc=status) + !call verify_(status) + + esmfalarm_ring = ESMF_AlarmIsRinging(esmfalarm,rc=status) + call verify_(status) + if (modulo((i-3),4) == 0) then + ! Time step of 15 minutes, with time starting at 45 minutes past the hour, alarm + ! rings every hour, so alarm should ring every 4th time step starting with i==3 + if (.not. esmfalarm_ring) then + allCorrect = .false. + end if + else + if (esmfalarm_ring) then + allCorrect = .false. + end if + end if - call ESMF_TimeIntervalSet(ringDuration, m=30, rc=rc) + firstalarm_ring = ESMF_AlarmIsRinging(firstalarm,rc=status) + call verify_(status) + if (modulo((i-7),8) == 0) then + ! Time step of 15 minutes, with time starting at 45 minutes past an odd-numbered + ! hour, alarm rings every two hours, so alarm should ring every 8th time step + ! starting with i==7 + if (.not. firstalarm_ring) then + allCorrect = .false. + end if + else + if (firstalarm_ring) then + allCorrect = .false. + end if + end if - call ESMF_TimeSet(alarmStopTime, yy=2000, mm=1, dd=1, h=13, & - calendar=gregorianCalendar, rc=rc) - alarm4 = ESMF_AlarmCreate(clock=clock2, ringTime=alarmTime, & - ringInterval=alarmStep, & - ringTimeStepCount=3, & - ringDuration=ringDuration, & - stopTime=alarmStopTime, sticky=.false., rc=rc) - ! number of clock time steps alarm rings for - nstep = 0 - - ! run the clock - do while (.not. ESMF_ClockIsStopTime(clock2, rc=rc)) - if (ESMF_AlarmIsRinging(alarm4)) then - nstep = nstep + 1 - endif - call ESMF_ClockAdvance(clock2, rc=rc) + call ESMF_ClockGet(clock,currTime=time) + if (time == start_time) exit enddo - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(nstep.eq.18), & - name, failMsg, result, ESMF_SRCLINE) - - call ESMF_AlarmDestroy(alarm4, rc=rc) - call ESMF_ClockDestroy(clock2, rc=rc) - - ! ---------------------------------------------------------------------------- + call ESMF_ClockSet(clock, direction=ESMF_DIRECTION_FORWARD, rc=status) + call verify_(status) + do i=1,nstep*2 + call ESMF_ClockAdvance(clock,rc=status) + call verify_(status) + !call ESMF_ClockDebug(clock, 'forward clock again', rc=status) + !call verify_(status) + !call ESMF_AlarmDebug(esmfalarm, 'forward esmfalarm again', rc=status) + !call verify_(status) + + esmfalarm_ring = ESMF_AlarmIsRinging(esmfalarm,rc=status) + call verify_(status) + if (modulo(i,4) == 0) then + ! Time step of 15 minutes, alarm rings every hour, so alarm should ring every 4th time step + if (.not. esmfalarm_ring) then + allCorrect = .false. + end if + else + if (esmfalarm_ring) then + allCorrect = .false. + end if + end if - !EX_UTest - !Test Non-Sticky Alarms 5 - ! Test reverse non-sticky alarm - write(failMsg, *) "Did not return nstep=24, forwardCount=96, reverseCount=0, etc., and ESMF_SUCCESS" - write(name, *) "Non-Sticky Alarm Test 5" - call ESMF_TimeIntervalSet(timeStep, m=15, rc=rc) - call ESMF_TimeSet(startTime, yy=1999, mm=12, dd=31, h=23, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeSet(stopTime, yy=2000, mm=1, dd=1, h=23, & - calendar=gregorianCalendar, rc=rc) - clock2 = ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & - name="Clock 2", rc=rc) - call ESMF_TimeSet(alarmTime, yy=2000, mm=1, dd=1, h=1, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeIntervalSet(alarmStep, h=2, rc=rc) - call ESMF_TimeIntervalSet(ringDuration, m=30, rc=rc) - call ESMF_TimeSet(alarmStopTime, yy=2000, mm=1, dd=1, h=13, & - calendar=gregorianCalendar, rc=rc) - alarm4 = ESMF_AlarmCreate(clock=clock2, ringTime=alarmTime, & - ringInterval=alarmStep, & - ringDuration=ringDuration, & - stopTime=alarmStopTime, sticky=.false., rc=rc) - ! number of clock time steps alarm rings for - nstep = 0 - - ! number of times the clock has been run - nclock = 0 - - do while (nclock < 2) - ! run the clock - do while (.not. ESMF_ClockIsDone(clock2, rc=rc)) - !call ESMF_ClockGet(clock2, currTime=currentTime, rc=rc) - !call ESMF_TimeGet(currentTime, yy=yy, mm=mm, dd=dd, h=h, m=m, rc=rc) - !print *, mm, "/", dd, "/", yy, " ", h, ":", m - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - if (ESMF_AlarmIsRinging(alarm4)) then - nstep = nstep + 1 - !print *, "on" - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - else - !print *, "off" - endif - !call ESMF_AlarmPrint(alarm4, options="ringtime string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_ClockAdvance(clock2, rc=rc) - enddo - - if (nclock.eq.0) then - call ESMF_ClockGet(clock2, direction=forwardDirection, & - advanceCount=forwardCount, rc=rc) - !print *, "forwardCount = ", forwardCount + firstalarm_ring = ESMF_AlarmIsRinging(firstalarm,rc=status) + call verify_(status) + if (modulo(i,8) == 0) then + ! Time step of 15 minutes, alarm rings every two hours, so alarm should ring every 8th time step + if (.not. firstalarm_ring) then + allCorrect = .false. + end if else - call ESMF_ClockGet(clock2, direction=reverseDirection, & - advanceCount=reverseCount, rc=rc) - !print *, "reverseCount = ", reverseCount - endif + if (firstalarm_ring) then + allCorrect = .false. + end if + end if + enddo - call ESMF_ClockSet(clock2, direction=ESMF_DIRECTION_REVERSE, rc=rc) - nclock = nclock + 1 + call ESMF_AlarmDestroy(esmfalarm, rc=status) + call verify_(status) + call ESMF_AlarmDestroy(firstalarm, rc=status) + call verify_(status) + call ESMF_ClockDestroy(clock, rc=status) + call verify_(status) - enddo + if (allCorrect) then + testPass = .true. + else + testPass = .false. + end if + end subroutine Test_ReverseAlarms - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(nstep.eq.24).and. & - (forwardCount.eq.96).and.(reverseCount.eq.0).and. & - (forwardDirection.eq.ESMF_DIRECTION_FORWARD).and. & - (reverseDirection.eq.ESMF_DIRECTION_REVERSE).and. & - ESMF_ClockIsReverse(clock2), & - name, failMsg, result, ESMF_SRCLINE) + subroutine Test_AlarmHang(testPass, rc) + ! Note that, in addition to testing a case that led to a hang at one point, this + ! also tests the behavior of a sticky alarm with a clock running both forward and + ! reverse. + logical, intent(out) :: testPass + integer, intent(out) :: rc - !print *, "nstep = ", nstep, " nclock = ", nclock - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) + integer :: status - call ESMF_AlarmDestroy(alarm4, rc=rc) - call ESMF_ClockDestroy(clock2, rc=rc) + type(ESMF_TimeInterval) :: dt + type(ESMF_Time) :: start_time, clock_start, clock_end + type(ESMF_Clock) :: clock - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Non-Sticky Alarms 6 - ! Test reverse non-sticky alarm with negative timestep - write(failMsg, *) "Did not return nring=48, forwardCount=96, reverseCount=0, etc., and ESMF_SUCCESS" - write(name, *) "Non-Sticky Alarm Test 6" - call ESMF_TimeIntervalSet(timeStep, m=-15, rc=rc) - call ESMF_TimeSet(startTime, yy=2000, mm=1, dd=1, h=23, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeSet(stopTime, yy=1999, mm=12, dd=31, h=23, & - calendar=gregorianCalendar, rc=rc) - clock2 = ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & - name="Clock 2", rc=rc) - call ESMF_TimeSet(alarmTime, yy=2000, mm=1, dd=1, h=23, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeIntervalSet(alarmStep, h=-2, rc=rc) - call ESMF_TimeIntervalSet(ringDuration, m=-30, rc=rc) - call ESMF_TimeSet(alarmStopTime, yy=1999, mm=12, dd=31, h=21, & - calendar=gregorianCalendar, rc=rc) - alarm4 = ESMF_AlarmCreate(clock=clock2, ringTime=alarmTime, & - ringInterval=alarmStep, & - ringDuration=ringDuration, & - stopTime=alarmStopTime, & - sticky=.false., rc=rc) - ! number of clock time steps alarm rings for - nring = 0 - - ! number of times the clock has been run - nclock = 0 - - do while (nclock < 2) - ! run the clock - do while (.not. ESMF_ClockIsDone(clock2, rc=rc)) - call ESMF_ClockGet(clock2, currTime=currentTime, rc=rc) - call ESMF_TimeGet(currentTime, yy=yy, mm=mm, dd=dd, h=h, m=m, rc=rc) - !print *, mm, "/", dd, "/", yy, " ", h, ":", m - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - if (ESMF_AlarmIsRinging(alarm4)) then - nring = nring + 1 - !print *, "ringing!" - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - endif - !call ESMF_AlarmPrint(alarm4, options="ringbegin string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_AlarmPrint(alarm4, options="ringtime string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_ClockAdvance(clock2, rc=rc) - enddo - - if (nclock.eq.0) then - call ESMF_ClockGet(clock2, direction=forwardDirection, & - advanceCount=forwardCount, rc=rc) - !print *, "forwardCount = ", forwardCount - else - call ESMF_ClockGet(clock2, direction=reverseDirection, & - advanceCount=reverseCount, rc=rc) - !print *, "reverseCount = ", reverseCount - endif - - !print *, "Going in REVERSE ..." - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_ClockSet(clock2, direction=ESMF_DIRECTION_REVERSE, rc=rc) - nclock = nclock + 1 - - enddo - - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(nring.eq.48).and. & - (forwardCount.eq.96).and.(reverseCount.eq.0).and. & - (forwardDirection.eq.ESMF_DIRECTION_FORWARD).and. & - (reverseDirection.eq.ESMF_DIRECTION_REVERSE).and. & - ESMF_ClockIsReverse(clock2), & - name, failMsg, result, ESMF_SRCLINE) - - !print *, "nring = ", nring, " nclock = ", nclock - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - - call ESMF_AlarmDestroy(alarm4, rc=rc) - call ESMF_ClockDestroy(clock2, rc=rc) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Sticky Alarms 1 - ! Test reverse sticky alarm - write(failMsg, *) " Did not return nstep=2 and ESMF_SUCCESS" - write(name, *) "Sticky Alarm Test 1" - call ESMF_TimeIntervalSet(timeStep, m=15, rc=rc) - call ESMF_TimeSet(startTime, yy=1999, mm=12, dd=31, h=23, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeSet(stopTime, yy=2000, mm=1, dd=1, h=23, & - calendar=gregorianCalendar, rc=rc) - clock2 = ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & - name="Clock 2", rc=rc) - call ESMF_TimeSet(alarmTime, yy=2000, mm=1, dd=1, h=1, & - calendar=gregorianCalendar, rc=rc) - alarm4 = ESMF_AlarmCreate(clock=clock2, ringTime=alarmTime, rc=rc) - ! number of clock time steps alarm rings for - nstep = 0 - - ! number of times the clock has been run - nclock = 0 - - do while (nclock < 2) - ! run the clock - do while (.not. ESMF_ClockIsDone(clock2, rc=rc)) - call ESMF_ClockGet(clock2, currTime=currentTime, rc=rc) - call ESMF_TimeGet(currentTime, yy=yy, mm=mm, dd=dd, h=h, m=m, rc=rc) - !print *, mm, "/", dd, "/", yy, " ", h, ":", m - if (ESMF_AlarmIsRinging(alarm4)) then - nstep = nstep + 1 - !print *, "on" - call ESMF_AlarmRingerOff(alarm4, rc=rc) - else - !print *, "off" - endif - call ESMF_ClockAdvance(clock2, rc=rc) - enddo - - call ESMF_ClockSet(clock2, direction=ESMF_DIRECTION_REVERSE, rc=rc) - nclock = nclock + 1 - enddo - - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(nstep.eq.2), & - name, failMsg, result, ESMF_SRCLINE) - - !print *, "nstep = ", nstep, " nclock = ", nclock - - call ESMF_AlarmDestroy(alarm4, rc=rc) - call ESMF_ClockDestroy(clock2, rc=rc) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Sticky Alarms 2 - ! Test reverse interval sticky alarm - write(failMsg, *) " Did not return nstep=23 and ESMF_SUCCESS" - write(name, *) "Sticky Alarm Test 2" - call ESMF_TimeIntervalSet(timeStep, m=15, rc=rc) - call ESMF_TimeSet(startTime, yy=1999, mm=12, dd=31, h=23, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeSet(stopTime, yy=2000, mm=1, dd=1, h=23, & - calendar=gregorianCalendar, rc=rc) - clock2 = ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & - name="Clock 2", rc=rc) - call ESMF_TimeSet(alarmTime, yy=2000, mm=1, dd=1, h=1, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeIntervalSet(alarmStep, h=2, rc=rc) - alarm4 = ESMF_AlarmCreate(clock=clock2, ringTime=alarmTime, & - ringInterval=alarmStep, rc=rc) - ! number of clock time steps alarm rings for - nstep = 0 - - ! number of times the clock has been run - nclock = 0 - - do while (nclock < 2) - ! run the clock - do while (.not. ESMF_ClockIsDone(clock2, rc=rc)) - call ESMF_ClockGet(clock2, currTime=currentTime, rc=rc) - call ESMF_TimeGet(currentTime, yy=yy, mm=mm, dd=dd, h=h, m=m, rc=rc) - !print *, mm, "/", dd, "/", yy, " ", h, ":", m - if (ESMF_AlarmIsRinging(alarm4)) then - nstep = nstep + 1 - !print *, "on" - call ESMF_AlarmRingerOff(alarm4, rc=rc) - else - !print *, "off" - endif - call ESMF_ClockAdvance(clock2, rc=rc) - enddo - - call ESMF_ClockSet(clock2, direction=ESMF_DIRECTION_REVERSE, rc=rc) - nclock = nclock + 1 - enddo - - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(nstep.eq.23), & - name, failMsg, result, ESMF_SRCLINE) - - !print *, "nstep = ", nstep, " nclock = ", nclock - - call ESMF_AlarmDestroy(alarm4, rc=rc) - call ESMF_ClockDestroy(clock2, rc=rc) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Sticky Alarms 3 - ! Test reverse one-shot sticky alarms per WRF use case - ! From Tom Henderson/WRF - - write(name, *) "Sticky Alarm Test 3" - write(failMsg, *) " Alarms did not turn on/off at the correct time/iteration or did not return ESMF_SUCCESS" - - call ESMF_TimeIntervalSet(timeStep, h=1, rc=rc) - call ESMF_TimeSet(startTime, yy=2005, mm=6, dd=15, h=1, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeSet(stopTime, yy=2005, mm=6, dd=15, h=5, & - calendar=gregorianCalendar, rc=rc) - domainClock = ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & - name="WRF Clock", rc=rc) - - call ESMF_TimeSet(beforeAlarmTime, yy=2005, mm=6, dd=15, h=2, & - calendar=gregorianCalendar, rc=rc) - beforeAlarm = ESMF_AlarmCreate(clock=domainClock, & - ringTime=beforeAlarmTime, rc=rc) - - call ESMF_TimeSet(afterAlarmTime, yy=2005, mm=6, dd=15, h=3, & - calendar=gregorianCalendar, rc=rc) - afterAlarm = ESMF_AlarmCreate(clock=domainClock, & - ringTime=afterAlarmTime, rc=rc) - - ! any single failure will cause the whole test to fail - testPass = .true. - - ! track loop iterations - iteration = 0 - - call ESMF_ClockGet(domainClock, currTime=currentTime, rc=rc) - call ESMF_TimeGet(currentTime, yy=yy, mm=mm, dd=dd, h=h, rc=rc) - !print *, "Begin" - !print *, mm, "/", dd, "/", yy, " ", h, ": 0" - - ! run the clock forward - do while (.not. ESMF_ClockIsDone(domainClock, rc=rc)) - iteration = iteration + 1 - !print *, "Iteration = ", iteration - - if (ESMF_AlarmIsRinging(beforeAlarm, rc=rc)) then - if (iteration .ne. 2 .or. h .ne. 2) then - testPass = .false. - endif - !print *, " beforeAlarm on" - call ESMF_AlarmRingerOff(beforeAlarm, rc=rc) - else - !print *, " beforeAlarm off" - endif - - ! would call WRF solver here, before clock advance - !print *, " Solve" - - call ESMF_ClockAdvance(domainClock, rc=rc) - call ESMF_ClockGet(domainClock, currTime=currentTime, rc=rc) - call ESMF_TimeGet(currentTime, yy=yy, mm=mm, dd=dd, h=h, rc=rc) - !print *, " ClockAdvance()" - !print *, mm, "/", dd, "/", yy, " ", h, ": 0" - - if (ESMF_AlarmIsRinging(afterAlarm, rc=rc)) then - if (iteration .ne. 2 .or. h .ne. 3) then - testPass = .false. - endif - !print *, " afterAlarm on" - call ESMF_AlarmRingerOff(afterAlarm, rc=rc) - else - !print *, " afterAlarm off" - endif - enddo - - ! run the clock backwards - call ESMF_ClockSet(domainClock, direction=ESMF_DIRECTION_REVERSE, rc=rc) - !print * - !print *, "domainClock set in reverse" - !print * - - do while (.not. ESMF_ClockIsDone(domainClock, rc=rc)) - !print *, "Iteration = ", iteration - - if (ESMF_AlarmIsRinging(afterAlarm, rc=rc)) then - if (iteration .ne. 2 .or. h .ne. 3) then - testPass = .false. - endif - !print *, " afterAlarm on" - call ESMF_AlarmRingerOff(afterAlarm, rc=rc) - else - !print *, " afterAlarm off" - endif - - ! advance clock - call ESMF_ClockAdvance(domainClock, rc=rc) - call ESMF_ClockGet(domainClock, currTime=currentTime, rc=rc) - call ESMF_TimeGet(currentTime, yy=yy, mm=mm, dd=dd, h=h, rc=rc) - !print *, " ClockAdvance()" - !print *, mm, "/", dd, "/", yy, " ", h, ": 0" - - ! would call WRF solver here, after clock advance - !print *, " Solve" - - if (ESMF_AlarmIsRinging(beforeAlarm, rc=rc)) then - if (iteration .ne. 2 .or. h .ne. 2) then - testPass = .false. - endif - !print *, " beforeAlarm on" - call ESMF_AlarmRingerOff(beforeAlarm, rc=rc) - else - !print *, " beforeAlarm off" - endif - - iteration = iteration - 1 - enddo - - call ESMF_Test(testPass.and.(rc.eq.ESMF_SUCCESS), & - name, failMsg, result, ESMF_SRCLINE) - - call ESMF_AlarmDestroy(afterAlarm, rc=rc) - call ESMF_AlarmDestroy(beforeAlarm, rc=rc) - call ESMF_ClockDestroy(domainClock, rc=rc) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Sticky Alarms 4 - ! Test reverse *interval* sticky alarms; variation on WRF use case above - - write(name, *) "Sticky Alarm Test 4" - write(failMsg, *) " Alarms did not turn on/off at the correct time/iteration or did not return ESMF_SUCCESS" - - call ESMF_TimeIntervalSet(timeStep, h=1, rc=rc) - call ESMF_TimeSet(startTime, yy=2005, mm=6, dd=15, h=1, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeSet(stopTime, yy=2005, mm=6, dd=15, h=10, & - calendar=gregorianCalendar, rc=rc) - domainClock = ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & - name="WRF Clock", rc=rc) - - call ESMF_TimeSet(beforeAlarmTime, yy=2005, mm=6, dd=15, h=2, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeIntervalSet(alarmStep, h=3, rc=rc) - beforeAlarm = ESMF_AlarmCreate(clock=domainClock, & - ringTime=beforeAlarmTime, & - ringInterval=alarmStep, rc=rc) - - call ESMF_TimeSet(afterAlarmTime, yy=2005, mm=6, dd=15, h=3, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeIntervalSet(alarmStep2, h=2, rc=rc) - afterAlarm = ESMF_AlarmCreate(clock=domainClock, & - ringTime=afterAlarmTime, & - ringInterval=alarmStep2, rc=rc) - - ! any single failure will cause the whole test to fail - testPass = .true. - - ! track loop iterations - iteration = 0 - - call ESMF_ClockGet(domainClock, currTime=currentTime, rc=rc) - call ESMF_TimeGet(currentTime, yy=yy, mm=mm, dd=dd, h=h, rc=rc) - !print *, "Begin" - !print *, mm, "/", dd, "/", yy, " ", h, ": 0" - - ! run the clock forward - do while (.not. ESMF_ClockIsDone(domainClock, rc=rc)) - iteration = iteration + 1 - !print *, "Iteration = ", iteration - - if (ESMF_AlarmIsRinging(beforeAlarm, rc=rc)) then - if ((iteration .ne. 2 .or. h .ne. 2).and. & - (iteration .ne. 5 .or. h .ne. 5).and. & - (iteration .ne. 8 .or. h .ne. 8)) then - testPass = .false. - endif - !print *, " beforeAlarm on" - call ESMF_AlarmRingerOff(beforeAlarm, rc=rc) - else - !print *, " beforeAlarm off" - endif - - ! would call WRF solver here, before clock advance - !print *, " Solve" - - call ESMF_ClockAdvance(domainClock, rc=rc) - call ESMF_ClockGet(domainClock, currTime=currentTime, rc=rc) - call ESMF_TimeGet(currentTime, yy=yy, mm=mm, dd=dd, h=h, rc=rc) - !print *, " ClockAdvance()" - !print *, mm, "/", dd, "/", yy, " ", h, ": 0" - - if (ESMF_AlarmIsRinging(afterAlarm, rc=rc)) then - if ((iteration .ne. 2 .or. h .ne. 3).and. & - (iteration .ne. 4 .or. h .ne. 5).and. & - (iteration .ne. 6 .or. h .ne. 7).and. & - (iteration .ne. 8 .or. h .ne. 9)) then - testPass = .false. - endif - !print *, " afterAlarm on" - call ESMF_AlarmRingerOff(afterAlarm, rc=rc) - else - !print *, " afterAlarm off" - endif - enddo - - ! run the clock backwards - call ESMF_ClockSet(domainClock, direction=ESMF_DIRECTION_REVERSE, rc=rc) - !print * - !print *, "domainClock set in reverse" - !print * - - do while (.not. ESMF_ClockIsDone(domainClock, rc=rc)) - !print *, "Iteration = ", iteration - - if (ESMF_AlarmIsRinging(afterAlarm, rc=rc)) then - if ((iteration .ne. 2 .or. h .ne. 3).and. & - (iteration .ne. 4 .or. h .ne. 5).and. & - (iteration .ne. 6 .or. h .ne. 7).and. & - (iteration .ne. 8 .or. h .ne. 9)) then - testPass = .false. - endif - !print *, " afterAlarm on" - call ESMF_AlarmRingerOff(afterAlarm, rc=rc) - else - !print *, " afterAlarm off" - endif - - ! advance clock - call ESMF_ClockAdvance(domainClock, rc=rc) - call ESMF_ClockGet(domainClock, currTime=currentTime, rc=rc) - call ESMF_TimeGet(currentTime, yy=yy, mm=mm, dd=dd, h=h, rc=rc) - !print *, " ClockAdvance()" - !print *, mm, "/", dd, "/", yy, " ", h, ": 0" - - ! would call WRF solver here, after clock advance - !print *, " Solve" - - if (ESMF_AlarmIsRinging(beforeAlarm, rc=rc)) then - if ((iteration .ne. 2 .or. h .ne. 2).and. & - (iteration .ne. 5 .or. h .ne. 5).and. & - (iteration .ne. 8 .or. h .ne. 8)) then - testPass = .false. - endif - !print *, " beforeAlarm on" - call ESMF_AlarmRingerOff(beforeAlarm, rc=rc) - else - !print *, " beforeAlarm off" - endif - - iteration = iteration - 1 - enddo - - call ESMF_Test(testPass.and.(rc.eq.ESMF_SUCCESS), & - name, failMsg, result, ESMF_SRCLINE) - - call ESMF_AlarmDestroy(afterAlarm, rc=rc) - call ESMF_AlarmDestroy(beforeAlarm, rc=rc) - call ESMF_ClockDestroy(domainClock, rc=rc) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Sticky Alarms 5 - ! Test delay in checking for ringing sticky alarms, - ! from James Geiger in #2825456, case #2 in his alarm_test.f90 reproducer - write(name, *) "Sticky Alarm Test 5" - write(failMsg, *) " Alarm did not ring at the correct times or did not return ESMF_SUCCESS" - call ESMF_TimeIntervalSet(timeStep, s=3600, rc=rc) - call ESMF_TimeSet(startTime, yy=2000, mm=1, dd=1, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeSet(stopTime, yy=2000, mm=1, dd=3, & - calendar=gregorianCalendar, rc=rc) - clock2 = ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & - name="Clock", rc=rc) - call ESMF_TimeSet(alarmTime, yy=2000, mm=1, dd=1, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeIntervalSet(alarmStep, h=3, rc=rc) - alarmTime = alarmTime + alarmStep - alarm4 = ESMF_AlarmCreate(clock=clock2, ringTime=alarmTime, & - ringInterval=alarmStep, rc=rc) - testPass = .false. - iteration = 0 - nring = 0 - do while (.not.ESMF_ClockIsStopTime(clock2, rc=rc)) - iteration = iteration + 1 - !print *, "clock2 timestep ", iteration - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - if (iteration .eq. 10) then - ! waiting period is over, clear any alarm which may have occurred - if (ESMF_AlarmIsRinging(alarm4, rc=rc)) then - call ESMF_AlarmRingerOff(alarm4, rc=rc) - endif - endif - call ESMF_ClockAdvance(clock2, rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_ClockPrint(clock2, options="currTime string", rc=rc) - - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - if (iteration .gt. 10) then - ! process any alarm occuring after initial 10 hour waiting period - if (ESMF_AlarmIsRinging(alarm4, rc=rc)) then - nring = nring + 1 - !print *, "alarm4 is ringing!" - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_AlarmRingerOff(alarm4, rc=rc) - endif - endif - end do - - ! test in REVERSE mode (not from James) - call ESMF_ClockSet(clock2, direction=ESMF_DIRECTION_REVERSE, rc=rc) - - do while (.not.ESMF_ClockIsDone(clock2, rc=rc)) - iteration = iteration + 1 - !print *, "clock2 timestep ", iteration - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_ClockAdvance(clock2, rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_ClockPrint(clock2, options="currTime string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - if (ESMF_AlarmIsRinging(alarm4, rc=rc)) then - nring = nring + 1 - !print *, "alarm4 is ringing!" - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_AlarmRingerOff(alarm4, rc=rc) - endif - end do - - ! test double back in FORWARD mode (not from James) - call ESMF_ClockSet(clock2, direction=ESMF_DIRECTION_FORWARD, rc=rc) - - do while (.not.ESMF_ClockIsDone(clock2, rc=rc)) - iteration = iteration + 1 - !print *, "clock2 timestep ", iteration - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_ClockAdvance(clock2, rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_ClockPrint(clock2, options="currTime string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - if (ESMF_AlarmIsRinging(alarm4, rc=rc)) then - nring = nring + 1 - !print *, "alarm4 is ringing!" - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_AlarmRingerOff(alarm4, rc=rc) - endif - end do - - !print *, "alarm4 rang ", nring, " times, clock stepped ", iteration, " times." - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - if (nring.eq.44 .and. iteration.eq.144) testPass = .true. - call ESMF_Test(testPass.and.(rc.eq.ESMF_SUCCESS), & - name, failMsg, result, ESMF_SRCLINE) - - call ESMF_AlarmDestroy(alarm4, rc=rc) - call ESMF_ClockDestroy(clock2, rc=rc) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Sticky Alarms 6 - ! Test timeStep == ringInterval, from James Geiger in #2910203 - write(name, *) "Sticky Alarm Test 6" - write(failMsg, *) " Alarm did not ring at the correct times or did not return ESMF_SUCCESS" - call ESMF_TimeIntervalSet(timeStep, s=900, rc=rc) - call ESMF_TimeSet(startTime, yy=2003, mm=9, dd=1, & - calendar=gregorianCalendar, rc=rc) - ! dd=3, instead of original 30 in Jims report, to shorten test run time - call ESMF_TimeSet(stopTime, yy=2003, mm=9, dd=3, & - calendar=gregorianCalendar, rc=rc) - clock2 = ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & - name="The Clock", rc=rc) - call ESMF_TimeSet(alarmTime, yy=2003, mm=9, dd=1, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeIntervalSet(alarmStep, s=900, rc=rc) - alarm4 = ESMF_AlarmCreate(clock=clock2, ringTime=alarmTime, & - ringInterval=alarmStep, rc=rc) - testPass = .false. - iteration = 0 - nring = 0 - do while (.not.ESMF_ClockIsStopTime(clock2, rc=rc)) - iteration = iteration + 1 - !print *, "clock2 timestep ", iteration - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_ClockAdvance(clock2, rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_ClockPrint(clock2, options="currTime string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - if (ESMF_AlarmIsRinging(alarm4, rc=rc)) then - nring = nring + 1 - !print *, "alarm4 is ringing!" - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_AlarmRingerOff(alarm4, rc=rc) - endif - end do - - ! test in REVERSE mode (not from James) - call ESMF_ClockSet(clock2, direction=ESMF_DIRECTION_REVERSE, rc=rc) - - do while (.not.ESMF_ClockIsDone(clock2, rc=rc)) - iteration = iteration + 1 - !print *, "clock2 timestep ", iteration - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_ClockAdvance(clock2, rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_ClockPrint(clock2, options="currTime string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - if (ESMF_AlarmIsRinging(alarm4, rc=rc)) then - nring = nring + 1 - !print *, "alarm4 is ringing!" - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_AlarmRingerOff(alarm4, rc=rc) - endif - end do - - ! test double back in FORWARD mode (not from James), - call ESMF_ClockSet(clock2, direction=ESMF_DIRECTION_FORWARD, rc=rc) - - do while (.not.ESMF_ClockIsDone(clock2, rc=rc)) - iteration = iteration + 1 - !print *, "clock2 timestep ", iteration - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_ClockAdvance(clock2, rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_ClockPrint(clock2, options="currTime string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - if (ESMF_AlarmIsRinging(alarm4, rc=rc)) then - nring = nring + 1 - !print *, "alarm4 is ringing!" - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_AlarmRingerOff(alarm4, rc=rc) - endif - end do - - !print *, "alarm4 rang ", nring, " times, clock stepped ", iteration, " times." - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - if (nring.eq.576 .and. iteration.eq.576) testPass = .true. - call ESMF_Test(testPass.and.(rc.eq.ESMF_SUCCESS), & - name, failMsg, result, ESMF_SRCLINE) - - call ESMF_AlarmDestroy(alarm4, rc=rc) - call ESMF_ClockDestroy(clock2, rc=rc) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Sticky Alarms 7 - ! Test timeStep > ringInterval, inspired by James Geiger in #2910203 - write(name, *) "Sticky Alarm Test 7" - write(failMsg, *) " Alarm did not ring at the correct times or did not return ESMF_SUCCESS" - call ESMF_TimeIntervalSet(timeStep, s=1800, rc=rc) - call ESMF_TimeSet(startTime, yy=2003, mm=9, dd=1, & - calendar=gregorianCalendar, rc=rc) - ! dd=3, instead of original 30 in Jims report, to save test run time - call ESMF_TimeSet(stopTime, yy=2003, mm=9, dd=3, & - calendar=gregorianCalendar, rc=rc) - clock2 = ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & - name="The Clock", rc=rc) - call ESMF_TimeSet(alarmTime, yy=2003, mm=9, dd=1, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeIntervalSet(alarmStep, s=900, rc=rc) - alarm4 = ESMF_AlarmCreate(clock=clock2, ringTime=alarmTime, & - ringInterval=alarmStep, rc=rc) - testPass = .false. - iteration = 0 - nring = 0 - do while (.not.ESMF_ClockIsStopTime(clock2, rc=rc)) - iteration = iteration + 1 - !print *, "clock2 timestep ", iteration - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_ClockAdvance(clock2, rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_ClockPrint(clock2, options="currTime string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - if (ESMF_AlarmIsRinging(alarm4, rc=rc)) then - nring = nring + 1 - !print *, "alarm4 is ringing!" - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_AlarmRingerOff(alarm4, rc=rc) - endif - !call ESMF_AlarmPrint(alarm4, options="ringtime string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - end do - !print *, "At end of 1st forward run, nring = ", nring - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - - ! TODO: test in REVERSE mode (not from James) - ! currently doesn't ring in REVERSE - call ESMF_ClockSet(clock2, direction=ESMF_DIRECTION_REVERSE, rc=rc) - - do while (.not.ESMF_ClockIsDone(clock2, rc=rc)) - iteration = iteration + 1 - !print *, "clock2 timestep ", iteration - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_ClockAdvance(clock2, rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_ClockPrint(clock2, options="currTime string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - if (ESMF_AlarmIsRinging(alarm4, rc=rc)) then - nring = nring + 1 - !print *, "alarm4 is ringing!" - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_AlarmRingerOff(alarm4, rc=rc) - endif - !call ESMF_AlarmPrint(alarm4, options="ringtime string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - end do - !print *, "At end of reverse run, nring = ", nring - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - - ! TODO: test double back in FORWARD mode (not from James) - ! currently doesn't work until back into day 2 - call ESMF_ClockSet(clock2, direction=ESMF_DIRECTION_FORWARD, rc=rc) - - do while (.not.ESMF_ClockIsDone(clock2, rc=rc)) - iteration = iteration + 1 - !print *, "clock2 timestep ", iteration - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_ClockAdvance(clock2, rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_ClockPrint(clock2, options="currTime string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - if (ESMF_AlarmIsRinging(alarm4, rc=rc)) then - nring = nring + 1 - !print *, "alarm4 is ringing!" - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_AlarmRingerOff(alarm4, rc=rc) - endif - !call ESMF_AlarmPrint(alarm4, options="ringtime string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - end do - !print *, "At end of 2nd forward run, nring = ", nring - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - - !print *, "alarm4 rang ", nring, " times, clock stepped ", iteration, " times." - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - if (nring.eq.288 .and. iteration.eq.288) testPass = .true. - call ESMF_Test(testPass.and.(rc.eq.ESMF_SUCCESS), & - name, failMsg, result, ESMF_SRCLINE) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - - call ESMF_AlarmDestroy(alarm4, rc=rc) - call ESMF_ClockDestroy(clock2, rc=rc) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Fractional Time Alarms 1 - write(failMsg, *) " Did not return nstep=8, and ESMF_SUCCESS" - write(name, *) "Fractional Time Alarm Test 1" - call ESMF_TimeIntervalSet(timeStep, ms=10, rc=rc) - call ESMF_TimeIntervalSet(alarmStep, ms=100, rc=rc) - call ESMF_TimeSet(startTime, yy=1999, mm=12, dd=31, h=23, m=59, s=59, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeSet(stopTime, yy=2000, mm=1, dd=1, & - calendar=gregorianCalendar, rc=rc) - clock2=ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & - name="Clock 2", rc=rc) - call ESMF_TimeSet(alarmTime, yy=1999, mm=12, dd=31, h=23, m=59, s=59, & - ms=200, calendar=gregorianCalendar, rc=rc) - alarm4 = ESMF_AlarmCreate(clock=clock2, ringTime=alarmTime, & - ringInterval=alarmStep, rc=rc) - - ! number of clock time steps alarm rings for - nstep = 0 - - ! run the clock - do while (.not. ESMF_ClockIsStopTime(clock2, rc=rc)) - if (ESMF_AlarmIsRinging(alarm4)) then - nstep = nstep + 1 - call ESMF_AlarmRingerOff(alarm4) - endif - call ESMF_ClockAdvance(clock2, rc=rc) - enddo - - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(nstep.eq.8), & - name, failMsg, result, ESMF_SRCLINE) - - call ESMF_AlarmDestroy(alarm4, rc=rc) - call ESMF_ClockDestroy(clock2, rc=rc) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Fractional Time Alarms 2 - write(failMsg, *) " Did not return nstep=4, and ESMF_SUCCESS" - write(name, *) "Fractional Time Alarm Test 2" - call ESMF_TimeIntervalSet(timeStep, sN=-22, sD=7, rc=rc) - call ESMF_TimeIntervalSet(alarmStep, sN=-44, sD=7, rc=rc) - call ESMF_TimeSet(startTime, yy=2000, mm=1, dd=1, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeSet(stopTime, yy=1999, mm=12, dd=31, h=23, m=59, s=28, & - sN=4, sD=7, calendar=gregorianCalendar, rc=rc) - clock2=ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & - name="Clock 2", rc=rc) - call ESMF_TimeSet(alarmTime, yy=1999, mm=12, dd=31, h=23, m=59, s=53, & - sN=2, sD=7, calendar=gregorianCalendar, rc=rc) - alarm4 = ESMF_AlarmCreate(clock=clock2, ringTime=alarmTime, & - ringInterval=alarmStep, rc=rc) - - !print *, "stopTime = " - !call ESMF_TimePrint(stopTime) - !print *, "alarmTime = " - !call ESMF_TimePrint(alarmTime) - !print *, "timeStep = " - !call ESMF_TimeIntervalPrint(timeStep) - !print *, "alarmStep = " - !call ESMF_TimeIntervalPrint(alarmStep) - - ! number of clock time steps alarm rings for - nstep = 0 - - ! run the clock - do while (.not. ESMF_ClockIsStopTime(clock2, rc=rc)) - if (ESMF_AlarmIsRinging(alarm4)) then - nstep = nstep + 1 - call ESMF_AlarmRingerOff(alarm4) - endif - call ESMF_ClockAdvance(clock2, rc=rc) - enddo - - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(nstep.eq.4), & - name, failMsg, result, ESMF_SRCLINE) - - call ESMF_AlarmDestroy(alarm4, rc=rc) - call ESMF_ClockDestroy(clock2, rc=rc) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Alarm ringTime = clock startTime => should ring immediately - ! upon alarm creation. - write(failMsg, *) " Did not return alarm ringing and ESMF_SUCCESS" - write(name, *) "Test Alarm ringTime = Clock startTime" - call ESMF_TimeIntervalSet(timeStep, ms=10, rc=rc) - call ESMF_TimeSet(startTime, yy=1999, mm=12, dd=31, h=23, m=59, s=59, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeSet(stopTime, yy=2000, mm=1, dd=1, & - calendar=gregorianCalendar, rc=rc) - clock2=ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & - name="Clock 2", rc=rc) - alarm4 = ESMF_AlarmCreate(clock=clock2, ringTime=startTime, rc=rc) - - bool = ESMF_AlarmIsRinging(alarm4) - - call ESMF_Test((bool.and.rc.eq.ESMF_SUCCESS), & - name, failMsg, result, ESMF_SRCLINE) - - call ESMF_AlarmDestroy(alarm4, rc=rc) - call ESMF_ClockDestroy(clock2, rc=rc) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Alarm ringTime = clock startTime *and* ringInterval specified - ! upon alarm creation => should ring immediately. Test 1 - ! From Tom Black in Support ticket 1989990. - write(failMsg, *) " Did not return alarm ringing and ESMF_SUCCESS" - write(name, *) "Alarm ringTime = Clock startTime with ringInterval, test 1" - call ESMF_TimeIntervalSet(timeStep, m=2, rc=rc) - call ESMF_TimeIntervalSet(alarmStep, s=60, rc=rc) - call ESMF_TimeSet(startTime, yy=2007, mm=9, dd=18, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeSet(stopTime, yy=2007, mm=9, dd=19, & - calendar=gregorianCalendar, rc=rc) - clock2=ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & - name="Clock 2", rc=rc) - alarm4 = ESMF_AlarmCreate(clock=clock2, ringTime=startTime, & - ringInterval=alarmStep, rc=rc) - - call ESMF_AlarmGet(alarm4, ringTime=alarmTime, rc=rc) - bool = ESMF_AlarmIsRinging(alarm4) - - call ESMF_Test(((alarmTime==startTime+alarmStep).and.bool.and. & - rc.eq.ESMF_SUCCESS), name, failMsg, result, ESMF_SRCLINE) - - call ESMF_AlarmDestroy(alarm4, rc=rc) - call ESMF_ClockDestroy(clock2, rc=rc) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Alarm ringTime = clock startTime *and* ringInterval specified - ! upon alarm creation => should ring immediately. Test 2 - ! From Tom Black in Support ticket 1989990. - write(failMsg, *) " Did not return alarm ringing 21 times and ESMF_SUCCESS" - write(name, *) "Alarm ringTime = Clock startTime with ringInterval, test 2" - - ! any single failure will cause the whole test to fail - testPass = .true. - - call ESMF_TimeIntervalSet(timeStep, s=60, rc=rc) - call ESMF_TimeIntervalSet(runDuration, s=3600, rc=rc) - call ESMF_TimeIntervalSet(alarmStep, s=180, rc=rc) - call ESMF_TimeSet(startTime, yy=2007, mm=9, dd=18, & - calendar=gregorianCalendar, rc=rc) - clock2=ESMF_ClockCreate(timeStep, startTime, & - runDuration=runDuration, name="Clock 2", rc=rc) - - ! Tom Black's AlarmCreate() ... - alarm4=ESMF_AlarmCreate( & - name ='ALARM Recv from Parent' & !<-- Name of Alarm - ,clock =clock2 & !<-- Each domain's ATM Driver Clock - ,ringTime =startTime & !<-- First time the Alarm rings (ESMF) - ,ringInterval =alarmStep & !<-- Recv from my parent at this - ! frequency (ESMF) - ,ringTimeStepCount=1 & !<-- The Alarm rings for this many - ! timesteps - ,sticky =.false. & !<-- Alarm does not ring until turned off - ,rc =rc) - - ! run the clock - ringCount = 0 - do while (.not. ESMF_ClockIsStopTime(clock2, rc=rc)) - call ESMF_ClockGet(clock2, advanceCount=forwardCount, rc=rc) - !print *, "At clock timestep #", forwardCount - - call ESMF_AlarmGet(alarm4, clock=clock1, rc=rc) - call ESMF_ClockGet(clock1, currTime=currentTime2, rc=rc) - !print *, "Alarm's clock's currTime ..." - !call ESMF_TimePrint(currentTime2, options="string", rc=rc) - if (clock2 /= clock1) then - testPass = .false. - !print *, "Alarm's clock and domain clock are *not* the same" - endif - - call ESMF_ClockGet(clock2, currTime=currentTime, prevTime=prevTime, & - rc=rc) - !print *, "Clock's currTime and prevTime ..." - !call ESMF_TimePrint(currentTime, options="string", rc=rc) - !call ESMF_TimePrint(prevTime, options="string", rc=rc) - - if (currentTime /= currentTime2) then - testPass = .false. - !print *, "Alarm's clock's currTime is *not* the same as the domain clock's currTime" - endif - - call ESMF_AlarmGet(alarm4, ringTime=alarmTime, rc=rc) - !print *, "Alarm's ringTime ..." - !call ESMF_TimePrint(alarmTime, options="string", rc=rc) - - if (ESMF_AlarmIsRinging(alarm=alarm4, rc=rc)) then - ringCount = ringCount + 1 - !print *, " Alarm is ringing" - if (alarmTime /= currentTime+alarmStep) then - testPass = .false. - !print *, " Alarm ringTime *not* equal to clock currTime + alarmStep" - endif - endif - call ESMF_ClockAdvance(clock2, rc=rc) - enddo - - call ESMF_ClockGet(clock2, advanceCount=forwardCount, rc=rc) - !print *, "End of clock run: At clock timestep #", forwardCount - if (ESMF_AlarmIsRinging(alarm=alarm4, rc=rc)) then - !print *, " Alarm is ringing" - ringCount = ringCount + 1 - endif - - ! Alarm should have rung 21 times, including from timestep 0 (upon alarm - ! creation) through timestep 60 (end of clock run) inclusive. - ! Final ringTime should be one alarmStep past the clock end time. - call ESMF_AlarmGet(alarm4, ringTime=alarmTime, rc=rc) - call ESMF_Test(((alarmTime==startTime+runDuration+alarmStep).and. & - ringCount==21.and.testPass.and. & - rc.eq.ESMF_SUCCESS), name, failMsg, result, ESMF_SRCLINE) - !print *, "Alarm rang ", ringCount, " times." - !print *, "Alarm's final ringTime, after final clockAdvance() ..." - !call ESMF_TimePrint(alarmTime, options="string", rc=rc) - - call ESMF_AlarmDestroy(alarm4, rc=rc) - call ESMF_ClockDestroy(clock2, rc=rc) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Alarm ringTime = clock startTime *and* ringInterval specified - ! upon alarm creation => should ring immediately. Test 3, test REVERSE - ! back to clock starttime. Robustness test for solution to - ! Tom Black problem in Support ticket 1989990. - write(failMsg, *) " Did not return alarm ringing 41 times and ESMF_SUCCESS" - write(name, *) "Alarm ringTime = Clock startTime with ringInterval, test 3 (reverse)" - - call ESMF_TimeIntervalSet(timeStep, s=60, rc=rc) - call ESMF_TimeIntervalSet(runDuration, s=3600, rc=rc) - call ESMF_TimeIntervalSet(alarmStep, s=180, rc=rc) - call ESMF_TimeSet(startTime, yy=2007, mm=9, dd=18, & - calendar=gregorianCalendar, rc=rc) - clock2=ESMF_ClockCreate(timeStep, startTime, & - runDuration=runDuration, name="Clock 2", rc=rc) - - ! like Tom Black's AlarmCreate(), but sticky - alarm4=ESMF_AlarmCreate( & - name ='ALARM Recv from Parent' & !<-- Name of Alarm - ,clock =clock2 & !<-- Each domain's ATM Driver Clock - ,ringTime =startTime & !<-- First time the Alarm rings (ESMF) - ,ringInterval =alarmStep & !<-- Recv from my parent at this - ! frequency (ESMF) - ,rc =rc) - - ! number of clock time steps alarm rings for - nring = 0 - - ! number of times the clock has been run - nclock = 0 - - do while (nclock < 2) - ! run the clock - do while (.not. ESMF_ClockIsDone(clock2, rc=rc)) - if (ESMF_AlarmIsRinging(alarm4)) then - nring = nring + 1 - !print *, "on" - call ESMF_AlarmRingerOff(alarm4, rc=rc) - else - !print *, "off" - endif - call ESMF_ClockAdvance(clock2, rc=rc) - enddo - - if (nclock.eq.0) then - call ESMF_ClockGet(clock2, direction=forwardDirection, & - advanceCount=forwardCount, rc=rc) - !print *, "forwardCount = ", forwardCount - else - call ESMF_ClockGet(clock2, direction=reverseDirection, & - advanceCount=reverseCount, rc=rc) - !print *, "reverseCount = ", reverseCount - endif - - call ESMF_ClockSet(clock2, direction=ESMF_DIRECTION_REVERSE, rc=rc) - nclock = nclock + 1 - enddo - - ! count ring at the end point - if (ESMF_AlarmIsRinging(alarm4)) then - nring = nring + 1 - !print *, "on" - call ESMF_AlarmRingerOff(alarm4, rc=rc) - else - !print *, "off" - endif - - call ESMF_Test((rc.eq.ESMF_SUCCESS).and.(nring.eq.41).and. & - (forwardCount.eq.60).and.(reverseCount.eq.0).and. & - (forwardDirection.eq.ESMF_DIRECTION_FORWARD).and. & - (reverseDirection.eq.ESMF_DIRECTION_REVERSE).and. & - ESMF_ClockIsReverse(clock2), & - name, failMsg, result, ESMF_SRCLINE) - - !print *, "nring = ", nring, " nclock = ", nclock - - call ESMF_AlarmDestroy(alarm4, rc=rc) - call ESMF_ClockDestroy(clock2, rc=rc) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Alarm ringTime = clock startTime *and* ringInterval specified - ! upon alarm creation *and* after clock restored from restart state -- - ! with 2 calls to ESMF_ClockSet() -- should ring immediately. - ! This approach to restart will become obsolete with the implementation - ! of WriteRestart()/ReadStart(), but it should remain technically valid, - ! along with this unit test. From Ratko Vasic in ticket #2685243. - - write(failMsg, *) " Did not return alarm ringing and ESMF_SUCCESS" - write(name, *) "Alarm ringTime = Clock startTime with ringInterval, after clock restore" - - call ESMF_TimeIntervalSet(timeStep, m=3, rc=rc) - call ESMF_TimeIntervalSet(TIMEINTERVAL_HISTORY, h=3, rc=rc) - call ESMF_TimeSet(startTime, mm=9, dd=18, yy=2007, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeSet(stopTime, mm=9, dd=19, yy=2007, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeSet(currTime, mm=9, dd=18, yy=2007, h=12, & - calendar=gregorianCalendar, rc=rc) - - CLOCK_ATM=ESMF_ClockCreate( & - name ='CLOCK_ATM' & !<-- The ATM Clock's name - ,timeStep =timeStep & !<-- The fundamental timestep in - ! this component - ,startTime =startTime & !<-- Start time of simulation - ,stopTime =stopTime & !<-- Stop time of simulation - ,rc =rc) - - ! 1st ClockSet() to reset currTime and advanceCount for restart - call ESMF_ClockSet( & - clock =CLOCK_ATM & !<-- The ATM Component's Clock - ,currtime =currTime & !<-- Current time of simulation - ,advanceCount=240_ESMF_KIND_I8 & !<-- Timestep at this current time - ,rc =rc) - - ! 2nd ClockSet() with same values that CLOCK_ATM already has; should - ! have no affect - call ESMF_ClockSet(clock =CLOCK_ATM & - ,currtime =currTime & - ,starttime=startTime & - ,rc =rc) - - !call ESMF_ClockPrint(CLOCK_ATM, rc=rc) - - ALARM_HISTORY=ESMF_AlarmCreate( & - name ='ALARM_HISTORY' & - ,clock =CLOCK_ATM & ! <-- ATM Clock - ,ringTime =currTime & ! <-- Forecast/Restart start - ! time (ESMF) - ,ringInterval =TIMEINTERVAL_HISTORY & ! <-- Time interval between - ,ringTimeStepCount=1 & ! <-- The Alarm rings for - ! this many timesteps - ,sticky =.false. & ! <-- Alarm does not ring - ! until turned off - ,rc =rc) - - !call ESMF_AlarmPrint(ALARM_HISTORY, rc=rc) - - call ESMF_AlarmGet(ALARM_HISTORY, ringTime=alarmTime, rc=rc) - bool = ESMF_AlarmIsRinging(ALARM_HISTORY) - - call ESMF_Test(((alarmTime==currTime+TIMEINTERVAL_HISTORY).and.bool & - .and. rc.eq.ESMF_SUCCESS), & - name, failMsg, result, ESMF_SRCLINE) - - call ESMF_AlarmDestroy(ALARM_HISTORY, rc=rc) - call ESMF_ClockDestroy(CLOCK_ATM, rc=rc) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Alarm list re-allocation within clock, part 1 - write(failMsg, *) " Did not return ESMF_SUCCESS" - write(name, *) "Alarm list reallocation Test 1" - call ESMF_TimeIntervalSet(timeStep, ms=10, rc=rc) - call ESMF_TimeIntervalSet(alarmStep, ms=100, rc=rc) - call ESMF_TimeSet(startTime, yy=1999, mm=12, dd=31, h=23, m=59, s=59, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeSet(stopTime, yy=2000, mm=1, dd=1, & - calendar=gregorianCalendar, rc=rc) - clock2=ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & - name="Clock 2", rc=rc) - call ESMF_TimeSet(alarmTime, yy=1999, mm=12, dd=31, h=23, m=59, s=59, & - ms=200, calendar=gregorianCalendar, rc=rc) - - ! fill up clock's alarmList - do i=1,200 - alarm5(i) = ESMF_AlarmCreate(clock=clock2, ringTime=alarmTime, & - ringInterval=alarmStep, rc=rc) - enddo - - ! add one more alarm than there is space for (200), forcing a - ! reallocation to 400 alarms - ! also, set 201st alarm to be the first to ring upon the 1st timestep - call ESMF_TimeSet(alarmTime, yy=1999, mm=12, dd=31, h=23, m=59, s=59, & - ms=10, calendar=gregorianCalendar, rc=rc) - alarm4 = ESMF_AlarmCreate(name="201st Alarm", clock=clock2, & - ringTime=alarmTime, ringInterval=alarmStep, & - rc=rc) - - ! see if the 201st alarm was successfully added to the clock - call ESMF_Test((rc.eq.ESMF_SUCCESS), & - name, failMsg, result, ESMF_SRCLINE) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Alarm list re-allocation within clock, part 2 - write(failMsg, *) " Did not return 201 alarms and name '201st Alarm'" - write(name, *) "Alarm list reallocation Test 2" - call ESMF_ClockGetAlarmList(clock2, ESMF_ALARMLIST_ALL, & - alarmList=alarmList, & - alarmCount=alarmCount, rc=rc) - write(*,*) "rc=",rc - call ESMF_AlarmGet(alarmList(alarmCount), name=aName, rc=rc) - - !print *, "alarmCount = ", alarmCount - !print *, "201st alarm name = ", aName - write(*,*) "rc=",rc - - ! see if we have 201 alarms and if the 201st alarm has the right name! - call ESMF_Test((alarmCount.eq.201).and.(aName.eq."201st Alarm") & - .and.(rc.eq.ESMF_SUCCESS), & - name, failMsg, result, ESMF_SRCLINE) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Alarm list re-allocation within clock, part 3 - write(failMsg, *) " Did not return 201st alarm ringing" - write(name, *) "Alarm list reallocation Test 3" - call ESMF_ClockAdvance(clock2, rc=rc) - call ESMF_ClockGetAlarmList(clock2, ESMF_ALARMLIST_RINGING, & - alarmList=alarmList, & - alarmCount=alarmCount, rc=rc) - ! double check ringing with Alarm API call - isringing = ESMF_AlarmIsRinging(alarm4, rc=rc) - - !print *, "alarmCount = ", alarmCount - call ESMF_AlarmGet(alarmList(alarmCount), name=aName, rc=rc) - !print *, "Ringing alarm name = ", trim(aName), ", is ringing = ", & - !isringing - - ! see if the 201st alarm is the only one ringing - call ESMF_Test(isringing.and.(alarmCount.eq.1) & - .and.(aName.eq."201st Alarm") & - .and.(rc.eq.ESMF_SUCCESS), & - name, failMsg, result, ESMF_SRCLINE) - - ! cleanup - do i=1,200 - call ESMF_AlarmDestroy(alarm5(i), rc=rc) - enddo - call ESMF_AlarmDestroy(alarm4, rc=rc) - call ESMF_ClockDestroy(clock2, rc=rc) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - ! Based on reproducer clocktester.F90 from Atanas. See bug #1531948. - write(failMsg, *) " Did not ring enough times during forward/backward march" - write(name, *) "Test ESMF_DIRECTION_FORWARD to a non-sticky alarm " // & - "point, ESMF_DIRECTION_REVERSE, ESMF_DIRECTION_FORWARD" - testPass = .true. - call ESMF_TimeSet (startTime, yy=2009, mm=1, dd=1, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeSet (stopTime, yy=2009, mm=1, dd=2, h=0, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeIntervalSet (timeStep, s=3600, rc=rc) - clock = ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & - name="ApplClock", rc=rc) - if (rc /= ESMF_SUCCESS) testPass = .false. - - call ESMF_TimeIntervalSet (alarmStep, s=7200, rc=rc) - !call ESMF_TimeIntervalSet(ringDuration, h=1, rc=rc) - !call ESMF_TimeSet(alarmStopTime, yy=2009, mm=1, dd=1, h=21, & - ! calendar=gregorianCalendar, rc=rc) - alarm1 = ESMF_AlarmCreate (clock=clock, & - ringTime=startTime, ringInterval=alarmStep, & - ! ringDuration=ringDuration, & - ! stopTime=alarmStopTime, & - sticky=.false., name="testAlarm", rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - - !call ESMF_AlarmPrint(alarm1, options="ringduration string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_AlarmPrint(alarm1, options="ringtimestepcount string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - - alarmCount = 0 - expectedCount = 22 - do - !print *, "***********************Top of loop 1 **********************" - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_ClockPrint(clock, options="currtime string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - if (ESMF_AlarmIsRinging(alarm1, rc=rc)) then - alarmCount = alarmCount + 1 - !print *, "alarm1 is ringing" - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_AlarmRingerOff(alarm1, rc=rc) - endif - !call ESMF_AlarmPrint(alarm1, options="ringbegin string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_AlarmPrint(alarm1, options="ringtime string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_AlarmPrint(alarm1, options="ringend string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_ClockAdvance(clock, rc=rc) - !call ESMF_AlarmPrint(alarm1, options="ringend string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - if (ESMF_ClockIsStopTime(clock, rc=rc)) exit - enddo - !print *, "At end of 1st forward run, alarmCount = ", alarmCount - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - - call ESMF_ClockSet(clock, direction=ESMF_DIRECTION_REVERSE, rc=rc) - - i=0 - do - !print *, "***********************Top of loop 2 **********************" - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_ClockPrint(clock, options="currtime string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - if (ESMF_AlarmIsRinging(alarm1, rc=rc)) then - alarmCount = alarmCount + 1 - !print *, "alarm1 is ringing" - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_AlarmRingerOff(alarm1, rc=rc) - endif - !call ESMF_AlarmPrint(alarm1, options="ringbegin string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_AlarmPrint(alarm1, options="ringtime string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_ClockAdvance(clock, rc=rc) - i = i+1 - if (i == 5) exit - enddo - !print *, "At end of reverse run, alarmCount = ", alarmCount - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - - call ESMF_ClockSet(clock, direction=ESMF_DIRECTION_FORWARD, rc=rc) - - i=0 - do - !print *, "***********************Top of loop 3 **********************" - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_ClockPrint(clock, options="currtime string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - if (ESMF_AlarmIsRinging(alarm1, rc=rc)) then - alarmCount = alarmCount + 1 - !print *, "alarm1 is ringing" - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_AlarmRingerOff(alarm1, rc=rc) - endif - !call ESMF_AlarmPrint(alarm1, options="ringbegin string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - !call ESMF_AlarmPrint(alarm1, options="ringtime string", rc=rc) - !call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_ClockAdvance(clock, rc=rc) - i = i+1 - if (i == 15) exit - enddo - - if (.not. testPass .or. alarmCount /= expectedCount) then - if (.not. testPass) print *, 'bad return codes discovered' - write (failMsg,*) trim (failMsg), ', alarmCount = ', alarmCount, ', expected = ', expectedCount - print *, 'The alarm ringTime may be stuck at:' - call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - call ESMF_AlarmPrint (alarm1, options="ringTime string", rc=rc) - call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - end if - - call ESMF_Test (testPass .and. alarmCount == expectedCount, & - name, failMsg, result, ESMF_SRCLINE) - call ESMF_UtilIOUnitFlush(ESMF_UtilIOStdout) - - call ESMF_AlarmDestroy (alarm1, rc=rc) - call ESMF_ClockDestroy (clock, rc=rc) - - ! ---------------------------------------------------------------------------- - !EX_UTest - !Test Alarm ringTime increment, first forwards a fixed number of - !timesteps, stopping at an alarm ringing time step. - !Using ESMF_DIRECTION_REVERSE, step backwards to some time prior to the - !clock's startTime. Then go ESMF_DIRECTION_FORWARD to one step past an - !alarm ringing time step, and then ESMF_DIRECTION_REVERSE once more. - ! Count number of rings. See bug #1531948. - write(failMsg, *) " Did not ring enough times during forward/backward march" - write(name, *) "Test ESMF_DIRECTION_FORWARD to an alarm point, " // & - "ESMF_DIRECTION_REVERSE, ESMF_DIRECTION_FORWARD, " // & - "ESMF_DIRECTION_REVERSE" - - testPass = .true. - call ESMF_TimeSet (startTime, yy=2008, mm=1, dd=23, h=0, & - calendar=gregorianCalendar, rc=rc) - !call ESMF_TimePrint (startTime, options="string isofrac", rc=rc) - call ESMF_TimeIntervalSet (timeStep, h=3, rc=rc) - clock = ESMF_ClockCreate(startTime = startTime, timeStep=timeStep, & - name="clock 1", rc=rc) - if (rc /= ESMF_SUCCESS) testPass = .false. - - call ESMF_TimeSet (alarmTime, yy=2008, mm=1, dd=23, h=6, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeIntervalSet (alarmStep, h=6, rc=rc) - alarm1 = ESMF_AlarmCreate ( & - name="Alarm 1", clock=clock, & - ringTime=alarmTime, ringInterval=alarmStep, rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - - alarmCount = 0 - expectedCount = 11 - do, i=1,6 - call ESMF_ClockAdvance (clock, rc=rc) - !call ESMF_ClockPrint (clock, options="currTime string", rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - if (ESMF_alarmIsRinging (alarm1)) then - alarmCount = alarmCount + 1 - !print *, 'alarm IS ringing at forwards timestep', i - call ESMF_AlarmRingerOff (alarm1, rc=rc) - else - !print *, 'alarm not ringing at forwards timestep', i - end if - end do - - !print *, 'SETTING CLOCK BACKWARDS' - call ESMF_ClockSet (clock, direction=ESMF_DIRECTION_REVERSE, rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - - do, i=5, -5, -1 - call ESMF_ClockAdvance (clock, rc=rc) - !call ESMF_ClockPrint (clock, options="currTime string", rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - if (ESMF_alarmIsRinging (alarm1)) then - alarmCount = alarmCount + 1 - !print *, 'alarm IS ringing at backwards timestep', i - call ESMF_AlarmRingerOff (alarm1, rc=rc) - !call ESMF_AlarmPrint(alarm1, options="ringTime string", rc=rc) - else - !print *, 'alarm not ringing at backwards timestep', i - !call ESMF_ClockPrint (clock, options="currTime string", rc=rc) - end if - end do - - !print *, 'SETTING CLOCK FORWARDS' - call ESMF_ClockSet (clock, direction=ESMF_DIRECTION_FORWARD, rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - - do, i=-4,7 - call ESMF_ClockAdvance (clock, rc=rc) - !call ESMF_ClockPrint (clock, options="currTime string", rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - if (ESMF_alarmIsRinging (alarm1)) then - alarmCount = alarmCount + 1 - !print *, 'alarm IS ringing at forwards timestep', i - call ESMF_AlarmRingerOff (alarm1, rc=rc) - else - !print *, 'alarm not ringing at forwards timestep', i - end if - end do - - !print *, 'SETTING CLOCK BACKWARDS' - call ESMF_ClockSet (clock, direction=ESMF_DIRECTION_REVERSE, rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - - do, i=6, -5, -1 - call ESMF_ClockAdvance (clock, rc=rc) - !call ESMF_ClockPrint (clock, options="currTime string", rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - if (ESMF_alarmIsRinging (alarm1)) then - alarmCount = alarmCount + 1 - !print *, 'alarm IS ringing at backwards timestep', i - call ESMF_AlarmRingerOff (alarm1, rc=rc) - !call ESMF_AlarmPrint(alarm1, options="ringTime string", rc=rc) - else - !print *, 'alarm not ringing at backwards timestep', i - !call ESMF_ClockPrint (clock, options="currTime string", rc=rc) - end if - end do - - if (.not. testPass .or. alarmCount /= expectedCount) then - if (.not. testPass) print *, 'bad return codes discovered' - write (failMsg,*) trim (failMsg), ', alarmCount = ', alarmCount, ', expected = ', expectedCount - print *, 'The alarm ringTime may be stuck at:' - call ESMF_AlarmPrint (alarm1, options="ringTime string", rc=rc) - end if - - call ESMF_Test (testPass .and. alarmCount == expectedCount, & - name, failMsg, result, ESMF_SRCLINE) - - call ESMF_AlarmDestroy (alarm1, rc=rc) - call ESMF_ClockDestroy (clock, rc=rc) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Alarm ringTime increment, first forwards a fixed number of - !timesteps, stopping at an alarm ringing time step. Using a negative - !timestemp, step backwards to some time prior to the clock's startTime. - !Count number of rings. See bugs #1531948, #1457135. - write(failMsg, *) " Did not ring enough times during forward/backward march" - write(name, *) "Test forward to an alarm point, then step backward using a negative timeStep" - - testPass = .true. - call ESMF_TimeSet (startTime, yy=2008, mm=1, dd=23, h=0, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeIntervalSet (timeStep, h=3, rc=rc) - clock = ESMF_ClockCreate(startTime = startTime, timeStep=timeStep, & - name="clock 1", rc=rc) - if (rc /= ESMF_SUCCESS) testPass = .false. - - call ESMF_TimeSet (alarmTime, yy=2008, mm=1, dd=23, h=6, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeIntervalSet (alarmStep, h=6, rc=rc) - alarm1 = ESMF_AlarmCreate ( & - name="Alarm 1", clock=clock, & - ringTime=alarmTime, ringInterval=alarmStep, rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - - alarmCount = 0 - expectedCount = 8 - do, i=1,6 - call ESMF_ClockAdvance (clock, rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - if (ESMF_alarmIsRinging (alarm1)) then - alarmCount = alarmCount + 1 - !print *, 'alarm IS ringing at forwards timestep', i - call ESMF_AlarmRingerOff (alarm1, rc=rc) - else - !print *, 'alarm not ringing at forwards timestep', i - end if - end do - - !print *, 'SETTING CLOCK BACKWARDS WITH NEGATIVE TIMESTEP' - timeStep = -timeStep - call ESMF_ClockSet (clock, timeStep=timeStep, rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - - do, i=5, -5, -1 - call ESMF_ClockAdvance (clock, rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - if (ESMF_alarmIsRinging (alarm1)) then - alarmCount = alarmCount + 1 - !print *, 'alarm IS ringing at backwards timestep', i, ', time:' - !call ESMF_ClockPrint (clock, options="currTime string") - call ESMF_AlarmRingerOff (alarm1, rc=rc) - else - !print *, 'alarm not ringing at backwards timestep', i - !call ESMF_ClockPrint (clock, options="currTime string") - end if - end do - - if (.not. testPass .or. alarmCount /= expectedCount) then - if (.not. testPass) print *, 'bad return codes discovered' - write (failMsg,*) trim (failMsg), ', alarmCount = ', alarmCount, ', expected = ', expectedCount - print *, 'The alarm ringTime may be stuck at:' - call ESMF_AlarmPrint (alarm1, options="ringTime string", rc=rc) - end if - - call ESMF_Test (testPass .and. alarmCount == expectedCount, & - name, failMsg, result, ESMF_SRCLINE) - - call ESMF_AlarmDestroy (alarm1, rc=rc) - call ESMF_ClockDestroy (clock, rc=rc) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Alarm ringTime increment, first forwards a fixed number of - !timesteps, stopping at a non-alarm ringing time step. Using a negative - !timestemp, step backwards to some time prior to the clock's startTime. - !Count number of rings. See bugs #1531948, #1457135. - write(failMsg, *) " Did not ring enough times during forward/backward march" - write(name, *) "Test forward to a non-ringing step, then step backward using a negative timeStep" - - testPass = .true. - call ESMF_TimeSet (startTime, yy=2008, mm=1, dd=23, h=0, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeIntervalSet (timeStep, h=3, rc=rc) - clock = ESMF_ClockCreate(startTime = startTime, timeStep=timeStep, & - name="clock 1", rc=rc) - if (rc /= ESMF_SUCCESS) testPass = .false. - - call ESMF_TimeSet (alarmTime, yy=2008, mm=1, dd=23, h=6, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeIntervalSet (alarmStep, h=6, rc=rc) - alarm1 = ESMF_AlarmCreate ( & - name="Alarm 1", clock=clock, & - ringTime=alarmTime, ringInterval=alarmStep, rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - - alarmCount = 0 - expectedCount = 9 - do, i=1,7 - call ESMF_ClockAdvance (clock, rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - if (ESMF_alarmIsRinging (alarm1)) then - alarmCount = alarmCount + 1 - !print *, 'alarm IS ringing at forwards timestep', i - call ESMF_AlarmRingerOff (alarm1, rc=rc) - else - !print *, 'alarm not ringing at forwards timestep', i - end if - end do - - !print *, 'SETTING CLOCK BACKWARDS WITH NEGATIVE TIMESTEP' - timeStep = -timeStep - call ESMF_ClockSet (clock, timeStep=timeStep, rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - - do, i=6, -5, -1 - call ESMF_ClockAdvance (clock, rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - if (ESMF_alarmIsRinging (alarm1)) then - alarmCount = alarmCount + 1 - !print *, 'alarm IS ringing at backwards timestep', i, ', time:' - !call ESMF_ClockPrint (clock, options="currTime string") - call ESMF_AlarmRingerOff (alarm1, rc=rc) - else - !print *, 'alarm not ringing at backwards timestep', i - !call ESMF_ClockPrint (clock, options="currTime string") - end if - end do - - if (.not. testPass .or. alarmCount /= expectedCount) then - if (.not. testPass) print *, 'bad return codes discovered' - write (failMsg,*) trim (failMsg), ', alarmCount = ', alarmCount, ', expected = ', expectedCount - print *, 'The alarm ringTime may be stuck at:' - call ESMF_AlarmPrint (alarm1, options="ringTime string", rc=rc) - end if - - call ESMF_Test (testPass .and. alarmCount == expectedCount, & - name, failMsg, result, ESMF_SRCLINE) - - ! - ! ---------------------------------------------------------------------------- - - !EX_UTest - write(failMsg, *) " Did not show null clock in alarm" - write(name, *) "Test alarm after destroying its associated clock" - call ESMF_ClockDestroy (clock, rc=rc) - willRingNext = ESMF_AlarmWillRingNext(alarm1, rc=rc) - call ESMF_Test (rc==ESMC_RC_PTR_NULL .and. .not.willRingNext, & - name, failMsg, result, ESMF_SRCLINE) - - call ESMF_AlarmDestroy (alarm1, rc=rc) - - ! ---------------------------------------------------------------------------- - - !EX_UTest - !Test Alarm ringTime increment, arbitrarily forwards and backwards using - ! positive and negative timesteps. Alarm ringTime and ringInterval are - ! changed with each change in timestep direction. The extent of the run - ! of each timestep value is different with each change in direction. - write(failMsg, *) " Did not ring enough times during arbitrary forward/backward march" - write(name, *) "Test arbitrary positive/negative timeStep runs with differing alarms" - - testPass = .true. - alarmCountPass = .true. - - call ESMF_TimeSet (startTime, yy=2008, mm=1, dd=23, h=0, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeIntervalSet (timeStep, h=1, rc=rc) - clock = ESMF_ClockCreate(startTime=startTime, timeStep=timeStep, & - name="clock 1", rc=rc) - if (rc /= ESMF_SUCCESS) testPass = .false. - - call ESMF_TimeSet (alarmTime, yy=2008, mm=1, dd=23, h=2, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeIntervalSet (alarmStep, h=2, rc=rc) - alarm1 = ESMF_AlarmCreate ( & - name="Alarm 1", clock=clock, & - ringTime=alarmTime, ringInterval=alarmStep, rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - - alarmCount = 0 - expectedCount = 15 - - do, i=1,7 - call ESMF_ClockAdvance (clock, rc=rc) - !call ESMF_ClockPrint (clock, options="currTime string", rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - if (ESMF_alarmIsRinging (alarm1)) then - alarmCount = alarmCount + 1 - !print *, 'alarm IS ringing at forwards timestep', i - call ESMF_AlarmRingerOff (alarm1, rc=rc) - else - !print *, 'alarm not ringing at forwards timestep', i - end if - end do - if (alarmCountPass .and. alarmCount /= 3) then - alarmCountPass = .false. - !print *, 'alarmCount = ', alarmCount, ' not 3 at 1st turnaround point' - end if - - !print *, 'SETTING CLOCK BACKWARDS WITH NEW NEGATIVE TIMESTEP AND RINGINTERVAL' - timeStep = -2 * timeStep - alarmStep = -2 * alarmStep - call ESMF_ClockSet (clock, timeStep=timeStep, rc=rc) - call ESMF_AlarmSet (alarm1, ringInterval=alarmStep, rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - - do, i=6, -5, -1 - call ESMF_ClockAdvance (clock, rc=rc) - !call ESMF_ClockPrint (clock, options="currTime string", rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - if (ESMF_alarmIsRinging (alarm1)) then - alarmCount = alarmCount + 1 - !print *, 'alarm IS ringing at backwards timestep', i - call ESMF_AlarmRingerOff (alarm1, rc=rc) - else - !print *, 'alarm not ringing at backwards timestep', i - end if - end do - if (alarmCountPass .and. alarmCount /= 9) then - alarmCountPass = .false. - !print *, 'alarmCount = ', alarmCount, ' not 9 at 2nd turnaround point' - end if - - !print *, 'SETTING CLOCK FORWARDS WITH NEW POSITIVE TIMESTEP, RINGINTERVAL, and RINGTIME' - call ESMF_TimeIntervalSet (timeStep, h=3, rc=rc) - call ESMF_TimeSet (alarmTime, yy=2008, mm=1, dd=22, h=11, & - calendar=gregorianCalendar, rc=rc) - call ESMF_TimeIntervalSet (alarmStep, h=6, rc=rc) - call ESMF_ClockSet (clock, timeStep=timeStep, rc=rc) - call ESMF_AlarmSet (alarm1, ringTime=alarmTime, ringInterval=alarmStep, & - rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - - do, i=1,5 - call ESMF_ClockAdvance (clock, rc=rc) - !call ESMF_ClockPrint (clock, options="currTime string", rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - if (ESMF_alarmIsRinging (alarm1)) then - alarmCount = alarmCount + 1 - !print *, 'alarm IS ringing at forwards timestep', i - call ESMF_AlarmRingerOff (alarm1, rc=rc) - else - !print *, 'alarm not ringing at forwards timestep', i - end if - end do - if (alarmCountPass .and. alarmCount /= 11) then - alarmCountPass = .false. - !print *, 'alarmCount = ', alarmCount, ' not 11 at 3rd turnaround point' - end if - - !print *, 'SETTING CLOCK BACKWARDS WITH NEW NEGATIVE TIMESTEP AND RINGTIME' - call ESMF_TimeIntervalSet (timeStep, h=-1, rc=rc) - call ESMF_TimeSet (alarmTime, yy=2008, mm=1, dd=22, h=21, & - calendar=gregorianCalendar, rc=rc) - call ESMF_ClockSet (clock, timeStep=timeStep, rc=rc) - call ESMF_AlarmSet (alarm1, ringTime=alarmTime, rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - - do, i=4,2,-1 - call ESMF_ClockAdvance (clock, rc=rc) - !call ESMF_ClockPrint (clock, options="currTime string", rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - if (ESMF_alarmIsRinging (alarm1)) then - alarmCount = alarmCount + 1 - !print *, 'alarm IS ringing at backwards timestep', i - call ESMF_AlarmRingerOff (alarm1, rc=rc) - else - !print *, 'alarm not ringing at backwards timestep', i - end if - end do - if (alarmCountPass .and. alarmCount /= 12) then - alarmCountPass = .false. - !print *, 'alarmCount = ', alarmCount, ' not 12 at 4th turnaround point' - end if - - !print *, 'SETTING CLOCK FORWARDS WITH NEW POSITIVE TIMESTEP' - timeStep = -timeStep - call ESMF_ClockGet(clock, currTime=startTime, rc=rc) - call ESMF_ClockSet(clock, timeStep=timeStep, startTime=startTime, & - runTimeStepCount=15, rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - - do while (.not. ESMF_ClockIsDone(clock, rc=rc)) - call ESMF_ClockAdvance (clock, rc=rc) - !call ESMF_ClockPrint (clock, options="currTime string", rc=rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - if (ESMF_alarmIsRinging (alarm1)) then - alarmCount = alarmCount + 1 - !print *, 'alarm IS ringing' - call ESMF_AlarmRingerOff (alarm1, rc=rc) - else - !print *, 'alarm not ringing' - end if - end do - if (alarmCountPass .and. alarmCount /= expectedCount) then - alarmCountPass = .false. - !print *, 'alarmCount = ', alarmCount, ', not ', expectedCount, ' at the end' - end if - - if (.not. alarmCountPass) then - write(failMsg,*) trim(failMsg), ', alarmCount incorrect at one or more turnaround points' - !print *, 'Final alarmCount = ', alarmCount, ', expected = ', expectedCount - !print *, 'Final alarm ringTime:' - !call ESMF_AlarmPrint (alarm1, "ringTime string", rc=rc) - end if - - if (.not. testPass) print *, 'bad return codes discovered' - - call ESMF_Test (testPass .and. alarmCountPass, & - name, failMsg, result, ESMF_SRCLINE) - - call ESMF_AlarmDestroy (alarm1, rc=rc) - call ESMF_ClockDestroy (clock, rc=rc) - - ! ---------------------------------------------------------------------------- -#if 0 - ! The following tests are from Ben@NASA's support ticket 3614994 - write(failMsg, *) " Alarms did not rewind correct number of times " - write(name, *) "Test multiple alarms rewind correct number of times " - rc = ESMF_SUCCESS - testPass = .true. - call Test_ReverseAlarms(testPass, rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - if (.not. testPass) print *, 'bad return codes discovered' - call ESMF_Test (testPass, name, failMsg, result, ESMF_SRCLINE) - - ! ---------------------------------------------------------------------------- - - write(failMsg, *) " Alarms hang... " - write(name, *) "Test multiple alarms replay without hanging " - rc = ESMF_SUCCESS - testPass = .true. - call Test_AlarmHang(testPass, rc) - if (testPass .and. rc /= ESMF_SUCCESS) testPass = .false. - if (.not. testPass) print *, 'bad return codes discovered' - call ESMF_Test (testPass, name, failMsg, result, ESMF_SRCLINE) -#endif - - ! ---------------------------------------------------------------------------- -#endif - - ! destroy calendars - call ESMF_CalendarDestroy(esmf_360dayCalendar, rc=rc) - call ESMF_CalendarDestroy(no_leapCalendar, rc=rc) - call ESMF_CalendarDestroy(julianCalendar, rc=rc) - call ESMF_CalendarDestroy(gregorianCalendar, rc=rc) - - ! finalize ESMF framework - call ESMF_TestEnd(ESMF_SRCLINE) - -#if 0 - contains - - subroutine test_reverseAlarms(testPass, rc) - implicit none - - logical, intent(out) :: testPass - integer :: status,rc - - type(ESMF_TimeInterval) :: dt - type(ESMF_Time) :: start_time, clock_start, clock_end - type(ESMF_Clock) :: clock - character(len=5) :: add_2nd - integer :: nargs - - type(ESMF_TimeInterval) :: tint - type(ESMF_Alarm) :: esmfalarm, firstalarm - - integer :: i,nstep - - type(ESMF_Time) :: time - character(len=10) :: iam='test_clock' - logical :: esmf_ring - integer :: nalarms, n_rings=0 - - testPass = .false. - call ESMF_CalendarSetDefault ( ESMF_CALKIND_GREGORIAN, rc=status ) - call verify_(status) - call ESMF_TimeSet(clock_start,yy=2000,mm=1,dd=1,h=21,m=0,s=0,rc=status) - call verify_(status) - call ESMF_TimeSet(clock_end,yy=2000,mm=12,dd=1,h=21,m=0,s=0,rc=status) - call verify_(status) - call ESMF_TimeSet(start_time,yy=2000,mm=10,dd=1,h=21,m=0,s=0,rc=status) - call verify_(status) - call ESMF_TimeIntervalSet(dt,S=900, sN=0, sD=1,rc=status) - call verify_(status) - clock= ESMF_ClockCreate(timeStep=dt,startTime=clock_start,stopTime=clock_end,rc=status) - call verify_(status) - call ESMF_ClockSet(clock,currTime=start_time,rc=status) - call verify_(status) - - call ESMF_ClockGet(clock,currtime=start_time,rc=status) - if(status /= ESMF_SUCCESS) call ESMF_Finalize() - call ESMF_TimeIntervalSet(tint,h=2,rc=status) - if(status /= ESMF_SUCCESS) call ESMF_Finalize() - firstalarm = ESMF_AlarmCreate(clock=clock,ringInterval=tint,ringTime=start_time,sticky=.false.,name="alarm1",rc=status) - if(status /= ESMF_SUCCESS) call ESMF_Finalize() - - nstep=47 - call ESMF_ClockGet(clock,currtime=start_time,alarmCount=nalarms,rc=status) - !write(*,*) "alarms already in clock: ",nalarms - call verify_(status) - call ESMF_TimeIntervalSet(tint,h=1,rc=status) - call verify_(status) - esmfalarm = ESMF_AlarmCreate(clock=clock,ringInterval=tint,ringTime=start_time,sticky=.false.,name="alarm2",rc=status) - do i=1,nstep - call ESMF_ClockGet(clock,currTime=time) - esmf_ring = ESMF_AlarmIsRinging(esmfalarm,rc=status) - call verify_(status) - if ( esmf_ring) then - !write(*,*)'ringing' - !call ESMF_TimePrint(time,options='string') - end if - call ESMF_ClockAdvance(clock) - enddo - call ESMF_ClockSet(clock, direction=ESMF_DIRECTION_REVERSE, rc=status) - call verify_(status) - !write(*,*)"*************** start rewind *********************" - i = 0 - do - i = i + 1 - !write(*,*) 'Rewind step: ', i - call ESMF_ClockAdvance(clock,rc=status) - call verify_(status) - call ESMF_ClockGet(clock,currTime=time) - if (ESMF_AlarmIsRinging(esmfalarm)) then - !write(*,*)'rewinding one step ',ESMF_AlarmIsRinging(esmfalarm) - n_rings = n_rings + 1 - !call ESMF_TimePrint(time,options='string') - end if - - if (time == start_time) exit - enddo - call ESMF_ClockSet(clock, direction=ESMF_DIRECTION_FORWARD, rc=status) - call verify_(status) - !write(*,*)"*************** end rewind *********************" - do i=1,nstep*2 - call ESMF_ClockGet(clock,currTime=time) - esmf_ring = ESMF_AlarmIsRinging(esmfalarm,rc=status) - call verify_(status) - if ( esmf_ring ) then - !write(*,*)'ringing' - !call ESMF_TimePrint(time,options='string') - end if - call ESMF_ClockAdvance(clock) - enddo - if(n_rings == 12) testPass = .true. - - call ESMF_AlarmDestroy(esmfalarm, rc=status) - call verify_(status) - call ESMF_AlarmDestroy(firstalarm, rc=status) - call verify_(status) - call ESMF_ClockDestroy(clock, rc=status) - call verify_(status) - - end subroutine Test_ReverseAlarms - - subroutine Test_AlarmHang(testPass, rc) - logical, intent(out) :: testPass - integer :: status,rc - - type(ESMF_TimeInterval) :: dt - type(ESMF_Time) :: start_time, clock_start, clock_end - type(ESMF_Clock) :: clock - character(len=5) :: add_2nd - integer :: nargs - - integer :: i,nstep + integer :: i,nstep type(ESMF_TimeInterval) :: tint type(ESMF_Time) :: time type(ESMF_Alarm) :: esmfalarm type(ESMF_Alarm) :: testalarm - character(len=10) :: iam='test_clock' - logical :: esmf_ring - integer :: nalarms + logical :: esmfalarm_ring, testalarm_ring + logical :: allCorrect + rc = ESMF_SUCCESS testPass = .false. + allCorrect = .true. call ESMF_CalendarSetDefault ( ESMF_CALKIND_GREGORIAN, rc=status ) call verify_(status) @@ -3532,9 +1498,6 @@ subroutine Test_AlarmHang(testPass, rc) call verify_(status) nstep = 12 - call ESMF_ClockGet(clock,currtime=start_time,alarmCount=nalarms,rc=status) - !write(*,*) "alarms already in clock: ",nalarms - call verify_(status) call ESMF_TimeIntervalSet(tint,h=1,rc=status) call verify_(status) esmfalarm = ESMF_AlarmCreate(clock=clock,ringInterval=tint,ringTime=start_time,sticky=.false.,name="alarm2",rc=status) @@ -3545,50 +1508,95 @@ subroutine Test_AlarmHang(testPass, rc) call ESMF_AlarmRingerOff(testalarm,rc=status) call verify_(status) do i=1,nstep - call ESMF_AlarmRingerOn(testalarm,rc=status) - call verify_(status) - call ESMF_ClockGet(clock,currTime=time) - esmf_ring = ESMF_AlarmIsRinging(esmfalarm,rc=status) - call verify_(status) - if ( esmf_ring) then - !write(*,*)'ringing: esmfalarm' - call ESMF_TimePrint(time,options='string') - end if - call ESMF_ClockAdvance(clock) + call ESMF_AlarmRingerOn(testalarm,rc=status) + call verify_(status) + esmfalarm_ring = ESMF_AlarmIsRinging(esmfalarm,rc=status) + call verify_(status) + if (modulo((i-1),4) == 0) then + if (.not. esmfalarm_ring) then + allCorrect = .false. + end if + else + if (esmfalarm_ring) then + allCorrect = .false. + end if + end if + testalarm_ring = ESMF_AlarmIsRinging(testalarm,rc=status) + call verify_(status) + if (.not. testalarm_ring) then + allCorrect = .false. + end if + call ESMF_ClockAdvance(clock,rc=status) + call verify_(status) enddo + call ESMF_ClockSet(clock, direction=ESMF_DIRECTION_REVERSE, rc=status) call verify_(status) call ESMF_AlarmRingerOff(testalarm,rc=status) call verify_(status) - !write(*,*)"*************** start rewind *********************" + i = 0 do - call ESMF_ClockAdvance(clock,rc=status) - call verify_(status) - call ESMF_ClockGet(clock,currTime=time) - if (ESMF_AlarmIsRinging(esmfalarm)) then - !write(*,*)'rewinding one step: esmfalarm ',ESMF_AlarmIsRinging(esmfalarm) - call ESMF_TimePrint(time,options='string') - end if - - if (ESMF_AlarmIsRinging(esmfalarm)) then - write(*,*)'rewinding one step: testalarm ',ESMF_AlarmIsRinging(testalarm) - call ESMF_TimePrint(time,options='string') - end if - - if (time == start_time) exit + i = i + 1 + call ESMF_ClockAdvance(clock,rc=status) + call verify_(status) + esmfalarm_ring = ESMF_AlarmIsRinging(esmfalarm,rc=status) + call verify_(status) + if (modulo(i,4) == 0) then + if (.not. esmfalarm_ring) then + allCorrect = .false. + end if + else + if (esmfalarm_ring) then + allCorrect = .false. + end if + end if + testalarm_ring = ESMF_AlarmIsRinging(testalarm,rc=status) + call verify_(status) + call ESMF_ClockGet(clock,currTime=time,rc=status) + call verify_(status) + if (time == start_time & + ! Reversing the clock leads to a shift by one time step in the alarm time, so + ! we also expect it to ring at (start_time + dt) (see also discussion here: + ! https://github.com/esmf-org/esmf/pull/340#discussion_r1900300522) + .or. time == (start_time + dt) & + ! FIXME:(wjs, 2025-01-02) Due to what may be a bug, the clock also currently + ! rings at start_time + 2*dt, because the ring time is adjusted by an + ! additional dt when calling ESMF_AlarmRingerOff after setting the clock's + ! direction to reverse (see + ! https://github.com/esmf-org/esmf/pull/340#issuecomment-2566736806) + .or. time == (start_time + 2*dt)) then + if (.not. testalarm_ring) then + allCorrect = .false. + end if + else + if (testalarm_ring) then + allCorrect = .false. + end if + end if + if (time == start_time) exit enddo + call ESMF_ClockSet(clock, direction=ESMF_DIRECTION_FORWARD, rc=status) call verify_(status) - !write(*,*)"*************** end rewind *********************" do i=1,nstep*2 - call ESMF_ClockGet(clock,currTime=time) - esmf_ring = ESMF_AlarmIsRinging(esmfalarm,rc=status) - call verify_(status) - if ( esmf_ring ) then - !write(*,*)'ringing: esmfalarm' - call ESMF_TimePrint(time,options='string') - end if - call ESMF_ClockAdvance(clock) + esmfalarm_ring = ESMF_AlarmIsRinging(esmfalarm,rc=status) + call verify_(status) + if (modulo((i-1),4) == 0) then + if (.not. esmfalarm_ring) then + allCorrect = .false. + end if + else + if (esmfalarm_ring) then + allCorrect = .false. + end if + end if + testalarm_ring = ESMF_AlarmIsRinging(testalarm,rc=status) + call verify_(status) + if (.not. testalarm_ring) then + allCorrect = .false. + end if + call ESMF_ClockAdvance(clock,rc=status) + call verify_(status) enddo call ESMF_AlarmDestroy(esmfalarm, rc=status) @@ -3598,9 +1606,1370 @@ subroutine Test_AlarmHang(testPass, rc) call ESMF_ClockDestroy(clock, rc=status) call verify_(status) - testPass = .true. + if (allCorrect) then + testPass = .true. + else + testPass = .false. + end if end subroutine Test_AlarmHang -#endif + +subroutine Test_AlarmAdvRewind(testPass, rc) + logical, intent(out) :: testPass + integer, intent(out) :: rc + + type(ESMF_TimeInterval) :: dt + type(ESMF_Time) :: start_time, clock_start, clock_end + type(ESMF_Clock) :: clock + + type(ESMF_TimeInterval) :: tint + + integer :: status,i,j,nstep + + character(len=ESMF_MAXSTR) :: alarm_name + type(ESMF_Time) :: time + type(ESMF_Alarm) :: esmfalarm900, esmfalarm1800 + logical :: esmfalarm900_ring, esmfalarm1800_ring + logical :: allCorrect + + rc = ESMF_SUCCESS + testPass = .false. + allCorrect = .true. + + call ESMF_CalendarSetDefault ( ESMF_CALKIND_GREGORIAN, rc=status ) + call verify_(status) + call ESMF_TimeSet(clock_start,yy=2000,mm=1,dd=1,h=21,m=0,s=0,rc=status) + call verify_(status) + call ESMF_TimeSet(clock_end,yy=2000,mm=12,dd=1,h=21,m=0,s=0,rc=status) + call verify_(status) + call ESMF_TimeSet(start_time,yy=2000,mm=10,dd=1,h=21,m=0,s=0,rc=status) + call verify_(status) + call ESMF_TimeIntervalSet(dt,S=900, sN=0, sD=1,rc=status) + call verify_(status) + clock= ESMF_ClockCreate(timeStep=dt,startTime=clock_start,stopTime=clock_end,rc=status) + call verify_(status) + call ESMF_ClockSet(clock,currTime=start_time,rc=status) + call verify_(status) + + call ESMF_TimeIntervalSet(tint,s=900) + esmfalarm900 = ESMF_AlarmCreate(clock=clock,ringInterval=tint,ringTime=start_time,sticky=.false.,name='alarm_900',rc=status) + call verify_(status) + call ESMF_TimeIntervalSet(tint,s=1800) + esmfalarm1800 = ESMF_AlarmCreate(clock=clock,ringInterval=tint,ringTime=start_time,sticky=.false.,name='alarm_1800',rc=status) + call verify_(status) + + esmfalarm900_ring = ESMF_AlarmIsRinging(esmfalarm900, rc=status) + call verify_(status) + if (.not. esmfalarm900_ring) then + allCorrect = .false. + end if + esmfalarm1800_ring = ESMF_AlarmIsRinging(esmfalarm1800, rc=status) + call verify_(status) + if (.not. esmfalarm1800_ring) then + allCorrect = .false. + end if + + nstep=12 + do i=1,nstep + call ESMF_ClockAdvance(clock) + + esmfalarm900_ring = ESMF_AlarmIsRinging(esmfalarm900, rc=status) + call verify_(status) + if (.not. esmfalarm900_ring) then + allCorrect = .false. + end if + + esmfalarm1800_ring = ESMF_AlarmIsRinging(esmfalarm1800, rc=status) + call verify_(status) + if (modulo(i,2) == 0) then + if (.not. esmfalarm1800_ring) then + allCorrect = .false. + end if + else + if (esmfalarm1800_ring) then + allCorrect = .false. + end if + end if + enddo + + call ESMF_ClockSet(clock, direction=ESMF_DIRECTION_REVERSE, rc=status) + call verify_(status) + i = 0 + do + i = i + 1 + call ESMF_ClockAdvance(clock,rc=status) + call verify_(status) + + esmfalarm900_ring = ESMF_AlarmIsRinging(esmfalarm900, rc=status) + call verify_(status) + if (.not. esmfalarm900_ring) then + allCorrect = .false. + end if + + esmfalarm1800_ring = ESMF_AlarmIsRinging(esmfalarm1800, rc=status) + call verify_(status) + if (modulo(i,2) == 0) then + if (.not. esmfalarm1800_ring) then + allCorrect = .false. + end if + else + if (esmfalarm1800_ring) then + allCorrect = .false. + end if + end if + + call ESMF_ClockGet(clock,currTime=time) + if (time == start_time) exit + enddo + + call ESMF_ClockSet(clock, direction=ESMF_DIRECTION_FORWARD, rc=status) + call verify_(status) + do i=1,nstep*2 + call ESMF_ClockAdvance(clock) + + esmfalarm900_ring = ESMF_AlarmIsRinging(esmfalarm900, rc=status) + call verify_(status) + if (.not. esmfalarm900_ring) then + allCorrect = .false. + end if + + esmfalarm1800_ring = ESMF_AlarmIsRinging(esmfalarm1800, rc=status) + call verify_(status) + if (modulo(i,2) == 0) then + if (.not. esmfalarm1800_ring) then + allCorrect = .false. + end if + else + if (esmfalarm1800_ring) then + allCorrect = .false. + end if + end if + enddo + + if (allCorrect) then + testPass = .true. + else + testPass = .false. + end if +end subroutine Test_AlarmAdvRewind + + subroutine verify_(rc) + integer, intent(in) :: rc + + integer :: error_code,status + if (rc /=0) then + call ESMF_Finalize() + end if + end subroutine verify_ + +subroutine Test_ClockSet(doReverse, testPass, rc) + ! Test ClockSet after an alarm is attached to the clock +#define CONTEXT line=__LINE__,file=__FILE__ +#define CHECKRC if(ESMF_LogFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,CONTEXT,rcToReturn=rc))then;write(0,*)'app abort: ',__FILE__,__LINE__;return;endif + logical, intent(in) :: doReverse ! whether to set up the clock with reverse direction + logical, intent(out) :: testPass + integer, intent(out) :: rc + integer, parameter :: r8 = SELECTED_REAL_KIND(12) ! real r8 + + type(ESMF_Clock) :: clock + type(ESMF_Alarm) :: alarm + type(ESMF_TimeInterval) :: esmf_ival + type(ESMF_Time) :: time, initial, finish, ring_time + real(kind=r8) :: secs + logical :: sticky_alarm + + rc = ESMF_SUCCESS + testPass = .false. + + call ESMF_CalendarSetDefault ( ESMF_CALKIND_GREGORIAN, rc=rc) + CHECKRC + + call ESMF_TimeSet(time, yy=2021, mm=4, dd=6, rc=rc) + CHECKRC + secs = 0 + call ESMF_TimeIntervalSet(esmf_ival,s_r8=secs,rc=rc) + CHECKRC + + initial = time + esmf_ival + + secs = 6000 + call ESMF_TimeIntervalSet(esmf_ival,s_r8=secs,rc=rc) + CHECKRC + finish = time + 2*esmf_ival + + secs = 60 + call ESMF_TimeIntervalSet(esmf_ival,s_r8=secs,rc=rc) + CHECKRC + + clock = ESMF_Clockcreate(timeStep=esmf_ival & + ,startTime=initial,stopTime=finish & + ,refTime=time, rc=rc ) + CHECKRC + + if (doReverse) then + call ESMF_ClockSet(clock,direction=ESMF_DIRECTION_REVERSE, rc=rc) + CHECKRC + sticky_alarm = .false. + else + sticky_alarm = .true. + end if + + secs = 3000 + call ESMF_TimeIntervalSet(esmf_ival,s_r8=secs,rc=rc) + CHECKRC + ring_time = initial + 2*esmf_ival + alarm = ESMF_AlarmCreate(clock, ringTime=ring_time, sticky=sticky_alarm, & + rc=rc) + CHECKRC + + call ESMF_ClockSet(clock, stopTime=ring_time, rc=rc) + CHECKRC + + testPass = .true. ! Because the C++ runtime failure cannot be caught reliably, set this to false. + +#undef CONTEXT +#undef CHECKRC +end subroutine Test_ClockSet + +subroutine Test_GetPrevRingTime(testPass, rc) +#define CONTEXT line=__LINE__,file=__FILE__ +#define CHECKRC if(ESMF_LogFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,CONTEXT,rcToReturn=rc))then;write(0,*)'app abort: ',__FILE__,__LINE__;return;endif + logical, intent(out) :: testPass + integer, intent(out) :: rc + integer, parameter :: r8 = SELECTED_REAL_KIND(12) ! real r8 + + type(ESMF_Clock) :: clock + type(ESMF_Alarm) :: alarm + type(ESMF_TimeInterval) :: esmf_ival, diffTime + type(ESMF_Time) :: time, initial, finish, ring_time, ringTime, prevTime + real(kind=r8) :: secs + logical :: reverse_clock, sticky_alarm, esmf_ring + integer :: i, nstep = 6, nrings + logical :: allCorrect + + rc = ESMF_SUCCESS + testPass = .false. + allCorrect = .true. + + call ESMF_TimeSet(time, yy=2021, mm=4, dd=6, rc=rc) ; CHECKRC + + secs = 0 + call ESMF_TimeIntervalSet(esmf_ival,s_r8=secs,rc=rc) ; CHECKRC + initial = time + esmf_ival + call ESMF_TimePrint(initial, options="string", rc=rc) ; CHECKRC + + secs = 6000 ! 100 minutes + call ESMF_TimeIntervalSet(esmf_ival,s_r8=secs,rc=rc) ; CHECKRC + finish = time + esmf_ival + call ESMF_TimePrint(finish, options="string", rc=rc) ; CHECKRC + + secs = 60 ! 1 minute + call ESMF_TimeIntervalSet(esmf_ival,s_r8=secs,rc=rc) ; CHECKRC + + clock = ESMF_Clockcreate(timeStep=esmf_ival & + ,startTime=initial,stopTime=finish & + ,refTime=time, rc=rc ) ; CHECKRC + + secs = 120 ! alarm step is clock step x 2, 2 minutes + call ESMF_TimeIntervalSet(esmf_ival,s_r8=secs,rc=rc) ; CHECKRC + ring_time = initial + alarm = ESMF_AlarmCreate(clock, ringTime=ring_time, ringInterval=esmf_ival, & + sticky=.false., rc=rc) ; CHECKRC + nrings = 0 + prevTime = initial + do i=1,nstep + call ESMF_ClockAdvance(clock) + call ESMF_ClockGet(clock,currTime=time) + esmf_ring = ESMF_AlarmIsRinging(alarm, rc=rc) + call verify_(rc) + if ( esmf_ring) then + nrings = nrings + 1 + write(*,*) 'alarm is ringing', nrings + call ESMF_TimePrint(time,options='string') + call ESMF_AlarmGet(alarm, ringTime=ringTime, rc=rc) + call verify_(rc) + write(*,*) 'Ring Time' + call ESMF_TimePrint(ringTime,options='string') + + diffTime = ringTime - prevTime + if(diffTime /= esmf_ival) allCorrect = .false. ! both should be 20 minutes or 120 seconds + prevTime = ringTime + end if + enddo + +! call ESMF_ClockSet(clock,direction=ESMF_DIRECTION_REVERSE, rc=rc) ; CHECKRC +! +! reverse_clock = ESMF_ClockIsReverse(clock, rc=rc) ; CHECKRC +! sticky_alarm = .not.reverse_clock +! +! write(0,'("reverse =",x,l)') reverse_clock +! write(0,'("sticky =",x,l)') sticky_alarm +! +! secs = 3000 +! call ESMF_TimeIntervalSet(esmf_ival,s_r8=secs,rc=rc) ; CHECKRC +! ring_time = initial + esmf_ival +! print *, 'Before Alarm Create ringTime: ' +! call ESMF_TimePrint(ring_time, options="string", rc=rc) ; CHECKRC +! +! call ESMF_TimePrint(ring_time, options="string", rc=rc) ; CHECKRC +! call ESMF_AlarmGet(alarm, ringTime=ring_time, rc=rc) ; CHECKRC +! print *, 'After Alarm Create ringTime: ' +! call ESMF_TimePrint(ring_time, options="string", rc=rc) ; CHECKRC +! +! call ESMF_ClockSet(clock, stopTime=ring_time, rc=rc) ; CHECKRC +! +! call ESMF_alarmPrint(alarm,options='sticky') + + if (allCorrect) then + testPass = .true. + else + testPass = .false. + end if + +#undef CONTEXT +#undef CHECKRC +end subroutine Test_GetPrevRingTime + + + character*64 function clockCurrTime(clock) + type(ESMF_Clock) :: clock + type(ESMF_Time ) :: time + integer :: yy, mm, dd, d, h, m, s, rc + type (ESMF_VM) :: vm + integer :: lpet + + call ESMF_ClockGet(clock, currTime=time, rc=rc) + if(rc /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_TimeGet(Time, yy=yy, mm=mm, dd=dd, d=d, h=h, m=m, s=s, rc=rc) + if(rc /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_VMGetCurrent(vm=vm, rc=rc) + if(rc /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_VMGet(vm, localpet = lpet, rc=rc) + if(rc /= ESMF_SUCCESS) call ESMF_Finalize() + + if(lpet == 0) then + !write(clockCurrTime, '(3I4, 3I4)') yy, mm, dd, h, m, s + write(clockCurrTime, '(I2.2,A1,I2.2,A1,I2.2)') h, ':', m, ':', s + endif + end function + +!------------------------------------------------------------------------ +! Forward Tests +!------------------------------------------------------------------------ + subroutine ForwardAlarm_Test1(rc) + ! Test 1: c.t0 = a.t0, c.dt = a.dt = 10 min + + integer, intent(out) :: rc + + type (ESMF_Clock) :: clock + type (ESMF_Alarm) :: alarm + type (ESMF_Time) :: startTime, stopTime, ringTime + type (ESMF_TimeInterval) :: timeStep, ringTimeInterval + + integer :: status, n + logical :: ringing, enabled, sticky + logical :: allCorrect + + rc = ESMF_FAILURE + allCorrect = .true. + + call ESMF_TimeSet(startTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(stopTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(ringTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_TimeIntervalSet(timeStep,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeIntervalSet(ringTimeInterval,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + clock = ESMF_ClockCreate(timeStep=timeStep,startTime=startTime,stopTime=stopTime,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + alarm = ESMF_AlarmCreate(clock, ringTime=ringTime, ringInterval=ringTimeInterval, enabled=.true., sticky=.false., name='alarm', rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + !call ESMF_AlarmDebug(alarm,'test1',rc=status) + !if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (.not. ringing) then + allCorrect = .false. + end if + do n = 1, 6 + call ESMF_ClockAdvance(clock,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (.not. ringing) then + allCorrect = .false. + end if + enddo + + if (allCorrect) then + rc = ESMF_SUCCESS + end if + end subroutine +!------------------------------------------------------------------------ + subroutine ForwardAlarm_Test2(rc) + ! Test 2: c.t0 = a.t0, c.dt = 10 min, a.dt = 20 min + + integer, intent(out) :: rc + + type (ESMF_Clock) :: clock + type (ESMF_Alarm) :: alarm + type (ESMF_Time) :: startTime, stopTime, ringTime + type (ESMF_TimeInterval) :: timeStep, ringTimeInterval + + integer :: status, n + logical :: ringing, enabled, sticky + logical :: allCorrect + + rc = ESMF_FAILURE + allCorrect = .true. + + call ESMF_TimeSet(startTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(stopTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(ringTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_TimeIntervalSet(timeStep,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeIntervalSet(ringTimeInterval,S=1200, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + clock = ESMF_ClockCreate(timeStep=timeStep,startTime=startTime,stopTime=stopTime,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + alarm = ESMF_AlarmCreate(clock, ringTime=ringTime, ringInterval=ringTimeInterval, enabled=.true., sticky=.false., name='alarm', rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + !call ESMF_AlarmDebug(alarm,'test2',rc=status) + !if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (.not. ringing) then + allCorrect = .false. + end if + do n = 1, 6 + call ESMF_ClockAdvance(clock,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (modulo(n,2) == 0) then + ! Alarm should be ringing on even time steps + if (.not. ringing) then + allCorrect = .false. + end if + else + ! Alarm should NOT be ringing on odd time steps + if (ringing) then + allCorrect = .false. + end if + end if + enddo + + if (allCorrect) then + rc = ESMF_SUCCESS + end if + end subroutine +!------------------------------------------------------------------------ + subroutine ForwardAlarm_Test3(rc) + ! Test 3: c.t0 = a.t0, c.dt = 20 min, a.dt = 10 min + ! + ! This should raise an error: it's an error to create an alarm with alarm timeInterval + ! less than clock timeStep + + integer, intent(out) :: rc + + type (ESMF_Clock) :: clock + type (ESMF_Alarm) :: alarm + type (ESMF_Time) :: startTime, stopTime, ringTime + type (ESMF_TimeInterval) :: timeStep, ringTimeInterval + + integer :: status, n + logical :: ringing, enabled, sticky + + rc = ESMF_FAILURE + + call ESMF_TimeSet(startTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(stopTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(ringTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_TimeIntervalSet(timeStep,S=1200, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeIntervalSet(ringTimeInterval,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + clock = ESMF_ClockCreate(timeStep=timeStep,startTime=startTime,stopTime=stopTime,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + ! It's an error to create an alarm with alarm timeInterval less than clock timeStep + alarm = ESMF_AlarmCreate(clock, ringTime=ringTime, ringInterval=ringTimeInterval, enabled=.true., sticky=.false., name='alarm', rc=status) + if(status /= ESMF_SUCCESS) then + ! This is the expected result: the status of ESMF_AlarmCreate should be an error, so + ! in this case, this test returns SUCCESS + rc = ESMF_SUCCESS + else + ! On the other hand, if ESMF_AlarmCreate succeeded, then this test has failed + rc = ESMF_FAILURE + end if + !call ESMF_AlarmDebug(alarm,'test3',rc=status) + end subroutine +!------------------------------------------------------------------------ + subroutine ForwardAlarm_Test4(rc) + ! Test 4: c.t0 = a.t0, c.dt = 10 min, a.dt = 12 min + + integer, intent(out) :: rc + + type (ESMF_Clock) :: clock + type (ESMF_Alarm) :: alarm, alarm_sticky + type (ESMF_Time) :: startTime, stopTime, ringTime + type (ESMF_TimeInterval) :: timeStep, ringTimeInterval + + integer :: status, n + logical :: ringing, enabled + logical :: allCorrect + + rc = ESMF_FAILURE + allCorrect = .true. + + call ESMF_TimeSet(startTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(stopTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(ringTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_TimeIntervalSet(timeStep,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeIntervalSet(ringTimeInterval,S=720, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + clock = ESMF_ClockCreate(timeStep=timeStep,startTime=startTime,stopTime=stopTime,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + alarm = ESMF_AlarmCreate(clock, ringTime=ringTime, ringInterval=ringTimeInterval, enabled=.true., sticky=.false., name='alarm', rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + ! call ESMF_AlarmDebug(alarm,'test4',rc=status) + ! if(status /= ESMF_SUCCESS) call ESMF_Finalize() + alarm_sticky = ESMF_AlarmCreate(clock, ringTime=ringTime, ringInterval=ringTimeInterval, enabled=.true., sticky=.true., name='alarm_sticky', rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + ! call ESMF_AlarmDebug(alarm_sticky,'test4',rc=status) + ! if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (.not. ringing) then + allCorrect = .false. + end if + call ESMF_AlarmGet(alarm_sticky, ringing=ringing, enabled=enabled, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (.not. ringing) then + allCorrect = .false. + end if + + call ESMF_AlarmRingerOff(alarm_sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + do n = 1, 8 + call ESMF_ClockAdvance(clock,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (n == 6) then + ! Alarm should be ringing on the 6th time step, when alarm dt aligns with clock dt + if (.not. ringing) then + allCorrect = .false. + end if + else + ! Alarm should NOT be ringing on other time steps + if (ringing) then + allCorrect = .false. + end if + end if + + call ESMF_AlarmGet(alarm_sticky, ringing=ringing, enabled=enabled, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (n == 6) then + ! Alarm should be ringing on the 6th time step, when alarm dt aligns with clock dt + if (.not. ringing) then + allCorrect = .false. + end if + else + ! Alarm should NOT be ringing on other time steps + if (ringing) then + allCorrect = .false. + end if + end if + call ESMF_AlarmRingerOff(alarm_sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + enddo + + if (allCorrect) then + rc = ESMF_SUCCESS + end if + end subroutine +!------------------------------------------------------------------------ + subroutine ForwardAlarm_Test5(rc) + ! Test 5: c.t0 = 00:00:00, a.t0=00:04:00, c.dt = a.dt = 10 min, sticky (an alarm won't ring) + ! + ! This should raise an error: it's an error to create an alarm where the alarm interval + ! is the same as clock interval but ringTime is misaligned with clock time: in this + ! case, the alarm will never ring. + + integer, intent(out) :: rc + + type (ESMF_Clock) :: clock + type (ESMF_Alarm) :: alarm + type (ESMF_Time) :: startTime, stopTime, ringTime + type (ESMF_TimeInterval) :: timeStep, ringTimeInterval + + integer :: status, n + logical :: ringing, enabled, sticky + + rc = ESMF_FAILURE + + call ESMF_TimeSet(startTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(stopTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(ringTime,yy=1,mm=1,dd=1,h=0,m=4,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_TimeIntervalSet(timeStep,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeIntervalSet(ringTimeInterval,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + clock = ESMF_ClockCreate(timeStep=timeStep,startTime=startTime,stopTime=stopTime,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + alarm = ESMF_AlarmCreate(clock, ringTime=ringTime, ringInterval=ringTimeInterval, enabled=.true., sticky=.true., name='alarm', rc=status) + if(status /= ESMF_SUCCESS) then + ! This is the expected result: the status of ESMF_AlarmCreate should be an error, so + ! in this case, this test returns SUCCESS + rc = ESMF_SUCCESS + else + ! On the other hand, if ESMF_AlarmCreate succeeded, then this test has failed + rc = ESMF_FAILURE + end if + + ! call ESMF_AlarmDebug(alarm,'test5',rc=status) + ! if(status /= ESMF_SUCCESS) call ESMF_Finalize() + end subroutine +!------------------------------------------------------------------------ + subroutine ForwardAlarm_Test6(rc) + ! Test 6: c.t0 = 00:00:00, a.t0 = 00:30:00, c.dt = 10 min, a.dt = unspecified (one shot) + + integer, intent(out) :: rc + + type (ESMF_Clock) :: clock + type (ESMF_Alarm) :: alarm + type (ESMF_Time) :: startTime, stopTime, ringTime + type (ESMF_TimeInterval) :: timeStep + + integer :: status, n + logical :: ringing, enabled, sticky + logical :: allCorrect + + rc = ESMF_FAILURE + allCorrect = .true. + + call ESMF_TimeSet(startTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(stopTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(ringTime,yy=1,mm=1,dd=1,h=0,m=30,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_TimeIntervalSet(timeStep,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + clock = ESMF_ClockCreate(timeStep=timeStep,startTime=startTime,stopTime=stopTime,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + alarm = ESMF_AlarmCreate(clock, ringTime=ringTime, enabled=.true., sticky=.false., name='alarm', rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + ! call ESMF_AlarmDebug(alarm,'test6',rc=status) + ! if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (ringing) then + allCorrect = .false. + end if + do n = 1, 6 + call ESMF_ClockAdvance(clock,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (n == 3) then + ! Alarm should be ringing on the 3rd time step, when the clock time should match + ! the alarm's initial time + if (.not. ringing) then + allCorrect = .false. + end if + else + ! Alarm should NOT be ringing on other time steps + if (ringing) then + allCorrect = .false. + end if + end if + enddo + + if (allCorrect) then + rc = ESMF_SUCCESS + end if + + end subroutine +!------------------------------------------------------------------------ + subroutine ForwardAlarm_Test7(rc) + ! Test 7: c.t0, a.t0 unspecified default to c.t0, c.dt = 10 min, a.dt = 10 min + + integer, intent(out) :: rc + + type (ESMF_Clock) :: clock + type (ESMF_Alarm) :: alarm + type (ESMF_Time) :: startTime, stopTime + type (ESMF_TimeInterval) :: timeStep, ringTimeInterval + + integer :: status, n + logical :: ringing, enabled, sticky + logical :: allCorrect + + rc = ESMF_FAILURE + allCorrect = .true. + + call ESMF_TimeSet(startTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(stopTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_TimeIntervalSet(timeStep,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeIntervalSet(ringTimeInterval,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + clock = ESMF_ClockCreate(timeStep=timeStep,startTime=startTime,stopTime=stopTime,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + alarm = ESMF_AlarmCreate(clock, ringInterval=ringTimeInterval, enabled=.true., sticky=.false., name='alarm', rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + ! call ESMF_AlarmDebug(alarm,'test7',rc=status) + ! if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (.not. ringing) then + allCorrect = .false. + end if + do n = 1, 6 + call ESMF_ClockAdvance(clock,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (.not. ringing) then + allCorrect = .false. + end if + enddo + + if (allCorrect) then + rc = ESMF_SUCCESS + end if + end subroutine + + +!------------------------------------------------------------------------ +! Reverse Tests +!------------------------------------------------------------------------ + subroutine ReverseAlarm_Test1(rc) + ! Test 1: c.t0 = a.t0, c.dt = a.dt = 10 min, time reversed + + integer, intent(out) :: rc + + type (ESMF_Clock) :: clock + type (ESMF_Alarm) :: alarm + type (ESMF_Time) :: startTime, stopTime, ringTime, currTime + type (ESMF_TimeInterval) :: timeStep, ringTimeInterval + + integer :: status, n + logical :: ringing, enabled, sticky + logical :: allCorrect + + rc = ESMF_FAILURE + allCorrect = .true. + + call ESMF_TimeSet(startTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(stopTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(ringTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_TimeIntervalSet(timeStep,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeIntervalSet(ringTimeInterval,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + clock = ESMF_ClockCreate(timeStep=timeStep,startTime=startTime,stopTime=stopTime,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_ClockSet(clock, currTime = stopTime, direction=ESMF_DIRECTION_REVERSE, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + alarm = ESMF_AlarmCreate(clock, ringTime=ringTime, ringInterval=ringTimeInterval, enabled=.true., sticky=.false., name='alarm', rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + !call ESMF_AlarmDebug(alarm,'test1',rc=status) + !if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (.not. ringing) then + allCorrect = .false. + end if + do n = 1, 6 + call ESMF_ClockAdvance(clock,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (.not. ringing) then + allCorrect = .false. + end if + enddo + + if (allCorrect) then + rc = ESMF_SUCCESS + end if + end subroutine +!------------------------------------------------------------------------ + subroutine ReverseAlarm_Test2(rc) + ! Test 2: c.t0 = a.t0, c.dt = 10 min, a.dt = 20 min, time reversed + + integer, intent(out) :: rc + + type (ESMF_Clock) :: clock + type (ESMF_Alarm) :: alarm + type (ESMF_Time) :: startTime, stopTime, ringTime + type (ESMF_TimeInterval) :: timeStep, ringTimeInterval + + integer :: status, n + logical :: ringing, enabled, sticky + logical :: allCorrect + + rc = ESMF_FAILURE + allCorrect = .true. + + call ESMF_TimeSet(startTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(stopTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(ringTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_TimeIntervalSet(timeStep,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeIntervalSet(ringTimeInterval,S=1200, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + clock = ESMF_ClockCreate(timeStep=timeStep,startTime=startTime,stopTime=stopTime,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_ClockSet(clock, currTime = stopTime, direction=ESMF_DIRECTION_REVERSE, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + alarm = ESMF_AlarmCreate(clock, ringTime=ringTime, ringInterval=ringTimeInterval, enabled=.true., sticky=.false., name='alarm', rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + !call ESMF_AlarmDebug(alarm,'test2',rc=status) + !if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (.not. ringing) then + allCorrect = .false. + end if + do n = 1, 6 + call ESMF_ClockAdvance(clock,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (modulo(n,2) == 0) then + ! Alarm should be ringing on even time steps + if (.not. ringing) then + allCorrect = .false. + end if + else + ! Alarm should NOT be ringing on odd time steps + if (ringing) then + allCorrect = .false. + end if + end if + enddo + + if (allCorrect) then + rc = ESMF_SUCCESS + end if + end subroutine +!------------------------------------------------------------------------ + subroutine ReverseAlarm_Test3(rc) + ! Test 3: c.t0 = a.t0, c.dt = 20 min, a.dt = 10 min, time reversed + ! + ! This should raise an error: it's an error to create an alarm with alarm timeInterval + ! less than clock timeStep + + integer, intent(out) :: rc + + type (ESMF_Clock) :: clock + type (ESMF_Alarm) :: alarm + type (ESMF_Time) :: startTime, stopTime, ringTime + type (ESMF_TimeInterval) :: timeStep, ringTimeInterval + + integer :: status, n + logical :: ringing, enabled, sticky + + rc = ESMF_FAILURE + + call ESMF_TimeSet(startTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(stopTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(ringTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_TimeIntervalSet(timeStep,S=1200, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeIntervalSet(ringTimeInterval,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + clock = ESMF_ClockCreate(timeStep=timeStep,startTime=startTime,stopTime=stopTime,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_ClockSet(clock, currTime = stopTime, direction=ESMF_DIRECTION_REVERSE, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + ! It's an error to create an alarm with alarm timeInterval less than clock timeStep + alarm = ESMF_AlarmCreate(clock, ringTime=ringTime, ringInterval=ringTimeInterval, enabled=.true., sticky=.false., name='alarm', rc=status) + if(status /= ESMF_SUCCESS) then + ! This is the expected result: the status of ESMF_AlarmCreate should be an error, so + ! in this case, this test returns SUCCESS + rc = ESMF_SUCCESS + else + ! On the other hand, if ESMF_AlarmCreate succeeded, then this test has failed + rc = ESMF_FAILURE + end if + !call ESMF_AlarmDebug(alarm,'test3',rc=status) + end subroutine +!------------------------------------------------------------------------ + subroutine ReverseAlarm_Test4(rc) + ! Test 4: c.t0 = a.t0, c.dt = 10 min, a.dt = 12 min, time reversed + + integer, intent(out) :: rc + + type (ESMF_Clock) :: clock + type (ESMF_Alarm) :: alarm + type (ESMF_Time) :: startTime, stopTime, ringTime + type (ESMF_TimeInterval) :: timeStep, ringTimeInterval + + integer :: status, n + logical :: ringing, enabled, sticky + logical :: allCorrect + + rc = ESMF_FAILURE + allCorrect = .true. + + call ESMF_TimeSet(startTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(stopTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(ringTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_TimeIntervalSet(timeStep,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeIntervalSet(ringTimeInterval,S=720, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + clock = ESMF_ClockCreate(timeStep=timeStep,startTime=startTime,stopTime=stopTime,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_ClockSet(clock, currTime = stopTime, direction=ESMF_DIRECTION_REVERSE, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + alarm = ESMF_AlarmCreate(clock, ringTime=ringTime, ringInterval=ringTimeInterval, enabled=.true., sticky=.false., name='alarm', rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + ! call ESMF_AlarmDebug(alarm,'test4',rc=status) + ! if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (.not. ringing) then + allCorrect = .false. + end if + do n = 1, 8 + call ESMF_ClockAdvance(clock,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (n == 6) then + ! Alarm should be ringing on the 6th time step, when alarm dt aligns with clock dt + if (.not. ringing) then + allCorrect = .false. + end if + else + ! Alarm should NOT be ringing on other time steps + if (ringing) then + allCorrect = .false. + end if + end if + enddo + + if (allCorrect) then + rc = ESMF_SUCCESS + end if + end subroutine +!------------------------------------------------------------------------ + subroutine ReverseAlarm_Test5(rc) + ! Test 5: c.t0 = 00:00:00, a.t0=00:04:00, c.dt = a.dt = 10 min, sticky, time reversed (an alarm won't ring) + ! + ! This should raise an error: it's an error to create an alarm where the alarm interval + ! is the same as clock interval but ringTime is misaligned with clock time: in this + ! case, the alarm will never ring. + + integer, intent(out) :: rc + + type (ESMF_Clock) :: clock + type (ESMF_Alarm) :: alarm + type (ESMF_Time) :: startTime, stopTime, ringTime + type (ESMF_TimeInterval) :: timeStep, ringTimeInterval + + integer :: status, n + logical :: ringing, enabled, sticky + + rc = ESMF_FAILURE + + call ESMF_TimeSet(startTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(stopTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(ringTime,yy=1,mm=1,dd=1,h=0,m=4,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_TimeIntervalSet(timeStep,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeIntervalSet(ringTimeInterval,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + clock = ESMF_ClockCreate(timeStep=timeStep,startTime=startTime,stopTime=stopTime,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_ClockSet(clock, currTime = stopTime, direction=ESMF_DIRECTION_REVERSE, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + alarm = ESMF_AlarmCreate(clock, ringTime=ringTime, ringInterval=ringTimeInterval, enabled=.true., sticky=.true., name='alarm', rc=status) + if(status /= ESMF_SUCCESS) then + ! This is the expected result: the status of ESMF_AlarmCreate should be an error, so + ! in this case, this test returns SUCCESS + rc = ESMF_SUCCESS + else + ! On the other hand, if ESMF_AlarmCreate succeeded, then this test has failed + rc = ESMF_FAILURE + end if + + ! call ESMF_AlarmDebug(alarm,'test5',rc=status) + ! if(status /= ESMF_SUCCESS) call ESMF_Finalize() + end subroutine +!------------------------------------------------------------------------ + subroutine ReverseAlarm_Test6(rc) + ! Test 6: c.t0 = 00:00:00, a.t0 = 00:30:00, c.dt = 10 min, a.dt = unspecified (one shot), time reversed + + integer, intent(out) :: rc + + type (ESMF_Clock) :: clock + type (ESMF_Alarm) :: alarm + type (ESMF_Time) :: startTime, stopTime, ringTime + type (ESMF_TimeInterval) :: timeStep + + integer :: status, n + logical :: ringing, enabled, sticky + logical :: allCorrect + + rc = ESMF_FAILURE + allCorrect = .true. + + call ESMF_TimeSet(startTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(stopTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(ringTime,yy=1,mm=1,dd=1,h=0,m=30,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_TimeIntervalSet(timeStep,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + clock = ESMF_ClockCreate(timeStep=timeStep,startTime=startTime,stopTime=stopTime,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_ClockSet(clock, currTime = stopTime, direction=ESMF_DIRECTION_REVERSE, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + alarm = ESMF_AlarmCreate(clock, ringTime=ringTime, enabled=.true., sticky=.false., name='alarm', rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + ! call ESMF_AlarmDebug(alarm,'test6',rc=status) + ! if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (ringing) then + allCorrect = .false. + end if + do n = 1, 6 + call ESMF_ClockAdvance(clock,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (n == 3) then + ! Alarm should be ringing on the 3rd time step, when the clock time should match + ! the alarm's initial time + if (.not. ringing) then + allCorrect = .false. + end if + else + ! Alarm should NOT be ringing on other time steps + if (ringing) then + allCorrect = .false. + end if + end if + enddo + + if (allCorrect) then + rc = ESMF_SUCCESS + end if + end subroutine + +!------------------------------------------------------------------------ +! Forward and Reverse +!------------------------------------------------------------------------ + subroutine ForwardReverseAlarm_Test1(rc) + ! Test 1: c.t0 = a.t0, c.dt = a.dt = 10 min + + integer, intent(out) :: rc + + type (ESMF_Clock) :: clock + type (ESMF_Alarm) :: alarm + type (ESMF_Time) :: startTime, stopTime, ringTime + type (ESMF_TimeInterval) :: timeStep, ringTimeInterval + + integer :: status, n + logical :: ringing, enabled, sticky + logical :: allCorrect + + rc = ESMF_FAILURE + allCorrect = .true. + + call ESMF_TimeSet(startTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(stopTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(ringTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_TimeIntervalSet(timeStep,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeIntervalSet(ringTimeInterval,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + clock = ESMF_ClockCreate(timeStep=timeStep,startTime=startTime,stopTime=stopTime,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + alarm = ESMF_AlarmCreate(clock, ringTime=ringTime, ringInterval=ringTimeInterval, enabled=.true., sticky=.false., name='alarm', rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + ! call ESMF_AlarmDebug(alarm,'test1',rc=status) + ! if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (.not. ringing) then + allCorrect = .false. + end if + do n = 1, 6 + call ESMF_ClockAdvance(clock,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (.not. ringing) then + allCorrect = .false. + end if + enddo + call ESMF_ClockSet(clock, direction = ESMF_DIRECTION_REVERSE, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + do n = 1, 6 + call ESMF_ClockAdvance(clock,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (.not. ringing) then + allCorrect = .false. + end if + enddo + if (allCorrect) then + rc = ESMF_SUCCESS + end if + end subroutine + + subroutine ForwardReverseAlarm_Test2(rc) + ! Test 2: c.t0 = a.t0, c.dt = 10 min, a.dt = 20 min + + integer, intent(out) :: rc + + type (ESMF_Clock) :: clock + type (ESMF_Alarm) :: alarm + type (ESMF_Time) :: startTime, stopTime, ringTime + type (ESMF_TimeInterval) :: timeStep, ringTimeInterval + + integer :: status, n + logical :: ringing, enabled, sticky + logical :: allCorrect + + rc = ESMF_FAILURE + allCorrect = .true. + + call ESMF_TimeSet(startTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(stopTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(ringTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_TimeIntervalSet(timeStep,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeIntervalSet(ringTimeInterval,S=1200, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + clock = ESMF_ClockCreate(timeStep=timeStep,startTime=startTime,stopTime=stopTime,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + alarm = ESMF_AlarmCreate(clock, ringTime=ringTime, ringInterval=ringTimeInterval, enabled=.true., sticky=.false., name='alarm', rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + ! call ESMF_AlarmDebug(alarm,'test1',rc=status) + ! if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (.not. ringing) then + allCorrect = .false. + end if + do n = 1, 6 + call ESMF_ClockAdvance(clock,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (modulo(n,2) == 0) then + ! Alarm should be ringing on even time steps + if (.not. ringing) then + allCorrect = .false. + end if + else + ! Alarm should NOT be ringing on odd time steps + if (ringing) then + allCorrect = .false. + end if + end if + enddo + call ESMF_ClockSet(clock, direction = ESMF_DIRECTION_REVERSE, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + do n = 1, 6 + call ESMF_ClockAdvance(clock,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (modulo(n,2) == 0) then + ! Alarm should be ringing on even time steps + if (.not. ringing) then + allCorrect = .false. + end if + else + ! Alarm should NOT be ringing on odd time steps + if (ringing) then + allCorrect = .false. + end if + end if + enddo + if (allCorrect) then + rc = ESMF_SUCCESS + end if + end subroutine + + subroutine ForwardReverseAlarm_Test3(rc) + ! Test 3: c.t0 = a.t0, c.dt = 10 min, a.dt = 12 min + + integer, intent(out) :: rc + + type (ESMF_Clock) :: clock + type (ESMF_Alarm) :: alarm + type (ESMF_Time) :: startTime, stopTime, ringTime + type (ESMF_TimeInterval) :: timeStep, ringTimeInterval + + integer :: status, n + logical :: ringing, enabled, sticky + logical :: allCorrect + + rc = ESMF_FAILURE + allCorrect = .true. + + call ESMF_TimeSet(startTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(stopTime,yy=1,mm=1,dd=1,h=1,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeSet(ringTime,yy=1,mm=1,dd=1,h=0,m=0,s=0,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_TimeIntervalSet(timeStep,S=600, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_TimeIntervalSet(ringTimeInterval,S=720, sN=0, sD=1,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + clock = ESMF_ClockCreate(timeStep=timeStep,startTime=startTime,stopTime=stopTime,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + alarm = ESMF_AlarmCreate(clock, ringTime=ringTime, ringInterval=ringTimeInterval, enabled=.true., sticky=.false., name='alarm', rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + ! call ESMF_AlarmDebug(alarm,'test1',rc=status) + ! if(status /= ESMF_SUCCESS) call ESMF_Finalize() + + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (.not. ringing) then + allCorrect = .false. + end if + do n = 1, 6 + call ESMF_ClockAdvance(clock,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (n == 6) then + ! Alarm should be ringing on the 6th time step, when alarm dt aligns with clock dt + if (.not. ringing) then + allCorrect = .false. + end if + else + ! Alarm should NOT be ringing on other time steps + if (ringing) then + allCorrect = .false. + end if + end if + enddo + call ESMF_ClockSet(clock, direction = ESMF_DIRECTION_REVERSE, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + do n = 1, 6 + call ESMF_ClockAdvance(clock,rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + call ESMF_AlarmGet(alarm, ringing=ringing, enabled=enabled, sticky=sticky, rc=status) + if(status /= ESMF_SUCCESS) call ESMF_Finalize() + if (n == 6) then + ! Alarm should be ringing on the 6th time step, when alarm dt aligns with clock dt + if (.not. ringing) then + allCorrect = .false. + end if + else + ! Alarm should NOT be ringing on other time steps + if (ringing) then + allCorrect = .false. + end if + end if + enddo + if (allCorrect) then + rc = ESMF_SUCCESS + end if + end subroutine end program ESMF_AlarmTest