1 #ifndef SimTK_SimTKCOMMON_EVENT_H_
2 #define SimTK_SimTKCOMMON_EVENT_H_
3 
4 /* -------------------------------------------------------------------------- *
5  *                       Simbody(tm): SimTKcommon                             *
6  * -------------------------------------------------------------------------- *
7  * This is part of the SimTK biosimulation toolkit originating from           *
8  * Simbios, the NIH National Center for Physics-Based Simulation of           *
9  * Biological Structures at Stanford, funded under the NIH Roadmap for        *
10  * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody.  *
11  *                                                                            *
12  * Portions copyright (c) 2008-12 Stanford University and the Authors.        *
13  * Authors: Michael Sherman                                                   *
14  * Contributors:                                                              *
15  *                                                                            *
16  * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
17  * not use this file except in compliance with the License. You may obtain a  *
18  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
19  *                                                                            *
20  * Unless required by applicable law or agreed to in writing, software        *
21  * distributed under the License is distributed on an "AS IS" BASIS,          *
22  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
23  * See the License for the specific language governing permissions and        *
24  * limitations under the License.                                             *
25  * -------------------------------------------------------------------------- */
26 
27 /** @file
28  *
29  * This file declares the types needed for Simbody's support for Events.
30  */
31 
32 #include "SimTKcommon/basics.h"
33 
34 namespace SimTK {
35 
36 /** @class SimTK::EventId
37 This is a class to represent unique IDs for events in a type-safe way. These
38 are created and managed by the System, not the State. **/
39 SimTK_DEFINE_UNIQUE_INDEX_TYPE(EventId);
40 
41 /** @class SimTK::SystemEventTriggerIndex
42 This unique integer type is for identifying a triggered event in the full
43 System-level view of the State. More precisely, this is the index of the slot
44 in the global array in the cache allocated to hold the value of that event's
45 trigger function.
46 @see EventTriggerIndex **/
47 SimTK_DEFINE_UNIQUE_INDEX_TYPE(SystemEventTriggerIndex);
48 
49 /** @class SimTK::SystemEventTriggerByStageIndex
50 This unique integer type is for identifying a triggered event within a
51 particular Stage of the full System-level view of the State. (Event triggers
52 for a particular Stage are stored consecutively within the full collection of
53 event triggers.) That is, the EventTriggerByStageIndex will be 0 for the first
54 event trigger at that stage.
55 @see EventTriggerByStageIndex
56 **/
57 SimTK_DEFINE_UNIQUE_INDEX_TYPE(SystemEventTriggerByStageIndex);
58 
59 /** @class SimTK::EventTriggerByStageIndex
60 Unique integer type for Subsystem-local, per-stage event indexing.
61 @see SystemEventTriggerByStageIndex **/
62 SimTK_DEFINE_UNIQUE_INDEX_TYPE(EventTriggerByStageIndex);
63 
64 /** An Event is "something that happens" during a Study that is advancing
65 through time. Its occurrence interrupts the normal flow of computation, allowing
66 an event Handler to adjust the State prior to resuming the Study.
67 
68 Events are allocated by Subsystems, but require some System global resources.
69 All Events are given a unique EventId. Some Events require other State
70 resources, such as slots for the values of trigger functions in the case of
71 Triggered events.
72 
73 Events can be allocated at Topology, Model, and Instance Stages. All Event
74 resources are assigned when the Instance stage is realized. However, if an
75 Event requires state variables, then it must be allocated by Model stage. **/
76 class Event {
77 public:
78 
79     /** These are all the possible causes for events.
80 
81     @par Initialization
82     A Study has performed its own initialization and is about to start.
83 
84     @par Triggered
85     An event trigger function underwent a monitored sign transition.
86 
87     @par Scheduled
88     An integrator reached a previously-scheduled time for the Event to occur.
89 
90     @par TimeAdvanced
91     An integrator completed an internal step, meaning that it has reached
92     a point where time has advanced irreversibly.
93 
94     @par Signaled
95     A flag in the State has been explicitly set, meaning that a particular
96     Event has occurred. Anyone with write access to a State can set these,
97     but typically they are set in event handlers associated with one of
98     the other kinds of events.
99 
100     @par Termination
101     The Study has finished. If a Termination event handler signals more
102     Events, those signaled events are not processed by the Study; that is,
103     the signals remain set in the final State.
104 
105     In case several of these causes are detected in a single step, they are
106     sequentialized in the order shown, like this:
107 
108     1. The occurrence of triggered events is reported and the triggering state
109        and a list of triggered events are passed to the event handler for
110        processing (meaning the state, but not the time, is modified). Note
111        that simultaneity *within* the set of triggered events may also require
112        special handling; we're not talking about that here, just simultaneity
113        of *causes*.
114     2. Next, using the state resulting from step 1, the time is checked to see
115        if scheduled events have occurred. If so, a list of those events is
116        passed to the event handler for processing.
117     3. Next, if this system has requested time-advanced events, the event
118        handler is called with the state that resulted from step 2 and the "time
119        advanced" cause noted. No event list is passed in that case. The state
120        may be modified.
121     4. Last, if the final time has been reached or if any of the event handlers
122        asked for termination, we pass the state to the event handler again
123        noting that we have reached termination. The state may be modified and
124        the result will be the final state of the simulation.
125     **/
126     class Cause {
127     public:
128         enum Num {
129             Initialization  = 1,
130             Triggered       = 2,
131             Scheduled       = 3,
132             TimeAdvanced    = 4,
133             Signaled        = 5,
134             Termination     = 6,
135             Invalid         = -1
136         };
137 
Cause()138         Cause() : value(Invalid) {}
Cause(Num n)139         Cause(Num n) : value(n) {}           // implicit conversion
Num()140         operator Num() const {return value;} // implicit conversion
141         Cause& operator=(Num n) {value=n; return *this;}
142 
isValid()143         bool isValid() const {return Initialization<=value && value<=Termination;}
144 
145     private:
146         Num value;
147     };
148 
149     /** This is useful for debugging; it translates an Event::Cause into a
150     readable string. **/
151     SimTK_SimTKCOMMON_EXPORT static const char* getCauseName(Cause);
152 
153 
154     /** Triggered Events respond to zero crossings of their associated trigger
155     function. This enum defines constants for use in specifying which kind
156     of zero crossing has been seen, or which kinds are considered interesting.
157     For the latter purpose, these can be or'ed together to make a mask. **/
158     enum Trigger {
159         NoEventTrigger          =0x0000,    // must be 0
160 
161         PositiveToNegative      =0x0001,    // 1
162         NegativeToPositive      =0x0002,    // 2
163 
164         Falling                 =(PositiveToNegative), // 1
165         Rising                  =(NegativeToPositive), // 2
166         AnySignChange           =(PositiveToNegative|NegativeToPositive)    // 3
167     };
168 
169     /** This is useful for debugging; it translates an Event::Trigger or a mask
170     formed by a union of Event::Triggers, into a readable string. **/
171     SimTK_SimTKCOMMON_EXPORT static std::string eventTriggerString(Trigger);
172 
173 
174     /** Classify a before/after sign transition. Before and after must both
175     be -1,0, or 1 as returned by the SimTK::sign() function applied to
176     the trigger function value at the beginning and end of a step. **/
classifyTransition(int before,int after)177     static Trigger classifyTransition(int before, int after) {
178         if (before==after)
179             return NoEventTrigger;
180         if (before==0)
181             return NoEventTrigger; // Do not report transitions away from zero.
182         if (before==1)
183             return PositiveToNegative;
184         // before==-1
185         return NegativeToPositive;
186     }
187 
188     /** Given an observed transition, weed out ignorable ones using the supplied
189     mask. That is, the return will indicate NoEventTrigger unless the original
190     Trigger was present in the mask. **/
maskTransition(Trigger transition,Trigger mask)191     static Trigger maskTransition(Trigger transition, Trigger mask) {
192         // we're depending on NoEventTrigger==0
193         return Trigger(transition & mask);
194     }
195 
196 private:
197 };
198 
199 
200 /** This class is used to communicate between the System and an Integrator
201 regarding the properties of a particular event trigger function. Currently
202 these are:
203   - Whether to watch for rising sign transitions, falling, or both. [BOTH]
204   - Whether to watch for transitions to and from zero. [NO]
205   - The localization window in units of the System's timescale. [10%]
206     (That is then the "unit" window which is reduced by the accuracy setting.)
207 
208 The default values are shown in brackets above. **/
209 class SimTK_SimTKCOMMON_EXPORT EventTriggerInfo {
210 public:
211     EventTriggerInfo();
212     explicit EventTriggerInfo(EventId eventId);
213     ~EventTriggerInfo();
214     EventTriggerInfo(const EventTriggerInfo&);
215     EventTriggerInfo& operator=(const EventTriggerInfo&);
216 
217     EventId getEventId() const; // returns -1 if not set
218     bool shouldTriggerOnRisingSignTransition()  const; // default=true
219     bool shouldTriggerOnFallingSignTransition() const; // default=true
220     Real getRequiredLocalizationTimeWindow()    const; // default=0.1
221 
222     // These return the modified 'this', like assignment operators.
223     EventTriggerInfo& setEventId(EventId);
224     EventTriggerInfo& setTriggerOnRisingSignTransition(bool);
225     EventTriggerInfo& setTriggerOnFallingSignTransition(bool);
226     EventTriggerInfo& setRequiredLocalizationTimeWindow(Real);
227 
calcTransitionMask()228     Event::Trigger calcTransitionMask() const {
229         unsigned mask = 0;
230         if (shouldTriggerOnRisingSignTransition()) {
231             mask |= Event::NegativeToPositive;
232         }
233         if (shouldTriggerOnFallingSignTransition()) {
234             mask |= Event::PositiveToNegative;
235         }
236         return Event::Trigger(mask);
237     }
238 
calcTransitionToReport(Event::Trigger transitionSeen)239     Event::Trigger calcTransitionToReport
240        (Event::Trigger transitionSeen) const
241     {
242         // report -1 to 1 or 1 to -1 as appropriate
243         if (transitionSeen & Event::Rising)
244             return Event::NegativeToPositive;
245         if (transitionSeen & Event::Falling)
246             return Event::PositiveToNegative;
247         assert(!"impossible event transition situation");
248         return Event::NoEventTrigger;
249     }
250 
251 private:
252     class EventTriggerInfoRep;
253 
254     // opaque implementation for binary compatibility
255     EventTriggerInfoRep* rep;
256 
getRep()257     const EventTriggerInfoRep& getRep() const {assert(rep); return *rep;}
updRep()258     EventTriggerInfoRep&       updRep()       {assert(rep); return *rep;}
259 };
260 
261 
262 
263 
264 //==============================================================================
265 //              HANDLE EVENTS OPTIONS and HANDLE EVENTS RESULTS
266 //==============================================================================
267 /** Options for the handleEvent() method. Accuracy should be be set by the
268 caller, but if not the default is 1e-4. **/
269 class HandleEventsOptions {
270 public:
271     enum Option {
272         /** Take all defaults. **/
273         None            = 0x0000,
274         /** Normally failure to meet the accuracy requirements throws an
275         exception. This will force the handleEvent() method to quietly return bad
276         status instead. **/
277         DontThrow       = 0x0001,
278         /** Use the stricter infinity (max absolute value) norm rather than
279         the default RMS norm to determine when accuracy has been achieved. **/
280         UseInfinityNorm = 0x0002
281     };
282 
283 
HandleEventsOptions()284     HandleEventsOptions() {clear();}
HandleEventsOptions(Real accuracy)285     explicit HandleEventsOptions(Real accuracy)
286     {   clear(); setAccuracy(accuracy); }
HandleEventsOptions(Option opt)287     explicit HandleEventsOptions(Option opt)
288     {   clear(); setOption(opt); }
289 
290     /** Restore this object to its default-constructed state (no options
291     selected, default accuracy). A reference to the
292     newly-cleared object is returned. **/
clear()293     HandleEventsOptions& clear()
294     {   optionSet=0; setAccuracyDefaults(); return *this; }
295 
296     /** The norm of the constraint errors must be driven to below this value
297     for a project() to be considered successful. Normally an RMS norm is used
298     but you can override that to use an infinity norm instead. **/
setAccuracy(Real accuracy)299     HandleEventsOptions& setAccuracy(Real accuracy) {
300         assert(accuracy > 0);
301         requiredAccuracy = accuracy;
302         return *this;
303     }
304 
305     /** Remove a given option from the set. Nothing happens if the option wasn't
306     already set. **/
clearOption(Option opt)307     HandleEventsOptions& clearOption(Option opt)
308     {   optionSet &= ~(unsigned)opt; return *this; }
309     /** Select a given option from the set. Nothing happens if the option wasn't
310     already set. **/
setOption(Option opt)311     HandleEventsOptions& setOption  (Option opt)
312     {   optionSet |= (unsigned)opt; return *this; }
313 
314     /** Return the current value for the accuracy option. **/
getAccuracy()315     Real getAccuracy()       const {return requiredAccuracy;}
316 
isOptionSet(Option opt)317     bool isOptionSet(Option opt) const {return (optionSet&(unsigned)opt) != 0;}
318 
getDefaultAccuracy()319     static Real getDefaultAccuracy() {return Real(1e-4);}
320 
321     // Set operators: not, or, and, set difference
322     HandleEventsOptions& operator|=(const HandleEventsOptions& opts)
323     {   optionSet |= opts.optionSet; return *this; }
324     HandleEventsOptions& operator&=(const HandleEventsOptions& opts)
325     {   optionSet &= opts.optionSet; return *this; }
326     HandleEventsOptions& operator-=(const HandleEventsOptions& opts)
327     {   optionSet &= ~opts.optionSet; return *this; }
328 
329     HandleEventsOptions& operator|=(Option opt) {setOption(opt); return *this;}
330     HandleEventsOptions& operator-=(Option opt) {clearOption(opt); return *this;}
331 
332 private:
333     Real     requiredAccuracy;
334     unsigned optionSet;
335 
setAccuracyDefaults()336     void setAccuracyDefaults() {
337         requiredAccuracy = getDefaultAccuracy();
338     }
339 };
340 
341 /** Results returned by the handleEvent() method. In addition to return
342 status, this records the lowest stage in the state that was modified by
343 the handler. The caller can use this to determine how much reinitialization
344 is required before time stepping can proceed. **/
345 class HandleEventsResults {
346 public:
HandleEventsResults()347     HandleEventsResults() : m_lowestModifiedStage(Stage::Infinity) {clear();}
348 
349     enum Status {
350         /** This object has not been filled in yet and holds no results. **/
351         Invalid                 = -1,
352         /** The handleEvent() operation was successful and time stepping
353         may continue. **/
354         Succeeded               = 0,
355         /** The handleEvent() call was successful but the event requires
356         time stepping to terminate. An explanation may have been placed in
357         the message argument. **/
358         ShouldTerminate         = 1,
359         /** The handleEvent() call was unable to successfully handle the
360         event. This is likely to be a fatal error. A human-readable
361         explanation is in the message argument. **/
362         Failed                  = 2
363     };
364 
365     /** Restore this object to its default-constructed state, with the return
366     status set to Invalid. **/
clear()367     HandleEventsResults& clear() {
368         m_exitStatus = Invalid;
369         m_anyChangeMade = false;
370         m_lowestModifiedStage = Stage::Infinity; // i.e., nothing modified
371         m_message.clear();
372         return *this;
373     }
isValid()374     bool    isValid()           const {return m_exitStatus != Invalid;}
getExitStatus()375     Status  getExitStatus()     const {return m_exitStatus;}
376 
getAnyChangeMade()377     bool getAnyChangeMade()     const
378     {   assert(isValid()); return m_anyChangeMade; }
getLowestModifiedStage()379     Stage getLowestModifiedStage() const
380     {   assert(isValid()); return m_lowestModifiedStage; }
getMessage()381     const String& getMessage() const
382     {   assert(isValid()); return m_message; }
383 
setExitStatus(Status status)384     HandleEventsResults& setExitStatus(Status status)
385     {   m_exitStatus=status; return *this; }
setAnyChangeMade(bool changeMade)386     HandleEventsResults& setAnyChangeMade(bool changeMade)
387     {   m_anyChangeMade=changeMade; return *this; }
setLowestModifiedStage(Stage stage)388     HandleEventsResults& setLowestModifiedStage(Stage stage)
389     {   m_lowestModifiedStage=stage; return *this; }
setMessage(const String & message)390     HandleEventsResults& setMessage(const String& message)
391     {   m_message=message; return *this; }
392 private:
393     Status  m_exitStatus;
394     bool    m_anyChangeMade;
395     Stage   m_lowestModifiedStage;
396     String  m_message;
397 };
398 
399 } // namespace SimTK
400 
401 #endif // SimTK_SimTKCOMMON_EVENT_H_
402