Simbody
3.4 (development)
|
00001 #ifndef SimTK_SimTKCOMMON_EVENT_H_ 00002 #define SimTK_SimTKCOMMON_EVENT_H_ 00003 00004 /* -------------------------------------------------------------------------- * 00005 * Simbody(tm): SimTKcommon * 00006 * -------------------------------------------------------------------------- * 00007 * This is part of the SimTK biosimulation toolkit originating from * 00008 * Simbios, the NIH National Center for Physics-Based Simulation of * 00009 * Biological Structures at Stanford, funded under the NIH Roadmap for * 00010 * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody. * 00011 * * 00012 * Portions copyright (c) 2008-12 Stanford University and the Authors. * 00013 * Authors: Michael Sherman * 00014 * Contributors: * 00015 * * 00016 * Licensed under the Apache License, Version 2.0 (the "License"); you may * 00017 * not use this file except in compliance with the License. You may obtain a * 00018 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. * 00019 * * 00020 * Unless required by applicable law or agreed to in writing, software * 00021 * distributed under the License is distributed on an "AS IS" BASIS, * 00022 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 00023 * See the License for the specific language governing permissions and * 00024 * limitations under the License. * 00025 * -------------------------------------------------------------------------- */ 00026 00032 #include "SimTKcommon/basics.h" 00033 00034 namespace SimTK { 00035 00039 SimTK_DEFINE_UNIQUE_INDEX_TYPE(EventId); 00040 00047 SimTK_DEFINE_UNIQUE_INDEX_TYPE(SystemEventTriggerIndex); 00048 00057 SimTK_DEFINE_UNIQUE_INDEX_TYPE(SystemEventTriggerByStageIndex); 00058 00062 SimTK_DEFINE_UNIQUE_INDEX_TYPE(EventTriggerByStageIndex); 00063 00076 class Event { 00077 public: 00078 00123 class Cause { 00124 public: 00125 enum Num { 00126 Initialization = 1, 00127 Triggered = 2, 00128 Scheduled = 3, 00129 TimeAdvanced = 4, 00130 Signaled = 5, 00131 Termination = 6, 00132 Invalid = -1 00133 }; 00134 00135 Cause() : value(Invalid) {} 00136 Cause(Num n) : value(n) {} // implicit conversion 00137 operator Num() const {return value;} // implicit conversion 00138 Cause& operator=(Num n) {value=n; return *this;} 00139 00140 bool isValid() const {return Initialization<=value && value<=Termination;} 00141 00142 private: 00143 Num value; 00144 }; 00145 00148 SimTK_SimTKCOMMON_EXPORT static const char* getCauseName(Cause); 00149 00150 00155 enum Trigger { 00156 NoEventTrigger =0x0000, // must be 0 00157 00158 PositiveToNegative =0x0001, // 1 00159 NegativeToPositive =0x0002, // 2 00160 00161 Falling =(PositiveToNegative), // 1 00162 Rising =(NegativeToPositive), // 2 00163 AnySignChange =(PositiveToNegative|NegativeToPositive) // 3 00164 }; 00165 00168 SimTK_SimTKCOMMON_EXPORT static std::string eventTriggerString(Trigger); 00169 00170 00174 static Trigger classifyTransition(int before, int after) { 00175 if (before==after) 00176 return NoEventTrigger; 00177 if (before==0) 00178 return NoEventTrigger; // Do not report transitions away from zero. 00179 if (before==1) 00180 return PositiveToNegative; 00181 // before==-1 00182 return NegativeToPositive; 00183 } 00184 00188 static Trigger maskTransition(Trigger transition, Trigger mask) { 00189 // we're depending on NoEventTrigger==0 00190 return Trigger(transition & mask); 00191 } 00192 00193 private: 00194 }; 00195 00196 00205 class SimTK_SimTKCOMMON_EXPORT EventTriggerInfo { 00206 public: 00207 EventTriggerInfo(); 00208 explicit EventTriggerInfo(EventId eventId); 00209 ~EventTriggerInfo(); 00210 EventTriggerInfo(const EventTriggerInfo&); 00211 EventTriggerInfo& operator=(const EventTriggerInfo&); 00212 00213 EventId getEventId() const; // returns -1 if not set 00214 bool shouldTriggerOnRisingSignTransition() const; // default=true 00215 bool shouldTriggerOnFallingSignTransition() const; // default=true 00216 Real getRequiredLocalizationTimeWindow() const; // default=0.1 00217 00218 // These return the modified 'this', like assignment operators. 00219 EventTriggerInfo& setEventId(EventId); 00220 EventTriggerInfo& setTriggerOnRisingSignTransition(bool); 00221 EventTriggerInfo& setTriggerOnFallingSignTransition(bool); 00222 EventTriggerInfo& setRequiredLocalizationTimeWindow(Real); 00223 00224 Event::Trigger calcTransitionMask() const { 00225 unsigned mask = 0; 00226 if (shouldTriggerOnRisingSignTransition()) { 00227 mask |= Event::NegativeToPositive; 00228 } 00229 if (shouldTriggerOnFallingSignTransition()) { 00230 mask |= Event::PositiveToNegative; 00231 } 00232 return Event::Trigger(mask); 00233 } 00234 00235 Event::Trigger calcTransitionToReport 00236 (Event::Trigger transitionSeen) const 00237 { 00238 // report -1 to 1 or 1 to -1 as appropriate 00239 if (transitionSeen & Event::Rising) 00240 return Event::NegativeToPositive; 00241 if (transitionSeen & Event::Falling) 00242 return Event::PositiveToNegative; 00243 assert(!"impossible event transition situation"); 00244 return Event::NoEventTrigger; 00245 } 00246 00247 private: 00248 class EventTriggerInfoRep; 00249 00250 // opaque implementation for binary compatibility 00251 EventTriggerInfoRep* rep; 00252 00253 const EventTriggerInfoRep& getRep() const {assert(rep); return *rep;} 00254 EventTriggerInfoRep& updRep() {assert(rep); return *rep;} 00255 }; 00256 00257 00258 00259 00260 //============================================================================== 00261 // HANDLE EVENTS OPTIONS and HANDLE EVENTS RESULTS 00262 //============================================================================== 00265 class HandleEventsOptions { 00266 public: 00267 enum Option { 00269 None = 0x0000, 00273 DontThrow = 0x0001, 00276 UseInfinityNorm = 0x0002 00277 }; 00278 00279 00280 HandleEventsOptions() {clear();} 00281 explicit HandleEventsOptions(Real accuracy) 00282 { clear(); setAccuracy(accuracy); } 00283 explicit HandleEventsOptions(Option opt) 00284 { clear(); setOption(opt); } 00285 00289 HandleEventsOptions& clear() 00290 { optionSet=0; setAccuracyDefaults(); return *this; } 00291 00295 HandleEventsOptions& setAccuracy(Real accuracy) { 00296 assert(accuracy > 0); 00297 requiredAccuracy = accuracy; 00298 return *this; 00299 } 00300 00303 HandleEventsOptions& clearOption(Option opt) 00304 { optionSet &= ~(unsigned)opt; return *this; } 00307 HandleEventsOptions& setOption (Option opt) 00308 { optionSet |= (unsigned)opt; return *this; } 00309 00311 Real getAccuracy() const {return requiredAccuracy;} 00312 00313 bool isOptionSet(Option opt) const {return (optionSet&(unsigned)opt) != 0;} 00314 00315 static Real getDefaultAccuracy() {return Real(1e-4);} 00316 00317 // Set operators: not, or, and, set difference 00318 HandleEventsOptions& operator|=(const HandleEventsOptions& opts) 00319 { optionSet |= opts.optionSet; return *this; } 00320 HandleEventsOptions& operator&=(const HandleEventsOptions& opts) 00321 { optionSet &= opts.optionSet; return *this; } 00322 HandleEventsOptions& operator-=(const HandleEventsOptions& opts) 00323 { optionSet &= ~opts.optionSet; return *this; } 00324 00325 HandleEventsOptions& operator|=(Option opt) {setOption(opt); return *this;} 00326 HandleEventsOptions& operator-=(Option opt) {clearOption(opt); return *this;} 00327 00328 private: 00329 Real requiredAccuracy; 00330 unsigned optionSet; 00331 00332 void setAccuracyDefaults() { 00333 requiredAccuracy = getDefaultAccuracy(); 00334 } 00335 }; 00336 00341 class HandleEventsResults { 00342 public: 00343 HandleEventsResults() : m_lowestModifiedStage(Stage::Infinity) {clear();} 00344 00345 enum Status { 00347 Invalid = -1, 00350 Succeeded = 0, 00354 ShouldTerminate = 1, 00358 Failed = 2 00359 }; 00360 00363 HandleEventsResults& clear() { 00364 m_exitStatus = Invalid; 00365 m_anyChangeMade = false; 00366 m_lowestModifiedStage = Stage::Infinity; // i.e., nothing modified 00367 m_message.clear(); 00368 return *this; 00369 } 00370 bool isValid() const {return m_exitStatus != Invalid;} 00371 Status getExitStatus() const {return m_exitStatus;} 00372 00373 bool getAnyChangeMade() const 00374 { assert(isValid()); return m_anyChangeMade; } 00375 Stage getLowestModifiedStage() const 00376 { assert(isValid()); return m_lowestModifiedStage; } 00377 const String& getMessage() const 00378 { assert(isValid()); return m_message; } 00379 00380 HandleEventsResults& setExitStatus(Status status) 00381 { m_exitStatus=status; return *this; } 00382 HandleEventsResults& setAnyChangeMade(bool changeMade) 00383 { m_anyChangeMade=changeMade; return *this; } 00384 HandleEventsResults& setLowestModifiedStage(Stage stage) 00385 { m_lowestModifiedStage=stage; return *this; } 00386 HandleEventsResults& setMessage(const String& message) 00387 { m_message=message; return *this; } 00388 private: 00389 Status m_exitStatus; 00390 bool m_anyChangeMade; 00391 Stage m_lowestModifiedStage; 00392 String m_message; 00393 }; 00394 00395 } // namespace SimTK 00396 00397 #endif // SimTK_SimTKCOMMON_EVENT_H_