CASToR  3.2
Tomographic Reconstruction (PET/SPECT/CT)
toolkits/castor-datafileExplorer.cc
Go to the documentation of this file.
1 
8 #include "gVariables.hh"
9 #include "gOptions.hh"
10 #include "oImageDimensionsAndQuantification.hh"
11 #include "iDataFilePET.hh"
12 #include "iDataFileSPECT.hh"
13 #include "iDataFileCT.hh"
14 #include "sOutputManager.hh"
15 #include "sScannerManager.hh"
16 #include "sRandomNumberGenerator.hh"
17 #include "iScannerPET.hh"
18 #include "sAddonManager.hh"
19 
20 // =============================================================================================================================================
21 // =============================================================================================================================================
22 // =============================================================================================================================================
23 // H E L P F U N C T I O N S
24 // =============================================================================================================================================
25 // =============================================================================================================================================
26 // =============================================================================================================================================
27 
28 
33 void ShowHelp()
34 {
35  // Show help
36  cout << endl;
37  cout << "Usage: castor-datafileExplorer -df datafile.cdh [settings]" << endl;
38  cout << endl;
39  cout << "This program can be used to explore a datafile and get some info about it. By default, it simply prints general information recovered" << endl;
40  cout << "from the reader. If the '-e' option is supply, an event-by-event exploration will be performed: information about each event will be" << endl;
41  cout << "displayed." << endl;
42  cout << endl;
43  cout << "[Mandatory parameters]:" << endl;
44  cout << " -df datafile.cdh : Give the path to a single datafile." << endl;
45  cout << endl;
46  cout << "[Options]:" << endl;
47  cout << " -e : Flag for event by event exploration (will list the content of each event)." << endl;
48  cout << " -i : Flag for interactive one by one event exploration when -e option is supplied." << endl;
49  cout << " -g : Flag for global exploration (will not list the content of each event but will supply a summary)." << endl;
50  cout << " -vb value : Give the verbosity level, from 0 (no verbose) to 2 (default: 1)" << endl;
51  cout << " --help,-h,-help : Print out this help page." << endl; // managed by main
52  cout << endl;
53  #ifdef BUILD_DATE
54  cout << " Build date: " << BUILD_DATE << endl;
55  cout << endl;
56  #endif
57  #ifdef CASTOR_VERSION
58  cout << " This program is part of the CASToR release version " << CASTOR_VERSION << "." << endl;
59  cout << endl;
60  #endif
61 }
62 
63 // =============================================================================================================================================
64 // =============================================================================================================================================
65 // =============================================================================================================================================
66 // M A I N P R O G R A M
67 // =============================================================================================================================================
68 // =============================================================================================================================================
69 // =============================================================================================================================================
70 
71 int main(int argc, char** argv)
72 {
73  // ============================================================================================================
74  // MPI stuff (we make all instances but the first one returning 0 directly)
75  // ============================================================================================================
76  #ifdef CASTOR_MPI
77  int mpi_rank = 0;
78  int mpi_size = 1;
79  MPI_Init(&argc, &argv);
80  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
81  MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
82  if (mpi_rank!=0) return 0;
83  #endif
84 
85  // No argument, then show help
86  if (argc==1)
87  {
88  ShowHelp();
89  Exit(EXIT_SUCCESS);
90  }
91 
92  // ============================================================================================================
93  // The few parameters
94  // ============================================================================================================
95 
96  // String of a single path to a data file name
97  string path_to_data_filename;
98  // General verbose level
99  int verbose = 1;
100  // Flag for event-by-event exploring
101  bool event_by_event_flag = false;
102  // Flag for interactive mode for event-by-event
103  bool interactive_flag = false;
104  // Flag for global exploration
105  bool global_flag = false;
106 
107  // ============================================================================================================
108  // Read command-line parameters
109  // ============================================================================================================
110 
111  // Must manually increment the option index when an argument is needed after an option
112  for (int i=1; i<argc; i++)
113  {
114  // Get the option as a string
115  string option = (string)argv[i];
116  // Show help
117  if (option=="-h" || option=="--help" || option=="-help")
118  {
119  ShowHelp();
120  Exit(EXIT_SUCCESS);
121  }
122  // General verbosity level
123  else if (option=="-vb")
124  {
125  if (i>=argc-1)
126  {
127  Cerr("***** castor-datafileExplorer() -> Argument missing for option: " << option << endl);
128  Exit(EXIT_FAILURE);
129  }
130  if (ConvertFromString(argv[i+1], &verbose))
131  {
132  Cerr("***** castor-datafileExplorer() -> Exception when trying to read provided verbosity level '" << verbose << " for option: " << option << endl);
133  Exit(EXIT_FAILURE);
134  }
135  i++;
136  }
137  // DataFile
138  else if (option=="-df") // This is a mandatory option
139  {
140  if (i>=argc-1)
141  {
142  Cerr("***** castor-datafileExplorer() -> Argument missing for option: " << option << endl);
143  Exit(EXIT_FAILURE);
144  }
145  path_to_data_filename = (string)argv[i+1];
146  i++;
147  }
148  // Event by event exploration
149  else if (option=="-e")
150  {
151  event_by_event_flag = true;
152  }
153  // Interactive mode for event-by-event exploration
154  else if (option=="-i")
155  {
156  interactive_flag = true;
157  }
158  // Global exploration
159  else if (option=="-g")
160  {
161  global_flag = true;
162  }
163  // Unknown option!
164  else
165  {
166  Cerr("***** castor-datafileExplorer() -> Unknown option '" << option << "' !" << endl);
167  Exit(EXIT_FAILURE);
168  }
169  }
170 
171  // ============================================================================================================
172  // Some checks
173  // ============================================================================================================
174 
175  // Check for a datafile name
176  if (path_to_data_filename=="")
177  {
178  Cerr("***** castor-datafileExplorer() -> Please provide a datafile name !" << endl);
179  Exit(EXIT_FAILURE);
180  }
181  // Verbose
182  if (verbose<=0)
183  {
184  Cerr("***** castor-datafileExplorer() -> Verbose less than 1 has no sense for a program used to solely print out information on screen !" << endl);
185  Exit(EXIT_FAILURE);
186  }
187  // Restrict verbose level to 2 to avoid having to much useless information during initialization
188  if (verbose>2) verbose = 2;
189  // Cannot have event-by-event and global both enables
190  if (global_flag && event_by_event_flag)
191  {
192  Cerr("***** castor-datafileExplorer() -> Cannot use global and event-by-event mode at the same time !" << endl);
193  Exit(EXIT_FAILURE);
194  }
195 
196  // ============================================================================================================
197  // Initializations
198  // ============================================================================================================
199 
200  // Verbose (we know it is at least 1 so we don't check it)
201  Cout("==============================================================" << endl);
202  Cout("castor-datafileExplorer() -> Initialization starts" << endl);
203 
204  // ----------------------------------------------------------------------------------------
205  // Create sScannerManager
206  // ----------------------------------------------------------------------------------------
207 
208  // Get user endianness (interfile I/O)
210 
211  // Create the scanner manager
212  sScannerManager* p_ScannerManager = sScannerManager::GetInstance();
213  p_ScannerManager->SetVerbose(verbose);
214 
215  // Get system name from the dataFile
216  string scanner_name = "";
217  if (ReadDataASCIIFile(path_to_data_filename, "Scanner name", &scanner_name, 1, KEYWORD_MANDATORY))
218  {
219  Cerr("***** castor-datafileExplorer() -> A problem occurred while trying to find the system name in the datafile header !" << endl);
220  Exit(EXIT_FAILURE);
221  }
222  if (p_ScannerManager->FindScannerSystem(scanner_name) )
223  {
224  Cerr("***** castor-datafileExplorer() -> A problem occurred while searching for scanner system !" << endl);
225  Exit(EXIT_FAILURE);
226  }
227  if (p_ScannerManager->BuildScannerObject() )
228  {
229  Cerr("***** castor-datafileExplorer() -> A problem occurred during scanner object construction ! !" << endl);
230  Exit(EXIT_FAILURE);
231  }
232  if (p_ScannerManager->InstantiateScanner() )
233  {
234  Cerr("***** castor-datafileExplorer() -> A problem occurred while creating Scanner object !" << endl);
235  Exit(EXIT_FAILURE);
236  }
237  if (p_ScannerManager->GetGeometricInfoFromDataFile(path_to_data_filename))
238  {
239  Cerr("***** castor-datafileExplorer() -> A problem occurred while retrieving scanner fields from the datafile header !" << endl);
240  Exit(EXIT_FAILURE);
241  }
242  if (p_ScannerManager->BuildLUT() )
243  {
244  Cerr("***** castor-datafileExplorer() -> A problem occurred while generating/reading the LUT !" << endl);
245  Exit(EXIT_FAILURE);
246  }
247  if (p_ScannerManager->CheckParameters())
248  {
249  Cerr("***** castor-datafileExplorer() -> A problem occurred while checking scanner manager parameters !" << endl);
250  Exit(EXIT_FAILURE);
251  }
252  if (p_ScannerManager->Initialize())
253  {
254  Cerr("***** castor-datafileExplorer() -> A problem occurred while initializing scanner !" << endl);
255  Exit(EXIT_FAILURE);
256  }
257 
258  // ----------------------------------------------------------------------------------------
259  // Create vDataFile
260  // ----------------------------------------------------------------------------------------
261 
262  // Create a default image dimensions and quantification object
264  p_ID->SetDefault();
265  p_ID->SetVerbose(verbose);
266  // Virtual datafile
267  vDataFile* p_DataFile = NULL;
268  // Create specific data file
269  if (p_ScannerManager->GetScannerType() == SCANNER_PET) p_DataFile = new iDataFilePET();
270  else if (p_ScannerManager->GetScannerType() == SCANNER_SPECT_CONVERGENT) p_DataFile = new iDataFileSPECT();
271  else if (p_ScannerManager->GetScannerType() == SCANNER_CT) p_DataFile = new iDataFileCT();
272  // Unknown scanner
273  else
274  {
275  Cerr("***** castor-datafileExplorer() -> Unknown scanner type (" << p_ScannerManager->GetScannerType() << ") for datafile construction ! Abort." << endl);
276  Exit(EXIT_FAILURE);
277  }
278  // Set data file name
279  p_DataFile->SetHeaderDataFileName(path_to_data_filename);
280  // Few parameters
281  p_DataFile->SetImageDimensionsAndQuantification(p_ID);
282  p_DataFile->SetBedIndex(0);
283  p_DataFile->SetVerbose(verbose);
284  // Read information from the header, without affecting the quantification (as no ImageDimensionsAndQuantification object is used here)
285  bool do_not_affect_quantification = false;
286  if (p_DataFile->ReadInfoInHeader(do_not_affect_quantification))
287  {
288  Cerr("***** castor-datafileExplorer() -> A problem occurred during datafile header reading ! Abort." << endl);
289  Exit(EXIT_FAILURE);
290  }
291  if (p_DataFile->CheckParameters())
292  {
293  Cerr("***** castor-datafileExplorer() -> A problem occurred while checking datafile parameters ! Abort." << endl);
294  Exit(EXIT_FAILURE);
295  }
296  if (p_DataFile->ComputeSizeEvent())
297  {
298  Cerr("***** castor-datafileExplorer() -> A problem occurred in datafile initialization ! Abort." << endl);
299  Exit(EXIT_FAILURE);
300  }
301  if (p_DataFile->InitializeMappedFile())
302  {
303  Cerr("***** castor-datafileExplorer() -> A problem occurred in datafile initialization ! Abort." << endl);
304  Exit(EXIT_FAILURE);
305  }
306  if (p_DataFile->PrepareDataFile())
307  {
308  Cerr("***** castor-datafileExplorer() -> A problem occurred in datafile preparation ! Abort." << endl);
309  Exit(EXIT_FAILURE);
310  }
311 
312  // Verbose
313  Cout("castor-datafileExplorer() -> End of initialization" << endl);
314  Cout("==============================================================" << endl);
315 
316  // ============================================================================================================
317  // Actions
318  // ============================================================================================================
319 
320  // -------------------------------------------------------------------
321  // Ask the datafile to describe itself
322  // -------------------------------------------------------------------
323  p_DataFile->Describe();
324  Cout("==============================================================" << endl);
325 
326  // -------------------------------------------------------------------
327  // Then if the event-by-event option is on, describe each event
328  // -------------------------------------------------------------------
329 
330  if (event_by_event_flag)
331  {
332  Cout("castor-datafileExplorer() -> Start exploration of all events" << endl);
333  // Get index start and stop
334  int64_t index_start = 0; int64_t index_stop = 0;
335  p_DataFile->GetEventIndexStartAndStop(&index_start, &index_stop);
336  // Launch the loop on all events
337  int64_t index = index_start;
338  while (index>=index_start && index<index_stop)
339  {
340  // Verbose
341  Cout("------------------------- Event index " << index << " -------------------------" << endl);
342  // Get the current event
343  vEvent* p_event = p_DataFile->GetEvent(index);
344  if (p_event==NULL)
345  {
346  Cerr("***** castor-datafileExplorer() -> An error occurred while getting the event from index " << index << " !" << endl);
347  Exit(EXIT_FAILURE);
348  }
349  // Describe the event
350  p_event->Describe();
351  // Interactive mode
352  if (interactive_flag)
353  {
354  // The user may provide a specific event index or simply press enter to get to the next
355  cout << "--------> Give an event index or simply press enter for next event: " << flush;
356  // Read the answer
357  string answer = ""; getline(cin,answer);
358  cout << endl;
359  // If empty answer, then go to the next event
360  if (answer=="") index++;
361  // Otherwise
362  else
363  {
364  // Convert the answer to int64_t
365  int64_t next_index = stoll(answer);
366  if (next_index<index_start || next_index>=index_stop)
367  {
368  Cerr("***** castor-datafileExplorer() -> The provided event index (" << next_index << ") is out of datafile range"
369  << " [" << index_start << ":" << index_stop << "[ !" << endl);
370  break;
371  }
372  else index = next_index;
373  }
374  }
375  else index++;
376  }
377  Cout("==============================================================" << endl);
378  }
379 
380  // -------------------------------------------------------------------
381  // Or perform a global exploration
382  // -------------------------------------------------------------------
383 
384  else if (global_flag)
385  {
386  // Verbose
387  Cout("castor-datafileExplorer() -> Start global exploration of all events" << endl);
388  // Progression (increments of 2%)
389  cout << "0 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%" << endl;
390  cout << "|----|----|----|----|----|----|----|----|----|----|" << endl;
391  cout << "|" << flush;
392  int progression_percentage_old = 0;
393  int progression_nb_bars = 0;
394  uint64_t progression_printing_index = 0;
395  // Get index start and stop
396  int64_t index_start = 0; int64_t index_stop = 0;
397  p_DataFile->GetEventIndexStartAndStop(&index_start, &index_stop);
398  // Cumulative values
399  HPFLTNB total_nb_data = 0.;
400  // Launch the loop on all events
401  for (int64_t index=index_start ; index<index_stop ; index++)
402  {
403  // Print progression
404  if (progression_printing_index%1000==0)
405  {
406  int progression_percentage_new = ((int)( (((float)(index-index_start+1))/((float)(index_stop-index_start)) ) * 100.));
407  if (progression_percentage_new>=progression_percentage_old+2) // Increments of 2%
408  {
409  int nb_steps = (progression_percentage_new-progression_percentage_old)/2;
410  for (int i=0; i<nb_steps; i++)
411  {
412  cout << "-" << flush;
413  progression_nb_bars++;
414  }
415  progression_percentage_old += nb_steps*2;
416  }
417  }
418  progression_printing_index++;
419  // Get the current event
420  vEvent* p_event = p_DataFile->GetEvent(index);
421  if (p_event==NULL)
422  {
423  Cerr("***** castor-datafileExplorer() -> An error occurred while getting the event from index " << index << " !" << endl);
424  Exit(EXIT_FAILURE);
425  }
426  // Number of data
427  for (INTNB b=0; b<p_event->GetNbValueBins(); b++) total_nb_data += ((HPFLTNB)(p_event->GetEventValue(b)));
428  }
429  // End of progression printing (do not log out with Cout here)
430  int progression_total_bars = 49;
431  for (int i=0; i<progression_total_bars-progression_nb_bars; i++) cout << "-";
432  cout << "|" << endl;
433  Cout(" --> Total number of data: " << total_nb_data << endl);
434  Cout("==============================================================" << endl);
435  }
436 
437  // ============================================================================================================
438  // End
439  // ============================================================================================================
440 
441  // Delete objects in the inverse order in which they were created
442  delete p_DataFile;
443 
444  // Ending
445  #ifdef CASTOR_MPI
446  MPI_Finalize();
447  #endif
448  return EXIT_SUCCESS;
449 }
This class is designed to be a mother virtual class for DataFile.
static sScannerManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
void GetEventIndexStartAndStop(int64_t *ap_indexStart, int64_t *ap_indexStop, int a_subsetNum=0, int a_NbSubsets=1)
#define Cerr(MESSAGE)
int CheckParameters()
Check the initialization of member variables Call the CheckSpecificParameters() function implemente...
int FindScannerSystem(string a_scannerName)
int BuildScannerObject()
Instantiate the specific scanner object related to the modality, and set verbosity of scanner object...
int ReadInfoInHeader(bool a_affectQuantificationFlag=true)
void SetVerbose(int a_verboseLevel)
int main(int argc, char **argv)
virtual int ComputeSizeEvent()=0
This function is implemented in child classes Computation of the size of each event according to th...
void Exit(int code)
int CheckParameters()
Check if all parameters have been correctly initialized, and call the CheckParameters function of the...
int InitializeMappedFile()
Check the datafile existency, map it to memory and get the raw char* pointer. .
int InstantiateScanner()
Instantiate scanner using the related function in the scanner classes.
vEvent * GetEvent(int64_t a_eventIndex, int a_th=0)
#define SCANNER_SPECT_CONVERGENT
int BuildLUT()
Call the eponym function of the scanner class.
Singleton class that Instantiate and initialize the scanner object.
virtual int PrepareDataFile()=0
This function is implemented in child classes Store different kind of information inside arrays (da...
Inherit from vDataFile. Class that manages the reading of a SPECT input file (header + data)...
void SetHeaderDataFileName(const string &a_headerFileName)
#define KEYWORD_MANDATORY
virtual FLTNB GetEventValue(int a_bin)=0
int Initialize()
Initialization : .
void SetBedIndex(int a_bedIndex)
virtual void Describe()=0
This function can be used to get a description of the event printed out.
void GetUserEndianness()
Check user/host computer endianness and write it to the global variable User_Endianness.
Mother class for the Event objects.
int ConvertFromString(const string &a_str, string *a_result)
Copy the &#39;a_str&#39; string in the position pointed by &#39;a_result&#39;.
Inherit from vDataFile. Class that manages the reading of a CT input file (header + data)...
void Describe()
A function used to describe the generic parts of the datafile.
This class is designed to manage all dimensions and quantification related stuff. ...
virtual INTNB GetNbValueBins()=0
Get the number of event value bins.
void SetVerbose(int a_verboseLevel)
void SetDefault()
A function used to set number of threads and MPI instances to 1 and bypass the CheckParameters() func...
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...
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
Inherit from vDataFile. Class that manages the reading of a PET input file (header + data)...
int GetGeometricInfoFromDataFile(string a_pathToDataFilename)
#define Cout(MESSAGE)