Skip to content

Commit e6a1b25

Browse files
authored
Merge pull request opensim-org#3500 from ComputationalBiomechanicsLab/refactor-fiber-state-estimate-result
Cleanup: Muscle state estimate return type in `Millard2012QuilibriumMuscle`
2 parents 63f69c6 + 838db49 commit e6a1b25

File tree

2 files changed

+71
-93
lines changed

2 files changed

+71
-93
lines changed

OpenSim/Actuators/Millard2012EquilibriumMuscle.cpp

Lines changed: 59 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -556,43 +556,38 @@ computeFiberEquilibrium(SimTK::State& s, bool solveForVelocity) const
556556
double pathSpeed = solveForVelocity ? getLengtheningSpeed(s) : 0;
557557
double activation = getActivation(s);
558558

559-
try {
560-
std::pair<StatusFromEstimateMuscleFiberState,
561-
ValuesFromEstimateMuscleFiberState> result =
562-
estimateMuscleFiberState(activation, pathLength, pathSpeed,
563-
tol, maxIter, solveForVelocity);
564-
565-
switch(result.first) {
566-
567-
case StatusFromEstimateMuscleFiberState::Success_Converged:
568-
setActuation(s, result.second["tendon_force"]);
569-
setFiberLength(s, result.second["fiber_length"]);
570-
break;
571-
572-
case StatusFromEstimateMuscleFiberState::Warning_FiberAtLowerBound:
573-
log_warn("Millard2012EquilibriumMuscle static solution: '{}' is "
574-
"at its minimum fiber length of {}.",
575-
getName(), result.second["fiber_length"]);
576-
setActuation(s, result.second["tendon_force"]);
577-
setFiberLength(s, result.second["fiber_length"]);
578-
break;
579-
580-
case StatusFromEstimateMuscleFiberState::Failure_MaxIterationsReached:
581-
// Report internal variables and throw exception.
582-
std::ostringstream ss;
583-
ss << "\n Solution error " << abs(result.second["solution_error"])
584-
<< " exceeds tolerance of " << tol << "\n"
585-
<< " Newton iterations reached limit of " << maxIter << "\n"
586-
<< " Activation is " << activation << "\n"
587-
<< " Fiber length is " << result.second["fiber_length"] << "\n";
588-
OPENSIM_THROW_FRMOBJ(MuscleCannotEquilibrate, ss.str());
589-
break;
590-
}
559+
const MuscleStateEstimate result =
560+
estimateMuscleFiberState(
561+
activation,
562+
pathLength,
563+
pathSpeed,
564+
tol,
565+
maxIter,
566+
solveForVelocity);
567+
568+
if (result.status ==
569+
MuscleStateEstimate::Status::Failure_MaxIterationsReached) {
570+
std::ostringstream oss;
571+
oss << "Failed to compute muscle equilibrium state:\n"
572+
<< " Solution error " << std::abs(result.solutionError)
573+
<< " exceeds tolerance of " << tol << "\n"
574+
<< " Newton iterations reached limit of " << maxIter << "\n"
575+
<< " Activation is " << activation << "\n"
576+
<< " Fiber length is " << result.fiberLength << "\n";
577+
OPENSIM_THROW_FRMOBJ(MuscleCannotEquilibrate, oss.str());
578+
}
591579

592-
} catch (const std::exception& x) {
593-
OPENSIM_THROW_FRMOBJ(MuscleCannotEquilibrate,
594-
"Internal exception encountered.\n" + std::string{x.what()});
580+
if (result.status ==
581+
MuscleStateEstimate::Status::Warning_FiberAtLowerBound) {
582+
log_warn(
583+
"Millard2012EquilibriumMuscle static solution: '{}' is at its"
584+
"minimum fiber length of {}.",
585+
getName(),
586+
result.fiberLength);
595587
}
588+
589+
setActuation(s, result.tendonForce);
590+
setFiberLength(s, result.fiberLength);
596591
}
597592

598593
//==============================================================================
@@ -1355,15 +1350,14 @@ double Millard2012EquilibriumMuscle::clampFiberLength(double lce) const
13551350
return max(lce, getMinimumFiberLength());
13561351
}
13571352

1358-
std::pair<Millard2012EquilibriumMuscle::StatusFromEstimateMuscleFiberState,
1359-
Millard2012EquilibriumMuscle::ValuesFromEstimateMuscleFiberState>
1360-
Millard2012EquilibriumMuscle::estimateMuscleFiberState(
1361-
const double aActivation,
1362-
const double pathLength,
1363-
const double pathLengtheningSpeed,
1364-
const double aSolTolerance,
1365-
const int aMaxIterations,
1366-
bool staticSolution) const
1353+
Millard2012EquilibriumMuscle::MuscleStateEstimate
1354+
Millard2012EquilibriumMuscle::estimateMuscleFiberState(
1355+
const double aActivation,
1356+
const double pathLength,
1357+
const double pathLengtheningSpeed,
1358+
const double aSolTolerance,
1359+
const int aMaxIterations,
1360+
bool staticSolution) const
13671361
{
13681362
// If seeking a static solution, set velocities to zero and avoid the
13691363
// velocity-sharing algorithm below, as it can produce nonzero fiber and
@@ -1600,59 +1594,44 @@ Millard2012EquilibriumMuscle::estimateMuscleFiberState(
16001594
iter++;
16011595
}
16021596

1603-
// Populate the result map.
1604-
ValuesFromEstimateMuscleFiberState resultValues;
1597+
MuscleStateEstimate result;
1598+
result.solutionError = ferr;
16051599

1606-
if(abs(ferr) < aSolTolerance) { // The solution converged.
1600+
// Check if solution converged.
1601+
if(abs(ferr) < aSolTolerance) {
1602+
result.status = MuscleStateEstimate::Status::Success_Converged;
16071603

1608-
if (isFiberStateClamped(lce, dlceN)) {
1609-
lce = getMinimumFiberLength();
1610-
}
1611-
1612-
resultValues["solution_error"] = ferr;
1613-
resultValues["iterations"] = (double)iter;
1614-
resultValues["fiber_length"] = lce;
1615-
resultValues["fiber_velocity"] = dlce;
1616-
resultValues["tendon_force"] = fse*fiso;
1604+
result.fiberLength = clampFiberLength(lce);
1605+
result.tendonVelocity = dlce;
1606+
result.tendonForce = fse * fiso;
16171607

1618-
return std::pair<StatusFromEstimateMuscleFiberState,
1619-
ValuesFromEstimateMuscleFiberState>
1620-
(StatusFromEstimateMuscleFiberState::Success_Converged, resultValues);
1608+
return result;
16211609
}
16221610

1623-
// Fiber length is at or exceeds its lower bound.
1611+
// Check if fiberlength is at or exceeds lower bound.
16241612
if (lce <= getMinimumFiberLength()) {
1613+
result.status = MuscleStateEstimate::Status::
1614+
Warning_FiberAtLowerBound;
16251615

1626-
lce = getMinimumFiberLength();
1616+
lce = getMinimumFiberLength();
16271617
phi = getPennationModel().calcPennationAngle(lce);
16281618
cosphi = cos(phi);
16291619
tl = getPennationModel().calcTendonLength(cosphi,lce,ml);
16301620
lceN = lce/ofl;
16311621
tlN = tl/tsl;
16321622
fse = fseCurve.calcValue(tlN);
16331623

1634-
resultValues["solution_error"] = ferr;
1635-
resultValues["iterations"] = (double)iter;
1636-
resultValues["fiber_length"] = lce;
1637-
resultValues["fiber_velocity"] = 0;
1638-
resultValues["tendon_force"] = fse*fiso;
1624+
result.fiberLength = lce;
1625+
result.tendonVelocity = 0;
1626+
result.tendonForce = fse * fiso;
16391627

1640-
return std::pair<StatusFromEstimateMuscleFiberState,
1641-
ValuesFromEstimateMuscleFiberState>
1642-
(StatusFromEstimateMuscleFiberState::Warning_FiberAtLowerBound,
1643-
resultValues);
1628+
return result;
16441629
}
16451630

1646-
resultValues["solution_error"] = ferr;
1647-
resultValues["iterations"] = (double)iter;
1648-
resultValues["fiber_length"] = SimTK::NaN;
1649-
resultValues["fiber_velocity"] = SimTK::NaN;
1650-
resultValues["tendon_force"] = SimTK::NaN;
1651-
1652-
return std::pair<StatusFromEstimateMuscleFiberState,
1653-
ValuesFromEstimateMuscleFiberState>
1654-
(StatusFromEstimateMuscleFiberState::Failure_MaxIterationsReached,
1655-
resultValues);
1631+
// Solution failed to converge.
1632+
result.status = MuscleStateEstimate::Status::
1633+
Failure_MaxIterationsReached;
1634+
return result;
16561635
}
16571636

16581637
//==============================================================================

OpenSim/Actuators/Millard2012EquilibriumMuscle.h

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -734,18 +734,19 @@ OpenSim_DECLARE_CONCRETE_OBJECT(Millard2012EquilibriumMuscle, Muscle);
734734
// length.
735735
double clampFiberLength(double lce) const;
736736

737-
// Status flag returned by estimateMuscleFiberState().
738-
enum StatusFromEstimateMuscleFiberState {
739-
Success_Converged,
740-
Warning_FiberAtLowerBound,
741-
Failure_MaxIterationsReached
737+
struct MuscleStateEstimate {
738+
double solutionError = SimTK::NaN;
739+
double fiberLength = SimTK::NaN;
740+
double tendonVelocity = SimTK::NaN;
741+
double tendonForce = SimTK::NaN;
742+
743+
enum class Status {
744+
Success_Converged,
745+
Warning_FiberAtLowerBound,
746+
Failure_MaxIterationsReached
747+
} status = Status::Failure_MaxIterationsReached;
742748
};
743749

744-
// Associative array of values returned by estimateMuscleFiberState():
745-
// solution_error, iterations, fiber_length, fiber_velocity, and
746-
// tendon_force.
747-
typedef std::map<std::string, double> ValuesFromEstimateMuscleFiberState;
748-
749750
/* Solves fiber length and velocity to satisfy the equilibrium equations.
750751
The velocity of the entire musculotendon actuator is shared between the
751752
tendon and the fiber based on their relative mechanical stiffnesses.
@@ -760,9 +761,7 @@ OpenSim_DECLARE_CONCRETE_OBJECT(Millard2012EquilibriumMuscle, Muscle);
760761
@param staticSolution set to true to calculate the static equilibrium
761762
solution, setting fiber and tendon velocities to zero
762763
*/
763-
std::pair<StatusFromEstimateMuscleFiberState,
764-
ValuesFromEstimateMuscleFiberState>
765-
estimateMuscleFiberState(const double aActivation,
764+
MuscleStateEstimate estimateMuscleFiberState(const double aActivation,
766765
const double pathLength,
767766
const double pathLengtheningSpeed,
768767
const double aSolTolerance,

0 commit comments

Comments
 (0)