Simbody
|
00001 #ifndef SimTK_SimTKCOMMON_MEASURE_IMPLEMENTATION_H_ 00002 #define SimTK_SimTKCOMMON_MEASURE_IMPLEMENTATION_H_ 00003 00004 /* -------------------------------------------------------------------------- * 00005 * SimTK Core: SimTKcommon * 00006 * -------------------------------------------------------------------------- * 00007 * This is part of the SimTK Core 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. * 00011 * * 00012 * Portions copyright (c) 2008-9 Stanford University and the Authors. * 00013 * Authors: Michael Sherman * 00014 * Contributors: * 00015 * * 00016 * Permission is hereby granted, free of charge, to any person obtaining a * 00017 * copy of this software and associated documentation files (the "Software"), * 00018 * to deal in the Software without restriction, including without limitation * 00019 * the rights to use, copy, modify, merge, publish, distribute, sublicense, * 00020 * and/or sell copies of the Software, and to permit persons to whom the * 00021 * Software is furnished to do so, subject to the following conditions: * 00022 * * 00023 * The above copyright notice and this permission notice shall be included in * 00024 * all copies or substantial portions of the Software. * 00025 * * 00026 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 00027 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * 00028 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * 00029 * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 00030 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 00031 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * 00032 * USE OR OTHER DEALINGS IN THE SOFTWARE. * 00033 * -------------------------------------------------------------------------- */ 00034 00035 #include "SimTKcommon/basics.h" 00036 #include "SimTKcommon/Simmatrix.h" 00037 #include "SimTKcommon/internal/State.h" 00038 #include "SimTKcommon/internal/Measure.h" 00039 #include "SimTKcommon/internal/Subsystem.h" 00040 #include "SimTKcommon/internal/System.h" 00041 #include "SimTKcommon/internal/SubsystemGuts.h" 00042 00043 #include <cmath> 00044 00045 00046 namespace SimTK { 00047 00048 00050 // MEASURE::IMPLEMENTATION // 00052 00056 class SimTK_SimTKCOMMON_EXPORT AbstractMeasure::Implementation { 00057 protected: 00058 // This constructor is for use by concrete Measure::Implementations. Note 00059 // that this serves as a default constructor since the argument has a 00060 // default. 00061 explicit Implementation(const String& name="<NONAME>") 00062 : measureName(name), copyNumber(0), mySubsystem(0), refCount(0) {} 00063 00064 // Base class copy constructor copies the name, removes the Subsystem 00065 // and sets the reference count to zero. This gets used by the clone() 00066 // methods in the concrete classes. 00067 Implementation(const Implementation& src) 00068 : measureName(src.measureName), copyNumber(src.copyNumber+1), 00069 mySubsystem(0), refCount(0) {} 00070 00071 // Base class copy assignment operator copies the name, removes the 00072 // Subsystem, and sets the reference count to zero. This is probably 00073 // not used. 00074 Implementation& operator=(const Implementation& src) { 00075 if (&src != this) 00076 { measureName=src.measureName; copyNumber=src.copyNumber+1; 00077 refCount=0; mySubsystem=0; } 00078 return *this; 00079 } 00080 00081 // destructor is virtual 00082 00083 // Increment the reference count and return its new value. 00084 int incrRefCount() const {return ++refCount;} 00085 00086 // Decrement the reference count and return its new value. 00087 int decrRefCount() const {return --refCount;} 00088 00089 // Get the current value of the reference counter. 00090 int getRefCount() const {return refCount;} 00091 00092 const String& getName() const {return measureName;} 00093 int getCopyNumber() const {return copyNumber;} 00094 00095 // This is a deep copy of the concrete Implementation object, except the 00096 // Subsystem will have been removed. The reference count on the new object 00097 // will be zero; be sure to increment it if you put it in a handle. 00098 Implementation* clone() const {return cloneVirtual();} 00099 00100 // realizeTopology() is pure virtual below for Measure_<T> to supply. 00101 void realizeModel (State& s) const {realizeMeasureModelVirtual(s);} 00102 void realizeInstance (const State& s) const {realizeMeasureInstanceVirtual(s);} 00103 void realizeTime (const State& s) const {realizeMeasureTimeVirtual(s);} 00104 void realizePosition (const State& s) const {realizeMeasurePositionVirtual(s);} 00105 void realizeVelocity (const State& s) const {realizeMeasureVelocityVirtual(s);} 00106 void realizeDynamics (const State& s) const {realizeMeasureDynamicsVirtual(s);} 00107 void realizeAcceleration(const State& s) const {realizeMeasureAccelerationVirtual(s);} 00108 void realizeReport (const State& s) const {realizeMeasureReportVirtual(s);} 00109 00110 // This should be called at the start of a numerical integration study to 00111 // cause initial conditions to get set for any Measures that have integrated 00112 // state variables. 00113 void initialize(State& s) const {initializeVirtual(s);} 00114 00115 int getNumTimeDerivatives() const {return getNumTimeDerivativesVirtual();} 00116 00117 Stage getDependsOnStage(int derivOrder) const { 00118 SimTK_ERRCHK2(0 <= derivOrder && derivOrder <= getNumTimeDerivatives(), 00119 "Measure::getDependsOnStage()", 00120 "derivOrder %d was out of range; this Measure allows 0-%d.", 00121 derivOrder, getNumTimeDerivatives()); 00122 return getDependsOnStageVirtual(derivOrder); 00123 } 00124 00125 00126 void setSubsystem(Subsystem& sub, MeasureIndex mx) 00127 { assert(!mySubsystem && mx.isValid()); 00128 mySubsystem = ⊂ myIndex = mx; } 00129 00130 bool isInSubsystem() const {return mySubsystem != 0;} 00131 const Subsystem& getSubsystem() const {assert(mySubsystem); return *mySubsystem;} 00132 Subsystem& updSubsystem() {assert(mySubsystem); return *mySubsystem;} 00133 MeasureIndex getSubsystemMeasureIndex() const {assert(mySubsystem); return myIndex;} 00134 SubsystemIndex getSubsystemIndex() const 00135 { return getSubsystem().getMySubsystemIndex(); } 00136 00137 void invalidateTopologyCache() const 00138 { if (isInSubsystem()) getSubsystem().invalidateSubsystemTopologyCache(); } 00139 00140 Stage getStage(const State& s) const {return getSubsystem().getStage(s);} 00141 00142 // VIRTUALS // 00143 // Ordinals must retain the same meaning from release to release 00144 // to preserve binary compatibility. 00145 00146 /* 0*/virtual ~Implementation() {} 00147 /* 1*/virtual Implementation* cloneVirtual() const = 0; 00148 00149 /* 2*/virtual void realizeTopology(State&)const = 0; 00150 00151 /* 3*/virtual void realizeMeasureModelVirtual(State&) const {} 00152 /* 4*/virtual void realizeMeasureInstanceVirtual(const State&) const {} 00153 /* 5*/virtual void realizeMeasureTimeVirtual(const State&) const {} 00154 /* 6*/virtual void realizeMeasurePositionVirtual(const State&) const {} 00155 /* 7*/virtual void realizeMeasureVelocityVirtual(const State&) const {} 00156 /* 8*/virtual void realizeMeasureDynamicsVirtual(const State&) const {} 00157 /* 9*/virtual void realizeMeasureAccelerationVirtual(const State&) const {} 00158 /*10*/virtual void realizeMeasureReportVirtual(const State&) const {} 00159 00160 /*11*/virtual void initializeVirtual(State&) const {} 00161 /*12*/virtual int 00162 getNumTimeDerivativesVirtual() const {return 0;} 00163 /*13*/virtual Stage 00164 getDependsOnStageVirtual(int order) const = 0; 00165 00166 private: 00167 String measureName; 00168 int copyNumber; // bumped each time we do a deep copy 00169 00170 // These are set when this Measure is adopted by a Subsystem. 00171 Subsystem* mySubsystem; 00172 MeasureIndex myIndex; 00173 00174 // Measures have shallow copy semantics so they share the Implementation 00175 // objects, which are only deleted when the refCount goes to zero. 00176 mutable int refCount; 00177 00178 friend class AbstractMeasure; 00179 friend class Subsystem::Guts; 00180 friend class Subsystem::Guts::GutsRep; 00181 }; 00182 00184 // ABSTRACT MEASURE DEFINITIONS // 00186 00187 // These had to wait for Implementation to be defined. 00188 00189 inline AbstractMeasure:: 00190 AbstractMeasure(Implementation* g) 00191 : impl(g) 00192 { if (impl) impl->incrRefCount(); } 00193 00194 inline AbstractMeasure:: 00195 AbstractMeasure(Subsystem& sub, Implementation* g, const SetHandle&) 00196 : impl(g) { 00197 SimTK_ERRCHK(hasImpl(), "AbstractMeasure::ctor()", 00198 "An empty Measure handle can't be put in a Subsystem."); 00199 impl->incrRefCount(); 00200 sub.adoptMeasure(*this); 00201 } 00202 00203 // Shallow copy constructor. 00204 inline AbstractMeasure::AbstractMeasure(const AbstractMeasure& src) 00205 : impl(0) { 00206 if (src.impl) { 00207 impl = src.impl; 00208 impl->incrRefCount(); 00209 } 00210 } 00211 00212 // Shallow assignment. 00213 inline AbstractMeasure& AbstractMeasure:: 00214 shallowAssign(const AbstractMeasure& src) { 00215 if (impl != src.impl) { 00216 if (impl && impl->decrRefCount()==0) delete impl; 00217 impl = src.impl; 00218 impl->incrRefCount(); 00219 } 00220 return *this; 00221 } 00222 00223 // Note that even if the source and destination are currently pointing 00224 // to the same Implementation, we still have to make a new copy so that 00225 // afterwards the destination has its own, refcount==1 copy. 00226 inline AbstractMeasure& AbstractMeasure:: 00227 deepAssign(const AbstractMeasure& src) { 00228 if (&src != this) { 00229 if (impl && impl->decrRefCount()==0) delete impl; 00230 if (src.impl) { 00231 impl = src.impl->clone(); 00232 impl->incrRefCount(); 00233 } else 00234 impl = 0; 00235 } 00236 return *this; 00237 } 00238 00239 inline AbstractMeasure:: 00240 ~AbstractMeasure() 00241 { if (impl && impl->decrRefCount()==0) delete impl;} 00242 00243 inline bool AbstractMeasure:: 00244 isInSubsystem() const 00245 { return hasImpl() && getImpl().isInSubsystem(); } 00246 00247 inline const Subsystem& AbstractMeasure:: 00248 getSubsystem() const 00249 { return getImpl().getSubsystem(); } 00250 00251 inline MeasureIndex AbstractMeasure:: 00252 getSubsystemMeasureIndex() const 00253 { return getImpl().getSubsystemMeasureIndex();} 00254 00255 inline int AbstractMeasure:: 00256 getNumTimeDerivatives() const 00257 { return getImpl().getNumTimeDerivatives(); } 00258 00259 inline Stage AbstractMeasure:: 00260 getDependsOnStage(int derivOrder) const 00261 { return getImpl().getDependsOnStage(derivOrder); } 00262 00263 inline int AbstractMeasure:: 00264 getRefCount() const 00265 { return getImpl().getRefCount(); } 00266 00267 00269 // MEASURE_<T>::IMPLEMENTATION // 00271 00281 template <class T> 00282 class Measure_<T>::Implementation : public AbstractMeasure::Implementation { 00283 public: 00284 const T& getValue(const State& s, int derivOrder) const { 00285 SimTK_ERRCHK2(0 <= derivOrder && derivOrder <= getNumTimeDerivatives(), 00286 "Measure_<T>::getValue()", 00287 "derivOrder %d was out of range; this Measure allows 0-%d.", 00288 derivOrder, getNumTimeDerivatives()); 00289 00290 SimTK_ERRCHK2 00291 ( getDependsOnStage(derivOrder)==Stage::Empty 00292 || (isInSubsystem() 00293 && getStage(s)>=getDependsOnStage(derivOrder)) 00294 || (!isInSubsystem() 00295 && s.getSystemStage()>=getDependsOnStage(derivOrder)), 00296 "Measure_<T>::getValue()", 00297 "Expected State to have been realized to at least stage " 00298 "%s but stage was %s.", 00299 getDependsOnStage(derivOrder).getName().c_str(), 00300 (isInSubsystem() ? getStage(s) : s.getSystemStage()) 00301 .getName().c_str()); 00302 00303 if (derivOrder < getNumCacheEntries()) { 00304 if (!isCacheValueRealized(s,derivOrder)) { 00305 T& value = updCacheEntry(s,derivOrder); 00306 calcCachedValueVirtual(s, derivOrder, value); 00307 markCacheValueRealized(s,derivOrder); 00308 return value; 00309 } 00310 return getCacheEntry(s,derivOrder); 00311 } 00312 00313 // We can't handle it here -- punt to the concrete Measure 00314 // for higher order derivatives. 00315 return getUncachedValueVirtual(s,derivOrder); 00316 } 00317 00318 void setIsPresumedValidAtDependsOnStage(bool presume) 00319 { presumeValidAtDependsOnStage = presume; 00320 this->invalidateTopologyCache(); } 00321 00322 bool getIsPresumedValidAtDependsOnStage() const 00323 { return presumeValidAtDependsOnStage; } 00324 00325 protected: 00326 // numValues is one greater than the number of derivatives; i.e., there 00327 // is room for the value ("0th" derivative) also. The default is to 00328 // allocate just room for the value. 00329 explicit Implementation(int numValues=1) 00330 : presumeValidAtDependsOnStage(false), 00331 derivIx(numValues) {} 00332 00333 // Copy constructor copies the *number* of cache entries from the 00334 // source, but not the cache indices themselves as those must be 00335 // allocated uniquely for the copy. 00336 Implementation(const Implementation& source) 00337 : presumeValidAtDependsOnStage(source.presumeValidAtDependsOnStage), 00338 derivIx(source.derivIx.size()) {} 00339 00340 00341 // Satisfy the realizeTopology() pure virtual here now that we know 00342 // the data type T. Allocate lazy- or auto-validated- cache entries 00343 // depending on the setting of presumeValidAtDependsOnStage. 00344 void realizeTopology(State& s) const { 00345 Implementation* mutableThis = const_cast<Implementation*>(this); 00346 // Allocate cache entries. 00347 for (int i=0; i < getNumCacheEntries(); ++i) { 00348 const Stage dependsOn = getDependsOnStage(i); 00349 if (presumeValidAtDependsOnStage) { 00350 // Allocate auto-validated cache entries. 00351 mutableThis->derivIx[i] = 00352 this->getSubsystem().allocateCacheEntry 00353 (s, dependsOn, new Value<T>()); 00354 } else { 00355 // Allocate lazy cache entries. 00356 mutableThis->derivIx[i] = 00357 this->getSubsystem().allocateLazyCacheEntry 00358 (s, dependsOn, new Value<T>()); 00359 } 00360 } 00361 00362 // Call the concrete class virtual if any. 00363 realizeMeasureTopologyVirtual(s); 00364 } 00365 00366 int getNumCacheEntries() const {return (int)derivIx.size();} 00367 00368 const T& getCacheEntry(const State& s, int derivOrder) const { 00369 SimTK_ERRCHK2(0 <= derivOrder && derivOrder < getNumCacheEntries(), 00370 "Measure_<T>::Implementation::getCacheEntry()", 00371 "Derivative order %d is out of range; only %d cache entries" 00372 " were allocated.", derivOrder, getNumCacheEntries()); 00373 00374 return Value<T>::downcast( 00375 this->getSubsystem().getCacheEntry(s, derivIx[derivOrder])); 00376 } 00377 00378 T& updCacheEntry(const State& s, int derivOrder) const { 00379 SimTK_ERRCHK2(0 <= derivOrder && derivOrder < getNumCacheEntries(), 00380 "Measure_<T>::Implementation::updCacheEntry()", 00381 "Derivative order %d is out of range; only %d cache entries" 00382 " were allocated.", derivOrder, getNumCacheEntries()); 00383 00384 return Value<T>::updDowncast( 00385 this->getSubsystem().updCacheEntry(s, derivIx[derivOrder])); 00386 } 00387 00388 bool isCacheValueRealized(const State& s, int derivOrder) const { 00389 SimTK_ERRCHK2(0 <= derivOrder && derivOrder < getNumCacheEntries(), 00390 "Measure_<T>::Implementation::isCacheValueRealized()", 00391 "Derivative order %d is out of range; only %d cache entries" 00392 " were allocated.", derivOrder, getNumCacheEntries()); 00393 00394 return this->getSubsystem().isCacheValueRealized(s, derivIx[derivOrder]); 00395 } 00396 00397 void markCacheValueRealized(const State& s, int derivOrder) const { 00398 SimTK_ERRCHK2(0 <= derivOrder && derivOrder < getNumCacheEntries(), 00399 "Measure_<T>::Implementation::markCacheValueRealized()", 00400 "Derivative order %d is out of range; only %d cache entries" 00401 " were allocated.", derivOrder, getNumCacheEntries()); 00402 00403 this->getSubsystem().markCacheValueRealized(s, derivIx[derivOrder]); 00404 } 00405 00406 void markCacheValueNotRealized(const State& s, int derivOrder) const { 00407 SimTK_ERRCHK2(0 <= derivOrder && derivOrder < getNumCacheEntries(), 00408 "Measure_<T>::Implementation::markCacheValueNotRealized()", 00409 "Derivative order %d is out of range; only %d cache entries" 00410 " were allocated.", derivOrder, getNumCacheEntries()); 00411 00412 this->getSubsystem().markCacheValueNotRealized(s, derivIx[derivOrder]); 00413 } 00414 00415 // VIRTUALS // 00416 // Ordinals must retain the same meaning from release to release 00417 // to preserve binary compatibility. 00418 00419 /* 0*/virtual void realizeMeasureTopologyVirtual(State&) const {} 00420 /* 1*/virtual void 00421 calcCachedValueVirtual(const State&, int derivOrder, T& value) const 00422 { SimTK_ERRCHK1_ALWAYS(!"implemented", 00423 "Measure_<T>::Implementation::calcCachedValueVirtual()", 00424 "This method should have been overridden by the derived" 00425 " Measure but was not. It is needed to calculate the" 00426 " cached value for derivOrder=%d.", derivOrder); } 00427 00428 // This is only called when derivOrder >= the number of cache 00429 // entries we have, but still <= the number of derivatives the 00430 // Measure says it can deliver. 00431 /* 2*/virtual const T& 00432 getUncachedValueVirtual(const State&, int derivOrder) const 00433 { SimTK_ERRCHK1_ALWAYS(!"implemented", 00434 "Measure_<T>::Implementation::getUncachedValueVirtual()", 00435 "This method should have been overridden by the derived" 00436 " Measure but was not. It is needed to return the uncached" 00437 " value at derivOrder=%d.", derivOrder); 00438 return *reinterpret_cast<T*>(0); 00439 } 00440 00441 // STATICS // 00442 static const T& getValueZero() { 00443 static T zero(0); 00444 return zero; 00445 } 00446 00447 static const T& getValueOne() { 00448 static T one(1); 00449 return one; 00450 } 00451 00452 private: 00453 bool presumeValidAtDependsOnStage; 00454 Array_<CacheEntryIndex> derivIx; 00455 }; 00456 00457 00458 00460 // CONSTANT::IMPLEMENTATION // 00462 00463 template <class T> 00464 class Measure_<T>::Constant::Implementation 00465 : public Measure_<T>::Implementation 00466 { 00467 public: 00468 // We don't want the base class to allocate *any* cache entries. 00469 Implementation() : Measure_<T>::Implementation(0) {} 00470 explicit Implementation(const T& value) 00471 : Measure_<T>::Implementation(0), value(value) {} 00472 00473 // Allow this to be overridden by derived classes so they can 00474 // refuse to allow their values to change. 00475 virtual void setValue(const T& v) { 00476 value = v; 00477 this->invalidateTopologyCache(); 00478 } 00479 00480 // Implementations of virtual methods. 00481 // Measure_<T> virtuals: 00482 // No cached values. 00483 00484 const T& getUncachedValueVirtual(const State&, int derivOrder) const 00485 { return derivOrder>0 ? this->getValueZero() : value; } 00486 00487 // AbstractMeasure virtuals: 00488 Implementation* cloneVirtual() const {return new Implementation(*this);} 00489 Stage getDependsOnStageVirtual(int derivOrder) const 00490 { return derivOrder>0 ? Stage::Empty : Stage::Topology; } 00491 int getNumTimeDerivativesVirtual() const 00492 { return std::numeric_limits<int>::max(); } 00493 00494 private: 00495 T value; 00496 }; 00497 00499 // ZERO::IMPLEMENTATION // 00501 00502 template <class T> 00503 class Measure_<T>::Zero::Implementation 00504 : public Constant::Implementation 00505 { 00506 public: 00507 Implementation() : Constant::Implementation(T(0)) {} 00508 00509 // VIRTUALS 00510 // From Constant::Implementation: 00511 void setValue(const T&) { 00512 SimTK_ERRCHK_ALWAYS(!"invalid", "Measure_<T>::Zero::setValue()", 00513 "You can't change the value of Zero!"); 00514 } 00515 00516 // From AbstractMeasure: 00517 Implementation* cloneVirtual() const {return new Implementation(*this);} 00518 Stage getDependsOnStageVirtual(int) const 00519 { return Stage::Empty; } 00520 }; 00521 00523 // ONE::IMPLEMENTATION // 00525 00526 00527 template <class T> 00528 class Measure_<T>::One::Implementation 00529 : public Constant::Implementation 00530 { 00531 public: 00532 Implementation() : Constant::Implementation(T(1)) {} 00533 00534 // VIRTUALS 00535 // From Constant::Implementation: 00536 void setValue(const T&) { 00537 SimTK_ERRCHK_ALWAYS(!"invalid", "Measure_<T>::One::setValue()", 00538 "You can't change the value of One!"); 00539 } 00540 // From AbstractMeasure: 00541 Implementation* cloneVirtual() const {return new Implementation(*this);} 00542 Stage getDependsOnStageVirtual(int) const 00543 { return Stage::Empty; } 00544 }; 00545 00546 00548 // TIME::IMPLEMENTATION // 00550 00551 template <class T> 00552 class Measure_<T>::Time::Implementation {}; 00553 00554 template <> 00555 class Measure_<Real>::Time::Implementation 00556 : public Measure_<Real>::Implementation 00557 { 00558 public: 00559 // We don't want the base class to allocate *any* cache entries. 00560 Implementation() : Measure_<Real>::Implementation(0) {} 00561 00562 // Implementations of virtual methods. 00563 // Measure_<Real> virtuals: 00564 // No cached values. 00565 00566 const Real& getUncachedValueVirtual(const State& s, int derivOrder) const 00567 { return derivOrder==0 ? s.getTime() 00568 : (derivOrder==1 ? this->getValueOne() 00569 : this->getValueZero()); } 00570 00571 // AbstractMeasure virtuals: 00572 Implementation* cloneVirtual() const {return new Implementation(*this);} 00573 Stage getDependsOnStageVirtual(int derivOrder) const 00574 { return derivOrder>0 ? Stage::Empty : Stage::Time; } 00575 00576 // Value is t, 1st derivative is 1, the rest are 0. 00577 int getNumTimeDerivativesVirtual() const 00578 { return std::numeric_limits<int>::max(); } 00579 }; 00580 00582 // VARIABLE::IMPLEMENTATION // 00584 00585 template <class T> 00586 class Measure_<T>::Variable::Implementation 00587 : public Measure_<T>::Implementation 00588 { 00589 public: 00590 // We don't want the base class to allocate *any* cache entries; 00591 // we'll use the variable as its own value and zeroes for all 00592 // the derivatives. 00593 Implementation() 00594 : Measure_<T>::Implementation(0), 00595 invalidatedStage(Stage::Empty), defaultValue() {} 00596 00597 Implementation(Stage invalidated, const T& defaultValue) 00598 : Measure_<T>::Implementation(0), 00599 invalidatedStage(invalidated), defaultValue(defaultValue) {} 00600 00601 // Copy constructor should not copy the variable. 00602 Implementation(const Implementation& source) 00603 : Measure_<T>::Implementation(0), 00604 invalidatedStage(source.invalidatedStage), 00605 defaultValue(source.defaultValue) {} 00606 00607 void setDefaultValue(const T& v) { 00608 defaultValue = v; 00609 this->invalidateTopologyCache(); 00610 } 00611 00612 void setInvalidatedStage(Stage invalidates) { 00613 invalidatedStage = invalidates; 00614 this->invalidateTopologyCache(); 00615 } 00616 00617 const T& getDefaultValue() const {return defaultValue;} 00618 Stage getInvalidatedStage() const {return invalidatedStage;} 00619 00620 void setValue(State& state, const T& value) const 00621 { updVarValue(state) = value; } 00622 00623 // Implementations of virtual methods. 00624 Implementation* cloneVirtual() const {return new Implementation(*this);} 00625 00626 int getNumTimeDerivativesVirtual() const 00627 { return std::numeric_limits<int>::max(); } 00628 00629 // Discrete variable is available after Model stage; but all its 00630 // derivatives are zero so are always available. 00631 Stage getDependsOnStageVirtual(int derivOrder) const 00632 { return derivOrder>0 ? Stage::Empty : Stage::Model;} 00633 00634 const T& getUncachedValueVirtual(const State& s, int derivOrder) const 00635 { return derivOrder>0 ? this->getValueZero() : getVarValue(s); } 00636 00637 // No cached values. 00638 00639 void realizeMeasureTopologyVirtual(State& s) const { 00640 discreteVarIndex = this->getSubsystem().allocateDiscreteVariable 00641 (s, invalidatedStage, new Value<T>(defaultValue)); 00642 } 00643 private: 00644 const T& getVarValue(const State& s) const { 00645 assert(discreteVarIndex.isValid()); 00646 return Value<T>::downcast( 00647 this->getSubsystem().getDiscreteVariable(s, discreteVarIndex)); 00648 } 00649 T& updVarValue(State& s) const { 00650 assert(discreteVarIndex.isValid()); 00651 return Value<T>::downcast( 00652 this->getSubsystem().updDiscreteVariable(s, discreteVarIndex)); 00653 } 00654 00655 // TOPOLOGY STATE 00656 Stage invalidatedStage; // TODO this shouldn't be needed 00657 T defaultValue; 00658 00659 // TOPOLOGY CACHE 00660 mutable DiscreteVariableIndex discreteVarIndex; 00661 }; 00662 00663 00665 // RESULT::IMPLEMENTATION // 00667 00668 template <class T> 00669 class Measure_<T>::Result::Implementation 00670 : public Measure_<T>::Implementation 00671 { 00672 public: 00673 // We want the base class to allocate a single cache entry of type T. 00674 Implementation() 00675 : Measure_<T>::Implementation(1), 00676 dependsOnStage(Stage::Topology), invalidatedStage(Stage::Infinity) {} 00677 00678 Implementation(Stage dependsOn, Stage invalidated) 00679 : Measure_<T>::Implementation(1), 00680 dependsOnStage(dependsOn==Stage::Empty ? Stage::Topology : dependsOn), 00681 invalidatedStage(invalidated) 00682 { SimTK_ERRCHK2_ALWAYS(invalidated > dependsOn,"Measure::Result::ctor()", 00683 "Got invalidated stage %s and dependsOn stage %s which is illegal " 00684 "because the invalidated stage must be later than dependsOn.", 00685 invalidated.getName().c_str(), dependsOn.getName().c_str()); 00686 } 00687 00688 // Copy constructor will not copy the cache entry index. 00689 Implementation(const Implementation& source) 00690 : Measure_<T>::Implementation(source), 00691 dependsOnStage(source.dependsOnStage), 00692 invalidatedStage(source.invalidatedStage) {} 00693 00694 void setDependsOnStage(Stage dependsOn) { 00695 if (dependsOn == Stage::Empty) dependsOn = Stage::Topology; 00696 SimTK_ERRCHK2_ALWAYS(dependsOn < getInvalidatedStage(), 00697 "Measure::Result::setDependsOnStage()", 00698 "The provided dependsOn stage %s is illegal because it is not " 00699 "less than the current invalidated stage %s. Change the " 00700 "invalidated stage first with setInvalidatedStage().", 00701 dependsOn.getName().c_str(), 00702 getInvalidatedStage().getName().c_str()); 00703 00704 dependsOnStage = dependsOn; 00705 this->invalidateTopologyCache(); 00706 } 00707 00708 void setInvalidatedStage(Stage invalidated) { 00709 SimTK_ERRCHK2_ALWAYS(invalidated > getDependsOnStage(), 00710 "Measure::Result::setInvalidatedStage()", 00711 "The provided invalidated stage %s is illegal because it is not " 00712 "greater than the current dependsOn stage %s. Change the " 00713 "dependsOn stage first with setDependsOnStage().", 00714 invalidated.getName().c_str(), 00715 getDependsOnStage().getName().c_str()); 00716 00717 invalidatedStage = invalidated; 00718 this->invalidateTopologyCache(); 00719 } 00720 00721 00722 Stage getDependsOnStage() const {return dependsOnStage;} 00723 Stage getInvalidatedStage() const {return invalidatedStage;} 00724 00725 00726 void markAsValid(const State& state) const 00727 { const Stage subsystemStage = this->getSubsystem().getStage(state); 00728 SimTK_ERRCHK3_ALWAYS(subsystemStage >= getDependsOnStage().prev(), 00729 "Measure::Result::markAsValid()", 00730 "This Result Measure cannot be marked valid in a State where this " 00731 "measure's Subsystem has been realized only to stage %s, because " 00732 "its value was declared to depend on stage %s. To mark it valid, " 00733 "we require that the State have been realized at least to the " 00734 "previous stage (%s in this case); that is, you must at least be " 00735 "*working on* the dependsOn stage in order to claim this result is " 00736 "available.", 00737 subsystemStage.getName().c_str(), 00738 getDependsOnStage().getName().c_str(), 00739 getDependsOnStage().prev().getName().c_str()); 00740 this->markCacheValueRealized(state, 0); } 00741 00742 bool isValid(const State& state) const 00743 { return this->isCacheValueRealized(state, 0); } 00744 00745 void markAsNotValid(const State& state) const 00746 { this->markCacheValueNotRealized(state, 0); 00747 state.invalidateAllCacheAtOrAbove(invalidatedStage); } 00748 00749 T& updValue(const State& state) const 00750 { markAsNotValid(state); return this->updCacheEntry(state, 0); } 00751 00752 00753 // Implementations of virtual methods. 00754 virtual Implementation* cloneVirtual() const 00755 { return new Implementation(*this); } 00756 00757 virtual int getNumTimeDerivativesVirtual() const {return 0;} 00758 00759 // Discrete variable is available after Model stage; but all its 00760 // derivatives are zero so are always available. 00761 virtual Stage getDependsOnStageVirtual(int derivOrder) const 00762 { return derivOrder>0 ? Stage::Empty : dependsOnStage;} 00763 00764 virtual void 00765 calcCachedValueVirtual(const State&, int derivOrder, T& value) const 00766 { SimTK_ERRCHK_ALWAYS(!"calcCachedValueVirtual() implemented", 00767 "Measure_<T>::Result::getValue()", 00768 "Measure_<T>::Result::getValue() was called when the value was not " 00769 "yet valid. For most Measure types, this would have initiated " 00770 "computation of the value, but Result measures must have their values " 00771 "calculated and set externally, and then marked valid."); } 00772 00773 private: 00774 // TOPOLOGY STATE 00775 Stage dependsOnStage; 00776 Stage invalidatedStage; 00777 }; 00778 00779 00781 // SINUSOID::IMPLEMENTATION // 00783 00784 template <class T> 00785 class Measure_<T>::Sinusoid::Implementation 00786 : public Measure_<T>::Implementation 00787 { 00788 static const int NumDerivs = 3; 00789 public: 00790 Implementation() 00791 : Measure_<T>::Implementation(NumDerivs+1), 00792 a(CNT<T>::getNaN()), w(CNT<T>::getNaN()), p(CNT<T>::getNaN()) {} 00793 00794 Implementation(const T& amplitude, 00795 const T& frequency, 00796 const T& phase=T(0)) 00797 : Measure_<T>::Implementation(NumDerivs+1), 00798 a(amplitude), w(frequency), p(phase) {} 00799 00800 // Default copy constructor is fine. 00801 00802 // Implementations of virtual methods. 00803 Implementation* cloneVirtual() const {return new Implementation(*this);} 00804 00805 int getNumTimeDerivativesVirtual() const {return NumDerivs;} 00806 00807 Stage getDependsOnStageVirtual(int order) const 00808 { return Stage::Time; } 00809 00810 void calcCachedValueVirtual(const State& s, int derivOrder, T& value) const { 00811 // We need to allow the compiler to select std::sin or SimTK::sin 00812 // based on the argument type. 00813 using std::sin; using std::cos; 00814 00815 assert(NumDerivs == 3); 00816 const Real t = s.getTime(); 00817 const T arg = w*t + p; 00818 00819 switch (derivOrder) { 00820 case 0: value = a*sin(arg); break; 00821 case 1: value = w*a*cos(arg); break; 00822 case 2: value = -w*w*a*sin(arg); break; 00823 case 3: value = -w*w*w*a*cos(arg); break; 00824 default: SimTK_ASSERT1_ALWAYS(!"out of range", 00825 "Measure::Sinusoid::Implementation::calcCachedValueVirtual():" 00826 " derivOrder %d is out of range 0-3.", derivOrder); 00827 } 00828 } 00829 00830 // There are no uncached values. 00831 00832 private: 00833 // TOPOLOGY STATE 00834 T a, w, p; 00835 00836 // TOPOLOGY CACHE 00837 // nothing 00838 }; 00839 00841 // PLUS::IMPLEMENTATION // 00843 00844 template <class T> 00845 class Measure_<T>::Plus::Implementation 00846 : public Measure_<T>::Implementation 00847 { 00848 public: 00849 // TODO: Currently allocates just one cache entry. 00850 // left and right will be empty handles. 00851 Implementation() {} 00852 00853 Implementation(const Measure_<T>& left, 00854 const Measure_<T>& right) 00855 : left(left), right(right) {} 00856 00857 // Default copy constructor gives us a new Implementation object, 00858 // but with references to the *same* operand measures. 00859 00860 // Implementations of virtual methods. 00861 00862 // This uses the default copy constructor. 00863 Implementation* cloneVirtual() const 00864 { return new Implementation(*this); } 00865 00866 // TODO: Let this be settable up to the min number of derivatives 00867 // provided by the arguments. 00868 int getNumTimeDerivativesVirtual() const {return 0;} 00869 //{ return std::min(left.getNumTimeDerivatives(), 00870 // right.getNumTimeDerivatives()); } 00871 00872 Stage getDependsOnStageVirtual(int order) const 00873 { return Stage(std::max(left.getDependsOnStage(order), 00874 right.getDependsOnStage(order))); } 00875 00876 00877 void calcCachedValueVirtual(const State& s, int derivOrder, T& value) const { 00878 value = left.getValue(s,derivOrder) + right.getValue(s,derivOrder); 00879 } 00880 00881 // There are no uncached values. 00882 00883 private: 00884 // TOPOLOGY STATE 00885 const Measure_<T> left; 00886 const Measure_<T> right; 00887 00888 // TOPOLOGY CACHE 00889 // nothing 00890 }; 00891 00893 // MINUS::IMPLEMENTATION // 00895 00896 template <class T> 00897 class Measure_<T>::Minus::Implementation 00898 : public Measure_<T>::Implementation 00899 { 00900 public: 00901 // TODO: Currently allocates just one cache entry. 00902 // left and right will be empty handles. 00903 Implementation() {} 00904 00905 Implementation(const Measure_<T>& left, 00906 const Measure_<T>& right) 00907 : left(left), right(right) {} 00908 00909 // Default copy constructor gives us a new Implementation object, 00910 // but with references to the *same* operand measures. 00911 00912 // Implementations of virtual methods. 00913 00914 // This uses the default copy constructor. 00915 Implementation* cloneVirtual() const 00916 { return new Implementation(*this); } 00917 00918 // TODO: Let this be settable up to the min number of derivatives 00919 // provided by the arguments. 00920 int getNumTimeDerivativesVirtual() const {return 0;} 00921 //{ return std::min(left.getNumTimeDerivatives(), 00922 // right.getNumTimeDerivatives()); } 00923 00924 Stage getDependsOnStageVirtual(int order) const 00925 { return Stage(std::max(left.getDependsOnStage(order), 00926 right.getDependsOnStage(order))); } 00927 00928 00929 void calcCachedValueVirtual(const State& s, int derivOrder, T& value) const { 00930 value = left.getValue(s,derivOrder) - right.getValue(s,derivOrder); 00931 } 00932 00933 // There are no uncached values. 00934 00935 private: 00936 // TOPOLOGY STATE 00937 const Measure_<T> left; 00938 const Measure_<T> right; 00939 00940 // TOPOLOGY CACHE 00941 // nothing 00942 }; 00943 00944 00946 // SCALE::IMPLEMENTATION // 00948 00949 template <class T> 00950 class Measure_<T>::Scale::Implementation 00951 : public Measure_<T>::Implementation 00952 { 00953 public: 00954 // TODO: Currently allocates just one cache entry. 00955 // scale will be uninitialized, operand will be empty handle. 00956 Implementation() : factor(NaN) {} 00957 00958 Implementation(Real factor, const Measure_<T>& operand) 00959 : factor(factor), operand(operand) {} 00960 00961 // Default copy constructor gives us a new Implementation object, 00962 // but with references to the *same* operand measure. 00963 00964 void setScaleFactor(Real sf) { 00965 factor = sf; 00966 this->invalidateTopologyCache(); 00967 } 00968 00969 // Implementations of virtual methods. 00970 00971 // This uses the default copy constructor. 00972 Implementation* cloneVirtual() const 00973 { return new Implementation(*this); } 00974 00975 // TODO: Let this be settable up to the min number of derivatives 00976 // provided by the arguments. 00977 int getNumTimeDerivativesVirtual() const {return 0;} 00978 //{ return std::min(left.getNumTimeDerivatives(), 00979 // right.getNumTimeDerivatives()); } 00980 00981 Stage getDependsOnStageVirtual(int order) const 00982 { return operand.getDependsOnStage(order); } 00983 00984 00985 void calcCachedValueVirtual(const State& s, int derivOrder, T& value) const { 00986 value = factor * operand.getValue(s,derivOrder); 00987 } 00988 00989 // There are no uncached values. 00990 00991 private: 00992 // TOPOLOGY STATE 00993 const Real factor; 00994 const Measure_<T> operand; 00995 00996 // TOPOLOGY CACHE 00997 // nothing 00998 }; 00999 01001 // INTEGRATE::IMPLEMENTATION // 01003 01004 template <class T> 01005 class Measure_<T>::Integrate::Implementation 01006 : public Measure_<T>::Implementation { 01007 public: 01008 // We don't want any cache entries allocated -- we'll use the 01009 // State z variable as its own value and let the derivative 01010 // Measure supply its value. 01011 01012 // The derivative and initialConditions Measures will be 01013 // empty handles if this is default constructed. 01014 Implementation() : Measure_<T>::Implementation(0) {} 01015 01016 // Here we're shallow-copying the Measure handles so we'll 01017 // be referring to the original Measures. 01018 Implementation(const Measure_<T>& deriv, const Measure_<T>& ic) 01019 : Measure_<T>::Implementation(0), 01020 derivMeasure(deriv), icMeasure(ic) {} 01021 01022 // Copy constructor shallow-copies the referenced measures, but 01023 // we don't want to share our state variable. 01024 Implementation(const Implementation& source) 01025 : Measure_<T>::Implementation(0), 01026 derivMeasure(source.derivMeasure), icMeasure(source.icMeasure) {} 01027 01028 void setValue(State& s, const T& value) const 01029 { assert(zIndex >= 0); 01030 this->getSubsystem().updZ(s)[zIndex] = value; } 01031 01032 const Measure_<T>& getDerivativeMeasure() const 01033 { SimTK_ERRCHK(!derivMeasure.isEmptyHandle(), 01034 "Measure_<T>::Integrate::getDerivativeMeasure()", 01035 "No derivative measure is available for this integrated measure."); 01036 return derivMeasure; } 01037 01038 const Measure_<T>& getInitialConditionMeasure() const 01039 { SimTK_ERRCHK(!icMeasure.isEmptyHandle(), 01040 "Measure_<T>::Integrate::getInitialConditionMeasure()", 01041 "No initial condition measure is available for this " 01042 "integrated measure."); 01043 return icMeasure; } 01044 01045 void setDerivativeMeasure(const Measure_<T>& d) 01046 { derivMeasure = d; this->invalidateTopologyCache(); } 01047 void setInitialConditionMeasure(const Measure_<T>& ic) 01048 { icMeasure = ic; this->invalidateTopologyCache(); } 01049 01050 // Implementations of virtuals. 01051 01052 // This uses the copy constructor defined above. 01053 Implementation* cloneVirtual() const 01054 { return new Implementation(*this); } 01055 01056 int getNumTimeDerivativesVirtual() const {return 1;} 01057 01058 // There are no cached values. 01059 01060 const T& getUncachedValueVirtual(const State& s, int derivOrder) const 01061 { if (derivOrder>0) 01062 return getDerivativeMeasure().getValue(s); 01063 else { 01064 assert(zIndex.isValid()); 01065 return this->getSubsystem().getZ(s)[zIndex]; 01066 } 01067 } 01068 Stage getDependsOnStageVirtual(int derivOrder) const 01069 { return derivOrder>0 ? getDerivativeMeasure().getDependsOnStage(0) 01070 : Stage::Time; } 01071 01072 void initializeVirtual(State& s) const { 01073 assert(zIndex.isValid()); 01074 Real& z = this->getSubsystem().updZ(s)[zIndex]; 01075 if (!icMeasure.isEmptyHandle()) 01076 z = icMeasure.getValue(s); 01077 else z = 0; 01078 } 01079 01080 void realizeMeasureTopologyVirtual(State& s) const { 01081 static const Vector zero(1, Real(0)); 01082 zIndex = this->getSubsystem().allocateZ(s, zero); 01083 } 01084 01085 void realizeMeasureAccelerationVirtual(const State& s) const { 01086 assert(zIndex.isValid()); 01087 Real& zdot = this->getSubsystem().updZDot(s)[zIndex]; 01088 if (!derivMeasure.isEmptyHandle()) 01089 zdot = derivMeasure.getValue(s); 01090 else zdot = 0; 01091 } 01092 01093 private: 01094 // TOPOLOGY STATE 01095 const Measure_<T> derivMeasure; // just handles 01096 const Measure_<T> icMeasure; 01097 01098 // TOPOLOGY CACHE 01099 mutable ZIndex zIndex; 01100 }; 01101 01103 // DIFFERENTIATE::IMPLEMENTATION // 01105 01106 // This helper class is the contents of the discrete state variable and corresponding 01107 // cache entry maintained by this measure. The variable is auto-update, 01108 // meaning the value of the cache entry replaces the state variable at the 01109 // start of each step. 01110 // TODO: This was a local class in Measure_<T>::Differentiate::Implementation 01111 // but VC++ 8 (2005) failed to properly instantiate the templatized operator<<() 01112 // in that case; doing it this way is a workaround. 01113 template <class T> 01114 class Measure_Differentiate_Result { 01115 public: 01116 Measure_Differentiate_Result() : derivIsGood(false) {} 01117 T operand; // previous value of operand 01118 T operandDot; // previous value of derivative 01119 bool derivIsGood; // do we think the deriv is a good one? 01120 }; 01121 01122 01123 // Dummy for Value<Measure_Differentiate_Result>. 01124 template <class T> inline std::ostream& 01125 operator<<(std::ostream& o, 01126 const Measure_Differentiate_Result<T>&) 01127 { assert(!"not implemented"); return o; } 01128 01129 template <class T> 01130 class Measure_<T>::Differentiate::Implementation 01131 : public Measure_<T>::Implementation 01132 { 01133 typedef Measure_Differentiate_Result<T> Result; 01134 public: 01135 // Don't allocate any cache entries in the base class. 01136 Implementation() : Measure_<T>::Implementation(0) {} 01137 01138 Implementation(const Measure_<T>& operand) 01139 : Measure_<T>::Implementation(0), 01140 operand(operand), forceUseApprox(false), isApproxInUse(false) {} 01141 01142 // Default copy constructor gives us a new Implementation object, 01143 // but with reference to the *same* operand measure. 01144 01145 void setForceUseApproximation(bool mustApproximate) { 01146 forceUseApprox = mustApproximate; 01147 this->invalidateTopologyCache(); 01148 } 01149 01150 void setOperandMeasure(const Measure_<T>& operand) { 01151 this->operand = operand; 01152 this->invalidateTopologyCache(); 01153 } 01154 01155 bool getForceUseApproximation() const {return forceUseApprox;} 01156 bool isUsingApproximation() const {return isApproxInUse;} 01157 const Measure_<T>& getOperandMeasure() const {return operand;} 01158 01159 // Implementations of virtual methods. 01160 01161 // This uses the default copy constructor. 01162 Implementation* cloneVirtual() const 01163 { return new Implementation(*this); } 01164 01165 // This has one fewer than the operand. 01166 int getNumTimeDerivativesVirtual() const 01167 { if (!isApproxInUse) return operand.getNumTimeDerivatives()-1; 01168 else return 0; } 01169 01170 Stage getDependsOnStageVirtual(int order) const 01171 { if (!isApproxInUse) return operand.getDependsOnStage(order+1); 01172 else return operand.getDependsOnStage(order); } 01173 01174 01175 // We're not using the Measure_<T> base class cache services, but 01176 // we do have one of our own. It looks uncached from the base class 01177 // point of view which is why we're implementing it here. 01178 const T& getUncachedValueVirtual(const State& s, int derivOrder) const 01179 { if (!isApproxInUse) 01180 return operand.getValue(s, derivOrder+1); 01181 01182 ensureDerivativeIsRealized(s); 01183 const Subsystem& subsys = this->getSubsystem(); 01184 const Result& result = Value<Result>::downcast 01185 (subsys.getDiscreteVarUpdateValue(s,resultIx)); 01186 return result.operandDot; // has a value but might not be a good one 01187 } 01188 01189 void initializeVirtual(State& s) const { 01190 if (!isApproxInUse) return; 01191 01192 assert(resultIx.isValid()); 01193 const Subsystem& subsys = this->getSubsystem(); 01194 Result& result = Value<Result>::updDowncast 01195 (subsys.updDiscreteVariable(s,resultIx)); 01196 result.operand = operand.getValue(s); 01197 result.operandDot = this->getValueZero(); 01198 result.derivIsGood = false; 01199 } 01200 01201 void realizeMeasureTopologyVirtual(State& s) const { 01202 isApproxInUse = (forceUseApprox || operand.getNumTimeDerivatives()==0); 01203 if (!isApproxInUse) 01204 return; 01205 01206 resultIx = this->getSubsystem() 01207 .allocateAutoUpdateDiscreteVariable(s, operand.getDependsOnStage(0), 01208 new Value<Result>(), operand.getDependsOnStage(0)); 01209 } 01210 01211 void ensureDerivativeIsRealized(const State& s) const { 01212 assert(resultIx.isValid()); 01213 const Subsystem& subsys = this->getSubsystem(); 01214 if (subsys.isDiscreteVarUpdateValueRealized(s,resultIx)) 01215 return; 01216 01217 const Real t0 = subsys.getDiscreteVarLastUpdateTime(s,resultIx); 01218 const Result& prevResult = Value<Result>::downcast 01219 (subsys.getDiscreteVariable(s,resultIx)); 01220 const T& f0 = prevResult.operand; 01221 const T& fdot0 = prevResult.operandDot; // may be invalid 01222 const bool good0 = prevResult.derivIsGood; 01223 01224 const Real t = s.getTime(); 01225 Result& result = Value<Result>::updDowncast 01226 (subsys.updDiscreteVarUpdateValue(s,resultIx)); 01227 T& f = result.operand; // renaming 01228 T& fdot = result.operandDot; 01229 bool& good = result.derivIsGood; 01230 01231 f = operand.getValue(s); 01232 good = false; 01233 if (!isFinite(t0)) 01234 fdot = this->getValueZero(); 01235 else if (t == t0) { 01236 fdot = fdot0; 01237 good = good0; 01238 } else { 01239 fdot = (f-f0)/(t-t0); // 1st order 01240 if (good0) 01241 fdot = Real(2)*fdot - fdot0; // now 2nd order 01242 good = true; // either 1st or 2nd order estimate 01243 } 01244 subsys.markDiscreteVarUpdateValueRealized(s,resultIx); 01245 } 01246 private: 01247 // TOPOLOGY STATE 01248 Measure_<T> operand; 01249 bool forceUseApprox; 01250 01251 // TOPOLOGY CACHE 01252 mutable bool isApproxInUse; 01253 mutable DiscreteVariableIndex resultIx; // auto-update 01254 }; 01255 01256 01257 } // namespace SimTK 01258 01259 01260 01261 01262 #endif // SimTK_SimTKCOMMON_MEASURE_IMPLEMENTATION_H_