#include <State.h>
This object is intended to contain all State information for a SimTK::System, except topological information which is stored in the System itself. A System is "const" after its topology has been constructed and realized.
Systems are composed of Subsystems, and the State supports that concept by allowing per-subsystem partitioning of the total System state. This allows subsytems to have their own private state variables, while permitting the system to allow shared access to state among the subsystems when necessary.
The State provides services reflecting the structure of the equations it expects to find in the System. Three different views of the same state information are supported to accommodate three different users:
The system is expected to be a "hybrid DAE", that is, a mixture of continuous and discrete dynamic equations, and algebraic constraints. There is an independent variable t, continuous state variables y, and discrete state variables d.
The continuous part is an ODE-on-a-manifold system suitable for solution via coordinate projection, structured like this for the view taken by numerical methods: (1) y' = f(d;t,y) differential equations (2) c = c(d;t,y) algebraic equations (manifold is c=0) (3) e = e(d;t,y) event triggers (watch for zero crossings) with initial conditions t0,y0,d0 such that c=0. The discrete variables d are updated upon occurence of specific events, which are detected using the set of scalar-valued event trigger functions e (3).
In the more detailed view as seen from the System, we consider y={q,u,z} to be partitioned into position variables q, velocity variables u, and auxiliary variables z. There will be algebraic constraints involving q, u, and u's time derivatives udot. The system is now assumed to look like this:
(4) qdot = Q(q) u (5) zdot = zdot(d;t,q,u,z)
(6) M(q) udot + ~G(q) mult = f(d;t,q,u,z) G(q) udot = b(d;t,q,u)
(7) udotErr = [ pdotdot(d;t,q,u) ] = 0 [ vdot(d;t,q,u) ] [ a(d;t,q,u) ]
(8) uErr = [ pdot(d;t,q,u) ] [ v(d;t,q,u) ] = 0
(9) qErr = [ p(d;t,q) ] = 0 [ n(q) ]Here G = [P;V;A] with A(q) being the coefficient matrix for constraints appearing only at the acceleration level, and V(q)=partial(v)/partial(u) the coefficient matrix for the velocity (nonholonomic) constraints, and P(q)=partial(pdot)/partial(u) is the coefficient matrix of the first time derivatives of the position (holonomic) constraints. Note that uErr in Eq 8 is assumed to include equations resulting from differentiation of p() in Eq 9, as well as ones first introduced at the velocity level (nonholonomic constraints), and udotErr is similarly built from acceleration-only constraints a() and derivatives of higher-level constraints.
If a system allocates nq q's, nu u's, and nz z's the State will also allocate matching cache variables qdot, qdotdot, udot, and zdot. If mp position (holonomic) constraints (9), mpv velocity constraints (8) and mpva acceleration constraints (7) are allocated, the state creates cache entries of like sizes qErr, uErr, udotErr. In addition room for the mpva Lagrange multipliers 'mult' is allocated in the cache.
In the final view, the Subsystem view, the same variables and cache entries exist, but only the ones allocated by that Subsystem are visible. All of a Subsystem's q's are consecutive in memory, as are its u's, uErr's, etc., but the q's are not adjacent to the u's as they are for the System's view.
The default constructor creates a State containing no state variables and with its realization cache stage set to Stage::Empty. During Subsystem construction, variables and cache entries for any stage can be allocated, however *all* Model stage variables must be allocated during this time. At the end of construction, call advanceSubsystemToStage(Topology) which will put the Subsystem at Stage::Topology. Then the Subsystems realize their Model stages, during which variables at any stage > Model, and cache entries at any stage >= Model can be allocated. After that call advanceSubsystemToStage(Model) which sets the stage to Stage::Model and disallows further allocation.
Note that there is a global Stage for the state as a whole, and individual Stages for each subsystem. The global stage can never be higher than the lowest subsystem stage. Global resources are allocated when the global Stage advances to "Model" and tossed out if that stage is invalidated. Note that subsystems will "register" their use of the global variable pools during their own modeling stages, but that the actual global resources won't exist until the *system* has been advanced to Model stage.
Public Member Functions | |
State () | |
Create an empty State. | |
~State () | |
void | clear () |
Restore State to default-constructed condition. | |
void | setNSubsystems (int i) |
Set the number of subsystems in this state. | |
void | initializeSubsystem (SubsystemIndex, const String &name, const String &version) |
Set the name and version for a given subsystem, which must already have a slot allocated. | |
State (const State &) | |
Make the current State a copy of the source state, copying only state variables and not the cache. | |
State & | operator= (const State &) |
Make the current State a copy of the source state, copying only state variables and not the cache. | |
int | addSubsystem (const String &name, const String &version) |
Register a new subsystem as a client of this State. | |
int | getNSubsystems () const |
const String & | getSubsystemName (SubsystemIndex) const |
const String & | getSubsystemVersion (SubsystemIndex) const |
const Stage & | getSubsystemStage (SubsystemIndex) const |
const Stage & | getSystemStage () const |
This returns the *global* stage for this State. | |
void | invalidateAll (Stage) const |
If any subsystem or the system stage is currently at or higher than the passed-in one, back up to the stage just prior. | |
void | advanceSubsystemToStage (SubsystemIndex, Stage) const |
Advance the current stage by one to the indicated stage. | |
void | advanceSystemToStage (Stage) const |
int | allocateQ (SubsystemIndex, const Vector &qInit) |
These are shared among all the subsystems and are not allocated until the *System* is advanced to Stage::Model. | |
int | allocateU (SubsystemIndex, const Vector &uInit) |
int | allocateZ (SubsystemIndex, const Vector &zInit) |
int | allocateQErr (SubsystemIndex, int nqerr) const |
Slots for constraint errors are handled similarly, although these are just cache entries not state variables. | |
int | allocateUErr (SubsystemIndex, int nuerr) const |
int | allocateUDotErr (SubsystemIndex, int nudoterr) const |
int | allocateEvent (SubsystemIndex, Stage, int nevent) const |
Slots for event witness values are similar to constraint errors. | |
int | allocateDiscreteVariable (SubsystemIndex, Stage, AbstractValue *v) |
DiscreteVariables and CacheEntries are private to each subsystem and are allocated immediately. | |
int | allocateCacheEntry (SubsystemIndex, Stage, AbstractValue *v) |
int | getNY () const |
Dimensions. | |
int | getQStart () const |
int | getNQ () const |
int | getUStart () const |
int | getNU () const |
int | getZStart () const |
int | getNZ () const |
int | getNYErr () const |
int | getQErrStart () const |
int | getNQErr () const |
int | getUErrStart () const |
int | getNUErr () const |
int | getNUDotErr () const |
int | getNMultipliers () const |
int | getQStart (SubsystemIndex) const |
int | getNQ (SubsystemIndex) const |
int | getUStart (SubsystemIndex) const |
int | getNU (SubsystemIndex) const |
int | getZStart (SubsystemIndex) const |
int | getNZ (SubsystemIndex) const |
int | getQErrStart (SubsystemIndex) const |
int | getNQErr (SubsystemIndex) const |
int | getUErrStart (SubsystemIndex) const |
int | getNUErr (SubsystemIndex) const |
int | getUDotErrStart (SubsystemIndex) const |
int | getNUDotErr (SubsystemIndex) const |
int | getMultipliersStart (SubsystemIndex i) const |
int | getNMultipliers (SubsystemIndex i) const |
int | getNEvents () const |
int | getEventStartByStage (Stage) const |
int | getNEventsByStage (Stage) const |
int | getEventStartByStage (SubsystemIndex, Stage) const |
int | getNEventsByStage (SubsystemIndex, Stage) const |
const Vector & | getEvents () const |
const Vector & | getEventsByStage (Stage) const |
const Vector & | getEventsByStage (SubsystemIndex, Stage) const |
Vector & | updEvents () const |
Vector & | updEventsByStage (Stage) const |
Vector & | updEventsByStage (SubsystemIndex, Stage) const |
const Vector & | getQ (SubsystemIndex) const |
Per-subsystem access to the global shared variables. | |
const Vector & | getU (SubsystemIndex) const |
const Vector & | getZ (SubsystemIndex) const |
Vector & | updQ (SubsystemIndex) |
Vector & | updU (SubsystemIndex) |
Vector & | updZ (SubsystemIndex) |
const Vector & | getQDot (SubsystemIndex) const |
Per-subsystem access to the shared cache entries. | |
const Vector & | getUDot (SubsystemIndex) const |
const Vector & | getZDot (SubsystemIndex) const |
const Vector & | getQDotDot (SubsystemIndex) const |
Vector & | updQDot (SubsystemIndex) const |
Vector & | updUDot (SubsystemIndex) const |
Vector & | updZDot (SubsystemIndex) const |
Vector & | updQDotDot (SubsystemIndex) const |
const Vector & | getQErr (SubsystemIndex) const |
const Vector & | getUErr (SubsystemIndex) const |
const Vector & | getUDotErr (SubsystemIndex) const |
const Vector & | getMultipliers (SubsystemIndex) const |
Vector & | updQErr (SubsystemIndex) const |
Vector & | updUErr (SubsystemIndex) const |
Vector & | updUDotErr (SubsystemIndex) const |
Vector & | updMultipliers (SubsystemIndex) const |
const Real & | getTime () const |
You can call these as long as *system* stage >= Model. | |
const Vector & | getY () const |
const Vector & | getQ () const |
These are just views into Y. | |
const Vector & | getU () const |
const Vector & | getZ () const |
Real & | updTime () |
You can call these as long as stage >= Model, but the stage will be backed up if necessary to the indicated stage. | |
Vector & | updY () |
void | setTime (Real t) |
An alternate syntax equivalent to updTime() and updY(). | |
void | setY (const Vector &y) |
Vector & | updQ () |
These are just views into Y. | |
Vector & | updU () |
Vector & | updZ () |
void | setQ (const Vector &q) |
Alternate interface. | |
void | setU (const Vector &u) |
void | setZ (const Vector &z) |
const Vector & | getYDot () const |
const Vector & | getQDot () const |
These are just views into YDot. | |
const Vector & | getZDot () const |
const Vector & | getUDot () const |
const Vector & | getQDotDot () const |
This has its own space, not a view. | |
Vector & | updYDot () const |
These are mutable. | |
Vector & | updQDot () const |
Vector & | updZDot () const |
Vector & | updUDot () const |
Vector & | updQDotDot () const |
This is a separate shared cache entry, not part of YDot. | |
const Vector & | getYErr () const |
Return the current constraint errors for all constraints. | |
const Vector & | getQErr () const |
These are just views into YErr. | |
const Vector & | getUErr () const |
const Vector & | getUDotErr () const |
These have their own space, the are not views. | |
const Vector & | getMultipliers () const |
Vector & | updYErr () const |
These are mutable. | |
Vector & | updQErr () const |
Vector & | updUErr () const |
Vector & | updUDotErr () const |
Vector & | updMultipliers () const |
const AbstractValue & | getDiscreteVariable (SubsystemIndex, int index) const |
OK if dv.stage==Model or stage >= Model. | |
AbstractValue & | updDiscreteVariable (SubsystemIndex, int index) |
OK if dv.stage==Model or stage >= Model; set stage to dv.stage-1. | |
void | setDiscreteVariable (SubsystemIndex i, int index, const AbstractValue &v) |
Alternate interface to updDiscreteVariable. | |
const AbstractValue & | getCacheEntry (SubsystemIndex, int index) const |
Stage >= ce.stage. | |
AbstractValue & | updCacheEntry (SubsystemIndex, int index) const |
Stage >= ce.stage-1; does not change stage. | |
void | createRestrictedState (State &restrictedState, EnumerationSet< Stage > restrictedStages, std::set< SubsystemIndex > restrictedSubsystems) |
Transform a State into one which shares all the same data as this one, such that modifying either one will modify both of them. | |
EnumerationSet< Stage > | getRestrictedStages () const |
Get the set of stages which cannot be modified in this State. | |
std::set< SubsystemIndex > | getRestrictedSubsystems () const |
Get the set of subsystems which cannot be modified in this State. | |
String | toString () const |
String | cacheToString () const |
~State | ( | ) |
Make the current State a copy of the source state, copying only state variables and not the cache.
If the source state hasn't been realized to Model stage, then we don't copy its state variables either, except those associated with the Topology stage.
void clear | ( | ) |
Restore State to default-constructed condition.
void setNSubsystems | ( | int | i | ) |
Set the name and version for a given subsystem, which must already have a slot allocated.
Make the current State a copy of the source state, copying only state variables and not the cache.
If the source state hasn't been realized to Model stage, then we don't copy its state variables either, except those associated with the Topology stage.
Register a new subsystem as a client of this State.
The supplied strings are stored with the State but are not interpreted by it. The intent is that they can be used to perform "sanity checks" on deserialized States to make sure they match the currently instantiated System. The subsystem index (a small integer) is returned.
int getNSubsystems | ( | ) | const |
const String& getSubsystemName | ( | SubsystemIndex | ) | const |
const String& getSubsystemVersion | ( | SubsystemIndex | ) | const |
const Stage& getSubsystemStage | ( | SubsystemIndex | ) | const |
const Stage& getSystemStage | ( | ) | const |
This returns the *global* stage for this State.
Referenced by OLDRungeKuttaMerson::initialize(), OLDExplicitEuler::initialize(), OLDCPodesIntegrator::initialize(), OLDCPodesIntegrator::OLDCPodesIntegrator(), OLDExplicitEuler::OLDExplicitEuler(), OLDRungeKuttaMerson::OLDRungeKuttaMerson(), OLDRungeKuttaMerson::step(), OLDExplicitEuler::step(), and OLDCPodesIntegrator::step().
void invalidateAll | ( | Stage | ) | const |
If any subsystem or the system stage is currently at or higher than the passed-in one, back up to the stage just prior.
Otherwise do nothing.
void advanceSubsystemToStage | ( | SubsystemIndex | , | |
Stage | ||||
) | const |
Advance the current stage by one to the indicated stage.
The stage is passed in just to give us a chance to verify that all is as expected. You can only advance one stage at a time. Advancing to "Topology" and "Model" stages affect what you can do later.
void advanceSystemToStage | ( | Stage | ) | const |
int allocateQ | ( | SubsystemIndex | , | |
const Vector & | qInit | |||
) |
These are shared among all the subsystems and are not allocated until the *System* is advanced to Stage::Model.
The returned index is local to each subsystem. After the System is modeled, we guarantee that all the q's for a subsystem will be contiguous, and similarly for u's and z's. However, q,u,z will *not* be contiguous with each other. The *global* y is contiguous, and global q,u,z are contiguous within y, in that order.
int allocateU | ( | SubsystemIndex | , | |
const Vector & | uInit | |||
) |
int allocateZ | ( | SubsystemIndex | , | |
const Vector & | zInit | |||
) |
int allocateQErr | ( | SubsystemIndex | , | |
int | nqerr | |||
) | const |
Slots for constraint errors are handled similarly, although these are just cache entries not state variables.
Q errors and U errors will each be contiguous for a given subsystem, but *not* with each other. However, yerr={qerr,uerr} *is* a single contiguous vector. UDotErr is a separate quantity, not part of yerr. Again the UDotErr's for each subsystem will be contiguous within the larger UDotErr Vector. Allocating a UDotErr has the side effect of allocating another Vector of the same size in the cache for the corresponding Lagrange multipliers, and these are partitioned identically to UDotErrs.
int allocateUErr | ( | SubsystemIndex | , | |
int | nuerr | |||
) | const |
int allocateUDotErr | ( | SubsystemIndex | , | |
int | nudoterr | |||
) | const |
int allocateEvent | ( | SubsystemIndex | , | |
Stage | , | |||
int | nevent | |||
) | const |
Slots for event witness values are similar to constraint errors.
However, this also allocates a discrete state variable to hold the "triggered" indication. The Stage here is the stage at which the event witness function can first be examined.
int allocateDiscreteVariable | ( | SubsystemIndex | , | |
Stage | , | |||
AbstractValue * | v | |||
) |
DiscreteVariables and CacheEntries are private to each subsystem and are allocated immediately.
Ownership of the AbstractValue object is taken over by the State -- don't delete the object after this call!
int allocateCacheEntry | ( | SubsystemIndex | , | |
Stage | , | |||
AbstractValue * | v | |||
) |
int getNY | ( | ) | const |
Dimensions.
These are valid at Stage::Model while access to the various arrays may have stricter requirements. Hence it is better to use these routines than to get a reference to a Vector and ask for its size().
int getQStart | ( | ) | const |
int getNQ | ( | ) | const |
int getUStart | ( | ) | const |
int getNU | ( | ) | const |
int getZStart | ( | ) | const |
int getNZ | ( | ) | const |
int getNYErr | ( | ) | const |
int getQErrStart | ( | ) | const |
int getNQErr | ( | ) | const |
int getUErrStart | ( | ) | const |
int getNUErr | ( | ) | const |
int getNUDotErr | ( | ) | const |
int getNMultipliers | ( | ) | const |
int getQStart | ( | SubsystemIndex | ) | const |
int getNQ | ( | SubsystemIndex | ) | const |
int getUStart | ( | SubsystemIndex | ) | const |
int getNU | ( | SubsystemIndex | ) | const |
int getZStart | ( | SubsystemIndex | ) | const |
int getNZ | ( | SubsystemIndex | ) | const |
int getQErrStart | ( | SubsystemIndex | ) | const |
int getNQErr | ( | SubsystemIndex | ) | const |
int getUErrStart | ( | SubsystemIndex | ) | const |
int getNUErr | ( | SubsystemIndex | ) | const |
int getUDotErrStart | ( | SubsystemIndex | ) | const |
int getNUDotErr | ( | SubsystemIndex | ) | const |
int getMultipliersStart | ( | SubsystemIndex | i | ) | const |
int getNMultipliers | ( | SubsystemIndex | i | ) | const |
int getNEvents | ( | ) | const |
int getEventStartByStage | ( | Stage | ) | const |
int getNEventsByStage | ( | Stage | ) | const |
int getEventStartByStage | ( | SubsystemIndex | , | |
Stage | ||||
) | const |
int getNEventsByStage | ( | SubsystemIndex | , | |
Stage | ||||
) | const |
const Vector& getEvents | ( | ) | const |
Vector& updEvents | ( | ) | const |
const Vector& getQ | ( | SubsystemIndex | ) | const |
Per-subsystem access to the global shared variables.
const Vector& getU | ( | SubsystemIndex | ) | const |
const Vector& getZ | ( | SubsystemIndex | ) | const |
Vector& updQ | ( | SubsystemIndex | ) |
Vector& updU | ( | SubsystemIndex | ) |
Vector& updZ | ( | SubsystemIndex | ) |
const Vector& getQDot | ( | SubsystemIndex | ) | const |
Per-subsystem access to the shared cache entries.
const Vector& getUDot | ( | SubsystemIndex | ) | const |
const Vector& getZDot | ( | SubsystemIndex | ) | const |
const Vector& getQDotDot | ( | SubsystemIndex | ) | const |
Vector& updQDot | ( | SubsystemIndex | ) | const |
Vector& updUDot | ( | SubsystemIndex | ) | const |
Vector& updZDot | ( | SubsystemIndex | ) | const |
Vector& updQDotDot | ( | SubsystemIndex | ) | const |
const Vector& getQErr | ( | SubsystemIndex | ) | const |
const Vector& getUErr | ( | SubsystemIndex | ) | const |
const Vector& getUDotErr | ( | SubsystemIndex | ) | const |
const Vector& getMultipliers | ( | SubsystemIndex | ) | const |
Vector& updQErr | ( | SubsystemIndex | ) | const |
Vector& updUErr | ( | SubsystemIndex | ) | const |
Vector& updUDotErr | ( | SubsystemIndex | ) | const |
Vector& updMultipliers | ( | SubsystemIndex | ) | const |
const Real& getTime | ( | ) | const |
You can call these as long as *system* stage >= Model.
Referenced by TimeStepper::getTime(), OLDCPodesIntegrator::initialize(), OLDRungeKuttaMerson::step(), and OLDExplicitEuler::step().
const Vector& getY | ( | ) | const |
const Vector& getQ | ( | ) | const |
These are just views into Y.
const Vector& getU | ( | ) | const |
const Vector& getZ | ( | ) | const |
Real& updTime | ( | ) |
You can call these as long as stage >= Model, but the stage will be backed up if necessary to the indicated stage.
Referenced by CPodesMultibodySystem::constraint(), CPodesMultibodySystem::explicitODE(), CPodesMultibodySystem::project(), OLDRungeKuttaMerson::step(), and OLDExplicitEuler::step().
Vector& updY | ( | ) |
void setY | ( | const Vector & | y | ) |
Vector& updQ | ( | ) |
These are just views into Y.
Vector& updU | ( | ) |
Vector& updZ | ( | ) |
void setQ | ( | const Vector & | q | ) |
Alternate interface.
void setU | ( | const Vector & | u | ) |
void setZ | ( | const Vector & | z | ) |
const Vector& getYDot | ( | ) | const |
Referenced by CPodesMultibodySystem::explicitODE(), OLDRungeKuttaMerson::step(), and OLDExplicitEuler::step().
const Vector& getQDot | ( | ) | const |
These are just views into YDot.
const Vector& getZDot | ( | ) | const |
const Vector& getUDot | ( | ) | const |
const Vector& getQDotDot | ( | ) | const |
This has its own space, not a view.
Vector& updYDot | ( | ) | const |
These are mutable.
Vector& updQDot | ( | ) | const |
Vector& updZDot | ( | ) | const |
Vector& updUDot | ( | ) | const |
Vector& updQDotDot | ( | ) | const |
This is a separate shared cache entry, not part of YDot.
If you have a direct 2nd order integrator you can integrate QDotDot (twice) to get Q.
const Vector& getYErr | ( | ) | const |
Return the current constraint errors for all constraints.
Referenced by CPodesMultibodySystem::constraint(), OLDCPodesIntegrator::initialize(), and OLDExplicitEuler::step().
const Vector& getQErr | ( | ) | const |
These are just views into YErr.
const Vector& getUErr | ( | ) | const |
const Vector& getUDotErr | ( | ) | const |
These have their own space, the are not views.
const Vector& getMultipliers | ( | ) | const |
Vector& updYErr | ( | ) | const |
These are mutable.
Vector& updQErr | ( | ) | const |
Vector& updUErr | ( | ) | const |
Vector& updUDotErr | ( | ) | const |
Vector& updMultipliers | ( | ) | const |
const AbstractValue& getDiscreteVariable | ( | SubsystemIndex | , | |
int | index | |||
) | const |
OK if dv.stage==Model or stage >= Model.
AbstractValue& updDiscreteVariable | ( | SubsystemIndex | , | |
int | index | |||
) |
OK if dv.stage==Model or stage >= Model; set stage to dv.stage-1.
void setDiscreteVariable | ( | SubsystemIndex | i, | |
int | index, | |||
const AbstractValue & | v | |||
) |
Alternate interface to updDiscreteVariable.
const AbstractValue& getCacheEntry | ( | SubsystemIndex | , | |
int | index | |||
) | const |
Stage >= ce.stage.
AbstractValue& updCacheEntry | ( | SubsystemIndex | , | |
int | index | |||
) | const |
Stage >= ce.stage-1; does not change stage.
void createRestrictedState | ( | State & | restrictedState, | |
EnumerationSet< Stage > | restrictedStages, | |||
std::set< SubsystemIndex > | restrictedSubsystems | |||
) |
Transform a State into one which shares all the same data as this one, such that modifying either one will modify both of them.
The new State restricts which stages and subsystems may be modified. Any attempt to modify restricted data through that object will produce an exception.
This method can only add restrictions, not remove them. If this State was itself created by createRestrictedState(), the new state will inherit all of the restrictions from this one, in addition to any that are specified in the arguments.
EnumerationSet<Stage> getRestrictedStages | ( | ) | const |
Get the set of stages which cannot be modified in this State.
Attempting to modify any of these stages will produce an exception.
std::set<SubsystemIndex> getRestrictedSubsystems | ( | ) | const |
Get the set of subsystems which cannot be modified in this State.
Attempting to modify any of these subsystems will produce an exception.
String toString | ( | ) | const |
String cacheToString | ( | ) | const |