Skip to content

Commit

Permalink
update and scoot some examples
Browse files Browse the repository at this point in the history
  • Loading branch information
Ipuch committed Jul 13, 2023
1 parent b8f333a commit c11c721
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -66,34 +66,36 @@ 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(
bio_model,
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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
SelectionMapping,
Dependency,
BoundsList,
Bounds,
InitialGuessList,
OdeSolver,
Solver,
Expand All @@ -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)
Expand Down Expand Up @@ -77,34 +73,38 @@ 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(
bio_model,
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,
Expand Down
9 changes: 3 additions & 6 deletions bioptim/optimization/solution.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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(
Expand Down
68 changes: 63 additions & 5 deletions tests/test_all_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down Expand Up @@ -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,
)

0 comments on commit c11c721

Please sign in to comment.