CASToR  3.2
Tomographic Reconstruction (PET/SPECT/CT)
code/toolkits/castor-datafileConversionEx.cc
Go to the documentation of this file.
1 
16 #include "gVariables.hh"
17 #include "gOptions.hh"
18 #include "iDataFilePET.hh"
19 #include "sOutputManager.hh"
20 #include "sScannerManager.hh"
21 #include <iomanip> //std::setprecision
22 
23 #ifdef CASTOR_ROOT
24  #ifdef _WIN32
25  #include "Windows4Root.h"
26  #endif
27  #include "TROOT.h"
28  #include "TApplication.h"
29  #include "TGClient.h"
30  #include "TCanvas.h"
31  #include "TSystem.h"
32  #include "TTree.h"
33  #include "TBranch.h"
34  #include "TFile.h"
35 #endif
36 
41 void ShowHelp(int a_returnCode)
42 {
43  cout << endl;
44  cout << "NOTE : This program is an example code providing guidance regarding how to generate a PET CASToR datafile from any system datafile " << endl;
45  cout << " It does NOT perform any conversion by itself and must be adjusted to the conversion of any system dataset !" << endl;
46  cout << endl;
47  cout << endl;
48  cout << "Usage: castor-datafileConversionEx -ih input_datafile : (if datafile is histogram mode)" << endl;
49  cout << " -il input_datafile : (if datafile is list-mode)" << endl;
50  cout << " -o output_datafile" << endl;
51  cout << " -s scanner_alias "<< endl;
52  cout << " [-nc norm_factors_file" << endl;
53  cout << " [-sc scat_factors_file" << endl;
54  cout << " [-rc rdm_factors_file" << endl;
55  cout << " [-ac atn_factors_file" << endl;
56  cout << " [-cf calibration factor" << endl;
57  cout << " [-ist isotope_alias" << endl;
58  //cout << " [-poi flag for POI]" << endl;
59  //cout << " [-tof flag for TOF]" << endl;
60  cout << " [-vb verbosity]" << endl;
61  cout << endl;
62  cout << endl;
63  cout << "[Main settings]:" << endl;
64  cout << " -ih path_to_histo_datafile : provide an input histogram datafile to convert" << endl;
65  cout << " -il path_to_listm_datafile : provide an input list-mode datafile to convert" << endl;
66  cout << " -o path_to_cstr_file.cdh : provide the path to the output file will be created inside this folder (no default)" << endl;
67  cout << " -s scanner_alias : provide the name of the scanner used for to acquire the original data" << endl;
68  cout << " : Must correspond to a .geom or .hscan file in the config/scanner repository." << endl;
69  cout << endl;
70  cout << "[Optional settings]:" << endl;
71  cout << " -nc norm_factors_file : provide a file containing normalization correction factors" << endl;
72  cout << " -sc scat_factors_file : provide a file containing scatter correction factors" << endl;
73  cout << " -rc rdm_factors_file : provide a file containing random correction factors" << endl;
74  cout << " -ac atn_factors_file : provide a file containing attenuation correction factors" << endl;
75  cout << " -cf calibration factor : provide a calibration factor" << endl;
76  cout << " -ist isotope_alias : provide alias of the isotope used in the input datafile"<< endl;
77  cout << " Supported PET isotopes and their parameters are listed in config/misc/isotopes_pet"<< endl;
78  cout << " Other isotopes can be added in the same file"<< endl;
79  cout << endl;
80  cout << "[Miscellaneous settings]:" << endl;
81  cout << " -vb : give the verbosity level, from 0 (no verbose) to above 5 (at the event level) (default: 1)." << endl;
82  cout << endl;
83  #ifdef CASTOR_VERSION
84  cout << " This program is part of the CASToR release version " << CASTOR_VERSION << "." << endl;
85  cout << endl;
86  #endif
87  Exit(a_returnCode);
88 }
89 
90 
91 /*
92  Main program
93 */
94 int main(int argc, char** argv)
95 {
96  // ============================================================================================================
97  // MPI stuff (we make all instances but the first one returning 0 directly)
98  // ============================================================================================================
99  #ifdef CASTOR_MPI
100  int mpi_rank = 0;
101  int mpi_size = 1;
102  MPI_Init(&argc, &argv);
103  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
104  MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
105  if (mpi_rank!=0) return 0;
106  #endif
107 
108  // No argument, then show help
109  if (argc==1) ShowHelp(0);
110 
111  // ============================================================================================================
112  // Parameterized variables with their default values
113  // ============================================================================================================
114 
115  // String containing the path to the input data filename provided by the user
116  string path_to_input_file = "";
117 
118  // DataFile mode (histogram or list (default)
119  int data_mode = MODE_LIST;
120 
121  // Path to user provided data
122  string path_to_out_file = "";
123  string path_to_data_file = "";
124  string path_to_header_file = "";
125  string path_to_norm_file = "";
126  string path_to_scat_file = "";
127  string path_to_rdm_file = "";
128  string path_to_acf_file = "";
129  FLTNB calib_factor = 1.;
130 
131  string scanner_alias = "";
132  string istp_alias = "";
133 
134  // Verbosity
135  int vb = 1;
136 
137  // Input datafile is histogram
138  bool is_histogram_flag = 0;
139 
140 
141  // ============================================================================================================
142  // Read command-line parameters
143  // ============================================================================================================
144 
145  for (int i=1; i<argc; i++)
146  {
147  string option = (string)argv[i];
148 
149  // Provide an histogram datafile to convert
150  if (option=="-ih")
151  {
152  if (!path_to_input_file.empty())
153  {
154  Cerr("***** castor-datafileConversionEx :: the following file names have already been provided (either -ih or -il option must be used): " << endl);
155  Cout(path_to_input_file << endl);
156  Exit(EXIT_FAILURE);
157  }
158  else
159  {
160  if (argv[i+1] == NULL)
161  {
162  Cerr("***** castor-datafileConversionEx :: argument missing for option: " << option << endl);
163  Exit(EXIT_FAILURE);
164  }
165  else
166  path_to_input_file = (string)argv[i+1];
167 
168  data_mode = MODE_HISTOGRAM;
169  i++;
170  }
171  }
172 
173  // Provide a list-mode datafile to convert
174  if (option=="-il")
175  {
176  if (!path_to_input_file.empty())
177  {
178  Cerr("***** castor-datafileConversionEx :: the following file names have already been provided (either -ih or -il option must be used): " << endl);
179  Cout(path_to_input_file << endl);
180  Exit(EXIT_FAILURE);
181  }
182  else
183  {
184  if (argv[i+1] == NULL)
185  {
186  Cerr("***** castor-datafileConversionEx :: argument missing for option: " << option << endl);
187  Exit(EXIT_FAILURE);
188  }
189  else
190  path_to_input_file = (string)argv[i+1];
191 
192  data_mode = MODE_LIST;
193  i++;
194  }
195  }
196 
197  // Output CASToR datafile
198  else if (option=="-o")
199  {
200  if (argv[i+1] == NULL)
201  {
202  Cerr("***** castor-datafileConversionEx :: argument missing for option: " << option << endl);
203  Exit(EXIT_FAILURE);
204  }
205  else
206  path_to_out_file = (string)argv[i+1];
207  i++;
208  }
209 
210  // Scanner alias
211  else if (option=="-s")
212  {
213  if (argv[i+1] == NULL)
214  {
215  Cerr("***** castor-datafileConversionEx :: argument missing for option: " << option << endl);
216  Exit(EXIT_FAILURE);
217  }
218  else
219  scanner_alias = (string)argv[i+1];
220  i++;
221  }
222 
223  // Provide a norm correction file
224  else if (option=="-nc")
225  {
226  if (argv[i+1] == NULL)
227  {
228  Cerr("***** castor-datafileConversionEx :: argument missing for option: " << option << endl);
229  Exit(EXIT_FAILURE);
230  }
231  else
232  path_to_norm_file = (string)argv[i+1];
233 
234  i++;
235  }
236 
237  // Provide a scatter correction file
238  else if (option=="-sc")
239  {
240  if (argv[i+1] == NULL)
241  {
242  Cerr("***** castor-datafileConversionEx :: argument missing for option: " << option << endl);
243  Exit(EXIT_FAILURE);
244  }
245  else
246  path_to_scat_file = (string)argv[i+1];
247 
248  i++;
249  }
250 
251  // Provide a rdm correction file
252  else if (option=="-rc")
253  {
254  if (argv[i+1] == NULL)
255  {
256  Cerr("***** castor-datafileConversionEx :: argument missing for option: " << option << endl);
257  Exit(EXIT_FAILURE);
258  }
259  else
260  path_to_rdm_file = (string)argv[i+1];
261 
262  i++;
263  }
264 
265  // Provide an acf correction file
266  else if (option=="-ac")
267  {
268  if (argv[i+1] == NULL)
269  {
270  Cerr("***** castor-datafileConversionEx :: argument missing for option: " << option << endl);
271  Exit(EXIT_FAILURE);
272  }
273  else
274  path_to_acf_file = (string)argv[i+1];
275 
276  i++;
277  }
278 
279  // Provide a calibration factor
280  else if (option=="-cf")
281  {
282  if (argv[i+1] == NULL)
283  {
284  Cerr("***** castor-datafileConversionEx :: argument missing for option: " << option << endl);
285  Exit(EXIT_FAILURE);
286  }
287  else
288  {
289  string val_str = (string)argv[i+1];
290  if(ConvertFromString(val_str, &calib_factor) )
291  {
292  Cerr("***** castor-datafileConversionEx :: Exception when trying to read'" << val_str << " for option: " << option << endl);
293  Exit(EXIT_FAILURE);
294  }
295  }
296  i++;
297  }
298 
299  // Provide an isotope alias
300  else if (option=="-ist")
301  {
302  if (argv[i+1] == NULL)
303  {
304  Cerr("***** castor-datafileConversionEx :: argument missing for option: " << option << endl);
305  Exit(EXIT_FAILURE);
306  }
307  else
308  istp_alias = (string)argv[i+1];
309 
310  i++;
311  }
312 
313  // Verbosity level
314  else if (option=="-vb")
315  {
316  if (i>=argc-1)
317  {
318  Cerr("***** castor-datafileConversionEx :: Argument missing for option: " << option << endl);
319  Exit(EXIT_FAILURE);
320  }
321  vb = atoi(argv[i+1]);
322  i++;
323  }
324 
325  else
326  {
327  Cerr("***** castor-datafileConversionEx :: Unknown option '" << option << "' !" << endl);
328  Exit(EXIT_FAILURE);
329  }
330  }
331 
332 
333  // ============================================================================================================
334  // Basic initialization checks (minimal initializations mandatory for the next steps)
335  // ============================================================================================================
336 
337  // data files
338  if (path_to_input_file.empty() )
339  {
340  Cerr("***** castor-datafileConversionEx :: Please provide at least one data filename (-ih for histogram, -il for list-mode)" << endl);
341  cout << " -input filename : give an input datafile (no default)." << endl;
342  Exit(EXIT_FAILURE);
343  }
344 
345  // output directory
346  if (path_to_out_file.empty() )
347  {
348  Cerr("***** castor-datafileConversionEx :: Please provide the output file name (-o)" << endl);
349  Exit(EXIT_FAILURE);
350  }
351 
352  // scanner
353  if (scanner_alias.empty())
354  {
355  Cerr("***** castor-datafileConversionEx :: Please provide a scanner alias (-s) :" << endl);
356  Cout(" It must correspond to a .geom or .hscan (user-made LUT) file in the config/scanner directory." << endl);
357  ShowHelp(0);
358  Exit(EXIT_FAILURE);
359  }
360 
361  // Throw error by default.
362  // These two lines must be erased when implementing any datafile converter!
363  //Cerr("castor-GATERootToCastor :: This script is only for demonstration purposes " << endl);
364  //Exit(EXIT_FAILURE);
365 
366 
367  // ============================================================================================================
368  // SOutputManager object initialisation:
369  // (Used for log file)
370  // ============================================================================================================
371 
372  sOutputManager* p_outputManager = sOutputManager::GetInstance();
373  // Set verbose level
374  p_outputManager->SetVerbose(vb);
375  // Set MPI rank
376  p_outputManager->SetMPIRank(0);
377 
378  // Set path to the config directory
379  if (p_outputManager->CheckConfigDir(""))
380  {
381  Cerr("***** castor-datafileConversionEx :: A problem occurred while checking for the config directory path !" << endl);
382  Exit(EXIT_FAILURE);
383  }
384  // Initialize output directory and base name
385  if (p_outputManager->InitOutputDirectory(path_to_out_file, ""))
386  {
387  Cerr("***** castor-datafileConversionEx :: A problem occurred while initializing output directory !" << endl);
388 
389  Exit(EXIT_FAILURE);
390  }
391  // Log command line
392  if (p_outputManager->LogCommandLine(argc,argv))
393  {
394  Cerr("***** castor-datafileConversionEx :: A problem occurred while logging command line arguments !" << endl);
395  Exit(EXIT_FAILURE);
396  }
397 
398  // Output progression options
399  cout << std::fixed;
400  cout << std::setprecision(2);
401 
402  // ============================================================================================================
403  // ScannerManager object initialization
404  // (Basic initialization to locate scanner geometry files)
405  // ============================================================================================================
406 
407  sScannerManager* p_scannermanager = sScannerManager::GetInstance();
408  p_scannermanager->SetVerbose(vb);
409 
410  // Check if the scanner exists and get the name from ScannerManager
411  scanner_alias = (scanner_alias.find(OS_SEP)) ?
412  scanner_alias.substr(scanner_alias.find_last_of(OS_SEP)+1) :
413  scanner_alias;
414 
415  if(p_scannermanager->FindScannerSystem(scanner_alias) )
416  {
417  Cerr("**** castor-datafileConversionEx :: A problem occurred while searching for scanner system !" << endl);
418  Exit(EXIT_FAILURE);
419  }
420 
421  // Build output file names
422  path_to_data_file = path_to_out_file + ".Cdf";
423  path_to_header_file = path_to_out_file + ".Cdh";
424 
425  // ============================================================================================================
426  // Instanciate/Initialize CASToR DataFile
427  // (Enable/Disable optionnal field to be written)
428  // ============================================================================================================
429 
430  // Instantiate & Initialize oImageDimensionsAndQuantification object, required for datafile generation (number of threads)
432 
433  // Instanciate & Initialize iDataFilePET and Event objects
434  iDataFilePET* Out_data_file = NULL;
435  vEvent* Event = NULL;
436 
437  // ===> This variable set the maximum number of LORs contained in one event
438  // ===> in the whole dataset (for compression purposes)
439  // ===> This depends on the dataset to convert
440  uint16_t max_nb_lines_per_event = 1;
441 
442  // Create datafile and set variables
443  Out_data_file = new iDataFilePET();
444 
445  // Set the image oImageDimensionsAndQuantification object (required for initialization)
446  Out_data_file->SetImageDimensionsAndQuantification(p_ID);
447 
448  // Set path to header datafile
449  Out_data_file->SetHeaderDataFileName(path_to_header_file);
450 
451  // Set verbosity
452  Out_data_file->SetVerbose(vb);
453 
454  // Set data mode (list/hitogram)
455  Out_data_file->SetDataMode(data_mode);
456 
457  // Set modality
458  Out_data_file->SetDataType(TYPE_PET);
459 
460  // Set maximum number of LORs contained in one event
461  Out_data_file->SetMaxNumberOfLinesPerEvent(max_nb_lines_per_event);
462 
463  // Set calibration factor
464  Out_data_file->SetCalibrationFactor(calib_factor);
465 
466  // Set isotope
467  if(!istp_alias.empty())
468  {
469  if(p_ID->SetPETIsotope(0, istp_alias) )
470  {
471  Cerr("**** castor-datafileConversionEx :: A problem occurred while checking isotope name !" << endl);
472  Exit(EXIT_FAILURE);
473  }
474  Out_data_file->SetIsotope(istp_alias);
475  }
476 
477  // Allocate the Event structure (containing all information for a listmode
478  // or histogram event, depending on data mode)
479  if(data_mode == MODE_HISTOGRAM)
480  {
481  // Instanciate list-mode Event
482  Event = new iEventHistoPET();
483  Event->SetNbLines(max_nb_lines_per_event);
484  Event->AllocateID();
485  }
486  else
487  {
488  // Instanciate histogram Event
489  Event = new iEventListPET();
490  Event->SetNbLines(max_nb_lines_per_event);
491  Event->AllocateID();
492  }
493 
494 
495  // ============================================================================================================
496  // ===> Read sinogram correction file(s) (if any) and set datafile flag for each correction
497  // ============================================================================================================
498 
499  // ===> Compute sinogram dimensions.
500  // ===> Values must be adjusted to the dataset to convert.
501  uint32_t nbins = 1;
502  uint32_t nangles = 1;
503  uint32_t nsinos = 1;
504  uint32_t nb_cor_factors = nbins
505  * nangles
506  * nsinos;
507 
508  // --- Normalization correction factors ---
509 
510  // FLTNBDATA is either a float (default) or double type.
511  // Defined in /management/gVariables.hh
512  FLTNBDATA *p_norm = NULL;
513  bool norm_flag = false;
514 
515  if( !path_to_norm_file.empty() )
516  {
517  if(vb>=2) Cout("--> Reading the norm correction factors file = " << path_to_norm_file << "..." << endl);
518  ifstream ifile(path_to_norm_file.c_str(), ios::binary | ios::in);
519 
520  if (!ifile)
521  {
522  Cerr("***** castor-datafileConversionEx :: Error reading normalization factor file: "<< path_to_norm_file <<" !" << endl);
523  Exit(EXIT_FAILURE);
524  }
525  else
526  {
527  // Allocate buffer storing the normalisation
528  p_norm = new FLTNBDATA [nb_cor_factors * sizeof( FLTNBDATA )];
529  ifile.read(reinterpret_cast < char* > (p_norm), nb_cor_factors * sizeof( FLTNBDATA));
530  ifile.close();
531  }
532 
533  // ===> Set normalization correction flag in datafile objet
534  // ===> (required to indicate that normalization correction will be provided)
535  Out_data_file->SetNormCorrectionFlagOn();
536  norm_flag = true;
537  }
538 
539  // --- Scatter correction factors file ---
540  FLTNBDATA *p_scat = NULL;
541  bool scat_flag = false;
542 
543  if( !path_to_scat_file.empty() )
544  {
545  if(vb>=2) Cout("--> Reading the scatter correction factors file = " << path_to_scat_file << "..." << endl);
546  ifstream ifile(path_to_scat_file.c_str(), ios::binary | ios::in);
547 
548  if (!ifile)
549  {
550  Cerr("***** castor-datafileConversionEx :: Error reading scatter factor file: "<< path_to_scat_file <<" !" << endl);
551  Exit(EXIT_FAILURE);
552  }
553  else
554  {
555  // Allocating buffer storing the scatter
556  p_scat = new FLTNBDATA [nb_cor_factors * sizeof( FLTNBDATA )];
557  ifile.read(reinterpret_cast < char* > (p_scat), nb_cor_factors * sizeof( FLTNBDATA));
558  ifile.close();
559  }
560 
561  // ===> Set scatter correction flag in datafile objet
562  // ===> (required to indicate that scatter correction will be provided)
563  Out_data_file->SetScatterCorrectionFlagOn();
564  scat_flag = true;
565  }
566 
567  // --- Random correction factors file ---
568  FLTNBDATA *p_rdm = NULL;
569  bool rdm_flag = false;
570 
571  if( !path_to_rdm_file.empty() )
572  {
573  if(vb>=2) Cout("--> Reading the random correction factors file = " << path_to_rdm_file << "..." << endl);
574  ifstream ifile(path_to_rdm_file.c_str(), ios::binary | ios::in);
575 
576  if (!ifile)
577  {
578  Cerr("***** castor-datafileConversionEx :: Error reading random correction factor file: "<< path_to_rdm_file <<" !" << endl);
579  Exit(EXIT_FAILURE);
580  }
581  else
582  {
583  // Allocating buffer storing the random
584  p_rdm = new FLTNBDATA [nb_cor_factors * sizeof( FLTNBDATA )];
585  ifile.read(reinterpret_cast < char* > (p_rdm), nb_cor_factors * sizeof( FLTNBDATA));
586  ifile.close();
587  }
588 
589  // ===> Set random correction flag in datafile objet
590  // ===> (required to indicate that random correction will be provided)
591  Out_data_file->SetRandomCorrectionFlagOn();
592  rdm_flag = true;
593  }
594 
595  // --- Attenuation correction factors file ---
596  FLTNBDATA *p_acf = NULL;
597  bool acf_flag = false;
598 
599  if( !path_to_acf_file.empty() )
600  {
601  if(vb>=2) Cout("--> Reading the attenuation correction factors file = " << path_to_acf_file << "..." << endl);
602  ifstream ifile(path_to_acf_file.c_str(), ios::binary | ios::in);
603 
604  if (!ifile)
605  {
606  Cerr("***** castor-datafileConversionEx :: Error reading attenuation correction factor file: "<< path_to_acf_file <<" !" << endl);
607  Exit(EXIT_FAILURE);
608  }
609  else
610  {
611  // Allocating buffer storing the acf
612  p_acf = new FLTNBDATA [nb_cor_factors * sizeof( FLTNBDATA )];
613  ifile.read(reinterpret_cast < char* > (p_acf), nb_cor_factors* sizeof( FLTNBDATA));
614  ifile.close();
615  }
616 
617  // ===> Set attenuation correction flag in datafile objet
618  // ===> (required to indicate that attenuation correction will be provided)
619  Out_data_file->SetAtnCorrectionFlagOn();
620  acf_flag = true;
621  }
622 
623  // Initialize datafile object
624  Out_data_file->PROJ_InitFile();
625 
626  // Compute the event size relatively to the mandatory
627  // and optionnal (correction factors) elements
628  Out_data_file->ComputeSizeEvent();
629 
630  // Init DataFile
631  Out_data_file->PrepareDataFile();
632 
633 
634  // ============================================================================================================
635  // *********************************************** CONVERSION *************************************************
636  // ============================================================================================================
637  Cout(" --- Start conversion of datafile : " << path_to_input_file << endl
638  << " CASToR output header datafile: " << path_to_header_file << endl
639  << " CASToR output binary datafile: " << path_to_data_file << endl << endl);
640 
641 
642  // ============================================================================================================
643  // Init variables
644  // ============================================================================================================
645 
646  // Index for progression printing
647  uint32_t printing_index = 0;
648 
649  // ===> Recover the total number of events (number of coincidences or
650  // ===> histogram bins) from the dataset metadata
651  uint32_t nEvents = 0;
652 
653 
654  // ===> Acquisition duration and start time in seconds
655  // ===> This should be recovered from the dataset metadata)
656  FLTNB start_time_sec = 0.;
657  FLTNB stop_time_sec = 1.;
658  FLTNB duration_sec = stop_time_sec - start_time_sec;
659 
660  // ===> Scanner variables (blocs, modules, submodules, crystals etc..)
661  // ===> depending on the system.
662  uint32_t nRsectorsPerRing = 70;
663  uint32_t nb_crystals_trs = 9,
664  nb_crystals_axl = 6;
665  uint32_t nb_crystals_per_ring = nRsectorsPerRing
666  * nb_crystals_trs;
667 
668  // ===> Variables to recover indices of the two crystals for each potential
669  // ===> LORs contributing to the event
670  uint32_t *castor_id1 = new uint32_t[max_nb_lines_per_event];
671  uint32_t *castor_id2 = new uint32_t[max_nb_lines_per_event];
672 
673  // --------------------------------
674  // Initialization of root variables
675  // The following lines are just required for the demonstration dataset used in this sample code,
676  // Must be erased when adjusting this code to the conversion of any dataset
677 
678  // ROOT objects/variables
679  int32_t rSectorID1 = 0, rSectorID2 = 0;
680  int32_t moduleID1 = 0, moduleID2 = 0;
681  int32_t crystalID1 = 0, crystalID2 = 0;
682 
683  #ifdef CASTOR_ROOT
684  TApplication *Tapp = new TApplication("tapp",0,0);
685  TTree* Coincidences = new TTree;
686  TFile* Tfile_root = new TFile(path_to_input_file.c_str(),"READ","ROOT file with histograms");
687  Coincidences = (TTree*)Tfile_root->Get("Coincidences");
688  nEvents += Coincidences->GetEntries();
689 
690  //------------- ROOT branches
691  double_t time1=0;
692  Coincidences->SetBranchAddress("time1",&time1);
693  Coincidences->SetBranchAddress("rsectorID1",&rSectorID1);
694  Coincidences->SetBranchAddress("moduleID1",&moduleID1);
695  Coincidences->SetBranchAddress("crystalID1",&crystalID1);
696 
697  double_t time2=0;
698  Coincidences->SetBranchAddress("time2",&time2);
699  Coincidences->SetBranchAddress("rsectorID2",&rSectorID2);
700  Coincidences->SetBranchAddress("moduleID2",&moduleID2);
701  Coincidences->SetBranchAddress("crystalID2",&crystalID2);
702 
703  // Recover acquisition start time from the first event
704  Coincidences->GetEntry(0);
705  #endif
706  // --------------------------------
707 
708  // Just for progression output
709  uint32_t printing_ratio = (nEvents>1000) ? 1000 : nEvents/10;
710 
711  // Loop on the data elements (histogram bins or LORs)
712  for (uint32_t i=0; i<nEvents ; i++)
713  {
714  // ===> Recover event value (list-mode, or dynamic histogram dataset)
715  uint32_t time_ms = 0;
716  stop_time_sec = (FLTNB)time_ms/1000;
717 
718  // ===> Recover the number of lines in the event (if compression).
719  int nb_lines_in_event = 1;
720 
721  // -----------------------------------------------------------------
722  // The following lines are just required for the demonstration dataset used in this sample code.
723  // Must be erased/adapted when adjusting this code to the conversion of any dataset
724  #ifdef CASTOR_ROOT
725  Coincidences->GetEntry(i);
726  time_ms = time1;
727  #endif
728 
729  // ===> Compute CASToR indexation depending on the system layout
730  // ===> This directly depends on the type of scanner file used to
731  // ===> described the system geometry.
732  // ===> See documentation for more information
733  uint32_t crystals_trs_id1 = (uint32_t)(crystalID1/nb_crystals_trs);
734 
735  uint32_t ringID1 = moduleID1*nb_crystals_axl
736  + crystals_trs_id1;
737 
738  uint32_t crystals_trs_id2 = (uint32_t)(crystalID2/nb_crystals_trs);
739 
740  uint32_t ringID2 = moduleID2*nb_crystals_axl
741  + crystals_trs_id2;
742 
743  // Loop on the LORs contained in the event
744  for(int l=0 ; l<nb_lines_in_event ; l++)
745  {
746  // Recover the CASToR ID position of the two crystals according to
747  // the LUT corresponding to this scanner
748  castor_id1[l] = ringID1*nb_crystals_per_ring
749  + rSectorID1*nb_crystals_trs
750  + crystalID1%nb_crystals_trs ;
751 
752  castor_id2[l] = ringID2*nb_crystals_per_ring
753  + rSectorID2*nb_crystals_trs
754  + crystalID2%nb_crystals_trs ;
755  }
756  // -----------------------------------------------------------------
757 
758  // --- Histo-mode event ---
759  if(is_histogram_flag) // histogram mode event
760  {
761  // Set the number of lines in this event
762  Event->SetNbLines(nb_lines_in_event);
763 
764  // Set CASToR IDs in the event structure for each contributing line
765  for(int l=0 ; l<nb_lines_in_event ; l++)
766  {
767  Event->SetID1(l, castor_id1[l]); // 1st argument : line, 2nd argument : index
768  Event->SetID2(l, castor_id2[l]); // 1st argument : line, 2nd argument : index
769  }
770 
771  // Set information related to each TOF bin
772  int nb_tof_bins = 1;
773  for (int b=0; b<nb_tof_bins; b++)
774  {
775  // ===> Recover and set event value (histogram dataset)
776  FLTNB event_value = 1.;
777  Event->SetEventValue(b, event_value); // 1st argument : TOF bin, 2nd argument : event value
778 
779  // ===> Set scatter correction factor (if any)
780  // ===> Require computation of the scatter correction value for
781  // ===> this LOR from the factors loaded in the "p_scat" buffer
782  if(scat_flag)
783  {
784  FLTNB scat_correction_coeff = 0.; // computed from p_scat
785  ((iEventHistoPET*)Event)->SetScatterRate(b, scat_correction_coeff);
786  }
787  }
788 
789  // ===> Set timestamp of the event in ms (global timestamp for histogram)
790  // ===> i.e : 0, or timestamp of a dynamic frame
791  Event->SetTimeInMs(time_ms); // uint32_t
792 
793  // ===> Set random correction factor (if any)
794  // ===> Require computation of the random correction value for
795  // ===> this LOR from the factors loaded in the "p_rdm" buffer
796  if(rdm_flag)
797  {
798  FLTNB rdm_correction_coeff = 0.; // computed from p_rdm
799  ((iEventPET*)Event)->SetRandomRate(rdm_correction_coeff);
800  }
801 
802  // ===> Set normalization correction factor (if any)
803  // ===> Require computation of the norm correction value for
804  // ===> this LOR from the factors loaded in the "p_norm" buffer
805  if(norm_flag)
806  {
807  FLTNB norm_correction_coeff = 0.; // computed from p_norm
808  ((iEventPET*)Event)->SetNormalizationFactor(norm_correction_coeff);
809  }
810 
811  // ===> Set attenuation correction factor (if any)
812  // ===> Require computation of the atn correction value for
813  // ===> this LOR from the factors loaded in the "p_acf" buffer
814  if(acf_flag)
815  {
816  FLTNB atn_correction_coeff = 0.; // computed from p_acf
817  ((iEventPET*)Event)->SetAttenuationCorrectionFactor(atn_correction_coeff);
818  }
819 
820  // Write event in the datafile
821  // ('0' argument is just thread-related. No change required)
822  Out_data_file->WriteEvent(Event, 0);
823  }
824 
825  // --- List-mode event ---
826  else
827  {
828  // Set the number of lines in this event
829  Event->SetNbLines(nb_lines_in_event);
830 
831  // Set CASToR ID in the event structure
832  for(int l=0 ; l<nb_lines_in_event ; l++)
833  {
834  Event->SetID1(l, castor_id1[l]); // 1st argument : line, 2nd argument :index
835  Event->SetID2(l, castor_id2[l]); // 1st argument : line, 2nd argument :index
836  }
837 
838  // ===> Set scatter correction factor (if any)
839  // ===> Require computation of the scatter correction value for
840  // ===> this LOR from the factors loaded in the "p_scat" buffer
841  if(scat_flag)
842  {
843  FLTNB scat_correction_coeff = 0.; // computed from p_scat
844  // First argument '0' by default for list-mode (it is used for histograms with TOF bins).
845  ((iEventListPET*)Event)->SetScatterRate(0, scat_correction_coeff);
846  }
847 
848  // ===> Set timestamp of the event in ms
849  Event->SetTimeInMs(time_ms); // uint32_t
850 
851  // ===> Set random correction factor (if any)
852  // ===> Require computation of the random correction value for
853  // ===> this LOR from the factors loaded in the "p_rdm" buffer
854  if(rdm_flag)
855  {
856  FLTNB rdm_correction_coeff = 0.; // computed from p_rdm
857  ((iEventPET*)Event)->SetRandomRate(rdm_correction_coeff);
858  }
859 
860  // ===> Set normalization correction factor (if any)
861  // ===> Require computation of the norm correction value for
862  // ===> this LOR from the factors loaded in the "p_norm" buffer
863  if(norm_flag)
864  {
865  FLTNB norm_correction_coeff = 0.; // computed from p_norm
866  ((iEventPET*)Event)->SetNormalizationFactor(norm_correction_coeff);
867  }
868 
869  // ===> Set attenuation correction factor (if any)
870  // ===> Require computation of the atn correction value for
871  // ===> this LOR from the factors loaded in the "p_acf" buffer
872  if(acf_flag)
873  {
874  FLTNB atn_correction_coeff = 0.; // computed from p_acf
875  ((iEventPET*)Event)->SetAttenuationCorrectionFactor(atn_correction_coeff);
876  }
877 
878  // Write event in the datafile
879  // ('0' argument is just thread-related. No change required)
880  Out_data_file->WriteEvent(Event, 0);
881  }
882 
883  // Progression output
884  if (printing_index%printing_ratio==0)
885  {
886  FLTNB percent = ( ((FLTNB)(printing_index+1))/((FLTNB)nEvents) ) * ((FLTNB)100);
887  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 "
888  << percent << " % ";
889  }
890  printing_index++;
891  }
892 
893  Cout("The simulated dataset contained " << nEvents << " coincidences / bins" << endl);
894 
895  // Set duration and nb of events in datafile
896  Out_data_file->SetStartTime(start_time_sec);
897  Out_data_file->SetDuration(duration_sec);
898  Out_data_file->SetNbEvents(nEvents);
899 
900  // Write datafile header
901  Out_data_file->WriteHeader();
902 
903  // Write raw datafile
904  Out_data_file->PROJ_WriteData();
905 
906  // Delete tmp writing file (if any)
907  Out_data_file->PROJ_DeleteTmpDataFile();
908 
909  cout << endl;
910 
911  // ============================================================================================================
912  // End
913  // ============================================================================================================
914 
915  // Free Root objects
916  #ifdef CASTOR_ROOT
917  delete Coincidences;
918  delete Tfile_root;
919  delete Tapp;
920  #endif
921 
922  delete[] castor_id1;
923  delete[] castor_id2;
924 
925  if(p_acf != NULL) delete[] p_acf;
926  if(p_rdm != NULL) delete[] p_rdm;
927  if(p_scat != NULL) delete[] p_scat;
928  if(p_norm != NULL) delete[] p_norm;
929 
930  // Delete objects
931  if (Event)
932  {
933  if (is_histogram_flag)
934  delete (iEventHistoPET*)Event;
935  else
936  delete (iEventListPET*)Event;
937  }
938 
939  delete Out_data_file;
940  delete p_ID;
941 
942  return 0;
943 }
int WriteEvent(vEvent *ap_Event, int a_th)
void SetDataMode(int a_dataMode)
static sScannerManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
#define MODE_HISTOGRAM
void SetNbLines(uint16_t a_value)
void SetAtnCorrectionFlagOn()
set to true the flag indicating the presence of attenuation correction factors in the datafile ...
#define Cerr(MESSAGE)
int FindScannerSystem(string a_scannerName)
void SetScatterCorrectionFlagOn()
set to true the flag indicating the presence of scatter correction factors in the datafile ...
void SetVerbose(int a_verboseLevel)
void SetDuration(FLTNB a_value)
void Exit(int code)
static sOutputManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
int ComputeSizeEvent()
Computation of the size of each event according to the mandatory/optional correction fields...
int LogCommandLine(int argc, char **argv)
int PROJ_WriteData()
Write/Merge chunk of data in a general data file.
int CheckConfigDir(const string &a_path)
Inherit from iEventPET. Class for PET list-mode events.
Inherit from iEventPET. Class for PET histogram mode events.
void SetStartTime(FLTNB a_value)
Singleton class that manages output writing on disk (images, sinograms, etc). It also manages loggi...
void SetMaxNumberOfLinesPerEvent(uint16_t a_value)
void ShowHelp(int a_returnCode)
void SetDataType(int a_dataType)
Singleton class that Instantiate and initialize the scanner object.
void SetCalibrationFactor(FLTNB a_value)
virtual void SetEventValue(int a_bin, FLTNBDATA a_value)=0
void SetRandomCorrectionFlagOn()
set to true the flag indicating the presence of random correction factors in the datafile ...
void SetHeaderDataFileName(const string &a_headerFileName)
int WriteHeader()
Generate a header file according to the data output information.
int AllocateID()
Instantiate the mp_ID1 and mp_ID2 indices arrays.
int PROJ_InitFile()
Initialize the fstream objets for output writing as well as some other variables specific to the Proj...
Inherit from vEvent. Main PET class for the Event objects.
void SetNbEvents(int64_t a_value)
int PrepareDataFile()
Store different kind of information inside arrays (data relative to specific correction as well as ba...
void SetID2(int a_line, uint32_t a_value)
int main(int argc, char **argv)
void SetTimeInMs(uint32_t a_value)
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;.
void SetNormCorrectionFlagOn()
set to true the flag indicating the presence of normalization correction factors in the datafile ...
This class is designed to manage all dimensions and quantification related stuff. ...
void SetVerbose(int a_verboseLevel)
int PROJ_DeleteTmpDataFile()
Delete temporary datafile used for multithreaded output writing if needed.
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
Inherit from vDataFile. Class that manages the reading of a PET input file (header + data)...
#define Cout(MESSAGE)
void SetID1(int a_line, uint32_t a_value)