| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837 |
- """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
|