Skip to content

Commit

Permalink
biomod reader
Browse files Browse the repository at this point in the history
  • Loading branch information
EveCharbie committed Jan 29, 2025
1 parent c6062f0 commit 11b4f54
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 8 deletions.
128 changes: 127 additions & 1 deletion binding/python3/model_creation/biomechanical_model_real.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import os.path
import numpy as np

from biorbd import Model

class BiomechanicalModelReal:
def __init__(self):
def __init__(self, biomod_path: str = None):
from .segment_real import SegmentReal # Imported here to prevent from circular imports
from .muscle_group import MuscleGroup
from .muscle_real import MuscleReal
Expand All @@ -12,6 +17,127 @@ def __init__(self):
self.muscles: dict[str:MuscleReal, ...] = {}
self.via_points: dict[str:ViaPointReal, ...] = {}

if biomod_path is not None:
if os.path.exists(biomod_path):
print(f"Reading from file {os.path.abspath(biomod_path)}")
self.read(biomod_path)
else:
raise RuntimeError(f"The file {os.path.abspath(biomod_path)} does not exist, therefore it cannot be read.")


def read(self, biomod_path: str):
"""
This method allows to read a bioMod file to fasten the creation of a BiomechanicalModel.
Parameters
----------
biomod_path: str
The path to the bioMod file to read
"""
from .segment_real import SegmentReal # Imported here to prevent from circular imports
from .muscle_group import MuscleGroup
from .muscle_real import MuscleReal
from .via_point_real import ViaPointReal
from .inertia_parameters_real import InertiaParametersReal
from .translations import Translations
from .rotations import Rotations
from .range_of_motion import RangeOfMotion, Ranges
from .segment_coordinate_system_real import SegmentCoordinateSystemReal
from .marker_real import MarkerReal


def get_segment_name(segment):
return segment.name().to_string()

def get_segment_parent_name(segment):
return segment.parent().to_string()

def get_segment_translation(segment):
trans_name = segment.seqT().to_string()
if trans_name == '':
return Translations.NONE
else:
return Translations(trans_name)

def get_segment_rotation(segment):
rot_name = segment.seqR().to_string()
if rot_name == '':
return Rotations.NONE
else:
return Rotations(rot_name)

def get_segment_q_range(segment):
if len(segment.QRanges()) == 0:
return None
else:
segment_ranges = segment.QRanges()
q_min = []
q_max = []
for i_range, range in enumerate(segment_ranges):
q_min.append(range.min())
q_max.append(range.max())
return RangeOfMotion(range_type=Ranges.Q, min_bound=q_min, max_bound=q_max)

def get_segment_qdot_range(segment):
if len(segment.QdotRanges()) == 0:
return None
else:
segment_ranges = segment.QdotRanges()
qdot_min = []
qdot_max = []
for i_range, range in enumerate(segment_ranges):
qdot_min.append(range.min())
qdot_max.append(range.max())
return RangeOfMotion(range_type=Ranges.Qdot, min_bound=qdot_min, max_bound=qdot_max)

def get_segment_coordinate_system(segment):
return SegmentCoordinateSystemReal(scs=segment.localJCS().to_array())

def get_segment_inertia_parameters(segment):
mass = segment.characteristics().mass()
center_of_mass = segment.characteristics().CoM().to_array()
inertia = np.diag(segment.characteristics().inertia().to_array())
inertial_parameters = InertiaParametersReal(mass=mass,
center_of_mass=center_of_mass.reshape(-1, 1),
inertia=inertia)
return inertial_parameters

model_to_load = Model(biomod_path)

# Fill segments' information
for i_segment, segment in enumerate(model_to_load.segments()):
# TODO: add meshes and mesh_files, @pariterre: I cannot find how to extract meshes :(
name = get_segment_name(segment)
self.segments[name] = SegmentReal(
name=name,
parent_name=get_segment_parent_name(segment),
translations=get_segment_translation(segment),
rotations=get_segment_rotation(segment),
q_ranges=get_segment_q_range(segment),
qdot_ranges=get_segment_qdot_range(segment),
segment_coordinate_system=get_segment_coordinate_system(segment),
inertia_parameters=get_segment_inertia_parameters(segment),
)
# Fill markers' information
marker_names = [m.to_string() for m in model_to_load.markerNames()]
segment_names = list(self.segments.keys())
parent_ids = [str(m.parentId()) for m in model_to_load.markers()]
segment_ids = [str(s.id()) for s in model_to_load.segments()]
for i_marker, marker in enumerate(model_to_load.markers()):
parent_idx = segment_ids.index(parent_ids[i_marker])
parent_name = segment_names[parent_idx]
self.segments[parent_name].add_marker(MarkerReal(name=marker_names[i_marker],
parent_name=parent_name,
position=marker.to_array()))

# getBodyBiorbdId


# contactNames / contactSegmentBiorbdId

# getMuscleGroupId muscleNames


def __str__(self):
out_string = "version 4\n\n"

Expand Down
64 changes: 57 additions & 7 deletions examples/python3/modelCreation.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,54 @@ def complex_model_from_scratch(mesh_path="../test/models/meshFiles/stl/pendulum.

if remove_temporary:
os.remove(kinematic_model_file_path)


# TODO: @pariterre -> finally I would like to write this model to a biomod so that I can load it, is it OK ?


def read_and_modify_model():

# Create the model from an existing biomod
biomod_path = "../../test/models/arm26_degroote.bioMod"
initial_model = biorbd.Model(biomod_path)
bio_model = BiomechanicalModelReal(biomod_path=biomod_path)
bio_model.write("modified.bioMod")

# Modify an existing segment
bio_model.segments["r_humerus_rotation2"].translations = Translations.XYZ
bio_model.segments["r_humerus_rotation2"].q_ranges = RangeOfMotion(range_type=Ranges.Q, min_bound=[-1, -1, -1, -np.pi], max_bound=[1, 1, 1, np.pi]),

# Add a new complex segment
bio_model.segments["new_segment"] = Segment(
name="new_segment",
translations=Translations.XYZ,
rotations=Rotations.X,
q_ranges=RangeOfMotion(range_type=Ranges.Q, min_bound=[-1, -1, -1, -np.pi], max_bound=[1, 1, 1, np.pi]),
qdot_ranges=RangeOfMotion(range_type=Ranges.Qdot, min_bound=[-10, -10, -10, -np.pi*10], max_bound=[10, 10, 10, np.pi*10])
)
bio_model.segments["new_segment"].add_contact(Contact(name="new_contact",
function=lambda m: np.array([0, 0, 0]),
parent_name="new_segment",
axis=Translations.XYZ))
bio_model.muscle_groups["new_muscle_group"] = MuscleGroup(name="new_muscle_group",
origin_parent_name="base",
insertion_parent_name="new_muscle_group")
bio_model.muscles["new_muscle"] = Muscle("new_muscle",
muscle_type=MuscleType.HILLTHELEN,
state_type=MuscleStateType.DEGROOTE,
muscle_group="new_muscle_group",
origin_position_function=lambda m: np.array([0, 0, 0]),
insertion_position_function=lambda m: np.array([0, 0, 1]),
optimal_length_function=lambda model, m: 0.1,
maximal_force_function=lambda m: 100.0,
tendon_slack_length_function=lambda model, m: 0.05,
pennation_angle_function=lambda model, m: 0.05)
bio_model.via_points["new_via_point"] = ViaPoint("new_via_point",
position_function=lambda m: np.array([0, 0, 0.5]),
parent_name="new_segment",
muscle_name="new_muscle",
muscle_group="new_muscle_group",
)


def model_creation_from_measured_data(remove_temporary: bool = True):
"""
Expand Down Expand Up @@ -411,14 +458,17 @@ def write_markers_to_c3d(save_path: str, model: biorbd.Model):


def main():
# Create the model from user defined dimensions
model_creation_from_static_trial()
# # Create the model from user defined dimensions
# model_creation_from_static_trial()
#
# # Create a complex model from scratch
# complex_model_from_scratch()

# Cre a complex model from scratch
complex_model_from_scratch()
# Read and modify an existing biorbd model
read_and_modify_model()

# Create the model from a data file and markers as template
model_creation_from_measured_data()
# # Create the model from a data file and markers as template
# model_creation_from_measured_data()


if __name__ == "__main__":
Expand Down

0 comments on commit 11b4f54

Please sign in to comment.