CASToR  3.2
Tomographic Reconstruction (PET/SPECT/CT)
toolkits/castor-makeReplicates.cc
Go to the documentation of this file.
1 
8 #include "gVariables.hh"
9 #include "gOptions.hh"
10 #include "oImageDimensionsAndQuantification.hh"
11 #include "vDataFile.hh"
12 #include "iDataFilePET.hh"
13 #include "iDataFileSPECT.hh"
14 #include "iDataFileCT.hh"
15 #include "sOutputManager.hh"
16 #include "sRandomNumberGenerator.hh"
17 
18 // =============================================================================================================================================
19 // =============================================================================================================================================
20 // =============================================================================================================================================
21 // H E L P F U N C T I O N S
22 // =============================================================================================================================================
23 // =============================================================================================================================================
24 // =============================================================================================================================================
25 
26 
31 void ShowHelp()
32 {
33  // Show help
34  cout << endl;
35  cout << "Usage: castor-makeReplicates -df datafile.cdh -(f/d)out output (-rep replicates || -down factor) [settings]" << endl;
36  cout << endl;
37  cout << "This program can be used to build replicates of less statistics than the provided input CASToR datafile by the use" << endl;
38  cout << "of the '-rep' options and choosing the number of replicates. It can also be used to create only one datafile by" << endl;
39  cout << "down-scaling the statistics by the use of the '-down' option. The input datafile is assumed to be a list-mode." << endl;
40  cout << endl;
41  cout << "If the '-rep' option is used, based on the provided number of replicates, the latter are built based on the time" << endl;
42  cout << "flag of each event: a pseudo gating strategy is used where each gate will correspond to a replicate. To avoid" << endl;
43  cout << "seeing a difference between replicates when a high number is required, the pseudo gate duration has to be as small" << endl;
44  cout << "as possible. The default value is thus 2 ms." << endl;
45  cout << endl;
46  cout << "If the '-down' option is used, based on the provided down-sampling factor ]0.;1.[, for each event, a random number" << endl;
47  cout << "is shot to decide whether the event is kept or not." << endl;
48  cout << "All additive corrections as well as the quantification factor are modified accordingly to keep the same image quantification." << endl;
49  cout << endl;
50  cout << "[Mandatory parameters]:" << endl;
51  cout << " -df datafile.cdh : Give a CASToR list-mode datafile." << endl;
52  cout << " -fout name : Give the root name for all output files (no default, alternative to -dout)" << endl;
53  cout << " -dout name : Give the name of the output directory where all output files will be written (no default, alternative to -fout)" << endl;
54  cout << " One of the two following options has to be chosen: " << endl;
55  cout << " -rep value : Give the number of replicates to be built using a pseudo-gating strategy." << endl;
56  cout << " -down value : Give the down-sampling factor to build only one file with less statistics ]0.;1.[." << endl;
57  cout << endl;
58  cout << "[Options]:" << endl;
59  cout << " -rng : Give a seed for the random number generator (should be >=0)" << endl;
60  cout << " -gate value : Give the pseudo gate duration in milliseconds (default: 2)" << endl;
61  cout << " -vb value : Give the verbosity level, from 0 (no verbose) to 2 (default: 1)" << endl;
62  cout << " --help,-h,-help : Print out this help page." << endl; // managed by main
63  cout << endl;
64  #ifdef BUILD_DATE
65  cout << " Build date: " << BUILD_DATE << endl;
66  cout << endl;
67  #endif
68  #ifdef CASTOR_VERSION
69  cout << " This program is part of the CASToR release version " << CASTOR_VERSION << "." << endl;
70  cout << endl;
71  #endif
72 }
73 
74 // =============================================================================================================================================
75 // =============================================================================================================================================
76 // =============================================================================================================================================
77 // M A I N P R O G R A M
78 // =============================================================================================================================================
79 // =============================================================================================================================================
80 // =============================================================================================================================================
81 
82 int main(int argc, char** argv)
83 {
84  // ============================================================================================================
85  // MPI stuff (we make all instances except the first one returning 0 directly)
86  // ============================================================================================================
87  int mpi_rank = 0;
88  #ifdef CASTOR_MPI
89  int mpi_size = 1;
90  MPI_Init(&argc, &argv);
91  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
92  MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
93  if (mpi_rank!=0) return 0;
94  #endif
95 
96  // No argument, then show help
97  if (argc==1)
98  {
99  ShowHelp();
100  Exit(EXIT_SUCCESS);
101  }
102 
103  // ============================================================================================================
104  // Parameterized variables with their default values
105  // ============================================================================================================
106 
107  // --------------------------------------------------------------------------------
108  // Input settings
109  // --------------------------------------------------------------------------------
110 
111  // Input datafile
112  string datafile = "";
113 
114  // --------------------------------------------------------------------------------
115  // Output settings
116  // --------------------------------------------------------------------------------
117 
118  // Output directory name.
119  string path_dout = "";
120  // Or root name
121  string path_fout = "";
122 
123  // --------------------------------------------------------------------------------
124  // Miscellaneous settings
125  // --------------------------------------------------------------------------------
126 
127  // Number of replicates to build
128  int nb_replicates = -1;
129  // Pseudo gate duration in ms (default: 2)
130  uint32_t gate_duration = 2;
131  // Down sampling factor
132  HPFLTNB down_sampling = -1.;
133  // Verbose level
134  int verbose = 1;
135  // Initial seed for random number generator
136  int64_t random_generator_seed = -1;
137 
138  // ============================================================================================================
139  // Read command-line parameters
140  // ============================================================================================================
141 
142  // Must manually increment the option index when an argument is needed after an option
143  for (int i=1; i<argc; i++)
144  {
145  // Get the option as a string
146  string option = (string)argv[i];
147 
148  // --------------------------------------------------------------------------------
149  // Miscellaneous settings
150  // --------------------------------------------------------------------------------
151 
152  // Show help
153  if (option=="-h" || option=="--help" || option=="-help")
154  {
155  ShowHelp();
156  Exit(EXIT_SUCCESS);
157  }
158  // RNG seed
159  else if (option=="-rng")
160  {
161  if (i>=argc-1)
162  {
163  Cerr("***** castor-makeReplicates() -> Argument missing for option: " << option << endl);
164  Exit(EXIT_FAILURE);
165  }
166  if (ConvertFromString(argv[i+1], &random_generator_seed))
167  {
168  Cerr("***** castor-makeReplicates() -> Exception when trying to read provided number '" << random_generator_seed << " for option: " << option << endl);
169  Exit(EXIT_FAILURE);
170  }
171  i++;
172  }
173  // Number of replicates to build
174  else if (option=="-rep")
175  {
176  if (i>=argc-1)
177  {
178  Cerr("***** castor-makeReplicates() -> Argument missing for option: " << option << endl);
179  Exit(EXIT_FAILURE);
180  }
181  if (ConvertFromString(argv[i+1], &nb_replicates))
182  {
183  Cerr("***** castor-makeReplicates() -> Exception when trying to read provided number of replicates '" << nb_replicates << " for option: " << option << endl);
184  Exit(EXIT_FAILURE);
185  }
186  i++;
187  }
188  // Pseudo gate duration in milliseconds
189  else if (option=="-gate")
190  {
191  if (i>=argc-1)
192  {
193  Cerr("***** castor-makeReplicates() -> Argument missing for option: " << option << endl);
194  Exit(EXIT_FAILURE);
195  }
196  if (ConvertFromString(argv[i+1], &gate_duration))
197  {
198  Cerr("***** castor-makeReplicates() -> Exception when trying to read provided pseudo gate duration '" << gate_duration << " for option: " << option << endl);
199  Exit(EXIT_FAILURE);
200  }
201  i++;
202  }
203  // Down sampling factor
204  else if (option=="-down")
205  {
206  if (i>=argc-1)
207  {
208  Cerr("***** castor-makeReplicates() -> Argument missing for option: " << option << endl);
209  Exit(EXIT_FAILURE);
210  }
211  if (ConvertFromString(argv[i+1], &down_sampling))
212  {
213  Cerr("***** castor-makeReplicates() -> Exception when trying to read provided down-sampling factor '" << down_sampling << " for option: " << option << endl);
214  Exit(EXIT_FAILURE);
215  }
216  i++;
217  }
218  // General verbosity level
219  else if (option=="-vb")
220  {
221  if (i>=argc-1)
222  {
223  Cerr("***** castor-makeReplicates() -> Argument missing for option: " << option << endl);
224  Exit(EXIT_FAILURE);
225  }
226  if (ConvertFromString(argv[i+1], &verbose))
227  {
228  Cerr("***** castor-makeReplicates() -> Exception when trying to read provided verbosity level '" << verbose << " for option: " << option << endl);
229  Exit(EXIT_FAILURE);
230  }
231  i++;
232  }
233 
234  // --------------------------------------------------------------------------------
235  // Input settings
236  // --------------------------------------------------------------------------------
237 
238  // Images
239  else if (option=="-df") // This is a mandatory option
240  {
241  if (i>=argc-1)
242  {
243  Cerr("***** castor-makeReplicates() -> Argument missing for option: " << option << endl);
244  Exit(EXIT_FAILURE);
245  }
246  datafile = (string)argv[i+1];
247  i++;
248  }
249 
250  // --------------------------------------------------------------------------------
251  // Output settings
252  // --------------------------------------------------------------------------------
253 
254  // Name of the output directory
255  else if (option=="-dout") // This is a mandatory option
256  {
257  if (i>=argc-1)
258  {
259  Cerr("***** castor-makeReplicates() -> Argument missing for option: " << option << endl);
260  Exit(EXIT_FAILURE);
261  }
262  path_dout = argv[i+1];
263  i++;
264  }
265  // Base name of the output files
266  else if (option=="-fout") // This is a mandatory option
267  {
268  if (i>=argc-1)
269  {
270  Cerr("***** castor-makeReplicates() -> Argument missing for option: " << option << endl);
271  Exit(EXIT_FAILURE);
272  }
273  path_fout = argv[i+1];
274  i++;
275  }
276 
277  // --------------------------------------------------------------------------------
278  // Unknown option!
279  // --------------------------------------------------------------------------------
280 
281  else
282  {
283  Cerr("***** castor-makeReplicates() -> Unknown option '" << option << "' !" << endl);
284  Exit(EXIT_FAILURE);
285  }
286  }
287 
288  // ============================================================================================================
289  // Some checks
290  // ============================================================================================================
291 
292  // Data file
293  if (datafile=="")
294  {
295  Cerr("***** castor-makeReplicates() -> Please provide an input datafile !" << endl);
296  Exit(EXIT_FAILURE);
297  }
298  // Output files
299  if (path_fout.empty() && path_dout.empty())
300  {
301  Cerr("***** castor-makeReplicates() -> Please provide an output option for output files (-fout or -dout) !" << endl);
302  Exit(EXIT_FAILURE);
303  }
304  // Check that only one option has been provided
305  if (!path_fout.empty() && !path_dout.empty())
306  {
307  Cerr("***** castor-makeReplicates() -> Please provide either output option -fout or -dout but not both !" << endl);
308  Exit(EXIT_FAILURE);
309  }
310  // Check that at least a number of replicates or a down sampling factor has been provided
311  if (nb_replicates==-1 && down_sampling==-1.)
312  {
313  Cerr("***** castor-makeReplicates() -> Please provide one of the two following options '-rep' or '-down' !" << endl);
314  Exit(EXIT_FAILURE);
315  }
316  // Check number of replicates when no down-sampling factor is provided
317  if (down_sampling==-1. && nb_replicates<1)
318  {
319  Cerr("***** castor-makeReplicates() -> Please provide a correct number of replicates (at least 2) !" << endl);
320  Exit(EXIT_FAILURE);
321  }
322  // Check pseudo gate duration when no down-sampling factor is provided
323  if (down_sampling==-1. && gate_duration<1)
324  {
325  Cerr("***** castor-makeReplicates() -> Please provide a correct pseudo gate duration in milliseconds (at least 1) !" << endl);
326  Exit(EXIT_FAILURE);
327  }
328  // Check dow sampling factor when no number of replicates is provided
329  if (nb_replicates==-1 && (down_sampling<=0. || down_sampling>=1.))
330  {
331  Cerr("***** castor-makeReplicates() -> Please provide a correct down-sampling factor ]0.;1.[ !" << endl);
332  Exit(EXIT_FAILURE);
333  }
334 
335  // ============================================================================================================
336  // Create sOutputManager
337  // ============================================================================================================
338  sOutputManager* p_OutputManager = sOutputManager::GetInstance();
339  // Set verbose level
340  p_OutputManager->SetVerbose(verbose);
341  // Set MPI rank
342  p_OutputManager->SetMPIRank(mpi_rank);
343  // Initialize output directory and base name
344  if (p_OutputManager->InitOutputDirectory(path_fout, path_dout))
345  {
346  Cerr("***** castor-makeReplicates() -> A problem occurred while initializing output directory !" << endl);
347  Exit(EXIT_FAILURE);
348  }
349  // Log command line
350  if (p_OutputManager->LogCommandLine(argc,argv))
351  {
352  Cerr("***** castor-makeReplicates() -> A problem occurred while logging command line arguments !" << endl);
353  Exit(EXIT_FAILURE);
354  }
355 
356  // ============================================================================================================
357  // Random number generator
358  // ============================================================================================================
359 
360  sRandomNumberGenerator* p_RandomNumberGenerator = sRandomNumberGenerator::GetInstance();
361  p_RandomNumberGenerator->SetVerbose(verbose);
362  // Use a user-provided seed to initialize the RNG if one has been provided. Use random number otherwise.
363  int no_thread = 0;
364  int one_generator = 1;
365  if (random_generator_seed>=0) p_RandomNumberGenerator->Initialize(random_generator_seed, no_thread, one_generator);
366  else p_RandomNumberGenerator->Initialize(no_thread, one_generator);
367 
368  // ============================================================================================================
369  // Create sScannerManager (in order to get the datafile type)
370  // ============================================================================================================
371  sScannerManager* p_ScannerManager = sScannerManager::GetInstance();
372  p_ScannerManager->SetVerbose(verbose);
373  // Get system name from the dataFile
374  string scanner_name = "";
375  if (ReadDataASCIIFile(datafile, "Scanner name", &scanner_name, 1, KEYWORD_MANDATORY))
376  {
377  Cerr("***** castor-makeReplicates() -> A problem occurred while trying to find the system name in the datafile header !" << endl);
378  Exit(EXIT_FAILURE);
379  }
380  if (p_ScannerManager->FindScannerSystem(scanner_name) )
381  {
382  Cerr("***** castor-makeReplicates() -> A problem occurred while searching for scanner system !" << endl);
383  Exit(EXIT_FAILURE);
384  }
385  if (p_ScannerManager->BuildScannerObject() )
386  {
387  Cerr("***** castor-makeReplicates() -> A problem occurred during scanner object construction ! !" << endl);
388  Exit(EXIT_FAILURE);
389  }
390  if (p_ScannerManager->InstantiateScanner() )
391  {
392  Cerr("***** castor-makeReplicates() -> A problem occurred while creating Scanner object !" << endl);
393  Exit(EXIT_FAILURE);
394  }
395  if (p_ScannerManager->GetGeometricInfoFromDataFile(datafile))
396  {
397  Cerr("***** castor-makeReplicates() -> A problem occurred while retrieving scanner fields from the datafile header !" << endl);
398  Exit(EXIT_FAILURE);
399  }
400  if (p_ScannerManager->BuildLUT() )
401  {
402  Cerr("***** castor-makeReplicates() -> A problem occurred while generating/reading the LUT !" << endl);
403  Exit(EXIT_FAILURE);
404  }
405 
406  // ============================================================================================================
407  // Create the input datafile
408  // ============================================================================================================
409 
410  // Create a default image dimensions and quantification object
412  p_ID->SetDefault();
413  p_ID->SetVerbose(verbose);
414  // Create the datafile based on the data type
415  vDataFile* p_DataFile = NULL;
416  if (p_ScannerManager->GetScannerType() == SCANNER_PET) p_DataFile = new iDataFilePET();
417  else if (p_ScannerManager->GetScannerType() == SCANNER_SPECT_CONVERGENT) p_DataFile = new iDataFileSPECT();
418  else if (p_ScannerManager->GetScannerType() == SCANNER_CT) p_DataFile = new iDataFileCT();
419  else
420  {
421  Cerr("***** castor-makeReplicates() -> Unknown scanner type (" << p_ScannerManager->GetScannerType() << ") for datafile construction ! Abort." << endl);
422  Exit(EXIT_FAILURE);
423  }
424  p_DataFile->SetImageDimensionsAndQuantification(p_ID);
425  p_DataFile->SetHeaderDataFileName(datafile);
426  p_DataFile->SetVerbose(verbose);
427  p_DataFile->SetBedIndex(0);
428  bool do_not_affect_quantification = false;
429  if (p_DataFile->ReadInfoInHeader(do_not_affect_quantification))
430  {
431  Cerr("***** castor-makeReplicates() -> A problem occurred during datafile header reading ! Abort." << endl);
432  Exit(EXIT_FAILURE);
433  }
434  if (p_DataFile->CheckParameters())
435  {
436  Cerr("***** castor-makeReplicates() -> A problem occurred while checking datafile parameters ! Abort." << endl);
437  Exit(EXIT_FAILURE);
438  }
439  if (p_DataFile->ComputeSizeEvent())
440  {
441  Cerr("***** castor-makeReplicates() -> A problem occurred in datafile initialization ! Abort." << endl);
442  Exit(EXIT_FAILURE);
443  }
444  if (p_DataFile->InitializeMappedFile())
445  {
446  Cerr("***** castor-makeReplicates() -> A problem occurred in datafile initialization ! Abort." << endl);
447  Exit(EXIT_FAILURE);
448  }
449  if (p_DataFile->PrepareDataFile())
450  {
451  Cerr("***** castor-makeReplicates() -> A problem occurred in datafile preparation ! Abort." << endl);
452  Exit(EXIT_FAILURE);
453  }
454  // Check if datafile is a listmode, otherwise, throw an error
455  if (p_DataFile->GetDataMode()!=MODE_LIST)
456  {
457  Cerr("***** castor-makeReplicates() -> The input datafile is not a list-mode, this program is only suitable to list-mode files !" << endl);
458  Exit(EXIT_FAILURE);
459  }
460 
461  // ============================================================================================================
462  // Pseudo-gating mode
463  // ============================================================================================================
464 
465  if (down_sampling==-1.)
466  {
467  // --------------------------------------------------
468  // Initialization part
469  // --------------------------------------------------
470  // Create output datafiles
471  vDataFile** pp_OutputDataFile = (vDataFile**)malloc(nb_replicates*sizeof(vDataFile*));
472  for (int rep=0; rep<nb_replicates; rep++)
473  {
474  if (p_ScannerManager->GetScannerType() == SCANNER_PET) pp_OutputDataFile[rep] = new iDataFilePET();
475  else if (p_ScannerManager->GetScannerType() == SCANNER_SPECT_CONVERGENT) pp_OutputDataFile[rep] = new iDataFileSPECT();
476  else if (p_ScannerManager->GetScannerType() == SCANNER_CT) pp_OutputDataFile[rep] = new iDataFileCT();
477  // Build output data file from the input one
478  if (pp_OutputDataFile[rep]->SetParametersFrom(p_DataFile))
479  {
480  Cerr("***** castor-makeReplicates() -> An error occurred while setting parameters of output file from input file (replicate " << rep+1 << ") !" << endl);
481  Exit(EXIT_FAILURE);
482  }
483  // Build a suffix for the filename based on the replicate number
484  char tmp[128]; sprintf(tmp,"%d",rep+1); string rep_suffix = "_" + ((string)tmp);
485  // Open output file
486  if (pp_OutputDataFile[rep]->OpenFileForWriting(rep_suffix))
487  {
488  Cerr("***** castor-makeReplicates() -> An error occurred while opening file for writing (replicate " << rep+1 << ") !" << endl);
489  Exit(EXIT_FAILURE);
490  }
491  }
492  // --------------------------------------------------
493  // Processing part
494  // --------------------------------------------------
495  // Verbose
496  if (verbose>=1) Cout("castor-makeReplicates() -> Start pseudo-replicating input datafile with " << nb_replicates << " replicates ..." << endl);
497  if (verbose>=2) Cout(" --> Use a pseudo-gate duration of " << gate_duration << " ms" << endl);
498  // Counters
499  int64_t* nb_events_per_rep = (int64_t*)calloc(nb_replicates,sizeof(int64_t));
500  int64_t total_events = 0;
501  // Pseudo gating management
502  int current_replicate = 0;
503  uint32_t current_replicate_time = 0;
504  // Get index start and stop
505  int64_t index_start = 0; int64_t index_stop = 0;
506  p_DataFile->GetEventIndexStartAndStop(&index_start, &index_stop);
507  // Launch the loop on all events
508  int64_t printing_index = 0;
509  for (int64_t index = index_start ; index < index_stop ; index++)
510  {
511  // Verbose
512  if (verbose>=2)
513  {
514  if (printing_index%10000==0)
515  {
516  int percent = ((int)( ((FLTNB)(index-index_start)) * 100. / ((FLTNB)(index_stop-index_start)) ));
517  cout << "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b "
518  << percent << " % " << flush;
519  }
520  printing_index++;
521  }
522  // Get the current event
523  vEvent* event = p_DataFile->GetEvent(index);
524  if (event==NULL)
525  {
526  Cerr("***** castor-makeReplicates() -> An error occurred while getting the event from index " << index << " !" << endl);
527  for (int rep=0; rep<nb_replicates; rep++)
528  if (pp_OutputDataFile[rep]->CloseFile())
529  Cerr("***** castor-makeReplicates() -> An error occurred while closing file during writing (replicate " << rep+1 << ") !" << endl);
530  Exit(EXIT_FAILURE);
531  }
532  // Increment the total number of events
533  total_events++;
534  // Get time for this event
535  uint32_t this_time = event->GetTimeInMs();
536  // Check if the time for this event has passed the current replicate time of more than the gate duration
537  if (this_time >= current_replicate_time + gate_duration)
538  {
539  // Compute the time difference
540  uint32_t time_difference = this_time - current_replicate_time;
541  // Compute the number of gates/replicates passed
542  uint32_t nb_replicates_passed = time_difference / gate_duration;
543  // Update the reference time
544  current_replicate_time += nb_replicates_passed * gate_duration;
545  // Update the current gate/replicate
546  current_replicate = (current_replicate + nb_replicates_passed) % nb_replicates;
547  }
548  // Increment the current gate/replicate count
549  nb_events_per_rep[current_replicate]++;
550  // Apply down sampling factor to additive corrections
551  event->MultiplyAdditiveCorrections(1./((FLTNB)nb_replicates));
552  // Write the event to the current gate/replicate
553  pp_OutputDataFile[current_replicate]->WriteEvent(event);
554  }
555  if (verbose>=2) cout << "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
556  << " --> 100 % " << endl;
557  // --------------------------------------------------
558  // Conclusion part
559  // --------------------------------------------------
560  // Loop on replicates
561  for (int rep=0; rep<nb_replicates; rep++)
562  {
563  // Close file
564  if (pp_OutputDataFile[rep]->CloseFile())
565  {
566  Cerr("***** castor-makeReplicates() -> An error occurred while closing file after writing (replicate " << rep+1 << ") !" << endl);
567  Exit(EXIT_FAILURE);
568  }
569  // Set number of events
570  pp_OutputDataFile[rep]->SetNbEvents(nb_events_per_rep[rep]);
571  // Apply dow sampling factor onto the calibration factor
572  pp_OutputDataFile[rep]->SetCalibrationFactor(p_DataFile->GetCalibrationFactor()*((FLTNB)nb_replicates));
573  }
574  // Verbose
575  if (verbose>=2)
576  {
577  Cout("castor-makeReplicates() -> Here are some events statistics:" << endl);
578  Cout(" --> Total number of events: " << total_events << endl);
579  for (int rep=0; rep<nb_replicates; rep++) Cout(" --> Number of events for replicate " << rep+1 << ": " << nb_events_per_rep[rep] << endl);
580  }
581  // Loop on replicates
582  for (int rep=0; rep<nb_replicates; rep++)
583  {
584  // Write header
585  if (pp_OutputDataFile[rep]->WriteHeader())
586  {
587  Cerr("***** castor-makeReplicates() -> An error occurred while writing output header file (replicate " << rep+1 << ") !" << endl);
588  Exit(EXIT_FAILURE);
589  }
590  }
591  }
592 
593  // ============================================================================================================
594  // Down sampling mode
595  // ============================================================================================================
596 
597  if (nb_replicates==-1)
598  {
599  // --------------------------------------------------
600  // Initialization part
601  // --------------------------------------------------
602  // Create output datafile
603  vDataFile* p_OutputDataFile = NULL;
604  if (p_ScannerManager->GetScannerType() == SCANNER_PET) p_OutputDataFile = new iDataFilePET();
605  else if (p_ScannerManager->GetScannerType() == SCANNER_SPECT_CONVERGENT) p_OutputDataFile = new iDataFileSPECT();
606  else if (p_ScannerManager->GetScannerType() == SCANNER_CT) p_OutputDataFile = new iDataFileCT();
607  // Build output data file from the input one
608  if (p_OutputDataFile->SetParametersFrom(p_DataFile))
609  {
610  Cerr("***** castor-makeReplicates() -> An error occurred while setting parameters of output file from input file !" << endl);
611  Exit(EXIT_FAILURE);
612  }
613  // Open output file
614  if (p_OutputDataFile->OpenFileForWriting())
615  {
616  Cerr("***** castor-makeReplicates() -> An error occurred while opening file for writing !" << endl);
617  Exit(EXIT_FAILURE);
618  }
619  // --------------------------------------------------
620  // Processing part
621  // --------------------------------------------------
622  // Verbose
623  if (verbose>=1) Cout("castor-makeReplicates() -> Start down-sampling input datafile with factor " << down_sampling << " ..." << endl);
624  // Counters
625  int64_t kept_events = 0, rejected_events = 0;
626  // Get index start and stop
627  int64_t index_start = 0; int64_t index_stop = 0;
628  p_DataFile->GetEventIndexStartAndStop(&index_start, &index_stop);
629  // Launch the loop on all events
630  int64_t printing_index = 0;
631  for (int64_t index = index_start ; index < index_stop ; index++)
632  {
633  // Verbose
634  if (verbose>=2)
635  {
636  if (printing_index%10000==0)
637  {
638  int percent = ((int)( ((FLTNB)(index-index_start)) * 100. / ((FLTNB)(index_stop-index_start)) ));
639  cout << "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b "
640  << percent << " % " << flush;
641  }
642  printing_index++;
643  }
644  // Get the current event
645  vEvent* event = p_DataFile->GetEvent(index);
646  if (event==NULL)
647  {
648  Cerr("***** castor-makeReplicates() -> An error occurred while getting the event from index " << index << " !" << endl);
649  if (p_OutputDataFile->CloseFile())
650  Cerr("***** castor-makeReplicates() -> An error occurred while closing file during writing !" << endl);
651  Exit(EXIT_FAILURE);
652  }
653  // Shoot a random number
654  HPFLTNB chance = p_RandomNumberGenerator->GenerateExtraRdmNber(0);
655  // Continue to next event or not ?
656  if (chance>down_sampling)
657  {
658  rejected_events++;
659  continue;
660  }
661  // Apply down sampling factor to additive corrections
662  event->MultiplyAdditiveCorrections(down_sampling);
663  // Write the event
664  p_OutputDataFile->WriteEvent(event);
665  kept_events++;
666  }
667  if (verbose>=2) cout << "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
668  << " --> 100 % " << endl;
669  // --------------------------------------------------
670  // Conclusion part
671  // --------------------------------------------------
672  // CLose file
673  if (p_OutputDataFile->CloseFile())
674  {
675  Cerr("***** castor-makeReplicates() -> An error occurred while closing file after writing !" << endl);
676  Exit(EXIT_FAILURE);
677  }
678  // Set number of events
679  p_OutputDataFile->SetNbEvents(kept_events);
680  // Apply dow sampling factor onto the calibration factor
681  p_OutputDataFile->SetCalibrationFactor(p_DataFile->GetCalibrationFactor()/down_sampling);
682  // Verbose
683  if (verbose>=2)
684  {
685  int64_t total_events = kept_events + rejected_events;
686  Cout("castor-makeReplicates() -> Here are some events statistics:" << endl);
687  Cout(" --> Total number of events: " << total_events << endl);
688  Cout(" --> Kept events: " << kept_events << endl);
689  Cout(" --> Rejected events: " << rejected_events << endl);
690  Cout(" --> Effective down-sampling factor: " << ((double)kept_events) / ((double)total_events) << endl);
691  }
692  // Write header
693  if (p_OutputDataFile->WriteHeader())
694  {
695  Cerr("***** castor-makeReplicates() -> An error occurred while writing output header file !" << endl);
696  Exit(EXIT_FAILURE);
697  }
698  }
699 
700  // ============================================================================================================
701  // Free memory properly
702  // ============================================================================================================
703 
704  // Ending
705  #ifdef CASTOR_MPI
706  MPI_Finalize();
707  #endif
708  return EXIT_SUCCESS;
709 }
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)
static sRandomNumberGenerator * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
#define Cerr(MESSAGE)
int CheckParameters()
Check the initialization of member variables Call the CheckSpecificParameters() function implemente...
virtual int WriteHeader()=0
This function is implemented in child classes. Generate a header file according to the data output ...
int FindScannerSystem(string a_scannerName)
int BuildScannerObject()
Instantiate the specific scanner object related to the modality, and set verbosity of scanner object...
int SetParametersFrom(vDataFile *ap_DataFile)
virtual int WriteEvent(vEvent *ap_Event, int a_th=0)=0
int ReadInfoInHeader(bool a_affectQuantificationFlag=true)
void SetVerbose(int a_verboseLevel)
HPFLTNB GenerateExtraRdmNber(int a_nb=0)
Generate a random number using the specified additional not thread safe random generator, for use in sequential parts of an otherwise multithreaded code.
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)
void SetVerbose(int a_verboseLevel)
Set verbosity level.
static sOutputManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
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.
int LogCommandLine(int argc, char **argv)
vEvent * GetEvent(int64_t a_eventIndex, int a_th=0)
int CloseFile()
Close as many binary file stream for writing.
#define SCANNER_SPECT_CONVERGENT
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...
Singleton class that Instantiate and initialize the scanner object.
void SetCalibrationFactor(FLTNB a_value)
int Initialize(int a_nbThreads, int a_nbExtra)
Instantiate pseudo random number generators, one per thread by default, and additional extra ones if ...
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)
int OpenFileForWriting(string a_suffix="")
int main(int argc, char **argv)
#define KEYWORD_MANDATORY
Singleton class that generate a thread-safe random generator number for openMP As singleton...
void SetNbEvents(int64_t a_value)
void SetBedIndex(int a_bedIndex)
Mother class for the Event objects.
int InitOutputDirectory(const string &a_pathFout, const string &a_pathDout)
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)...
This class is designed to manage all dimensions and quantification related stuff. ...
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)