Skip to content

Commit

Permalink
Merge pull request #3535 from opensim-org/wrapping_abstract_path
Browse files Browse the repository at this point in the history
Implement `AbstractPath` and related API changes to support multiple path types
  • Loading branch information
nickbianco authored Sep 7, 2023
2 parents aeaaf93 + 83959bb commit 3f1fe38
Show file tree
Hide file tree
Showing 28 changed files with 555 additions and 249 deletions.
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();
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;

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

0 comments on commit 3f1fe38

Please sign in to comment.