CASToR  3.0
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-2019 all CASToR contributors listed below:
18 
19  --> Didier BENOIT, Claude COMTAT, Marina FILIPOVIC, Thibaut MERLIN, Mael MILLARDET, Simon STUTE, Valentin VIELZEUF
20 
21 This is CASToR version 3.0.
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_nbRGates
811  \param a_nbCGates
812  \param a_fr
813  \param a_rg
814  \param a_cg
815  \brief Get numerator value according to the modality to compute percent progression during the analytical projection process
816  \return the required progression value if success, negative value otherwise
817  \todo Cases for CT and sinogram scanner types
818  \todo Optimize this, for now it's quite a lot of operation for each couple of elements
819  \todo Check everything is ok for 3D/4D PET and SPECT
820 */
821 int64_t sScannerManager::PROJ_GetCurrentProgression(int64_t a_elt1, int64_t a_elt2, int64_t* ap_nbEltsArray,
822  int a_nbRGates, int a_nbCGates,
823  int a_fr, int a_rg, int a_cg)
824 {
826 
827  // TODO : optimization, maybe too much operations for each couple of elements
829  {
830  int64_t nb_total_elts = mp_Scanner->GetSystemNbElts();
831 
832  return ap_nbEltsArray[a_elt1]+a_elt2+1 +
833  (int64_t)(a_fr*a_nbRGates*a_nbCGates + a_rg*a_nbCGates + a_cg)* nb_total_elts*nb_total_elts/2;
834  }
837  {
838  return a_elt2
839  + a_elt1*mp_Scanner->GetSystemNbElts()
840  + a_fr * a_nbRGates * a_nbCGates * mp_Scanner->GetSystemNbElts()
841  + a_rg * a_nbCGates * mp_Scanner->GetSystemNbElts()
842  + a_cg * mp_Scanner->GetSystemNbElts();
843  }
844  else if(mp_Scanner->GetScannerType() == SCANNER_CT)
845  {
846  //TODO
847  Cerr("sScannerManager::PROJ_GetCurrentProgression()-> Not implemented for CT yet!" << endl);
848  return -1;
849  }
851  {
852  //TODO + should call a GetType() like function for scanner defined as a sinogram
853  Cerr("sScannerManager::PROJ_GetCurrentProgression()-> Not implemented for Sinogram scanner yet!" << endl);
854  return -1;
855  }
856  else
857  {
858  Cerr("sScannerManager::PROJ_GetCurrentProgression()-> Unknown scanner type!" << endl);
859  return -1;
860  }
861 }
862 
863 // =====================================================================
864 // ---------------------------------------------------------------------
865 // ---------------------------------------------------------------------
866 // =====================================================================
867 /*
868  \fn PROJ_GetProgressionFinalValue
869  \brief Get numerator value according to the modality to compute percent progression during the projection process
870  \return the required progression value if success, negative value otherwise
871  \todo Cases for CT and sinogram scanner types
872 */
874 {
876 
878  {
879  //return mp_Scanner->GetSystemNbElts();
880  int64_t nb_total_elts = mp_Scanner->GetSystemNbElts();
881  return nb_total_elts*nb_total_elts/2;
882  }
885  {
886  return (int64_t)mp_Scanner->PROJ_GetSPECTNbProjections()*mp_Scanner->GetSystemNbElts(); // cast from uint16_t to int
887  }
888  else if(mp_Scanner->GetScannerType() == SCANNER_CT)
889  {
890  //TODO
891  Cerr("sScannerManager::PROJ_GetProgressionFinalValue()-> Not implemented for CT yet!" << endl);
892  return -1;
893  }
895  {
896  //TODO + should call a GetType() like function for scanner defined as a sinogram
897  Cerr("sScannerManager::PROJ_GetProgressionFinalValue()-> Not implemented for Sinogram scanner yet!" << endl);
898  return -1;
899  }
900  else
901  {
902  Cerr("sScannerManager::PROJ_GetProgressionFinalValue()-> Unknown scanner type!" << endl);
903  return -1;
904  }
905 }
906 
907 // =====================================================================
908 // ---------------------------------------------------------------------
909 // ---------------------------------------------------------------------
910 // =====================================================================
911 /*
912  \fn PROJ_SetPETSpecificParameters (Analytic Projection)
913  \param a_maxAxialDiffmm : max axial difference in mm between 2 crystals forming a lor
914  \brief Deliver to the PET scanner object all informations provided from the datafile header
915  \return 0 if success, positive value otherwise
916  \todo How to handle systems with several layer of rings ?
917 */
919 {
921 
922  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::PROJ_SetPETSpecificParameters ..."<< endl);
923 
925  {
926  Cerr("***** sScannerManager::SetPETSpecificParameters() -> The scanner object is not of PET type !" << endl);
927  return 1;
928  }
929  else
930  {
931  mp_Scanner->SetPETMaxAxialDiffmm(a_maxAxialDiffmm);
932  }
933 
934  return 0;
935 }
936 
937 // =====================================================================
938 // ---------------------------------------------------------------------
939 // ---------------------------------------------------------------------
940 // =====================================================================
941 /*
942  \fn PROJ_GetPETSpecificParameters (Analytic Projection)
943  \param ap_maxRingDiff : maximal axial difference in mm between 2 crystals forming a lor
944  \brief Transfer addresses to each geometric parameter of the PET scanner objets to the corresponding pointer of the datafile passed as argument
945  \return 0 if success, positive value otherwise
946  \todo How to handle systems with several layer of rings ?
947 */
949 {
951 
952  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::PROJ_GetPETSpecificParameters ..."<< endl);
953 
955  {
956  Cerr("***** sScannerManager::PROJ_GetPETSpecificParameters()-> The scanner object is not of PET type !" << endl);
957  return 1;
958  }
959  else
960  {
961  // Negative value means no ring diff restriction
962  FLTNB max_ring_diff = -1.;
963 
964  if (mp_Scanner->PROJ_GetPETSpecificParameters(&max_ring_diff) )
965  {
966  Cerr("***** sScannerManager::PROJ_GetPETSpecificParameters()-> A problem occurred while retrieving PET parameters from the scanner object !" << endl);
967  return 1;
968  }
969 
970  *ap_maxRingDiff = max_ring_diff;
971  }
972  return 0;
973 }
974 
975 // =====================================================================
976 // ---------------------------------------------------------------------
977 // ---------------------------------------------------------------------
978 // =====================================================================
979 /*
980  \fn PROJ_SetSPECTSpecificParameters (Analytic Projection)
981  \param ap_nbOfBins : 2 elements array containing transaxial number of bins
982  \param a_nbOfProjections : number of views/projections
983  \param a_firstAngle : angle of the first view
984  \param a_lastAngle : angle of the last view
985  \param ap_projectionAngles : an array containing angles for each view
986  \param a_CORtoDetectorDistance : a distance between the center of rotation and the detector
987  \param a_RotDirection : Rotation direction of the head (clockwise/counter-clockwise)
988  \brief Deliver to the SPECT scanner object all informations provided from the acquisition parameters
989  \details For analytical projection, this data is provided from the command-line options
990  \return 0 if success, positive value otherwise
991 */
993  uint32_t a_nbOfProjections,
994  FLTNB a_firstAngle,
995  FLTNB a_stepAngle,
996  FLTNB* ap_projectionAngles,
997  FLTNB a_CORtoDetectorDistance,
998  string a_rotDirection)
999 {
1001 
1002  if (m_verbose>=VERBOSE_DETAIL) Cout("sScannerManager::PROJ_SetSPECTSpecificParameters ..."<< endl);
1003 
1004  // Return error if wrong modality
1006  {
1007  Cerr("***** sScannerManager::SetPETSpecificParameters()-> The scanner object is not of PET type !" << endl);
1008  return 1;
1009  }
1010  else
1011  {
1012  // Nb bins
1013  mp_Scanner->PROJ_SetSPECTNbBins(ap_nbOfBins);
1014 
1015  // Nb projections
1016  if(a_nbOfProjections == 0)
1017  {
1018  Cerr("***** sScannerManager::SetSPECTSpecificParameters()-> Error, SPECT analytic projection requires an user-specified number of projections !" << endl);
1019  return 1;
1020  }
1021 
1022  mp_Scanner->PROJ_SetSPECTNbProjections(a_nbOfProjections);
1023 
1024 
1025  // Projection angles initialized with either each angles, or calculated from first/last angle
1026  // By default, we chose the user-provided custom initialization for SPECT projection angles
1027  // If not initialized, we computed them from first/last angle
1028  if(ap_projectionAngles == NULL)
1029  {
1030  // 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
1031  if(a_firstAngle<0 || a_stepAngle<0)
1032  {
1033  Cerr("***** sScannerManager::SetSPECTSpecificParameters()-> Error, SPECT projection requires to set the projection angles using either the '-SPECT_ang' or '-SPECT_c_ang' options !" << endl);
1034  return 1;
1035  }
1036  else
1037  {
1038  // Fill the SPECT_projection_angles array
1039  ap_projectionAngles = new FLTNB[a_nbOfProjections];
1040  ap_projectionAngles[0] = a_firstAngle;
1041 
1042  for(uint32_t a=1 ; a<a_nbOfProjections ; a++)
1043  ap_projectionAngles[a] = ap_projectionAngles[a-1] + a_stepAngle;
1044  }
1045  }
1046 
1047  if(mp_Scanner->PROJ_SetSPECTAngles(ap_projectionAngles) )
1048  {
1049  Cerr("***** sScannerManager::SetSPECTAngles() -> An error occurred while trying to initialize SPECT projection angles !" << endl);
1050  return 1;
1051  }
1052 
1053  // CORtoDetectorDistance
1054  if(mp_Scanner->PROJ_SetSPECTCORtoDetectorDistance(a_CORtoDetectorDistance) )
1055  {
1056  Cerr("***** sScannerManager::SetPETSpecificParameters() -> An error occurred while trying to initialize SPECT distance between center of rotation to detectors !" << endl);
1057  return 1;
1058  }
1059 
1060  // Set rotation direction
1061  mp_Scanner->SetRotDirection(a_rotDirection);
1062  }
1063 
1064  return 0;
1065 }
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)
#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.
int64_t PROJ_GetCurrentProgression(int64_t a_elt1, int64_t a_elt2, int64_t *ap_nbEltsArray, int a_nbRGates, int a_nbCGates, int a_fr, int a_rg, int a_cg)
Get numerator value according to the modality to compute percent progression during the analytical pr...
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) ...