1. Time Management
    1. Introduction
    2. This chapter introduces the RTIambassador service and FederateAmbassador callback methods that support time management functionality. The RTI provides a variety of optional time management services. Though optional, it is important to understand the time management models available in the RTI and the implication of exchanging events between federates with different time management policies. Chapter 3, The Role of Time, provides a philosophical introduction to time management. The focus here is on the mechanics required to implement time management policies and negotiate time advances.

       

    3. Toggling "regulating" and "constrained" Status
    4. Chapter 3, The Role of Time, presented the definitions for "regulating" and "constrained." Figure 6-1 identifies the RTIambassador and FederateAmbassador member functions associated with establishing whether a federate is regulating or not, and whether a federate is constrained or not. Key methods are presented briefly below and discussed in detail in the appendices.

       

      Figure 6-1. Toggling "regulating" and "constrained" Status

       

      1. Regulation Policy
      2. Federates have regulation disabled by default. A federate utilizes the RTIambassador member function enableTimeRegulation() to request that the federate be acknowledged as a regulating federate. The Local RTI Component (LRC) calls the FederateAmbassador callback timeRegulationEnabled() to inform a federate that the enableTimeRegulation() request has been granted and informs the federate of its (possibly new) logical time. In Section 3.4, Advancing Time, the effect of a late arriving federate wishing to be time regulating was discussed. In synopsis, such a federate is obligated to advance to a time such that the current LBTS of existing federates is guaranteed to be honored.

        It is possible to change the regulation policy dynamically. The RTIambassador method disableTimeRegulation() is the counterpart to enableTimeRegulation(). Unlike enableTimeRegulation(), disableTimeRegulation() takes effect immediately.

      3. Constrained Policy

      Federates have constrained disabled by default. A federate utilizes the RTIambassador member function enableTimeConstrained() to request that the federate be acknowledged as a constrained federate. The timeConstrainedEnabled() callback informs a federate that the enableTimeConstrained() request has been granted. It is possible to change the constrained policy dynamically. The RTIambassador method disableTimeConstrained() is the counterpart to enableTimeConstrained().

    5. Time Advance Requests
    6. Three variants of the time advancement service exist to provide the requisite functionality for time-step, event-based, and optimistic federates. Typically, a federate will employ only one of the time advancement services; however, some federates may find it useful to use more than one of the services throughout the federate’s execution.

      1. Time-Stepped Federates
      2. Time-stepped federates will calculate values based on a point in time and then process all events that occur up to the next point in time (current time + time step). Figure 6-2 illustrates the functions used to advance a federate's logical time for a time-stepped simulation.

        When a timeAdvanceRequest() or timeAdvanceRequestAvailable() service is used, the federate’s LRC will be eligible to release any receive order messages from the FIFO Queue and all time-stamp ordered messages that have a time stamp less than or equal to the time requested from the TSO queue. After all TSO messages in a federation execution with time less than or equal to the requested time have been received, the federate will receive a timeAdvanceGrant() callback via the FederateAmbassador. See the man pages for a more detailed discussion of the released events and the granted time for the timeAdvanceRequest() and timeAdvanceRequestAvailable() services.

        Figure 6-2. Logical Time Advancement for a Time-Step Federate

         

      3. Event-Based Federates
      4. Event-based federates will calculate values based on each event received from the federation execution. After an event is processed, the federate may need to send new events to the federation execution. This implies that the events may not happen on set time intervals but the times of events will be based on the time of the received events. Figure 6-3 illustrates the functions used to advance a federate's logical time for an event-based simulation.

        When a nextEventRequest() or nextEventRequestAvailable() service is used, the federate’s LRC will be eligible to release any receive order messages from the FIFO Queue and all time-stamp ordered messages that have a time stamp equal to the minimum next event time from the TSO queue.

        After all TSO messages with time equal to the minimum next event time have been received, the federate will receive a timeAdvanceGrant() callback via the FederateAmbassador. See the man pages for a more detailed discussion of the released events and the granted time for the nextEventRequest() and nextEventRequestAvailable() services.

        Figure 6-3. Logical Time Advancement for an Event-Based Federate

         

      5. Optimistic Federates

      Optimistic federates do not want to be constrained by the time advancement of regulating federates but instead will proceed ahead of LBTS to calculate and send events in the future. These federates will want to receive all of the events that have been sent in the federation execution regardless of the time-stamp ordering. A federate that uses the flushQueueRequest() service is likely to generate events that are in the future of messages that it has yet to receive. The messages that are received with a time-stamp less than messages already sent may invalidate the previous messages. In this case, the optimistic federate will need to retract the messages that have been invalidated and all federates that have received the invalid messages will receive a requestRetraction() callback on their FederateAmbassador. See the man pages for a detailed discussion of the retract() and requestRetraction() services.

      When the flushQueueRequest() service is used, the federate’s LRC will be eligible to release all receive order messages from the FIFO Queue and all time-stamp ordered messages from the TSO queue. After all TSO messages that were in the queue at the time of the flushQueueRequest() invocation have been released, the federate will receive a timeAdvanceGrant() callback via the FederateAmbassador. See the man pages for a more detailed discussion of the released events and the granted time for the flushQueueRequest() service. Figure 6-4 illustrates the functions used to advance a federate's logical time for an optimistic simulation.

      Figure 6-4. Logical Time Advancement for an Optimistic Federate

    7. FoodFight Example

Time advance requests are made through an RTIambassador instance. Time advance grants are received through a FederateAmbassador instance. User code must unite the request and grant. This pattern is repeated throughout the RTI. One approach to uniting code is to communicate through global variables (globals). In the following examples, globals are used to tie the following service request, callback pairs:

RTIambassador::enableTimeRegulation()® FederateAmbassador::timeRegulationEnabled()

RTIambassador::enableTimeConstrained()® FederateAmbassador::timeConstrainedEnabled()

RTIambassador::timeAdvanceRequest()® FederateAmbassador::timeAdvanceGrant()

Whenever user-defined global variables or global functions are used in coding examples, they're preceded by the global scope resolution operator "::". While it is a bad practice to use globals, it is a good practice to identify any globals with this operator.

 

globals.h

  1. #ifndef globals_h
  2. #define globals_h
  3. #include <RTI.hh>
  4. :
  5. // The time of the last time advance grant.
  6. extern RTI::FedTime* p_current_time;
  7. // The lookahead period promised by this federate. Set when federate
  8. // attempts to become regulating.
  9. extern RTI::FedTime* p_lookahead;
  10. // Variable indicating whether we currently have a pending time advance
  11. extern int time_advance_outstanding;
  12. // Flag indicating if federate is constrained.
  13. extern int regulation_enabled;
  14. // Flag indicating if federate is constrained.
  15. extern int constrain_enabled;
  16. :
  17. #endif
  18. // globals_h
  19. globals.cxx

  20. #include "globals.h"
  21. :
  22. RTI::FedTime* p_current_time = new RTIfedTime(0.0);
  23. RTI::FedTime* p_lookahead = 0; // Not set yet.
  24. int time_advance_outstanding = 0;
  25. int regulation_enabled = 0; // Disabled by default.
  26. int constrain_enabled = 0; // Disabled by default.
  27. :
  28. ::PrimarySimulation()

  29. void
  30. PrimarySimulation (int regulating_flag,
  31. int constrained_flag)
  32. {
  33. // Abstract
  34. // This function produces the FoodFight simulation.
  35. Pstring federation_name("FoodFight");
  36. Pstring federate_name("ExampleFederate");
  37. // Create and join the FoodFight federation.
  38. ::CreateAndJoinFederation(federation_name, federate_name);
  39. // Set up time-management services.
  40. if (regulating_flag)
  41. {
  42. ::p_lookahead = new RTIfedTime(1.0); // One second.
  43. ::rti_ambassador.enableTimeRegulation(*::p_current_time, *::lookahead);
  44. // A request to become regulating is, effectively, a time advance
  45. // request.
  46. ::time_advance_outstanding = 1;
  47. }
  48. if (constrained_flag)
  49. {
  50. cout << "Federate is constrained!" << endl;
  51. ::rti_ambassador.enableTimeConstrained();
  52. }
  53. :
  54. :
  55. // The time interval for this federate has been set (arbitrarily) to the
  56. // lookahead value.
  57. RTI::FedTime* p_interval = new RTIfedTime(0.0);
  58. *p_interval = *::p_lookahead;
  59. while (::local_students.entries())
  60. {
  61. if (!::time_advance_outstanding)
  62. {
  63. // Do one interval's worth of simulation.
  64. :
  65. :
  66. // Attempt to advance federate's logical time. The logical time
  67. // isn't officially advanced until a time advance grant is
  68. // received. If a regulating federate is still attempting to
  69. // generate events, it should pretend like the time advance has
  70. // been granted for the purpose of observing its lookahead promise.
  71. *::p_current_time += *p_interval;
  72. ::rti_ambassador.timeAdvanceRequest(*::p_current_time);
  73. ::time_advance_outstanding = 1;
  74. }
  75. :
  76. :
  77. // Work to be interleaved with tick only!
  78. :
  79. :
  80. // Tick the RTI, initiating federate ambassador callbacks.
  81. ::rti_ambassador.tick(1.0, 1.0);
  82. }
  83. // Resign from the federation execution and attempt to destroy.
  84. ::ResignAndDestroyFederation(federation_name, federate_name);
  85. }
  86. The two-argument form of tick is called in the preceding example. In the example, the goal is to slow the simulation so students can observe simulation progress. As an alternative to line 87, the one-argument version of tick() might be used. Between calls to tick() and prior to receiving a time advance grant, the federate may choose to interleave some preparatory work.

  87. ::rti_ambassador.tick(); // Alternative to line 87 above.
  88. FoodFightFedAmb.h

  89. class FoodFightFedAmb : public DefaultFedAmb
  90. {
  91. // Abstract
  92. // The DefaultFedAmb defines all the federate ambassador methods
  93. // to "do nothing". Here, we override the ones we're interested
  94. // in.
  95. public:
  96. virtual void timeRegulationEnabled (const FedTime&)
  97. throw (InvalidFederationTime, EnableTimeRegulationWasNotPending,
  98. FederateInternalError);
  99. virtual void timeConstrainedEnabled (const FedTime&)
  100. throw (InvalidFederationTime, EnableTimeConstrainedWasNotPending,
  101. FederateInternalError);
  102. virtual void timeAdvanceGrant (const RTI::FedTime&)
  103. throw (RTI::InvalidFederationTime, RTI::TimeAdvanceWasNotInProgress,
  104. RTI::FederateInternalError);
  105. :
  106. FoodFightFedAmb.cxx

  107. :
  108. void
  109. FoodFightFedAmb::
  110. timeRegulationEnabled (const FedTime& time)
  111. throw (InvalidFederationTime, EnableTimeRegulationWasNotPending,
  112. FederateInternalError)
  113. {
  114. cout << "Federate acknowledged as regulating!" << endl;
  115. ::regulation_enabled = 1;
  116. ::time_advance_outstanding = 0;
  117. *::p_current_time = time;
  118. }
  119. void
  120. FoodFightFedAmb::
  121. timeConstrainedEnabled (const FedTime&) // Argument ignored below.
  122. throw (InvalidFederationTime, EnableTimeConstrainedWasNotPending,
  123. FederateInternalError)
  124. {
  125. cout << "Federate acknowledged as constrained!" << endl;
  126. ::constrain_enabled = 1;
  127. }
  128. void
  129. FoodFightFedAmb::
  130. timeAdvanceGrant (const RTI::FedTime& time)
  131. throw (RTI::InvalidFederationTime,
  132. RTI::TimeAdvanceWasNotInProgress, RTI::FederateInternalError)
  133. {
  134. if (!::time_advance_outstanding)
  135. {
  136. const char* err_msg = "Unexpected timeAdvanceGrant().";
  137. cerr << err_msg;
  138. throw RTI::TimeAdvanceWasNotInProgress(err_msg);
  139. }
  140. if (time < *::p_current_time)
  141. {
  142. const char* err_msg = "Old time passed in timeAdvanceGrant().";
  143. cerr << err_msg;
  144. throw RTI::InvalidFederationTime(err_msg);
  145. }
  146. try
  147. {
  148. *::p_current_time = time;
  149. ::time_advance_outstanding = 0;
  150. // Display current time.
  151. char* p_string(0);
  152. p_current_time.getPrintableString(p_string);
  153. cout << "t = " << p_string << endl;
  154. delete p_string;
  155. }
  156. catch (...)
  157. {
  158. const char* err_msg = "Exception caught in timeAdvanceGrant().";
  159. cerr << err_msg;
  160. throw RTI::FederateInternalError(err_msg);
  161. }
  162. }
  163. :
    1. Time-Related Queries

Several additional time management functions are available to query or fine tune time policy. Figure 6-4, Time Queries, shows additional functions. Consult the man pages for these functions for detailed descriptions.

Figure 6-4. Time Queries