From c11c721cd8e260ad2ba3fc2228eb5a321070241d Mon Sep 17 00:00:00 2001 From: Ipuch Date: Thu, 13 Jul 2023 11:31:48 -0400 Subject: [PATCH] update and scoot some examples --- ...act_forces_inequality_constraint_muscle.py | 30 ++++---- ...nequality_constraint_muscle_excitations.py | 40 +++++------ bioptim/optimization/solution.py | 9 +-- tests/test_all_examples.py | 68 +++++++++++++++++-- 4 files changed, 102 insertions(+), 45 deletions(-) diff --git a/bioptim/examples/muscle_driven_with_contact/contact_forces_inequality_constraint_muscle.py b/bioptim/examples/muscle_driven_with_contact/contact_forces_inequality_constraint_muscle.py index 0c81836d6..81272ec1a 100644 --- a/bioptim/examples/muscle_driven_with_contact/contact_forces_inequality_constraint_muscle.py +++ b/bioptim/examples/muscle_driven_with_contact/contact_forces_inequality_constraint_muscle.py @@ -32,7 +32,7 @@ def prepare_ocp(biorbd_model_path, phase_time, n_shooting, min_bound, max_bound) tau_min, tau_max, tau_init = -500.0, 500.0, 0.0 activation_min, activation_max, activation_init = 0.0, 1.0, 0.5 dof_mapping = BiMappingList() - dof_mapping.add("tau", [None, None, None, 0], [3]) + dof_mapping.add("tau", bimapping=None, to_second=[None, None, None, 0], to_first=[3]) # Add objective functions objective_functions = ObjectiveList() @@ -66,22 +66,24 @@ def prepare_ocp(biorbd_model_path, phase_time, n_shooting, min_bound, max_bound) # Initialize x_bounds x_bounds = BoundsList() - x_bounds.add(bounds=bio_model.bounds_from_ranges(["q", "qdot"])) - x_bounds[0][:, 0] = pose_at_first_node + [0] * n_qdot + x_bounds["q"] = bio_model.bounds_from_ranges("q") + x_bounds["q"][:, 0] = pose_at_first_node + x_bounds["qdot"] = bio_model.bounds_from_ranges("qdot") + x_bounds["qdot"][:, 0] = 0 # Initial guess x_init = InitialGuessList() - x_init.add(pose_at_first_node + [0] * n_qdot) + x_init["q"] = pose_at_first_node + x_init["qdot"] = np.zeros((n_qdot,)) # Define control path constraint u_bounds = BoundsList() - u_bounds.add( - [tau_min] * len(dof_mapping["tau"].to_first) + [activation_min] * bio_model.nb_muscles, - [tau_max] * len(dof_mapping["tau"].to_first) + [activation_max] * bio_model.nb_muscles, - ) + u_bounds["tau"] = [tau_min] * len(dof_mapping["tau"].to_first), [tau_max] * len(dof_mapping["tau"].to_first) + u_bounds["muscles"] = [activation_min] * bio_model.nb_muscles, [activation_max] * bio_model.nb_muscles u_init = InitialGuessList() - u_init.add([tau_init] * len(dof_mapping["tau"].to_first) + [activation_init] * bio_model.nb_muscles) + u_init["tau"] = [tau_init] * len(dof_mapping["tau"].to_first) + u_init["muscles"] = [activation_init] * bio_model.nb_muscles # ------------- # return OptimalControlProgram( @@ -89,11 +91,11 @@ def prepare_ocp(biorbd_model_path, phase_time, n_shooting, min_bound, max_bound) dynamics, n_shooting, phase_time, - x_init, - u_init, - x_bounds, - u_bounds, - objective_functions, + x_bounds=x_bounds, + u_bounds=u_bounds, + x_init=x_init, + u_init=u_init, + objective_functions=objective_functions, constraints=constraints, variable_mappings=dof_mapping, assume_phase_dynamics=True, diff --git a/bioptim/examples/muscle_driven_with_contact/contact_forces_inequality_constraint_muscle_excitations.py b/bioptim/examples/muscle_driven_with_contact/contact_forces_inequality_constraint_muscle_excitations.py index 93867d0a6..3c0a315da 100644 --- a/bioptim/examples/muscle_driven_with_contact/contact_forces_inequality_constraint_muscle_excitations.py +++ b/bioptim/examples/muscle_driven_with_contact/contact_forces_inequality_constraint_muscle_excitations.py @@ -22,7 +22,6 @@ SelectionMapping, Dependency, BoundsList, - Bounds, InitialGuessList, OdeSolver, Solver, @@ -38,12 +37,9 @@ def prepare_ocp(biorbd_model_path, phase_time, n_shooting, min_bound, ode_solver # adds a bimapping to bimappinglist # dof_mapping.add("tau", [None, None, None, 0], [3]) # easier way is to use SelectionMapping which is a subclass of biMapping - bimap = SelectionMapping( - nb_elements=bio_model.nb_dof, - independent_indices=(3,), - dependencies=(Dependency(dependent_index=None, reference_index=None, factor=None),), - ) - dof_mapping.add(name="tau", bimapping=bimap) + dof_mapping = BiMappingList() + dof_mapping.add("tau", bimapping=None, to_second=[None, None, None, 0], to_first=[3]) + # Add objective functions objective_functions = ObjectiveList() objective_functions.add(ObjectiveFcn.Mayer.MINIMIZE_PREDICTED_COM_HEIGHT, weight=-1) @@ -77,23 +73,27 @@ def prepare_ocp(biorbd_model_path, phase_time, n_shooting, min_bound, ode_solver # Initialize x_bounds x_bounds = BoundsList() - x_bounds.add(bounds=bio_model.bounds_from_ranges(["q", "qdot"])) - x_bounds[0].concatenate(Bounds([activation_min] * n_mus, [activation_max] * n_mus)) - x_bounds[0][:, 0] = pose_at_first_node + [0] * n_qdot + [0.5] * n_mus + x_bounds["q"] = bio_model.bounds_from_ranges("q") + x_bounds["q"][:, 0] = pose_at_first_node + x_bounds["qdot"] = bio_model.bounds_from_ranges("qdot") + x_bounds["qdot"][:, 0] = np.zeros((n_qdot,)) + x_bounds["muscles"] = [[activation_min] * n_mus, [activation_max] * n_mus] + x_bounds["muscles"][:, 0] = np.zeros((n_mus,)) # Initial guess x_init = InitialGuessList() - x_init.add(pose_at_first_node + [0] * n_qdot + [0.5] * n_mus) + x_init["q"] = pose_at_first_node + x_init["qdot"] = np.zeros((n_qdot,)) + x_init["muscles"] = np.zeros((n_mus,)) # Define control path constraint u_bounds = BoundsList() - u_bounds.add( - [torque_min] * len(dof_mapping["tau"].to_first) + [activation_min] * bio_model.nb_muscles, - [torque_max] * len(dof_mapping["tau"].to_first) + [activation_max] * bio_model.nb_muscles, - ) + u_bounds["tau"] = [torque_min] * len(dof_mapping["tau"].to_first), [torque_max] * len(dof_mapping["tau"].to_first) + u_bounds["muscles"] = [activation_min] * bio_model.nb_muscles, [activation_max] * bio_model.nb_muscles u_init = InitialGuessList() - u_init.add([torque_init] * len(dof_mapping["tau"].to_first) + [activation_init] * bio_model.nb_muscles) + u_init["tau"] = [torque_init] * len(dof_mapping["tau"].to_first) + u_init["muscles"] = [activation_init] * bio_model.nb_muscles # ------------- # return OptimalControlProgram( @@ -101,10 +101,10 @@ def prepare_ocp(biorbd_model_path, phase_time, n_shooting, min_bound, ode_solver dynamics, n_shooting, phase_time, - x_init, - u_init, - x_bounds, - u_bounds, + x_bounds=x_bounds, + u_bounds=u_bounds, + x_init=x_init, + u_init=u_init, objective_functions=objective_functions, constraints=constraints, variable_mappings=dof_mapping, diff --git a/bioptim/optimization/solution.py b/bioptim/optimization/solution.py index 330dd5d5a..2ca325afc 100644 --- a/bioptim/optimization/solution.py +++ b/bioptim/optimization/solution.py @@ -25,6 +25,7 @@ from ..optimization.optimization_vector import OptimizationVectorHelper from ..dynamics.ode_solver import OdeSolver from ..interfaces.solve_ivp_interface import solve_ivp_interface, solve_ivp_bioptim_interface +from ..interfaces.biorbd_model import BiorbdModel class Solution: @@ -1401,12 +1402,8 @@ def animate( tracked_markers = [None for _ in range(len(self.ocp.nlp))] # detect this is the same instance over each phase - - first_phase_model_type = type(self.nlp[0].model) - if not all([type(nlp.model) == first_phase_model_type for nlp in self.nlp]): - raise RuntimeError( - "The animation is only available for the same model type that imported your model." - ) + if not all([isinstance(nlp.model, BiorbdModel) for nlp in self.ocp.nlp]): + raise RuntimeError("The animation is only available for the same model type that imported your model.") # assuming that all the models or the same type. self.ocp.nlp[0].model.animate( diff --git a/tests/test_all_examples.py b/tests/test_all_examples.py index 51a8263d1..d55ce26a5 100644 --- a/tests/test_all_examples.py +++ b/tests/test_all_examples.py @@ -230,10 +230,10 @@ def test__getting_started__example_multinode_objective(): ) with pytest.raises( - ValueError, - match="Valid values for setting the cx is 0, 1 or 2. If you reach this error message, you probably tried to " - "add more penalties than available in a multinode constraint. You can try to split the constraints " - "into more penalties or use assume_phase_dynamics=False.", + ValueError, + match="Valid values for setting the cx is 0, 1 or 2. If you reach this error message, you probably tried to " + "add more penalties than available in a multinode constraint. You can try to split the constraints " + "into more penalties or use assume_phase_dynamics=False.", ): ocp_module.prepare_ocp( biorbd_model_path=bioptim_folder + "/models/pendulum.bioMod", @@ -255,7 +255,7 @@ def test__getting_started__example_save_and_load(assume_phase_dynamics): if not assume_phase_dynamics: with pytest.raises( - RuntimeError, match="n_threads is greater than 1 is not compatible with assume_phase_dynamics=False" + RuntimeError, match="n_threads is greater than 1 is not compatible with assume_phase_dynamics=False" ): ocp_module.prepare_ocp( biorbd_model_path=bioptim_folder + "/models/pendulum.bioMod", @@ -610,3 +610,61 @@ def test__inverse_optimal_control__double_pendulum_torque_driven_IOCP(assume_pha coefficients=[1, 1, 1], biorbd_model_path=bioptim_folder + "/models/double_pendulum.bioMod", ) + + +@pytest.mark.parametrize("assume_phase_dynamics", [False]) +def test__contact_and_muscle_forces_example(assume_phase_dynamics): + from bioptim.examples.muscle_driven_with_contact import contact_forces_inequality_constraint_muscle as ocp_module + + bioptim_folder = os.path.dirname(ocp_module.__file__) + + ocp_module.prepare_ocp( + biorbd_model_path=bioptim_folder + "/models/2segments_4dof_2contacts_1muscle.bioMod", + phase_time=0.3, + n_shooting=10, + min_bound=50, + max_bound=np.inf, + ) + + +@pytest.mark.parametrize("assume_phase_dynamics", [False]) +def test__contact_and_muscle_forces_example(assume_phase_dynamics): + from bioptim.examples.muscle_driven_with_contact import contact_forces_inequality_constraint_muscle as ocp_module + + bioptim_folder = os.path.dirname(ocp_module.__file__) + + ocp_module.prepare_ocp( + biorbd_model_path=bioptim_folder + "/models/2segments_4dof_2contacts_1muscle.bioMod", + phase_time=0.3, + n_shooting=10, + min_bound=50, + max_bound=np.inf, + ) + + +def test__contact_and_muscle_forces_example(): + from bioptim.examples.muscle_driven_with_contact import contact_forces_inequality_constraint_muscle as ocp_module + + bioptim_folder = os.path.dirname(ocp_module.__file__) + + ocp_module.prepare_ocp( + biorbd_model_path=bioptim_folder + "/models/2segments_4dof_2contacts_1muscle.bioMod", + phase_time=0.3, + n_shooting=10, + min_bound=50, + max_bound=np.inf, + ) + + +def test__contact_and_muscle_forces_example_excitation(): + from bioptim.examples.muscle_driven_with_contact import contact_forces_inequality_constraint_muscle_excitations as ocp_module + + bioptim_folder = os.path.dirname(ocp_module.__file__) + + ocp_module.prepare_ocp( + biorbd_model_path=bioptim_folder + "/models/2segments_4dof_2contacts_1muscle.bioMod", + phase_time=0.3, + n_shooting=10, + min_bound=50, + ) +