Skip to content

Commit

Permalink
Merge pull request #20 from KrisThielemans/Triples
Browse files Browse the repository at this point in the history
add Triple events, multiples strategy and changed CoincidenceEvent
  • Loading branch information
KrisThielemans authored Sep 6, 2024
2 parents fe29abd + 62ccc79 commit b7e042c
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 19 deletions.
4 changes: 2 additions & 2 deletions cpp/prd_analysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ main(int argc, char* argv[])

for (auto& event : time_block.prompt_events)
{
energy_1 += energy_mid_points[event.energy_1_idx];
energy_2 += energy_mid_points[event.energy_2_idx];
energy_1 += energy_mid_points[event.energy_indices[0]];
energy_2 += energy_mid_points[event.energy_indices[1]];
}
}

Expand Down
8 changes: 4 additions & 4 deletions cpp/prd_generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,10 @@ get_events(const prd::Header& header, std::size_t num_events)
{
const auto detectors = get_random_pair(header.scanner.NumberOfDetectors());
prd::CoincidenceEvent e;
e.detector_1_id = detectors.first;
e.detector_2_id = detectors.second;
e.energy_1_idx = get_random_energy_value();
e.energy_2_idx = get_random_energy_value();
e.detector_ids[0] = detectors.first;
e.detector_ids[1] = detectors.second;
e.energy_indices[0] = get_random_energy_value();
e.energy_indices[1] = get_random_energy_value();
e.tof_idx = get_random_tof_value();
events.push_back(e);
}
Expand Down
11 changes: 6 additions & 5 deletions model/CoincidenceEvent.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# All information about a coincidence event specified as identifiers or indices (i.e. discretized).
# All information about a coincidence event specified as identifiers or indices (i.e. discretized). Indices start from 0.
# TODO: this might take up too much space, so some/all of these could be combined in a single index if necessary.
CoincidenceEvent: !record
fields:
detector1Id: uint
detector2Id: uint
# the pair of detector elements
detectorIds: uint*2
# an index into the tofBinEdges field in the ScannerInformation
tofIdx: uint
energy1Idx: uint
energy2Idx: uint
# a pair of indices into the energyBinEdges field in the ScannerInformation
energyIndices: uint*2
5 changes: 3 additions & 2 deletions model/Protocol.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ TimeBlock: !record
# list of prompts in this time block
# TODO might be better to use !array
promptEvents: CoincidenceEvent*
# list of delayed coincidences in this time block
# optional list of delayed coincidences in this time block
delayedEvents: CoincidenceEvent*?

# optional list of triple coincidences in this time block
tripleEvents: TripleEvent*?
25 changes: 25 additions & 0 deletions model/ScannerInformation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,34 @@ Detector: !record
y: float
z: float

# Type definition for how to encode how the scanner handles multiple coincidences when recording the prompts.
# Due to various effects (such as high count rate, prompt gammas), it is possible that multiple single
# events are detected within the coincidence window. This type encodes some different ways
# that this multiple events are handled, and recorded in the coincidence stream.
CoincidencePolicy: !enum
values:
# multiples will be rejected
- rejectMultiples

# multiples will be stored as a sequence of pairs, e.g. a triple leads to 3 pairs
- storeMultiplesAsPairs

# other options, to be listed in the future
- other


ScannerInformation: !record
fields:
modelName: string?

# list of geometric information for all detector elements
# TODO will be adjusted when properly encoding geometry
detectors: Detector*

# edge information for TOF bins in mm (given as from first to last edge, so there is one more edge than the number of bins)
# 0 corresponds to the same arrival time. Negative numbers indicate that the first detector detected first.
# For instance, a coincidence event is stored as 2 detectorIds, denoting the arrival time at the first
# detector t1 and the arrival time at the second detector t2, we store (t1-t2)*c/2.
# TODO: this currently assumes equal size for each TOF bin, but some scanners "stretch" TOF bins depending on length of LOR
tofBinEdges: !array
items: float
Expand All @@ -32,6 +54,9 @@ ScannerInformation: !record
# duration of each time block in ms
listmodeTimeBlockDuration: uint

# encode how the scanner handles multiple coincidences
coincidencePolicy: CoincidencePolicy

computedFields:
numberOfDetectors: size(detectors)
numberOfTOFBins: size(tofBinEdges)-1
Expand Down
11 changes: 11 additions & 0 deletions model/TripleEvent.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# All information about a triple event specified as identifiers or indices (i.e. discretized).
TripleEvent: !record
fields:
detectorIds: uint*3
# timing differences (converted to mm) w.r.t. first event, stored as
# indices into the tofBinEdges field in the ScannerInformation
# Note: only 2, corresponding to the arrival time differences of the second and third detectorId
# listed w.r.t. the first detectorId
tofIndices: uint*2
# indices for each single event into the energyBinEdges field in the ScannerInformation
energyIndices: uint*3
4 changes: 2 additions & 2 deletions python/prd_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
last_time = time_block.id * header.scanner.listmode_time_block_duration
num_prompts += len(time_block.prompt_events)
for event in time_block.prompt_events:
energy_1 += energy_mid_points[event.energy_1_idx]
energy_2 += energy_mid_points[event.energy_2_idx]
energy_1 += energy_mid_points[event.energy_indices[0]]
energy_2 += energy_mid_points[event.energy_indices[1]]

print(f"Last time block at {last_time} ms")
print(f"Number of prompt events: {num_prompts}")
Expand Down
8 changes: 4 additions & 4 deletions python/prd_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,10 @@ def get_events(header: prd.Header, num_events: int) -> Iterator[prd.CoincidenceE
detector_count = header.scanner.number_of_detectors()
for _ in range(num_events):
yield prd.CoincidenceEvent(
detector_1_id=random.randrange(0, detector_count),
detector_2_id=random.randrange(0, detector_count),
energy_1_idx=random.randrange(0, NUMBER_OF_ENERGY_BINS),
energy_2_idx=random.randrange(0, NUMBER_OF_ENERGY_BINS),
detector_ids = [random.randrange(0, detector_count),
random.randrange(0, detector_count)],
energy_indices = [random.randrange(0, NUMBER_OF_ENERGY_BINS),
random.randrange(0, NUMBER_OF_ENERGY_BINS)],
tof_idx=random.randrange(0, NUMBER_OF_TOF_BINS),
)

Expand Down

0 comments on commit b7e042c

Please sign in to comment.