1 #ifndef SimTK_SimTKCOMMON_MEASURE_IMPLEMENTATION_H_
2 #define SimTK_SimTKCOMMON_MEASURE_IMPLEMENTATION_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-14 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 #include "SimTKcommon/basics.h"
28 #include "SimTKcommon/Simmatrix.h"
29 #include "SimTKcommon/internal/State.h"
30 #include "SimTKcommon/internal/Measure.h"
31 #include "SimTKcommon/internal/Subsystem.h"
32 #include "SimTKcommon/internal/System.h"
33 #include "SimTKcommon/internal/SubsystemGuts.h"
34
35 #include <cmath>
36
37
38 namespace SimTK {
39
40
41 //==============================================================================
42 // ABSTRACT MEASURE :: IMPLEMENTATION
43 //==============================================================================
44
45 /**
46 * The abstract parent of all Measure Implementation classes.
47 */
48 class SimTK_SimTKCOMMON_EXPORT AbstractMeasure::Implementation {
49 protected:
50 /** This default constructor is for use by concrete measure implementation
51 classes. **/
Implementation()52 Implementation() : copyNumber(0), mySubsystem(0), refCount(0) {}
53
54 /** Base class copy constructor removes the Subsystem
55 and sets the reference count to zero. This gets used by the clone()
56 methods in the concrete classes. **/
Implementation(const Implementation & src)57 Implementation(const Implementation& src)
58 : copyNumber(src.copyNumber+1), mySubsystem(0), refCount(0) {}
59
60 /** Base class copy assignment operator removes the
61 Subsystem, and sets the reference count to zero. This is probably
62 not used. **/
63 Implementation& operator=(const Implementation& src) {
64 if (&src != this)
65 { copyNumber=src.copyNumber+1;
66 refCount=0; mySubsystem=0; }
67 return *this;
68 }
69
70 // destructor is virtual; below
71
72 // Increment the reference count and return its new value.
incrRefCount()73 int incrRefCount() const {return ++refCount;}
74
75 // Decrement the reference count and return its new value.
decrRefCount()76 int decrRefCount() const {return --refCount;}
77
78 // Get the current value of the reference counter.
getRefCount()79 int getRefCount() const {return refCount;}
80
getCopyNumber()81 int getCopyNumber() const {return copyNumber;}
82
83 /** This is a deep copy of the concrete Implementation object, except the
84 Subsystem will have been removed. The reference count on the new object
85 will be zero; be sure to increment it if you put it in a handle. **/
clone()86 Implementation* clone() const {return cloneVirtual();}
87
88 // realizeTopology() is pure virtual below for Measure_<T> to supply.
realizeModel(State & s)89 void realizeModel (State& s) const {realizeMeasureModelVirtual(s);}
realizeInstance(const State & s)90 void realizeInstance (const State& s) const {realizeMeasureInstanceVirtual(s);}
realizeTime(const State & s)91 void realizeTime (const State& s) const {realizeMeasureTimeVirtual(s);}
realizePosition(const State & s)92 void realizePosition (const State& s) const {realizeMeasurePositionVirtual(s);}
realizeVelocity(const State & s)93 void realizeVelocity (const State& s) const {realizeMeasureVelocityVirtual(s);}
realizeDynamics(const State & s)94 void realizeDynamics (const State& s) const {realizeMeasureDynamicsVirtual(s);}
realizeAcceleration(const State & s)95 void realizeAcceleration(const State& s) const {realizeMeasureAccelerationVirtual(s);}
realizeReport(const State & s)96 void realizeReport (const State& s) const {realizeMeasureReportVirtual(s);}
97
98 /** This should be called at the start of a time stepping study to
99 cause this %Measure to set its state variables (if any) in the supplied
100 state to their initial conditions. **/
initialize(State & s)101 void initialize(State& s) const {initializeVirtual(s);}
102
getNumTimeDerivatives()103 int getNumTimeDerivatives() const {return getNumTimeDerivativesVirtual();}
104
getDependsOnStage(int derivOrder)105 Stage getDependsOnStage(int derivOrder) const {
106 SimTK_ERRCHK2(0 <= derivOrder && derivOrder <= getNumTimeDerivatives(),
107 "Measure::getDependsOnStage()",
108 "derivOrder %d was out of range; this Measure allows 0-%d.",
109 derivOrder, getNumTimeDerivatives());
110 return getDependsOnStageVirtual(derivOrder);
111 }
112
113
setSubsystem(Subsystem & sub,MeasureIndex mx)114 void setSubsystem(Subsystem& sub, MeasureIndex mx)
115 { assert(!mySubsystem && mx.isValid());
116 mySubsystem = ⊂ myIndex = mx; }
117
isInSubsystem()118 bool isInSubsystem() const {return mySubsystem != 0;}
getSubsystem()119 const Subsystem& getSubsystem() const {assert(mySubsystem); return *mySubsystem;}
updSubsystem()120 Subsystem& updSubsystem() {assert(mySubsystem); return *mySubsystem;}
getSubsystemMeasureIndex()121 MeasureIndex getSubsystemMeasureIndex() const {assert(mySubsystem); return myIndex;}
getSubsystemIndex()122 SubsystemIndex getSubsystemIndex() const
123 { return getSubsystem().getMySubsystemIndex(); }
124
invalidateTopologyCache()125 void invalidateTopologyCache() const
126 { if (isInSubsystem()) getSubsystem().invalidateSubsystemTopologyCache(); }
127
getStage(const State & s)128 Stage getStage(const State& s) const {return getSubsystem().getStage(s);}
129
130 // VIRTUALS //
131
~Implementation()132 virtual ~Implementation() {}
133 virtual Implementation* cloneVirtual() const = 0;
134
135 virtual void realizeTopology(State&)const = 0;
136
realizeMeasureModelVirtual(State &)137 virtual void realizeMeasureModelVirtual(State&) const {}
realizeMeasureInstanceVirtual(const State &)138 virtual void realizeMeasureInstanceVirtual(const State&) const {}
realizeMeasureTimeVirtual(const State &)139 virtual void realizeMeasureTimeVirtual(const State&) const {}
realizeMeasurePositionVirtual(const State &)140 virtual void realizeMeasurePositionVirtual(const State&) const {}
realizeMeasureVelocityVirtual(const State &)141 virtual void realizeMeasureVelocityVirtual(const State&) const {}
realizeMeasureDynamicsVirtual(const State &)142 virtual void realizeMeasureDynamicsVirtual(const State&) const {}
realizeMeasureAccelerationVirtual(const State &)143 virtual void realizeMeasureAccelerationVirtual(const State&) const {}
realizeMeasureReportVirtual(const State &)144 virtual void realizeMeasureReportVirtual(const State&) const {}
145
initializeVirtual(State &)146 virtual void initializeVirtual(State&) const {}
getNumTimeDerivativesVirtual()147 virtual int getNumTimeDerivativesVirtual() const {return 0;}
148 virtual Stage getDependsOnStageVirtual(int order) const = 0;
149
150 private:
151 int copyNumber; // bumped each time we do a deep copy
152
153 // These are set when this Measure is adopted by a Subsystem.
154 Subsystem* mySubsystem;
155 MeasureIndex myIndex;
156
157 // Measures have shallow copy semantics so they share the Implementation
158 // objects, which are only deleted when the refCount goes to zero.
159 mutable int refCount;
160
161 friend class AbstractMeasure;
162 friend class Subsystem::Guts;
163 };
164
165 //==============================================================================
166 // ABSTRACT MEASURE DEFINITIONS
167 //==============================================================================
168 // These had to wait for AbstractMeasure::Implementation to be defined.
169
170 inline AbstractMeasure::
AbstractMeasure(Implementation * g)171 AbstractMeasure(Implementation* g)
172 : impl(g)
173 { if (impl) impl->incrRefCount(); }
174
175 inline AbstractMeasure::
AbstractMeasure(Subsystem & sub,Implementation * g,const SetHandle &)176 AbstractMeasure(Subsystem& sub, Implementation* g, const SetHandle&)
177 : impl(g) {
178 SimTK_ERRCHK(hasImpl(), "AbstractMeasure::AbstractMeasure()",
179 "An empty Measure handle can't be put in a Subsystem.");
180 impl->incrRefCount();
181 sub.adoptMeasure(*this);
182 }
183
184 // Shallow copy constructor.
AbstractMeasure(const AbstractMeasure & src)185 inline AbstractMeasure::AbstractMeasure(const AbstractMeasure& src)
186 : impl(0) {
187 if (src.impl) {
188 impl = src.impl;
189 impl->incrRefCount();
190 }
191 }
192
193 // Shallow assignment.
194 inline AbstractMeasure& AbstractMeasure::
shallowAssign(const AbstractMeasure & src)195 shallowAssign(const AbstractMeasure& src) {
196 if (impl != src.impl) {
197 if (impl && impl->decrRefCount()==0) delete impl;
198 impl = src.impl;
199 impl->incrRefCount();
200 }
201 return *this;
202 }
203
204 // Note that even if the source and destination are currently pointing
205 // to the same Implementation, we still have to make a new copy so that
206 // afterwards the destination has its own, refcount==1 copy.
207 inline AbstractMeasure& AbstractMeasure::
deepAssign(const AbstractMeasure & src)208 deepAssign(const AbstractMeasure& src) {
209 if (&src != this) {
210 if (impl && impl->decrRefCount()==0) delete impl;
211 if (src.impl) {
212 impl = src.impl->clone();
213 impl->incrRefCount();
214 } else
215 impl = 0;
216 }
217 return *this;
218 }
219
220 inline AbstractMeasure::
~AbstractMeasure()221 ~AbstractMeasure()
222 { if (impl && impl->decrRefCount()==0) delete impl;}
223
224 inline bool AbstractMeasure::
isInSubsystem()225 isInSubsystem() const
226 { return hasImpl() && getImpl().isInSubsystem(); }
227
228 inline const Subsystem& AbstractMeasure::
getSubsystem()229 getSubsystem() const
230 { return getImpl().getSubsystem(); }
231
232 inline bool AbstractMeasure::
isSameSubsystem(const Subsystem & other)233 isSameSubsystem(const Subsystem& other) const
234 { return getSubsystem().isSameSubsystem(other); }
235
236 inline MeasureIndex AbstractMeasure::
getSubsystemMeasureIndex()237 getSubsystemMeasureIndex() const
238 { return getImpl().getSubsystemMeasureIndex();}
239
240 inline int AbstractMeasure::
getNumTimeDerivatives()241 getNumTimeDerivatives() const
242 { return getImpl().getNumTimeDerivatives(); }
243
244 inline Stage AbstractMeasure::
getDependsOnStage(int derivOrder)245 getDependsOnStage(int derivOrder) const
246 { return getImpl().getDependsOnStage(derivOrder); }
247
248 inline int AbstractMeasure::
getRefCount()249 getRefCount() const
250 { return getImpl().getRefCount(); }
251
252
253 /** @cond **/ // Hide from Doxygen.
254 // This is a helper class that makes it possible to treat Real, Vec, and
255 // Vector objects uniformly.
256 template <class T> class Measure_Num {
257 };
258
259 template <> class Measure_Num<float> {
260 public:
261 typedef float Element;
size(const float &)262 static int size(const float&) {return 1;}
get(const float & v,int i)263 static const float& get(const float& v, int i) {assert(i==0); return v;}
upd(float & v,int i)264 static float& upd(float& v, int i) {assert(i==0); return v;}
makeNaNLike(const float &,float & nanValue)265 static void makeNaNLike(const float&, float& nanValue)
266 { nanValue = CNT<float>::getNaN();}
makeZeroLike(const float &,float & zeroValue)267 static void makeZeroLike(const float&, float& zeroValue) {zeroValue=0.f;}
268 };
269
270 template <> class Measure_Num<double> {
271 public:
272 typedef double Element;
size(const double &)273 static int size(const double&) {return 1;}
get(const double & v,int i)274 static const double& get(const double& v, int i) {assert(i==0); return v;}
upd(double & v,int i)275 static double& upd(double& v, int i) {assert(i==0); return v;}
makeNaNLike(const double &,double & nanValue)276 static void makeNaNLike(const double&, double& nanValue)
277 { nanValue = CNT<double>::getNaN(); }
makeZeroLike(const double &,double & zeroValue)278 static void makeZeroLike(const double&, double& zeroValue) {zeroValue=0.;}
279 };
280
281 // We only support stride 1 (densely packed) Vec types.
282 template <int M, class E>
283 class Measure_Num< Vec<M,E,1> > {
284 typedef Vec<M,E,1> T;
285 public:
286 typedef E Element;
size(const T &)287 static int size(const T&) {return M;}
get(const T & v,int i)288 static const E& get(const T& v, int i) {return v[i];}
upd(T & v,int i)289 static E& upd(T& v, int i) {return v[i];}
makeNaNLike(const T &,T & nanValue)290 static void makeNaNLike (const T&, T& nanValue) {nanValue.setToNaN();}
makeZeroLike(const T &,T & zeroValue)291 static void makeZeroLike(const T&, T& zeroValue) {zeroValue.setToZero();}
292 };
293
294 // We only support column major (densely packed) Mat types.
295 template <int M, int N, class E>
296 class Measure_Num< Mat<M,N,E> > {
297 typedef Mat<M,N,E> T;
298 public:
299 typedef E Element;
size(const T &)300 static int size(const T&) {return N;} // number of columns
get(const T & m,int j)301 static const typename T::TCol& get(const T& m, int j) {return m.col(j);}
upd(T & m,int j)302 static typename T::TCol& upd(T& m, int j) {return m.col(j);}
makeNaNLike(const T &,T & nanValue)303 static void makeNaNLike (const T&, T& nanValue) {nanValue.setToNaN();}
makeZeroLike(const T &,T & zeroValue)304 static void makeZeroLike(const T&, T& zeroValue) {zeroValue.setToZero();}
305 };
306
307
308 template <class E>
309 class Measure_Num< Vector_<E> > {
310 typedef Vector_<E> T;
311 public:
312 typedef E Element;
size(const T & v)313 static int size(const T& v) {return v.size();}
get(const T & v,int i)314 static const E& get(const T& v, int i) {return v[i];}
upd(T & v,int i)315 static E& upd(T& v, int i) {return v[i];}
makeNaNLike(const T & v,T & nanValue)316 static void makeNaNLike(const T& v, T& nanValue)
317 { nanValue.resize(v.size()); nanValue.setToNaN(); }
makeZeroLike(const T & v,T & zeroValue)318 static void makeZeroLike(const T& v, T& zeroValue)
319 { zeroValue.resize(v.size()); zeroValue.setToZero(); }
320 };
321
322
323 template <class E>
324 class Measure_Num< Rotation_<E> > {
325 typedef Rotation_<E> T;
326 public:
327 typedef T Element;
size(const T &)328 static int size(const T&) {return 1;}
get(const T & v,int i)329 static const T& get(const T& v, int i) {assert(i==0); return v;}
upd(T & v,int i)330 static T& upd(T& v, int i) {assert(i==0); return v;}
makeNaNLike(const T &,T & nanValue)331 static void makeNaNLike(const T&, T& nanValue)
332 { nanValue.setRotationToNaN(); }
makeZeroLike(const T &,T & zeroValue)333 static void makeZeroLike(const T&, T& zeroValue)
334 { zeroValue.setRotationToIdentityMatrix(); }
335 };
336
337 template <class E>
338 class Measure_Num< Transform_<E> > {
339 typedef Transform_<E> T;
340 public:
341 typedef T Element;
size(const T &)342 static int size(const T&) {return 1;}
get(const T & v,int i)343 static const T& get(const T& v, int i) {assert(i==0); return v;}
upd(T & v,int i)344 static T& upd(T& v, int i) {assert(i==0); return v;}
makeNaNLike(const T &,T & nanValue)345 static void makeNaNLike(const T&, T& nanValue)
346 { nanValue.setToNaN(); }
makeZeroLike(const T &,T & zeroValue)347 static void makeZeroLike(const T&, T& zeroValue)
348 { zeroValue.setToZero(); }
349 };
350
351 /** @endcond **/
352
353 //==============================================================================
354 // MEASURE_<T> :: IMPLEMENTATION
355 //==============================================================================
356 /** This is the base Implementation class for all Measures whose value type is
357 known. This class is still abstract but provides many services related to the
358 values of the derived Measure and its derivatives, all of which require cache
359 entries of type T.
360
361 The constructor needs to be told how many type-T cache entries to allocate. **/
362 template <class T>
363 class Measure_<T>::Implementation : public AbstractMeasure::Implementation {
364 public:
getValue(const State & s,int derivOrder)365 const T& getValue(const State& s, int derivOrder) const {
366 SimTK_ERRCHK2(0 <= derivOrder && derivOrder <= getNumTimeDerivatives(),
367 "Measure_<T>::getValue()",
368 "derivOrder %d was out of range; this Measure allows 0-%d.",
369 derivOrder, getNumTimeDerivatives());
370
371 // We require the stage to have been advanced to at least the one
372 // before this measure's depends-on stage since this will get called
373 // towards the end of the depends-on stage realization.
374 if (getDependsOnStage(derivOrder) != Stage::Empty) {
375 #ifndef NDEBUG
376 Stage prevStage = getDependsOnStage(derivOrder).prev();
377 #endif
378
379 SimTK_ERRCHK2
380 ( ( isInSubsystem() && getStage(s)>=prevStage)
381 || (!isInSubsystem() && s.getSystemStage()>=prevStage),
382 "Measure_<T>::getValue()",
383 "Expected State to have been realized to at least stage "
384 "%s but stage was %s.",
385 prevStage.getName().c_str(),
386 (isInSubsystem() ? getStage(s) : s.getSystemStage())
387 .getName().c_str());
388 }
389
390 if (derivOrder < getNumCacheEntries()) {
391 if (!isCacheValueRealized(s,derivOrder)) {
392 T& value = updCacheEntry(s,derivOrder);
393 calcCachedValueVirtual(s, derivOrder, value);
394 markCacheValueRealized(s,derivOrder);
395 return value;
396 }
397 return getCacheEntry(s,derivOrder);
398 }
399
400 // We can't handle it here -- punt to the concrete Measure
401 // for higher order derivatives.
402 return getUncachedValueVirtual(s,derivOrder);
403 }
404
405 /** Set a new default value for this %Measure. This is a topological
406 change. **/
setDefaultValue(const T & defaultValue)407 void setDefaultValue(const T& defaultValue) {
408 this->defaultValue = defaultValue;
409 Measure_Num<T>::makeZeroLike(defaultValue, zeroValue);
410 this->invalidateTopologyCache();
411 }
412
413 /** Return a reference to the value that this %Measure will use to
414 initialize its value-level state resource (state variable or cache entry)
415 during the next call to realizeTopology(). **/
getDefaultValue()416 const T& getDefaultValue() const {return defaultValue;}
417
setIsPresumedValidAtDependsOnStage(bool presume)418 void setIsPresumedValidAtDependsOnStage(bool presume)
419 { presumeValidAtDependsOnStage = presume;
420 this->invalidateTopologyCache(); }
421
getIsPresumedValidAtDependsOnStage()422 bool getIsPresumedValidAtDependsOnStage() const
423 { return presumeValidAtDependsOnStage; }
424
425 protected:
426 explicit Implementation(const T& defaultValue, int numCacheEntries=1)
presumeValidAtDependsOnStage(false)427 : presumeValidAtDependsOnStage(false),
428 defaultValue(defaultValue),
429 derivIx(numCacheEntries)
430 {
431 Measure_Num<T>::makeZeroLike(defaultValue, zeroValue);
432 }
433
434 /** Argument \a numCacheEntries should be one greater than the number of
435 derivatives; that is, there is room for the value ("0th" derivative) also.
436 The default is to allocate just room for the value. **/
437 explicit Implementation(int numCacheEntries=1)
presumeValidAtDependsOnStage(false)438 : presumeValidAtDependsOnStage(false),
439 defaultValue(),
440 derivIx(numCacheEntries)
441 {
442 Measure_Num<T>::makeZeroLike(defaultValue, zeroValue);
443 }
444
445 /** Copy constructor copies the \e number of cache entries from the source,
446 but not the cache indices themselves as those must be allocated uniquely
447 for the copy. **/
Implementation(const Implementation & source)448 Implementation(const Implementation& source)
449 : presumeValidAtDependsOnStage(source.presumeValidAtDependsOnStage),
450 defaultValue(source.defaultValue),
451 derivIx(source.derivIx.size())
452 {
453 Measure_Num<T>::makeZeroLike(defaultValue, zeroValue);
454 }
455
456
457 /** Return the number of elements in the data type of this %Measure; for
458 Vector measures this is determined by the size of the default value. **/
size()459 int size() const {return Measure_Num<T>::size(defaultValue);}
460
461 /** Return the number of cache entries allocated for the value and
462 derivatives of this %Measure. **/
getNumCacheEntries()463 int getNumCacheEntries() const {return (int)derivIx.size();}
464
465 /** Get a const reference to the value stored in one of this %Measure's
466 cache entries, indexed by the derivative order (with the value treated as
467 the 0th derivative). **/
getCacheEntry(const State & s,int derivOrder)468 const T& getCacheEntry(const State& s, int derivOrder) const {
469 SimTK_ERRCHK2(0 <= derivOrder && derivOrder < getNumCacheEntries(),
470 "Measure_<T>::Implementation::getCacheEntry()",
471 "Derivative order %d is out of range; only %d cache entries"
472 " were allocated.", derivOrder, getNumCacheEntries());
473
474 return Value<T>::downcast(
475 this->getSubsystem().getCacheEntry(s, derivIx[derivOrder]));
476 }
477
478 /** Get a writable reference to the value stored in one of this %Measure's
479 cache entries, indexed by the derivative order (with the value treated as
480 the 0th derivative). **/
updCacheEntry(const State & s,int derivOrder)481 T& updCacheEntry(const State& s, int derivOrder) const {
482 SimTK_ERRCHK2(0 <= derivOrder && derivOrder < getNumCacheEntries(),
483 "Measure_<T>::Implementation::updCacheEntry()",
484 "Derivative order %d is out of range; only %d cache entries"
485 " were allocated.", derivOrder, getNumCacheEntries());
486
487 return Value<T>::updDowncast(
488 this->getSubsystem().updCacheEntry(s, derivIx[derivOrder]));
489 }
490
491 /** Determine whether a particular one of this %Measure's cache entries has
492 already been realized since the given state was modified. **/
isCacheValueRealized(const State & s,int derivOrder)493 bool isCacheValueRealized(const State& s, int derivOrder) const {
494 SimTK_ERRCHK2(0 <= derivOrder && derivOrder < getNumCacheEntries(),
495 "Measure_<T>::Implementation::isCacheValueRealized()",
496 "Derivative order %d is out of range; only %d cache entries"
497 " were allocated.", derivOrder, getNumCacheEntries());
498
499 return this->getSubsystem().isCacheValueRealized(s, derivIx[derivOrder]);
500 }
501
502 /** Mark one of this %Measure's cache entries up to date; call this after
503 you have calculated a value or derivative and stored it in the
504 corresponding cache entry. **/
markCacheValueRealized(const State & s,int derivOrder)505 void markCacheValueRealized(const State& s, int derivOrder) const {
506 SimTK_ERRCHK2(0 <= derivOrder && derivOrder < getNumCacheEntries(),
507 "Measure_<T>::Implementation::markCacheValueRealized()",
508 "Derivative order %d is out of range; only %d cache entries"
509 " were allocated.", derivOrder, getNumCacheEntries());
510
511 this->getSubsystem().markCacheValueRealized(s, derivIx[derivOrder]);
512 }
513
514 /** Invalidate one of this %Measure's cache entries. This is not normally
515 necessary since the cache entries will be invalidated automatically when
516 state variables they depend on change. However, this can be useful in
517 some cases, particularly during debugging and testing. **/
markCacheValueNotRealized(const State & s,int derivOrder)518 void markCacheValueNotRealized(const State& s, int derivOrder) const {
519 SimTK_ERRCHK2(0 <= derivOrder && derivOrder < getNumCacheEntries(),
520 "Measure_<T>::Implementation::markCacheValueNotRealized()",
521 "Derivative order %d is out of range; only %d cache entries"
522 " were allocated.", derivOrder, getNumCacheEntries());
523
524 this->getSubsystem().markCacheValueNotRealized(s, derivIx[derivOrder]);
525 }
526
527 // VIRTUALS //
528
529 /** Concrete measures can override this to allocate Topology-stage
530 resources. **/
realizeMeasureTopologyVirtual(State &)531 virtual void realizeMeasureTopologyVirtual(State&) const {}
532
533 /** Concrete measures must override this if the state cache is used for
534 precalculated values or derivatives. **/
535 virtual void
calcCachedValueVirtual(const State &,int derivOrder,T & value)536 calcCachedValueVirtual(const State&, int derivOrder, T& value) const
537 { SimTK_ERRCHK1_ALWAYS(!"implemented",
538 "Measure_<T>::Implementation::calcCachedValueVirtual()",
539 "This method should have been overridden by the derived"
540 " Measure but was not. It is needed to calculate the"
541 " cached value for derivOrder=%d.", derivOrder); }
542
543 /** This is only called when derivOrder >= the number of cache
544 entries we have, but still <= the number of derivatives the
545 %Measure says it can deliver. You don't need to override this if that
546 condition can't occur. This is commonly used for functions whose derivatives
547 above a certain order are zero. **/
548 virtual const T&
getUncachedValueVirtual(const State &,int derivOrder)549 getUncachedValueVirtual(const State&, int derivOrder) const
550 { SimTK_ERRCHK1_ALWAYS(!"implemented",
551 "Measure_<T>::Implementation::getUncachedValueVirtual()",
552 "This method should have been overridden by the derived"
553 " Measure but was not. It is needed to return the uncached"
554 " value at derivOrder=%d.", derivOrder);
555 return *reinterpret_cast<T*>(0);
556 }
557
558 /** Return a reference to a zero of the same type and size as this
559 %Measure's value. **/
getValueZero()560 const T& getValueZero() const {return zeroValue;}
561
562 private:
563 // Satisfy the realizeTopology() pure virtual here now that we know the
564 // data type T. Allocate lazy- or auto-validated- cache entries depending
565 // on the setting of presumeValidAtDependsOnStage.
realizeTopology(State & s)566 void realizeTopology(State& s) const override final {
567 // Allocate cache entries. Initialize the value cache entry to
568 // the given defaultValue; all the derivative cache entries should be
569 // initialized to a NaN of the same size.
570 if (getNumCacheEntries()) {
571 derivIx[0] = presumeValidAtDependsOnStage
572 ? this->getSubsystem().allocateCacheEntry
573 (s, getDependsOnStage(0), new Value<T>(defaultValue))
574 : this->getSubsystem().allocateLazyCacheEntry
575 (s, getDependsOnStage(0), new Value<T>(defaultValue));
576
577 if (getNumCacheEntries() > 1) {
578 T nanValue; Measure_Num<T>::makeNaNLike(defaultValue, nanValue);
579 for (int i=1; i < getNumCacheEntries(); ++i) {
580 derivIx[i] = presumeValidAtDependsOnStage
581 ? this->getSubsystem().allocateCacheEntry
582 (s, getDependsOnStage(i), new Value<T>(nanValue))
583 : this->getSubsystem().allocateLazyCacheEntry
584 (s, getDependsOnStage(i), new Value<T>(nanValue));
585 }
586 }
587 }
588
589 // Call the concrete class virtual if any.
590 realizeMeasureTopologyVirtual(s);
591 }
592
593 //------------------------------------------------------------------------------
594 private:
595 // TOPOLOGY STATE
596 bool presumeValidAtDependsOnStage;
597 T defaultValue;
598 T zeroValue;
599
600 // TOPOLOGY CACHE
601 mutable Array_<CacheEntryIndex> derivIx;
602 };
603
604
605
606 //==============================================================================
607 // CONSTANT :: IMPLEMENTATION
608 //==============================================================================
609 template <class T>
610 class Measure_<T>::Constant::Implementation
611 : public Measure_<T>::Implementation
612 {
613 public:
614 // We don't want the base class to allocate *any* cache entries.
Implementation()615 Implementation() : Measure_<T>::Implementation(0) {}
Implementation(const T & value)616 explicit Implementation(const T& value)
617 : Measure_<T>::Implementation(value,0) {}
618
619 /** Changing the value of a %Constant measure is a topological change;
620 if this is a Vector measure you can change the size here too. **/
setValue(const T & v)621 void setValue(const T& v) {this->setDefaultValue(v);}
622
623 // Implementations of virtual methods.
624 // Measure_<T> virtuals:
625 // No cached values.
626
getUncachedValueVirtual(const State &,int derivOrder)627 const T& getUncachedValueVirtual(const State&, int derivOrder) const
628 override
629 { return derivOrder>0 ? this->getValueZero() : this->getDefaultValue(); }
630
631 // AbstractMeasure virtuals:
cloneVirtual()632 Implementation* cloneVirtual() const override
633 { return new Implementation(*this); }
getDependsOnStageVirtual(int derivOrder)634 Stage getDependsOnStageVirtual(int derivOrder) const override
635 { return derivOrder>0 ? Stage::Empty : Stage::Topology; }
getNumTimeDerivativesVirtual()636 int getNumTimeDerivativesVirtual() const override
637 { return std::numeric_limits<int>::max(); }
638 };
639
640
641
642 //==============================================================================
643 // MEASURE ZERO and ONE
644 //==============================================================================
645 // These had to wait for Constant::Implementation to be declared.
646
647 template <class T> inline
Zero()648 Measure_<T>::Zero::Zero() : Constant(T(0)) {}
649 template <class T> inline
Zero(Subsystem & sub)650 Measure_<T>::Zero::Zero(Subsystem& sub) : Constant(sub, T(0)) {}
651
Zero(int size)652 inline Measure_< Vector >::Zero::Zero(int size)
653 : Constant(Vector(size, Real(0))) {}
Zero(Subsystem & sub,int size)654 inline Measure_< Vector >::Zero::Zero(Subsystem& sub, int size)
655 : Constant(sub, Vector(size, Real(0))) {}
656
657 template <class T> inline
One()658 Measure_<T>::One::One() : Constant(T(1)) {}
659 template <class T> inline
One(Subsystem & sub)660 Measure_<T>::One::One(Subsystem& sub) : Constant(sub, T(1)) {}
661
One(int size)662 inline Measure_< Vector >::One::One(int size)
663 : Constant(Vector(size, Real(1))) {}
One(Subsystem & sub,int size)664 inline Measure_< Vector >::One::One(Subsystem& sub, int size)
665 : Constant(sub, Vector(size, Real(1))) {}
666
667
668
669 //==============================================================================
670 // TIME :: IMPLEMENTATION
671 //==============================================================================
672 template <class T>
673 class Measure_<T>::Time::Implementation {};
674
675 template <>
676 class Measure_<Real>::Time::Implementation
677 : public Measure_<Real>::Implementation
678 {
679 public:
680 // We don't want the base class to allocate *any* cache entries.
Implementation()681 Implementation() : Measure_<Real>::Implementation(0) {}
682
683 // Implementations of virtual methods.
684 // Measure_<Real> virtuals:
685 // No cached values.
686
getUncachedValueVirtual(const State & s,int derivOrder)687 const Real& getUncachedValueVirtual(const State& s, int derivOrder) const
688 override
689 { return derivOrder==0 ? s.getTime()
690 : (derivOrder==1 ? SimTK::One
691 : SimTK::Zero); }
692
693 // AbstractMeasure virtuals:
cloneVirtual()694 Implementation* cloneVirtual() const override
695 { return new Implementation(*this); }
getDependsOnStageVirtual(int derivOrder)696 Stage getDependsOnStageVirtual(int derivOrder) const override
697 { return derivOrder>0 ? Stage::Empty : Stage::Time; }
698
699 // Value is t, 1st derivative is 1, the rest are 0.
getNumTimeDerivativesVirtual()700 int getNumTimeDerivativesVirtual() const override
701 { return std::numeric_limits<int>::max(); }
702 };
703
704
705
706 //==============================================================================
707 // VARIABLE :: IMPLEMENTATION
708 //==============================================================================
709 template <class T>
710 class Measure_<T>::Variable::Implementation
711 : public Measure_<T>::Implementation
712 {
713 public:
714 // We don't want the base class to allocate *any* cache entries;
715 // we'll use the variable as its own value and zeroes for all
716 // the derivatives.
Implementation()717 Implementation()
718 : Measure_<T>::Implementation(0),
719 invalidatedStage(Stage::Empty) {}
720
Implementation(Stage invalidated,const T & defaultValue)721 Implementation(Stage invalidated, const T& defaultValue)
722 : Measure_<T>::Implementation(defaultValue, 0),
723 invalidatedStage(invalidated) {}
724
725 // Copy constructor should not copy the variable.
Implementation(const Implementation & source)726 Implementation(const Implementation& source)
727 : Measure_<T>::Implementation(source.getDefaultValue(), 0),
728 invalidatedStage(source.invalidatedStage) {}
729
setInvalidatedStage(Stage invalidates)730 void setInvalidatedStage(Stage invalidates) {
731 invalidatedStage = invalidates;
732 this->invalidateTopologyCache();
733 }
734
getInvalidatedStage()735 Stage getInvalidatedStage() const {return invalidatedStage;}
736
737 /** Change the value of this %Measure in the given \a state. Invalidates
738 cache entries in that \a state for any stage at or above the "invalidates"
739 stage that was set when this %Measure was constructed. **/
setValue(State & state,const T & value)740 void setValue(State& state, const T& value) const
741 { updVarValue(state) = value; }
742
743 // Implementations of virtual methods.
cloneVirtual()744 Implementation* cloneVirtual() const override
745 { return new Implementation(*this); }
746
getNumTimeDerivativesVirtual()747 int getNumTimeDerivativesVirtual() const override
748 { return std::numeric_limits<int>::max(); }
749
750 // Discrete variable is available after Model stage; but all its
751 // derivatives are zero so are always available.
getDependsOnStageVirtual(int derivOrder)752 Stage getDependsOnStageVirtual(int derivOrder) const override
753 { return derivOrder>0 ? Stage::Empty : Stage::Model;}
754
getUncachedValueVirtual(const State & s,int derivOrder)755 const T& getUncachedValueVirtual(const State& s, int derivOrder) const
756 override
757 { return derivOrder>0 ? this->getValueZero() : getVarValue(s); }
758
759 // No cached values.
760
realizeMeasureTopologyVirtual(State & s)761 void realizeMeasureTopologyVirtual(State& s) const override {
762 discreteVarIndex = this->getSubsystem().allocateDiscreteVariable
763 (s, invalidatedStage, new Value<T>(this->getDefaultValue()));
764 }
765 private:
getVarValue(const State & s)766 const T& getVarValue(const State& s) const {
767 assert(discreteVarIndex.isValid());
768 return Value<T>::downcast(
769 this->getSubsystem().getDiscreteVariable(s, discreteVarIndex));
770 }
updVarValue(State & s)771 T& updVarValue(State& s) const {
772 assert(discreteVarIndex.isValid());
773 return Value<T>::downcast(
774 this->getSubsystem().updDiscreteVariable(s, discreteVarIndex));
775 }
776
777 // TOPOLOGY STATE
778 Stage invalidatedStage; // TODO this shouldn't be needed
779
780 // TOPOLOGY CACHE
781 mutable DiscreteVariableIndex discreteVarIndex;
782 };
783
784
785
786 //==============================================================================
787 // RESULT :: IMPLEMENTATION
788 //==============================================================================
789 template <class T>
790 class Measure_<T>::Result::Implementation
791 : public Measure_<T>::Implementation
792 {
793 public:
794 // We want the base class to allocate a single cache entry of type T.
Implementation()795 Implementation()
796 : Measure_<T>::Implementation(1),
797 dependsOnStage(Stage::Topology), invalidatedStage(Stage::Infinity) {}
798
Implementation(Stage dependsOn,Stage invalidated)799 Implementation(Stage dependsOn, Stage invalidated)
800 : Measure_<T>::Implementation(1),
801 dependsOnStage(dependsOn==Stage::Empty ? Stage::Topology : dependsOn),
802 invalidatedStage(invalidated)
803 { SimTK_ERRCHK2_ALWAYS(invalidated > dependsOn,"Measure::Result::ctor()",
804 "Got invalidated stage %s and dependsOn stage %s which is illegal "
805 "because the invalidated stage must be later than dependsOn.",
806 invalidated.getName().c_str(), dependsOn.getName().c_str());
807 }
808
809 // Copy constructor will not copy the cache entry index.
Implementation(const Implementation & source)810 Implementation(const Implementation& source)
811 : Measure_<T>::Implementation(source),
812 dependsOnStage(source.dependsOnStage),
813 invalidatedStage(source.invalidatedStage) {}
814
setDependsOnStage(Stage dependsOn)815 void setDependsOnStage(Stage dependsOn) {
816 if (dependsOn == Stage::Empty) dependsOn = Stage::Topology;
817 SimTK_ERRCHK2_ALWAYS(dependsOn < getInvalidatedStage(),
818 "Measure::Result::setDependsOnStage()",
819 "The provided dependsOn stage %s is illegal because it is not "
820 "less than the current invalidated stage %s. Change the "
821 "invalidated stage first with setInvalidatedStage().",
822 dependsOn.getName().c_str(),
823 getInvalidatedStage().getName().c_str());
824
825 dependsOnStage = dependsOn;
826 this->invalidateTopologyCache();
827 }
828
setInvalidatedStage(Stage invalidated)829 void setInvalidatedStage(Stage invalidated) {
830 SimTK_ERRCHK2_ALWAYS(invalidated > getDependsOnStage(),
831 "Measure::Result::setInvalidatedStage()",
832 "The provided invalidated stage %s is illegal because it is not "
833 "greater than the current dependsOn stage %s. Change the "
834 "dependsOn stage first with setDependsOnStage().",
835 invalidated.getName().c_str(),
836 getDependsOnStage().getName().c_str());
837
838 invalidatedStage = invalidated;
839 this->invalidateTopologyCache();
840 }
841
842
getDependsOnStage()843 Stage getDependsOnStage() const {return dependsOnStage;}
getInvalidatedStage()844 Stage getInvalidatedStage() const {return invalidatedStage;}
845
846
markAsValid(const State & state)847 void markAsValid(const State& state) const
848 { const Stage subsystemStage = this->getSubsystem().getStage(state);
849 SimTK_ERRCHK3_ALWAYS(subsystemStage >= getDependsOnStage().prev(),
850 "Measure::Result::markAsValid()",
851 "This Result Measure cannot be marked valid in a State where this "
852 "measure's Subsystem has been realized only to stage %s, because "
853 "its value was declared to depend on stage %s. To mark it valid, "
854 "we require that the State have been realized at least to the "
855 "previous stage (%s in this case); that is, you must at least be "
856 "*working on* the dependsOn stage in order to claim this result is "
857 "available.",
858 subsystemStage.getName().c_str(),
859 getDependsOnStage().getName().c_str(),
860 getDependsOnStage().prev().getName().c_str());
861 this->markCacheValueRealized(state, 0); }
862
isValid(const State & state)863 bool isValid(const State& state) const
864 { return this->isCacheValueRealized(state, 0); }
865
markAsNotValid(const State & state)866 void markAsNotValid(const State& state) const
867 { this->markCacheValueNotRealized(state, 0);
868 state.invalidateAllCacheAtOrAbove(invalidatedStage); }
869
updValue(const State & state)870 T& updValue(const State& state) const
871 { markAsNotValid(state); return this->updCacheEntry(state, 0); }
872
873
874 // Implementations of virtual methods.
cloneVirtual()875 Implementation* cloneVirtual() const override
876 { return new Implementation(*this); }
877
getNumTimeDerivativesVirtual()878 int getNumTimeDerivativesVirtual() const override {return 0;}
879
880 /** Cache value is available after its "depends on" stage has been
881 realized; but all its derivatives are zero so are always available. **/
getDependsOnStageVirtual(int derivOrder)882 Stage getDependsOnStageVirtual(int derivOrder) const override
883 { return derivOrder>0 ? Stage::Empty : dependsOnStage;}
884
calcCachedValueVirtual(const State &,int derivOrder,T & value)885 void calcCachedValueVirtual(const State&, int derivOrder, T& value) const
886 override
887 { SimTK_ERRCHK_ALWAYS(!"calcCachedValueVirtual() implemented",
888 "Measure_<T>::Result::getValue()",
889 "Measure_<T>::Result::getValue() was called when the value was not "
890 "yet valid. For most Measure types, this would have initiated "
891 "computation of the value, but Result measures must have their values "
892 "calculated and set externally, and then marked valid."); }
893
894 private:
895 // TOPOLOGY STATE
896 Stage dependsOnStage;
897 Stage invalidatedStage;
898 };
899
900
901
902 //==============================================================================
903 // SINUSOID :: IMPLEMENTATION
904 //==============================================================================
905 template <class T>
906 class Measure_<T>::Sinusoid::Implementation
907 : public Measure_<T>::Implementation
908 {
909 static const int NumDerivs = 3;
910 public:
Implementation()911 Implementation()
912 : Measure_<T>::Implementation(NumDerivs+1),
913 a(CNT<T>::getNaN()), w(CNT<T>::getNaN()), p(CNT<T>::getNaN()) {}
914
915 Implementation(const T& amplitude,
916 const T& frequency,
917 const T& phase=T(0))
918 : Measure_<T>::Implementation(NumDerivs+1),
919 a(amplitude), w(frequency), p(phase) {}
920
921 // Default copy constructor is fine.
922
923 // Implementations of virtual methods.
cloneVirtual()924 Implementation* cloneVirtual() const override
925 { return new Implementation(*this); }
926
getNumTimeDerivativesVirtual()927 int getNumTimeDerivativesVirtual() const override {return NumDerivs;}
928
getDependsOnStageVirtual(int order)929 Stage getDependsOnStageVirtual(int order) const override
930 { return Stage::Time; }
931
calcCachedValueVirtual(const State & s,int derivOrder,T & value)932 void calcCachedValueVirtual(const State& s, int derivOrder, T& value) const
933 override
934 {
935 // We need to allow the compiler to select std::sin or SimTK::sin
936 // based on the argument type.
937 using std::sin; using std::cos;
938
939 assert(NumDerivs == 3);
940 const Real t = s.getTime();
941 const T arg = w*t + p;
942
943 switch (derivOrder) {
944 case 0: value = a*sin(arg); break;
945 case 1: value = w*a*cos(arg); break;
946 case 2: value = -w*w*a*sin(arg); break;
947 case 3: value = -w*w*w*a*cos(arg); break;
948 default: SimTK_ASSERT1_ALWAYS(!"out of range",
949 "Measure::Sinusoid::Implementation::calcCachedValueVirtual():"
950 " derivOrder %d is out of range 0-3.", derivOrder);
951 }
952 }
953
954 // There are no uncached values.
955
956 private:
957 // TOPOLOGY STATE
958 T a, w, p;
959
960 // TOPOLOGY CACHE
961 // nothing
962 };
963
964
965
966 //==============================================================================
967 // PLUS :: IMPLEMENTATION
968 //==============================================================================
969 template <class T>
970 class Measure_<T>::Plus::Implementation : public Measure_<T>::Implementation {
971 public:
972 // TODO: Currently allocates just one cache entry.
973 // left and right will be empty handles.
Implementation()974 Implementation() {}
975
Implementation(const Measure_<T> & left,const Measure_<T> & right)976 Implementation(const Measure_<T>& left,
977 const Measure_<T>& right)
978 : left(left), right(right) {}
979
980 // Default copy constructor gives us a new Implementation object,
981 // but with references to the *same* operand measures.
982
983 // Implementations of virtual methods.
984
985 // This uses the default copy constructor.
cloneVirtual()986 Implementation* cloneVirtual() const override
987 { return new Implementation(*this); }
988
989 // TODO: Let this be settable up to the min number of derivatives
990 // provided by the arguments.
getNumTimeDerivativesVirtual()991 int getNumTimeDerivativesVirtual() const override {return 0;}
992 //{ return std::min(left.getNumTimeDerivatives(),
993 // right.getNumTimeDerivatives()); }
994
getDependsOnStageVirtual(int order)995 Stage getDependsOnStageVirtual(int order) const override
996 { return Stage(std::max(left.getDependsOnStage(order),
997 right.getDependsOnStage(order))); }
998
999
calcCachedValueVirtual(const State & s,int derivOrder,T & value)1000 void calcCachedValueVirtual(const State& s, int derivOrder, T& value) const
1001 override
1002 {
1003 value = left.getValue(s,derivOrder) + right.getValue(s,derivOrder);
1004 }
1005
1006 // There are no uncached values.
1007
1008 private:
1009 // TOPOLOGY STATE
1010 Measure_<T> left;
1011 Measure_<T> right;
1012
1013 // TOPOLOGY CACHE
1014 // nothing
1015 };
1016
1017
1018
1019 //==============================================================================
1020 // MINUS :: IMPLEMENTATION
1021 //==============================================================================
1022 template <class T>
1023 class Measure_<T>::Minus::Implementation : public Measure_<T>::Implementation {
1024 public:
1025 // TODO: Currently allocates just one cache entry.
1026 // left and right will be empty handles.
Implementation()1027 Implementation() {}
1028
Implementation(const Measure_<T> & left,const Measure_<T> & right)1029 Implementation(const Measure_<T>& left,
1030 const Measure_<T>& right)
1031 : left(left), right(right) {}
1032
1033 // Default copy constructor gives us a new Implementation object,
1034 // but with references to the *same* operand measures.
1035
1036 // Implementations of virtual methods.
1037
1038 // This uses the default copy constructor.
cloneVirtual()1039 Implementation* cloneVirtual() const override
1040 { return new Implementation(*this); }
1041
1042 // TODO: Let this be settable up to the min number of derivatives
1043 // provided by the arguments.
getNumTimeDerivativesVirtual()1044 int getNumTimeDerivativesVirtual() const override {return 0;}
1045 //{ return std::min(left.getNumTimeDerivatives(),
1046 // right.getNumTimeDerivatives()); }
1047
getDependsOnStageVirtual(int order)1048 Stage getDependsOnStageVirtual(int order) const override
1049 { return Stage(std::max(left.getDependsOnStage(order),
1050 right.getDependsOnStage(order))); }
1051
1052
calcCachedValueVirtual(const State & s,int derivOrder,T & value)1053 void calcCachedValueVirtual(const State& s, int derivOrder, T& value) const
1054 override
1055 {
1056 value = left.getValue(s,derivOrder) - right.getValue(s,derivOrder);
1057 }
1058
1059 // There are no uncached values.
1060
1061 private:
1062 // TOPOLOGY STATE
1063 Measure_<T> left;
1064 Measure_<T> right;
1065
1066 // TOPOLOGY CACHE
1067 // nothing
1068 };
1069
1070
1071
1072 //==============================================================================
1073 // SCALE :: IMPLEMENTATION
1074 //==============================================================================
1075 template <class T>
1076 class Measure_<T>::Scale::Implementation
1077 : public Measure_<T>::Implementation
1078 {
1079 public:
1080 // TODO: Currently allocates just one cache entry.
1081 // scale will be uninitialized, operand will be empty handle.
Implementation()1082 Implementation() : factor(NaN) {}
1083
Implementation(Real factor,const Measure_<T> & operand)1084 Implementation(Real factor, const Measure_<T>& operand)
1085 : factor(factor), operand(operand) {}
1086
1087 // Default copy constructor gives us a new Implementation object,
1088 // but with references to the *same* operand measure.
1089
setScaleFactor(Real sf)1090 void setScaleFactor(Real sf) {
1091 factor = sf;
1092 this->invalidateTopologyCache();
1093 }
1094
getOperandMeasure()1095 const Measure_<T>& getOperandMeasure() const
1096 {
1097 return operand;
1098 }
1099
1100 // Implementations of virtual methods.
1101
1102 // This uses the default copy constructor.
cloneVirtual()1103 Implementation* cloneVirtual() const override
1104 { return new Implementation(*this); }
1105
1106 // TODO: Let this be settable up to the min number of derivatives
1107 // provided by the arguments.
getNumTimeDerivativesVirtual()1108 int getNumTimeDerivativesVirtual() const override {return 0;}
1109 //{ return std::min(left.getNumTimeDerivatives(),
1110 // right.getNumTimeDerivatives()); }
1111
getDependsOnStageVirtual(int order)1112 Stage getDependsOnStageVirtual(int order) const override
1113 { return operand.getDependsOnStage(order); }
1114
1115
calcCachedValueVirtual(const State & s,int derivOrder,T & value)1116 void calcCachedValueVirtual(const State& s, int derivOrder, T& value) const
1117 override
1118 {
1119 value = factor * operand.getValue(s,derivOrder);
1120 }
1121
1122 // There are no uncached values.
1123
1124 private:
1125 // TOPOLOGY STATE
1126 Real factor;
1127 Measure_<T> operand;
1128
1129 // TOPOLOGY CACHE
1130 // nothing
1131 };
1132
1133
1134
1135 //==============================================================================
1136 // INTEGRATE :: IMPLEMENTATION
1137 //==============================================================================
1138 /** The implementation for %Integrate measures allocates a continuous state
1139 variable or variables from the State's z pool and generates zdot values to be
1140 integrated into those z variables. The z's are then copied into a type T,
1141 Time-stage cache entry so that we can return the value as a type T reference.
1142 Derivative requests are passed through to the integrand so only one cache
1143 entry is required here. **/
1144 template <class T>
1145 class Measure_<T>::Integrate::Implementation
1146 : public Measure_<T>::Implementation {
1147 public:
1148 /** The derivative and initialConditions Measures will be empty handles if
1149 this is default constructed. **/
Implementation()1150 Implementation() : Measure_<T>::Implementation(1) {}
1151
1152 /** Here we're shallow-copying the Measure handles so we'll be referring to
1153 the original Measures. **/
Implementation(const Measure_<T> & deriv,const Measure_<T> & ic,const T & defaultValue)1154 Implementation(const Measure_<T>& deriv, const Measure_<T>& ic,
1155 const T& defaultValue)
1156 : Measure_<T>::Implementation(defaultValue, 1),
1157 derivMeasure(deriv), icMeasure(ic) {}
1158
1159 /** Copy constructor shallow-copies the referenced measures, but we don't
1160 want to share our state variables. **/
Implementation(const Implementation & source)1161 Implementation(const Implementation& source)
1162 : Measure_<T>::Implementation(source.getDefaultValue(), 1),
1163 derivMeasure(source.derivMeasure), icMeasure(source.icMeasure) {}
1164
1165 /** Set the value of the state variables(s) that hold the integral. This
1166 cannot be used to change the size if the type T is a Vector; the supplied
1167 \a value must be the same length as the default value of this %Measure. **/
setValue(State & s,const T & value)1168 void setValue(State& s, const T& value) const
1169 { assert(zIndex >= 0);
1170 for (int i=0; i < this->size(); ++i)
1171 this->getSubsystem().updZ(s)[zIndex+i] =
1172 Measure_Num<T>::get(value, i); }
1173
getDerivativeMeasure()1174 const Measure_<T>& getDerivativeMeasure() const
1175 { SimTK_ERRCHK(!derivMeasure.isEmptyHandle(),
1176 "Measure_<T>::Integrate::getDerivativeMeasure()",
1177 "No derivative measure is available for this integrated measure.");
1178 return derivMeasure; }
1179
getInitialConditionMeasure()1180 const Measure_<T>& getInitialConditionMeasure() const
1181 { SimTK_ERRCHK(!icMeasure.isEmptyHandle(),
1182 "Measure_<T>::Integrate::getInitialConditionMeasure()",
1183 "No initial condition measure is available for this "
1184 "integrated measure.");
1185 return icMeasure; }
1186
setDerivativeMeasure(const Measure_<T> & d)1187 void setDerivativeMeasure(const Measure_<T>& d)
1188 { derivMeasure = d; this->invalidateTopologyCache(); }
setInitialConditionMeasure(const Measure_<T> & ic)1189 void setInitialConditionMeasure(const Measure_<T>& ic)
1190 { icMeasure = ic; this->invalidateTopologyCache(); }
1191
1192 // Implementations of virtuals.
1193
1194 // This uses the copy constructor defined above.
cloneVirtual()1195 Implementation* cloneVirtual() const override
1196 { return new Implementation(*this); }
1197
1198 /** This measure has one more time derivative than the integrand. **/
getNumTimeDerivativesVirtual()1199 int getNumTimeDerivativesVirtual() const override
1200 { int integralDerivs = getDerivativeMeasure().getNumTimeDerivatives();
1201 // Careful - can't add 1 to max int and stay an int.
1202 if (integralDerivs < std::numeric_limits<int>::max())
1203 ++integralDerivs;
1204 return integralDerivs; }
1205
calcCachedValueVirtual(const State & s,int derivOrder,T & value)1206 void calcCachedValueVirtual(const State& s, int derivOrder, T& value) const
1207 override
1208 { assert(derivOrder == 0); // only one cache entry
1209 assert(Measure_Num<T>::size(value) == this->size());
1210 assert(zIndex.isValid());
1211 const Vector& allZ = this->getSubsystem().getZ(s);
1212 for (int i=0; i < this->size(); ++i)
1213 Measure_Num<T>::upd(value,i) = allZ[zIndex+i];
1214 }
1215
getUncachedValueVirtual(const State & s,int derivOrder)1216 const T& getUncachedValueVirtual(const State& s, int derivOrder) const
1217 override
1218 { assert(derivOrder > 0); // 0th entry is cached
1219 return getDerivativeMeasure().getValue(s, derivOrder-1);
1220 }
1221
getDependsOnStageVirtual(int derivOrder)1222 Stage getDependsOnStageVirtual(int derivOrder) const override
1223 { return derivOrder>0
1224 ? getDerivativeMeasure().getDependsOnStage(derivOrder-1)
1225 : Stage::Time; }
1226
1227 /** Initialize the state to the current value of the initial condition
1228 measure, if there is one, otherwise to the default value. **/
initializeVirtual(State & s)1229 void initializeVirtual(State& s) const override {
1230 assert(zIndex.isValid());
1231 Vector& allZ = this->getSubsystem().updZ(s);
1232 if (!icMeasure.isEmptyHandle()) {
1233 this->getSubsystem().getSystem()
1234 .realize(s, icMeasure.getDependsOnStage());
1235 const T& ic = icMeasure.getValue(s);
1236 for (int i=0; i < this->size(); ++i)
1237 allZ[zIndex+i] = Measure_Num<T>::get(ic,i);
1238 } else {
1239 for (int i=0; i < this->size(); ++i)
1240 allZ[zIndex+i] = Measure_Num<T>::get(this->getDefaultValue(),i);
1241 }
1242 }
1243
1244 /** Allocate one Real continuous state variable z per element of this
1245 %Measure's data type T, using the default value to determine
1246 how many are needed (if that's not part of the type T), and initialize them
1247 to the corresponding element from the default value. **/
realizeMeasureTopologyVirtual(State & s)1248 void realizeMeasureTopologyVirtual(State& s) const override {
1249 Vector init(this->size());
1250 for (int i=0; i < this->size(); ++i)
1251 init[i] = Measure_Num<T>::get(this->getDefaultValue(),i);
1252 zIndex = this->getSubsystem().allocateZ(s, init);
1253 }
1254
1255 /** Set the zdots to the integrand (derivative measure) value. If no
1256 integrand was provided it is treated as though it were zero. **/
realizeMeasureAccelerationVirtual(const State & s)1257 void realizeMeasureAccelerationVirtual(const State& s) const override {
1258 assert(zIndex.isValid());
1259 Vector& allZDot = this->getSubsystem().updZDot(s);
1260 if (!derivMeasure.isEmptyHandle()) {
1261 const T& deriv = derivMeasure.getValue(s);
1262 for (int i=0; i < this->size(); ++i)
1263 allZDot[zIndex+i] = Measure_Num<T>::get(deriv,i);
1264 } else {
1265 allZDot(zIndex,this->size()) = 0; // derivative is zero
1266 }
1267 }
1268
1269 private:
1270 // TOPOLOGY STATE
1271 Measure_<T> derivMeasure; // just handles
1272 Measure_<T> icMeasure;
1273
1274 // TOPOLOGY CACHE
1275 mutable ZIndex zIndex; // This is the first index if more than one z.
1276 };
1277
1278
1279
1280 //==============================================================================
1281 // DIFFERENTIATE :: IMPLEMENTATION
1282 //==============================================================================
1283
1284 /** @cond **/ // Hide from Doxygen.
1285 // This helper class is the contents of the discrete state variable and
1286 // corresponding cache entry maintained by this measure. The variable is
1287 // auto-update, meaning the value of the cache entry replaces the state
1288 // variable at the start of each step.
1289 // TODO: This was a local class in Measure_<T>::Differentiate::Implementation
1290 // but VC++ 8 (2005) failed to properly instantiate the templatized operator<<()
1291 // in that case; doing it this way is a workaround.
1292 template <class T>
1293 class Measure_Differentiate_Result {
1294 public:
Measure_Differentiate_Result()1295 Measure_Differentiate_Result() : derivIsGood(false) {}
1296 T operand; // previous value of operand
1297 T operandDot; // previous value of derivative
1298 bool derivIsGood; // do we think the deriv is a good one?
1299 };
1300 /** @endcond **/
1301
1302 template <class T>
1303 class Measure_<T>::Differentiate::Implementation
1304 : public Measure_<T>::Implementation
1305 {
1306 typedef Measure_Differentiate_Result<T> Result;
1307 public:
1308 // Don't allocate any cache entries in the base class.
Implementation()1309 Implementation() : Measure_<T>::Implementation(0) {}
1310
Implementation(const Measure_<T> & operand)1311 Implementation(const Measure_<T>& operand)
1312 : Measure_<T>::Implementation(0),
1313 operand(operand), forceUseApprox(false), isApproxInUse(false) {}
1314
1315 // Default copy constructor gives us a new Implementation object,
1316 // but with reference to the *same* operand measure.
1317
setForceUseApproximation(bool mustApproximate)1318 void setForceUseApproximation(bool mustApproximate) {
1319 forceUseApprox = mustApproximate;
1320 this->invalidateTopologyCache();
1321 }
1322
setOperandMeasure(const Measure_<T> & operand)1323 void setOperandMeasure(const Measure_<T>& operand) {
1324 this->operand = operand;
1325 this->invalidateTopologyCache();
1326 }
1327
getForceUseApproximation()1328 bool getForceUseApproximation() const {return forceUseApprox;}
isUsingApproximation()1329 bool isUsingApproximation() const {return isApproxInUse;}
getOperandMeasure()1330 const Measure_<T>& getOperandMeasure() const {return operand;}
1331
1332 // Implementations of virtual methods.
1333
1334 // This uses the default copy constructor.
cloneVirtual()1335 Implementation* cloneVirtual() const override
1336 { return new Implementation(*this); }
1337
1338 // This has one fewer than the operand.
getNumTimeDerivativesVirtual()1339 int getNumTimeDerivativesVirtual() const override
1340 { if (!isApproxInUse) return operand.getNumTimeDerivatives()-1;
1341 else return 0; }
1342
getDependsOnStageVirtual(int order)1343 Stage getDependsOnStageVirtual(int order) const override
1344 { if (!isApproxInUse) return operand.getDependsOnStage(order+1);
1345 else return operand.getDependsOnStage(order); }
1346
1347
1348 // We're not using the Measure_<T> base class cache services, but
1349 // we do have one of our own. It looks uncached from the base class
1350 // point of view which is why we're implementing it here.
getUncachedValueVirtual(const State & s,int derivOrder)1351 const T& getUncachedValueVirtual(const State& s, int derivOrder) const
1352 override
1353 { if (!isApproxInUse)
1354 return operand.getValue(s, derivOrder+1);
1355
1356 ensureDerivativeIsRealized(s);
1357 const Subsystem& subsys = this->getSubsystem();
1358 const Result& result = Value<Result>::downcast
1359 (subsys.getDiscreteVarUpdateValue(s,resultIx));
1360 return result.operandDot; // has a value but might not be a good one
1361 }
1362
initializeVirtual(State & s)1363 void initializeVirtual(State& s) const override {
1364 if (!isApproxInUse) return;
1365
1366 assert(resultIx.isValid());
1367 const Subsystem& subsys = this->getSubsystem();
1368 Result& result = Value<Result>::updDowncast
1369 (subsys.updDiscreteVariable(s,resultIx));
1370 this->getSubsystem().getSystem().realize(s,operand.getDependsOnStage());
1371 result.operand = operand.getValue(s);
1372 result.operandDot = this->getValueZero();
1373 result.derivIsGood = false;
1374 }
1375
realizeMeasureTopologyVirtual(State & s)1376 void realizeMeasureTopologyVirtual(State& s) const override {
1377 isApproxInUse = (forceUseApprox || operand.getNumTimeDerivatives()==0);
1378 if (!isApproxInUse)
1379 return;
1380
1381 resultIx = this->getSubsystem()
1382 .allocateAutoUpdateDiscreteVariable(s, operand.getDependsOnStage(0),
1383 new Value<Result>(), operand.getDependsOnStage(0));
1384 }
1385
1386 /** In case no one has updated the value of this measure yet, we have
1387 to make sure it gets updated before the integration moves ahead. **/
realizeMeasureAccelerationVirtual(const State & s)1388 void realizeMeasureAccelerationVirtual(const State& s) const override {
1389 ensureDerivativeIsRealized(s);
1390 }
1391
ensureDerivativeIsRealized(const State & s)1392 void ensureDerivativeIsRealized(const State& s) const {
1393 assert(resultIx.isValid());
1394 const Subsystem& subsys = this->getSubsystem();
1395 if (subsys.isDiscreteVarUpdateValueRealized(s,resultIx))
1396 return;
1397
1398 const Real t0 = subsys.getDiscreteVarLastUpdateTime(s,resultIx);
1399 const Result& prevResult = Value<Result>::downcast
1400 (subsys.getDiscreteVariable(s,resultIx));
1401 const T& f0 = prevResult.operand;
1402 const T& fdot0 = prevResult.operandDot; // may be invalid
1403 const bool good0 = prevResult.derivIsGood;
1404
1405 const Real t = s.getTime();
1406 Result& result = Value<Result>::updDowncast
1407 (subsys.updDiscreteVarUpdateValue(s,resultIx));
1408 T& f = result.operand; // renaming
1409 T& fdot = result.operandDot;
1410 bool& good = result.derivIsGood;
1411
1412 f = operand.getValue(s);
1413 good = false;
1414 if (!isFinite(t0))
1415 fdot = this->getValueZero();
1416 else if (t == t0) {
1417 fdot = fdot0;
1418 good = good0;
1419 } else {
1420 fdot = (f-f0)/(t-t0); // 1st order
1421 if (good0)
1422 fdot = Real(2)*fdot - fdot0; // now 2nd order
1423 good = true; // either 1st or 2nd order estimate
1424 }
1425 subsys.markDiscreteVarUpdateValueRealized(s,resultIx);
1426 }
1427 private:
1428 // TOPOLOGY STATE
1429 Measure_<T> operand;
1430 bool forceUseApprox;
1431
1432 // TOPOLOGY CACHE
1433 mutable bool isApproxInUse;
1434 mutable DiscreteVariableIndex resultIx; // auto-update
1435 };
1436
1437
1438
1439 //==============================================================================
1440 // EXTREME :: IMPLEMENTATION
1441 //==============================================================================
1442 template <class T>
1443 class Measure_<T>::Extreme::Implementation : public Measure_<T>::Implementation
1444 {
1445 typedef typename Measure_<T>::Extreme Extreme;
1446 typedef typename Extreme::Operation Operation;
1447 public:
1448 /** Default constructor leaves the operand measure unspecified; no base
1449 class cache entries are allocated. **/
Implementation()1450 Implementation()
1451 : Measure_<T>::Implementation(0), operation(Extreme::MaxAbs) {}
1452
1453 /** Construct a measure that returns the extreme value taken on by the
1454 operand measure during a time stepping study. **/
Implementation(const Measure_<T> & operand,Operation op)1455 Implementation(const Measure_<T>& operand, Operation op)
1456 : Measure_<T>::Implementation(0), operand(operand), operation(op) {}
1457
1458 // Default copy constructor gives us a new Implementation object,
1459 // but with reference to the *same* operand measure.
1460
1461 /** Set the operand measure for this %Extreme measure; this is a Topology
1462 stage change so you'll have to call realizeTopology() again if you call
1463 this. **/
setOperandMeasure(const Measure_<T> & operand)1464 void setOperandMeasure(const Measure_<T>& operand) {
1465 this->operand = operand;
1466 this->invalidateTopologyCache();
1467 }
1468
1469 /** Set the particular operation to be performed by this %Extreme measure;
1470 this is a Topology stage change so you'll have to call realizeTopology()
1471 again if you call this. **/
setOperation(Operation op)1472 void setOperation(Operation op) {
1473 this->operation = op;
1474 this->invalidateTopologyCache();
1475 }
1476
1477 /** Return a reference to the operand measure for this %Extreme measure. **/
getOperandMeasure()1478 const Measure_<T>& getOperandMeasure() const {return operand;}
1479
1480 /** Return the particular operation being performed by this %Extreme
1481 measure. **/
getOperation()1482 Operation getOperation() const {return operation;}
1483
1484 /** Set the current extreme value stored in this %Extreme measure's state
1485 variable. **/
setValue(State & s,const T & value)1486 void setValue(State& s, const T& value) const {
1487 assert(extremeIx.isValid());
1488 const Subsystem& subsys = this->getSubsystem();
1489 T& prevMin = Value<T>::updDowncast
1490 (subsys.updDiscreteVariable(s,extremeIx));
1491 prevMin = value;
1492 }
1493
1494 /** Return the time at which the extreme was last updated. This will be
1495 the current time if the operand is currently at its most extreme value,
1496 otherwise it will be sometime in the past. **/
getTimeOfExtremeValue(const State & s)1497 Real getTimeOfExtremeValue(const State& s) const {
1498 const Subsystem& subsys = this->getSubsystem();
1499 const bool hasNewExtreme = ensureExtremeHasBeenUpdated(s);
1500 Real tUpdate;
1501 if (hasNewExtreme)
1502 tUpdate = s.getTime(); // i.e., now
1503 else
1504 tUpdate = subsys.getDiscreteVarLastUpdateTime(s,extremeIx);
1505 return tUpdate;
1506 }
1507
1508 // Implementations of virtual methods.
1509
1510 // This uses the default copy constructor.
cloneVirtual()1511 Implementation* cloneVirtual() const override
1512 { return new Implementation(*this); }
1513
1514 /** Extreme(f(t)) has the same number of derivatives as f except that
1515 they are all zero unless f(t) is a new extreme. **/
getNumTimeDerivativesVirtual()1516 int getNumTimeDerivativesVirtual() const override
1517 { return operand.getNumTimeDerivatives(); }
1518
1519 /** The depends-on stage for this measure is the same as for its
1520 operand. **/
getDependsOnStageVirtual(int order)1521 Stage getDependsOnStageVirtual(int order) const override
1522 { return operand.getDependsOnStage(order); }
1523
1524
1525 /** We're not using the Measure_<T> base class cache services, but
1526 we do have one of our own. It looks uncached from the base class
1527 point of view which is why we're implementing it here. **/
getUncachedValueVirtual(const State & s,int derivOrder)1528 const T& getUncachedValueVirtual(const State& s, int derivOrder) const
1529 override
1530 {
1531 const Subsystem& subsys = this->getSubsystem();
1532 const bool hasNewExtreme = ensureExtremeHasBeenUpdated(s);
1533 if (derivOrder > 0) {
1534 // TODO: should be handled elementwise and zero unless the
1535 // derivative is acting in the direction that changes the
1536 // extreme.
1537 return hasNewExtreme ? operand.getValue(s, derivOrder)
1538 : this->getValueZero();
1539 }
1540 if (hasNewExtreme) {
1541 const T& newExt = Value<T>::downcast
1542 (subsys.getDiscreteVarUpdateValue(s,extremeIx));
1543 return newExt;
1544 } else {
1545 const T& currentExt = Value<T>::downcast
1546 (subsys.getDiscreteVariable(s,extremeIx));
1547 return currentExt;
1548 }
1549 }
1550
1551 /** At start of a time stepping study, this should be called to set the
1552 current extreme value to the current value of the operand. **/
initializeVirtual(State & s)1553 void initializeVirtual(State& s) const override {
1554 this->getSubsystem().getSystem().realize(s,operand.getDependsOnStage());
1555 setValue(s, operand.getValue(s));
1556 }
1557
1558 /** Allocate the auto-updated state variable that holds the extreme seen
1559 so far. We'll assume that changes to this variable invalidate Dynamics
1560 (force) stage so that any forces that depend on it will be recomputed if
1561 it changes. Also allocate an auxiliary boolean variable that is used to hold
1562 whether the current value is a new extreme; that is private to the
1563 implementation and not user-accessible since you can instead check the
1564 time of last update. **/
realizeMeasureTopologyVirtual(State & s)1565 void realizeMeasureTopologyVirtual(State& s) const override {
1566 // TODO: this should be NaN once initialization is working properly.
1567 T initVal = this->getDefaultValue();
1568 switch(operation) {
1569 case Minimum: initVal = Infinity; break;
1570 case Maximum: initVal = -Infinity; break;
1571 case MinAbs: initVal = Infinity; break;
1572 case MaxAbs: initVal = 0; break;
1573 };
1574
1575 extremeIx = this->getSubsystem()
1576 .allocateAutoUpdateDiscreteVariable(s, Stage::Dynamics,
1577 new Value<T>(initVal), operand.getDependsOnStage(0));
1578
1579 isNewExtremeIx = this->getSubsystem()
1580 .allocateAutoUpdateDiscreteVariable(s, Stage::Dynamics,
1581 new Value<bool>(false), operand.getDependsOnStage(0));
1582 }
1583
1584 /** In case no one has updated the value of this measure yet, we have
1585 to make sure it gets updated before the integration moves ahead. **/
realizeMeasureAccelerationVirtual(const State & s)1586 void realizeMeasureAccelerationVirtual(const State& s) const override {
1587 ensureExtremeHasBeenUpdated(s);
1588 }
1589
1590 /** Here we make sure that the cache entry is updated if the current value
1591 of the operand is more extreme than the previous one, and return a bool
1592 indicating whether we have a new extreme. We don't want to create an update
1593 entry unless the extreme value has changed, because we would like the state
1594 variable's last update value to reflect the last actual change. **/
ensureExtremeHasBeenUpdated(const State & s)1595 bool ensureExtremeHasBeenUpdated(const State& s) const {
1596 assert(extremeIx.isValid() && isNewExtremeIx.isValid());
1597 const Subsystem& subsys = this->getSubsystem();
1598
1599 // We may have already determined whether we're at a new extreme in
1600 // which case we don't need to do it again.
1601 if (subsys.isDiscreteVarUpdateValueRealized(s, isNewExtremeIx))
1602 return Value<bool>::downcast
1603 (subsys.getDiscreteVarUpdateValue(s,isNewExtremeIx));
1604
1605 // We're going to have to decide if we're at a new extreme, and if
1606 // so record the new extreme value in the auto-update cache entry of
1607 // the extreme value state variable.
1608
1609 // Get the previous extreme value and the current operand value.
1610 const T& prevExtreme = Value<T>::downcast
1611 (subsys.getDiscreteVariable(s,extremeIx));
1612 const T& currentVal = operand.getValue(s);
1613
1614 // Search to see if any element has reached a new extreme.
1615 bool foundNewExt = false;
1616 for (int i=0; i < this->size() && !foundNewExt; ++i)
1617 foundNewExt = isNewExtreme(Measure_Num<T>::get(currentVal,i),
1618 Measure_Num<T>::get(prevExtreme,i));
1619
1620 // Record the result and mark the auto-update cache entry valid
1621 // so we won't have to recalculate. When the integrator advances to the
1622 // next step this cache entry will be swapped with the corresponding
1623 // state and marked invalid so we'll be sure to recalculate each step.
1624 Value<bool>::updDowncast
1625 (subsys.updDiscreteVarUpdateValue(s,isNewExtremeIx)) = foundNewExt;
1626 subsys.markDiscreteVarUpdateValueRealized(s,isNewExtremeIx);
1627
1628 // Don't update the auto-update cache entry if we didn't see a new
1629 // extreme. That way no auto-update will occur and the state variable
1630 // will remain unchanged with the existing update time preserved.
1631 if (!foundNewExt)
1632 return false;
1633
1634 // We have encountered a new extreme. We'll record the new extreme
1635 // in the auto-update cache entry which will be used as the current
1636 // result until the integrator advances to the next step at which time
1637 // this will be swapped with the state variable to serve as the previous
1638 // extreme value until a further extreme is encountered.
1639 T& newExtreme = Value<T>::updDowncast
1640 (subsys.updDiscreteVarUpdateValue(s,extremeIx));
1641
1642 for (int i=0; i < this->size(); ++i)
1643 Measure_Num<T>::upd(newExtreme,i) =
1644 extremeOf(Measure_Num<T>::get(currentVal,i),
1645 Measure_Num<T>::get(prevExtreme,i));
1646
1647 // Marking this valid is what ensures that an auto-update occurs later.
1648 subsys.markDiscreteVarUpdateValueRealized(s,extremeIx);
1649 return true;
1650 }
1651 private:
1652 // Return true if newVal is "more extreme" than oldExtreme, according
1653 // to the operation we're performing.
isNewExtreme(const typename Measure_Num<T>::Element & newVal,const typename Measure_Num<T>::Element & oldExtreme)1654 bool isNewExtreme(const typename Measure_Num<T>::Element& newVal,
1655 const typename Measure_Num<T>::Element& oldExtreme) const
1656 {
1657 switch (operation) {
1658 case Extreme::Maximum: return newVal > oldExtreme;
1659 case Extreme::Minimum: return newVal < oldExtreme;
1660 case Extreme::MaxAbs: return std::abs(newVal) > std::abs(oldExtreme);
1661 case Extreme::MinAbs: return std::abs(newVal) < std::abs(oldExtreme);
1662 };
1663 SimTK_ASSERT1_ALWAYS(!"recognized",
1664 "Measure::Extreme::Implementation::isNewExtreme(): "
1665 "unrecognized operation %d", (int)operation);
1666 return false; /*NOTREACHED*/
1667 }
1668
1669 // Given the value of one element of the operand, and that value's time
1670 // derivative, determine whether the derivative is moving the element
1671 // into the "more extreme" direction, according to the operation.
isExtremeDir(const typename Measure_Num<T>::Element & value,const typename Measure_Num<T>::Element & deriv)1672 bool isExtremeDir(const typename Measure_Num<T>::Element& value,
1673 const typename Measure_Num<T>::Element& deriv) const
1674 {
1675 const int sv = sign(value), sd = sign(deriv);
1676 if (sd == 0) return false; // derivative is zero; not changing
1677 switch (operation) {
1678 case Extreme::Maximum: return sd == 1; // getting larger
1679 case Extreme::Minimum: return sd == -1; // getting smaller
1680 case Extreme::MaxAbs: return sv==0 || sd==sv; // abs is growing
1681 case Extreme::MinAbs: return sd == -sv;
1682 };
1683 SimTK_ASSERT1_ALWAYS(!"recognized",
1684 "Measure::Extreme::Implementation::isExtremeDir(): "
1685 "unrecognized operation %d", (int)operation);
1686 return false; /*NOTREACHED*/
1687 }
1688
1689 typename Measure_Num<T>::Element
extremeOf(const typename Measure_Num<T>::Element & newVal,const typename Measure_Num<T>::Element & oldExtreme)1690 extremeOf(const typename Measure_Num<T>::Element& newVal,
1691 const typename Measure_Num<T>::Element& oldExtreme) const
1692 {
1693 return isNewExtreme(newVal,oldExtreme) ? newVal : oldExtreme;
1694 }
1695
1696 // TOPOLOGY STATE
1697 Measure_<T> operand;
1698 Operation operation;
1699
1700 // TOPOLOGY CACHE
1701 mutable DiscreteVariableIndex extremeIx; // extreme so far; auto-update
1702
1703 // This auto-update flag records whether the current value is a new
1704 // extreme. We don't really need to save it as a state variable since you
1705 // can figure this out from the timestamp, but we need to to get invalidated
1706 // by the auto-update swap so that we'll figure it out anew each step.
1707 mutable DiscreteVariableIndex isNewExtremeIx;
1708 };
1709
1710
1711
1712 //==============================================================================
1713 // DELAY :: IMPLEMENTATION
1714 //==============================================================================
1715 /** @cond **/ // Hide from Doxygen.
1716 // This helper class is the contents of the discrete state variable and
1717 // corresponding cache entry maintained by this measure. The variable is
1718 // auto-update, meaning the value of the cache entry replaces the state
1719 // variable at the start of each step.
1720 //
1721 // Circular buffers look like this:
1722 //
1723 // oldest=0, n=0
1724 // v
1725 // Empty buffer: | available |
1726 //
1727 // By convention, oldest=0 whenever the buffer is empty.
1728 //
1729 //
1730 // oldest next=(oldest+n)%capacity
1731 // v v
1732 // | available | | | | | | | available |
1733 // ^ n=6 ^
1734 // 0 capacity
1735 // v v
1736 // or | | | | | | available | | | | | | | | n=12
1737 // ^ ^
1738 // next oldest
1739 // = (oldest+n)%capacity
1740 //
1741 // Number of entries = n (called size() below)
1742 // Empty = n==0
1743 // Full = n==capacity()
1744 // Next available = (oldest+n)%capacity()
1745 template <class T>
1746 class Measure_Delay_Buffer {
1747 public:
Measure_Delay_Buffer()1748 explicit Measure_Delay_Buffer() {initDataMembers();}
clear()1749 void clear() {initDataMembers();}
size()1750 int size() const {return m_size;} // # saved entries, *not* size of arrays
capacity()1751 int capacity() const {return m_times.size();}
empty()1752 bool empty() const {return size()==0;}
full()1753 bool full() const {return size()==capacity();}
1754
getEntryTime(int i)1755 double getEntryTime(int i) const
1756 { assert(i < size()); return m_times[getArrayIndex(i)];}
getEntryValue(int i)1757 const T& getEntryValue(int i) const
1758 { assert(i < size()); return m_values[getArrayIndex(i)];}
1759
1760 enum {
1761 InitialAllocation = 8, // smallest allocation
1762 GrowthFactor = 2, // how fast to grow (double)
1763 MaxShrinkProofSize = 16, // won't shrink unless bigger
1764 TooBigFactor = 5 // 5X too much->maybe shrink
1765 };
1766
1767 // Add a new entry to the end of the list, throwing out old entries that
1768 // aren't needed to answer requests at tEarliest or later.
append(double tEarliest,double tNow,const T & valueNow)1769 void append(double tEarliest, double tNow, const T& valueNow) {
1770 forgetEntriesMuchOlderThan(tEarliest);
1771 removeEntriesLaterOrEq(tNow);
1772 if (full())
1773 makeMoreRoom();
1774 else if (capacity() > std::max((int)MaxShrinkProofSize,
1775 (int)TooBigFactor * (size()+1)))
1776 makeLessRoom(); // less than 1/TooBigFactor full
1777 const int nextFree = getArrayIndex(m_size++);
1778 m_times[nextFree] = tNow;
1779 m_values[nextFree] = valueNow;
1780 m_maxSize = std::max(m_maxSize, size());
1781 }
1782
1783 // Prepend an older entry to the beginning of the list. No cleanup is done.
prepend(double tNewOldest,const T & value)1784 void prepend(double tNewOldest, const T& value) {
1785 assert(empty() || tNewOldest < m_times[m_oldest]);
1786 if (full()) makeMoreRoom();
1787 m_oldest = empty() ? 0 : getArrayIndex(-1);
1788 m_times[m_oldest] = tNewOldest;
1789 m_values[m_oldest] = value;
1790 ++m_size;
1791 m_maxSize = std::max(m_maxSize, size());
1792 }
1793
1794 // This is a specialized copy assignment for copying an old buffer
1795 // to a new one with updated contents. We are told the earliest time we'll
1796 // be asked about from now on, and won't copy any entries older than those
1797 // needed to answer that earliest request. We won't copy anything at or
1798 // newer than tNow, and finally we'll push (tNow,valueNow) as the newest
1799 // entry.
copyInAndUpdate(const Measure_Delay_Buffer & oldBuf,double tEarliest,double tNow,const T & valueNow)1800 void copyInAndUpdate(const Measure_Delay_Buffer& oldBuf, double tEarliest,
1801 double tNow, const T& valueNow) {
1802 // clear all current entries (no heap activity)
1803 m_oldest = m_size = 0;
1804
1805 // determine how may old entries we have to keep
1806 int firstNeeded = oldBuf.countNumUnneededOldEntries(tEarliest);
1807 int lastNeeded = oldBuf.findLastEarlier(tNow); // might be -1
1808 int numOldEntriesToKeep = lastNeeded-firstNeeded+1;
1809 int newSize = numOldEntriesToKeep+1; // includes the new one
1810
1811 int newSizeRequest = -1;
1812 if (capacity() < newSize) {
1813 newSizeRequest = std::max((int)InitialAllocation,
1814 (int)GrowthFactor * newSize);
1815 ++m_nGrows;
1816 } else if (capacity() > std::max((int)MaxShrinkProofSize,
1817 (int)TooBigFactor * newSize)) {
1818 newSizeRequest = std::max((int)MaxShrinkProofSize,
1819 (int)GrowthFactor * newSize);
1820 ++m_nShrinks;
1821 }
1822
1823 // Reallocate space if advisable.
1824 if (newSizeRequest != -1) {
1825 const double dNaN = NTraits<double>::getNaN();
1826 m_values.resize(newSizeRequest);
1827 if (m_values.capacity() > m_values.size())
1828 m_values.resize(m_values.capacity()); // don't waste any
1829 m_times.resize(m_values.size(), dNaN);
1830 }
1831
1832 m_maxCapacity = std::max(m_maxCapacity, capacity());
1833
1834 // Copy the entries we need to keep.
1835 int nxt = 0;
1836 for (int i=firstNeeded; i<=lastNeeded; ++i, ++nxt) {
1837 m_times[nxt] = oldBuf.getEntryTime(i);
1838 m_values[nxt] = oldBuf.getEntryValue(i);
1839 }
1840 // Now add the newest entry and set the size.
1841 m_times[nxt] = tNow;
1842 m_values[nxt] = valueNow;
1843 assert(nxt+1==newSize);
1844 m_size = nxt+1;
1845 m_maxSize = std::max(m_maxSize, size());
1846 }
1847
1848 // Given the current time and value and the earlier time at which the
1849 // value is needed, use the buffer and (if necessary) the current value
1850 // to estimate the delayed value.
1851 T calcValueAtTime(double tDelay, double tNow, const T& valueNow) const;
1852
1853 // Given the current time but *not* the current value of the source measure,
1854 // provide an estimate for the value at tDelay=tNow-delay using only the
1855 // buffer contents and linear interpolation or extrapolation.
calcValueAtTimeLinearOnly(double tDelay,T & delayedValue)1856 void calcValueAtTimeLinearOnly(double tDelay, T& delayedValue) const {
1857 if (empty()) {
1858 // Nothing in the buffer?? Shouldn't happen. Return empty Vector
1859 // or NaN for fixed-size types.
1860 Measure_Num<T>::makeNaNLike(T(), delayedValue);
1861 return;
1862 }
1863
1864 int firstLater = findFirstLaterOrEq(tDelay);
1865
1866 if (firstLater > 0) {
1867 // Normal case: tDelay is between two buffer entries.
1868 int firstEarlier = firstLater-1;
1869 double t0=getEntryTime(firstEarlier), t1=getEntryTime(firstLater);
1870 const T& v0=getEntryValue(firstEarlier);
1871 const T& v1=getEntryValue(firstLater);
1872 Real fraction = Real((tDelay-t0)/(t1-t0));
1873 delayedValue = T(v0 + fraction*(v1-v0));
1874 return;
1875 }
1876
1877 if (firstLater==0) {
1878 // Startup case: tDelay is at or before the oldest buffer entry.
1879 // Assume the value was flat before that.
1880 delayedValue = getEntryValue(firstLater);
1881 return;
1882 }
1883
1884 // tDelay is later than the latest entry in the buffer. We are going
1885 // to have to extrapolate (yuck).
1886
1887 if (size() == 1) {
1888 // Just one entry; we'll have to assume the value is flat.
1889 delayedValue = getEntryValue(0);
1890 return;
1891 }
1892
1893 // Extrapolate using the last two entries.
1894 double t0=getEntryTime(size()-2), t1=getEntryTime(size()-1);
1895 const T& v0=getEntryValue(size()-2);
1896 const T& v1=getEntryValue(size()-1);
1897 Real fraction = Real((tDelay-t0)/(t1-t0)); // > 1
1898 assert(fraction > 1.0);
1899 delayedValue = T(v0 + fraction*(v1-v0)); // Extrapolate.
1900 }
1901
1902 // Return the number of times we had to grow the buffer.
getNumGrows()1903 int getNumGrows() const {return m_nGrows;}
1904 // Return the number of times we decided the buffer was so overallocated
1905 // that we had to shrink it.
getNumShrinks()1906 int getNumShrinks() const {return m_nShrinks;}
1907 // Return the largest number of values we ever had in the buffer.
getMaxSize()1908 int getMaxSize() const {return m_maxSize;}
1909 // Return the largest capacity the buffer ever had.
getMaxCapacity()1910 int getMaxCapacity() const {return m_maxCapacity;}
1911
1912 private:
1913 // Return the i'th oldest entry
1914 // (0 -> oldest, size-1 -> newest, size -> first free, -1 -> last free)
getArrayIndex(int i)1915 int getArrayIndex(int i) const
1916 { assert(-1<=i && i<=size());
1917 const int rawIndex = m_oldest + i;
1918 if (rawIndex < 0) return rawIndex + capacity();
1919 else return rawIndex % capacity(); }
1920
1921 // Remove all but two entries older than the given time.
forgetEntriesMuchOlderThan(double tEarliest)1922 void forgetEntriesMuchOlderThan(double tEarliest) {
1923 const int numToRemove = countNumUnneededOldEntries(tEarliest);
1924 if (numToRemove) {
1925 m_oldest = getArrayIndex(numToRemove);
1926 m_size -= numToRemove;
1927 }
1928 }
1929
1930 // Count up how many old entries at the beginning of the buffer are so old
1931 // that they wouldn't be needed to respond to a request at time tEarliest or
1932 // later. We'll keep no more than two entries earlier than tEarliest.
countNumUnneededOldEntries(double tEarliest)1933 int countNumUnneededOldEntries(double tEarliest) const {
1934 const int firstLater = findFirstLaterOrEq(tEarliest);
1935 return std::max(0, firstLater-2);
1936 }
1937
1938 // Given the time now, delete anything at the end of the queue that is
1939 // at that same time or later.
removeEntriesLaterOrEq(double t)1940 void removeEntriesLaterOrEq(double t) {
1941 int lastEarlier = findLastEarlier(t);
1942 m_size = lastEarlier+1;
1943 if (m_size==0) m_oldest=0; // restart at beginning of array
1944 }
1945
1946 // Return the entry number (0..size-1) of the first entry whose time
1947 // is >= the given time, or -1 if there is none such.
findFirstLaterOrEq(double tDelay)1948 int findFirstLaterOrEq(double tDelay) const {
1949 for (int i=0; i < size(); ++i)
1950 if (getEntryTime(i) >= tDelay)
1951 return i;
1952 return -1;
1953 }
1954
1955 // Return the entry number(size-1..0) of the last entry whose time
1956 // is < the given time, or -1 if there is none such.
findLastEarlier(double t)1957 int findLastEarlier(double t) const {
1958 for (int i=size()-1; i>=0; --i)
1959 if (getEntryTime(i) < t)
1960 return i;
1961 return -1;
1962 }
1963
1964 // We don't have enough space. This is either the initial allocation or
1965 // we need to double the current space.
makeMoreRoom()1966 void makeMoreRoom() {
1967 const int newSizeRequest = std::max((int)InitialAllocation,
1968 (int)GrowthFactor * size());
1969 resize(newSizeRequest);
1970 ++m_nGrows;
1971 m_maxCapacity = std::max(m_maxCapacity, capacity());
1972 }
1973
1974 // We are wasting a lot of space, reduce the heap allocation to just
1975 // double what we're using now.
makeLessRoom()1976 void makeLessRoom() {
1977 const int targetMaxSize = std::max((int)MaxShrinkProofSize,
1978 (int)GrowthFactor * size());
1979 if (capacity() > targetMaxSize) {
1980 resize(targetMaxSize);
1981 ++m_nShrinks;
1982 }
1983 }
1984
1985 // Reallocate memory to get more space or stop wasting space. The new
1986 // size request must be big enough to hold all the current contents. The
1987 // amount we actually get may be somewhat larger than the request. On
1988 // return, the times and values arrays will have been resized and the
1989 // oldest entry will now be entry 0.
resize(int newSizeRequest)1990 void resize(int newSizeRequest) {
1991 assert(newSizeRequest >= size());
1992 const double dNaN = NTraits<double>::getNaN();
1993 Array_<T,int> newValues(newSizeRequest);
1994 if (newValues.capacity() > newValues.size())
1995 newValues.resize(newValues.capacity()); // don't waste any
1996 Array_<double,int> newTimes(newValues.size(), dNaN);
1997
1998 // Pack existing values into start of new arrays.
1999 for (int i=0; i < size(); ++i) {
2000 const int ix = getArrayIndex(i);
2001 newTimes[i] = m_times[ix];
2002 newValues[i] = m_values[ix];
2003 }
2004 m_times.swap(newTimes); // switch heap space
2005 m_values.swap(newValues);
2006 m_oldest = 0; // starts at the beginning now; size unchanged
2007 }
2008
2009 // Initialize everything to its default-constructed state.
initDataMembers()2010 void initDataMembers() {
2011 m_times.clear(); m_values.clear();
2012 m_oldest=m_size=0;
2013 m_nGrows=m_nShrinks=m_maxSize=m_maxCapacity=0;
2014 }
2015
2016 // These are circular buffers of the same size.
2017 Array_<double,int> m_times;
2018 Array_<T,int> m_values;
2019 int m_oldest; // Array index of oldest (time,value)
2020 int m_size; // number of entries in use
2021
2022 // Statistics.
2023 int m_nGrows, m_nShrinks, m_maxSize, m_maxCapacity;
2024 };
2025 /** @endcond **/
2026
2027 template <class T>
2028 class Measure_<T>::Delay::Implementation: public Measure_<T>::Implementation {
2029 typedef Measure_Delay_Buffer<T> Buffer;
2030 public:
2031 // Allocate one cache entry in the base class for the value; we allocate
2032 // a specialized one for the buffer.
Implementation()2033 Implementation()
2034 : Measure_<T>::Implementation(1), m_delay(NaN),
2035 m_canUseCurrentValue(false), m_useLinearInterpolationOnly(false) {}
2036
Implementation(const Measure_<T> & source,Real delay)2037 Implementation(const Measure_<T>& source, Real delay)
2038 : Measure_<T>::Implementation(1), m_source(source), m_delay(delay),
2039 m_canUseCurrentValue(false), m_useLinearInterpolationOnly(false) {}
2040
2041 // Default copy constructor gives us a new Implementation object,
2042 // but with reference to the *same* source measure.
2043
setSourceMeasure(const Measure_<T> & source)2044 void setSourceMeasure(const Measure_<T>& source) {
2045 if (!source.isSameMeasure(this->m_source)) {
2046 this->m_source = source;
2047 this->invalidateTopologyCache();
2048 }
2049 }
2050
setDelay(Real delay)2051 void setDelay(Real delay) {
2052 if (delay != this->m_delay) {
2053 this->m_delay = delay;
2054 this->invalidateTopologyCache();
2055 }
2056 }
2057
setUseLinearInterpolationOnly(bool linearOnly)2058 void setUseLinearInterpolationOnly(bool linearOnly) {
2059 if (linearOnly != this->m_useLinearInterpolationOnly) {
2060 this->m_useLinearInterpolationOnly = linearOnly;
2061 this->invalidateTopologyCache();
2062 }
2063 }
2064
setCanUseCurrentValue(bool canUseCurrentValue)2065 void setCanUseCurrentValue(bool canUseCurrentValue) {
2066 if (canUseCurrentValue != this->m_canUseCurrentValue) {
2067 this->m_canUseCurrentValue = canUseCurrentValue;
2068 this->invalidateTopologyCache();
2069 }
2070 }
2071
getSourceMeasure()2072 const Measure_<T>& getSourceMeasure() const {return this->m_source;}
getDelay()2073 Real getDelay() const {return this->m_delay;}
getUseLinearInterpolationOnly()2074 bool getUseLinearInterpolationOnly() const
2075 { return this->m_useLinearInterpolationOnly; }
getCanUseCurrentValue()2076 bool getCanUseCurrentValue() const
2077 { return this->m_canUseCurrentValue; }
2078
2079
2080 // Implementations of virtual methods.
2081
2082 // This uses the default copy constructor.
cloneVirtual()2083 Implementation* cloneVirtual() const override
2084 { return new Implementation(*this); }
2085
2086 // Currently no derivative supported.
getNumTimeDerivativesVirtual()2087 int getNumTimeDerivativesVirtual() const override
2088 { return 0; }
2089
2090 // If we are allowed to use the current value of the source measure to
2091 // determine the delayed value, the depends-on stage here is the same as
2092 // for the source; otherwise it is Stage::Time.
getDependsOnStageVirtual(int order)2093 Stage getDependsOnStageVirtual(int order) const override
2094 { return this->m_canUseCurrentValue ? m_source.getDependsOnStage(order)
2095 : Stage::Time; }
2096
2097 // Calculate the delayed value and return it to the Measure base class to
2098 // be put in a cache entry.
calcCachedValueVirtual(const State & s,int derivOrder,T & value)2099 void calcCachedValueVirtual(const State& s, int derivOrder, T& value) const
2100 override
2101 { const Subsystem& subsys = this->getSubsystem();
2102 const Buffer& buffer = Value<Buffer>::downcast
2103 (subsys.getDiscreteVariable(s,m_bufferIx));
2104 //TODO: use cubic interpolation if allowed
2105 buffer.calcValueAtTimeLinearOnly(s.getTime()-m_delay, value);
2106 }
2107
initializeVirtual(State & s)2108 void initializeVirtual(State& s) const override {
2109 assert(m_bufferIx.isValid());
2110 const Subsystem& subsys = this->getSubsystem();
2111 Buffer& buffer = Value<Buffer>::updDowncast
2112 (subsys.updDiscreteVariable(s,m_bufferIx));
2113 buffer.clear();
2114 this->getSubsystem().getSystem().realize(s,m_source.getDependsOnStage());
2115 buffer.append(s.getTime()-m_delay, s.getTime(), m_source.getValue(s));
2116 }
2117
realizeMeasureTopologyVirtual(State & s)2118 void realizeMeasureTopologyVirtual(State& s) const override {
2119 m_bufferIx = this->getSubsystem()
2120 .allocateAutoUpdateDiscreteVariable(s, Stage::Report,
2121 new Value<Buffer>(), getDependsOnStageVirtual(0));
2122 }
2123
2124 /** In case no one has updated the value of this measure yet, we have
2125 to make sure it gets updated before the integration moves ahead. **/
realizeMeasureAccelerationVirtual(const State & s)2126 void realizeMeasureAccelerationVirtual(const State& s) const override {
2127 updateBuffer(s);
2128 }
2129
2130 // This uses the buffer from the state to update the one in the
2131 // corresponding cache entry. The update adds the current value of the
2132 // source to the end of the buffer and tosses out unneeded old entries.
updateBuffer(const State & s)2133 void updateBuffer(const State& s) const {
2134 assert(m_bufferIx.isValid());
2135 const Subsystem& subsys = this->getSubsystem();
2136
2137 const Buffer& prevBuffer = Value<Buffer>::downcast
2138 (subsys.getDiscreteVariable(s,m_bufferIx));
2139
2140 Buffer& nextBuffer = Value<Buffer>::updDowncast
2141 (subsys.updDiscreteVarUpdateValue(s,m_bufferIx));
2142
2143 const Real t = s.getTime();
2144 nextBuffer.copyInAndUpdate(prevBuffer, t-m_delay,
2145 t, m_source.getValue(s));
2146
2147 subsys.markDiscreteVarUpdateValueRealized(s,m_bufferIx);
2148 }
2149 private:
2150 // TOPOLOGY STATE
2151 Measure_<T> m_source;
2152 Real m_delay;
2153 bool m_canUseCurrentValue;
2154 bool m_useLinearInterpolationOnly;
2155
2156 // TOPOLOGY CACHE
2157 mutable DiscreteVariableIndex m_bufferIx; // auto-update
2158 };
2159
2160
2161 } // namespace SimTK
2162
2163
2164
2165
2166 #endif // SimTK_SimTKCOMMON_MEASURE_IMPLEMENTATION_H_
2167