API 4.4.1-2022-10-19-2c4045e59
For MATLAB, Python, Java, and C++ users
OpenSim::StatesTrajectory Class Reference

Public Member Functions

 StatesTrajectory ()
 Create an empty trajectory of states. More...
 
size_t getSize () const
 The number of SimTK::States in the trajectory. More...
 
TimeSeriesTable exportToTable (const Model &model, const std::vector< std::string > &stateVars={}) const
 Export the continuous state variables to a data table, perhaps to write to a file and postprocess in MATLAB/Python/Excel. More...
 
Accessing individual SimTK::States
const SimTK::State & operator[] (size_t index) const
 Get a const reference to the state at a given index in the trajectory. More...
 
const SimTK::State & get (size_t index) const
 Get a const reference to the state at a given index in the trajectory. More...
 
const SimTK::State & front () const
 Get a const reference to the first state in the trajectory. More...
 
const SimTK::State & back () const
 Get a const reference to the last state in the trajectory. More...
 
Iterating through the trajectory
const_iterator begin () const
 Iterator pointing to first SimTK::State; does not allow modifying the states. More...
 
const_iterator end () const
 Iterator pointing past the end of the trajectory. More...
 
Modify the contents of the trajectory
void clear ()
 Clear all the states in the trajectory. More...
 
void append (const SimTK::State &state)
 Append a SimTK::State to this trajectory. More...
 
Checks for integrity
bool hasIntegrity () const
 Checks isNondecreasingInTime() and isConsistent(). More...
 
bool isNondecreasingInTime () const
 Returns true if times are non-decreasing; false otherwise. More...
 
bool isConsistent () const
 Checks if the states have the same number of state variables, constraints, etc. More...
 
bool isCompatibleWith (const Model &model) const
 Weak check for if the trajectory can be used with the given model. More...
 

Static Public Member Functions

Create partial trajectory from a states table
static StatesTrajectory createFromStatesStorage (const Model &model, const Storage &sto, bool allowMissingColumns=false, bool allowExtraColumns=false, bool assemble=false)
 This function is identical to createFromStatesTable() except that this function accepts a Storage instead of a TimeSeriesTable. More...
 
static StatesTrajectory createFromStatesTable (const Model &model, const TimeSeriesTable &table, bool allowMissingColumns=false, bool allowExtraColumns=false, bool assemble=false)
 Create a partial trajectory of States from a states table. More...
 
static StatesTrajectory createFromStatesStorage (const Model &model, const std::string &filepath)
 Convenience form of createFromStatesStorage() that takes the path to a Storage file instead of a Storage object. More...
 

Detailed Description

StatesTrajectory

This class holds a sequence of SimTK::States. You can obtain a StatesTrajectory during a simulation via the StatesTrajectoryReporter. You can also create a StatesTrajectory from a states storage (.sto) file (see createFromStatesStorage()). Users can modify a trajectory by appending states to it, but users cannot modify the individual states that are already in a trajectory.

This class was introduced in OpenSim version 4.0, and enables scripting (Python/MATLAB) and C++ users to postprocess their results with greater ease and flexibility than with an Analysis.

Note
In a future release, we plan to support an OSTATES file format that allows one to write the trajectory to a file with full numerical precision.

Guarantees

This class is designed to ensure the following:

  • The states are ordered nondecreasing in time (adjacent states can have the same time).
  • All states in the trajectory are consistent with each other (see isConsistent()).
Note
These guarantees apply when using this class through C++, Java, or the OpenSim GUI, but not through Python or MATLAB. This is because Python and MATLAB do not enforce constness and thus allow modifying the trajectory.

Using with an OpenSim:: Model

A StatesTrajectory is not very useful on its own, since neither the trajectory nor the contained states know how the Components name the state variables they create. You probably want to use the trajectory with an OpenSim::Model, through which the state variables have a meaning (e.g., model.getStateVariableValue(states[0], "soleus_r/activation")).

SimTK::States have a tight association with a specific OpenSim::Model (actually, with the SimTK::System within an OpenSim::Model). However, the StatesTrajectory does not know anything about the model to which it corresponds. So, for example, you could use a single StatesTrajectory with a generic gait2392 model as well as with a scaled (subject-specific) gait2392 model. This flexibility may be beneficial in some scenarios, but also allows one to accidentally use the wrong model with a given states trajectory, potentially leading to silent errors that could compromise a scientific study.

To increase your confidence that a StatesTrajectory matches a given Model, you can perform some weak checks with isCompatibleWith().

Usage

Here are a few basic things you can do with a StatesTrajectory, assuming you already have one:

StatesTrajectory states = getStatesTrajectorySomehow();
const double numStates = states.getSize();
const double initialTime = states[0].getTime();
const double finalTime = states.back().getTime();
StatesTrajectory()
Create an empty trajectory of states.
Definition: StatesTrajectory.h:145

Without a model, you can access the state variable values, but you won't know the identity of such state variables.

int numGeneralizedCoordinates = states[0].getNQ();
const SimTK::Vector& generalizedCoordinateValues = states[0].getQ();

To do most things with the StatesTrajectory, you'll need a model as well as its underlying SimTK::System. It is therefore required that you call Model::initSystem() before you try to use any states with the model:

Model model("subject01.osim");
model.initSystem();
double knee_angle = model.getStateVariableValue(states[0], "knee/flexion/value");
Vec3 com = model.calcMassCenterPosition(states[0]);

Depending on the quantity you want to obtain, you may also need to realize the state to a certain stage:

model.getMultibodySystem().realize(states[0], SimTK::Stage::Velocity);
model.getMuscles().get("soleus_r").getActivation(states[0]);

You can iterate through a trajectory to access the value of a state variable at each time in the trajectory.

for (const auto& state : states) {
std::cout << state.getTime() << " "
<< model.getStateVariableValue(state, "knee/flexion/value")
<< std::endl;
}

Constructor & Destructor Documentation

◆ StatesTrajectory()

OpenSim::StatesTrajectory::StatesTrajectory ( )
inline

Create an empty trajectory of states.

Member Typedef Documentation

◆ const_iterator

typedef std::vector<SimTK::State>::const_iterator OpenSim::StatesTrajectory::const_iterator

Iterator type that does not allow modifying the trajectory.

Most users do not need to understand what this is.

◆ IteratorRange

A helper type to allow using range for loops over a subset of the trajectory.

Member Function Documentation

◆ append()

void OpenSim::StatesTrajectory::append ( const SimTK::State &  state)

Append a SimTK::State to this trajectory.

This function ensures that the time in the new SimTK::State is greater than or equal to the time in the last SimTK::State in the trajectory.

The state that ends up in the trajectory is a deep copy of the one passed in.

◆ back()

const SimTK::State & OpenSim::StatesTrajectory::back ( ) const
inline

Get a const reference to the last state in the trajectory.

◆ begin()

const_iterator OpenSim::StatesTrajectory::begin ( ) const
inline

Iterator pointing to first SimTK::State; does not allow modifying the states.

Allows using this class in a range for loop.

◆ clear()

void OpenSim::StatesTrajectory::clear ( )

Clear all the states in the trajectory.

◆ createFromStatesStorage() [1/2]

static StatesTrajectory OpenSim::StatesTrajectory::createFromStatesStorage ( const Model model,
const std::string &  filepath 
)
static

Convenience form of createFromStatesStorage() that takes the path to a Storage file instead of a Storage object.

This convenience form uses the default values for allowMissingColumns and allowExtraColumns.

◆ createFromStatesStorage() [2/2]

static StatesTrajectory OpenSim::StatesTrajectory::createFromStatesStorage ( const Model model,
const Storage sto,
bool  allowMissingColumns = false,
bool  allowExtraColumns = false,
bool  assemble = false 
)
static

This function is identical to createFromStatesTable() except that this function accepts a Storage instead of a TimeSeriesTable.

◆ createFromStatesTable()

static StatesTrajectory OpenSim::StatesTrajectory::createFromStatesTable ( const Model model,
const TimeSeriesTable table,
bool  allowMissingColumns = false,
bool  allowExtraColumns = false,
bool  assemble = false 
)
static

Create a partial trajectory of States from a states table.

The resulting StatesTrajectory will restore continuous state variable values, but not discrete state variable values, modeling option values, etc. Also, keep in mind that states files usually do not contain the state values to full precision, and thus cannot exactly reproduce results from the initial state trajectory. Lastly, this function optionally modifies each state to obey any constraints in the model (by calling Model::assemble()).

The states in the resulting trajectory will be realized to SimTK::Stage::Instance. You should not use the resulting trajectory with an instance of the model other than the one you passed to this function (the state contains Instance-stage cache variables that are pointers to objects in the model; e.g., force elements).

Note
The naming convention for state variables changed in OpenSim v4.0; ankle_r/ankle_angle_r/speed used to be ankle_angle_r_u, soleus_r/activation used to be soleus_r.activation, etc. This function can handle column labels that use the pre-v4.0 naming convention.
Parameters
modelThe Model to which the states belong. A Model is necessary because the data file lists the state variables by name.
tableThe table containing state values.
allowMissingColumnsIf false, throws exception if there are continuous state variables in the Model for which there is no column in the table. If true, no exception is thrown but such state variables are set to NaN.
allowExtraColumnsIf false, throws exception if there are columns in the table that do not correspond to continuous state variables in the Model. If true, such columns of the table are ignored.
assembleModify state variable values to satisfy kinematic constraints (by calling Model::assemble()). Use this option if the provided states are incomplete (for example, the values for dependent coordinates are unspecified). Caution: enforcing constraints can drastically alter the provided states if they do not already obey the constraints. Do not use this option with results from a forward simulation: the states trajectory from a forward simulation may not meet the model's assembly accuracy, and therefore assembling could alter the trajectory and cause inconsistency between coordinate values and speeds.

Here is how you might use this function in python:

import opensim
model = opensim.Model("subject01.osim")
table = opensim.TimeSeriesTable("subject01_states.sto")
states = opensim.StatesTrajectory.createFromStatesTable(model, table)
print(states[0].getTime())
print(model.getStateVariableValue(states[0], "knee/flexion/value"))
Exceptions
MissingColumnsSee the description of the allowMissingColumns argument.
ExtraColumnsSee the description of the allowExtraColumns argument.
NonUniqueLabelsThrown if multiple columns in the table have the same name.
DataIsInDegreesThrown if the table is in degrees (inDegrees=yes); angular quantities must use radians to properly create the trajectory.

◆ end()

const_iterator OpenSim::StatesTrajectory::end ( ) const
inline

Iterator pointing past the end of the trajectory.

Allows using this class in a range for loop.

◆ exportToTable()

TimeSeriesTable OpenSim::StatesTrajectory::exportToTable ( const Model model,
const std::vector< std::string > &  stateVars = {} 
) const

Export the continuous state variables to a data table, perhaps to write to a file and postprocess in MATLAB/Python/Excel.

The names of the columns in the table will be the absolute names of the continuous state variables (e.g., knee/flexion/angle).

You must provide a model that is compatible with this trajectory, since only the model knows the names of the state variables.

By default, all continuous state variables are written to the table (one per column). If you only want some of them to be written to the table, use the stateVars argument to specify their absolute names (e.g., knee/flexion/angle).

auto allStateVars = states.exportToTable(model);
auto kneeStates = states.exportToTable(model, {"knee/flexion/value",
"knee/flexion/speed"});
Exceptions
IncompatibleModelThrown if the Model fails the check isCompatibleWith().

See DataAdapter for details on writing to files.

◆ front()

const SimTK::State & OpenSim::StatesTrajectory::front ( ) const
inline

Get a const reference to the first state in the trajectory.

◆ get()

const SimTK::State & OpenSim::StatesTrajectory::get ( size_t  index) const
inline

Get a const reference to the state at a given index in the trajectory.

Exceptions
IndexOutOfRangeIf the index is greater than the size of the trajectory.

◆ getSize()

size_t OpenSim::StatesTrajectory::getSize ( ) const

The number of SimTK::States in the trajectory.

◆ hasIntegrity()

bool OpenSim::StatesTrajectory::hasIntegrity ( ) const

Checks isNondecreasingInTime() and isConsistent().

The design of this class is such that this method should always return true. This check may be more useful in Python or MATLAB, in which it's possible to edit the trajectory such that this method could return false.

◆ isCompatibleWith()

bool OpenSim::StatesTrajectory::isCompatibleWith ( const Model model) const

Weak check for if the trajectory can be used with the given model.

Returns true if the trajectory isConsistent() and if the number of speeds in the model matches the number of U's in state.

Returns false otherwise. This method cannot guarantee that the trajectory will work with the given model, and makes no attempt to determine if the trajectory was generated with the given model.

◆ isConsistent()

bool OpenSim::StatesTrajectory::isConsistent ( ) const

Checks if the states have the same number of state variables, constraints, etc.

Returns true if the following quantities are the same for all states in the trajectory:

  • number of generalized coordinates (Q's)
  • number of generalized speeds (U's)
  • number of auxiliary state variables (Z's)
  • number of position constraints (QErr's)
  • number of velocity constraints (UErr's)
  • number of acceleration constraints (UDotErr's)
  • number of constraint Lagrange multipliers
  • number of event triggers

Returns false otherwise.

◆ isNondecreasingInTime()

bool OpenSim::StatesTrajectory::isNondecreasingInTime ( ) const

Returns true if times are non-decreasing; false otherwise.

◆ operator[]()

const SimTK::State & OpenSim::StatesTrajectory::operator[] ( size_t  index) const
inline

Get a const reference to the state at a given index in the trajectory.

Here's an example of getting a state variable value from the first state in the trajectory:

Model model("subject01.osim");
const StatesTrajectory states = getStatesTrajectorySomehow();
const auto& state = states[0];
model.getStateVariableValue(state, "knee/flexion/value");

This function does not check if the index is larger than the size of the trajectory; see get() if you want this check.


The documentation for this class was generated from the following file: