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

Implement AbstractPath and related API changes to support multiple path types #3535

Merged
merged 25 commits into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
34daa7a
First pass at implementing AbstractPath
nickbianco Aug 23, 2023
3d5c2ee
Update examples and tests after GeometryPath API changes
nickbianco Aug 24, 2023
e0f19be
Merge branch 'main' into wrapping_abstract_path
nickbianco Aug 25, 2023
81d1aee
Safely initialize GeometryPath for path-based objects
nickbianco Aug 25, 2023
b4f11fd
Update changelog // use updPath instead of upd_path
nickbianco Aug 26, 2023
b70b2fa
Update the Java bindings with path changes
nickbianco Aug 28, 2023
5e98a45
Revert Appearance to unnamed property
nickbianco Aug 29, 2023
4f81105
Add deprecated functions (e.g., getGeometryPath()) back in
nickbianco Aug 29, 2023
016d8bd
Reverting API changes pt. 2 + diff clean up
nickbianco Aug 29, 2023
bb4b8be
Reverting API changes pt. 3 + more diff clean up
nickbianco Aug 29, 2023
5a74515
More diff clean up
nickbianco Aug 29, 2023
ce3b0c4
Stop IDE from removing trailing whitespaces...
nickbianco Aug 29, 2023
c383f64
Rule of five; more code clean up
nickbianco Aug 30, 2023
e57c1f6
Handle unsupported path types when replacing muscles
nickbianco Aug 30, 2023
e53ea0b
Remove initGeometryPath() for now
nickbianco Aug 30, 2023
c3ac610
Backwards compatibility for deserializing GeometryPath
nickbianco Aug 30, 2023
df76b0a
Add abstraction for path copying
nickbianco Aug 31, 2023
f64e3cd
Move path properties back to public scope
nickbianco Aug 31, 2023
f6e7208
More reverted code
nickbianco Aug 31, 2023
2940c77
Remove unnecessary includes
nickbianco Aug 31, 2023
25ed001
Rename copyFrom() to assign(); change hasPath() to hasVisualPath()
nickbianco Sep 1, 2023
e9e0008
Move backwards compatibility for GeometryPath deserialization to Force
nickbianco Sep 1, 2023
507e4e1
Minor whitespace cleanup
nickbianco Sep 1, 2023
83577ea
Use AbstractProperty::assign() instead of a new virtual method
nickbianco Sep 6, 2023
83959bb
Flesh out changelog
nickbianco Sep 7, 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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ request related to the change, then we may provide the commit.

This is not a comprehensive list of changes but rather a hand-curated collection of the more notable ones. For a comprehensive history, see the [OpenSim Core GitHub repo](https://github.com/opensim-org/opensim-core).

v4.5
====
- Added `AbstractPath` which is a base class for `GeometryPath` and other path types (#3388). All path-based forces now
own the property `path` of type `AbstractPath` instead of the `GeometryPath` unnamed property. Getters and setters have
been added to these forces to provide access to concrete path types (e.g., `updPath<T>`). In `Ligament` and
`Blankevoort1991Ligament`, usages of `get_GeometryPath`, `upd_GeometryPath`, etc., need to be been updated to
`getGeometryPath`, `updGeometryPath`, etc., or a suitable alternative.

v4.4.1
======
- IMU::calcGyroscopeSignal() now reports angular velocities in the IMU frame.
Expand Down
34 changes: 3 additions & 31 deletions OpenSim/Actuators/DeGrooteFregly2016Muscle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1020,35 +1020,7 @@ void DeGrooteFregly2016Muscle::replaceMuscles(
muscBase.get_ignore_tendon_compliance());
actu->set_ignore_activation_dynamics(
muscBase.get_ignore_activation_dynamics());

const auto& pathPointSet = muscBase.getGeometryPath().getPathPointSet();
auto& geomPath = actu->updGeometryPath();
for (int ipp = 0; ipp < pathPointSet.getSize(); ++ipp) {
auto* pathPoint = pathPointSet.get(ipp).clone();
const auto& socketNames = pathPoint->getSocketNames();
for (const auto& socketName : socketNames) {
pathPoint->updSocket(socketName)
.connect(pathPointSet.get(ipp)
.getSocket(socketName)
.getConnecteeAsObject());
}
geomPath.updPathPointSet().adoptAndAppend(pathPoint);
}

const auto& pathWrapSet = muscBase.getGeometryPath().getWrapSet();
for (int ipw = 0; ipw < pathWrapSet.getSize(); ++ipw) {
auto* pathWrap = pathWrapSet.get(ipw).clone();
const auto& socketNames = pathWrap->getSocketNames();
for (const auto& socketName : socketNames) {
pathWrap->updSocket(socketName)
.connect(pathWrapSet.get(ipw)
.getSocket(socketName)
.getConnecteeAsObject());
}
geomPath.updWrapSet().adoptAndAppend(pathWrap);
}

std::string actname = actu->getName();
actu->updProperty_path().assign(muscBase.getProperty_path());
model.addForce(actu.release());

musclesToDelete.push_back(&muscBase);
Expand All @@ -1074,14 +1046,14 @@ void DeGrooteFregly2016Muscle::extendPostScale(
const SimTK::State& s, const ScaleSet& scaleSet) {
Super::extendPostScale(s, scaleSet);

GeometryPath& path = upd_GeometryPath();
AbstractPath& path = updPath();
adamkewley marked this conversation as resolved.
Show resolved Hide resolved
if (path.getPreScaleLength(s) > 0.0)
{
double scaleFactor = path.getLength(s) / path.getPreScaleLength(s);
upd_optimal_fiber_length() *= scaleFactor;
upd_tendon_slack_length() *= scaleFactor;

// Clear the pre-scale length that was stored in the GeometryPath.
// Clear the pre-scale length that was stored in the path.
path.setPreScaleLength(s, 0.0);
}
}
2 changes: 1 addition & 1 deletion OpenSim/Actuators/McKibbenActuator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ void McKibbenActuator::computeForce(const SimTK::State& s,

double actuation = computeActuation(s);

getGeometryPath().addInEquivalentForces(s, actuation, bodyForces, generalizedForces);
getPath().addInEquivalentForces(s, actuation, bodyForces, generalizedForces);
}
//_____________________________________________________________________________
/**
Expand Down
4 changes: 2 additions & 2 deletions OpenSim/Actuators/Millard2012AccelerationMuscle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -557,14 +557,14 @@ extendPostScale(const SimTK::State& s, const ScaleSet& scaleSet)

Super::extendPostScale(s, scaleSet);

GeometryPath& path = upd_GeometryPath();
AbstractPath& path = updPath();
if (path.getPreScaleLength(s) > 0.0)
{
double scaleFactor = path.getLength(s) / path.getPreScaleLength(s);
upd_optimal_fiber_length() *= scaleFactor;
upd_tendon_slack_length() *= scaleFactor;

// Clear the pre-scale length that was stored in the GeometryPath.
// Clear the pre-scale length that was stored in the path.
path.setPreScaleLength(s, 0.0);
}
}
Expand Down
4 changes: 2 additions & 2 deletions OpenSim/Actuators/Millard2012EquilibriumMuscle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -598,14 +598,14 @@ extendPostScale(const SimTK::State& s, const ScaleSet& scaleSet)
{
Super::extendPostScale(s, scaleSet);

GeometryPath& path = upd_GeometryPath();
AbstractPath& path = updPath();
if (path.getPreScaleLength(s) > 0.0)
{
double scaleFactor = path.getLength(s) / path.getPreScaleLength(s);
upd_optimal_fiber_length() *= scaleFactor;
upd_tendon_slack_length() *= scaleFactor;

// Clear the pre-scale length that was stored in the GeometryPath.
// Clear the pre-scale length that was stored in the path.
path.setPreScaleLength(s, 0.0);
}
}
Expand Down
41 changes: 7 additions & 34 deletions OpenSim/Actuators/ModelFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <OpenSim/Simulation/SimbodyEngine/PinJoint.h>
#include <OpenSim/Simulation/SimbodyEngine/SliderJoint.h>
#include <OpenSim/Simulation/SimbodyEngine/WeldJoint.h>
#include <OpenSim/Simulation/Model/GeometryPath.h>
#include <OpenSim/Common/CommonUtilities.h>

using namespace OpenSim;
Expand Down Expand Up @@ -158,49 +159,21 @@ void ModelFactory::replaceMusclesWithPathActuators(OpenSim::Model &model) {

// Create path actuators from muscle properties and add to the model. Save
// a list of pointers of the muscles to delete.
model.finalizeConnections();
std::vector<Muscle*> musclesToDelete;
auto& muscleSet = model.updMuscles();
for (int im = 0; im < muscleSet.getSize(); ++im) {
auto& musc = muscleSet.get(im);
auto* actu = new PathActuator();
auto actu = OpenSim::make_unique<PathActuator>();
actu->setName(musc.getName());
musc.setName(musc.getName() + "_delete");
actu->set_appliesForce(musc.get_appliesForce());
actu->setOptimalForce(musc.getMaxIsometricForce());
actu->setMinControl(musc.getMinControl());
actu->setMaxControl(musc.getMaxControl());

model.addForce(actu);

// For the connectee names in the PathPoints to be correct, we must add
// the path points after adding the PathActuator to the model.
const auto& pathPointSet = musc.getGeometryPath().getPathPointSet();
auto& geomPath = actu->updGeometryPath();
for (int ip = 0; ip < pathPointSet.getSize(); ++ip) {
auto* pathPoint = pathPointSet.get(ip).clone();
const auto& socketNames = pathPoint->getSocketNames();
for (const auto& socketName : socketNames) {
pathPoint->updSocket(socketName)
.connect(pathPointSet.get(ip)
.getSocket(socketName)
.getConnecteeAsObject());
}
geomPath.updPathPointSet().adoptAndAppend(pathPoint);
}

// For the connectee names in the PathWraps to be correct, we must add
// the path wraps after adding the PathActuator to the model.
const auto& pathWrapSet = musc.getGeometryPath().getWrapSet();
for (int ipw = 0; ipw < pathWrapSet.getSize(); ++ipw) {
auto* pathWrap = pathWrapSet.get(ipw).clone();
const auto& socketNames = pathWrap->getSocketNames();
for (const auto& socketName : socketNames) {
pathWrap->updSocket(socketName)
.connect(pathWrapSet.get(ipw)
.getSocket(socketName)
.getConnecteeAsObject());
}
geomPath.updWrapSet().adoptAndAppend(pathWrap);
}
actu->updProperty_path().assign(musc.getProperty_path());
actu->upd_path().setDefaultColor({0.5, 0.5, 0.5});
model.addForce(actu.release());

musclesToDelete.push_back(&musc);
}
Expand Down
2 changes: 1 addition & 1 deletion OpenSim/Actuators/ModelFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class OSIMACTUATORS_API ModelFactory {
/// @name Modify a Model
/// @{

/// Replace muscles in a model with a PathActuator of the same GeometryPath,
/// Replace muscles in a model with a PathActuator of the same path,
/// optimal force, and min/max control defaults.
/// @note This only replaces muscles within the model's ForceSet.
static void replaceMusclesWithPathActuators(Model& model);
Expand Down
2 changes: 1 addition & 1 deletion OpenSim/Actuators/RigidTendonMuscle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ void RigidTendonMuscle::calcMusclePotentialEnergyInfo(const SimTK::State& s,
void RigidTendonMuscle::calcFiberVelocityInfo(const State& s, FiberVelocityInfo& fvi) const
{
/*const MuscleLengthInfo &mli = */getMuscleLengthInfo(s);
fvi.fiberVelocity = getGeometryPath().getLengtheningSpeed(s);
fvi.fiberVelocity = getPath().getLengtheningSpeed(s);
fvi.normFiberVelocity = fvi.fiberVelocity /
(getOptimalFiberLength()*getMaxContractionVelocity());
fvi.fiberForceVelocityMultiplier =
Expand Down
3 changes: 2 additions & 1 deletion OpenSim/Common/XMLDocument.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@ using namespace std;
// 30516 for GeometryPath default_color -> Appearance
// 30517 for removal of _connectee_name suffix to shorten XML for socket, input
// 40000 for OpenSim 4.0 release 40000
// 40500 for updating 'GeometryPath' nodes to have property name 'path'.

const int XMLDocument::LatestVersion = 40000;
const int XMLDocument::LatestVersion = 40500;
//=============================================================================
// DESTRUCTOR AND CONSTRUCTOR(S)
//=============================================================================
Expand Down
68 changes: 68 additions & 0 deletions OpenSim/Simulation/Model/AbstractPath.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* -------------------------------------------------------------------------- *
* OpenSim: AbstractPath.cpp *
* -------------------------------------------------------------------------- *
* The OpenSim API is a toolkit for musculoskeletal modeling and simulation. *
* See http://opensim.stanford.edu and the NOTICE file for more information. *
* OpenSim is developed at Stanford University and supported by the US *
* National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA *
* through the Warrior Web program. *
* *
* Copyright (c) 2005-2023 Stanford University and the Authors *
* Author(s): Nicholas Bianco, Joris Verhagen, Adam Kewley *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may *
* not use this file except in compliance with the License. You may obtain a *
* copy of the License at http://www.apache.org/licenses/LICENSE-2.0. *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* -------------------------------------------------------------------------- */

#include "AbstractPath.h"
#include "Appearance.h"

using namespace OpenSim;

AbstractPath::AbstractPath() : ModelComponent() {
setAuthors("Nicholas Bianco, Joris Verhagen, Adam Kewley");

Appearance appearance;
appearance.set_color(SimTK::Gray);
constructProperty_Appearance(appearance);
}

AbstractPath::AbstractPath(AbstractPath const&) = default;

AbstractPath::~AbstractPath() noexcept = default;

AbstractPath& AbstractPath::operator=(const AbstractPath&) = default;
nickbianco marked this conversation as resolved.
Show resolved Hide resolved

AbstractPath::AbstractPath(AbstractPath&& other) = default;

AbstractPath& AbstractPath::operator=(AbstractPath&& other) = default;

// DEFAULTED METHODS
const SimTK::Vec3& AbstractPath::getDefaultColor() const
{
return get_Appearance().get_color();
}

void AbstractPath::setDefaultColor(const SimTK::Vec3& color)
{
updProperty_Appearance().setValueIsDefault(false);
upd_Appearance().set_color(color);
}

double AbstractPath::getPreScaleLength(const SimTK::State&) const
{
return _preScaleLength;
}

void AbstractPath::setPreScaleLength(const SimTK::State&,
double preScaleLength)
{
_preScaleLength = preScaleLength;
}
Loading