25.4. Assigning Detector IDs
Table of Contents
Why Detector IDs Matter
In a PET scanner simulation you rarely care about individual scintillation crystals for their own sake. What you really need to know is which detector element fired, in which ring, and at which angular position. This logical identity is what you will use later to build coincidences and lines of response.
Geant4 itself does not know what “detector number 37 in ring 2” means. It only transports particles and lets you define volumes and sensitive detectors. The mapping from a particle interaction to a detector index is your responsibility, and that mapping is what “assigning detector IDs” describes.
Whenever a hit is created in a PET crystal volume, you need to attach enough information to that hit so that later analysis can say “this hit came from detector (ring, crystal index, maybe axial index).” Detector IDs implement that link between geometry and data.
Logical vs Physical Identification
It is useful to distinguish two related but different ideas: volume identity in the geometry, and detector identity used in analysis.
Geant4 identifies volumes primarily through their logical and physical volume objects. A logical volume represents a kind of material and shape, such as “LYSO crystal,” and may be reused many times. A physical volume represents one placement of that logical volume in space. In a PET ring you may have tens or hundreds of placements that all use the same logical volume.
Your PET analysis, however, usually wants a compact indexing scheme. For example, you might use a single integer detector ID that runs from 0 to $N_\text{det}-1$, or you might keep separate indices, such as ring index and crystal index. This is a logical detector identity, independent of how exactly the geometry is built.
To connect these, you typically use one or more of the following:
- Position based identification. In the sensitive detector, you read the global hit position and infer which detector element it lies in, for example using angular binning around the ring.
- Copy numbers from volume placements. When you place many repeated detector crystals, you assign a copy number to each physical volume. That copy number is available in your sensitive detector and can be used as a detector index.
- Parameterized or replica geometry indices. If you use replicas or parameterized volumes to construct the ring, Geant4 provides an index for each child volume, which can be read and translated to your detector ID.
In PET, copy numbers are usually the simplest and most robust way to assign detector IDs, especially when you know in advance how many crystals per ring and how many rings your scanner has.
Using Copy Numbers for PET Crystals
Every G4VPhysicalVolume has an associated copy number. You can set it when you construct the geometry, and later, in your sensitive detector, you retrieve it from the step to know which copy of the volume was hit.
For a PET detector ring, you often have a repeated structure: many crystals placed around a circle, possibly repeated in several axial rings. A common convention is:
- Use one logical volume for all crystals.
- Place each crystal with a unique copy number.
- Encode the crystal index (and optionally ring index) into that copy number.
- Decode this number in the sensitive detector when storing hits.
The copy number is an integer, so you can pack several indices into one number if needed. For example, if you have $N_\text{cryst}$ crystals per ring and $N_\text{ring}$ rings, you can define a detector ID as
$$
\text{detID} = \text{ringIndex} \cdot N_\text{cryst} + \text{crystalIndex}.
$$
This single integer then uniquely identifies a detector element in the whole scanner.
Important rule: Always assign copy numbers deliberately and consistently in your PET geometry, and always use the same convention to encode and decode detector IDs. Inconsistent or implicit copy numbers are a very common source of indexing errors.
With this convention, if you later want to recover the ring and crystal index from a stored detID, you simply compute
$$
\text{ringIndex} = \left\lfloor \frac{\text{detID}}{N_\text{cryst}} \right\rfloor,\quad
\text{crystalIndex} = \text{detID} \bmod N_\text{cryst}.
$$
Assigning IDs in the Geometry
You assign detector IDs at the moment you build the PET crystals in the geometry, typically in your detector construction class. How you do it depends on how you choose to arrange the crystals, but for a simple single ring the pattern is straightforward.
Suppose you have a single ring in the transverse plane, with $N_\text{cryst}$ crystals arranged around a circle. You may write a loop that places each crystal at the appropriate angle, and at the same time set the copy number to the crystal index:
You loop over an integer index i from 0 to $N_\text{cryst} - 1$, compute the rotation and translation for crystal $i$, create a new G4PVPlacement for that crystal, and pass i to the copy number argument. Now copy number equals crystal index, and can later serve directly as the detector ID for a single ring.
If you have multiple rings in the axial direction, you add an outer loop over ring index j, and inside you still loop over crystals. The copy number can then be set to the combined ID:
$$
\text{copyNumber} = j \cdot N_\text{cryst} + i.
$$
Here i is the crystal index within a ring and j is the ring index. This pattern immediately matches the formula for detID.
If you use more advanced constructions such as replicas or parameterized volumes, the logic is similar, but Geant4 may provide indices automatically. For example, if you create a replica volume of crystals around a ring, each replica has an index from 0 to $N_\text{cryst}-1$. You can still compute a combined detector ID using that index and any additional index from an outer placement.
The main design decision is where to compute this integer detector ID. You can either:
Compute and assign the final detector ID directly as the copy number when building the geometry. In this case, your sensitive detector just reads the copy number and uses it as detID without further decoding.
Store separate indices (for example, set copy numbers at one hierarchy level to be the ring index, and at another level to be the crystal index) and combine them later in the sensitive detector. This is useful if your geometry is hierarchical and each replica has its own logical meaning.
For a beginner friendly PET example, assigning the final detector ID directly as the copy number in the crystal placements is often simplest.
Retrieving IDs in the Sensitive Detector
Once the geometry assigns detector IDs via copy numbers or indices, the sensitive detector is the place where you attach these IDs to hits. The sensitive detector’s ProcessHits method receives a G4Step pointer, which gives access to the current track and its volume.
To retrieve the detector ID for a hit, you typically:
Access the pre step point from the step. The pre step point corresponds to the entrance into the sensitive volume for that step, which is usually the correct place to identify the crystal.
Request the physical volume from the pre step point’s touchable handle. The touchable represents the full hierarchy of placements that led to this point in space.
Read the copy number or replica index from the appropriate level of the touchable. For simple placements where only one detector level is involved, you can simply call GetCopyNumber() on the volume. For nested structures, you might need to specify a depth in the touchable hierarchy.
Once you have the integer, you decide how to treat it. In a simple scheme where copy number already equals your overall detector ID, you can store it directly in the hit object. If copy numbers at multiple hierarchy levels are involved, you decode them into ring and crystal indices, or combine them into a single integer detID.
A typical PET hit class will therefore have at least one field that stores the detector ID. Some designs store both the overall detID and separate ringIndex and crystalIndex. This duplication can make later analysis and debugging easier.
At analysis time, when you read back your hits or ntuples, you will use these IDs to:
Group hits by detector for energy summing.
Find pairs of hits in opposite detectors for coincidence detection.
Convert detector indices into angular positions and ring numbers to build lines of response.
Without consistent detector IDs, these steps become fragile or impossible.
Indexing Schemes for PET Rings
PET scanners are naturally described using several indices, which you can combine or keep separate depending on your analysis needs. Typical indices are:
Azimuthal index around the ring, counting crystals in the transverse plane.
Axial index along the scanner axis, counting rings along the patient’s body.
Radial index, if you have multiple concentric rings of crystals at different radii.
You have several options for encoding these into detector IDs.
One contiguous global index approach is to give every crystal in the entire scanner exactly one unique ID from 0 to $N_\text{total}-1$. The copy number is then this ID, often computed as a combination of indices:
$$
\text{detID} = i_\text{axial} \cdot N_\text{azimuthal} \cdot N_\text{radial}
+ i_\text{azimuthal} \cdot N_\text{radial}
+ i_\text{radial}.
$$
This is useful if your analysis always needs a single unique number, for example for histogram binning or building compressed mappings.
A multi index approach is to keep the separate indices explicit. You may assign ring index in the placement of rings, and crystal index in a child placement or replica around the ring. In this case, the touchable hierarchy in the sensitive detector lets you read both indices. You then store both in the hit. When building a final detID (if you want one), you use the same formula consistently throughout your code.
Whatever you choose, two principles are important:
The mapping from geometry indices to detector IDs must be fixed and clearly documented. Do not rely on default or implicit copy numbers that may change when you modify the geometry.
The interpretation of detector IDs in analysis code must use the same mapping. If you change the geometry or indexing scheme, you must update your analysis accordingly.
Important statement: Once you have defined a detector ID convention for your PET scanner, treat it as part of the data format. Changing it after you have produced simulation data will make old and new results hard to compare, unless you carefully track and transform the IDs.
By planning and implementing detector ID assignment carefully at the geometry and sensitive detector levels, you prepare your PET simulation for robust coincidence building, line of response construction, and image reconstruction in the later stages of your project.
Views: 5
KAHIBARO