Skip to content

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

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

Add TetGen-based tetrahedral mesh volumes and MRCP input support#1113
ynskHuh wants to merge 17 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

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

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.

3 participants