STIR  6.2.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  HZLR,
169  RATPET,
170  PANDA,
171  HYPERimage,
172  nanoPET,
173  HRRT,
174  Allegro,
175  GeminiTF,
176  SAFIRDualRingPrototype,
177  UPENN_5rings,
178  UPENN_5rings_no_gaps,
179  UPENN_6rings,
180  UPENN_6rings_no_gaps,
181  User_defined_scanner,
182  Unknown_scanner
183  };
184 
185  virtual ~Scanner() {}
186 
188  Scanner(Type scanner_type);
189 
191 
196  Scanner(Type type_v,
197  const std::list<std::string>& list_of_names_v,
198  int num_detectors_per_ring_v,
199  int num_rings_v,
200  int max_num_non_arccorrected_bins_v,
201  int default_num_arccorrected_bins_v,
202  float inner_ring_radius_v,
203  float average_depth_of_interaction_v,
204  float ring_spacing_v,
205  float bin_size_v,
206  float intrinsic_tilt_v,
207  int num_axial_blocks_per_bucket_v,
208  int num_transaxial_blocks_per_bucket_v,
209  int num_axial_crystals_per_block_v,
210  int num_transaxial_crystals_per_block_v,
211  int num_axial_crystals_per_singles_unit_v,
212  int num_transaxial_crystals_per_singles_unit_v,
213  int num_detector_layers_v,
214  float energy_resolution_v = -1.0f,
215  float reference_energy_v = -1.0f,
216  short int max_num_of_timing_poss = -1,
217  float size_timing_pos = -1.0f,
218  float timing_resolution = -1.0f,
219  const std::string& scanner_geometry_v = "Cylindrical",
220  float axial_crystal_spacing_v = -1.0f,
221  float transaxial_crystal_spacing_v = -1.0f,
222  float axial_block_spacing_v = -1.0f,
223  float transaxial_block_spacing_v = -1.0f,
224  const std::string& crystal_map_file_name = "");
225 
227 
232  Scanner(Type type_v,
233  const std::string& name,
234  int num_detectors_per_ring_v,
235  int num_rings_v,
236  int max_num_non_arccorrected_bins_v,
237  int default_num_arccorrected_bins_v,
238  float inner_ring_radius_v,
239  float average_depth_of_interaction_v,
240  float ring_spacing_v,
241  float bin_size_v,
242  float intrinsic_tilt_v,
243  int num_axial_blocks_per_bucket_v,
244  int num_transaxial_blocks_per_bucket_v,
245  int num_axial_crystals_per_block_v,
246  int num_transaxial_crystals_per_block_v,
247  int num_axial_crystals_per_singles_unit_v,
248  int num_transaxial_crystals_per_singles_unit_v,
249  int num_detector_layers_v,
250  float energy_resolution_v = -1.0f,
251  float reference_energy_v = -1.0f,
252  short int max_num_of_timing_poss = -1,
253  float size_timing_pos = -1.0f,
254  float timing_resolution = -1.0f,
255  const std::string& scanner_geometry_v = "Cylindrical",
256  float axial_crystal_spacing_v = -1.0f,
257  float transaxial_crystal_spacing_v = -1.0f,
258  float axial_block_spacing_v = -1.0f,
259  float transaxial_block_spacing_v = -1.0f,
260  const std::string& crystal_map_file_name = "");
261 
263 
266  virtual void set_up();
267 
269  std::string parameter_info() const;
271  const std::string& get_name() const;
273  const std::list<std::string>& get_all_names() const;
275  std::string list_names() const;
276 
278  bool operator==(const Scanner& scanner) const;
279  inline bool operator!=(const Scanner& scanner) const;
280 
282  inline Type get_type() const;
284 
287  Succeeded check_consistency() const;
288 
290 
291 
293  inline int get_num_rings() const;
295  inline int get_num_detectors_per_ring() const;
297 
305  inline int get_max_num_non_arccorrected_bins() const;
307 
312  inline int get_default_num_arccorrected_bins() const;
314 
315  inline int get_max_num_views() const;
317  inline float get_inner_ring_radius() const;
319  inline float get_max_FOV_radius() const;
321  inline float get_effective_ring_radius() const;
323  inline float get_average_depth_of_interaction() const;
325  inline float get_ring_spacing() const;
327  inline float get_default_bin_size() const;
329 
334  inline float get_intrinsic_azimuthal_tilt() const;
336 
337  inline int get_num_transaxial_blocks_per_bucket() const;
340  inline int get_num_axial_blocks_per_bucket() const;
342  inline int get_num_axial_crystals_per_block() const;
344  inline int get_num_transaxial_crystals_per_block() const;
346  inline int get_num_transaxial_crystals_per_bucket() const;
348  inline int get_num_axial_crystals_per_bucket() const;
350  inline int get_num_detector_layers() const;
352  inline int get_num_axial_blocks() const;
354  inline int get_num_transaxial_blocks() const;
356  inline int get_num_axial_buckets() const;
358  inline int get_num_transaxial_buckets() const;
359 
361  inline int get_num_axial_crystals_per_singles_unit() const;
363  inline int get_num_transaxial_crystals_per_singles_unit() const;
364  // TODO accomodate more complex geometries of singles units.
365  /* inline int get_num_crystal_layers_per_singles_unit() const; */
367  inline int get_num_axial_singles_units() const;
369  inline int get_num_transaxial_singles_units() const;
370  /* inline int get_num_layers_singles_units() const; */
371  inline int get_num_singles_units() const;
373 
374  inline int get_max_num_timing_poss() const;
376 
380  inline float get_size_of_timing_pos() const;
382 
386  inline float get_timing_resolution() const;
388 
395  float get_coincidence_window_width_in_ps() const;
397 
398  float get_coincidence_window_width_in_mm() const;
399 
401 
407 
408  int get_num_virtual_axial_crystals_per_block() const;
409  int get_num_virtual_transaxial_crystals_per_block() const;
410  void set_num_virtual_axial_crystals_per_block(int);
411  void set_num_virtual_transaxial_crystals_per_block(int);
413 
415 
416 
418  inline std::string get_scanner_geometry() const;
420  inline float get_axial_crystal_spacing() const;
422  inline float get_transaxial_crystal_spacing() const;
424  inline float get_axial_block_spacing() const;
426  inline float get_transaxial_block_spacing() const;
430  inline float get_axial_length() const;
432 
435  inline std::string get_crystal_map_file_name() const;
436 
438 
440 
442 
443 
445 
449  inline float get_energy_resolution() const;
451 
452  inline float get_reference_energy() const;
454  inline bool has_energy_information() const;
455 
457 
459 
464  // zlong, 08-04-2004, add set_methods
466  inline void set_type(const Type& new_type);
468  inline void set_num_rings(const int& new_num);
470  inline void set_num_detectors_per_ring(const int& new_num);
472  inline void set_max_num_non_arccorrected_bins(const int& new_num);
474  inline void set_default_num_arccorrected_bins(const int& new_num);
476  inline void set_inner_ring_radius(const float& new_radius);
478  inline void set_average_depth_of_interaction(const float& new_depth_of_interaction);
480  inline void set_ring_spacing(const float& new_spacing);
482  inline void set_default_bin_size(const float& new_size);
484  inline void set_intrinsic_azimuthal_tilt(const float new_tilt);
486 
487  inline void set_num_transaxial_blocks_per_bucket(const int& new_num);
490  inline void set_num_axial_blocks_per_bucket(const int& new_num);
492  inline void set_num_axial_crystals_per_block(const int& new_num);
494  inline void set_num_transaxial_crystals_per_block(const int& new_num);
496  inline void set_num_detector_layers(const int& new_num);
498  inline void set_num_axial_crystals_per_singles_unit(const int& new_num);
500  inline void set_num_transaxial_crystals_per_singles_unit(const int& new_num);
501  // TODO accomodate more complex geometries of singles units.
503 
513  void set_scanner_geometry(const std::string& new_scanner_geometry);
515  inline void set_axial_crystal_spacing(const float& new_spacing);
517  inline void set_transaxial_crystal_spacing(const float& new_spacing);
519  inline void set_axial_block_spacing(const float& new_spacing);
521  inline void set_transaxial_block_spacing(const float& new_spacing);
523 
524  inline void set_crystal_map_file_name(const std::string& new_crystal_map_file_name);
526 
528 
530  inline void set_energy_resolution(const float new_num);
532 
533  inline void set_reference_energy(const float new_num);
535  inline void set_max_num_timing_poss(int new_num);
537  inline void set_size_of_timing_poss(float new_num);
539  inline void set_timing_resolution(float new_num_in_ps);
541 
543 
545  inline int get_singles_bin_index(int axial_index, int transaxial_index) const;
546 
549  inline int get_singles_bin_index(const DetectionPosition<>& det_pos) const;
550 
552  inline int get_axial_singles_unit(int singles_bin_index) const;
553 
555  inline int get_transaxial_singles_unit(int singles_bin_index) const;
556 
558  inline bool is_tof_ready() const;
559 
561  // used in CListRecordSAFIR.inl for accessing the coordinates
562  inline stir::DetectionPosition<> get_det_pos_for_index(const stir::DetectionPosition<>& det_pos) const;
564  // used in ProjInfoDataGenericNoArcCorr.cxx for accessing the coordinates
565  inline stir::CartesianCoordinate3D<float> get_coordinate_for_det_pos(const stir::DetectionPosition<>& det_pos) const;
567  inline stir::CartesianCoordinate3D<float> get_coordinate_for_index(const stir::DetectionPosition<>& det_pos) const;
569  // used in ProjInfoDataGenericNoArcCorr.cxx for accessing the get_bin
570  inline Succeeded find_detection_position_given_cartesian_coordinate(DetectionPosition<>& det_pos,
571  const CartesianCoordinate3D<float>& cart_coord) const;
572 
573  shared_ptr<const DetectorCoordinateMap> get_detector_map_sptr() const { return detector_map_sptr; }
574 
575 private:
576  bool _already_setup;
577  Type type;
578  std::list<std::string> list_of_names;
579  int num_rings; /* number of direct planes */
580  int max_num_non_arccorrected_bins;
581  int default_num_arccorrected_bins; /* default number of bins */
582  int num_detectors_per_ring;
583 
584  float inner_ring_radius;
585  float average_depth_of_interaction;
586  float max_FOV_radius;
587  float ring_spacing;
588  float bin_size;
589  float intrinsic_tilt;
591  int num_transaxial_blocks_per_bucket; /* transaxial blocks per bucket */
592  int num_axial_blocks_per_bucket; /* axial blocks per bucket */
593  int num_axial_crystals_per_block; /* number of crystals in the axial direction */
594  int num_transaxial_crystals_per_block; /* number of transaxial crystals */
595  int num_detector_layers;
596 
597  int num_axial_crystals_per_singles_unit;
598  int num_transaxial_crystals_per_singles_unit;
599 
605  float energy_resolution;
608  float reference_energy;
610  float timing_resolution;
612  int max_num_of_timing_poss;
614  float size_timing_pos;
615 
620  std::string scanner_geometry;
621  float axial_crystal_spacing;
622  float transaxial_crystal_spacing;
623  float axial_block_spacing;
624  float transaxial_block_spacing;
626  std::string crystal_map_file_name;
627  shared_ptr<DetectorCoordinateMap> detector_map_sptr;
629  void set_detector_map(const DetectorCoordinateMap::det_pos_to_coord_type& coord_map);
630  void initialise_max_FOV_radius();
631 
632  // function to create the maps
633  void read_detectormap_from_file(const std::string& filename);
634 
635  // ! set all parameters
636  void set_params(Type type_v,
637  const std::list<std::string>& list_of_names_v,
638  int num_rings_v,
639  int max_num_non_arccorrected_bins_v,
640  int default_num_arccorrected_bins_v,
641  int num_detectors_per_ring_v,
642  float inner_ring_radius_v,
643  float average_depth_of_interaction_v,
644  float ring_spacing_v,
645  float bin_size_v,
646  float intrinsic_tilt_v,
647  int num_axial_blocks_per_bucket_v,
648  int num_transaxial_blocks_per_bucket_v,
649  int num_axial_crystals_per_block_v,
650  int num_transaxial_crystals_per_block_v,
651  int num_axial_crystals_per_singles_unit_v,
652  int num_transaxial_crystals_per_singles_unit_v,
653  int num_detector_layers_v,
654  float energy_resolution_v = -1.0f,
655  float reference_energy = -1.0f,
656  short int max_num_of_timing_poss_v = -1.0f,
657  float size_timing_pos_v = -1.0f,
658  float timing_resolution_v = -1.0f,
659  const std::string& scanner_geometry_v = "",
660  float axial_crystal_spacing_v = -1.0f,
661  float transaxial_crystal_spacing_v = -1.0f,
662  float axial_block_spacing_v = -1.0f,
663  float transaxial_block_spacing_v = -1.0f,
664  const std::string& crystal_map_file_name = "");
665 };
666 
667 END_NAMESPACE_STIR
668 
669 #include "stir/Scanner.inl"
670 
671 #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 (or corresponding b...
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