STIR  6.3.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 
36 #include "stir/DetectionPosition.h"
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 
49 START_NAMESPACE_STIR
50 
51 class Succeeded;
107 class Scanner
108 {
109  friend class BlocksTests;
110 
111 public:
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  RPT,
156  HiDAC,
157  Advance,
158  DiscoveryLS,
159  DiscoveryST,
160  DiscoverySTE,
161  DiscoveryRX,
162  Discovery600,
163  PETMR_Signa,
164  Discovery690,
165  DiscoveryMI3ring,
166  DiscoveryMI4ring,
167  DiscoveryMI5ring,
168  DiscoveryMI6ring,
169  HZLR,
170  RATPET,
171  PANDA,
172  HYPERimage,
173  nanoPET,
174  HRRT,
175  Allegro,
176  GeminiTF,
177  SAFIRDualRingPrototype,
178  UPENN_5rings,
179  UPENN_5rings_no_gaps,
180  UPENN_6rings,
181  UPENN_6rings_no_gaps,
182  User_defined_scanner,
183  Unknown_scanner
184  };
185 
186  virtual ~Scanner() {}
187 
189  Scanner(Type scanner_type);
190 
192 
197  Scanner(Type type_v,
198  const std::list<std::string>& list_of_names_v,
199  int num_detectors_per_ring_v,
200  int num_rings_v,
201  int max_num_non_arccorrected_bins_v,
202  int default_num_arccorrected_bins_v,
203  float inner_ring_radius_v,
204  float average_depth_of_interaction_v,
205  float ring_spacing_v,
206  float bin_size_v,
207  float intrinsic_tilt_v,
208  int num_axial_blocks_per_bucket_v,
209  int num_transaxial_blocks_per_bucket_v,
210  int num_axial_crystals_per_block_v,
211  int num_transaxial_crystals_per_block_v,
212  int num_axial_crystals_per_singles_unit_v,
213  int num_transaxial_crystals_per_singles_unit_v,
214  int num_detector_layers_v,
215  float energy_resolution_v = -1.0f,
216  float reference_energy_v = -1.0f,
217  short int max_num_of_timing_poss = -1,
218  float size_timing_pos = -1.0f,
219  float timing_resolution = -1.0f,
220  const std::string& scanner_geometry_v = "Cylindrical",
221  float axial_crystal_spacing_v = -1.0f,
222  float transaxial_crystal_spacing_v = -1.0f,
223  float axial_block_spacing_v = -1.0f,
224  float transaxial_block_spacing_v = -1.0f,
225  const std::string& crystal_map_file_name = "");
226 
228 
233  Scanner(Type type_v,
234  const std::string& name,
235  int num_detectors_per_ring_v,
236  int num_rings_v,
237  int max_num_non_arccorrected_bins_v,
238  int default_num_arccorrected_bins_v,
239  float inner_ring_radius_v,
240  float average_depth_of_interaction_v,
241  float ring_spacing_v,
242  float bin_size_v,
243  float intrinsic_tilt_v,
244  int num_axial_blocks_per_bucket_v,
245  int num_transaxial_blocks_per_bucket_v,
246  int num_axial_crystals_per_block_v,
247  int num_transaxial_crystals_per_block_v,
248  int num_axial_crystals_per_singles_unit_v,
249  int num_transaxial_crystals_per_singles_unit_v,
250  int num_detector_layers_v,
251  float energy_resolution_v = -1.0f,
252  float reference_energy_v = -1.0f,
253  short int max_num_of_timing_poss = -1,
254  float size_timing_pos = -1.0f,
255  float timing_resolution = -1.0f,
256  const std::string& scanner_geometry_v = "Cylindrical",
257  float axial_crystal_spacing_v = -1.0f,
258  float transaxial_crystal_spacing_v = -1.0f,
259  float axial_block_spacing_v = -1.0f,
260  float transaxial_block_spacing_v = -1.0f,
261  const std::string& crystal_map_file_name = "");
262 
264 
267  virtual void set_up();
268 
270  std::string parameter_info() const;
272  const std::string& get_name() const;
274  const std::list<std::string>& get_all_names() const;
276  std::string list_names() const;
277 
279  bool operator==(const Scanner& scanner) const;
280  inline bool operator!=(const Scanner& scanner) const;
281 
283  inline Type get_type() const;
285 
288  Succeeded check_consistency() const;
289 
291 
292 
294  inline int get_num_rings() const;
296  inline int get_num_detectors_per_ring() const;
298 
306  inline int get_max_num_non_arccorrected_bins() const;
308 
313  inline int get_default_num_arccorrected_bins() const;
315 
316  inline int get_max_num_views() const;
318  inline float get_inner_ring_radius() const;
320  inline float get_max_FOV_radius() const;
322  inline float get_effective_ring_radius() const;
324  inline float get_average_depth_of_interaction() const;
326  inline float get_ring_spacing() const;
328  inline float get_default_bin_size() const;
330 
335  inline float get_intrinsic_azimuthal_tilt() const;
337 
338  inline int get_num_transaxial_blocks_per_bucket() const;
341  inline int get_num_axial_blocks_per_bucket() const;
343  inline int get_num_axial_crystals_per_block() const;
345  inline int get_num_transaxial_crystals_per_block() const;
347  inline int get_num_transaxial_crystals_per_bucket() const;
349  inline int get_num_axial_crystals_per_bucket() const;
351  inline int get_num_detector_layers() const;
353  inline int get_num_axial_blocks() const;
355  inline int get_num_transaxial_blocks() const;
357  inline int get_num_axial_buckets() const;
359  inline int get_num_transaxial_buckets() const;
360 
362  inline int get_num_axial_crystals_per_singles_unit() const;
364  inline int get_num_transaxial_crystals_per_singles_unit() const;
365  // TODO accomodate more complex geometries of singles units.
366  /* inline int get_num_crystal_layers_per_singles_unit() const; */
368  inline int get_num_axial_singles_units() const;
370  inline int get_num_transaxial_singles_units() const;
371  /* inline int get_num_layers_singles_units() const; */
372  inline int get_num_singles_units() const;
374 
375  inline int get_max_num_timing_poss() const;
377 
381  inline float get_size_of_timing_pos() const;
383 
387  inline float get_timing_resolution() const;
389 
396  float get_coincidence_window_width_in_ps() const;
398 
399  float get_coincidence_window_width_in_mm() const;
400 
402 
408 
409  int get_num_virtual_axial_crystals_per_block() const;
410  int get_num_virtual_transaxial_crystals_per_block() const;
411  void set_num_virtual_axial_crystals_per_block(int);
412  void set_num_virtual_transaxial_crystals_per_block(int);
414 
416 
417 
419  inline std::string get_scanner_geometry() const;
421  inline float get_axial_crystal_spacing() const;
423  inline float get_transaxial_crystal_spacing() const;
425  inline float get_axial_block_spacing() const;
427  inline float get_transaxial_block_spacing() const;
432  inline float get_axial_length() const;
434 
437  inline std::string get_crystal_map_file_name() const;
438 
440 
442 
444 
445 
447 
451  inline float get_energy_resolution() const;
453 
454  inline float get_reference_energy() const;
456  inline bool has_energy_information() const;
457 
459 
461 
466  // zlong, 08-04-2004, add set_methods
468  inline void set_type(const Type& new_type);
470  inline void set_num_rings(const int& new_num);
472  inline void set_num_detectors_per_ring(const int& new_num);
474  inline void set_max_num_non_arccorrected_bins(const int& new_num);
476  inline void set_default_num_arccorrected_bins(const int& new_num);
478  inline void set_inner_ring_radius(const float& new_radius);
480  inline void set_average_depth_of_interaction(const float& new_depth_of_interaction);
482  inline void set_ring_spacing(const float& new_spacing);
484  inline void set_default_bin_size(const float& new_size);
486  inline void set_intrinsic_azimuthal_tilt(const float new_tilt);
488 
489  inline void set_num_transaxial_blocks_per_bucket(const int& new_num);
492  inline void set_num_axial_blocks_per_bucket(const int& new_num);
494  inline void set_num_axial_crystals_per_block(const int& new_num);
496  inline void set_num_transaxial_crystals_per_block(const int& new_num);
498  inline void set_num_detector_layers(const int& new_num);
500  inline void set_num_axial_crystals_per_singles_unit(const int& new_num);
502  inline void set_num_transaxial_crystals_per_singles_unit(const int& new_num);
503  // TODO accomodate more complex geometries of singles units.
505 
515  void set_scanner_geometry(const std::string& new_scanner_geometry);
517  inline void set_axial_crystal_spacing(const float& new_spacing);
519  inline void set_transaxial_crystal_spacing(const float& new_spacing);
521  inline void set_axial_block_spacing(const float& new_spacing);
523  inline void set_transaxial_block_spacing(const float& new_spacing);
525 
526  inline void set_crystal_map_file_name(const std::string& new_crystal_map_file_name);
528 
530 
532  inline void set_energy_resolution(const float new_num);
534 
535  inline void set_reference_energy(const float new_num);
537  inline void set_max_num_timing_poss(int new_num);
539  inline void set_size_of_timing_poss(float new_num);
541  inline void set_timing_resolution(float new_num_in_ps);
543 
545 
547  inline int get_singles_bin_index(int axial_index, int transaxial_index) const;
548 
551  inline int get_singles_bin_index(const DetectionPosition<>& det_pos) const;
552 
554  inline int get_axial_singles_unit(int singles_bin_index) const;
555 
557  inline int get_transaxial_singles_unit(int singles_bin_index) const;
558 
560  inline bool is_tof_ready() const;
561 
563  // used in CListRecordSAFIR.inl for accessing the coordinates
564  inline stir::DetectionPosition<> get_det_pos_for_index(const stir::DetectionPosition<>& det_pos) const;
566  // used in ProjInfoDataGenericNoArcCorr.cxx for accessing the coordinates
567  inline stir::CartesianCoordinate3D<float> get_coordinate_for_det_pos(const stir::DetectionPosition<>& det_pos) const;
569  inline stir::CartesianCoordinate3D<float> get_coordinate_for_index(const stir::DetectionPosition<>& det_pos) const;
571  // used in ProjInfoDataGenericNoArcCorr.cxx for accessing the get_bin
572  inline Succeeded find_detection_position_given_cartesian_coordinate(DetectionPosition<>& det_pos,
573  const CartesianCoordinate3D<float>& cart_coord) const;
574 
575  shared_ptr<const DetectorCoordinateMap> get_detector_map_sptr() const { return detector_map_sptr; }
576 
577 private:
578  bool _already_setup;
579  Type type;
580  std::list<std::string> list_of_names;
581  int num_rings; /* number of direct planes */
582  int max_num_non_arccorrected_bins;
583  int default_num_arccorrected_bins; /* default number of bins */
584  int num_detectors_per_ring;
585 
586  float inner_ring_radius;
587  float average_depth_of_interaction;
588  float max_FOV_radius;
589  float ring_spacing;
590  float bin_size;
591  float intrinsic_tilt;
593  int num_transaxial_blocks_per_bucket; /* transaxial blocks per bucket */
594  int num_axial_blocks_per_bucket; /* axial blocks per bucket */
595  int num_axial_crystals_per_block; /* number of crystals in the axial direction */
596  int num_transaxial_crystals_per_block; /* number of transaxial crystals */
597  int num_detector_layers;
598 
599  int num_axial_crystals_per_singles_unit;
600  int num_transaxial_crystals_per_singles_unit;
601 
607  float energy_resolution;
610  float reference_energy;
612  float timing_resolution;
614  int max_num_of_timing_poss;
616  float size_timing_pos;
617 
622  std::string scanner_geometry;
623  float axial_crystal_spacing;
624  float transaxial_crystal_spacing;
625  float axial_block_spacing;
626  float transaxial_block_spacing;
628  std::string crystal_map_file_name;
629  shared_ptr<DetectorCoordinateMap> detector_map_sptr;
631  void set_detector_map(const DetectorCoordinateMap::det_pos_to_coord_type& coord_map);
632  void initialise_max_FOV_radius();
633 
634  // function to create the maps
635  void read_detectormap_from_file(const std::string& filename);
636 
637  // ! set all parameters
638  void set_params(Type type_v,
639  const std::list<std::string>& list_of_names_v,
640  int num_rings_v,
641  int max_num_non_arccorrected_bins_v,
642  int default_num_arccorrected_bins_v,
643  int num_detectors_per_ring_v,
644  float inner_ring_radius_v,
645  float average_depth_of_interaction_v,
646  float ring_spacing_v,
647  float bin_size_v,
648  float intrinsic_tilt_v,
649  int num_axial_blocks_per_bucket_v,
650  int num_transaxial_blocks_per_bucket_v,
651  int num_axial_crystals_per_block_v,
652  int num_transaxial_crystals_per_block_v,
653  int num_axial_crystals_per_singles_unit_v,
654  int num_transaxial_crystals_per_singles_unit_v,
655  int num_detector_layers_v,
656  float energy_resolution_v = -1.0f,
657  float reference_energy = -1.0f,
658  short int max_num_of_timing_poss_v = -1.0f,
659  float size_timing_pos_v = -1.0f,
660  float timing_resolution_v = -1.0f,
661  const std::string& scanner_geometry_v = "",
662  float axial_crystal_spacing_v = -1.0f,
663  float transaxial_crystal_spacing_v = -1.0f,
664  float axial_block_spacing_v = -1.0f,
665  float transaxial_block_spacing_v = -1.0f,
666  const std::string& crystal_map_file_name = "");
667 };
668 
669 END_NAMESPACE_STIR
670 
671 #include "stir/Scanner.inl"
672 
673 #endif
implementation of inline functions of class Scanner
Type
enum for all predefined scanners
Definition: Scanner.h:140
Import of std::shared_ptr, std::dynamic_pointer_cast and std::static_pointer_cast into the stir names...
Test class for Blocks.
Definition: test_blocks_on_cylindrical_projectors.cxx:65
A class for storing some info on the scanner.
Definition: Scanner.h:107
Declaration of class stir::DetectorCoordinateMap.
Declaration of class stir::DetectionPosition.
a class containing an enumeration type that can be used by functions to signal successful operation o...
Definition: Succeeded.h:43
defines the stir::CartesianCoordinate3D<coordT> class