diff --git a/src/libmtime_hl.f90 b/src/libmtime_hl.f90 index 9ab3668c471690a0bdc326dbdaa4dbb7d6580ba7..11cf3f4c43093fe561fbae584448a14505fea512 100644 --- a/src/libmtime_hl.f90 +++ b/src/libmtime_hl.f90 @@ -364,8 +364,9 @@ MODULE mtime_hl MODULE PROCEDURE t_eventGroup_constructor END INTERFACE - INTEGER :: number_of_t_eventGroups = 0 - + INTEGER :: event_group_id = 0 + INTEGER :: event_id = 0 + CONTAINS !___________________________________________________________________________ @@ -1144,8 +1145,8 @@ CONTAINS FUNCTION t_eventGroup_constructor(name) RESULT(this_event_group) TYPE(t_eventGroup) :: this_event_group CHARACTER(len=*), INTENT(in) :: name - number_of_t_eventGroups = number_of_t_eventGroups + 1 - this_event_group%event_group_id = number_of_t_eventGroups + event_group_id = event_group_id + 1 + this_event_group%event_group_id = event_group_id this_event_group%event_group_name = name this_event_group%first_event_in_group => NULL() this_event_group%last_event_in_group => NULL() diff --git a/src/trigger.f90 b/src/trigger.f90 index 89a5965cb2ab4e893489ef187a8f4406bc3d76a7..910fd0e313aa62e6dfa9fe9c516f2b01e4afd760 100644 --- a/src/trigger.f90 +++ b/src/trigger.f90 @@ -1,650 +1,4 @@ -! /** -! * @file mtime_eventHandling.c -! * -! * @brief Event-groups which contains a list of events. -! * -! * @author Luis Kornblueh, Rahul Sinha. MPIM. -! * @date March 2013 -! * -! * @note -! */ - -! #include <stdio.h> -! #include <stdlib.h> -! #include <stdint.h> -! #include <string.h> -! #include <sys/time.h> -! #include <unistd.h> - -! #include "mtime_eventHandling.h" - -! #include "mtime_datetime.h" -! #include "mtime_timedelta.h" -! #include "mtime_julianDay.h" -! #include "mtime_eventList.h" -! #include "mtime_iso8601.h" - -! /* Local static functions. */ -! static struct _datetime* -! getEventFirstTriggerDateTime(struct _datetime*, struct _timedelta*, struct _timedelta*, struct _datetime*, struct _datetime*); - -! // The IDs are unique only when they are live. Once a group/event has been deleted, the IDs will be reused. -! // Currently, the IDs are generated but not used. -! static int64_t EVENTGROUPID = 0; -! static int64_t EVENTID = 0; - - -! /** -! * @brief Construct new event-Group using a string. -! * -! * @param egn -! * A pointer to char. This string contains the name of event group. -! * -! * @return eg -! * A pointer to a initialized event-Group. -! * -! */ - -! struct _eventGroup* -! newEventGroup(const char* egn) -! { -! if ((egn != NULL) && (getCalendarType())) -! { -! struct _eventGroup* eg = (struct _eventGroup*)calloc(1,sizeof(struct _eventGroup)); -! if (eg == NULL) -! return NULL ; - -! /* Copy Group name. */ -! eg->eventGroupName = (char*)calloc(MAX_GROUPNAME_STR_LEN,sizeof(char)); -! if (eg->eventGroupName == NULL ) -! { -! free(eg); -! eg = NULL; -! return NULL ; -! } -! strncpy(eg->eventGroupName, egn, MAX_GROUPNAME_STR_LEN-1); -! eg->eventGroupName[MAX_GROUPNAME_STR_LEN - 1] = '\0'; - -! /* Generate eventGroupId. */ -! EVENTGROUPID = EVENTGROUPID + 1; -! eg->eventGroupId = EVENTGROUPID; - -! /* Initialize a NULL pointer. Stores a List of events associated with 'this' Event Group. */ -! eg->rootEvent = NULL; - -! return eg; -! } -! else -! return NULL; -! } - - -! /** -! * @brief Destructor of EventGroup. -! * -! * @param eg -! * A pointer to struct _eventGroup. eg is deallocated. -! */ - -! void -! deallocateEventGroup(struct _eventGroup* eg) -! { -! if (eg != NULL ) -! { -! EVENTGROUPID = EVENTGROUPID - 1; - -! if(eg->eventGroupName) -! { -! free(eg->eventGroupName); -! eg->eventGroupName = NULL; -! } - -! /* Deallocate all events in the list. */ -! deallocateEventsInGroup(eg); - -! free(eg); -! eg = NULL; -! } -! } - - -! /** -! * @brief Add new event to an eventgroup. -! * -! * @param e -! * A pointer to struct _event. The event to be added. -! * -! * @param eg -! * A pointer to struct _eventGroup. The eventGroup where the event is added. -! * -! * @return bool -! * true/false indicating success or failure of addition. -! */ - -! bool -! addNewEventToEventGroup(struct _event* e, struct _eventGroup* eg) -! { -! if ((e != NULL) && (eg != NULL)) -! return addNewEventToGroup(e,eg); -! else -! return false; -! } - - -! /** -! * @brief Remove event from eventgroup. CRITICAL: Also, deallocate the event. -! * -! * @param en -! * A pointer to char. The name of event to be removed. -! * -! * @param eg -! * A pointer to struct _eventGroup. The eventGroup to which this event belongs. -! * -! * @return bool -! * true/false indicating success or failure of removal. -! */ - -! bool -! removeEventFromEventGroup(char* en, struct _eventGroup* eg) -! { -! if ((en != NULL )&& (eg != NULL) ) -! return removeEventWithNameFromGroup(en,eg); -! else -! return false; -! } - -! int64_t -! getEventGroupId(struct _eventGroup* eg) -! { -! if (eg != NULL) -! return eg->eventGroupId; -! else -! return 0; -! } - -! char* -! getEventGroupName(struct _eventGroup* eg, char* gname) -! { -! if ((eg != NULL) && (gname != NULL)) -! { -! strncpy(gname, eg->eventGroupName, MAX_GROUPNAME_STR_LEN-1); -! gname[MAX_GROUPNAME_STR_LEN-1] = '\0'; -! return gname; -! } -! else -! return NULL; -! } - -! struct _event* -! getEventGroupRootEvent(struct _eventGroup* eg) -! { -! if (eg != NULL) -! return eg->rootEvent; -! else -! return NULL; -! } - - -! /** -! * @brief Construct new event using strings. -! * -! * To initialize an event, the event name and event interval must be specified. The reference date -! * (also known as the anchor-date), start date and event last date are optional. If first date is not -! * specified, first date is initialized as 0-01-01T00:00:00.000. If reference date is not specified, first date -! * is copied to reference date. If event last date is not defined, it is left as NULL and is logically equivalent -! * to Infinity. -! * -! * Notice that events trigger every _eventReferenceDT + Integral multiple of _eventInterval strictly in [_eventFirstDT,_eventLastDT]. -! * -! * @param _en -! * A pointer to char. This string contains the name of event. String name must be defined. -! * -! * @param _eventReferenceDT -! * A pointer to char. This string contains the Anchor date. Events are triggered at Anchor date + (N * eventInterval) where N is in Z. -! * This can be NULL in which case Anchor Date = First Date. -! * -! * @param _eventFirstDT -! * A pointer to char. This string contains the Starting datetime (A) of the DateTime range [A-B] in which trigger is allowed. -! * Can be NULL. -! * -! * @param _eventLastDT -! * A pointer to char. This string contains the Ending datetime (B) of the DateTime range [A-B] in which trigger is allowed. -! * Can be NULL. If defined, events will not trigger beyond this point. Else, equivalent to infinity. -! * -! * @param _eventOffset -! * A pointer to char. Adds a logical shift to _eventReferenceDT and the sifted value is used as the anchor date. -! * Can be NULL; Logically equivalent to 0 shift. -! * -! * @param _eventInterval -! * A pointer to char. This string contains the timestep. This must be defined for every event. -! * -! * @return e -! * A pointer to an initialized event. -! * -! */ - -! struct _event* -! newEvent(const char* _en, -! const char* _eventReferenceDT, -! const char* _eventFirstDT, -! const char* _eventLastDT, -! const char* _eventInterval, -! const char* _eventOffset) -! { -! if ((_en != NULL) && (_eventInterval != NULL) && getCalendarType()) -! { -! struct _event* e = (struct _event*)calloc(1,sizeof(struct _event)); -! if (e == NULL ) -! return NULL; - -! /* Initialize a null pointer. Connectes to the 'next' event in the list of Events in an Event Group. */ -! e->nextEventInGroup = NULL; - -! /* Copy event name. */ -! e->eventName = (char*)calloc(MAX_EVENTNAME_STR_LEN,sizeof(char)); -! if (e->eventName == NULL ) -! goto cleanup_and_exit; -! strncpy(e->eventName, _en, MAX_EVENTNAME_STR_LEN-1); -! e->eventName[MAX_EVENTNAME_STR_LEN - 1] = '\0'; - -! /* Generate eventId. */ -! EVENTID = EVENTID + 1; -! e->eventId = EVENTID; - -! /* Last evaluation date */ -! e->eventsLastEvaluationDateTime = NULL; - -! /* Start Date. */ -! if (_eventFirstDT) -! e->eventFirstDateTime = newDateTime(_eventFirstDT); -! else -! e->eventFirstDateTime = newDateTime(initDummyDTString); // Default start date = "0-01-01T00:00:00.000". - -! if (e->eventFirstDateTime == NULL ) -! goto cleanup_and_exit; - - -! /* Anchor date. */ -! if (_eventReferenceDT) -! e->eventReferenceDateTime = newDateTime(_eventReferenceDT); -! else -! e->eventReferenceDateTime = constructAndCopyDateTime(e->eventFirstDateTime); // If Anchor date is not defined, Anchor Date = First Date. - -! if (e->eventReferenceDateTime == NULL ) -! goto cleanup_and_exit; - - -! /* Last date. */ -! if (_eventLastDT) -! { -! e->eventLastDateTime = newDateTime(_eventLastDT); -! if (e->eventLastDateTime == NULL ) -! goto cleanup_and_exit; -! } -! else -! { -! e->eventLastDateTime = NULL; // Logically equivalent to Inf. -! } - -! /* _eventInterval must be defined. */ -! e->eventInterval = newTimeDelta(_eventInterval); -! if (e->eventInterval == NULL) -! goto cleanup_and_exit; - -! if (e->eventInterval->year == 0 && e->eventInterval->month == 0 && e->eventInterval->day == 0 -! && e->eventInterval->hour == 0 && e->eventInterval->minute == 0 && e->eventInterval->second == 0 && e->eventInterval->ms == 0) -! { -! e->neverTriggerEvent = true; - -! e->triggerCurrentEvent = false; - -! e->nextEventIsFirst = false; -! e->lastEventWasFinal = false; - -! e->eventisFirstInDay = false; -! e->eventisFirstInMonth = false; -! e->eventisFirstInYear = false; -! e->eventisLastInDay = false; -! e->eventisLastInMonth = false; -! e->eventisLastInYear = false; - -! /* Removed to prevent segfaults ... deallocateTimeDelta(e->eventInterval); */ - -! e->eventOffset = NULL; -! e->triggeredPreviousEventDateTime = NULL; -! e->triggerNextEventDateTime = NULL; - -! return e; -! } - -! if (_eventOffset) -! { -! e->eventOffset = newTimeDelta(_eventOffset); -! if (e->eventOffset == NULL) -! goto cleanup_and_exit; -! } -! else -! e->eventOffset = NULL; //Logically equivalent to 0. - -! /* Initialize with 'some' (arbitrary) value. */ -! e->triggeredPreviousEventDateTime = newDateTime(initDummyDTString); -! if (e->triggeredPreviousEventDateTime == NULL) -! goto cleanup_and_exit; - -! e->triggerNextEventDateTime = newDateTime(initDummyDTString); -! /* triggerNextEventDateTime holds the DateTime when an event should be triggered subjectively (i.e assuming real time starts at -Inf and moves fwd.) -! At init (right now), triggerNextEventDateTime stores the DateTime of First-Ever trigger. -! Events trigger at e->eventReferenceDateTime (+ e-> eventOffset ) + N * e->eventInterval where N is a positive, negative integer. -! Hence, first trigger happens at the nearest possible trigger >= e->eventFirstDateTime. */ -! if (!getEventFirstTriggerDateTime(e->eventFirstDateTime, e->eventInterval, e->eventOffset, e->eventReferenceDateTime, e->triggerNextEventDateTime)) -! goto cleanup_and_exit; - -! /* Init the Flags. */ -! e->neverTriggerEvent = false; - -! e->triggerCurrentEvent = false; - -! e->nextEventIsFirst = true; -! e->lastEventWasFinal = false; - -! e->eventisFirstInDay = false; -! e->eventisFirstInMonth = false; -! e->eventisFirstInYear = false; -! e->eventisLastInDay = false; -! e->eventisLastInMonth = false; -! e->eventisLastInYear = false; - -! return e; - -! cleanup_and_exit: -! if (e) -! { -! if (e->eventName) -! { -! free(e->eventName); -! e->eventName = NULL; -! } -! deallocateDateTime(e->eventReferenceDateTime); -! e->eventReferenceDateTime = NULL; -! deallocateDateTime(e->eventFirstDateTime); -! e->eventFirstDateTime = NULL; -! deallocateDateTime(e->eventLastDateTime); -! e->eventLastDateTime = NULL; -! deallocateTimeDelta(e->eventInterval); -! e->eventInterval = NULL; -! deallocateTimeDelta(e->eventOffset); -! e->eventOffset = NULL; -! deallocateDateTime(e->triggeredPreviousEventDateTime); -! e->triggeredPreviousEventDateTime = NULL; -! deallocateDateTime(e->triggerNextEventDateTime); -! e->triggerNextEventDateTime = NULL; -! free(e); -! e = NULL; -! } -! return NULL ; -! } -! else -! return NULL; -! } - - -! /** -! * @brief Construct new event using data-types. -! * -! * To initialize an event, the event name and event interval must be specified. The reference date -! * (also known as the anchor-date), start date and event last date are optional. If first date is not -! * specified, first date is initialized as 0-01-01T00:00:00.000. If reference date is not specified, first date -! * is copied to reference date. If event last date is not defined, it is left as NULL and is logically equivalent -! * to Infinity. -! * -! * Notice that events trigger every _eventReferenceDT + Integral multiple of _eventInterval strictly in [_eventFirstDT,_eventLastDT]. -! * -! * @param _en -! * A pointer to char. This string contains the name of event. -! * @param _eventReferenceDT -! * A pointer to struct _datetime. This pointer contains the First Reference date also called anchor date. -! * This can be NULL, but if defined acts as the true starting datetime overriding e->eventFirstDateTime. -! * @param _eventFirstDT -! * A pointer to struct _datetime. This pointer contains the Starting datetime. This must be defined for every Event. -! * @param _eventLastDT -! * A pointer to struct _datetime. This pointer contains the Ending datetime. -! * This can be NULL. If defined, events will not trigger beyond this point. -! * @param _eventInterval -! * A pointer to struct _timedelta. This pointer contains the timestep. This must be defined for every event. -! * @return e -! * A pointer to an initialized event. -! * -! */ - -! struct _event* -! newEventWithDataType(const char* _en, -! struct _datetime* _eventReferenceDT, -! struct _datetime* _eventFirstDT, -! struct _datetime* _eventLastDT, -! struct _timedelta* _eventInterval, -! struct _timedelta* _eventOffset) -! { -! if ((_en != NULL) && (_eventInterval != NULL) && getCalendarType()) -! { -! struct _event* e = (struct _event*)calloc(1,sizeof(struct _event)); -! if (e == NULL ) -! return NULL; - -! /* Initialize a null pointer. Connectes to the 'next' event in the list of Events in an Event Group. */ -! e->nextEventInGroup = NULL; - -! /* Copy event name. */ -! e->eventName = (char*)calloc(MAX_EVENTNAME_STR_LEN,sizeof(char)); -! if (e->eventName == NULL ) -! goto cleanup_and_exit; -! strncpy(e->eventName, _en, MAX_EVENTNAME_STR_LEN-1); -! e->eventName[MAX_EVENTNAME_STR_LEN - 1] = '\0'; - -! /* Generate eventId. */ -! EVENTID = EVENTID + 1; -! e->eventId = EVENTID; - -! /* Start Date. */ -! if (_eventFirstDT) -! e->eventFirstDateTime = constructAndCopyDateTime(_eventFirstDT); -! else -! e->eventFirstDateTime = newDateTime(initDummyDTString); // Default start date = "0-01-01T00:00:00.000". - -! if (e->eventFirstDateTime == NULL ) -! goto cleanup_and_exit; - - -! /* Anchor date. */ -! if (_eventReferenceDT) -! e->eventReferenceDateTime = constructAndCopyDateTime(_eventReferenceDT); -! else -! e->eventReferenceDateTime = constructAndCopyDateTime(e->eventFirstDateTime); // If Anchor date is not defined, Anchor Date = First Date. - -! if (e->eventReferenceDateTime == NULL ) -! goto cleanup_and_exit; - - -! /* Last date. */ -! if (_eventLastDT) -! e->eventLastDateTime = constructAndCopyDateTime(_eventLastDT); -! else -! e->eventLastDateTime = NULL; // Logically equivalent to Inf. - - -! if (_eventInterval->year == 0 && _eventInterval->month == 0 && _eventInterval->day == 0 -! && _eventInterval->hour == 0 && _eventInterval->minute == 0 && _eventInterval->second == 0 && _eventInterval->ms == 0) -! { -! e->neverTriggerEvent = true; - -! e->triggerCurrentEvent = false; - -! e->nextEventIsFirst = false; -! e->lastEventWasFinal = false; - -! e->eventisFirstInDay = false; -! e->eventisFirstInMonth = false; -! e->eventisFirstInYear = false; -! e->eventisLastInDay = false; -! e->eventisLastInMonth = false; -! e->eventisLastInYear = false; - -! /* Added to prevent segfaults ... */ -! e->eventInterval = constructAndCopyTimeDelta(_eventInterval); -! e->eventOffset = NULL; -! e->triggeredPreviousEventDateTime = NULL; -! e->triggerNextEventDateTime = NULL; - -! return e; -! } - -! /* _eventInterval must be defined. */ -! e->eventInterval = constructAndCopyTimeDelta(_eventInterval); -! if (e->eventInterval == NULL) -! goto cleanup_and_exit; - - -! /* Event trigger offset. */ -! if (_eventOffset) -! e->eventOffset = constructAndCopyTimeDelta(_eventOffset); -! else -! e->eventOffset = NULL; - -! /* Initialize with 'some'(arbitrary) value. */ -! e->triggeredPreviousEventDateTime = newDateTime(initDummyDTString); -! if (e->triggeredPreviousEventDateTime == NULL) -! goto cleanup_and_exit; - -! e->triggerNextEventDateTime = newDateTime(initDummyDTString); -! /* triggerNextEventDateTime holds the DateTime when an event should be triggered subjectively (i.e assuming real time starts at -Inf and moves fwd.) -! At init (right now), triggerNextEventDateTime stores the DateTime of First-Ever trigger. -! Events trigger at e->eventReferenceDateTime (+ e->eventOffset) + N*e->eventInterval where N is a positive, negative or zero integer. -! Hence, first trigger happens at the nearest possible trigger >= e->eventFirstDateTime. */ -! if (!getEventFirstTriggerDateTime(e->eventFirstDateTime, e->eventInterval, e->eventOffset, e->eventReferenceDateTime, e->triggerNextEventDateTime)) -! goto cleanup_and_exit; - -! /* Init the Flags. */ -! e->neverTriggerEvent = false; - -! e->triggerCurrentEvent = false; - -! e->nextEventIsFirst = true; -! e->lastEventWasFinal = false; - -! e->eventisFirstInDay = false; -! e->eventisFirstInMonth = false; -! e->eventisFirstInYear = false; -! e->eventisLastInDay = false; -! e->eventisLastInMonth = false; -! e->eventisLastInYear = false; - -! return e; - -! cleanup_and_exit: -! if (e) -! { -! if (e->eventName) -! { -! free(e->eventName); -! e->eventName = NULL; -! } -! deallocateDateTime(e->eventReferenceDateTime); -! e->eventReferenceDateTime = NULL; -! deallocateDateTime(e->eventFirstDateTime); -! e->eventFirstDateTime = NULL; -! deallocateDateTime(e->eventLastDateTime); -! e->eventLastDateTime = NULL; -! deallocateTimeDelta(e->eventInterval); -! e->eventInterval = NULL; -! deallocateTimeDelta(e->eventOffset); -! e->eventOffset = NULL; -! deallocateDateTime(e->triggeredPreviousEventDateTime); -! e->triggeredPreviousEventDateTime = NULL; -! deallocateDateTime(e->triggerNextEventDateTime); -! e->triggerNextEventDateTime = NULL; -! free(e); -! e = NULL; -! } -! return NULL ; -! } -! else -! return NULL; -! } - - -! /* INTERNAL FUNCTION. */ -! //Get if trigger is true. Trigger true in [T-minus_slack,T+plus_slack]. -! static -! compare_return_val -! isTriggerTimeInRange(struct _datetime* current_dt, struct _datetime* triggerNextEventDateTime, struct _timedelta* plus_slack, struct _timedelta* minus_slack) -! { -! int cmp_val_flag = -128; - -! /* Make a local copy of slack to avoid updating the user supplied timedeltas. */ -! struct _timedelta* plus_slack_local = NULL; -! struct _timedelta* minus_slack_local = NULL; - -! if (plus_slack) -! plus_slack_local = constructAndCopyTimeDelta(plus_slack); -! else -! plus_slack_local = newTimeDelta(initDummyTDString); //Translates to 0. - -! if (minus_slack) -! minus_slack_local = constructAndCopyTimeDelta(minus_slack); -! else -! minus_slack_local = newTimeDelta(initDummyTDString); //Translates to 0. - - - -! /* If plus_slack_local is defined, return the status of current_dt vis-a-vis trigger time +/- allowed delta. */ -! if((plus_slack_local->sign == '+') && ((minus_slack_local->sign == '+'))) -! { -! int upper_val_flag = -128; -! int lower_val_flag = -128; - -! struct _datetime *dt_upperbound = newDateTime(initDummyDTString); -! struct _datetime *dt_lowerbound = newDateTime(initDummyDTString); - -! minus_slack_local->sign = '-'; /* Change sign to obtain substraction. */ - - -! upper_val_flag = compareDatetime(current_dt,addTimeDeltaToDateTime(triggerNextEventDateTime,plus_slack_local,dt_upperbound)); -! lower_val_flag = compareDatetime(current_dt,addTimeDeltaToDateTime(triggerNextEventDateTime,minus_slack_local,dt_lowerbound)); - -! if ( -! (upper_val_flag == less_than || upper_val_flag == equal_to) -! && -! (lower_val_flag == greater_than || lower_val_flag == equal_to) -! ) -! { -! cmp_val_flag = equal_to; -! } -! else if (upper_val_flag == greater_than) -! { -! cmp_val_flag = greater_than; -! } -! else if (lower_val_flag == less_than) -! { -! cmp_val_flag = less_than; -! } - -! //Cleaup. -! deallocateDateTime(dt_upperbound); -! deallocateDateTime(dt_lowerbound); -! } -! else /* If slack is malformed (negative sign is not permitted), return as normal (follow exact match for equal). */ -! { -! cmp_val_flag = compareDatetime(current_dt,triggerNextEventDateTime); -! } - -! deallocateTimeDelta(plus_slack_local); -! deallocateTimeDelta(minus_slack_local); - -! return cmp_val_flag; -! } - - -!LK -function triggerEvent(this, current_dt, plus_slack, minus_slack) result(res) +FUNCTION triggerEvent(this, current_dt, plus_slack, minus_slack) RESULT(res) CLASS(t_event) :: this TYPE(t_datetime), INTENT(in) :: current_dt TYPE(t_timedelta), INTENT(in) :: plus_slack @@ -653,521 +7,368 @@ function triggerEvent(this, current_dt, plus_slack, minus_slack) result(res) TYPE(t_timedelta) :: modulo_td LOGICAL :: cmp_val_flag - IF (this%neverTriggerEvent) then - res = .false. - endif - - if (associated(event%eventsLastEvaluationDateTime)) then - if (this%eventsLastEvaluationDateTime == current_dt) - res = .true. - return - endif - - this%triggerCurrentEvent = .false. - - this%eventisFirstInDay = .false. - this%eventisFirstInMonth = .false. - this%eventisFirstInYear = .false. - this%eventisLastInDay = .false. - this%eventisLastInMonth = .false. - this%eventisLastInYear = .false. - - if (this%eventFirstDateTime == current_dt) then - res = .false. - return - endif + IF (this%neverTriggerEvent) THEN + res = .FALSE. + ENDIF + + IF (ASSOCIATED(event%eventsLastEvaluationDateTime)) THEN + IF (this%eventsLastEvaluationDateTime == current_dt) + res = .TRUE. + RETURN + ENDIF + + this%triggerCurrentEvent = .FALSE. + + this%eventisFirstInDay = .FALSE. + this%eventisFirstInMonth = .FALSE. + this%eventisFirstInYear = .FALSE. + this%eventisLastInDay = .FALSE. + this%eventisLastInMonth = .FALSE. + this%eventisLastInYear = .FALSE. + + IF (this%eventFirstDateTime == current_dt) THEN + res = .FALSE. + RETURN + ENDIF - if (this%eventLastDateTime .and. (compareDatetime(current_dt,this%eventLastDateTime) == greater_than)) then - if (.not. this%nextEventIsFirst) then + IF (this%eventLastDateTime .AND. (compareDatetime(current_dt,this%eventLastDateTime) == greater_than)) THEN + IF (.NOT. this%nextEventIsFirst) THEN this%lastEventWasFinal = true - res = .false. - return - endif + res = .FALSE. + RETURN + ENDIF - if (isTriggerTimeInRange(current_dt, this%triggerNextEventDateTime, plus_slack, NULL) == greater_than) then + IF (isTriggerTimeInRange(current_dt, this%triggerNextEventDateTime, plus_slack, NULL) == greater_than) THEN moduloTimeDeltaFromDateTime(this%triggerNextEventDateTime, this%eventInterval, current_dt, modulo_td) addTimeDeltaToDateTime(current_dt,modulo_td,this%triggerNextEventDateTime) - endif + ENDIF - if ( .not. this%lastEventWasFinal & - & .and. & - & (isTriggerTimeInRange(current_dt, this%triggerNextEventDateTime, plus_slack, minus_slack) == equal_to) ) then + IF ( .NOT. this%lastEventWasFinal & + & .AND. & + & (isTriggerTimeInRange(current_dt, this%triggerNextEventDateTime, plus_slack, minus_slack) == equal_to) ) THEN - if (this%nextEventIsFirst .or. iseventNextInNextDay(event)) this%eventisFirstInDay = .true. - if (this%nextEventIsFirst .or. iseventNextInNextMonth(event)) this%eventisFirstInMonth = .true. - if (this%nextEventIsFirst .or. iseventNextInNextYear(event)) this%eventisFirstInYear = .true. + IF (this%nextEventIsFirst .OR. iseventNextInNextDay(event)) this%eventisFirstInDay = .TRUE. + IF (this%nextEventIsFirst .OR. iseventNextInNextMonth(event)) this%eventisFirstInMonth = .TRUE. + IF (this%nextEventIsFirst .OR. iseventNextInNextYear(event)) this%eventisFirstInYear = .TRUE. this%triggeredPreviousEventDateTime = curent_dt cmp_val_flag = isTriggerTimeInRange(addTimeDeltaToDateTime(current_dt, this%eventInterval,tmp_dt), & this%eventLastDateTime, NULL, minus_slack - if (.not.(this%eventLastDateTime .and. (cmp_val_flag == greater_than)) then + IF (.NOT.(this%eventLastDateTime .AND. (cmp_val_flag == greater_than)) THEN addTimeDeltaToDateTime(this%triggerNextEventDateTime,this%eventInterval,this%triggerNextEventDateTime) - else + ELSE this%lastEventWasFinal = true - endif + ENDIF this%triggerCurrentEvent = true - if ((this%eventLastDateTime .and. (cmp_val_flag == greater_than)) .or. iseventNextInNextDay(event)) this%eventisLastInDay = .true. - if ((this%eventLastDateTime .and. (cmp_val_flag == greater_than)) .or. iseventNextInNextMonth(event)) this%eventisLastInMonth = .true. - if ((this%eventLastDateTime .and. (cmp_val_flag == greater_than)) .or. iseventNextInNextYear(event)) this%eventisLastInYear = .true. + IF ((this%eventLastDateTime .AND. (cmp_val_flag == greater_than)) .OR. iseventNextInNextDay(event)) this%eventisLastInDay = .TRUE. + IF ((this%eventLastDateTime .AND. (cmp_val_flag == greater_than)) .OR. iseventNextInNextMonth(event)) this%eventisLastInMonth = .TRUE. + IF ((this%eventLastDateTime .AND. (cmp_val_flag == greater_than)) .OR. iseventNextInNextYear(event)) this%eventisLastInYear = .TRUE. this%nextEventIsFirst = false this%eventsLastEvaluationDateTime = current_dt - res = .true. - return - endif - - res = .false. - return - endif - else - res = .false. - return - endif - -end function triggerEvent - -function iseventNextInNextDay(this) result(res) - logical :: res - class(t_event) :: this - type(t_date) :: d_next - type(t_date) :: d_prev + res = .TRUE. + RETURN + ENDIF + + res = .FALSE. + RETURN + ENDIF + ELSE + res = .FALSE. + RETURN + ENDIF + +END FUNCTION triggerEvent + +FUNCTION iseventNextInNextDay(this) RESULT(res) + LOGICAL :: res + CLASS(t_event) :: this + TYPE(t_date) :: d_next + TYPE(t_date) :: d_prev d_next = t_date(this%triggerNextEventDateTime) d_prev = t_date(this%triggeredPreviousEventDateTime) - res = .false. - if (d_next > d_prev) res = .true. -end function iseventNextInNextDay -function iseventNextInNextMonth(this) result(res) - logical :: res - class(t_event) :: this - type(t_date) :: d_next - type(t_date) :: d_prev + res = .FALSE. + IF (d_next > d_prev) res = .TRUE. +END FUNCTION iseventNextInNextDay +FUNCTION iseventNextInNextMonth(this) RESULT(res) + LOGICAL :: res + CLASS(t_event) :: this + TYPE(t_date) :: d_next + TYPE(t_date) :: d_prev d_next = t_date(this%triggerNextEventDateTime) d_prev = t_date(this%triggeredPreviousEventDateTime) d_next%day = 1 d_prev%day = 1 - res = .false. - if (d_next > d_prev) res = .true. -end function iseventNextInNextMonth -function iseventNextInNextYear(this) result(res) - logical :: res - class(t_event) :: this - type(t_date) :: d_next - type(t_date) :: d_prev + res = .FALSE. + IF (d_next > d_prev) res = .TRUE. +END FUNCTION iseventNextInNextMonth +FUNCTION iseventNextInNextYear(this) RESULT(res) + LOGICAL :: res + CLASS(t_event) :: this + TYPE(t_date) :: d_next + TYPE(t_date) :: d_prev d_next = t_date(this%triggerNextEventDateTime) d_prev = t_date(this%triggeredPreviousEventDateTime) d_next%day = 1 d_next%month = 1 d_prev%day = 1 d_prev%month = 1 - res = .false. - if (d_next > d_prev) res = .true. -end function iseventNextInNextYear - -! /** -! * @brief Get Event as a string. -! * -! * @param e -! * A pointer to struct _event. The event to be converted to string. -! * -! * @param string -! * A pointer to char. String where event is to be written. -! * -! * @return string -! * A pointer to the string containing event description. -! */ -! //TODO on Luis. Exact format. -! char* -! eventToString(struct _event* e, char* string) -! { -! if ((e != NULL) && (string != NULL)) -! { -! memset(string,'\0',MAX_EVENT_STR_LEN); -! if (e->eventName != NULL) -! { -! sprintf(string, "%s", e->eventName); -! return string; -! } -! else -! { -! //TODO. -! ; -! } -! return NULL; -! } -! else -! return NULL; -! } - + res = .FALSE. + IF (d_next > d_prev) res = .TRUE. +END FUNCTION iseventNextInNextYear + +FUNCTION getEventFirstTriggerDateTime(start_dt, timestep, offset, ref_dt) RESULT(first_trigger_dt) + TYPE(t_datetime) :: first_trigger_dt + TYPE(t_datetime), INTENT(in) :: start_dt + TYPE(t_timedelta), INTENT(in) :: timestep + TYPE(t_timedelta), INTENT(in) :: offset + TYPE(t_datetime), INTENT(in) :: ref_dt + + TYPE(t_datetime) :: anchor + TYPE(t_timedelta) :: timestep_bkw + TYPE(t_julianday) :: start_jd + TYPE(t_juliandelta) :: timestep_jd + TYPE(t_juliandelta) :: timestep_fastfwd_jd + TYPE(t_juliandelta) :: timestep_fastbkw_jd + + INTEGER(c_int64_t) :: differenceOfYears, yearToAdd + INTEGER :: differenceOfMonth, monthsToAdd + INTEGER(c_int64_t) :: areDatesToFar + INTEGER :: lambda + + IF ( & + & timestep%year /= 0 .AND. timestep%month == 0 .AND. timestep%day == 0 & + & .AND. timestep%hour == 0 .AND. timestep%minute == 0 .AND. timestep%second == 0 .AND. timestep%ms == 0) THEN -! /* Calculate the first trigger time. First trigger is the nearest allowed trigger time >= start_dt. -! Triggers are allowd only ref_dt + N * timestep where N can be positive, negative or 0. */ -! static -! struct _datetime* -! getEventFirstTriggerDateTime(struct _datetime* start_dt, struct _timedelta* timestep, struct _timedelta* offset, struct _datetime* ref_dt, struct _datetime* first_trigger_dt) -! { -! if ((start_dt != NULL) && (timestep != NULL) && (ref_dt != NULL) && (first_trigger_dt != NULL) ) //offset can be NULL. -! { + anchor = ref_dt + offset -! if (timestep->year != 0 && timestep->month == 0 && timestep->day == 0 -! && timestep->hour == 0 && timestep->minute == 0 && timestep->second == 0 && timestep->ms == 0) -! { -! /* NOTE: years only is a trivial case. */ - -! /* Get anchor. ref + offset is the real anchor. */ -! struct _datetime *anchor = constructAndCopyDateTime(ref_dt); -! addTimeDeltaToDateTime(ref_dt, offset, anchor); // Note: If offset is null, no addition takes place. - -! if (compareDatetime(anchor, start_dt) == greater_than) -! { -! replaceDatetime(anchor, first_trigger_dt); -! } -! else -! { -! /* Determine difference between anchor and start year */ -! int64_t differenceOfYears = start_dt->date.year - anchor->date.year; // result always >= 0. -! int64_t yearsToAdd = differenceOfYears % timestep->year; - -! /* We only need to update the year */ -! replaceDatetime(anchor, first_trigger_dt); -! first_trigger_dt->date.year += yearsToAdd; -! } - -! /* Cleanup. */ -! deallocateDateTime(anchor); + IF (anchor > start_dt) THEN + + first_trigger_dt = anchor + + ELSE + + differenceOfYears = start_dt%date%year - anchor%date%year + yearsToAdd = MOD(differenceOfYears % timestep%year) + + + first_trigger_dt = anchor + first_trigger_dt%year = first_trigger_dt%year + yearsToAdd -! /* And return. */ -! return first_trigger_dt; -! } + ENDIF -! else if (timestep->year == 0 && timestep->month != 0 && timestep->day == 0 -! && timestep->hour == 0 && timestep->minute == 0 && timestep->second == 0 && timestep->ms == 0) -! { -! /* NOTE: months only is again a trivial case. */ + RETURN -! /* Get anchor. ref + offset is the real anchor. */ -! struct _datetime *anchor = constructAndCopyDateTime(ref_dt); -! addTimeDeltaToDateTime(ref_dt, offset, anchor); // Note: If offset is null, no addition takes place. + ELSE IF ( & + & timestep%year == 0 .AND. timestep%month /= 0 .AND. timestep%day == 0 & + & .AND. timestep%hour == 0 .AND. timestep%minute == 0 .AND. timestep%second == 0 .AND. timestep%ms == 0) THEN + + anchor = ref_dt + offset -! if (compareDatetime(anchor, start_dt) == greater_than) -! { -! replaceDatetime(anchor, first_trigger_dt); -! } -! else -! { -! /* Determine difference between anchor and start in months */ -! int differenceOfMonths = 12*(start_dt->date.year - anchor->date.year) + start_dt->date.month - anchor->date.month; + IF (anchor > start_dt) THEN + + first_trigger_dt = anchor + + ELSE -! int yearsToAdd = differenceOfMonths / 12; -! int monthsToAdd = differenceOfMonths % timestep->month; + differenceOfMonths = 12*(start_dt%date%year - anchor%date%year) + start_dt%date%month - anchor%date%month + + yearsToAdd = differenceOfMonths / 12 + monthsToAdd = MOD(differenceOfMonths, timestep%month) -! /* We only need to update the year and month */ -! replaceDatetime(anchor, first_trigger_dt); -! first_trigger_dt->date.year += yearsToAdd; -! first_trigger_dt->date.month += monthsToAdd; -! } - -! /* Cleanup. */ -! deallocateDateTime(anchor); + first_trigger_dt = anchor + first_trigger_dt%date%year = first_trigger_dt%date%year + yearsToAdd + first_trigger_dt%date%month = first_trigger_dt%date%month + monthsToAdd -! /* And return. */ -! return first_trigger_dt; -! } - -! else if (timestep->year == 0 && timestep->month == 0) - -! { -! /* NOTE: This code is higly 'rigged', to a point where it might feel micromanaged. -! This is to speed-up the event-init process. Without the hack, the code -! will be too slow and hence the ends justify the means. -! */ + ENDIF -! struct _timedelta* timestep_bkw; - -! /* Get start date in julian. */ -! struct _julianday* start_jd = newJulianDay(0, 0); -! start_jd = date2julian(start_dt, start_jd); - - -! /* Get timedelta in juliandelta. */ -! struct _juliandelta* timestep_jd = newJulianDelta('+', 0, 0); -! timestep_jd = timeDeltaToJulianDelta(timestep, ref_dt, timestep_jd); - - -! /* For speed-up */ -! struct _juliandelta* timestep_fastfwd_jd = newJulianDelta('+', 0, 0); -! struct _juliandelta* timestep_fastbkw_jd = newJulianDelta('+', 0, 0); - - -! /* Get anchor. ref + offset is the real anchor. */ -! struct _datetime* anchor = constructAndCopyDateTime(ref_dt); -! addTimeDeltaToDateTime(ref_dt, offset, anchor); // Note: If offset is null, no addition takes place. - -! /* Get anchor in julian. */ -! struct _julianday* anchor_jd = newJulianDay(0, 0); -! anchor_jd = date2julian(anchor, anchor_jd); - -! /* Optimization hack: Calculate an approx metric are_dates_too_far and speed up the jumps. */ -! int64_t are_dates_too_far = 0; -! if (timestep_jd->day) -! are_dates_too_far = (start_jd->day - anchor_jd->day)/(timestep_jd->day); -! else if (timestep_jd->ms) -! are_dates_too_far = (start_jd->day - anchor_jd->day)/((float)timestep_jd->ms/NO_OF_MS_IN_A_DAY); -! //else ... well, should never happen. If it does, the initialized value of zero persists. - + RETURN + + ELSE IF (timestep%year == 0 .AND. timestep%month == 0) + + start_jd = t_julianday(start_dt) -! int lambda = 1; //speed-up const. Default is 1 or no speedup. -! if (are_dates_too_far>10 || are_dates_too_far<-10) -! lambda = 100000; //speed up if start-date and anchor are 'too-far' away. + timestep_jd = t_juliandelta(timestep, ref_dt) + + anchor = ref_dt + offset + anchor_jd = t_julianday(anchor) + + + IF (timestep_jd%day /= 0) THEN + are_dates_too_far = (start_jd%day - anchor_jd%day)/(timestep_jd%day) + ELSE IF (timestep_jd%ms /= 0) THEN + are_dates_too_far = (start_jd%day - anchor_jd%day)/((float)timestep_jd%ms/NO_OF_MS_IN_A_DAY) + ENDIF + + lambda = 1 + IF (are_dates_too_far > 10 .OR. are_dates_too_far < -10) THEN + lambda = 100000 + ENDIF + timestep_fastfwd_jd%day = lambda*timestep_jd%day + timestep_fastfwd_jd%ms = lambda*timestep_jd%ms -! /* Fast-Fwd */ -! timestep_fastfwd_jd->day = lambda*timestep_jd->day; -! timestep_fastfwd_jd->ms = lambda*timestep_jd->ms; + DO WHILE (timestep_fastfwd_jd%ms >= NO_OF_MS_IN_A_DAY) + timestep_fastfwd_jd%day++ + timestep_fastfwd_jd%ms = timestep_fastfwd_jd%ms - NO_OF_MS_IN_A_DAY + ENDDO -! while( timestep_fastfwd_jd->ms >= NO_OF_MS_IN_A_DAY ) -! { -! timestep_fastfwd_jd->day++; -! timestep_fastfwd_jd->ms = timestep_fastfwd_jd->ms - NO_OF_MS_IN_A_DAY; -! } + timestep_bkw = timestep + timestep_bkw%sign = '-' + timestep_bkw_jd = t_juliandelta(timestep_bkw, ref_dt) -! /* We need to Loop backwards: Create a timestep replica and change the sign to negative to travel-back-in-time. */ -! timestep_bkw = constructAndCopyTimeDelta(timestep); -! timestep_bkw->sign = '-'; + timestep_fastbkw_jd%day = lambda*timestep_bkw_jd%day + timestep_fastbkw_jd%ms = lambda*timestep_bkw_jd%ms -! struct _juliandelta* timestep_bkw_jd = newJulianDelta('+', 0, 0); -! timeDeltaToJulianDelta(timestep_bkw, ref_dt, timestep_bkw_jd); + DO WHILE (timestep_fastbkw_jd%ms <= (-1)*(NO_OF_MS_IN_A_DAY)) + timestep_fastbkw_jd%day-- + timestep_fastbkw_jd%ms = timestep_fastbkw_jd%ms + NO_OF_MS_IN_A_DAY + ENDDO -! /* Fast-Bkwd */ -! timestep_fastbkw_jd->day = lambda*timestep_bkw_jd->day; -! timestep_fastbkw_jd->ms = lambda*timestep_bkw_jd->ms; + IF (start_dt > ref_date) THEN + + DO + anchor_jd%day = anchor_jd%day + timestep_fastfwd_jd%day + anchor_jd%ms = anchor_jd%ms + timestep_fastfwd_jd%ms + + IF (anchor_jd%ms >= NO_OF_MS_IN_A_DAY) THEN + anchor_jd%day = anchor_jd%day + 1 + anchor_jd%ms = anchor_jd%ms - NO_OF_MS_IN_A_DAY + ENDIF + + IF ((anchor_jd%day > start_jd%day) .OR. (anchor_jd%day == start_jd%day .AND. anchor_jd%ms > start_jd%ms)) EXIT + ENDDO + + anchor_jd%day = anchor_jd%day - timestep_fastfwd_jd%day + anchor_jd%ms = anchor_jd%ms - timestep_fastfwd_jd%ms + + IF (anchor_jd%ms < 0) THEN + anchor_jd%day = anchor_jd%day - 1 + anchor_jd%ms = anchor_jd%ms + NO_OF_MS_IN_A_DAY + ENDIF + + DO + anchor_jd%day = anchor_jd%day + timestep_jd%day + anchor_jd%ms = anchor_jd%ms + timestep_jd%ms + + IF (anchor_jd%ms >= NO_OF_MS_IN_A_DAY) THEN + anchor_jd%day = anchor_jd%day + 1 + anchor_jd%ms = anchor_jd%ms - NO_OF_MS_IN_A_DAY + ENDIF -! while( timestep_fastbkw_jd->ms <= (-1)*(NO_OF_MS_IN_A_DAY) ) -! { -! timestep_fastbkw_jd->day--; -! timestep_fastbkw_jd->ms = timestep_fastbkw_jd->ms + NO_OF_MS_IN_A_DAY; -! } + IF ((anchor_jd%day > start_jd%day) .OR. (anchor_jd%day == start_jd%day .AND. anchor_jd%ms >= start_jd%ms)) EXIT + ENDDO + anchor_jd = t_juliandelta(anchor) -! switch (compareDatetime(start_dt,ref_dt)) -! { -! case greater_than: /* start_dt > ref_dt */ - -! /* Jump very fast and reach the start date quickly. */ -! do -! { -! anchor_jd->day = anchor_jd->day + timestep_fastfwd_jd->day; -! anchor_jd->ms = anchor_jd->ms + timestep_fastfwd_jd->ms; - -! if (anchor_jd->ms >= NO_OF_MS_IN_A_DAY) -! { -! anchor_jd->day = anchor_jd->day + 1; -! anchor_jd->ms = anchor_jd->ms - NO_OF_MS_IN_A_DAY; -! } - -! } while ( !((anchor_jd->day > start_jd->day) || (anchor_jd->day == start_jd->day && anchor_jd->ms > start_jd->ms)) ); - - -! /* But I jumped one time too much. Move back */ -! anchor_jd->day = anchor_jd->day - timestep_fastfwd_jd->day; -! anchor_jd->ms = anchor_jd->ms - timestep_fastfwd_jd->ms; + ELSE IF (start_dt == ref_dt) THEN -! if (anchor_jd->ms < 0) -! { -! anchor_jd->day = anchor_jd->day - 1; -! anchor_jd->ms = anchor_jd->ms + NO_OF_MS_IN_A_DAY; -! } + ! nothing to do - - -! /* I am close. Now determine the actual time. */ -! do -! { -! anchor_jd->day = anchor_jd->day + timestep_jd->day; -! anchor_jd->ms = anchor_jd->ms + timestep_jd->ms; - -! if (anchor_jd->ms >= NO_OF_MS_IN_A_DAY) -! { -! anchor_jd->day = anchor_jd->day + 1; -! anchor_jd->ms = anchor_jd->ms - NO_OF_MS_IN_A_DAY; -! } - -! } while ( !((anchor_jd->day > start_jd->day) || (anchor_jd->day == start_jd->day && anchor_jd->ms >= start_jd->ms)) ); - -! /* anchor_jd is now the true event-trigger-time. Set it to anchor. */ -! julian2date(anchor_jd,anchor); - -! break; - -! case equal_to: /* start_dt == ref_dt */ - -! break; - -! case less_than: /* start_dt < ref_dt */ + ELSE IF (start_dt < ref_dt) THEN + DO + anchor_jd%day = anchor_jd%day + timestep_fastbkw_jd%day + anchor_jd%ms = anchor_jd%ms + timestep_fastbkw_jd%ms + + IF ( anchor_jd%ms < 0 ) THEN + anchor_jd%day = anchor_jd%day - 1 + anchor_jd%ms = anchor_jd%ms + NO_OF_MS_IN_A_DAY + ENDIF -! /* Jump very fast bkwd and reach the start date quickly. */ -! do -! { -! anchor_jd->day = anchor_jd->day + timestep_fastbkw_jd->day; -! anchor_jd->ms = anchor_jd->ms + timestep_fastbkw_jd->ms; - -! if ( anchor_jd->ms < 0 ) -! { -! anchor_jd->day = anchor_jd->day - 1; -! anchor_jd->ms = anchor_jd->ms + NO_OF_MS_IN_A_DAY; -! } - -! } while(! (anchor_jd->day < start_jd->day || (anchor_jd->day == start_jd->day && anchor_jd->ms < start_jd->ms)) ); - - -! /* I jumped one time too much. Move forward. */ -! anchor_jd->day = anchor_jd->day + timestep_fastfwd_jd->day; -! anchor_jd->ms = anchor_jd->ms + timestep_fastfwd_jd->ms; - -! if (anchor_jd->ms >= NO_OF_MS_IN_A_DAY) -! { -! anchor_jd->day = anchor_jd->day + 1; -! anchor_jd->ms = anchor_jd->ms - NO_OF_MS_IN_A_DAY; -! } - - -! /* I am close. Get the real time. */ -! do -! { -! anchor_jd->day = anchor_jd->day + timestep_bkw_jd->day; -! anchor_jd->ms = anchor_jd->ms + timestep_bkw_jd->ms; - -! if ( anchor_jd->ms < 0 ) -! { -! anchor_jd->day = anchor_jd->day - 1; -! anchor_jd->ms = anchor_jd->ms + NO_OF_MS_IN_A_DAY; -! } - -! } while(! (anchor_jd->day < start_jd->day || (anchor_jd->day == start_jd->day && anchor_jd->ms < start_jd->ms)) ); - + IF (anchor_jd%day < start_jd%day .OR. (anchor_jd%day == start_jd%day .AND. anchor_jd%ms < start_jd%ms)) EXIT + ENDDO -! /* I jumped one time too much. Move forward. */ -! anchor_jd->day = anchor_jd->day + timestep_jd->day; -! anchor_jd->ms = anchor_jd->ms + timestep_jd->ms; + anchor_jd%day = anchor_jd%day + timestep_fastfwd_jd%day + anchor_jd%ms = anchor_jd%ms + timestep_fastfwd_jd%ms + + IF (anchor_jd%ms >= NO_OF_MS_IN_A_DAY) THEN + anchor_jd%day = anchor_jd%day + 1 + anchor_jd%ms = anchor_jd%ms - NO_OF_MS_IN_A_DAY + ENDIF + + DO + anchor_jd%day = anchor_jd%day + timestep_bkw_jd%day + anchor_jd%ms = anchor_jd%ms + timestep_bkw_jd%ms + + IF ( anchor_jd%ms < 0 ) THEN + anchor_jd%day = anchor_jd%day - 1 + anchor_jd%ms = anchor_jd%ms + NO_OF_MS_IN_A_DAY + ENDIF + + IF (anchor_jd%day < start_jd%day .OR. (anchor_jd%day == start_jd%day .AND. anchor_jd%ms < start_jd%ms)) EXIT + ENDDO -! if (anchor_jd->ms >= NO_OF_MS_IN_A_DAY) -! { -! anchor_jd->day = anchor_jd->day + 1; -! anchor_jd->ms = anchor_jd->ms - NO_OF_MS_IN_A_DAY; -! } + anchor_jd%day = anchor_jd%day + timestep_jd%day + anchor_jd%ms = anchor_jd%ms + timestep_jd%ms + + IF (anchor_jd%ms >= NO_OF_MS_IN_A_DAY) THEN + anchor_jd%day = anchor_jd%day + 1 + anchor_jd%ms = anchor_jd%ms - NO_OF_MS_IN_A_DAY + ENDIF + + anchor_jd = t_juliandelta(anchor) + + ELSE -! /* anchor_jd now has the true trigger time. Copy it to anchor. */ -! julian2date(anchor_jd,anchor); + ! should never happen. -! default: + ENDIF -! ; //Should never happen. Don't return NULL just yet as deallocateDateTime(anchor) still needs to be called. + first_trigger_date = anchor -! } - -! /* Copy the contents to target. */ -! replaceDatetime(anchor,first_trigger_dt); - - -! /* Cleanup. */ - -! deallocateDateTime(anchor); -! deallocateJulianDay(start_jd); -! deallocateJulianDay(anchor_jd); -! deallocateJulianDelta(timestep_jd); -! deallocateTimeDelta(timestep_bkw); -! deallocateJulianDelta(timestep_bkw_jd); - -! deallocateJulianDelta(timestep_fastfwd_jd); -! deallocateJulianDelta(timestep_fastbkw_jd); - -! /* And return. */ -! return first_trigger_dt; -! } -! else -! { -! /* NOTE: general case updates by explicit adding. */ + RETURN -! /* Get anchor. ref + offset is the real anchor. */ -! struct _datetime *anchor = constructAndCopyDateTime(ref_dt); -! addTimeDeltaToDateTime(ref_dt, offset, anchor); // Note: If offset is null, no addition takes place. + ELSE -! while (compareDatetime(anchor, start_dt) == less_than) -! { -! addTimeDeltaToDateTime(anchor, timestep, anchor); -! } -! /* Copy the contents to target. */ -! replaceDatetime(anchor,first_trigger_dt); - -! /* Cleanup. */ -! deallocateDateTime(anchor); + anchor = ref_dt + anchor = anchor + offset -! /* And return. */ -! return first_trigger_dt; -! } -! } -! else -! return NULL; -! } + DO WHILE (anchor < start_dt) + anchor = anchor + timestep + ENDDO + first_trigger_date = anchor -! /** -! * @brief Get the Datetime when 'this' event will be triggered next. -! * -! * WARNING: The value returned is with-respect-to current_dt and not a true copy of triggerNextEventDateTime in the event data structure. -! * -! * @param e -! * A pointer to struct _event. This is the event being queried. -! * -! * @param dt_return -! * A pointer to struct _datetime. The next trigger datetime is copied here. -! * -! * @return dt_return -! * A pointer to DateTime with next-trigger datetime. -! */ + RETURN -! struct _datetime* -! getTriggerNextEventAtDateTime(struct _event* e, struct _datetime* current_dt, struct _datetime* dt_return) -! { -! if ((e != NULL) && (current_dt != NULL) && (dt_return != NULL)) -! { -! /* If last date is defined, check if current_dt is ahead of event->eventLastDateTime. -! Return on NULL indicating no future trigger event scheduled.*/ -! if (e->eventLastDateTime && (compareDatetime(current_dt,e->eventLastDateTime) == greater_than)) -! return NULL; + ENDIF -! /* This if should evaluate to false normally. The only occasion when it does not is if the -! current_dt > triggerNextEventDateTime and isCurrentEventActive(.) has never been called */ -! if ( -! (e->nextEventIsFirst) -! && -! (compareDatetime(current_dt,e->triggerNextEventDateTime) == greater_than) -! ) -! { -! struct _timedelta* modulo_td = newTimeDelta("PT00.000S"); -! // Get the first trigger time and return (WARNING: Do not update e->triggerNextEventDateTime here!). -! moduloTimeDeltaFromDateTime(e->triggerNextEventDateTime, e->eventInterval, current_dt, modulo_td); -! addTimeDeltaToDateTime(current_dt,modulo_td,dt_return); -! // Cleanup. -! deallocateTimeDelta(modulo_td); -! return dt_return; -! } -! // else ... -! dt_return = replaceDatetime(e->triggerNextEventDateTime, dt_return); -! return dt_return; -! } -! else -! return NULL; -! } +END FUNCTION getEventFirstTriggerDateTime +function getTriggerNextEventAtDateTime(e, current_dt) result(dt_return) + type(t_datetime) :: dt_return + type(t_event), intent(in) :: e + type(t_datetime), intent(in) :: current_dt + + type(t_timedelta) :: modulo_td + + if (e%eventLastDateTime && (compareDatetime(current_dt,e%eventLastDateTime) == greater_than)) + return NULL + + if (e%nextEventIsFirst) .and. (current_dt > e%triggerNextEventDateTime)) then + struct _timedelta* modulo_td = newTimeDelta("PT00.000S") + // Get the first trigger time and return (WARNING: Do not update e%triggerNextEventDateTime here!). + moduloTimeDeltaFromDateTime(e%triggerNextEventDateTime, e%eventInterval, current_dt, modulo_td) + addTimeDeltaToDateTime(current_dt,modulo_td,dt_return) + // Cleanup. + deallocateTimeDelta(modulo_td) + return dt_return + } + // else ... + dt_return = replaceDatetime(e%triggerNextEventDateTime, dt_return) + return dt_return + +end function getTriggerNextEventAtDateTime + ! /** ! * @brief Get the Datetime when 'this' event was triggered last. ! * @@ -1184,115 +385,115 @@ end function iseventNextInNextYear ! struct _datetime* ! getTriggeredPreviousEventAtDateTime(struct _event* e, struct _datetime* dt_return) ! { -! if ((e != NULL )&& (dt_return != NULL) ) +! if ((e /= NULL )&& (dt_return /= NULL) ) ! { ! /* No trigger ever happened? */ -! if (e->nextEventIsFirst) -! return NULL; +! if (e%nextEventIsFirst) +! return NULL -! replaceDatetime(e->triggeredPreviousEventDateTime, dt_return); -! return dt_return; +! replaceDatetime(e%triggeredPreviousEventDateTime, dt_return) +! return dt_return ! } ! else -! return NULL; +! return NULL ! } ! struct _datetime* ! getEventReferenceDateTime(struct _event* e) ! { -! if (e != NULL) -! return e->eventReferenceDateTime; +! if (e /= NULL) +! return e%eventReferenceDateTime ! else -! return NULL; +! return NULL ! } ! struct _datetime* ! getEventFirstDateTime(struct _event* e) ! { -! if (e != NULL) -! return e->eventFirstDateTime; +! if (e /= NULL) +! return e%eventFirstDateTime ! else -! return NULL; +! return NULL ! } ! struct _datetime* ! getEventLastDateTime(struct _event* e) ! { -! if (e != NULL) -! return e->eventLastDateTime; +! if (e /= NULL) +! return e%eventLastDateTime ! else -! return NULL; +! return NULL ! } ! struct _timedelta* ! getEventInterval(struct _event* e) ! { -! if (e != NULL) -! return e->eventInterval; +! if (e /= NULL) +! return e%eventInterval ! else -! return NULL; +! return NULL ! } ! bool ! getNextEventIsFirst(struct _event* e) ! { -! if (e != NULL) -! return e->nextEventIsFirst; +! if (e /= NULL) +! return e%nextEventIsFirst ! else -! return false; +! return false ! } ! bool ! getEventisFirstInDay(struct _event* e) ! { -! if (e != NULL) -! return e->eventisFirstInDay; +! if (e /= NULL) +! return e%eventisFirstInDay ! else -! return false; +! return false ! } ! bool ! getEventisFirstInMonth(struct _event* e) ! { -! if (e != NULL) -! return e->eventisFirstInMonth; +! if (e /= NULL) +! return e%eventisFirstInMonth ! else -! return false; +! return false ! } ! bool ! getEventisFirstInYear(struct _event* e) ! { -! if (e != NULL) -! return e->eventisFirstInYear; +! if (e /= NULL) +! return e%eventisFirstInYear ! else -! return false; +! return false ! } ! bool ! getEventisLastInDay(struct _event* e) ! { -! if (e != NULL) -! return e->eventisLastInDay; +! if (e /= NULL) +! return e%eventisLastInDay ! else -! return false; +! return false ! } ! bool ! getEventisLastInMonth(struct _event* e) ! { -! if (e != NULL) -! return e->eventisLastInMonth; +! if (e /= NULL) +! return e%eventisLastInMonth ! else -! return false; +! return false ! } ! bool ! getEventisLastInYear(struct _event* e) ! { -! if (e != NULL) -! return e->eventisLastInYear; +! if (e /= NULL) +! return e%eventisLastInYear ! else -! return false; +! return false ! }