Skip to content

Add TetGen-based tetrahedral mesh volumes and MRCP input support - #1113

Open
ynskHuh wants to merge 18 commits into
OpenGATE:masterfrom
ynskHuh:mrcp-tet-phantom-10.1.1
Open

ynskHuh wants to merge 18 commits into
OpenGATE:masterfrom
ynskHuh:mrcp-tet-phantom-10.1.1

Conversation

@ynskHuh

@ynskHuh ynskHuh commented Aug 7, 2026 •

Copy link
Copy Markdown

Proposed pull request

Title

Add TetGen-based tetrahedral mesh volumes and MRCP input support

GitHub PR body

Purpose

This PR adds support for constructing parameterised Geant4 tetrahedral meshes
from TetGen files, with MRCP-style material and color mappings. It allows a
tetrahedral computational phantom to be used directly without converting it
to an image-volume representation.

Main changes

  • Add TetrahedralMeshVolume and its bounding-box solid.
  • Add a C++ parameterised mesh builder that creates one G4Tet per TetGen
    element and assigns materials, colors, visibility, and copy numbers by
    region.
  • Add strict TetGen node and element validation, including support for complete
    zero-based and one-based node indices.
  • Interpret MRCP node coordinates as centimetres at the C++ input boundary and
    convert them to Geant4 units with a fixed conversion.
  • Parse MRCP material density and elemental mass fractions and construct the
    corresponding Geant4 materials.
  • Add optional region selection through keep_regions and fallback handling
    through default_material.
  • Add CopyNumberFilter so actor scoring can select parameterised
    tetrahedron copies.
  • Add synthetic non-anatomical TetGen datasets and a minimal visualization
    example under opengate/contrib/mrcp.
  • Add user-facing documentation in opengate/contrib/mrcp/README.md.

Implementation map

The following map identifies the files changed by this PR and the main
classes or functions reviewers may want to inspect.

C++ tetrahedral mesh implementation

  • core/opengate_core/opengate_lib/GateTetrahedralMeshParameterisation.h
    • Declares GateTetrahedralMeshParameterisation and the public TetGen mesh
      builder entry points.
  • core/opengate_core/opengate_lib/GateTetrahedralMeshParameterisation.cpp
    • read_node_file() validates the TetGen header, node count, duplicate IDs,
      and complete zero-based or one-based index ranges. The caller supplies the
      coordinate scale used during parsing.
    • read_ele_file() reads tetrahedral connectivity and region IDs.
    • GateTetrahedralMeshParameterisation::ComputeSolid() selects the G4Tet
      solid for each parameterised copy.
    • GateTetrahedralMeshParameterisation::ComputeMaterial() assigns the
      material associated with the tetrahedron's region.
    • GateTetrahedralMeshParameterisation::get_or_create_vis() creates and
      reuses region-specific visualization attributes.
    • build_tetrahedral_mesh_impl() constructs the shared parameterised
      physical volume.
    • build_tetrahedral_mesh_from_tetgen() retains configurable scaling for
      generic TetGen input.
    • build_mrcp_tetrahedral_mesh_from_tetgen() applies the fixed MRCP
      centimetre-to-Geant4 conversion.
    • build_tetrahedral_mesh_from_tetgen_material_names() provides a builder
      variant that resolves existing Geant4 materials by name.

C++ and pybind11 registration

  • core/opengate_core/opengate_lib/pyGateTetrahedralMesh.cpp
    • init_GateTetrahedralMesh() exposes the generic, MRCP-specific, and
      material-name mesh builders to Python.
    • rgba_to_colour_map() converts Python region/RGBA mappings to Geant4
      colors.
  • core/opengate_core/g4_bindings/pyG4Tet.cpp
    • init_G4Tet() exposes G4Tet construction and selected solid methods.
    • tet_is_degenerate() provides a geometric tetrahedron degeneracy check.
  • core/opengate_core/g4_bindings/pyG4Material.cpp
    • Exposes both G4Material::AddElement() overloads so Python can add
      elements by mass fraction or atom count.
  • core/opengate_core/opengate_core.cpp
    • Registers the new G4Tet, tetrahedral mesh, and copy-number filter
      bindings in the opengate_core module.

Python geometry interface

  • opengate/geometry/solids.py
    • Adds TetrahedralMeshEnvelopeSolid.
    • _read_node_bounds() skips and validates the TetGen header before reading
      coordinates and verifies the declared node count.
    • get_bbox_size_and_center_mm() converts the MRCP node bounds from
      centimetres to millimetres and calculates the enclosing box.
    • build_solid() creates the enclosing G4Box with a configurable margin.
  • opengate/geometry/volumes.py
    • Adds TetrahedralMeshVolume and its user properties.
    • _parse_mrcp_material_file() reads region IDs, densities, and elemental
      mass fractions from the MRCP material format.
    • _ensure_custom_material_from_zfrac() creates and caches the resulting
      G4Material objects.
    • _parse_colour_dat() reads region RGBA values and visibility.
    • _build_region_dicts() applies keep_regions and assembles the mappings
      passed to C++.
    • construct() builds the envelope and invokes the MRCP-specific C++ mesh
      builder.
  • opengate/managers.py
    • Imports and registers TetrahedralMeshVolume, making
      sim.add_volume("TetrahedralMesh", ...) available.

Copy-number filtering

  • core/opengate_core/opengate_lib/filters/GateCopyNumberFilter.h/.cpp
    • Adds GateCopyNumberFilter.
    • InitializeUserInfo() reads and deduplicates copy_numbers.
    • Evaluate() tests the pre-step touchable copy number at history depth
      zero.
  • core/opengate_core/opengate_lib/filters/pyGateCopyNumberFilter.cpp
    • init_GateCopyNumberFilter() exposes the C++ filter to Python.
  • opengate/actors/filters.py
    • Adds and registers the Python CopyNumberFilter interface.

Contribution and example data

  • opengate/contrib/__init__.py
    • Registers the mrcp contribution package.
  • opengate/contrib/mrcp/mrcp_simple.py
    • Provides a minimal geometry and Qt visualization example.
  • opengate/contrib/mrcp/simple.*
    • Provides the synthetic sphere, cube, and regular-tetrahedron input.
  • opengate/contrib/mrcp/letter.*
    • Provides the separate synthetic 3D GATE input.
  • opengate/contrib/mrcp/README.md
    • Documents input assumptions, volume configuration, example datasets, and
      copy-number filtering.

Why the unit conversion is fixed

MRCP .node coordinates are stored in centimetres, whereas OpenGATE/Geant4
geometry is represented in Geant4 length units. The conversion is performed
while C++ reads the node file. It is intentionally not exposed as a JSON or
Python scale parameter, preventing accidental modification of an input-format
property and keeping generic TetGen scaling behavior separate.

Example data

No anatomical MRCP phantom data are included. The example uses synthetic
geometry:

  • simple.*: separated sphere approximation, cube, and regular tetrahedron;

The example only initializes geometry and visualization, so the expected
warning about a missing particle source is harmless.

PR_1 PR_2

Comment thread TETRAHEDRAL_MESH_CHANGELOG.md Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File to remove

@dsarrut

dsarrut commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Hi @ynskHuh,

Thank you for this very nice contribution! Adding native tetrahedral mesh and MRCP phantom support is a great addition to OpenGATE.

The code quality, error handling, and documentation in contrib/mrcp are excellent.

Before merging, could you please address two minor points:

  1. Remove TETRAHEDRAL_MESH_CHANGELOG.md from the repository root (as noted by @tbaudier).
  2. Add a minimal non-interactive automated test in opengate/tests/src/geometry/ (e.g., testXXX_tetrahedral_mesh.py) running a short simulation (e.g. 50-100 events) through the synthetic simple.* mesh for example with a SimulationStatisticsActor, to ensure tetrahedral mesh simulations remain tested in our CI.
  3. Rebase your branch on the latest master:
git fetch upstream master
git checkout mrcp-tet-phantom-10.1.1
git rebase upstream/master
git rm TETRAHEDRAL_MESH_CHANGELOG.md
git commit -m "Remove changelog from repository root"
git push --force-with-lease origin mrcp-tet-phantom-10.1.1

Once these two items are updated and the branch is rebased on master, we will be glad to merge it!

David (review made with AI help)

@ynskHuh
ynskHuh force-pushed the mrcp-tet-phantom-10.1.1 branch from 94a50a5 to ecafb72 Compare October 7, 2026 08:24
@ynskHuh

ynskHuh commented Oct 7, 2026

Copy link
Copy Markdown
Author

Hi David,
Thank you for the review!

I have addressed the requested changes:

  1. Removed TETRAHEDRAL_MESH_CHANGELOG.md from the repository root.
  2. Added opengate/tests/src/geometry/test115_tetrahedral_mesh.py, a non-interactive smoke test using the synthetic simple.* mesh. It runs 100 gamma primaries with one thread and checks the event, track, and step counts using SimulationStatisticsActor.

Rebased the branch onto the latest master.
I rebuilt the C++ core locally and confirmed that the new test passes after the rebase.

Thank you again!

Yoonsuk

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants