47.3. Creating Detector Modules
Table of Contents
Role of Detector Modules in a PET Ring
Detector modules are intermediate building blocks between the full PET ring and the individual crystals. Instead of placing every crystal one by one around the ring, you first define a module that groups several crystals in a fixed pattern, then repeat that module around the ring. This structure mirrors how real PET scanners are built and makes your simulation easier to configure, modify, and analyze.
In the context of the PET practical example, you already have, or will shortly have, a description of the PET ring geometry. The module sits inside that ring, and the crystals will later sit inside the module. When you count singles and coincidences, you will often identify events not only at the crystal level but also at the module level, so having a clear and regular module geometry is important.
Choosing a Module Geometry
A detector module is simply a volume in GATE that you place inside the ring volume. The physical design is usually a rectangular block containing an array of crystals. For this practical example you typically choose:
A rectangular box as the module envelope.
A crystal grid inside that box, for instance $N_x \times N_y$ crystals in transaxial and axial directions.
A small gap between crystals to represent reflective material or mechanical separation.
Although there is no universal rule for module size, it must be consistent with two aspects that are already defined or will be defined soon in other parts of the project: the ring radius and the crystal size.
The tangential size of the module, that is the dimension around the ring, should be approximately a multiple of the crystal width plus gaps. When you choose the number of modules per ring, the product of number of modules and module tangential width should match the ring circumference at the ring radius. If this does not match, modules will either overlap or leave gaps.
The axial size of the module, that is the dimension along the scanner axis, is usually constrained by the intended axial field of view. Here you decide how many modules you stack axially and how many crystals each module contains along that direction.
Before implementing the module, it is useful to write down a few simple relations between your chosen geometry parameters. If $r$ is the ring radius and $N_{\text{mod}}$ is the number of modules per ring, the tangential module width $w_{\text{mod}}$ should satisfy approximately
$$
N_{\text{mod}} \times w_{\text{mod}} \approx 2 \pi r.
$$
If each module contains $N_{\text{cryst}}$ crystals in the tangential direction, each with crystal width $w_{\text{cryst}}$ and gap $g$, then
$$
w_{\text{mod}} \approx N_{\text{cryst}} \times (w_{\text{cryst}} + g).
$$
Combining these gives you a consistency check between ring size, module count, and crystal size before you start coding.
Keep the module geometry consistent with the ring radius and the number of modules per ring. Large discrepancies will lead to overlaps or gaps and invalid PET geometry.
Defining Module Dimensions and Placement
Once you have decided on the number of crystals per module and their size, you can define the module envelope. In OpenGATE, the module is a volume that has a parent, usually the ring or the world, and a shape, commonly a box. Even though the exact code belongs to other chapters, you should understand how the parameters relate.
Assume you have decided to use $N_x$ crystals along the tangential direction and $N_y$ crystals along the axial direction. Let the crystal size be $(s_x, s_y, s_z)$ where $s_z$ is the radial thickness, and let the intercrystal gap be $g_x$ tangentially and $g_y$ axially. Then the module dimensions, ignoring any support structures, are approximately
$$
L_x = N_x \times s_x + (N_x - 1) \times g_x,
$$
$$
L_y = N_y \times s_y + (N_y - 1) \times g_y,
$$
$$
L_z = s_z,
$$
where $L_x$ is tangential, $L_y$ axial, and $L_z$ radial. In your simulation code you will typically define half lengths, that is $L_x/2$, $L_y/2$, and $L_z/2$, because the underlying Geant4 geometry uses half dimensions.
The module position is chosen so that the module center lies at a radius close to the ring radius. If the ring radius is $r_{\text{ring}}$, you place the module center approximately at $(x, y, z) = (r_{\text{ring}}, 0, 0)$ for the first module, then rotate copies of this module around the scanner axis. This radial placement will later align the crystals within the module so that their centers lie approximately on the desired detection radius.
In OpenGATE, repeated placement of the module around the ring is handled by repeated volumes or ring repetition tools that are explained elsewhere in the PET ring chapter. Conceptually, you first define a single module at a reference position and orientation, then instruct GATE to create multiple identical modules rotated by an angle
$$
\Delta \phi = \frac{2 \pi}{N_{\text{mod}}}
$$
around the scanner axis.
Module half lengths must be consistent with crystal sizes and gaps. Use half dimensions when defining box volumes and verify that the radial position of the module places the crystals on the intended detection radius.
Module Coordinate System and Orientation
To place crystals cleanly inside the module, it is helpful to choose a clear local coordinate system. Typically, you align the module box such that:
The local $z$ axis points radially outward or inward.
The local $x$ axis points tangentially around the ring.
The local $y$ axis points along the scanner axis.
With this convention, crystal indices $(i, j)$ where $i$ is tangential and $j$ is axial can be mapped directly to local coordinates inside the module. This is much simpler than working directly in global coordinates around the ring.
Suppose the module has tangential half length $L_x / 2$ and axial half length $L_y / 2$. For a crystal at index $i = 0, \dots, N_x - 1$ and $j = 0, \dots, N_y - 1$, you can compute its local $x$ coordinate as
$$
x_i = -\frac{L_x}{2} + \left(i + \frac{1}{2} \right)(s_x + g_x),
$$
and its local $y$ coordinate as
$$
y_j = -\frac{L_y}{2} + \left(j + \frac{1}{2} \right)(s_y + g_y).
$$
The local $z$ coordinate is typically zero if you center the crystals in the radial direction inside the module.
This consistent mapping from indices to positions makes it easy to use loops in your geometry code to create crystals later. You define the module only once, then use the index formulas to place every crystal in a rectangular array within the module.
Choose a simple, consistent local coordinate system for the module. This simplifies the mapping from crystal indices to positions and avoids rotation mistakes when the module is repeated around the ring.
Parameterizing Module Layout
For a practical PET example that you might extend or reuse, it is useful to define the module geometry using parameters instead of hard-coded values. In Python you would store parameters such as:
Number of crystals per module in each direction, $N_x$ and $N_y$.
Crystal dimensions and gaps, $s_x$, $s_y$, $s_z$, $g_x$, and $g_y$.
Module padding or extra support material thickness, if any.
From these parameters you compute derived quantities like $L_x$, $L_y$, $L_z$ and the module placement radius. The important point is not the specific code, which is handled in other chapters, but the structure of your decisions.
By parameterizing the module layout you can explore different scanner designs without rewriting the geometry. For example, you can study the impact of larger crystals, narrower gaps, or different numbers of crystals per module, simply by changing a few numbers.
A logical set of module-related parameters can be organized as in the following table.
| Parameter | Meaning |
|---|---|
| $N_x$ | Number of crystals tangentially per module |
| $N_y$ | Number of crystals axially per module |
| $s_x, s_y, s_z$ | Crystal size in each direction |
| $g_x, g_y$ | Gap between crystals |
| $L_x, L_y, L_z$ | Module dimensions |
| $r_{\text{ring}}$ | Ring radius for module center |
| $N_{\text{mod}}$ | Number of modules per ring |
When you later analyze singles or coincidences, you often identify detectors using crystal, module, and ring indices. Keeping these parameters explicit makes it straightforward to relate detector IDs to positions.
Avoid hard-coding module geometry values. Use parameters for crystal counts, sizes, and gaps so you can adapt and reuse the PET scanner model easily.
Avoiding Overlaps and Gaps Between Modules
Geometrical overlaps or unintended gaps between modules can lead to unphysical simulation results or even cause Geant4 to issue geometry warnings. When designing detector modules, you need to check two consistency conditions.
First, modules must not overlap each other at the ring radius. Using the earlier relations, verify that
$$
N_{\text{mod}} \times L_x \leq 2 \pi r_{\text{ring}}
$$
for tangential module length $L_x$. You can leave a very small clearance if you want explicit gaps for mechanical structures, but overlapping modules cause immediate problems.
Second, the crystals inside the module must not extend beyond the module envelope in any direction. That is, the extremal crystal centers plus half crystal size plus half gap must remain within the module half lengths. This is usually ensured automatically if you compute $L_x$ and $L_y$ from the crystal and gap parameters as described earlier.
During development it is useful to visualize the geometry and look closely at a small subset of modules and crystals to confirm that their placement is correct. The dedicated visualization chapters show how to do this, but you should already anticipate that visualization will be part of validating your module design.
Check that $N_{\text{mod}} \times L_x$ is compatible with $2 \pi r_{\text{ring}}$ and that crystals do not extend outside the module volume. Overlaps can invalidate the simulation and must be eliminated.
Module Identification and Integration with the Digitizer
Detector modules are not only geometric groupings. They also provide a natural level of identification for your digitizer and output. In the PET example, each crystal hit will typically be associated with several IDs, such as ring index, module index, and crystal index. The module is the intermediate level between the ring and the crystal.
Although the details of digitization and detector IDs are developed in separate chapters, during module creation you should already think about how modules will be indexed. A common convention is:
Assign a unique copy number or index to each module around the ring.
Derive that index from the repetition index when you repeat the module.
Later, when you build the crystal array inside the module, derive crystal IDs from the module and crystal indices.
This consistent hierarchy, ring to module to crystal, allows you to reconstruct detector positions from event data and to form lines of response between detector elements.
When you define the module volume, you should also give it a clear and descriptive name, for example "module" or "pet_module", so that you can later refer to it in actor or digitizer configurations.
Views: 9
KAHIBARO