STIR 6.4.0
Scanner.h
Go to the documentation of this file.
1/*
2 Copyright (C) 2000 PARAPET partners
3 Copyright (C) 2000-2010, Hammersmith Imanet Ltd
4 Copyright (C) 2011-2013, King's College London
5 Copyright (C) 2016, University of Hull
6 Copyright (C) 2016, 2019, 2021, 2023 UCL
7 Copyright 2017 ETH Zurich, Institute of Particle Physics and Astrophysics
8 Copyright (C 2017-2018, University of Leeds
9 This file is part of STIR.
10
11 SPDX-License-Identifier: Apache-2.0 AND License-ref-PARAPET-license
12
13 See STIR/LICENSE.txt for details
14*/
15
33#ifndef __stir_buildblock_SCANNER_H__
34#define __stir_buildblock_SCANNER_H__
35
39#include "stir/shared_ptr.h"
40#include <string>
41#include <list>
42#include <vector>
43#include <cmath>
44#include <algorithm>
45#include <fstream>
46#include <boost/algorithm/string.hpp>
47#include <boost/unordered_map.hpp>
48
49START_NAMESPACE_STIR
50
51class Succeeded;
108{
109 friend class BlocksTests;
110
111public:
112 /************* static members*****************************/
113 static Scanner* ask_parameters();
114
116 static Scanner* get_scanner_from_name(const std::string& name);
118 /* \return a string with one line per predefined scanner, listing the predefined names for
119 that scanner (separated by a comma)
120 */
121 static std::string list_all_names();
123 /* \return a list of strings, each element is a name of a predefined scanner.
124 If a scanner can have multiple names, only one name is returned, i.e.
125 the list has the same length as the number of predefined scanners.
126 */
127 static std::list<std::string> get_names_of_predefined_scanners();
128
129 // E931 HAS to be first, Unknown_scanner HAS to be last
130 // also, the list HAS to be consecutive (so DO NOT assign numbers here)
131 // finally, test_Scanner assumes E966 is the last in the list of CTI scanners
132 // supported by ecat_model from the LLN matrix library
133 // 08-3-2004, zlong, add user defined scanner
135 /* \a Userdefined_scanner can be used to set arbitrary scanner geometry info.
136 \a Unknown_scanner will be used when parsing (e.g. from an Interfile header)
137 to flag up an error and do some guess work in trying to recognise the scanner from
138 any given parameters.
139 */
140 enum Type
141 {
142 E931,
143 E951,
144 E953,
145 E921,
146 E925,
147 E961,
148 E962,
149 E966,
150 E1080,
151 test_scanner,
152 Siemens_mMR,
153 Siemens_mCT,
154 Siemens_Vision_600,
155 Siemens_Quadra,
156 RPT,
157 HiDAC,
158 Advance,
159 DiscoveryLS,
160 DiscoveryST,
161 DiscoverySTE,
162 DiscoveryRX,
163 Discovery600,
164 PETMR_Signa,
165 Discovery690,
166 DiscoveryMI3ring,
167 DiscoveryMI4ring,
168 DiscoveryMI5ring,
169 DiscoveryMI6ring,
170 HZLR,
171 RATPET,
172 PANDA,
173 HYPERimage,
174 nanoPET,
175 HRRT,
176 Allegro,
177 GeminiTF,
178 SAFIRDualRingPrototype,
179 UPENN_5rings,
180 UPENN_5rings_no_gaps,
181 UPENN_6rings,
182 UPENN_6rings_no_gaps,
183 User_defined_scanner,
184 Unknown_scanner
185 };
186
187 virtual ~Scanner() {}
188
190 Scanner(Type scanner_type);
191
193
198 Scanner(Type type_v,
199 const std::list<std::string>& list_of_names_v,
200 int num_detectors_per_ring_v,
201 int num_rings_v,
202 int max_num_non_arccorrected_bins_v,
203 int default_num_arccorrected_bins_v,
204 float inner_ring_radius_v,
205 float average_depth_of_interaction_v,
206 float ring_spacing_v,
207 float bin_size_v,
208 float intrinsic_tilt_v,
209 int num_axial_blocks_per_bucket_v,
210 int num_transaxial_blocks_per_bucket_v,
211 int num_axial_crystals_per_block_v,
212 int num_transaxial_crystals_per_block_v,
213 int num_axial_crystals_per_singles_unit_v,
214 int num_transaxial_crystals_per_singles_unit_v,
215 int num_detector_layers_v,
216 float energy_resolution_v = -1.0f,
217 float reference_energy_v = -1.0f,
218 short int max_num_of_timing_poss = -1,
219 float size_timing_pos = -1.0f,
220 float timing_resolution = -1.0f,
221 const std::string& scanner_geometry_v = "Cylindrical",
222 float axial_crystal_spacing_v = -1.0f,
223 float transaxial_crystal_spacing_v = -1.0f,
224 float axial_block_spacing_v = -1.0f,
225 float transaxial_block_spacing_v = -1.0f,
226 const std::string& crystal_map_file_name = "");
227
229
234 Scanner(Type type_v,
235 const std::string& name,
236 int num_detectors_per_ring_v,
237 int num_rings_v,
238 int max_num_non_arccorrected_bins_v,
239 int default_num_arccorrected_bins_v,
240 float inner_ring_radius_v,
241 float average_depth_of_interaction_v,
242 float ring_spacing_v,
243 float bin_size_v,
244 float intrinsic_tilt_v,
245 int num_axial_blocks_per_bucket_v,
246 int num_transaxial_blocks_per_bucket_v,
247 int num_axial_crystals_per_block_v,
248 int num_transaxial_crystals_per_block_v,
249 int num_axial_crystals_per_singles_unit_v,
250 int num_transaxial_crystals_per_singles_unit_v,
251 int num_detector_layers_v,
252 float energy_resolution_v = -1.0f,
253 float reference_energy_v = -1.0f,
254 short int max_num_of_timing_poss = -1,
255 float size_timing_pos = -1.0f,
256 float timing_resolution = -1.0f,
257 const std::string& scanner_geometry_v = "Cylindrical",
258 float axial_crystal_spacing_v = -1.0f,
259 float transaxial_crystal_spacing_v = -1.0f,
260 float axial_block_spacing_v = -1.0f,
261 float transaxial_block_spacing_v = -1.0f,
262 const std::string& crystal_map_file_name = "");
263
265
268 virtual void set_up();
269
271 std::string parameter_info() const;
273 const std::string& get_name() const;
275 const std::list<std::string>& get_all_names() const;
277 std::string list_names() const;
278
280 bool operator==(const Scanner& scanner) const;
281 inline bool operator!=(const Scanner& scanner) const;
282
284 inline Type get_type() const;
286
289 Succeeded check_consistency() const;
290
292
293
295 inline int get_num_rings() const;
297 inline int get_num_detectors_per_ring() const;
299
307 inline int get_max_num_non_arccorrected_bins() const;
309
314 inline int get_default_num_arccorrected_bins() const;
316
317 inline int get_max_num_views() const;
319 inline float get_inner_ring_radius() const;
321 inline float get_max_FOV_radius() const;
323 inline float get_effective_ring_radius() const;
325 inline float get_average_depth_of_interaction() const;
327 inline float get_ring_spacing() const;
329 inline float get_default_bin_size() const;
331
336 inline float get_intrinsic_azimuthal_tilt() const;
338
339
340 inline int get_num_transaxial_blocks_per_bucket() const;
342 inline int get_num_axial_blocks_per_bucket() const;
344 inline int get_num_axial_crystals_per_block() const;
346 inline int get_num_transaxial_crystals_per_block() const;
348 inline int get_num_transaxial_crystals_per_bucket() const;
350 inline int get_num_axial_crystals_per_bucket() const;
352 inline int get_num_detector_layers() const;
354 inline int get_num_axial_blocks() const;
356 inline int get_num_transaxial_blocks() const;
358 inline int get_num_axial_buckets() const;
360 inline int get_num_transaxial_buckets() const;
361
363 inline int get_num_axial_crystals_per_singles_unit() const;
365 inline int get_num_transaxial_crystals_per_singles_unit() const;
366 // TODO accomodate more complex geometries of singles units.
367 /* inline int get_num_crystal_layers_per_singles_unit() const; */
369 inline int get_num_axial_singles_units() const;
371 inline int get_num_transaxial_singles_units() const;
372 /* inline int get_num_layers_singles_units() const; */
373 inline int get_num_singles_units() const;
375
376 inline int get_max_num_timing_poss() const;
378
382 inline float get_size_of_timing_pos() const;
384
388 inline float get_timing_resolution() const;
390
397 float get_coincidence_window_width_in_ps() const;
399
400 float get_coincidence_window_width_in_mm() const;
401
403
410 int get_num_virtual_axial_crystals_per_block() const;
411 int get_num_virtual_transaxial_crystals_per_block() const;
412 void set_num_virtual_axial_crystals_per_block(int);
413 void set_num_virtual_transaxial_crystals_per_block(int);
415
417
418
420 inline std::string get_scanner_geometry() const;
422 inline float get_axial_crystal_spacing() const;
424 inline float get_transaxial_crystal_spacing() const;
426 inline float get_axial_block_spacing() const;
428 inline float get_transaxial_block_spacing() const;
433 inline float get_axial_length() const;
435
438 inline std::string get_crystal_map_file_name() const;
439
441
443
445
446
448
452 inline float get_energy_resolution() const;
454
455 inline float get_reference_energy() const;
457 inline bool has_energy_information() const;
458
460
462
467 // zlong, 08-04-2004, add set_methods
469 inline void set_type(const Type& new_type);
471 inline void set_num_rings(const int& new_num);
473 inline void set_num_detectors_per_ring(const int& new_num);
475 inline void set_max_num_non_arccorrected_bins(const int& new_num);
477 inline void set_default_num_arccorrected_bins(const int& new_num);
479 inline void set_inner_ring_radius(const float& new_radius);
481 inline void set_average_depth_of_interaction(const float& new_depth_of_interaction);
483 inline void set_ring_spacing(const float& new_spacing);
485 inline void set_default_bin_size(const float& new_size);
487 inline void set_intrinsic_azimuthal_tilt(const float new_tilt);
489
490
491 inline void set_num_transaxial_blocks_per_bucket(const int& new_num);
493 inline void set_num_axial_blocks_per_bucket(const int& new_num);
495 inline void set_num_axial_crystals_per_block(const int& new_num);
497 inline void set_num_transaxial_crystals_per_block(const int& new_num);
499 inline void set_num_detector_layers(const int& new_num);
501 inline void set_num_axial_crystals_per_singles_unit(const int& new_num);
503 inline void set_num_transaxial_crystals_per_singles_unit(const int& new_num);
504 // TODO accomodate more complex geometries of singles units.
506
508
516 void set_scanner_geometry(const std::string& new_scanner_geometry);
518 inline void set_axial_crystal_spacing(const float& new_spacing);
520 inline void set_transaxial_crystal_spacing(const float& new_spacing);
522 inline void set_axial_block_spacing(const float& new_spacing);
524 inline void set_transaxial_block_spacing(const float& new_spacing);
526
527 inline void set_crystal_map_file_name(const std::string& new_crystal_map_file_name);
529
531
533 inline void set_energy_resolution(const float new_num);
535
536 inline void set_reference_energy(const float new_num);
538 inline void set_max_num_timing_poss(int new_num);
540 inline void set_size_of_timing_poss(float new_num);
542 inline void set_timing_resolution(float new_num_in_ps);
544
546
548 inline int get_singles_bin_index(int axial_index, int transaxial_index) const;
549
552 inline int get_singles_bin_index(const DetectionPosition<>& det_pos) const;
553
555 inline int get_axial_singles_unit(int singles_bin_index) const;
556
558 inline int get_transaxial_singles_unit(int singles_bin_index) const;
559
561 inline bool is_tof_ready() const;
562
564 // used in CListRecordSAFIR.inl for accessing the coordinates
565 inline stir::DetectionPosition<> get_det_pos_for_index(const stir::DetectionPosition<>& det_pos) const;
567 // used in ProjInfoDataGenericNoArcCorr.cxx for accessing the coordinates
568 inline stir::CartesianCoordinate3D<float> get_coordinate_for_det_pos(const stir::DetectionPosition<>& det_pos) const;
570 inline stir::CartesianCoordinate3D<float> get_coordinate_for_index(const stir::DetectionPosition<>& det_pos) const;
572 // used in ProjInfoDataGenericNoArcCorr.cxx for accessing the get_bin
573 inline Succeeded find_detection_position_given_cartesian_coordinate(DetectionPosition<>& det_pos,
574 const CartesianCoordinate3D<float>& cart_coord) const;
575
576 shared_ptr<const DetectorCoordinateMap> get_detector_map_sptr() const { return detector_map_sptr; }
577
578private:
579 bool _already_setup;
580 Type type;
581 std::list<std::string> list_of_names;
582 int num_rings; /* number of direct planes */
583 int max_num_non_arccorrected_bins;
584 int default_num_arccorrected_bins; /* default number of bins */
585 int num_detectors_per_ring;
586
587 float inner_ring_radius;
588 float average_depth_of_interaction;
589 float max_FOV_radius;
590 float ring_spacing;
591 float bin_size;
592 float intrinsic_tilt;
593
594 int num_transaxial_blocks_per_bucket; /* transaxial blocks per bucket */
595 int num_axial_blocks_per_bucket; /* axial blocks per bucket */
596 int num_axial_crystals_per_block; /* number of crystals in the axial direction */
597 int num_transaxial_crystals_per_block; /* number of transaxial crystals */
598 int num_detector_layers;
599
600 int num_axial_crystals_per_singles_unit;
601 int num_transaxial_crystals_per_singles_unit;
602
608 float energy_resolution;
611 float reference_energy;
613 float timing_resolution;
615 int max_num_of_timing_poss;
617 float size_timing_pos;
618
623 std::string scanner_geometry;
624 float axial_crystal_spacing;
625 float transaxial_crystal_spacing;
626 float axial_block_spacing;
627 float transaxial_block_spacing;
628
629 std::string crystal_map_file_name;
630 shared_ptr<DetectorCoordinateMap> detector_map_sptr;
631
632 void set_detector_map(const DetectorCoordinateMap::det_pos_to_coord_type& coord_map);
633 void initialise_max_FOV_radius();
634
635 // function to create the maps
636 void read_detectormap_from_file(const std::string& filename);
637
638 // ! set all parameters
639 void set_params(Type type_v,
640 const std::list<std::string>& list_of_names_v,
641 int num_rings_v,
642 int max_num_non_arccorrected_bins_v,
643 int default_num_arccorrected_bins_v,
644 int num_detectors_per_ring_v,
645 float inner_ring_radius_v,
646 float average_depth_of_interaction_v,
647 float ring_spacing_v,
648 float bin_size_v,
649 float intrinsic_tilt_v,
650 int num_axial_blocks_per_bucket_v,
651 int num_transaxial_blocks_per_bucket_v,
652 int num_axial_crystals_per_block_v,
653 int num_transaxial_crystals_per_block_v,
654 int num_axial_crystals_per_singles_unit_v,
655 int num_transaxial_crystals_per_singles_unit_v,
656 int num_detector_layers_v,
657 float energy_resolution_v = -1.0f,
658 float reference_energy = -1.0f,
659 short int max_num_of_timing_poss_v = -1.0f,
660 float size_timing_pos_v = -1.0f,
661 float timing_resolution_v = -1.0f,
662 const std::string& scanner_geometry_v = "",
663 float axial_crystal_spacing_v = -1.0f,
664 float transaxial_crystal_spacing_v = -1.0f,
665 float axial_block_spacing_v = -1.0f,
666 float transaxial_block_spacing_v = -1.0f,
667 const std::string& crystal_map_file_name = "");
668};
669
670END_NAMESPACE_STIR
671
672#include "stir/Scanner.inl"
673
674#endif
defines the stir::CartesianCoordinate3D<coordT> class
Declaration of class stir::DetectionPosition.
Declaration of class stir::DetectorCoordinateMap.
implementation of inline functions of class Scanner
a templated class for 3-dimensional coordinates.
Definition CartesianCoordinate3D.h:53
A class for storing coordinates of a detection.
Definition DetectionPosition.h:61
A class for storing some info on the scanner.
Definition Scanner.h:108
static std::string list_all_names()
get a string listing names for all predefined scanners
Definition Scanner.cxx:2252
static std::list< std::string > get_names_of_predefined_scanners()
get a list with the names for each predefined scanner
Definition Scanner.cxx:2271
Type
enum for all predefined scanners
Definition Scanner.h:141
Scanner(Type scanner_type)
constructor that takes scanner type as an input argument
Definition Scanner.cxx:65
static Scanner * get_scanner_from_name(const std::string &name)
get the scanner pointer from the name
Definition Scanner.cxx:2222
Import of std::shared_ptr, std::dynamic_pointer_cast and std::static_pointer_cast into the stir names...