mbuali's picture
Upload folder using huggingface_hub
d1ceb73 verified
"""Tests for the ``sympy.physics.biomechanics.musculotendon.py`` module."""
import abc
import pytest
from sympy.core.expr import UnevaluatedExpr
from sympy.core.numbers import Float, Integer, Rational
from sympy.core.symbol import Symbol
from sympy.functions.elementary.exponential import exp
from sympy.functions.elementary.hyperbolic import tanh
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.functions.elementary.trigonometric import sin
from sympy.matrices.dense import MutableDenseMatrix as Matrix, eye, zeros
from sympy.physics.biomechanics.activation import (
FirstOrderActivationDeGroote2016
)
from sympy.physics.biomechanics.curve import (
CharacteristicCurveCollection,
FiberForceLengthActiveDeGroote2016,
FiberForceLengthPassiveDeGroote2016,
FiberForceLengthPassiveInverseDeGroote2016,
FiberForceVelocityDeGroote2016,
FiberForceVelocityInverseDeGroote2016,
TendonForceLengthDeGroote2016,
TendonForceLengthInverseDeGroote2016,
)
from sympy.physics.biomechanics.musculotendon import (
MusculotendonBase,
MusculotendonDeGroote2016,
MusculotendonFormulation,
)
from sympy.physics.biomechanics._mixin import _NamedMixin
from sympy.physics.mechanics.actuator import ForceActuator
from sympy.physics.mechanics.pathway import LinearPathway
from sympy.physics.vector.frame import ReferenceFrame
from sympy.physics.vector.functions import dynamicsymbols
from sympy.physics.vector.point import Point
from sympy.simplify.simplify import simplify
class TestMusculotendonFormulation:
@staticmethod
def test_rigid_tendon_member():
assert MusculotendonFormulation(0) == 0
assert MusculotendonFormulation.RIGID_TENDON == 0
@staticmethod
def test_fiber_length_explicit_member():
assert MusculotendonFormulation(1) == 1
assert MusculotendonFormulation.FIBER_LENGTH_EXPLICIT == 1
@staticmethod
def test_tendon_force_explicit_member():
assert MusculotendonFormulation(2) == 2
assert MusculotendonFormulation.TENDON_FORCE_EXPLICIT == 2
@staticmethod
def test_fiber_length_implicit_member():
assert MusculotendonFormulation(3) == 3
assert MusculotendonFormulation.FIBER_LENGTH_IMPLICIT == 3
@staticmethod
def test_tendon_force_implicit_member():
assert MusculotendonFormulation(4) == 4
assert MusculotendonFormulation.TENDON_FORCE_IMPLICIT == 4
class TestMusculotendonBase:
@staticmethod
def test_is_abstract_base_class():
assert issubclass(MusculotendonBase, abc.ABC)
@staticmethod
def test_class():
assert issubclass(MusculotendonBase, ForceActuator)
assert issubclass(MusculotendonBase, _NamedMixin)
assert MusculotendonBase.__name__ == 'MusculotendonBase'
@staticmethod
def test_cannot_instantiate_directly():
with pytest.raises(TypeError):
_ = MusculotendonBase()
@pytest.mark.parametrize('musculotendon_concrete', [MusculotendonDeGroote2016])
class TestMusculotendonRigidTendon:
@pytest.fixture(autouse=True)
def _musculotendon_rigid_tendon_fixture(self, musculotendon_concrete):
self.name = 'name'
self.N = ReferenceFrame('N')
self.q = dynamicsymbols('q')
self.origin = Point('pO')
self.insertion = Point('pI')
self.insertion.set_pos(self.origin, self.q*self.N.x)
self.pathway = LinearPathway(self.origin, self.insertion)
self.activation = FirstOrderActivationDeGroote2016(self.name)
self.e = self.activation.excitation
self.a = self.activation.activation
self.tau_a = self.activation.activation_time_constant
self.tau_d = self.activation.deactivation_time_constant
self.b = self.activation.smoothing_rate
self.formulation = MusculotendonFormulation.RIGID_TENDON
self.l_T_slack = Symbol('l_T_slack')
self.F_M_max = Symbol('F_M_max')
self.l_M_opt = Symbol('l_M_opt')
self.v_M_max = Symbol('v_M_max')
self.alpha_opt = Symbol('alpha_opt')
self.beta = Symbol('beta')
self.instance = musculotendon_concrete(
self.name,
self.pathway,
self.activation,
musculotendon_dynamics=self.formulation,
tendon_slack_length=self.l_T_slack,
peak_isometric_force=self.F_M_max,
optimal_fiber_length=self.l_M_opt,
maximal_fiber_velocity=self.v_M_max,
optimal_pennation_angle=self.alpha_opt,
fiber_damping_coefficient=self.beta,
)
self.da_expr = (
(1/(self.tau_a*(Rational(1, 2) + Rational(3, 2)*self.a)))
*(Rational(1, 2) + Rational(1, 2)*tanh(self.b*(self.e - self.a)))
+ ((Rational(1, 2) + Rational(3, 2)*self.a)/self.tau_d)
*(Rational(1, 2) - Rational(1, 2)*tanh(self.b*(self.e - self.a)))
)*(self.e - self.a)
def test_state_vars(self):
assert hasattr(self.instance, 'x')
assert hasattr(self.instance, 'state_vars')
assert self.instance.x == self.instance.state_vars
x_expected = Matrix([self.a])
assert self.instance.x == x_expected
assert self.instance.state_vars == x_expected
assert isinstance(self.instance.x, Matrix)
assert isinstance(self.instance.state_vars, Matrix)
assert self.instance.x.shape == (1, 1)
assert self.instance.state_vars.shape == (1, 1)
def test_input_vars(self):
assert hasattr(self.instance, 'r')
assert hasattr(self.instance, 'input_vars')
assert self.instance.r == self.instance.input_vars
r_expected = Matrix([self.e])
assert self.instance.r == r_expected
assert self.instance.input_vars == r_expected
assert isinstance(self.instance.r, Matrix)
assert isinstance(self.instance.input_vars, Matrix)
assert self.instance.r.shape == (1, 1)
assert self.instance.input_vars.shape == (1, 1)
def test_constants(self):
assert hasattr(self.instance, 'p')
assert hasattr(self.instance, 'constants')
assert self.instance.p == self.instance.constants
p_expected = Matrix(
[
self.l_T_slack,
self.F_M_max,
self.l_M_opt,
self.v_M_max,
self.alpha_opt,
self.beta,
self.tau_a,
self.tau_d,
self.b,
Symbol('c_0_fl_T_name'),
Symbol('c_1_fl_T_name'),
Symbol('c_2_fl_T_name'),
Symbol('c_3_fl_T_name'),
Symbol('c_0_fl_M_pas_name'),
Symbol('c_1_fl_M_pas_name'),
Symbol('c_0_fl_M_act_name'),
Symbol('c_1_fl_M_act_name'),
Symbol('c_2_fl_M_act_name'),
Symbol('c_3_fl_M_act_name'),
Symbol('c_4_fl_M_act_name'),
Symbol('c_5_fl_M_act_name'),
Symbol('c_6_fl_M_act_name'),
Symbol('c_7_fl_M_act_name'),
Symbol('c_8_fl_M_act_name'),
Symbol('c_9_fl_M_act_name'),
Symbol('c_10_fl_M_act_name'),
Symbol('c_11_fl_M_act_name'),
Symbol('c_0_fv_M_name'),
Symbol('c_1_fv_M_name'),
Symbol('c_2_fv_M_name'),
Symbol('c_3_fv_M_name'),
]
)
assert self.instance.p == p_expected
assert self.instance.constants == p_expected
assert isinstance(self.instance.p, Matrix)
assert isinstance(self.instance.constants, Matrix)
assert self.instance.p.shape == (31, 1)
assert self.instance.constants.shape == (31, 1)
def test_M(self):
assert hasattr(self.instance, 'M')
M_expected = Matrix([1])
assert self.instance.M == M_expected
assert isinstance(self.instance.M, Matrix)
assert self.instance.M.shape == (1, 1)
def test_F(self):
assert hasattr(self.instance, 'F')
F_expected = Matrix([self.da_expr])
assert self.instance.F == F_expected
assert isinstance(self.instance.F, Matrix)
assert self.instance.F.shape == (1, 1)
def test_rhs(self):
assert hasattr(self.instance, 'rhs')
rhs_expected = Matrix([self.da_expr])
rhs = self.instance.rhs()
assert isinstance(rhs, Matrix)
assert rhs.shape == (1, 1)
assert simplify(rhs - rhs_expected) == zeros(1)
@pytest.mark.parametrize(
'musculotendon_concrete, curve',
[
(
MusculotendonDeGroote2016,
CharacteristicCurveCollection(
tendon_force_length=TendonForceLengthDeGroote2016,
tendon_force_length_inverse=TendonForceLengthInverseDeGroote2016,
fiber_force_length_passive=FiberForceLengthPassiveDeGroote2016,
fiber_force_length_passive_inverse=FiberForceLengthPassiveInverseDeGroote2016,
fiber_force_length_active=FiberForceLengthActiveDeGroote2016,
fiber_force_velocity=FiberForceVelocityDeGroote2016,
fiber_force_velocity_inverse=FiberForceVelocityInverseDeGroote2016,
),
)
],
)
class TestFiberLengthExplicit:
@pytest.fixture(autouse=True)
def _musculotendon_fiber_length_explicit_fixture(
self,
musculotendon_concrete,
curve,
):
self.name = 'name'
self.N = ReferenceFrame('N')
self.q = dynamicsymbols('q')
self.origin = Point('pO')
self.insertion = Point('pI')
self.insertion.set_pos(self.origin, self.q*self.N.x)
self.pathway = LinearPathway(self.origin, self.insertion)
self.activation = FirstOrderActivationDeGroote2016(self.name)
self.e = self.activation.excitation
self.a = self.activation.activation
self.tau_a = self.activation.activation_time_constant
self.tau_d = self.activation.deactivation_time_constant
self.b = self.activation.smoothing_rate
self.formulation = MusculotendonFormulation.FIBER_LENGTH_EXPLICIT
self.l_T_slack = Symbol('l_T_slack')
self.F_M_max = Symbol('F_M_max')
self.l_M_opt = Symbol('l_M_opt')
self.v_M_max = Symbol('v_M_max')
self.alpha_opt = Symbol('alpha_opt')
self.beta = Symbol('beta')
self.instance = musculotendon_concrete(
self.name,
self.pathway,
self.activation,
musculotendon_dynamics=self.formulation,
tendon_slack_length=self.l_T_slack,
peak_isometric_force=self.F_M_max,
optimal_fiber_length=self.l_M_opt,
maximal_fiber_velocity=self.v_M_max,
optimal_pennation_angle=self.alpha_opt,
fiber_damping_coefficient=self.beta,
with_defaults=True,
)
self.l_M_tilde = dynamicsymbols('l_M_tilde_name')
l_MT = self.pathway.length
l_M = self.l_M_tilde*self.l_M_opt
l_T = l_MT - sqrt(l_M**2 - (self.l_M_opt*sin(self.alpha_opt))**2)
fl_T = curve.tendon_force_length.with_defaults(l_T/self.l_T_slack)
fl_M_pas = curve.fiber_force_length_passive.with_defaults(self.l_M_tilde)
fl_M_act = curve.fiber_force_length_active.with_defaults(self.l_M_tilde)
v_M_tilde = curve.fiber_force_velocity_inverse.with_defaults(
((((fl_T*self.F_M_max)/((l_MT - l_T)/l_M))/self.F_M_max) - fl_M_pas)
/(self.a*fl_M_act)
)
self.dl_M_tilde_expr = (self.v_M_max/self.l_M_opt)*v_M_tilde
self.da_expr = (
(1/(self.tau_a*(Rational(1, 2) + Rational(3, 2)*self.a)))
*(Rational(1, 2) + Rational(1, 2)*tanh(self.b*(self.e - self.a)))
+ ((Rational(1, 2) + Rational(3, 2)*self.a)/self.tau_d)
*(Rational(1, 2) - Rational(1, 2)*tanh(self.b*(self.e - self.a)))
)*(self.e - self.a)
def test_state_vars(self):
assert hasattr(self.instance, 'x')
assert hasattr(self.instance, 'state_vars')
assert self.instance.x == self.instance.state_vars
x_expected = Matrix([self.l_M_tilde, self.a])
assert self.instance.x == x_expected
assert self.instance.state_vars == x_expected
assert isinstance(self.instance.x, Matrix)
assert isinstance(self.instance.state_vars, Matrix)
assert self.instance.x.shape == (2, 1)
assert self.instance.state_vars.shape == (2, 1)
def test_input_vars(self):
assert hasattr(self.instance, 'r')
assert hasattr(self.instance, 'input_vars')
assert self.instance.r == self.instance.input_vars
r_expected = Matrix([self.e])
assert self.instance.r == r_expected
assert self.instance.input_vars == r_expected
assert isinstance(self.instance.r, Matrix)
assert isinstance(self.instance.input_vars, Matrix)
assert self.instance.r.shape == (1, 1)
assert self.instance.input_vars.shape == (1, 1)
def test_constants(self):
assert hasattr(self.instance, 'p')
assert hasattr(self.instance, 'constants')
assert self.instance.p == self.instance.constants
p_expected = Matrix(
[
self.l_T_slack,
self.F_M_max,
self.l_M_opt,
self.v_M_max,
self.alpha_opt,
self.beta,
self.tau_a,
self.tau_d,
self.b,
]
)
assert self.instance.p == p_expected
assert self.instance.constants == p_expected
assert isinstance(self.instance.p, Matrix)
assert isinstance(self.instance.constants, Matrix)
assert self.instance.p.shape == (9, 1)
assert self.instance.constants.shape == (9, 1)
def test_M(self):
assert hasattr(self.instance, 'M')
M_expected = eye(2)
assert self.instance.M == M_expected
assert isinstance(self.instance.M, Matrix)
assert self.instance.M.shape == (2, 2)
def test_F(self):
assert hasattr(self.instance, 'F')
F_expected = Matrix([self.dl_M_tilde_expr, self.da_expr])
assert self.instance.F == F_expected
assert isinstance(self.instance.F, Matrix)
assert self.instance.F.shape == (2, 1)
def test_rhs(self):
assert hasattr(self.instance, 'rhs')
rhs_expected = Matrix([self.dl_M_tilde_expr, self.da_expr])
rhs = self.instance.rhs()
assert isinstance(rhs, Matrix)
assert rhs.shape == (2, 1)
assert simplify(rhs - rhs_expected) == zeros(2, 1)
@pytest.mark.parametrize(
'musculotendon_concrete, curve',
[
(
MusculotendonDeGroote2016,
CharacteristicCurveCollection(
tendon_force_length=TendonForceLengthDeGroote2016,
tendon_force_length_inverse=TendonForceLengthInverseDeGroote2016,
fiber_force_length_passive=FiberForceLengthPassiveDeGroote2016,
fiber_force_length_passive_inverse=FiberForceLengthPassiveInverseDeGroote2016,
fiber_force_length_active=FiberForceLengthActiveDeGroote2016,
fiber_force_velocity=FiberForceVelocityDeGroote2016,
fiber_force_velocity_inverse=FiberForceVelocityInverseDeGroote2016,
),
)
],
)
class TestTendonForceExplicit:
@pytest.fixture(autouse=True)
def _musculotendon_tendon_force_explicit_fixture(
self,
musculotendon_concrete,
curve,
):
self.name = 'name'
self.N = ReferenceFrame('N')
self.q = dynamicsymbols('q')
self.origin = Point('pO')
self.insertion = Point('pI')
self.insertion.set_pos(self.origin, self.q*self.N.x)
self.pathway = LinearPathway(self.origin, self.insertion)
self.activation = FirstOrderActivationDeGroote2016(self.name)
self.e = self.activation.excitation
self.a = self.activation.activation
self.tau_a = self.activation.activation_time_constant
self.tau_d = self.activation.deactivation_time_constant
self.b = self.activation.smoothing_rate
self.formulation = MusculotendonFormulation.TENDON_FORCE_EXPLICIT
self.l_T_slack = Symbol('l_T_slack')
self.F_M_max = Symbol('F_M_max')
self.l_M_opt = Symbol('l_M_opt')
self.v_M_max = Symbol('v_M_max')
self.alpha_opt = Symbol('alpha_opt')
self.beta = Symbol('beta')
self.instance = musculotendon_concrete(
self.name,
self.pathway,
self.activation,
musculotendon_dynamics=self.formulation,
tendon_slack_length=self.l_T_slack,
peak_isometric_force=self.F_M_max,
optimal_fiber_length=self.l_M_opt,
maximal_fiber_velocity=self.v_M_max,
optimal_pennation_angle=self.alpha_opt,
fiber_damping_coefficient=self.beta,
with_defaults=True,
)
self.F_T_tilde = dynamicsymbols('F_T_tilde_name')
l_T_tilde = curve.tendon_force_length_inverse.with_defaults(self.F_T_tilde)
l_MT = self.pathway.length
v_MT = self.pathway.extension_velocity
l_T = l_T_tilde*self.l_T_slack
l_M = sqrt((l_MT - l_T)**2 + (self.l_M_opt*sin(self.alpha_opt))**2)
l_M_tilde = l_M/self.l_M_opt
cos_alpha = (l_MT - l_T)/l_M
F_T = self.F_T_tilde*self.F_M_max
F_M = F_T/cos_alpha
F_M_tilde = F_M/self.F_M_max
fl_M_pas = curve.fiber_force_length_passive.with_defaults(l_M_tilde)
fl_M_act = curve.fiber_force_length_active.with_defaults(l_M_tilde)
fv_M = (F_M_tilde - fl_M_pas)/(self.a*fl_M_act)
v_M_tilde = curve.fiber_force_velocity_inverse.with_defaults(fv_M)
v_M = v_M_tilde*self.v_M_max
v_T = v_MT - v_M/cos_alpha
v_T_tilde = v_T/self.l_T_slack
self.dF_T_tilde_expr = (
Float('0.2')*Float('33.93669377311689')*exp(
Float('33.93669377311689')*UnevaluatedExpr(l_T_tilde - Float('0.995'))
)*v_T_tilde
)
self.da_expr = (
(1/(self.tau_a*(Rational(1, 2) + Rational(3, 2)*self.a)))
*(Rational(1, 2) + Rational(1, 2)*tanh(self.b*(self.e - self.a)))
+ ((Rational(1, 2) + Rational(3, 2)*self.a)/self.tau_d)
*(Rational(1, 2) - Rational(1, 2)*tanh(self.b*(self.e - self.a)))
)*(self.e - self.a)
def test_state_vars(self):
assert hasattr(self.instance, 'x')
assert hasattr(self.instance, 'state_vars')
assert self.instance.x == self.instance.state_vars
x_expected = Matrix([self.F_T_tilde, self.a])
assert self.instance.x == x_expected
assert self.instance.state_vars == x_expected
assert isinstance(self.instance.x, Matrix)
assert isinstance(self.instance.state_vars, Matrix)
assert self.instance.x.shape == (2, 1)
assert self.instance.state_vars.shape == (2, 1)
def test_input_vars(self):
assert hasattr(self.instance, 'r')
assert hasattr(self.instance, 'input_vars')
assert self.instance.r == self.instance.input_vars
r_expected = Matrix([self.e])
assert self.instance.r == r_expected
assert self.instance.input_vars == r_expected
assert isinstance(self.instance.r, Matrix)
assert isinstance(self.instance.input_vars, Matrix)
assert self.instance.r.shape == (1, 1)
assert self.instance.input_vars.shape == (1, 1)
def test_constants(self):
assert hasattr(self.instance, 'p')
assert hasattr(self.instance, 'constants')
assert self.instance.p == self.instance.constants
p_expected = Matrix(
[
self.l_T_slack,
self.F_M_max,
self.l_M_opt,
self.v_M_max,
self.alpha_opt,
self.beta,
self.tau_a,
self.tau_d,
self.b,
]
)
assert self.instance.p == p_expected
assert self.instance.constants == p_expected
assert isinstance(self.instance.p, Matrix)
assert isinstance(self.instance.constants, Matrix)
assert self.instance.p.shape == (9, 1)
assert self.instance.constants.shape == (9, 1)
def test_M(self):
assert hasattr(self.instance, 'M')
M_expected = eye(2)
assert self.instance.M == M_expected
assert isinstance(self.instance.M, Matrix)
assert self.instance.M.shape == (2, 2)
def test_F(self):
assert hasattr(self.instance, 'F')
F_expected = Matrix([self.dF_T_tilde_expr, self.da_expr])
assert self.instance.F == F_expected
assert isinstance(self.instance.F, Matrix)
assert self.instance.F.shape == (2, 1)
def test_rhs(self):
assert hasattr(self.instance, 'rhs')
rhs_expected = Matrix([self.dF_T_tilde_expr, self.da_expr])
rhs = self.instance.rhs()
assert isinstance(rhs, Matrix)
assert rhs.shape == (2, 1)
assert simplify(rhs - rhs_expected) == zeros(2, 1)
class TestMusculotendonDeGroote2016:
@staticmethod
def test_class():
assert issubclass(MusculotendonDeGroote2016, ForceActuator)
assert issubclass(MusculotendonDeGroote2016, _NamedMixin)
assert MusculotendonDeGroote2016.__name__ == 'MusculotendonDeGroote2016'
@staticmethod
def test_instance():
origin = Point('pO')
insertion = Point('pI')
insertion.set_pos(origin, dynamicsymbols('q')*ReferenceFrame('N').x)
pathway = LinearPathway(origin, insertion)
activation = FirstOrderActivationDeGroote2016('name')
l_T_slack = Symbol('l_T_slack')
F_M_max = Symbol('F_M_max')
l_M_opt = Symbol('l_M_opt')
v_M_max = Symbol('v_M_max')
alpha_opt = Symbol('alpha_opt')
beta = Symbol('beta')
instance = MusculotendonDeGroote2016(
'name',
pathway,
activation,
musculotendon_dynamics=MusculotendonFormulation.RIGID_TENDON,
tendon_slack_length=l_T_slack,
peak_isometric_force=F_M_max,
optimal_fiber_length=l_M_opt,
maximal_fiber_velocity=v_M_max,
optimal_pennation_angle=alpha_opt,
fiber_damping_coefficient=beta,
)
assert isinstance(instance, MusculotendonDeGroote2016)
@pytest.fixture(autouse=True)
def _musculotendon_fixture(self):
self.name = 'name'
self.N = ReferenceFrame('N')
self.q = dynamicsymbols('q')
self.origin = Point('pO')
self.insertion = Point('pI')
self.insertion.set_pos(self.origin, self.q*self.N.x)
self.pathway = LinearPathway(self.origin, self.insertion)
self.activation = FirstOrderActivationDeGroote2016(self.name)
self.l_T_slack = Symbol('l_T_slack')
self.F_M_max = Symbol('F_M_max')
self.l_M_opt = Symbol('l_M_opt')
self.v_M_max = Symbol('v_M_max')
self.alpha_opt = Symbol('alpha_opt')
self.beta = Symbol('beta')
def test_with_defaults(self):
origin = Point('pO')
insertion = Point('pI')
insertion.set_pos(origin, dynamicsymbols('q')*ReferenceFrame('N').x)
pathway = LinearPathway(origin, insertion)
activation = FirstOrderActivationDeGroote2016('name')
l_T_slack = Symbol('l_T_slack')
F_M_max = Symbol('F_M_max')
l_M_opt = Symbol('l_M_opt')
v_M_max = Float('10.0')
alpha_opt = Float('0.0')
beta = Float('0.1')
instance = MusculotendonDeGroote2016.with_defaults(
'name',
pathway,
activation,
musculotendon_dynamics=MusculotendonFormulation.RIGID_TENDON,
tendon_slack_length=l_T_slack,
peak_isometric_force=F_M_max,
optimal_fiber_length=l_M_opt,
)
assert instance.tendon_slack_length == l_T_slack
assert instance.peak_isometric_force == F_M_max
assert instance.optimal_fiber_length == l_M_opt
assert instance.maximal_fiber_velocity == v_M_max
assert instance.optimal_pennation_angle == alpha_opt
assert instance.fiber_damping_coefficient == beta
@pytest.mark.parametrize(
'l_T_slack, expected',
[
(None, Symbol('l_T_slack_name')),
(Symbol('l_T_slack'), Symbol('l_T_slack')),
(Rational(1, 2), Rational(1, 2)),
(Float('0.5'), Float('0.5')),
],
)
def test_tendon_slack_length(self, l_T_slack, expected):
instance = MusculotendonDeGroote2016(
self.name,
self.pathway,
self.activation,
musculotendon_dynamics=MusculotendonFormulation.RIGID_TENDON,
tendon_slack_length=l_T_slack,
peak_isometric_force=self.F_M_max,
optimal_fiber_length=self.l_M_opt,
maximal_fiber_velocity=self.v_M_max,
optimal_pennation_angle=self.alpha_opt,
fiber_damping_coefficient=self.beta,
)
assert instance.l_T_slack == expected
assert instance.tendon_slack_length == expected
@pytest.mark.parametrize(
'F_M_max, expected',
[
(None, Symbol('F_M_max_name')),
(Symbol('F_M_max'), Symbol('F_M_max')),
(Integer(1000), Integer(1000)),
(Float('1000.0'), Float('1000.0')),
],
)
def test_peak_isometric_force(self, F_M_max, expected):
instance = MusculotendonDeGroote2016(
self.name,
self.pathway,
self.activation,
musculotendon_dynamics=MusculotendonFormulation.RIGID_TENDON,
tendon_slack_length=self.l_T_slack,
peak_isometric_force=F_M_max,
optimal_fiber_length=self.l_M_opt,
maximal_fiber_velocity=self.v_M_max,
optimal_pennation_angle=self.alpha_opt,
fiber_damping_coefficient=self.beta,
)
assert instance.F_M_max == expected
assert instance.peak_isometric_force == expected
@pytest.mark.parametrize(
'l_M_opt, expected',
[
(None, Symbol('l_M_opt_name')),
(Symbol('l_M_opt'), Symbol('l_M_opt')),
(Rational(1, 2), Rational(1, 2)),
(Float('0.5'), Float('0.5')),
],
)
def test_optimal_fiber_length(self, l_M_opt, expected):
instance = MusculotendonDeGroote2016(
self.name,
self.pathway,
self.activation,
musculotendon_dynamics=MusculotendonFormulation.RIGID_TENDON,
tendon_slack_length=self.l_T_slack,
peak_isometric_force=self.F_M_max,
optimal_fiber_length=l_M_opt,
maximal_fiber_velocity=self.v_M_max,
optimal_pennation_angle=self.alpha_opt,
fiber_damping_coefficient=self.beta,
)
assert instance.l_M_opt == expected
assert instance.optimal_fiber_length == expected
@pytest.mark.parametrize(
'v_M_max, expected',
[
(None, Symbol('v_M_max_name')),
(Symbol('v_M_max'), Symbol('v_M_max')),
(Integer(10), Integer(10)),
(Float('10.0'), Float('10.0')),
],
)
def test_maximal_fiber_velocity(self, v_M_max, expected):
instance = MusculotendonDeGroote2016(
self.name,
self.pathway,
self.activation,
musculotendon_dynamics=MusculotendonFormulation.RIGID_TENDON,
tendon_slack_length=self.l_T_slack,
peak_isometric_force=self.F_M_max,
optimal_fiber_length=self.l_M_opt,
maximal_fiber_velocity=v_M_max,
optimal_pennation_angle=self.alpha_opt,
fiber_damping_coefficient=self.beta,
)
assert instance.v_M_max == expected
assert instance.maximal_fiber_velocity == expected
@pytest.mark.parametrize(
'alpha_opt, expected',
[
(None, Symbol('alpha_opt_name')),
(Symbol('alpha_opt'), Symbol('alpha_opt')),
(Integer(0), Integer(0)),
(Float('0.1'), Float('0.1')),
],
)
def test_optimal_pennation_angle(self, alpha_opt, expected):
instance = MusculotendonDeGroote2016(
self.name,
self.pathway,
self.activation,
musculotendon_dynamics=MusculotendonFormulation.RIGID_TENDON,
tendon_slack_length=self.l_T_slack,
peak_isometric_force=self.F_M_max,
optimal_fiber_length=self.l_M_opt,
maximal_fiber_velocity=self.v_M_max,
optimal_pennation_angle=alpha_opt,
fiber_damping_coefficient=self.beta,
)
assert instance.alpha_opt == expected
assert instance.optimal_pennation_angle == expected
@pytest.mark.parametrize(
'beta, expected',
[
(None, Symbol('beta_name')),
(Symbol('beta'), Symbol('beta')),
(Integer(0), Integer(0)),
(Rational(1, 10), Rational(1, 10)),
(Float('0.1'), Float('0.1')),
],
)
def test_fiber_damping_coefficient(self, beta, expected):
instance = MusculotendonDeGroote2016(
self.name,
self.pathway,
self.activation,
musculotendon_dynamics=MusculotendonFormulation.RIGID_TENDON,
tendon_slack_length=self.l_T_slack,
peak_isometric_force=self.F_M_max,
optimal_fiber_length=self.l_M_opt,
maximal_fiber_velocity=self.v_M_max,
optimal_pennation_angle=self.alpha_opt,
fiber_damping_coefficient=beta,
)
assert instance.beta == expected
assert instance.fiber_damping_coefficient == expected
def test_excitation(self):
instance = MusculotendonDeGroote2016(
self.name,
self.pathway,
self.activation,
)
assert hasattr(instance, 'e')
assert hasattr(instance, 'excitation')
e_expected = dynamicsymbols('e_name')
assert instance.e == e_expected
assert instance.excitation == e_expected
assert instance.e is instance.excitation
def test_excitation_is_immutable(self):
instance = MusculotendonDeGroote2016(
self.name,
self.pathway,
self.activation,
)
with pytest.raises(AttributeError):
instance.e = None
with pytest.raises(AttributeError):
instance.excitation = None
def test_activation(self):
instance = MusculotendonDeGroote2016(
self.name,
self.pathway,
self.activation,
)
assert hasattr(instance, 'a')
assert hasattr(instance, 'activation')
a_expected = dynamicsymbols('a_name')
assert instance.a == a_expected
assert instance.activation == a_expected
def test_activation_is_immutable(self):
instance = MusculotendonDeGroote2016(
self.name,
self.pathway,
self.activation,
)
with pytest.raises(AttributeError):
instance.a = None
with pytest.raises(AttributeError):
instance.activation = None
def test_repr(self):
instance = MusculotendonDeGroote2016(
self.name,
self.pathway,
self.activation,
musculotendon_dynamics=MusculotendonFormulation.RIGID_TENDON,
tendon_slack_length=self.l_T_slack,
peak_isometric_force=self.F_M_max,
optimal_fiber_length=self.l_M_opt,
maximal_fiber_velocity=self.v_M_max,
optimal_pennation_angle=self.alpha_opt,
fiber_damping_coefficient=self.beta,
)
expected = (
'MusculotendonDeGroote2016(\'name\', '
'pathway=LinearPathway(pO, pI), '
'activation_dynamics=FirstOrderActivationDeGroote2016(\'name\', '
'activation_time_constant=tau_a_name, '
'deactivation_time_constant=tau_d_name, '
'smoothing_rate=b_name), '
'musculotendon_dynamics=0, '
'tendon_slack_length=l_T_slack, '
'peak_isometric_force=F_M_max, '
'optimal_fiber_length=l_M_opt, '
'maximal_fiber_velocity=v_M_max, '
'optimal_pennation_angle=alpha_opt, '
'fiber_damping_coefficient=beta)'
)
assert repr(instance) == expected