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