Skip to main content

opengate-gate-tree

CI Version Standard Python Standard Python Standard Python Documentation Status license Ruff Checked with mypy uv

opengate-gate-tree is a utility for processing GATE 9 output ROOT file with trees (Hits, Singles,Coincidences)

Supported GATE Versions

The package targets the C++ line of GATE, version 9.4.2 and newer. GATE 10, the Python implementation, is not supported.

Output files are not meant to be read back by GATE. They are conversions of the simulation output into whichever format suits the analysis that follows:

Format Typical consumer
root further analysis in C++ with the ROOT framework
hdf5 analysis in Python or MATLAB, large datasets, columnar access
csv quick inspection, spreadsheets, plain pandas.read_csv

Documentation

Full documentation, tutorials, and API reference are available on Read the Docs.

Quick Start

Install From PyPI

pip3 install opengate-gate-tree

Install From Source

make init
make install

Command-Line Options

The CLI accepts the following options:

Option Type Required Allowed values Description
--input-gate-root-file path yes file with .root extension Path to the GATE ROOT input file.
--output-dir path yes existing directory or new path Directory where output file will be saved. If it does not exist, it is created automatically.
--output-file-title string yes file name without directories Title of the output file. The file is named <title>.<tree>.<format>, for example patient_01.hits.csv.
--gate-tree enum-like string yes Hits, Singles, Coincidences Name of the tree to process from the input ROOT file.
--output-file-format enum-like string yes root, hdf5, csv Output file format.
--branches-to-extract list of strings no branch names valid for selected tree Space-separated list of branches to extract.
--input-tree-name string no name of a tree in the input file Tree to read, when it is not named after the selected tree or when the file holds several trees of hits.
--merge-hits-trees flag no Read every tree of hits in the input file as a single dataset. Only for --gate-tree Hits, and not together with --input-tree-name.
--statistics flag no Write a report describing the extracted data next to the output file, as <title>.<tree>.stats.json.
--skip-hits-validation flag no Extract the branches without recognising and checking the structure of the "Hits" tree.

Validation behavior:

  • the input file must exist, end with .root and be readable as a ROOT file
  • the output directory is created if it does not exist
  • an existing output file is overwritten without a prompt
  • all required options above must be provided
  • the selected tree must be present in the input file; if it is not, the error lists the trees the file actually holds
  • branch names are validated against the branches present in the input file
  • branches whose length varies per entry are reported as unsupported
  • the structure of the "Hits" tree is recognised and checked before anything is read; a file from a GATE build the package does not know is still extracted with --skip-hits-validation
  • hits stored under another name are found by their structure, so the GateToTree output, whose tree is called tree, needs no extra option
  • a file holding hits in several trees, one per run or one per sensitive detector, reports them and is read either one tree at a time (--input-tree-name) or as one dataset (--merge-hits-trees)

The structures the "Hits" tree can have, how the package tells them apart and what it checks are described in the guide, which also lists the branches of every supported structure.

The output file is named after the title, the tree it holds and the format it is written in: a run extracting the hits into csv under the title patient_01 writes patient_01.hits.csv. The tree is part of the name because one input file holds several trees, and extracting two of them should not land on the same file.

The output file holds the extracted tree only. Histograms stored next to the trees in a GATE file are not copied over.

Fixed-width array branches, such as volumeID, keep their shape in the root and hdf5 output. CSV has no cell for an array, so they are written there as one column per component, named volumeID_0 to volumeID_9.

Two branch names cannot be carried by every format, and are refused rather than written as something else. A name holding a bracket, such as the volumeID[0] of the GateToTree output, cannot go into a root file: uproot reads the bracket as an array dimension and writes a file that cannot be read back. A name holding a slash cannot go into an hdf5 file, where it would create a nested group instead of a dataset. Both layouts reach the other formats unchanged.

Examples:

opengate-gate-tree \
	--input-gate-root-file ./data/simulation.root \
	--output-dir ./out \
	--output-file-title patient_01 \
	--gate-tree Hits \
	--output-file-format csv
opengate-gate-tree \
	--input-gate-root-file ./data/simulation.root \
	--output-dir ./out \
	--output-file-title patient_01 \
	--gate-tree Singles \
	--output-file-format hdf5 \
	--branches-to-extract eventID trackID edep posX

Library Usage

Besides the command-line interface, the package can be used directly from Python code. Everything the command line does is reachable from opengate_gate_tree.

Loading And Exporting Files

from pathlib import Path

from opengate_gate_tree import (
    GateTree,
    OutputFileFormat,
    read_tree,
    write_tree,
)

# Load selected branches of the "Hits" tree from a GATE ROOT file.
data = read_tree(
    Path("simulation.root"),
    GateTree.HITS,
    ["eventID", "edep", "posX", "posY", "posZ"],
)

print(data.entry_count, data.branch_names)

# Work with the data as NumPy arrays or as a pandas.DataFrame.
energies = data["edep"]
frame = data.to_dataframe()

# Export to the format that fits the downstream analysis.
write_tree(data, Path("out/hits.hdf5"), OutputFileFormat.HDF5)

Omit the branch list to read every branch of the tree:

data = read_tree(Path("simulation.root"), GateTree.HITS)

When several trees come from the same file, open it once with RootFile:

from opengate_gate_tree import RootFile

with RootFile(Path("simulation.root")) as root_file:
    print(root_file.tree_names)
    hits = root_file.read(GateTree.HITS, ["eventID", "edep"])

Reading A Split File And Summarising It

GATE can write the hits of one simulation into several trees, one per run or one per sensitive detector. They are read as a single dataset, with a column recording which tree every row came from:

from opengate_gate_tree import (
    SOURCE_TREE_BRANCH,
    compute_statistics,
    format_statistics,
    read_hits_trees,
    write_statistics,
)

data = read_hits_trees(Path("simulation.root"))
print(set(data[SOURCE_TREE_BRANCH]))

Identifiers stay as GATE wrote them, so an event is told apart by its run and its event identifier together: eventID repeats between runs, and repeats for one decay recorded in two detectors.

A summary of what was extracted can be printed, saved, or both:

statistics = compute_statistics(data)
print(format_statistics(statistics))
write_statistics(statistics, Path("out/hits.stats.json"))

The structure of a tree can also be asked about on its own:

from opengate_gate_tree import RootFile, describe_hits_tree

with RootFile(Path("simulation.root")) as root_file:
    detection = root_file.detect_hits_tree()
    print(describe_hits_tree(detection))

Picking Out Rows

The pandas view is where an analysis picks rows out of a tree. Importing the package registers a gate namespace on pandas.Series and on pandas.DataFrame, and every filter is a function too:

frame = data.to_dataframe()

in_the_ring = frame.gate.in_cylinder((0, 0), radius=500.0, inner_radius=409.0)
energies = in_the_ring.gate.by_run(0)["edep"].gate.in_range(0.2, 0.511)

Each filter comes in two: is_* and has_* answer with a boolean column, which combines with & and |, while the other name of the pair answers with the rows themselves, which chains. Shapes are described by where they sit and how big they are, by_run and by_event name rows by the identifiers GATE wrote, and the selectors take the meaning of a code rather than its number. What pandas already says — comparing, isin, combining masks — is left to pandas. See the guide.

Reading What A Gamma Was

The branches a PositroniumSource writes hold integers saying what each gamma was and where it came from. The package names those values, and the names are the integers themselves, so a column compares against them as it was read:

from opengate_gate_tree import GammaType, SourceType, has_positronium_metadata

prompt = data["gammaType"] == GammaType.PROMPT
from_positronium = has_positronium_metadata(data["decayIndex"])

A plain enum.Enum written for the same purpose would not work here and would not say so: its members are not integers, so the comparison yields a mask of False rather than an error. See the guide for the meaning of every value.

Failures while reading or writing files are reported through a subclass of GateTreeError, so one except clause covers them. Malformed arguments, such as an empty branch name, raise ValueError instead:

from opengate_gate_tree import GateTreeError, TreeNotFoundError

try:
    data = read_tree(Path("simulation.root"), GateTree.SINGLES)
except TreeNotFoundError as error:
    print(f"tree missing: {error}")
except GateTreeError as error:
    print(f"could not process the file: {error}")

The package does not configure logging on import. Applications that want the defaults used by the command line can ask for them:

from opengate_gate_tree.logging_setup import configure_logging

configure_logging()

The package ships a py.typed marker, so type checkers see its annotations.

Available Package Capabilities (Cumulative)

This section is append-only. Add a capability entry only when its roadmap stage status changes from planned to completed.

Current development stage: version-0.5.0

Available capabilities:

  • 0.1.0: project structure initialized and minimal buildable package code added.
  • 0.2.0: GATE ROOT files can be loaded and validated, trees and branches extracted into a NumPy-backed representation with a pandas view, and written to ROOT, HDF5 or CSV. Usable both as a command-line tool and as a library, with user documentation on ReadTheDocs.
  • 0.3.0: the structure of the "Hits" tree is recognised and validated against the schema of the variant it holds, hits stored under another name are found by their structure, a file split into one tree per run or per sensitive detector is read as one dataset, statistics are computed and saved beside the data, and output files are named after the tree they hold.
  • 0.4.0: the branches a PositroniumSource writes are described by enum classes whose members are the integers GATE wrote, so a column compares against them as it was read; their values can be read as names, rows carrying the decay metadata of such a source are told from the rest, and a statistics report names those values instead of printing numbers.
  • 0.5.0: rows of a "Hits" tree are picked out by what the data means - a closed range, a box, a sphere or a ring in the geometry of the detector, the run and event a hit belongs to, the decay metadata it carries, and the meaning of the codes a PositroniumSource wrote - as functions and as a gate namespace on a pandas column and frame, each filter answering either with a mask that combines with others or with the rows themselves.

Development

Common development commands:

make lint
make format
make typecheck
make test
make check

Pre-commit setup

You can install and activate pre-commit in two supported ways.

Option A (recommended): use uv in this repository

uv add --dev pre-commit
uv sync
uv run pre-commit install --hook-type pre-commit

Optional one-time verification on all files:

uv run pre-commit run --all-files

Option B: install pre-commit from Debian packages

sudo apt update
sudo apt install -y pre-commit
pre-commit --version
pre-commit install --hook-type pre-commit

Optional one-time verification on all files:

pre-commit run --all-files

The configured hook runs make check before each commit and blocks the commit if validation fails.

Documentation

The user documentation is built with Sphinx:

make docs        # build docs/_build/html
make docs-check  # build with warnings treated as errors, as ReadTheDocs does

Project conventions and contribution standards:

License

MIT License

Contact: GitHub

Author

The project was designed and implemented by Mateusz Jakub Bała.

Contact: GitHub

Contribution

To contribute new functionality:

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

opengate_gate_tree-0.5.0.tar.gz (1.2 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

opengate_gate_tree-0.5.0-py3-none-any.whl (74.2 kB view details)

Uploaded Python 3

File details

Details for the file opengate_gate_tree-0.5.0.tar.gz.

File metadata

  • Download URL: opengate_gate_tree-0.5.0.tar.gz
  • Upload date:
  • Size: 1.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for opengate_gate_tree-0.5.0.tar.gz
Algorithm Hash digest
SHA256 49f42610530d9e0c4a064011a7a296019f0c6b18a79c255754d4cd4d78f136ae
MD5 5806d2b89a9ee80758d6180bb5217daf
BLAKE2b-256 74e7bfaacb711b72e185af190650a2a1e5b528982a4be6acd5f8517a23f8b0de

See more details on using hashes here.

Provenance

The following attestation bundles were made for opengate_gate_tree-0.5.0.tar.gz:

Publisher: publish.yml on MateuszBala/opengate-gate-tree

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file opengate_gate_tree-0.5.0-py3-none-any.whl.

File metadata

File hashes

Hashes for opengate_gate_tree-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ca44ddcf469d11d366125704711752584512e239b447545f6b596203378db7b4
MD5 55e23e884e3ee812c932ec2b1c016e6e
BLAKE2b-256 903daa90b4a51245d9800bc871e5901aa358b2fbcdb14913fd63f2aebb181756

See more details on using hashes here.

Provenance

The following attestation bundles were made for opengate_gate_tree-0.5.0-py3-none-any.whl:

Publisher: publish.yml on MateuszBala/opengate-gate-tree

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 files

0.4.0

2 files

0.3.0

2 files

0.2.1

2 files

0.2.0

2 files

0.1.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page