Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Exponential Contact #3310

Open
wants to merge 62 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 58 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
ff5fb01
Draft of OpenSim::ExponentialSpringForce
fcanderson May 19, 2022
60a82d6
First draft.
fcanderson May 24, 2022
39aeed4
Minor. Just line length corrections.
fcanderson May 24, 2022
9f73ff3
Completed the basic framework.
fcanderson May 24, 2022
569e1cf
Added draft of a Visualizer class.
fcanderson May 25, 2022
eb632ca
Adding 8 HuntCrossley at corners.
fcanderson May 25, 2022
3064448
Constructing based on "BodyName" instead of Body.
fcanderson May 27, 2022
ab3aeda
Added Exponential Springs and an ExternalForce.
fcanderson May 27, 2022
94f1b81
Minor Changes + Bug Fixes
fcanderson May 28, 2022
b5812da
Added Parameters. Changed name.
fcanderson Jun 5, 2022
8f339cd
Bug fix, plus minor tweaks
fcanderson Jun 5, 2022
6a9563f
Non-default params working + comments and tweaks.
fcanderson Jun 7, 2022
110d356
File rename: "ExpoentialSpringForce" to "ExponentialContact"
fcanderson Jun 7, 2022
4a0d4a7
Improved documentation comments.
fcanderson Jun 7, 2022
1ffa6e3
Cleaned up code, removed memory leaks, polished comments.
fcanderson Jun 18, 2022
814f974
Added detailed Doxygen comments.
fcanderson Jun 18, 2022
fa57ae2
Enhanced reported information.
fcanderson Jun 18, 2022
52c95bc
Registered class ExponentialContact.
fcanderson Jun 18, 2022
9e710a4
Bug fix and some internal testing.
fcanderson Jun 18, 2022
a4f91aa
Made naming more consistent.
fcanderson Jun 19, 2022
fd85ee5
Removed unused method.
fcanderson Jun 19, 2022
a5d5793
Tweaked/shortened command-line options.
fcanderson Jun 19, 2022
e5d97e1
Minor name change: FxES -> FxEC
fcanderson Jun 19, 2022
ff07658
Polished documentation comments.
fcanderson Jun 22, 2022
e4b3411
Memory management and simplifications.
fcanderson Jun 22, 2022
94ac923
Added ExponentialContact.h to include file.
fcanderson Jun 24, 2022
882e83f
Minor name changes.
fcanderson Jun 24, 2022
ccb4258
Added test routine for class ExponentialContact.
fcanderson Jun 24, 2022
9eca269
Added two new initial conditions.
fcanderson Sep 11, 2022
fc38ee5
Improved output formatting.
fcanderson Sep 11, 2022
56f4e22
Added resetAnchorPoint(), removed props, polished comments.
fcanderson Sep 16, 2022
82cf83d
Added resetAnchorPoint(), removed props, polished comments.
fcanderson Sep 16, 2022
11c8f36
Added accessors for states.
fcanderson Sep 17, 2022
fd02274
Added accessors for data cache entries.
fcanderson Sep 18, 2022
e7a006b
Added static method for resetting anchor points.
fcanderson Sep 18, 2022
e2a172b
ExponentialContact: Using monograph notation
fcanderson Oct 28, 2022
af8eb21
Merge branch 'opensim-org:master' into exponential_springs
fcanderson Oct 30, 2022
36145fc
Typo Fix: corrected volume of block.
fcanderson Nov 1, 2022
783c16f
testForce: enhanced test for ExponentialContact
fcanderson Nov 1, 2022
d2fbce2
Modified ExponentialContact::getRecordValues()
fcanderson Jan 6, 2023
7f8bdf1
Modified testExponentialContact() in testForces.cpp
fcanderson Jan 6, 2023
e24d170
Merge branch 'opensim-org:main' into exponential_springs
fcanderson Jan 6, 2023
2583850
Merge branch 'opensim-org:main' into exponential_springs
fcanderson Jan 17, 2023
540da3f
Dependencies updated to build against latest Simbody build.
fcanderson Jan 17, 2023
e7b17b1
Commented out some cout statements.
fcanderson Jan 18, 2023
eb6752f
updateFromXMLNode() now declared as override
fcanderson Jan 18, 2023
75e87c9
Ubuntu build fix?: Catching exception std::bad_cast
fcanderson Jan 18, 2023
f74c4d8
Merge branch 'opensim-org:main' into exponential_springs
fcanderson Jan 28, 2023
d1a605c
Minor changes to comments.
fcanderson Jan 28, 2023
855b73a
Added tests for Discrete Variable accessors.
fcanderson Jan 28, 2023
cf84b90
ExponentialContact:: added methods related to Discrete States.
fcanderson Jan 28, 2023
e114e54
Component: modifications to accommodate externally allocated Discrete…
fcanderson Jan 28, 2023
b1cf08d
Merge branch 'opensim-org:main' into exponential_springs
fcanderson Feb 5, 2023
0e67551
Merge branch 'exponential_springs' of https://github.com/fcanderson/o…
fcanderson Feb 5, 2023
0ea90bc
ExponentialContact: Exported elastic anchor point as a discrete varia…
fcanderson Feb 12, 2023
437feb7
[WIP] Modifications to support serializing Discrete Variables.
fcanderson Feb 12, 2023
63ff32f
Removed wip methods for traversing to a DiscreteVariable.
fcanderson Apr 27, 2023
69e747e
Discrete variables can now be accessed by path.
fcanderson May 6, 2023
9f2ee6d
Component.h: fixed a few typos
fcanderson May 9, 2023
19d99e7
testExponentialContact: output simulated states
fcanderson May 9, 2023
3f8e4d4
testExponentialContact: added StatesTrajectoryReporter
fcanderson May 15, 2023
eefb305
Merge branch 'opensim-org:main' into exponential_springs
fcanderson May 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
287 changes: 258 additions & 29 deletions OpenSim/Common/Component.cpp

Large diffs are not rendered by default.

229 changes: 220 additions & 9 deletions OpenSim/Common/Component.h
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,13 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object);
*/
Array<std::string> getStateVariableNames() const;

/**
* Get the names of discrete state variables maintained by the Component
* and its subcomponents.
* @throws ComponentHasNoSystem if this Component has not been added to a
* System (i.e., if initSystem has not been called)
*/
Array<std::string> getDiscreteVariableNames() const;

/** @name Component Socket Access methods
Access Sockets of this component by name. */
Expand Down Expand Up @@ -1369,16 +1376,17 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object);
const std::string& name) const;

/**
* Get the value of a discrete variable allocated by this Component by name.
* Get the value (assumed to be type double) of a discrete variable
* allocated by this Component by name.
*
* @param state the State from which to get the value
* @param name the name of the state variable
* @return value the discrete variable value
* @return value the discrete variable value as a double
* @throws ComponentHasNoSystem if this Component has not been added to a
* System (i.e., if initSystem has not been called)
*/
double getDiscreteVariableValue(const SimTK::State& state,
const std::string& name) const;
const std::string& name) const;

/**
* %Set the value of a discrete variable allocated by this Component by name.
Expand All @@ -1392,6 +1400,149 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object);
void setDiscreteVariableValue(SimTK::State& state, const std::string& name,
double value) const;


//-------------------------------------------------------------------------
// F. C. Anderson (January 2023, May 2023)
// Added the ability to get the value of a discrete variable as a
// SimTK::AbstractValue, thereby allowing types like Vec3.
// In addition, getDiscreteVariableAbstractValue() and
// updDiscreteVariableAbstractValue() accept the path of a discrete
// variable, not just its name.

/**
* Based on a specified path, resolve the name of a discrete variable and
* the component that owns it (i.e., its parent).
*
* @param pathName Specified path of the discrete variable in the Model
* heirarchy.
* @param dvName Returned name of the discrete variable. This string is
* simply the last string in the specified pathName.
* @return Pointer to the Component that owns the discrete variable.
*/
const Component* resolveDiscreteVariableNameAndOwner(
const std::string& pathName, std::string& dvName) const;

/**
* Retrieve a read-only reference to the abstract value of the discrete
* variable at a specified path. This method provides a more general
* interface that is not limited to values of type double.
*
* To obtain the type-specific value of a discrete variable, perform
* a cast using the template methods provided in class SimTK::Value<T>.
* When the type is unknow, it can be querried using the
Copy link
Member

@nickbianco nickbianco May 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of typos here: unknow --> unknown and querried -- > queried.

* SimTK::Value<T>::isA() method. For example,
*
* ```
* const SimTK::AbstractValue& valAbstract =
* getDiscreteVariableAbstractValue(state, pathName);
*
* if (SimTK::Value<double>::isA(valAbstract)) {
* const SimTK::Value<double>& valDbl =
* SimTK::Value<double>::downcast(valAbstract);
* double x = valDbl + 0.4;
*
* } else if (SimTK::Value<Vec3>::isA(valAbstract)) {
* const SimTK::Value<Vec3>& valVec3 =
* SimTK::Value<Vec3>::downcast(valAbstract);
* Vec3 x = valDbl + Vec3(0.4);
* }
* ```
*
* @param state State from which to get the value.
* @param pathName Specified path of the discrete variable in the Model
* heirarchy.
* @return Value of the discrete variable as a reference to an
* AbstractValue.
* @throws ComponentHasNoSystem if this Component has not been added to a
* System (i.e., if initSystem has not been called).
* @throws Exception if the discrete variable is not found.
*/
const SimTK::AbstractValue& getDiscreteVariableAbstractValue(
const SimTK::State& state, const std::string& pathName) const;

/**
* Retrieve a writable reference to the abstract value of the discrete
* variable at a specified path. This method provides a more general
* interface that is not limited to values of type double.
*
* To obtain the type-specific value of a discrete variable, perform
* a cast using the template methods provided in class SimTK::Value<T>.
* When the type is unknow, it can be querried using the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same typos here.

* SimTK::Value<T>::isA() method. For example,
*
* ```
* SimTK::AbstractValue& valAbstract =
* updDiscreteVariableAbstractValue(state, pathName);
*
* if (SimTK::Value<double>::isA(valAbstract)) {
* SimTK::Value<double>& valDbl =
* SimTK::Value<double>::updDowncast(valAbstract);
* valDbl = 0.4;
*
* } else if (SimTK::Value<Vec3>::isA(valAbstract)) {
* SimTK::Value<Vec3>& valVec3 =
* SimTK::Value<Vec3>::updDowncast(valAbstract);
* valDbl = Vec3(0.4);
* }
* ```
*
* @param state State from which to get the value.
* @param pathName Specified path of the discrete variable in the Model
* heirarchy.
* @return Value of the discrete variable as a reference to an
* AbstractValue.
* @throws ComponentHasNoSystem if this Component has not been added to a
* System (i.e., if initSystem has not been called).
* @throws Exception if the discrete variable is not found.
*/
SimTK::AbstractValue& updDiscreteVariableAbstractValue(
SimTK::State& state, const std::string& name) const;
//--------------------------------------------------------------------------



/**
* %Set the value of a discrete variable allocated by this Component by
* name. This method is a template to account for Discrete Variables that
* are not type double.
*
* @param s the State for which to set the value
* @param name the name of the discrete variable
* @param value the value to set
* @throws ComponentHasNoSystem if this Component has not been added to a
* System (i.e., if initSystem has not been called)
*/
template <class T>
void setDiscreteVariableValue(SimTK::State& s, const std::string& name,
const T& value) const
{
// Must have already called initSystem.
OPENSIM_THROW_IF_FRMOBJ(!hasSystem(), ComponentHasNoSystem);

std::map<std::string, DiscreteVariableInfo>::const_iterator it;
it = _namedDiscreteVariableInfo.find(name);

if (it != _namedDiscreteVariableInfo.end()) {
SimTK::DiscreteVariableIndex dvIndex = it->second.index;

// Account for non-default subsystem
const SimTK::Subsystem* subsystem = it->second.subsystem;
if (subsystem == nullptr) subsystem = &getDefaultSubsystem();

// Update the value
SimTK::Value<T>::downcast(
subsystem->updDiscreteVariable(s,dvIndex)) = value;

} else {
std::stringstream msg;
msg << "Component::setDiscreteVariable: ERR- name '" << name
<< "' not found.\n "
<< "for component '" << getName() << "' of type "
<< getConcreteClassName();
throw Exception(msg.str(), __FILE__, __LINE__);
}
}

/**
* A cache variable containing a value of type T.
*
Expand Down Expand Up @@ -1956,6 +2107,12 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object);

protected:
class StateVariable;

// F. C. Anderson (May 2023)
// Need declaration up front to support new methods for traversing the
// Component graph to Discrete Variables.
//struct DiscreteVariableInfo;

//template <class T> friend class ComponentSet;
// Give the ComponentMeasure access to the realize() methods.
template <class T> friend class ComponentMeasure;
Expand Down Expand Up @@ -2422,10 +2579,12 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object);
void addStateVariable(Component::StateVariable* stateVariable) const;

/** Add a system discrete variable belonging to this Component, give
it a name by which it can be referenced, and declare the lowest Stage that
should be invalidated if this variable's value is changed. **/
it a name by which it can be referenced, declare the lowest Stage that
should be invalidated if this variable's value is changed, and specify
whether the discrete state should be allocated by class Component.
*/
void addDiscreteVariable(const std::string& discreteVariableName,
SimTK::Stage invalidatesStage) const;
SimTK::Stage invalidatesStage, bool allocate = true) const;

/**
* Get writable reference to the MultibodySystem that this component is
Expand Down Expand Up @@ -2455,6 +2614,17 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object);
const SimTK::DiscreteVariableIndex
getDiscreteVariableIndex(const std::string& name) const;

/**
* Update the index of a Component's discrete variable. This method is
* intended for derived Components that may need to initialize the index
* held by OpenSim. Such a situation occurs when an underlying Simbody
* subsystem is responsible for the allocation of a discrete variable
* (not OpenSim), and OpenSim needs to be told the value of that index.
*/
void updDiscreteVariableIndex(const std::string& name,
const SimTK::DiscreteVariableIndex& index,
const SimTK::Subsystem* subsystem = nullptr) const;

// End of System Creation and Access Methods.
//@}

Expand Down Expand Up @@ -2657,6 +2827,8 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object);
*/
const StateVariable* traverseToStateVariable(
const ComponentPath& path) const;


#endif

/// @name Access to the owning component (advanced).
Expand Down Expand Up @@ -2934,6 +3106,18 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object);
{ return (int)_namedStateVariableInfo.size(); }
Array<std::string> getStateVariableNamesAddedByComponent() const;

// F. C. Anderson (Feb 2023)
// Added so that discrete states can be serialized and deserialized.
//
// Get the number of discrete states that the Component added to the
// underlying computational system. It includes the number of built-in
// discrete states exposed by this component. It represents the number of
// discrete variables managed by this Component.
int getNumDiscreteVariablesAddedByComponent() const {
return (int)_namedDiscreteVariableInfo.size();
}
Array<std::string> getDiscreteVariableNamesAddedByComponent() const;

const SimTK::DefaultSystemSubsystem& getDefaultSubsystem() const
{ return getSystem().getDefaultSubsystem(); }
SimTK::DefaultSystemSubsystem& updDefaultSubsystem() const
Expand Down Expand Up @@ -3176,17 +3360,44 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object);
int order;
};

// Structure to hold related info about discrete variables
// Structure to hold related info about discrete variables.
struct DiscreteVariableInfo {
DiscreteVariableInfo() {}
explicit DiscreteVariableInfo(SimTK::Stage invalidates)
: invalidatesStage(invalidates) {}
explicit DiscreteVariableInfo(SimTK::Stage invalidates,
bool allocate = true) :
invalidatesStage(invalidates), allocate(allocate) {}

// Model
SimTK::Stage invalidatesStage;

// System
SimTK::DiscreteVariableIndex index;

// F. C. Anderson (Jan 2023)
// Introduced two data members: 'subsystem' and 'allocate'.
// These two data members allow OpenSim::Component to expose a
// discrete state that was allocated by a class other than
// OpenSim::Component and as a member of Subsystem other than the
// default SimTK::Subsystem.

// Subsystem to which the discrete state belongs.
// If 'nullptr' (default), class Component assumes that the discrete
// state was allocated as a member of the default SimTK::Subsystem.
const SimTK::Subsystem* subsystem{nullptr};

// Flag to prevent a double allocation.
// If 'true' (default), the discrete variable is allocated normally
// in Component::extendRealizeTopology().
// If 'false', allocation in Component::extendRealizeTopology() is
// skipped and is assumed to occur elsewhere. In this case, the
// derived Component is responsible for initializing the index of the
// discrete state, as well as its Subsystem. This should be done by
// implementing an overriding extendRealizeTopology() method.
// See ExponentialContact::extendRealizeTopology() for an example.
bool allocate{true};
};


/**
* A cache variable, as stored internally by Component.
*/
Expand Down
Loading