Skip to content

Commit 2048784

Browse files
Merge pull request #136 from KrisThielemans/MoreCompleteAnalysisHelper
add extras to analysis helper: - loop over module-types - print box_shapes - cosmetics
2 parents 96c1dc0 + a1823a5 commit 2048784

File tree

2 files changed

+146
-91
lines changed

2 files changed

+146
-91
lines changed

cpp/helpers/petsird_analysis.cpp

Lines changed: 84 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,20 @@ print_usage_and_exit(char const* prog_name)
3939
std::exit(EXIT_FAILURE);
4040
}
4141

42+
// helper function to compute the mean of the corners in a BoxShape
43+
petsird::Coordinate
44+
mean_position(const petsird::BoxShape& box_shape)
45+
{
46+
petsird::Coordinate mean;
47+
mean.c = { 0, 0, 0 };
48+
for (auto& corner : box_shape.corners)
49+
{
50+
mean.c += corner.c;
51+
}
52+
mean.c /= box_shape.corners.size();
53+
return mean;
54+
}
55+
4256
int
4357
main(int argc, char const* argv[])
4458
{
@@ -86,35 +100,28 @@ main(int argc, char const* argv[])
86100
PETSIRDReader reader(filename);
87101
petsird::Header header;
88102
reader.ReadHeader(header);
103+
const auto& scanner = header.scanner;
89104

90105
std::cout << "Processing file: " << filename << std::endl;
91106
if (header.exam) // only do this if present
92107
std::cout << "Subject ID: " << header.exam->subject.id << std::endl;
93-
std::cout << "Types of modules: " << header.scanner.scanner_geometry.replicated_modules.size() << std::endl;
108+
const auto num_module_types = scanner.scanner_geometry.replicated_modules.size();
109+
std::cout << "Types of modules: " << num_module_types << std::endl;
94110
// TODO more than 1 type of module
95111
const petsird::TypeOfModule type_of_module{ 0 };
96112
std::cout << "Number of modules of first type: "
97-
<< header.scanner.scanner_geometry.replicated_modules[type_of_module].transforms.size() << std::endl;
113+
<< scanner.scanner_geometry.replicated_modules[type_of_module].transforms.size() << std::endl;
98114
std::cout << "Number of elements in modules of first type: "
99-
<< header.scanner.scanner_geometry.replicated_modules[type_of_module].object.detecting_elements.transforms.size()
115+
<< scanner.scanner_geometry.replicated_modules[type_of_module].object.detecting_elements.transforms.size()
100116
<< std::endl;
101117
std::cout << "Total number of 'crystals' in modules of first type : "
102-
<< petsird_helpers::get_num_det_els(header.scanner, type_of_module) << std::endl;
103-
// example printing of coordinates
104-
{
105-
const petsird::ExpandedDetectionBin expanded_detection_bin{ 0, 0, 0 };
106-
const auto box_shape = petsird_helpers::geometry::get_detecting_box(header.scanner, type_of_module, expanded_detection_bin);
107-
std::cout << "Coordinates of first detecting bin:\n";
108-
for (auto& corner : box_shape.corners)
109-
{
110-
std::cout << " [" << corner.c[0] << ", " << corner.c[1] << ", " << corner.c[2] << "]\n";
111-
}
112-
}
113-
const auto& tof_bin_edges = header.scanner.tof_bin_edges[type_of_module][type_of_module];
118+
<< petsird_helpers::get_num_det_els(scanner, type_of_module) << std::endl;
119+
120+
const auto& tof_bin_edges = scanner.tof_bin_edges[type_of_module][type_of_module];
114121
const auto num_tof_bins = tof_bin_edges.NumberOfBins();
115122
std::cout << "Number of TOF bins: " << num_tof_bins << std::endl;
116123
std::cout << "TOF bin edges: " << tof_bin_edges.edges << std::endl;
117-
const auto& event_energy_bin_edges = header.scanner.event_energy_bin_edges[type_of_module];
124+
const auto& event_energy_bin_edges = scanner.event_energy_bin_edges[type_of_module];
118125
const auto num_event_energy_bins = event_energy_bin_edges.NumberOfBins();
119126
std::cout << "Number of energy bins: " << num_event_energy_bins << std::endl;
120127
std::cout << "Event energy bin edges: " << event_energy_bin_edges.edges << std::endl;
@@ -124,7 +131,7 @@ main(int argc, char const* argv[])
124131
std::cout << "Event energy mid points: " << energy_mid_points << std::endl;
125132

126133
std::cout << "Singles Histogram Level: ";
127-
switch (header.scanner.singles_histogram_level)
134+
switch (scanner.singles_histogram_level)
128135
{
129136
case petsird::SinglesHistogramLevelType::kNone:
130137
std::cout << "none\n";
@@ -136,9 +143,9 @@ main(int argc, char const* argv[])
136143
std::cout << "all\n";
137144
break;
138145
}
139-
if (header.scanner.singles_histogram_level != petsird::SinglesHistogramLevelType::kNone)
146+
if (scanner.singles_histogram_level != petsird::SinglesHistogramLevelType::kNone)
140147
{
141-
const auto& singles_histogram_energy_bin_edges = header.scanner.singles_histogram_energy_bin_edges[type_of_module];
148+
const auto& singles_histogram_energy_bin_edges = scanner.singles_histogram_energy_bin_edges[type_of_module];
142149
std::cout << "Singles Histogram Energy Bin Edges: " << singles_histogram_energy_bin_edges.edges << std::endl;
143150
std::cout << "Number of Singles Histogram Energy Windows: " << singles_histogram_energy_bin_edges.NumberOfBins()
144151
<< std::endl;
@@ -157,37 +164,69 @@ main(int argc, char const* argv[])
157164
{
158165
auto& event_time_block = std::get<petsird::EventTimeBlock>(time_block);
159166
last_time = event_time_block.time_interval.stop;
160-
const petsird::TypeOfModulePair type_of_module_pair{ 0, 0 };
161-
num_prompts += event_time_block.prompt_events[type_of_module_pair[0]][type_of_module_pair[1]].size();
162-
if (event_time_block.delayed_events)
163-
num_delayeds += (*event_time_block.delayed_events)[type_of_module_pair[0]][type_of_module_pair[1]].size();
167+
164168
if (print_events)
165169
std::cout << "===================== Prompt events in time block from " << last_time << " ==============\n";
166170

167-
// Note: just doing one module-type ATM
168-
for (auto& event : event_time_block.prompt_events[type_of_module_pair[0]][type_of_module_pair[1]])
171+
for (unsigned mtype0 = 0; mtype0 < num_module_types; ++mtype0)
169172
{
170-
const auto expanded_detection_bin0
171-
= petsird_helpers::expand_detection_bin(header.scanner, type_of_module_pair[0], event.detection_bins[0]);
172-
const auto expanded_detection_bin1
173-
= petsird_helpers::expand_detection_bin(header.scanner, type_of_module_pair[1], event.detection_bins[1]);
174-
175-
energy_1 += energy_mid_points[expanded_detection_bin0.energy_index];
176-
energy_2 += energy_mid_points[expanded_detection_bin1.energy_index];
177-
178-
if (print_events)
173+
for (unsigned mtype1 = 0; mtype1 < num_module_types; ++mtype1)
179174
{
180-
std::cout << "CoincidenceEvent(detectionBins=[" << event.detection_bins[0] << ", " << event.detection_bins[1]
181-
<< "], tofIdx=" << event.tof_idx << "])\n";
182-
std::cout << " "
183-
<< "[ExpandedDetectionBin(module=" << expanded_detection_bin0.module_index << ", "
184-
<< "el=" << expanded_detection_bin0.element_index << ", "
185-
<< "energy_index=" << expanded_detection_bin0.energy_index
186-
<< "), ExpandedDetectionBin(module=" << expanded_detection_bin1.module_index << ", "
187-
<< "el=" << expanded_detection_bin1.element_index << ", "
188-
<< "energy_index=" << expanded_detection_bin1.energy_index << ")]\n";
189-
std::cout << " efficiency:"
190-
<< petsird_helpers::get_detection_efficiency(header.scanner, type_of_module_pair, event) << "\n";
175+
const petsird::TypeOfModulePair mtype_pair{ mtype0, mtype1 };
176+
const auto& prompt_events = event_time_block.prompt_events[mtype0][mtype1];
177+
178+
// count events
179+
num_prompts += prompt_events.size();
180+
if (event_time_block.delayed_events)
181+
{
182+
num_delayeds += (*event_time_block.delayed_events)[mtype0][mtype1].size();
183+
}
184+
185+
if (print_events)
186+
{
187+
std::cout << "---------------------------- prompts for modules : "
188+
<< "[" << mtype_pair[0] << ", " << mtype_pair[1] << "]\n";
189+
}
190+
191+
for (const auto& event : prompt_events)
192+
{
193+
const auto expanded_det_bin0
194+
= petsird_helpers::expand_detection_bin(scanner, mtype0, event.detection_bins[0]);
195+
const auto expanded_det_bin1
196+
= petsird_helpers::expand_detection_bin(scanner, mtype1, event.detection_bins[1]);
197+
198+
// accumulate energies to print average below
199+
energy_1 += energy_mid_points[expanded_det_bin0.energy_index];
200+
energy_2 += energy_mid_points[expanded_det_bin1.energy_index];
201+
202+
if (print_events)
203+
{
204+
std::cout << "CoincidenceEvent(detectionBins=[" << event.detection_bins[0] << ", "
205+
<< event.detection_bins[1] << "], tofIdx=" << event.tof_idx << "])\n";
206+
std::cout << " "
207+
<< "[ExpandedDetectionBin(module=" << expanded_det_bin0.module_index << ", "
208+
<< "el=" << expanded_det_bin0.element_index << ", "
209+
<< "energy_index=" << expanded_det_bin0.energy_index
210+
<< "), ExpandedDetectionBin(module=" << expanded_det_bin1.module_index << ", "
211+
<< "el=" << expanded_det_bin1.element_index << ", "
212+
<< "energy_index=" << expanded_det_bin1.energy_index << ")]\n";
213+
214+
const auto eff = petsird_helpers::get_detection_efficiency(scanner, mtype_pair, event);
215+
std::cout << " efficiency: " << eff << std::endl;
216+
217+
const auto box_shape0
218+
= petsird_helpers::geometry::get_detecting_box(scanner, mtype0, expanded_det_bin0);
219+
const auto box_shape1
220+
= petsird_helpers::geometry::get_detecting_box(scanner, mtype0, expanded_det_bin1);
221+
const auto mean0 = mean_position(box_shape0);
222+
const auto mean1 = mean_position(box_shape1);
223+
224+
std::cout << " mean of detection box 0: [" << mean0.c[0] << ", " << mean0.c[1] << ", " << mean0.c[2]
225+
<< "]\n";
226+
std::cout << " mean of detection box 1: [" << mean1.c[0] << ", " << mean1.c[1] << ", " << mean1.c[2]
227+
<< "]\n";
228+
}
229+
}
191230
}
192231
}
193232
}

python/petsird/helpers/analysis.py

Lines changed: 62 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ def parserCreator():
4343
if header.exam is not None:
4444
print(f"Subject ID: {header.exam.subject.id}")
4545
print(f"Scanner name: {scanner.model_name}")
46+
num_module_types = len(scanner.scanner_geometry.replicated_modules)
47+
print("Types of modules: ", num_module_types)
4648
type_of_module = 0
47-
print("Types of modules: ",
48-
len(scanner.scanner_geometry.replicated_modules))
4949
print(
5050
"Number of modules of first type: ",
5151
len(scanner.scanner_geometry.replicated_modules[type_of_module].
@@ -56,15 +56,6 @@ def parserCreator():
5656
object.detecting_elements.transforms))
5757
print("Total number of 'crystals': ",
5858
get_num_det_els(scanner, type_of_module))
59-
# example printing of coordinates
60-
expanded_detection_bin = petsird.ExpandedDetectionBin(module_index=0,
61-
element_index=0,
62-
energy_index=0)
63-
box_shape = petsird.helpers.geometry.get_detecting_box(
64-
header.scanner, type_of_module, expanded_detection_bin)
65-
print("Coordinates of first detecting bin:")
66-
for corner in box_shape.corners:
67-
print(corner.c)
6859

6960
tof_bin_edges = scanner.tof_bin_edges[type_of_module][type_of_module]
7061
num_tof_bins = tof_bin_edges.number_of_bins()
@@ -94,43 +85,68 @@ def parserCreator():
9485
last_time = 0
9586
for time_block in reader.read_time_blocks():
9687
if isinstance(time_block, petsird.TimeBlock.EventTimeBlock):
97-
# TODO just doing one module-type ATM
98-
type_of_module_pair = petsird.TypeOfModulePair((0, 0))
9988
last_time = time_block.value.time_interval.stop
100-
num_prompts += len(time_block.value.prompt_events[
101-
type_of_module_pair[0]][type_of_module_pair[1]])
102-
if time_block.value.delayed_events is not None:
103-
num_delayeds += len(time_block.value.delayed_events[
104-
type_of_module_pair[0]][type_of_module_pair[1]])
105-
print("===================== Events between module-types ",
106-
type_of_module_pair, " in time block until ", last_time,
107-
" ==============")
108-
for event in time_block.value.prompt_events[
109-
type_of_module_pair[0]][type_of_module_pair[1]]:
110-
expanded_detection_bin0 = expand_detection_bin(
111-
scanner, type_of_module_pair[0],
112-
event.detection_bins[0])
113-
expanded_detection_bin1 = expand_detection_bin(
114-
scanner, type_of_module_pair[1],
115-
event.detection_bins[1])
89+
for mtype0 in range(num_module_types):
90+
for mtype1 in range(num_module_types):
91+
mtype_pair = petsird.TypeOfModulePair((mtype0, mtype1))
11692

117-
energy_1 += energy_mid_points[
118-
expanded_detection_bin0.energy_index]
119-
energy_2 += energy_mid_points[
120-
expanded_detection_bin1.energy_index]
121-
if print_events:
122-
print(event)
123-
print(
124-
" ",
125-
expanded_detection_bin0,
126-
", ",
127-
expanded_detection_bin1,
128-
)
129-
print(
130-
" efficiency:",
131-
get_detection_efficiency(scanner,
132-
type_of_module_pair,
133-
event))
93+
# count events
94+
prompt_events = time_block.value.prompt_events[mtype0][
95+
mtype1]
96+
num_prompts += len(prompt_events)
97+
if time_block.value.delayed_events is not None:
98+
num_delayeds += len(
99+
time_block.value.delayed_events[mtype0]
100+
[mtype1])
101+
102+
if print_events:
103+
print(
104+
"---------------------------- prompts for modules : ",
105+
mtype_pair)
106+
107+
for event in prompt_events:
108+
expanded_det_bin0 = expand_detection_bin(
109+
scanner, mtype0, event.detection_bins[0])
110+
expanded_det_bin1 = expand_detection_bin(
111+
scanner, mtype1, event.detection_bins[1])
112+
113+
# accumulate energies to print average below
114+
energy_1 += energy_mid_points[
115+
expanded_det_bin0.energy_index]
116+
energy_2 += energy_mid_points[
117+
expanded_det_bin1.energy_index]
118+
if print_events:
119+
print(event)
120+
print(
121+
" ",
122+
expanded_det_bin0,
123+
", ",
124+
expanded_det_bin1,
125+
)
126+
eff = get_detection_efficiency(
127+
scanner, mtype_pair, event)
128+
print(" efficiency:", eff)
129+
130+
# get detector-element coordinates (relative to gantry)
131+
box_shape0 = petsird.helpers.geometry.get_detecting_box(
132+
scanner, mtype0, expanded_det_bin0)
133+
box_shape1 = petsird.helpers.geometry.get_detecting_box(
134+
scanner, mtype0, expanded_det_bin1)
135+
136+
# print some info
137+
# (but not complete box, as it's a bit overwhelming)
138+
print(
139+
" mean of detection box 0:",
140+
sum([
141+
corner.c
142+
for corner in box_shape0.corners
143+
]) / len(box_shape0.corners))
144+
print(
145+
" mean of detection box 1:",
146+
sum([
147+
corner.c
148+
for corner in box_shape1.corners
149+
]) / len(box_shape1.corners))
134150

135151
print(f"Last time block at {last_time} ms")
136152
print(f"Number of prompt events: {num_prompts}")

0 commit comments

Comments
 (0)