CASToR  3.1
Tomographic Reconstruction (PET/SPECT/CT)
sScannerManager.cc
Go to the documentation of this file.
1 /*
2 This file is part of CASToR.
3 
4  CASToR is free software: you can redistribute it and/or modify it under the
5  terms of the GNU General Public License as published by the Free Software
6  Foundation, either version 3 of the License, or (at your option) any later
7  version.
8 
9  CASToR is distributed in the hope that it will be useful, but WITHOUT ANY
10  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12  details.
13 
14  You should have received a copy of the GNU General Public License along with
15  CASToR (in file GNU_GPL.TXT). If not, see <http://www.gnu.org/licenses/>.
16 
17 Copyright 2017-2020 all CASToR contributors listed below:
18 
19  --> Didier BENOIT, Claude COMTAT, Marina FILIPOVIC, Thibaut MERLIN, Mael MILLARDET, Simon STUTE, Valentin VIELZEUF, Zacharias CHALAMPALAKIS
20 
21 This is CASToR version 3.1.
22 */
23 
30 #include "sScannerManager.hh"
31 #include "sAddonManager.hh"
32 
33 // Singleton : set pointer to object to NULL
35 
36 // =====================================================================
37 // ---------------------------------------------------------------------
38 // ---------------------------------------------------------------------
39 // =====================================================================
40 /*
41  \brief sScannerManager constructor.
42  \details It is private at this class is singleton.
43  This class should be instanciated using the GetInstance() function
44  Initialize the member variables to their default values.
45 */
47 {
48  mp_Scanner = NULL;
49  mp_ID = NULL;
50  m_verbose = -1;
52  m_scannerName = "";
53  m_hasUserScannerFile = false;
55  m_allParametersChecked = false;
56  m_saveLUTFlag = false;
57 }
58 
59 // =====================================================================
60 // ---------------------------------------------------------------------
61 // ---------------------------------------------------------------------
62 // =====================================================================
63 /*
64  \brief sScannerManager destructor.
65 */
67 {
68  if (mp_Scanner != NULL) delete mp_Scanner;
69 }
70 
71 // =====================================================================
72 // ---------------------------------------------------------------------
73 // ---------------------------------------------------------------------
74 // =====================================================================
75 /*
76  \fn CheckParameters
77  \brief Check if all parameters have been correctly initialized, and call the CheckParameters function of the scanner object
78  \return 0 if success. Positive value otherwise
79 */
81 {
83  // Check mandatory parameters
84  if (mp_Scanner == NULL)
85  {
86  Cerr("***** sScannerManager::CheckParameters() -> Scanner object not initialized !" << endl);
87  return 1;
88  }
90  {
91  Cerr("***** sScannerManager::CheckParameters() -> Scanner file type (generic or user provided) not initialized !" << endl);
92  return 1;
93  }
94  if (m_scannerName.empty())
95  {
96  Cerr("***** sScannerManager::CheckParameters() -> Scanner name not initialized" << endl);
97  return 1;
98  }
99  if (m_pathToScannerFile.empty())
100  {
101  Cerr("***** sScannerManager::CheckParameters() -> Path to scanner file not initialized !" << endl);
102  return 1;
103  }
104  if (m_verbose<0)
105  {
106  Cerr("***** sScannerManager::CheckParameters() -> Verbosity level not initialized !" << endl);
107  return 1;
108  }
109  // Check parameters of the scanner object
111  {
112  Cerr("***** sScannerManager::CheckParameters() -> A problem occurred while checking Scanner Object parameters !" << endl);
113  return 1;
114  }
115  // All parameters are checked
116  m_allParametersChecked = true;
117  // End
118  return 0;
119 }
120 
121 
122 
123 // =====================================================================
124 // ---------------------------------------------------------------------
125 // ---------------------------------------------------------------------
126 // =====================================================================
132 {
134 
135  if (mp_Scanner == NULL)
136  {
137  Cerr("***** WARNING: sScannerManager::Describe() -> Trying to describe the scanner object while it is not initialized !" << endl);
138  }
139  else
140  {
141  Cout(endl << "---------------------------------------------------------------------------" << endl);
142  Cout("sScannerManager::Describe() -> Here is some generic content of the scanner:" << endl);
143  Cout(" --> Scanner name: " << m_scannerName << endl);
144  Cout(" --> Scanner file: " << m_pathToScannerFile << endl);
145  mp_Scanner->Describe();
146  }
147 }
148 
149 
150 
151 
152 // =====================================================================
153 // ---------------------------------------------------------------------
154 // ---------------------------------------------------------------------
155 // =====================================================================
156 /*
157  \fn Initialize
158  \brief Initialization :
159  - check if all parameters of the manager have been checked
160  - call the initialization function of the scanner object
161  \return 0 if success. Positive value otherwise
162 */
164 {
166  // Parameters checked ?
168  {
169  Cerr("***** sScannerManager::Initialize() -> Parameters have not been checked !" << endl);
170  return 1;
171  }
172  // Verbose
173  if (m_verbose>=VERBOSE_LIGHT) Cout("sScannerManager::Initialize() -> From scanner " << m_scannerName << endl);
174  // Initialize the scanner object
175  if (mp_Scanner->Initialize())
176  {
177  Cerr("***** sScannerManager::Initialize() -> A problem occurred while initializing Scanner Object !" << endl);
178  return 1;
179  }
180  // End
181  return 0;
182 }
183 
184 // =====================================================================
185 // ---------------------------------------------------------------------
186 // ---------------------------------------------------------------------
187 // =====================================================================
188 /*
189  \fn ShowScannersDescription
190  \brief Get the description associated to the different scanners and print all on screen.
191  Walk through the scanner repository and look for the keyword "description" in .geom file and .hscan file.
192  \return 0 if success, positive value otherwise
193  \todo Check everything output correctly for all implemented scanners
194 */
196 {
198 
199  // Return when using MPI and mpi_rank is not 0
200  #ifdef CASTOR_MPI
201  int mpi_rank = 0;
202  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
203  if (mpi_rank!=0) return 0;
204  #endif
205 
206  // Verbose
207  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::ShowScannersDescription ..."<< endl);
208 
209  // Gather all the available scanner from the repository
210  vector<string> list_scanner_names;
211  if (GetAvailableScanners(&list_scanner_names))
212  {
213  Cerr("***** sScannerManager::ShowScannersDescription() -> A problem occurred while recovering scanner names from the scanner repository !" << endl);
214  return 1;
215  }
216 
217  // Print-out descriptions
218  cout << endl << "Here is the list of all available scanners in the repository along with their options:" << endl << endl;
219  for (unsigned int iter = 0; iter!=list_scanner_names.size(); iter++)
220  {
221  // Get the actual scanner in temporary local variable
222  string scanner_file = sOutputManager::GetInstance()->GetPathToConfigDir() + "scanner" + OS_SEP;
223  // Print out the name of this scanner
224  cout << "------------------------------------------------------------------" << endl;
225  cout << "----- \"" << list_scanner_names[iter] << "\"" << endl;
226  cout << "------------------------------------------------------------------" << endl;
227  // Proceed
228  scanner_file.append(list_scanner_names[iter]);
229  // Look for the "description" keyword in the .geom or .hscan file
230  string description;
231  ReadDataASCIIFile(scanner_file, "description", &description, 1, 1);
232  // Print out description
233  cout << description << endl << endl;
234  }
235  return 0;
236 }
237 
238 // =====================================================================
239 // ---------------------------------------------------------------------
240 // ---------------------------------------------------------------------
241 // =====================================================================
242 /*
243  \fn FindScannerSystem
244  \param a_scannerName : string containing name of the required scanner
245  \brief Look for a file matching with the scanner name in parameter inside the scanner repository
246  \return 0 if success (scanner found). Positive value otherwise
247 */
248 int sScannerManager::FindScannerSystem(string a_scannerName)
249 {
251 
252  // Check emptiness
253  if (a_scannerName.empty())
254  {
255  Cerr("***** sScannerManager::FindScannerSystem() -> scanner name is empty !" << endl);
256  return 1;
257  }
258 
259  // Verbose
260  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::FindScannerSystem() -> Search for scanner " << a_scannerName << " in the configuration directory" << endl);
261 
262  // Get the list of scanner from the repository
263  vector<string> repository_scanner_names;
264  if (GetAvailableScanners(&repository_scanner_names))
265  {
266  Cerr("***** sScannerManager::FindScannerSystem() -> A problem occurred while recovering scanner names from the scanner repository !" << endl);
267  return 1;
268  }
269 
270  // Set the scanner name
271  m_scannerName = a_scannerName;
273 
274  // String to recover generic/user-made scanner file
275  string generic_scanner_file, user_scanner_file;
276 
277  // Loop over the scanner available in the repository, and check if the scanner name match with any of these
278  for (unsigned int index_name=0 ; index_name<repository_scanner_names.size() ; index_name++)
279  {
280  string gfile = a_scannerName;
281  string ufile = a_scannerName;
282  // Check if the scanner match a geom file (generic_scanner_file)
283  if (gfile.append(".geom") == repository_scanner_names[index_name])
284  {
285  generic_scanner_file = a_scannerName;
286  generic_scanner_file.append(".geom");
288  if (m_verbose>=VERBOSE_DETAIL) Cout(" --> Matched generic file for the scanner system: " << repository_scanner_names[index_name] << endl);
289  }
290  // Check if the scanner match an user file (user provided LUT)
291  if (ufile.append(".hscan") == repository_scanner_names[index_name])
292  {
293  user_scanner_file = a_scannerName;
294  user_scanner_file.append(".hscan");
295  m_hasUserScannerFile = true;
296  if (m_verbose>=VERBOSE_DETAIL) Cout(" --> matched custom LUT for the scanner system: " << repository_scanner_names[index_name] << endl);
297  }
298  }
299 
300  // When both a generic file and user-provided LUT exist for this system, the generic file is selected by default
302  {
304  {
305  Cerr("***** WARNING sScannerManager::FindScannerSystem() -> Both a generic file and user-provided LUT have been detected for the " << a_scannerName << " system." << endl);
306  Cerr(" The generic file (*.geom) will be selected by default." << endl);
307  }
308  m_hasUserScannerFile = false;
309  }
310 
311  // Initialize m_pathToScannerFile member variable
312  if (m_hasGenericScannerFile) m_pathToScannerFile.append(generic_scanner_file.c_str());
313  else if (m_hasUserScannerFile) m_pathToScannerFile.append(user_scanner_file.c_str());
314  // Unknown scanner, output scanner description and throw error
315  else
316  {
317  Cerr("***** sScannerManager::FindScannerSystem() -> Scanner '"<< a_scannerName <<
318  "' is not known in the scanner repository. Please provide a LUT/generic file for this scanner in the scanner repository in: " <<
319  sOutputManager::GetInstance()->GetPathToConfigDir() << "scanner" << OS_SEP << endl << endl;);
321  return 1;
322  }
323  // End
324  return 0;
325 }
326 
327 
328 
329 
330 // =====================================================================
331 // ---------------------------------------------------------------------
332 // ---------------------------------------------------------------------
333 // =====================================================================
334 /*
335  \fn int sScannerManager::InitScannerWithFile()
336  \param a_pathScanFile : string containing the path to the scanner file
337  \param a_scannerName : string containing the name of the required scanner
338  \param a_fileTypeFlag : string containing the type of the scanner file (0=lut, 1=geom)
339  \brief Initialize member variables (file path, file type, and scanner name) with the provided arguments
340  \return 0 if success (scanner found). Positive value otherwise
341 */
342 int sScannerManager::InitScannerWithFile(string a_pathScanFile, string a_scannerName, int a_fileTypeFlag)
343 {
345  // Verbose
346  if (m_verbose>=VERBOSE_NORMAL) Cout("sScannerManager::InitScannerWithFile()" << endl);
347 
348  // Set the scanner name
349  m_scannerName = a_scannerName;
350  m_pathToScannerFile = a_pathScanFile;
351 
352  if( a_fileTypeFlag == 0 )
353  m_hasUserScannerFile = true;
354  else if ( a_fileTypeFlag == 1 )
356  else
357  {
358  Cerr("***** sScannerManager::InitScannerWithFile() -> Error : File type provided in argument must be == 0 (lut) or == 1 (geom). Current value is '" << a_fileTypeFlag << " !" << endl);
359  return 1;
360  }
361 
362  // End
363  return 0;
364 }
365 
366 // =====================================================================
367 // ---------------------------------------------------------------------
368 // ---------------------------------------------------------------------
369 // =====================================================================
370 /*
371  \fn BuildScannerObject()
372  \brief Instantiate the specific scanner object related to the modality, and set verbosity of scanner object
373  \todo delete the check on modality once all scanner classes will be completely implemented ?
374  \return 0 if success. Positive value otherwise
375 */
377 {
379 
380  // Verbose
381  if (m_verbose>=VERBOSE_NORMAL) Cout("sScannerManager::BuildScannerObject() -> Start building"<< endl);
382 
383  // Check scanner modality
384  string scanner_type;
385  typedef vScanner *(*maker_scanner) ();
386 
387  // Get the system type from the value of the modality field inside the scanner header
388  if (ReadDataASCIIFile(m_pathToScannerFile, "modality", &scanner_type, 1, KEYWORD_MANDATORY) == 1)
389  {
390  Cerr("***** sScannerManager::BuildScannerObject() -> 'Modality' field not found in the header of the scanner configuration file at :"<< endl);
391  Cerr("***** " << m_pathToScannerFile << endl);
392  return 1;
393  }
394 
395  // Get scanner's list from addon manager
396  std::map <string,maker_scanner> list = sAddonManager::GetInstance()->mp_listOfScannerTypes;
397 
398  // Instanciate the scanner class corresponding to the modality, throw error if no match
399  if (list[scanner_type]) mp_Scanner = list[scanner_type]();
400  else
401  {
402  Cerr("***** sScannerManager::BuildScannerObject() -> Modality '" << scanner_type << "' is unknown !" << endl);
404  return 1;
405  }
406 
407  // Set scanner verbosity
409 
410  // Set scanner image dimensions and quantification pointer
412 
413  // End
414  return 0;
415 }
416 
417 // =====================================================================
418 // ---------------------------------------------------------------------
419 // ---------------------------------------------------------------------
420 // =====================================================================
421 /*
422  \fn GetGeometricInfoFromDataFile
423  \param a_path : string containing the path to datafile header
424  \brief Call the specialized function of the scanner object in order to
425  get geometric informations from the datafile header
426  \return 0 if success. Positive value otherwise
427 */
429 {
431 
432  // Verbose
433  if (m_verbose>=VERBOSE_NORMAL) Cout("sScannerManager::GetGeometricInfoFromDataFile() -> Look for acquisition specific settings into datafile header"<< endl);
434 
435  // Get information
437  {
438  Cerr("***** sScannerManager::GetGeometricInfoFromDataFile() -> An error occurred while getting information from the datafile." << endl);
439  return 1;
440  }
441 
442  // End
443  return 0;
444 }
445 
446 // =====================================================================
447 // ---------------------------------------------------------------------
448 // ---------------------------------------------------------------------
449 // =====================================================================
450 /*
451  \fn InstantiateScanner
452  \brief Instantiate scanner using the related function in the scanner classes
453  \todo delete the check on scanner type once all scanner classes will be completely implemented.
454  \return 0 if success. Positive value otherwise
455 */
457 {
459 
460  // Verbose
461  if (m_verbose>=VERBOSE_NORMAL) Cout("sScannerManager::InstantiateScanner() -> Instantiate the scanner geometry structure"<< endl);
462 
463  // Check if the scanner object is known (TODO : delete this check once all scanner classes will be completely implemented)
464  if (mp_Scanner->GetScannerType()<0)
465  {
466  Cerr("***** sScannerManager::BuildScannerObject() -> Unknow scanner type !" << endl);
467  return 1;
468  }
469 
470  // Instantiate geometry
472  {
473  Cerr("***** sScannerManager::InstantiateScanner() -> An error occurred while instanciating the Scanner object !" << endl);
474  return 1;
475  }
476 
477  // End
478  return 0;
479 }
480 
481 // =====================================================================
482 // ---------------------------------------------------------------------
483 // ---------------------------------------------------------------------
484 // =====================================================================
485 /*
486  \fn BuildLUT()
487  \brief Call the eponym function of the scanner class
488  \return 0 if success. Positive value otherwise
489 */
491 {
493 
494  // Verbose
495  if (m_verbose>=VERBOSE_NORMAL) Cout("sScannerManager::BuildLUT() -> Generate the geometric Look-Up Table"<< endl);
496 
497  // Generate LUT
499  {
500  Cerr("***** sScannerManager::BuildLUT() -> A problem occurred while generating/reading the LUT !" << endl);
501  return 1;
502  }
503 
504  // End
505  return 0;
506 }
507 
508 // =====================================================================
509 // ---------------------------------------------------------------------
510 // ---------------------------------------------------------------------
511 // =====================================================================
512 /*
513  \fn GetAvailableScanners
514  \param ap_scannerNames : vector list of string to recover the available scanner names
515  \brief Gather all the names of the header files (.geom & .hscan)
516  in the repository folder in the vector<string> passed in parameter
517  \return 0 if sucess, positive value otherwise
518 */
519 int sScannerManager::GetAvailableScanners(vector<string> *ap_scannerNames)
520 {
522 
523  // Verbose
524  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::GetAvailableScanners() -> Scan the scanner configuration directory"<< endl);
525 
526  // Initialize directory
527  DIR *respository_dir;
528  struct dirent *ent;
529  string str_geom(".geom"), str_hscan(".hscan");
530  string scanner_repository = sOutputManager::GetInstance()->GetPathToConfigDir() + "scanner" + OS_SEP;
531 
532  // Open directory
533  if ((respository_dir = opendir(scanner_repository.c_str())) != NULL)
534  {
535  // Print all the files and directories within the repository directory
536  while ((ent = readdir (respository_dir)) != NULL)
537  {
538  string scanner_name = ent->d_name;
539  // Get rid of backup files in linux
540  if(scanner_name.at(scanner_name.size()-1) != '~')
541  // .geom or .hscan file found
542  if(scanner_name.find(str_geom)!=string::npos || scanner_name.find(str_hscan)!=string::npos )
543  {
544  ap_scannerNames->push_back(scanner_name);
545  }
546  }
547  // Close directory
548  closedir (respository_dir);
549  }
550  else
551  {
552  Cerr("***** sScannerManager::GetAvailableScanners() -> Could not open the repository directory at: " << scanner_repository << endl);
553  return 1;
554  }
555 
556  // End
557  return 0;
558 }
559 
560 
561 
562 
563 // =====================================================================
564 // ---------------------------------------------------------------------
565 // ---------------------------------------------------------------------
566 // =====================================================================
575 {
576  if( a_systemStr == "PET" )
577  return SCANNER_PET;
578  else if( a_systemStr == "SPECT_PINHOLE" )
579  return SCANNER_SPECT_PINHOLE;
580  else if( a_systemStr == "SPECT_CONVERGENT" )
582  else if( a_systemStr == "CT" )
583  return SCANNER_CT;
584  else if( a_systemStr == "SINOGRAM" )
585  return SCANNER_SINOGRAM;
586  else
587  return SCANNER_UNKNOWN;
588 
589  return SCANNER_UNKNOWN;
590 }
591 
592 
593 
594 
595 // =====================================================================
596 // ---------------------------------------------------------------------
597 // ---------------------------------------------------------------------
598 // =====================================================================
599 /*
600  \fn GetScannerLayerNbRings
601  \param a_layer : layer index
602  \brief Ask the number of rings to the scanner object for a specific layer.
603  Returns an error if this information is not available for the scanner type of the object (eg : SPECT systems)
604  \return The number of rings in the system if success. NEGATIVE value otherwise
605 
606 int sScannerManager::GetScannerLayerNbRings(int a_layer)
607 {
608  DEBUG_VERBOSE(m_verbose,VERBOSE_DEBUG_LIGHT)
609 
610  // Verbose
611  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::GetScannerLayerNbRings() -> For layer " << a_layer << endl);
612 
613  // Works only for PET scanners
614  if (mp_Scanner->GetScannerType() == SCANNER_PET)
615  {
616  // Get the number of rings
617  int nb_rings = mp_Scanner->GetScannerLayerNbRings(a_layer);
618  // Check for error
619  if (nb_rings <= 0)
620  {
621  Cerr("***** sScannerManager::GetScannerLayerNbRings() -> Error when trying to get the number of rings in the system for the crystal layer " << a_layer+1 << " !" << endl);
622  return -1;
623  }
624  else return nb_rings;
625  }
626  else
627  {
628  Cerr("***** sScannerManager::GetScannerLayerNbRings() -> This function is only available for PET scanners !" << endl);
629  return -1;
630  }
631 }
632 */
633 
634 // =====================================================================
635 // ---------------------------------------------------------------------
636 // ---------------------------------------------------------------------
637 // =====================================================================
638 
639 int sScannerManager::GetSPECTSpecificParameters(uint16_t* ap_nbOfProjections,
640  uint16_t* ap_nbHeads,
641  FLTNB* ap_acquisitionZoom,
642  uint16_t* ap_nbOfBins,
643  FLTNB* ap_pixSizeXY,
644  FLTNB*& ap_angles,
645  FLTNB*& ap_CORtoDetectorDistance,
646  int* ap_headRotDirection)
647 {
649 
650  // Verbose
651  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::GetSPECTSpecificParameters() -> Get acquisition dependent parameters"<< endl);
652 
653  // Check modality
655  {
656  Cerr("***** sScannerManager::GetSPECTSpecificParameters()-> The scanner object is not of SPECT type !" << endl);
657  return 1;
658  }
659  else
660  {
661  // TODO: SS: remove this function from the vScanner, let it be specific to the SPECT scanner and then do a dynamic_cast here
662  // and do the same for all functions declared in vScanner as virtual but that are entirely specific !
663  if (mp_Scanner->GetSPECTSpecificParameters(ap_nbOfProjections, ap_nbHeads, ap_acquisitionZoom, ap_nbOfBins, ap_pixSizeXY, ap_angles, ap_CORtoDetectorDistance, ap_headRotDirection) )
664  {
665  Cerr("***** sScannerManager::GetSPECTSpecificParameters()-> A problem occurred while retrieving SPECT parameters from the scanner object !" << endl);
666  return 1;
667  }
668  }
669  return 0;
670 }
671 
672 // =====================================================================
673 // ---------------------------------------------------------------------
674 // ---------------------------------------------------------------------
675 // =====================================================================
676 /*
677  \fn GetCTSpecificParameters (Reconstruction)
678  \param ap_nbOfProjections : number of views/projections
679  \param ap_angles : an array containing angles for each view
680  \param ap_headRotDirection : head rotation direction
681  \brief Transfer geometric information recovered from the datafile to the scanner object, by copy of pointers
682  \return 0 if success, positive value otherwise
683 */
684 int sScannerManager::GetCTSpecificParameters(uint16_t* ap_nbOfProjections,
685  FLTNB*& ap_angles,
686  int* ap_headRotDirection)
687 {
689 
690  // Verbose
691  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::GetCTSpecificParameters() -> Get acquisition dependent parameters"<< endl);
692 
693  // Check modality
695  {
696  Cerr("***** sScannerManager::GetCTSpecificParameters()-> The scanner object is not of CT type !" << endl);
697  return 1;
698  }
699  else
700  {
701  // TODO: SS: remove this function from the vScanner, let it be specific to the SPECT scanner and then do a dynamic_cast here
702  // and do the same for all functions declared in vScanner as virtual but that are entirely specific !
703  if (mp_Scanner->GetCTSpecificParameters(ap_nbOfProjections, ap_angles, ap_headRotDirection) )
704  {
705  Cerr("***** sScannerManager::GetCTSpecificParameters()-> A problem occurred while retrieving CT parameters from the scanner object !" << endl);
706  return 1;
707  }
708  }
709  return 0;
710 }
711 
712 // =====================================================================
713 // ---------------------------------------------------------------------
714 // ---------------------------------------------------------------------
715 // =====================================================================
716 /*
717  \fn PROJ_GetModalityStopValueMainLoop
718  \brief Get the stop value for the main loop of analytic projection depending on the modality
719  \return the required stop value if success, NEGATIVE value otherwise
720  \todo Cases for CT and sinogram scanner types
721 */
723 {
725 
726  if (m_verbose>=VERBOSE_DEBUG_NORMAL) Cout("sScannerManager::PROJ_GetModalityStopValueMainLoop ..."<< endl);
727 
729  return mp_Scanner->GetSystemNbElts();
732  return (int64_t)mp_Scanner->PROJ_GetSPECTNbProjections(); // cast from uint16_t to int
733  else if(mp_Scanner->GetScannerType() == SCANNER_CT)
734  {
735  // TODO
736  Cerr("sScannerManager::PROJ_GetModalityStopValueMainLoop()-> Not implemented for CT yet!" << endl);
737  return -1;
738  }
740  {
741  // TODO + should call a GetType() like function for scanner defined as a sinogram
742  Cerr("sScannerManager::PROJ_GetModalityStopValueMainLoop()-> Not implemented for Sinogram scanner yet!" << endl);
743  return -1;
744  }
745  else
746  {
747  Cerr("sScannerManager::PROJ_GetModalityStopValueMainLoop()-> Unknown scanner type!" << endl);
748  return -1;
749  }
750 
751  return 0;
752 }
753 
754 // =====================================================================
755 // ---------------------------------------------------------------------
756 // ---------------------------------------------------------------------
757 // =====================================================================
758 /*
759  \fn PROJ_GetModalityStartValueInnerLoop
760  \param a_elt1 : Current nb of processed crystals (PET), projections (SPECT)
761  \brief Get the start value for the inner loop of analytic projection depending on the modality
762  \return the required stop value if success, NEGATIVE value otherwise
763  \todo Cases for CT and sinogram scanner types
764  \todo Precise with SS on which index SPECT inner loop should be done
765 */
767 {
769 
771  {
772  return a_elt1+1;
773  }
776  {
777  return 0; // (first crystal)
778  // TODO SS: here the inner loop should be done on the number of views
779  }
780  else if(mp_Scanner->GetScannerType() == SCANNER_CT)
781  {
782  // TODO
783  Cerr("sScannerManager::PROJ_GetModalityStopValueMainLoop()-> Not implemented for CT yet!" << endl);
784  return -1;
785  }
787  {
788  // TODO + should call a GetType() like function for scanner defined as a sinogram
789  Cerr("sScannerManager::PROJ_GetModalityStopValueMainLoop()-> Not implemented for Sinogram scanner yet!" << endl);
790  return -1;
791  }
792  else
793  {
794  Cerr("sScannerManager::PROJ_GetModalityStopValueMainLoop()-> Unknown scanner type!" << endl);
795  return -1;
796  }
797 
798  return 0;
799 }
800 
801 // =====================================================================
802 // ---------------------------------------------------------------------
803 // ---------------------------------------------------------------------
804 // =====================================================================
805 /*
806  \fn PROJ_GetCurrentProgression
807  \param a_elt1 : Current nb of processed #1 crystals (PET), projections (SPECT)
808  \param a_elt2 : Current nb of processed #2 crystals (PET), crystals (SPECT)
809  \param ap_nbEltsArray : Total number of elements processed for each #1 crystals (PET/CT systems)
810  \param a_nbDynImgProcessed
811  \brief Get numerator value according to the modality to compute percent progression during the analytical projection process
812  \return the required progression value if success, negative value otherwise
813  \todo Cases for CT and sinogram scanner types
814  \todo Optimize this, for now it's quite a lot of operation for each couple of elements
815  \todo Check everything is ok for 3D/4D PET and SPECT
816 */
817 int64_t sScannerManager::PROJ_GetCurrentProgression(int64_t a_elt1, int64_t a_elt2, int64_t* ap_nbEltsArray, uint16_t a_nbDynImgProcessed)
818 {
820 
821  // TODO : optimization, maybe too much operations for each couple of elements
823  {
824  int64_t nb_total_elts = mp_Scanner->GetSystemNbElts();
825 
826  return ap_nbEltsArray[a_elt1]+a_elt2+1 +
827  (int64_t)(a_nbDynImgProcessed)* nb_total_elts*nb_total_elts/2;
828 
829  }
832  {
833  return a_elt2
834  + a_elt1*mp_Scanner->GetSystemNbElts()
835  + (int64_t)(a_nbDynImgProcessed) * mp_Scanner->GetSystemNbElts();
836  }
837  else if(mp_Scanner->GetScannerType() == SCANNER_CT)
838  {
839  //TODO
840  Cerr("sScannerManager::PROJ_GetCurrentProgression()-> Not implemented for CT yet!" << endl);
841  return -1;
842  }
844  {
845  //TODO + should call a GetType() like function for scanner defined as a sinogram
846  Cerr("sScannerManager::PROJ_GetCurrentProgression()-> Not implemented for Sinogram scanner yet!" << endl);
847  return -1;
848  }
849  else
850  {
851  Cerr("sScannerManager::PROJ_GetCurrentProgression()-> Unknown scanner type!" << endl);
852  return -1;
853  }
854 }
855 
856 // =====================================================================
857 // ---------------------------------------------------------------------
858 // ---------------------------------------------------------------------
859 // =====================================================================
860 /*
861  \fn PROJ_GetProgressionFinalValue
862  \brief Get numerator value according to the modality to compute percent progression during the projection process
863  \return the required progression value if success, negative value otherwise
864  \todo Cases for CT and sinogram scanner types
865 */
867 {
869 
871  {
872  //return mp_Scanner->GetSystemNbElts();
873  int64_t nb_total_elts = mp_Scanner->GetSystemNbElts();
874  return nb_total_elts*nb_total_elts/2;
875  }
878  {
879  return (int64_t)mp_Scanner->PROJ_GetSPECTNbProjections()*mp_Scanner->GetSystemNbElts(); // cast from uint16_t to int
880  }
881  else if(mp_Scanner->GetScannerType() == SCANNER_CT)
882  {
883  //TODO
884  Cerr("sScannerManager::PROJ_GetProgressionFinalValue()-> Not implemented for CT yet!" << endl);
885  return -1;
886  }
888  {
889  //TODO + should call a GetType() like function for scanner defined as a sinogram
890  Cerr("sScannerManager::PROJ_GetProgressionFinalValue()-> Not implemented for Sinogram scanner yet!" << endl);
891  return -1;
892  }
893  else
894  {
895  Cerr("sScannerManager::PROJ_GetProgressionFinalValue()-> Unknown scanner type!" << endl);
896  return -1;
897  }
898 }
899 
900 // =====================================================================
901 // ---------------------------------------------------------------------
902 // ---------------------------------------------------------------------
903 // =====================================================================
904 /*
905  \fn PROJ_SetPETSpecificParameters (Analytic Projection)
906  \param a_maxAxialDiffmm : max axial difference in mm between 2 crystals forming a lor
907  \brief Deliver to the PET scanner object all informations provided from the datafile header
908  \return 0 if success, positive value otherwise
909  \todo How to handle systems with several layer of rings ?
910 */
912 {
914 
915  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::PROJ_SetPETSpecificParameters ..."<< endl);
916 
918  {
919  Cerr("***** sScannerManager::SetPETSpecificParameters() -> The scanner object is not of PET type !" << endl);
920  return 1;
921  }
922  else
923  {
924  mp_Scanner->SetPETMaxAxialDiffmm(a_maxAxialDiffmm);
925  }
926 
927  return 0;
928 }
929 
930 // =====================================================================
931 // ---------------------------------------------------------------------
932 // ---------------------------------------------------------------------
933 // =====================================================================
934 /*
935  \fn PROJ_GetPETSpecificParameters (Analytic Projection)
936  \param ap_maxRingDiff : maximal axial difference in mm between 2 crystals forming a lor
937  \brief Transfer addresses to each geometric parameter of the PET scanner objets to the corresponding pointer of the datafile passed as argument
938  \return 0 if success, positive value otherwise
939  \todo How to handle systems with several layer of rings ?
940 */
942 {
944 
945  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::PROJ_GetPETSpecificParameters ..."<< endl);
946 
948  {
949  Cerr("***** sScannerManager::PROJ_GetPETSpecificParameters()-> The scanner object is not of PET type !" << endl);
950  return 1;
951  }
952  else
953  {
954  // Negative value means no ring diff restriction
955  FLTNB max_ring_diff = -1.;
956 
957  if (mp_Scanner->PROJ_GetPETSpecificParameters(&max_ring_diff) )
958  {
959  Cerr("***** sScannerManager::PROJ_GetPETSpecificParameters()-> A problem occurred while retrieving PET parameters from the scanner object !" << endl);
960  return 1;
961  }
962 
963  *ap_maxRingDiff = max_ring_diff;
964  }
965  return 0;
966 }
967 
968 // =====================================================================
969 // ---------------------------------------------------------------------
970 // ---------------------------------------------------------------------
971 // =====================================================================
972 /*
973  \fn PROJ_SetSPECTSpecificParameters (Analytic Projection)
974  \param ap_nbOfBins : 2 elements array containing transaxial number of bins
975  \param a_nbOfProjections : number of views/projections
976  \param a_firstAngle : angle of the first view
977  \param a_lastAngle : angle of the last view
978  \param ap_projectionAngles : an array containing angles for each view
979  \param a_CORtoDetectorDistance : a distance between the center of rotation and the detector
980  \param a_RotDirection : Rotation direction of the head (clockwise/counter-clockwise)
981  \brief Deliver to the SPECT scanner object all informations provided from the acquisition parameters
982  \details For analytical projection, this data is provided from the command-line options
983  \return 0 if success, positive value otherwise
984 */
986  uint32_t a_nbOfProjections,
987  FLTNB a_firstAngle,
988  FLTNB a_stepAngle,
989  FLTNB* ap_projectionAngles,
990  FLTNB a_CORtoDetectorDistance,
991  string a_rotDirection)
992 {
994 
995  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::PROJ_SetSPECTSpecificParameters ..."<< endl);
996 
997  // Return error if wrong modality
999  {
1000  Cerr("***** sScannerManager::SetPETSpecificParameters()-> The scanner object is not of PET type !" << endl);
1001  return 1;
1002  }
1003  else
1004  {
1005  // Nb bins
1006  mp_Scanner->PROJ_SetSPECTNbBins(ap_nbOfBins);
1007 
1008  // Nb projections
1009  if(a_nbOfProjections == 0)
1010  {
1011  Cerr("***** sScannerManager::SetSPECTSpecificParameters()-> Error, SPECT analytic projection requires an user-specified number of projections !" << endl);
1012  return 1;
1013  }
1014 
1015  mp_Scanner->PROJ_SetSPECTNbProjections(a_nbOfProjections);
1016 
1017 
1018  // Projection angles initialized with either each angles, or calculated from first/last angle
1019  // By default, we chose the user-provided custom initialization for SPECT projection angles
1020  // If not initialized, we computed them from first/last angle
1021  if(ap_projectionAngles == NULL)
1022  {
1023  // If no custom initialization have been provided, then we check if we have first and last angles values for automatic initialization of the projection angles
1024  if(a_firstAngle<0 || a_stepAngle<0)
1025  {
1026  Cerr("***** sScannerManager::SetSPECTSpecificParameters()-> Error, SPECT projection requires to set the projection angles using either the '-SPECT_ang' or '-SPECT_c_ang' options !" << endl);
1027  return 1;
1028  }
1029  else
1030  {
1031  // Fill the SPECT_projection_angles array
1032  ap_projectionAngles = new FLTNB[a_nbOfProjections];
1033  ap_projectionAngles[0] = a_firstAngle;
1034 
1035  for(uint32_t a=1 ; a<a_nbOfProjections ; a++)
1036  ap_projectionAngles[a] = ap_projectionAngles[a-1] + a_stepAngle;
1037  }
1038  }
1039 
1040  if(mp_Scanner->PROJ_SetSPECTAngles(ap_projectionAngles) )
1041  {
1042  Cerr("***** sScannerManager::SetSPECTAngles() -> An error occurred while trying to initialize SPECT projection angles !" << endl);
1043  return 1;
1044  }
1045 
1046  // CORtoDetectorDistance
1047  if(mp_Scanner->PROJ_SetSPECTCORtoDetectorDistance(a_CORtoDetectorDistance) )
1048  {
1049  Cerr("***** sScannerManager::SetPETSpecificParameters() -> An error occurred while trying to initialize SPECT distance between center of rotation to detectors !" << endl);
1050  return 1;
1051  }
1052 
1053  // Set rotation direction
1054  mp_Scanner->SetRotDirection(a_rotDirection);
1055  }
1056 
1057  return 0;
1058 }
virtual int PROJ_SetSPECTNbBins(uint16_t *ap_nbOfBins)
Set SPECT number of Bins.
Definition: vScanner.cc:325
int GetAvailableScanners(vector< string > *ap_scannerNames)
Gather all the names of the header files (.geom & .hscan) in the repository folder in the vector<stri...
virtual int PROJ_SetSPECTNbProjections(uint32_t a_nbOfProjections)
Set SPECT number of views.
Definition: vScanner.cc:346
int64_t PROJ_GetModalityStartValueInnerLoop(int64_t a_elt1)
Get the start value for the inner loop of analytic projection depending on the modality.
#define FLTNB
Definition: gVariables.hh:81
virtual int PROJ_GetPETSpecificParameters(FLTNB *ap_maxRingDiff)
Get geometric PET specific parameters to initialize the datafile.
Definition: vScanner.cc:223
virtual int SetPETMaxAxialDiffmm(FLTNB a_maxAxialDiffmm)
Set the maximal axial difference in mm between 2 crystals forming a lor.
Definition: vScanner.cc:202
int FindScannerSystem(string a_scannerName)
Look for a file matching with the scanner name in parameter inside the scanner repository.
virtual int PROJ_SetSPECTAngles(FLTNB *ap_projectionAngles)
Set SPECT projection angles.
Definition: vScanner.cc:370
int BuildScannerObject()
Instantiate the specific scanner object related to the modality, and set verbosity of scanner object...
int64_t PROJ_GetProgressionFinalValue()
Get numerator value according to the modality to compute percent progression during the projection pr...
virtual int GetGeometricInfoFromDataFile(string a_path)=0
This function is implemented in child classes Recover geometric informations specific to the scanne...
#define VERBOSE_DETAIL
char d_name[PATH_MAX]
#define SCANNER_UNKNOWN
int GetModalityFromString(string a_systemStr)
A simple utility function which returns the integer corresponding to the system string passed in pa...
static sScannerManager * mp_Instance
virtual uint16_t PROJ_GetSPECTNbProjections()
return the total number of projections for a SPECT acquisition
Definition: vScanner.cc:411
virtual int CheckParameters()=0
This function is implemented in child classes. Check that all parameters have been correctly initia...
std::map< string, maker_scanner > mp_listOfScannerTypes
int GetSPECTSpecificParameters(uint16_t *ap_nbOfProjections, uint16_t *ap_nbHeads, FLTNB *ap_acquisitionZoom, uint16_t *ap_nbOfBins, FLTNB *ap_pixSizeXY, FLTNB *&ap_angles, FLTNB *&ap_CORtoDetectorDistance, int *ap_headRotDirection)
Transfer geometric information recovered from the datafile to the scanner object. ...
static sOutputManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
#define SCANNER_PET
virtual int Initialize()=0
This function is implemented in child classes. Check initialization and set several parameters to t...
int CheckParameters()
Check if all parameters have been correctly initialized, and call the CheckParameters function of the...
int InstantiateScanner()
Instantiate scanner using the related function in the scanner classes.
sScannerManager()
sScannerManager constructor.
static sAddonManager * GetInstance()
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ID)
Set the pointer to the image dimensions and quantification object.
Definition: vScanner.hh:282
#define Cerr(MESSAGE)
#define SCANNER_SPECT_CONVERGENT
virtual int Instantiate(bool a_scannerFileIsLUT)=0
This function is implemented in child classes. Read the mandatory fields from the scanner file and al...
#define VERBOSE_DEBUG_LIGHT
virtual int SetRotDirection(string a_rotDirection)
Set rotation direction of the system.
Definition: vScanner.cc:289
int BuildLUT()
Call the eponym function of the scanner class.
const string & GetPathToConfigDir()
Return the path to the CASTOR config directory.
#define VERBOSE_LIGHT
int ReadDataASCIIFile(const string &a_file, const string &a_keyword, T *ap_return, int a_nbElts, bool a_mandatoryFlag)
Look for "a_nbElts" elts in the "a_file" file matching the "a_keyword" string passed as parameter a...
Definition: gOptions.cc:129
Singleton class that Instantiate and initialize the scanner object.
#define SCANNER_SINOGRAM
void Describe()
A function used to describe the generic parts of the datafile.
Definition: vScanner.cc:75
Declaration of class sScannerManager.
int PROJ_SetPETSpecificParameters(FLTNB a_maxAxialDiffmm)
Deliver to the PET scanner object all informations provided from the datafile header.
static int closedir(DIR *dirp)
int64_t PROJ_GetCurrentProgression(int64_t a_elt1, int64_t a_elt2, int64_t *ap_nbEltsArray, uint16_t a_nbDynImgProcessed)
Get numerator value according to the modality to compute percent progression during the analytical pr...
#define VERBOSE_NORMAL
static DIR * opendir(const char *dirname)
int ShowScannersDescription()
Get the description associated to the different scanners and print all on screen. Walk through the ...
~sScannerManager()
sScannerManager destructor.
#define KEYWORD_MANDATORY
Definition: gOptions.hh:47
int PROJ_SetSPECTSpecificParameters(uint16_t *ap_nbOfBins, uint32_t a_nbOfProjections, FLTNB a_firstAngle, FLTNB a_stepAngle, FLTNB *ap_projectionAngles, FLTNB a_CORtoDetectorDistance, string a_rotDirection)
Deliver to the SPECT scanner object all informations provided from the acquisition parameters...
virtual int GetSPECTSpecificParameters(uint16_t *ap_nbOfProjections, uint16_t *ap_nbHeads, FLTNB *ap_acquisitionZoom, uint16_t *ap_nbOfBins, FLTNB *ap_pixSizeXY, FLTNB *&ap_angles, FLTNB *&ap_CORtoDetectorDistance, int *ap_headRotDirection)
Recover geometric SPECT specific parameters from the scanner to initialize the datafile.
Definition: vScanner.cc:237
void SetVerbose(int a_verboseLevel)
Set verbosity.
Definition: vScanner.hh:275
int Initialize()
Initialization : .
#define SCANNER_SPECT_PINHOLE
virtual int PROJ_SetSPECTCORtoDetectorDistance(FLTNB a_CORtoDetectorDistance)
Set distance between center of rotation and SPECT detectors.
Definition: vScanner.cc:391
virtual int GetSystemNbElts()=0
This is a pure virtual method that must be implemented by children.
#define OS_SEP
vScanner * mp_Scanner
oImageDimensionsAndQuantification * mp_ID
void ShowHelpScanner()
Show help about all implemented scanners.
void Describe()
Call the eponym function from the Scanner object (if initialized)
#define DEBUG_VERBOSE(IGNORED1, IGNORED2)
#define Cout(MESSAGE)
int64_t PROJ_GetModalityStopValueMainLoop()
Get the stop value for the main loop of analytic projection depending on the modality.
static struct dirent * readdir(DIR *dirp)
#define SCANNER_CT
int GetCTSpecificParameters(uint16_t *ap_nbOfProjections, FLTNB *&ap_angles, int *ap_headRotDirection)
Transfer geometric information recovered from the datafile to the scanner object. ...
int GetGeometricInfoFromDataFile(string a_pathToDataFilename)
Call the specialized function of the scanner object in order to get geometric informations from the d...
int PROJ_GetPETSpecificParameters(FLTNB *ap_maxAxialDiffmm)
Transfer addresses to each geometric parameter of the PET scanner objets to the corresponding pointer...
virtual int GetCTSpecificParameters(uint16_t *ap_nbOfProjections, FLTNB *&ap_angles, int *ap_detectorRotDirection)
Recover geometric CT specific parameters from the scanner to initialize the datafile.
Definition: vScanner.cc:267
Declaration of class sAddonManager.
int GetScannerType()
Definition: vScanner.hh:262
Generic class for scanner objects.
Definition: vScanner.hh:61
#define VERBOSE_DEBUG_NORMAL
int InitScannerWithFile(string a_pathScanFile, string a_scannerName, int a_fileTypeFlag)
Initialize member variables (file path, file type, and scanner name) with the provided arguments...
virtual int BuildLUT(bool a_scannerFileIsLUT)=0
This function is implemented in child classes. Instantiate the scanner look-up-table (LUT) ...