3.7. Working with Files
Table of Contents
Paths
In GATE simulations written with Python, file paths tell your script where to find inputs and where to write results. Handling paths carefully is essential when you move simulations between computers or operating systems.
At the simplest level, a path is just a string, such as "data/phantom.mhd" or "C:\\Users\\user\\gate\\input.root". However, for portable and readable code you should prefer Python’s pathlib module. It provides a Path object that understands directory separators and can join parts of a path safely.
For example, instead of writing a hard coded string, you can write:
from pathlib import Path
base_dir = Path(__file__).parent # directory of the current script
data_dir = base_dir / "data" # create a subdirectory path
phantom_path = data_dir / "phantom.mhd"
The operator / joins path segments correctly on any operating system. When you pass paths to GATE or other libraries, you often need a string representation. You can obtain this with str(phantom_path) or phantom_path.as_posix().
Relative paths are interpreted from the current working directory, usually the directory from which you start Python. If you run a script from different locations, relative paths can suddenly fail. A common technique in simulation projects is to define paths relative to the script file, as in the example above, to remove dependence on how you start the program.
You can check if a path exists using path.exists(), create directories with path.mkdir(parents=True, exist_ok=True), and inspect components such as filename or extension with attributes like path.name, path.stem, and path.suffix. This is often used when building output locations for a series of simulations.
When building a GATE simulation, keep all path logic in a small number of places at the top of your script. For example, define a project root, a data directory for inputs, and an output directory for results. Later chapters will use these paths when loading images or writing dose maps, but the basic path handling described here will stay the same.
Input files
Input files provide external information to your simulations, such as geometry definitions, material tables, source descriptions, or medical images. In Python based GATE simulations, you will frequently read:
- Text files such as CSV or simple configuration files.
- Binary or scientific formats such as NumPy
.npyfiles, image volumes, or tables. - Metadata or settings files such as JSON or YAML.
For text input, always open files using the context manager syntax. This ensures files are closed as soon as you finish reading them.
from pathlib import Path
config_path = Path("config") / "settings.txt"
with config_path.open("r") as f:
lines = f.readlines()
If you need structured data, for example a table of source positions, NumPy and pandas are very helpful. NumPy can load simple arrays with np.loadtxt or np.genfromtxt, and pandas can read CSV tables with pd.read_csv.
import numpy as np
from pathlib import Path
positions_path = Path("data") / "source_positions.csv"
positions = np.loadtxt(positions_path, delimiter=",")
Later chapters introduce medical image formats and DICOM, but the same basic pattern applies. You build a Path, check that it exists, then use a library to read the file into Python.
It is a good habit to verify input files before starting long simulations. This can be as simple as checking path.exists() or inspecting shapes, ranges, and units of numerical data. You can wrap these checks in small helper functions. For instance, a function that reads a CSV file of source coordinates and asserts that each row has three columns for $x$, $y$, and $z$.
Whenever an input file contains physical quantities that will be passed to GATE, pay particular attention to units. If a CSV file stores distances in centimeters but your simulation expects millimeters, convert them in Python before using them. You might implement a small conversion like:
positions_cm = np.loadtxt(positions_path, delimiter=",")
positions_mm = positions_cm * 10.0Always document in comments or metadata which units are used in input files, and convert them explicitly to GATE units inside your Python script before building the simulation.
Finally, keep all input files under a clear directory structure, for example a data directory for geometry and image files and a config directory for settings. Then, refer to them with well named Path variables, rather than scattering file names throughout your code.
Output directories
GATE simulations typically generate multiple output files, for example ROOT files with hits and singles, dose images, and text summaries. If you do not plan your output directories in advance, it becomes very difficult to track results from different runs.
A common pattern is to create a main output directory, then a separate subdirectory for each simulation run. The subdirectory name can contain a short description or a timestamp, for example pet_test_001 or run_2026_08_18_1530. You can build and create such a directory with pathlib.
from pathlib import Path
from datetime import datetime
project_dir = Path(__file__).parent
output_root = project_dir / "output"
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
run_dir = output_root / f"run_{timestamp}"
run_dir.mkdir(parents=True, exist_ok=True)
You then pass str(run_dir) or a file path within this directory to GATE when you configure actors or digitizers that write files. For example, a statistics actor may write stats.txt, and a phase space actor may write phsp.root, both into run_dir.
Using separate directories per run provides several advantages. You can repeat a simulation with modified parameters without overwriting previous output. You can attach a small text file or JSON file with the exact simulation settings inside the same directory which supports reproducibility. Later, when you perform analysis with Python or ROOT, you can loop over run directories and combine or compare results.
You can also organize outputs by data type. Inside a run directory, you might create subdirectories for ROOT files, dose images, and logs. This is handled in the same way as before, by extending the path and creating the directory if it does not yet exist.
dose_dir = run_dir / "dose"
dose_dir.mkdir(exist_ok=True)
root_dir = run_dir / "root"
root_dir.mkdir(exist_ok=True)Always create output directories explicitly in Python before starting the simulation, and never rely on GATE to create intermediate directories for you. Use unique directory or file names for each run to avoid accidental overwriting of results.
In later chapters, you will see concrete examples where these directory paths are passed into the simulation object, actors, and digitizers. The basic idea remains the same: define clear paths at the top of your script, use them consistently, and keep simulation outputs separated and well documented.
Views: 16
KAHIBARO