{"id":34552834,"url":"https://github.com/pyomeca/biobuddy","last_synced_at":"2025-12-24T08:04:48.519Z","repository":{"id":280060938,"uuid":"940831172","full_name":"pyomeca/biobuddy","owner":"pyomeca","description":"A generic interface to generate a virtual buddy","archived":false,"fork":false,"pushed_at":"2025-12-04T21:55:26.000Z","size":12267,"stargazers_count":9,"open_issues_count":14,"forks_count":12,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-12-07T16:19:53.898Z","etag":null,"topics":["biomechanics","biomod","model-personalization","modeling","muscle","musculoskeletal","osim"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pyomeca.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"docs/contributing.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-02-28T21:54:00.000Z","updated_at":"2025-12-05T11:00:35.000Z","dependencies_parsed_at":"2025-03-01T01:26:39.114Z","dependency_job_id":"61f31994-fa35-49dd-9cbf-ed0212790c58","html_url":"https://github.com/pyomeca/biobuddy","commit_stats":null,"previous_names":["pyomeca/biobuddy"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/pyomeca/biobuddy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyomeca%2Fbiobuddy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyomeca%2Fbiobuddy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyomeca%2Fbiobuddy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyomeca%2Fbiobuddy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pyomeca","download_url":"https://codeload.github.com/pyomeca/biobuddy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyomeca%2Fbiobuddy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27998473,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-24T02:00:07.193Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["biomechanics","biomod","model-personalization","modeling","muscle","musculoskeletal","osim"],"created_at":"2025-12-24T08:04:07.123Z","updated_at":"2025-12-24T08:04:48.511Z","avatar_url":"https://github.com/pyomeca.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\n![biobuddy](https://github.com/user-attachments/assets/c8689155-0b26-4e13-835c-cdb6696e1acb)\n\n`BioBuddy` is an open-source tool for [translating](#model-translation), [creating](#model-creation) and [personalizing](#model-personalization) musculoskeletal models across different formats (e.g., .osim, .bioMod). By enabling reliable interoperability between modeling environments, BioBuddy allows researchers to focus on scientific questions rather than technical constraints.\n\n\u003c!---\n[![Actions Status](https://github.com/pyomeca/biobuddy/workflows/CI/badge.svg)](https://github.com/pyomeca/biobuddy/actions)\n[![PyPI](https://anaconda.org/conda-forge/biobuddy/badges/latest_release_date.svg)](https://pypi.org/project/biobuddy/)\n---\u003e\n\n[![codecov](https://codecov.io/gh/pyomeca/biobuddy/branch/main/graph/badge.svg)](https://codecov.io/gh/pyomeca/biobuddy)\n[![Discord](https://img.shields.io/discord/1340640457327247460.svg?label=chat\u0026logo=discord\u0026color=7289DA)](https://discord.gg/Ux7BkdjQFW)\n\n- [How to install](#how-to-install)\n    - [Set-up environment (user)](#set-up-environment-user)\n    - [Set-up environment (developer)](#set-up-environment-developer)\n    - [Installing from source](#installing-from-source)\n    - [Installing from conda-forge](#installing-from-conda-forge)\n    - [Installing from pip](#installing-from-pip)\n- [Features](#features)\n  - [Model translation](#model-translation)\n  - [Model creation](#model-creation)\n  - [Model personalization/modification](#model-personalizationmodification)\n      - [Scaling](#scaling)\n      - [Joint center identification](#joint-center-identification)\n      - [Merging segments](#merging-segments)\n      - [Modifying the kinematic chain](#modifying-the-kinematic-chain)\n      - [Flattening the model](#flattening-the-model)\n- [Note](#note)\n- [How to cite](#how-to-cite)\n- [How to contribute](#how-to-contribute)\n\n\n# How to install \n`BioBuddy` can be installed from source, from conda-forge, or pip.\n\n### Set-up environment (user)\nIf you are a user, you can set up your environment with minimal dependencies.\n```bash\nconda install -c conda-forge python=3.11.11 pip\npip install scipy==1.15.1 numpy==1.25.2 lxml ezc3d plotly\n```\nNote: On mac, you might need to add `conda install conda-forge::libcxx`\n\nAnd if you want to access all features, you will also need to install the following optional dependencies:\n```bash\nconda install -c conda-forge pyorerun rerun-sdk=0.21.0\n```\n\n### Set-up environment (developer)\nHowever, if you are a developer and want to contribute, you will need to set up your environment using the following command before installing BioBuddy:\nDue to the OpenSim dependency used only in BioBuddy's tests, we recommend using python=3.11.11\n```bash\npip install pytest pytest-cov codecov\nconda install -c opensim-org opensim=4.5.1\nconda install -c conda-forge biorbd=1.11.2=py311h9439bbc_1 deepdiff\n```\n\n### Installing from source\nOnce you have set up your environment, you can install BioBuddy by running:\n```bash\npip install .\n```\nfrom the root directory of the BioBuddy source code (the folder containing the file setup.py).\n\n### Installing from conda-forge\nYou can also install BioBuddy from conda-forge by running:\n```bash\nconda install -c conda-forge biobuddy\n``` \n\n### Installing from pip\nYou can also install BioBuddy from pip by running:\n```bash\npip install biobuddy\n```\n\n\n# Features\n## Model translation\nYou can load the original model using one of the `BiomechanicalModelReal().from_[format]` methods, and then export it \ninto another format using the `BiomechanicalModelReal.to_[format]` method (see [example](examples/read_and_write_models.py)).\n```python3\nfrom biobuddy import BiomechanicalModelReal\n\n# Read an .osim file\nmodel = BiomechanicalModelReal().from_osim(\n    filepath=osim_filepath,\n    # Other optional parameters here\n)\n\n# Translate it into a .bioMod file\nmodel.to_biomod(biomod_filepath)\n```\nSee the example [read_and_write_models.py](examples/read_and_write_models.py) for more details.\n\n## Model creation\nA model can also be created from scratch using the `BiomechanicalModel`. In this generic model, everything can be defined \nthrough functions (i.e., without numerical values). The subject specific model (a `BiomechanicalModelReal`) can then be \ngenerated by evaluating the generic model with a motion capture trial. This feature is especially useful for kinematic \nmodels where the joint centers are defined based on anatomical marker placement (like in the plug in gait, see full \n[example](examples/create_model_from_c3d.py)). \n\nHere is a simple example of how to add components to such a model:\n```python3\n\n# Create the model\nmodel = BiomechanicalModel()\nde_leva = DeLevaTable(total_mass=60, sex=Sex.FEMALE)\n\n# Add components to build the kinematic chain\nmodel.add_segment(\n    Segment(\n        name=\"HEAD\",\n        parent_name=\"TRUNK\",\n        segment_coordinate_system=SegmentCoordinateSystem(\n            \"BOTTOM_HEAD\",\n            first_axis=Axis(name=Axis.Name.Z, start=\"BOTTOM_HEAD\", end=\"HEAD_Z\"),\n            second_axis=Axis(name=Axis.Name.X, start=\"BOTTOM_HEAD\", end=\"HEAD_XZ\"),\n            axis_to_keep=Axis.Name.Z,\n        ),\n        mesh=Mesh((\"BOTTOM_HEAD\", \"TOP_HEAD\", \"HEAD_Z\", \"HEAD_XZ\", \"BOTTOM_HEAD\")),\n        inertia_parameters=de_leva[SegmentName.HEAD],\n    )\n)\nmodel.segments[\"HEAD\"].add_marker(Marker(\"BOTTOM_HEAD\"))\nmodel.segments[\"HEAD\"].add_marker(Marker(\"TOP_HEAD\"))\nmodel.segments[\"HEAD\"].add_marker(Marker(\"HEAD_Z\"))\nmodel.segments[\"HEAD\"].add_marker(Marker(\"HEAD_XZ\"))\n\n# Evaluate the model with a motion capture trial\nmodel_real = model.to_real(C3dData(c3d_filepath))\n```\nSee the example [create_model_from_c3d.py](examples/create_model_from_c3d.py) for more details.\n\n### Model components\nThere are many different components available to build a model (see this [example](examples/create_model.py) to see how to add those components to your model).\n\n![Build_segment](docs/images/Build_segment.png)\n\n### Inertial parameters \nAs you might have noticed, the inertial parameters of the segments can be defined by hand or using anthropometric tables.\nFor now, only the table from DeLeva (1996) is implemented through the `DeLevaTable` class, but more tables will be added in the future.\nA `DeLevaTable` can be initialized only using total height (normative segment proportions will be used) like this: \n```python3\nde_leva.from_height(total_height=1.70)\n```\nor using more detailed measurements like this:\n```python3\n# From manual measurements or from marker positions\nde_leva.from_measurements(\n    total_height=1.70,\n    ankle_height=0.07,\n    knee_height=0.45,\n    hip_height=0.98,\n    shoulder_height=1.42,\n    finger_span=1.72,\n    wrist_span=1.53,\n    elbow_span=0.85,\n    shoulder_span=0.34,\n    foot_length=0.34,\n    hip_width=0.35,\n)\n```\nor directly from a static trial (`.c3d` file) using markers placed on anatomical landmarks like this:\n```python3\nde_leva.from_static(static=C3dData(c3d_filepath))\n```\n\nOnce you have set your table, you can extract the inertial parameters from one segment like this:\n```python3\nhead_inertia_parameters = de_leva[SegmentName.HEAD]\n```\n\nor you can define a whole body model from a `DeLevaTable` like this:\n```python3\nmodel = de_leva.to_simple_model()\n```\n![DeLeva](docs/images/DeLeva.png)\n![DeLeva_measures](docs/images/DeLeva_measures.png)\n\n\n## Model personalization/modification\nThe current version of BioBuddy allows you to modify your `BiomechanicalModelReal` to personalize it to your subjects by:\n\n\n### Scaling:\nThe scaling is performed by the `ScaleTool` which can be initialized from scratch like this:\n```python3\noriginal_model = BiomechanicalModelReal()\n\n# Create the scaling configuration\nscaling_configuration = ScaleTool(original_model)\n\n# Add a scaling segment for the pelvis\nscaling_configuration.add_scaling_segment(\n    SegmentScaling(\n        name=\"pelvis\",\n        scaling_type= SegmentWiseScaling(\n            axis=Translations.XYZ,\n            marker_pairs=[\n                [\"RASIS\", \"LASIS\"],\n                [\"RPSIS\", \"LPSIS\"],\n            ]\n        )\n    )\n)\n\n# Add marker weights for the pelvis segment\nscaling_configuration.add_marker_weight(MarkerWeight(name=\"RASIS\", weight=1.0))\nscaling_configuration.add_marker_weight(MarkerWeight(name=\"LASIS\", weight=1.0))\nscaling_configuration.add_marker_weight(MarkerWeight(name=\"RPSIS\", weight=0.5))\nscaling_configuration.add_marker_weight(MarkerWeight(name=\"LPSIS\", weight=0.5))\n```\nor by reading from an existing file (e.g., `.xml` or `.biomod`) using the appropriate `ScaleTool.from_[format]` method.\nOnce the scaling configuration is set up, you can scale your model based on a static trial (`.c3d` file) and the total \nmass of your participant using the `ScaleTool.scale` like this:\n```python3\n# Performing the scaling based on a static trial\nscale_tool = ScaleTool.from_biomod(biomod_filepath)\nscaled_model = scale_tool.scale(static_c3d=C3dData(filepath), mass=mass)\n```\nSee the example [scaling_model.py](examples/scaling_model.py) for more details.\n\nFor now, there are three scaling methods available:\n- `BodyWiseScaling`: scales the entire body based on the total height of the participant.\n- `SegmentWiseScaling`: scales the segment based on the distance between marker pairs.\n- `AxisWiseScaling`: scales each axis of the segment independently based on the distance between marker pairs.\n![scaling_types](docs/images/Scaling_with_names.png)\n\n### Joint center identification:\nThe `JointCenterTool` allows you to identify the joint centers of your model based on the movement of segments during \nfunctional trials.\nFirst, you need to define the joint center configuration using `JointCenterTool.add()` method to define the joint \nyou want to modify.\nThen, you can use the `JointCenterTool.replace_joint_centers()` method to modify each joint.\n```python3\nfrom biobuddy import JointCenterTool\n\n# Set up the joint center identification tool\njoint_center_tool = JointCenterTool(scaled_model)\n# Example for the right hip\njoint_center_tool.add(\n    Score(\n        functional_c3d=C3dData(c3d_filepath, first_frame=100, last_frame=900),\n        parent_name=\"pelvis\",\n        child_name=\"femur_r\",\n        parent_marker_names=[\"RASIS\", \"LASIS\", \"LPSIS\", \"RPSIS\"],\n        child_marker_names=[\"RGT\", \"RUB_Leg\", \"RUF_Leg\", \"FBF_Leg\", \"RMFE\", \"RLFE\"],\n    )\n)\n# Example for the right knee\njoint_center_tool.add(\n    Sara(\n        functional_c3d=C3dData(c3d_filepath),\n        parent_name=\"femur_r\",\n        child_name=\"tibia_r\",\n        parent_marker_names=[\"RGT\", \"RUB_Leg\", \"RUF_Leg\", \"FBF_Leg\"],\n        child_marker_names=[\"RATT\", \"RUB_Tib\", \"RDF_Tib\", \"RDB_Tib\", \"RSPH\", \"RLM\"],\n    )\n)\n\n# Perform the joint center identification\nmodified_model = joint_center_tool.replace_joint_centers()\n```\nSee the example [replace_joint_centers_functionally.py](examples/replace_joint_centers_functionally.py) for more details.\n\nFor now, two algorithms were implemented `SCoRE` to locate the position of the joint center and `SARA` \nto identify the joint axis of rotation. Please note that in both cases, all segment components stay the same, only the \njoint position and axis are modified.\n\n![SCoRE_SARA](docs/images/SCoRE_SARA.png)\n\n\n### Merging segments:\nThe `MergeSegmentTool` allows you to merge two segments into one (including inertial parameters and all the components on the segment).\nYou can define which segments you want to merge using `SegmentMerge`, which requires the names of the segments to merge and the name of the new segment.\n```python3\nmerge_tool = MergeSegmentsTool(original_model)\n# By default, segments merge together setting the new segment coordinate as the mean of the old coordinates\nmerge_tool.add(\n   SegmentMerge(\n      name=\"LOWER_ARMS\", \n      first_segment_name=\"L_LOWER_ARM\", \n      second_segment_name=\"R_LOWER_ARM\",\n   )\n)\n# But you can also merge one segment on top of another one by specifying the segment coordinate system to keep\nmerge_tool.add(\n   SegmentMerge(\n      name=\"R_LOWER_ARM_AND_HAND\", \n      first_segment_name=\"R_LOWER_ARM\", \n      second_segment_name=\"R_HAND\", \n      merged_origin_name=\"R_LOWER_ARM\",\n   )\n)\nmodified_model = merge_tool.merge()\n```\nSee the example [create_a_population_of_models.py](examples/applied_examples/create_a_population_of_models.py) for more details.\n\n![merge_segments](docs/images/merge_segments.png)\n\n\n### Modifying the kinematic chain:\nThe `ModifyKinematicChainTool` allows you to modify the kinematic chain of your model.\nFor now, the only modification available is to change which segment is the first segment of the kinematic chain (`ChangeFirstSegment`).\nIt inverts all segments between the original first segment and the new first segment.\n```python3\nkinematic_chain_modifier = ModifyKinematicChainTool(original_model)\nkinematic_chain_modifier.add(ChangeFirstSegment(first_segment_name=\"FOOT\"))\nmodified_model = kinematic_chain_modifier.modify()\n```\nSee the example [create_a_population_of_models.py](examples/applied_examples/create_a_population_of_models.py) for more details.\n\n![kinematic_chain_modifier](docs/images/kinematic_chain_modifier.png)\n\n\n### Flattening the model:\nThe `FlatteningTool` allows you to transform a 3D into a 2D model.\nIt projects all segment components (com, muscle via points, ...) on the plane orthogonal to the `axis` specified.\nPlease note that for now the following components are not modified automatically (i.e., same as the original model):\n- Inertia (which should not have an impact of the model is used in a 2D simulation)\n- Degrees of freedom (these should be modified by the user after flattening the model)\n```python3\nsymmetry_tool = FlatteningTool(model, axis=Translations.Z)\nmodel = symmetry_tool.flatten()\n```\nSee the example [simplify_an_arm_model.py](examples/applied_examples/simplify_an_arm_model.py) for more details.\n\n\n# Note\nUnderstandably, not all modeling formats have the same functionalities, so some features may not be available for all \nformats. We will try to keep here a list up to date of the features that are available in BioBuddy that are not \navailable for each format: \n - biorbd (.bioMod):\n   - `PathPointCondition` is not implemented yet in biorbd. So if your BioBuddy model has this component, we recommend running `BiomechanicalModelReal.fix_via_points(q)` before `BiomechanicalModelReal.to_biomod(path)`. This will evaluate the via point conditions at the desired posture (which should be close to the range of motion during the movement studied). If the condition is not meet, the via point is inactive, so it is removed from the model. Please note that this is a destructive operation, once the conditions are evaluated, they are removed from the model and the remaining via points are fixed on the segments. \n   - `PathPointMovement` are not implemented yet in biorbd. So if your BioBuddy model has this components, we recommend running `BiomechanicalModelReal.fix_via_points(q)` before `BiomechanicalModelReal.to_biomod(path)`. This will fix the position of the moving via points, muscle origin, and muscle insertion by evaluating the position function at the desired posture (which should be close to the range of motion during the movement studied). Please note that this is a destructive operation, once the movements are evaluated, they are removed from the model and the remaining via points are fixed on the segments.  \n\n# How to cite\n```\n@software{biobuddy_2025,\n  author       = {Eve Charbonneau, Pierre Puchaud, Teddy Caderby, Mickael Begon, Amedeo Ceglia, Benjamin Michaud},\n  title        = {Bringing the musculoskeletal modeling community together with BioBuddy},\n  month        = april,\n  year         = 2025,\n  publisher    = {Congrès de la Société de biomécanique},\n  url          = {https://github.com/pyomeca/biobuddy}\n}\n```\n\n# How to contribute\nOur goal is to support as many musculoskeletal model formats as possible, so do not hesitate to contact us if you'd like to see your favorite format supported by BioBuddy. \nIf you are using BioBuddy and encounter any problem, please open an issue on this GitHub repository. \nWe are also open to suggestions for new features or improvements to existing functionality.\nAll contributions are welcome!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpyomeca%2Fbiobuddy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpyomeca%2Fbiobuddy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpyomeca%2Fbiobuddy/lists"}