CASToR  3.2
Tomographic Reconstruction (PET/SPECT/CT)
code/src/datafile/vDataFile.cc
Go to the documentation of this file.
1 
9 #include "vDataFile.hh"
10 
11 // =====================================================================
12 // ---------------------------------------------------------------------
13 // ---------------------------------------------------------------------
14 // =====================================================================
15 
17 {
18  mp_ID = NULL;
19  m_verbose = -1;
20 
21  // Variables related to the acquisition
22  m2p_dataFile = NULL;
23  m_headerFileName = "";
24  m_dataFileName = "";
25  m_scannerName = "";
29  m_nbEvents = -1;
30  m_bedIndex = -1;
32  m_bedPositionFlag = false;
33  m_startTimeInSec = 0.;
34  m_durationInSec = -1.;
36  m_sizeEvent = -1;
37 
38  // Default POI (meaning we do not have any)
39  mp_POIResolution[0] = -1.;
40  mp_POIResolution[1] = -1.;
41  mp_POIResolution[2] = -1.;
42  mp_POIDirectionFlag[0] = false;
43  mp_POIDirectionFlag[1] = false;
44  mp_POIDirectionFlag[2] = false;
45  m_POIInfoFlag = false;
46  m_ignorePOIFlag = false;
47 
48  // Variable related to Buffer/Container arrays
49  m2p_BufferEvent = NULL;
50  m_mpi1stEvent = -1;
51  m_mpiLastEvent = -1;
52  m_mpiNbEvents = -1;
53  mp_MappedFile = NULL;
54  mp_mappedMemory = NULL;
55 }
56 
57 // =====================================================================
58 // ---------------------------------------------------------------------
59 // ---------------------------------------------------------------------
60 // =====================================================================
61 
63 {
64  // Free the (vEvent) buffer event
65  if (m2p_BufferEvent)
66  {
67  for(int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
68  if (m2p_BufferEvent[th]) delete m2p_BufferEvent[th];
69  delete[] m2p_BufferEvent;
70  }
71  // Close datafiles and delete them
72  if (m2p_dataFile)
73  {
74  for(int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
75  if (m2p_dataFile[th]) m2p_dataFile[th]->close();
76  delete m2p_dataFile;
77  }
78  // Delete the mapped memory object
79  if (mp_MappedFile!=NULL) delete mp_MappedFile;
80 }
81 
82 // =====================================================================
83 // ---------------------------------------------------------------------
84 // ---------------------------------------------------------------------
85 // =====================================================================
86 
87 int vDataFile::ReadInfoInHeader(bool a_affectQuantificationFlag)
88 {
89  // Verbose
91  if (m_verbose>=VERBOSE_DETAIL) Cout("vDataFile::ReadInfoInHeader() -> Read datafile header from '" << m_headerFileName << " ...'" << endl);
92 
93  // Check that the image dimensions and quantification object has been set if the a_affectQuantificationFlag is true
94  if (a_affectQuantificationFlag && mp_ID==NULL)
95  {
96  Cerr("***** vDataFile::ReadInfoInHeader() -> Image dimensions and quantification object has not been set while it is asked to affect" << endl);
97  Cerr(" its parameters from information read into the header !" << endl);
98  return 1;
99  }
100 
101  // Read mandatory general fields in the header, check if errors (either mandatory tag not found or issue during data reading/conversion (==1) )
102  if (ReadDataASCIIFile(m_headerFileName, "Number of events", &m_nbEvents, 1, KEYWORD_MANDATORY) )
103  {
104  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while trying to read number of events in the header data file !" << endl);
105  return 1;
106  }
108  {
109  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while trying to read scanner name in the header data file !" << endl);
110  return 1;
111  }
112 
113  // Get data file name
115  {
116  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while trying to read data filename in the header data file !" << endl);
117  return 1;
118  }
119  // If it is an absolute path (start with a OS_SEP) then let it as is, otherwise past the path of the header file name (because we suppose the two
120  // files are side by side).
121  // This is currently only unix compatible...
122  if (m_dataFileName.substr(0,1)!=OS_SEP && m_headerFileName.find(OS_SEP)!=string::npos)
123  {
124  // Extract the path from the header file name
125  size_t last_slash = m_headerFileName.find_last_of(OS_SEP);
126  // Paste the path to the data file name
127  m_dataFileName = m_headerFileName.substr(0,last_slash+1) + m_dataFileName;
128  }
129 
130  // For data mode, multiple declarations are allowed, so we get the mode as a string and do some checks
131  string data_mode = "";
132  if (ReadDataASCIIFile(m_headerFileName, "Data mode", &data_mode, 1, KEYWORD_MANDATORY) )
133  {
134  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while trying to read data mode in the header data file !" << endl);
135  return 1;
136  }
137  if ( data_mode=="LIST" || data_mode=="LISTMODE" || data_mode=="LIST-MODE" ||
138  data_mode=="list" || data_mode=="listmode" || data_mode=="list-mode" || data_mode=="0" ) m_dataMode = MODE_LIST;
139  else if ( data_mode=="HISTOGRAM" || data_mode=="histogram" || data_mode=="Histogram" ||
140  data_mode=="HISTO" || data_mode=="histo" || data_mode=="Histo" || data_mode=="1" ) m_dataMode = MODE_HISTOGRAM;
141  else if ( data_mode=="NORMALIZATION" || data_mode=="normalization" || data_mode=="Normalization" ||
142  data_mode=="NORM" || data_mode=="norm" || data_mode=="Norm" || data_mode=="2" ) m_dataMode = MODE_NORMALIZATION;
143  else
144  {
145  Cerr("***** vDataFile::ReadInfoInHeader() -> Unknown data mode '" << data_mode << "' found in header file !" << endl);
146  return 1;
147  }
148 
149  // For data type, multiple declarations are allowed, so we get the mode as a string and do some checks
150  string data_type = "";
151  if (ReadDataASCIIFile(m_headerFileName, "Data type", &data_type, 1, KEYWORD_MANDATORY) )
152  {
153  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while trying to read data type in the header data file !" << endl);
154  return 1;
155  }
156  if ( data_type=="PET" || data_type=="pet" || data_type=="0" )
157  {
160  }
161  else if ( data_type=="SPECT" || data_type=="spect" || data_type=="1" )
162  {
165  }
166  else if ( data_type=="CT" || data_type=="ct" || data_type=="2" )
167  {
170  }
171  else
172  {
173  Cerr("***** vDataFile::ReadInfoInHeader() -> Unknown data type '" << data_type << "' found in header file !" << endl);
174  return 1;
175  }
176 
177  // Get start time and duration (optional for the normalization mode
179  {
181  {
182  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while trying to read acquisition start time in the header data file !" << endl);
183  return 1;
184  }
186  {
187  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while trying to read acquisition stop time in the header data file !" << endl);
188  return 1;
189  }
190  }
191  else
192  {
193  if (ReadDataASCIIFile(m_headerFileName, "Start time (s)", &m_startTimeInSec, 1, KEYWORD_OPTIONAL) == 1 )
194  {
195  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while reading acquisition start time in the header data file !" << endl);
196  return 1;
197  }
198  if (ReadDataASCIIFile(m_headerFileName, "Duration (s)", &m_durationInSec, 1, KEYWORD_OPTIONAL) == 1 )
199  {
200  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while reading acquisition stop time in the header data file !" << endl);
201  return 1;
202  }
203  }
204 
205  string gate_list_durations_in_sec = "";
206  if (ReadDataASCIIFile(m_headerFileName, "Gate duration (s)", &gate_list_durations_in_sec, 1, KEYWORD_OPTIONAL) == 1 )
207  {
208  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while reading acquisition gate duration in the header data file !" << endl);
209  return 1;
210  }
211 
212 
213  // Set the acquisition timing to the quantification factors
214  if (a_affectQuantificationFlag && mp_ID->SetAcquisitionTime(m_bedIndex, m_startTimeInSec, m_durationInSec, gate_list_durations_in_sec))
215  {
216  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while passing acquisition start and stop time to the ImageDimensionsAndQuantification !" << endl);
217  return 1;
218  }
219 
220  // Read optional bed relative position
221  int read_bed_position_status = ReadDataASCIIFile(m_headerFileName, "Horizontal bed relative position (mm)", &m_relativeBedPosition, 1, KEYWORD_OPTIONAL);
222  if (read_bed_position_status==KEYWORD_OPTIONAL_SUCCESS) m_bedPositionFlag = true;
223  else if (read_bed_position_status==KEYWORD_OPTIONAL_SUCCESS)
224  {
225  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while reading the 'Bed relative position (mm)' field in the data file header !" << endl);
226  return 1;
227  }
228 
229  // Read optional fields in the header, check if errors (issue during data reading/conversion (==1) )
230  if (ReadDataASCIIFile(m_headerFileName, "Calibration factor", &m_calibrationFactor, 1, KEYWORD_OPTIONAL) == 1 ||
232  ReadDataASCIIFile(m_headerFileName, "POI correction flag", &m_POIInfoFlag, 3, KEYWORD_OPTIONAL) == 1 )
233  {
234  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while reading optional field in the header data file !" << endl);
235  return 1;
236  }
237 
238  // Read fields specific to the modality (call to the related function implemented in child classes)
239  if (ReadSpecificInfoInHeader(a_affectQuantificationFlag) )
240  {
241  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while trying to read modality-specific informations from the header data file !" << endl);
242  return 1;
243  }
244 
245  // Give the calibration factor to the oImageDimensionsAndQuantification that manages the quantification factors
246  if (a_affectQuantificationFlag && mp_ID->SetCalibrationFactor(m_bedIndex, m_calibrationFactor))
247  {
248  Cerr("***** vDataFile::ReadSpecificInfoInHeader() -> A problem occurred while setting the calibration factor to oImageDimensionsAndQuantification !" << endl);
249  return 1;
250  }
251 
252  return 0;
253 }
254 
255 // =====================================================================
256 // ---------------------------------------------------------------------
257 // ---------------------------------------------------------------------
258 // =====================================================================
259 
261 {
262  // Verbose
263  m_verbose = ap_DataFile->GetVerbose();
264  // Variables related to the acquisition
265  m2p_dataFile = NULL;
266  m_scannerName = ap_DataFile->GetScannerName();
267  m_dataMode = ap_DataFile->GetDataMode();
268  m_dataType = ap_DataFile->GetDataType();
269  m_dataSpec = ap_DataFile->GetDataSpec();
270  m_bedIndex = ap_DataFile->GetBedIndex();
272  m_bedPositionFlag = ap_DataFile->GetBedPositionFlag();
273  m_startTimeInSec = ap_DataFile->GetStartTime();
274  m_durationInSec = ap_DataFile->GetDuration();
275  m_calibrationFactor = ap_DataFile->GetCalibrationFactor();
276  m_sizeEvent = ap_DataFile->GetEventSize();
277  // Default POI (meaning we do not have any)
278  m_POIInfoFlag = ap_DataFile->GetPOIInfoFlag();
279  mp_POIResolution[0] = ap_DataFile->GetPOIResolution()[0];
280  mp_POIResolution[1] = ap_DataFile->GetPOIResolution()[1];
281  mp_POIResolution[2] = ap_DataFile->GetPOIResolution()[2];
282  mp_POIDirectionFlag[0] = ap_DataFile->GetPOIDirectionFlag()[0];
283  mp_POIDirectionFlag[1] = ap_DataFile->GetPOIDirectionFlag()[1];
284  mp_POIDirectionFlag[2] = ap_DataFile->GetPOIDirectionFlag()[2];
285  // Call the specific function
286  if (SetSpecificParametersFrom(ap_DataFile))
287  {
288  Cerr("***** vDataFile::SetParametersFrom() -> An error occurred while setting specific parameters fro mthe provided datafile !" << endl);
289  return 1;
290  }
291  // End
292  return 0;
293 }
294 
295 // =====================================================================
296 // ---------------------------------------------------------------------
297 // ---------------------------------------------------------------------
298 // =====================================================================
299 
301 {
302  // Verbose
304  if (m_verbose>=VERBOSE_DETAIL) Cout("vDataFile::CheckParameters() -> Check mandatory parameters" << endl);
305  // Check mandatory parameters
306  if (mp_ID == NULL)
307  {
308  Cerr("***** vDataFile::CheckParameters() -> ImageDimensionsAndQuantification object not initialized !" << endl);
309  return 1;
310  }
311  if (m_headerFileName == "")
312  {
313  Cerr("***** vDataFile::CheckParameters() -> String containing path to header file not initialized !" << endl);
314  return 1;
315  }
316  if (m_dataFileName == "")
317  {
318  Cerr("***** vDataFile::CheckParameters() -> String containing path to raw data file not initialized !" << endl);
319  return 1;
320  }
321  if (m_nbEvents<0)
322  {
323  Cerr("***** vDataFile::CheckParameters() -> Number of events incorrectly initialized !" << endl);
324  return 1;
325  }
327  {
328  Cerr("***** vDataFile::CheckParameters() -> Data mode incorrectly initialized !" << endl);
329  return 1;
330  }
332  {
333  Cerr("***** vDataFile::CheckParameters() -> Acquisition duration (s) incorrectly initialized !" << endl);
334  return 1;
335  }
337  {
338  Cerr("***** vDataFile::CheckParameters() -> Data type incorrectly initialized !" << endl);
339  return 1;
340  }
342  {
343  Cerr("***** vDataFile::CheckParameters() -> Data physical property incorrectly initialized !" << endl);
344  return 1;
345  }
346  if (m_bedIndex<0)
347  {
348  Cerr("***** vDataFile::CheckParameters() -> Bed position index incorrectly initialized !" << endl);
349  return 1;
350  }
351  if (m_verbose<0)
352  {
353  Cerr("***** vDataFile::CheckParameters() -> Verbosity incorrectly initialized !" << endl);
354  return 1;
355  }
356  // Call to the related function implemented in child classes
358  {
359  Cerr("***** vDataFile::CheckParameters() -> Error while checking specific parameters !" << endl);
360  return 1;
361  }
362  // End
363  return 0;
364 }
365 
366 // =====================================================================
367 // ---------------------------------------------------------------------
368 // ---------------------------------------------------------------------
369 // =====================================================================
370 
372 {
373  // Verbose
375  if (m_verbose>=VERBOSE_DETAIL) Cout("vDataFile::CheckConsistencyWithAnotherBedDataFile() -> Check consistency between this and the provided datafiles" << endl);
376  // Check data type
377  if (m_dataType!=ap_DataFile->GetDataType())
378  {
379  Cerr("***** vDataFile::CheckConsistencyWithAnotherBedDataFile() -> Data types are inconsistent !" << endl);
380  return 1;
381  }
382  // Check data mode
383  if (m_dataMode!=ap_DataFile->GetDataMode())
384  {
385  Cerr("***** vDataFile::CheckConsistencyWithAnotherBedDataFile() -> Data modes are inconsistent !" << endl);
386  return 1;
387  }
388  // For histogram and normalization modes, check the number of events (i.e. the number of histogram bins)
390  {
391  Cerr("***** vDataFile::CheckConsistencyWithAnotherBedDataFile() -> Total number of events are inconsistent !" << endl);
392  return 1;
393  }
394  // Check the scanner name
395  if (m_scannerName!=ap_DataFile->GetScannerName())
396  {
397  Cerr("***** vDataFile::CheckConsistencyWithAnotherBedDataFile() -> Scanner names are inconsistent !" << endl);
398  return 1;
399  }
400  // Check the calibration factor
401  if (m_calibrationFactor!=ap_DataFile->GetCalibrationFactor())
402  {
403  Cerr("***** vDataFile::CheckConsistencyWithAnotherBedDataFile() -> Calibration factors are inconsistent !" << endl);
404  return 1;
405  }
406  // Check event size
407  if (m_sizeEvent!=ap_DataFile->GetEventSize())
408  {
409  Cerr("***** vDataFile::CheckConsistencyWithAnotherBedDataFile() -> Events sizes are inconsistent !" << endl);
410  return 1;
411  }
412  // Check POI info flag
413  if (m_POIInfoFlag!=ap_DataFile->GetPOIInfoFlag())
414  {
415  Cerr("***** vDataFile::CheckConsistencyWithAnotherBedDataFile() -> POI flags are inconsistent !" << endl);
416  return 1;
417  }
418  // Check POI resolutions
419  if ( (mp_POIResolution[0]!=ap_DataFile->GetPOIResolution()[0]) ||
420  (mp_POIResolution[1]!=ap_DataFile->GetPOIResolution()[1]) ||
421  (mp_POIResolution[2]!=ap_DataFile->GetPOIResolution()[2]) )
422  {
423  Cerr("***** vDataFile::CheckConsistencyWithAnotherBedDataFile() -> POI resolutions are inconsistent !" << endl);
424  return 1;
425  }
426  // Check the bed position flag
427  if (m_bedPositionFlag!=ap_DataFile->GetBedPositionFlag())
428  {
429  Cerr("***** vDataFile::CheckConsistencyWithAnotherBedDataFile() -> Bed relative positions must be provided for all beds or not at all !" << endl);
430  return 1;
431  }
432  // Call specific function
434  {
435  Cerr("***** vDataFile::CheckConsistencyWithAnotherBedDataFile() -> Inconsistency detected for specific characteristics !" << endl);
436  return 1;
437  }
438  // End
439  return 0;
440 }
441 
442 // =====================================================================
443 // ---------------------------------------------------------------------
444 // ---------------------------------------------------------------------
445 // =====================================================================
446 
448 {
449  // Verbose
451  if (m_verbose>=VERBOSE_NORMAL) Cout("vDataFile::InitializeMappedFile() -> Map datafile to memory" << endl);
452 
453  // Check file size consistency here (this is a pure virtual function implemented by children)
455  {
456  Cerr("***** vDataFile::InitializeMappedFile() -> A problem occurred while checking file size consistency !" << endl);
457  return 1;
458  }
459 
460  // Create mapped file
462  // Open the file
464  {
465  Cerr("***** vDataFile::InitializeMappedFile() -> Failed to open data file '" << m_dataFileName << "' !" << endl);
466  Cerr(" Provided in data file header '" << m_headerFileName << "'." << endl);
467  return 1;
468  }
469 
470  // Get raw pointer to mapped memory
472 
473  // ------------------ Compute here the piece of file that each MPI instance manages --------------------
474 
475  // 1. Compute the number of events that each instance has to manage
476  int64_t instance_size = m_nbEvents / mp_ID->GetMPISize();
477  // All instances manage an equal part of the file but the last one which also manages the few last events
478  if (mp_ID->GetMPIRank()!=mp_ID->GetMPISize()-1) m_mpiNbEvents = instance_size;
479  else m_mpiNbEvents = instance_size + (m_nbEvents - instance_size*mp_ID->GetMPISize());
480  // 2. Compute the first event managed by the instance
481  m_mpi1stEvent = mp_ID->GetMPIRank() * instance_size;
482  // 3. Compute the last event managed by the instance
483  m_mpiLastEvent = m_mpi1stEvent + m_mpiNbEvents - 1;
484 
485  // End
486  return 0;
487 }
488 
489 
490 // =====================================================================
491 // ---------------------------------------------------------------------
492 // ---------------------------------------------------------------------
493 // =====================================================================
494 
496 {
498  if (m_verbose==0) return;
499  // Describe the datafile
500  Cout("vDataFile::Describe() -> Here is some generic content of the datafile" << endl);
501  Cout(" --> Header file name: " << m_headerFileName << endl);
502  Cout(" --> Data file name: " << m_dataFileName << endl);
503  Cout(" --> Data type: " << GetDataTypeToString() << endl);
504  Cout(" --> Data mode: " << GetDataModeToString() << endl);
505  Cout(" --> Data spec: " << GetDataSpecToString() << endl);
506  Cout(" --> Scanner name: " << m_scannerName << endl);
507  Cout(" --> Number of specific events: " << m_nbEvents << endl);
508  Cout(" --> Size of an event: " << m_sizeEvent << " bytes" << endl);
509  Cout(" --> Time start: " << m_startTimeInSec << " sec" << endl);
510  Cout(" --> Duration: " << m_durationInSec << " sec" << endl);
511  Cout(" --> Calibration factor: " << m_calibrationFactor << endl);
512  if (m_bedPositionFlag) Cout(" --> Relative axial bed position: " << m_relativeBedPosition << " mm" << endl);
513  // Call the specific function
515 }
516 
517 // =====================================================================
518 // ---------------------------------------------------------------------
519 // ---------------------------------------------------------------------
520 // =====================================================================
521 
522 int vDataFile::OpenFileForWriting(string a_suffix)
523 {
524  // Check that file is not already open
525  if (m2p_dataFile && m2p_dataFile[0]->is_open())
526  {
527  Cerr("***** vDataFile::OpenFileForWriting() -> Output data file is already open !" << endl);
528  return 1;
529  }
530 
531  // Allocate the m2p_dataFile for each thread
532  m2p_dataFile = new fstream*[1];
533 
534  // Set the name of output files
536  string path_name = p_OutMgr->GetPathName();
537  string base_name = p_OutMgr->GetBaseName();
538  m_headerFileName = path_name + base_name + a_suffix + ".cdh";
539  m_dataFileName = path_name + base_name + a_suffix + ".cdf";
540 
541  // Verbose
542  if (m_verbose>=2) Cout("vDataFile::OpenFileForWriting() -> Output data file header is '" << m_headerFileName << "'" << endl);
543 
544  // Open file
545  m2p_dataFile[0] = new fstream( m_dataFileName.c_str(), ios::binary | ios::out );
546 
547  // Check
548  if (!m2p_dataFile[0]->is_open())
549  {
550  Cerr("***** vDataFile::OpenFileForWriting() -> Failed to create output file '" << m_dataFileName << "' !" << endl);
551  return 1;
552  }
553 
554  // End
555  return 0;
556 }
557 
558 // =====================================================================
559 // ---------------------------------------------------------------------
560 // ---------------------------------------------------------------------
561 // =====================================================================
562 
564 {
565  // Close binary data file
566  if (m2p_dataFile)
567  {
568  // Verbose
569  if (m_verbose>=2) Cout("vDataFile::CloseFile() -> Closing output binary data file" << endl);
570  // Close file
571  if (m2p_dataFile[0]) m2p_dataFile[0]->close();
572  delete m2p_dataFile;
573  }
574  // End
575  return 0;
576 }
577 
578 // =====================================================================
579 // ---------------------------------------------------------------------
580 // ---------------------------------------------------------------------
581 // =====================================================================
582 
583 vEvent* vDataFile::GetEvent(int64_t a_eventIndex, int a_th)
584 {
586  // The event pointer that will be returned
587  vEvent* p_event;
588  // Compute the adress into the buffer
589  char* event_address_in_array = mp_mappedMemory + a_eventIndex*m_sizeEvent;
590  // Get the event
591  p_event = GetEventSpecific(event_address_in_array, a_th);
592  // Return the event
593  return p_event;
594 }
595 
596 
597 
598 
599 // =====================================================================
600 // ---------------------------------------------------------------------
601 // ---------------------------------------------------------------------
602 // =====================================================================
603 
605  // dev tool, but it can be used currently by the datafile
606  // Ignored for now in windows compilation
607 
608 int vDataFile::Shuffle( int64_t nb_events_to_load )
609 {
610  #ifndef _WIN32
611  if (m_verbose >=2) Cout("vDataFile::Shuffle() : Everyday I shuffle in... " << endl);
612  // Buffer storing ordered indices from ( 0 ) to ( nb_events_to_load - 1 )
613  int64_t *rndmIdx = new int64_t[ nb_events_to_load ];
614  std::iota( rndmIdx, rndmIdx + nb_events_to_load, 0 );
615 
616  // Initializing random
617  std::random_device rd;
618  std::mt19937 rndm( rd() );
619  rndm.seed( 1100001001 );
620 
621  // Shuffling the buffer of indices
622  std::shuffle( rndmIdx, rndmIdx + nb_events_to_load, rndm );
623 
624  // Creating a tmp buffer
625  char *mp_arrayEvents_tmp = new char[ nb_events_to_load*m_sizeEvent ];
626 
627  // Copy sorted buffer to shuffled buffer
628  for( int64_t i = 0; i < nb_events_to_load; ++i )
629  {
630  for( int64_t j = 0; j < m_sizeEvent; ++j )
631  {
632  //mp_arrayEvents_tmp[ i * m_sizeEvent + j ] = mp_arrayEvents[ rndmIdx[ i ] * m_sizeEvent + j ];
633  mp_arrayEvents_tmp[ i * m_sizeEvent + j ] = mp_mappedMemory[ rndmIdx[ i ] * m_sizeEvent + j ];
634  }
635  }
636 
637  // Freeing memory
638  delete[] rndmIdx;
639  //delete[] mp_mappedMemory;
640 
641  //mp_arrayEvents = mp_arrayEvents_tmp;
642  mp_mappedMemory = mp_arrayEvents_tmp;
643 
644  if (m_verbose >=2) Cout("vDataFile::Shuffle OK" << endl);
645  #endif
646  return 0;
647 }
648 
649 
650 
651 // =====================================================================
652 // ---------------------------------------------------------------------
653 // ---------------------------------------------------------------------
654 // =====================================================================
655 
656 void vDataFile::GetEventIndexStartAndStop( int64_t* ap_indexStart, int64_t* ap_indexStop, int a_subsetNum, int a_nbSubsets )
657 {
659  // Basically here, the index start for a single MPI instance will be the current subset number.
660  // If multiple instances are used, the whole datafile is split into equal-size concatenated pieces.
661  // So for each instance, we just have to found the first index falling in its range (assuming that
662  // the event index step is always equal to the number of subsets).
663 
664  // For the first machine, index start is the current subset number
665  if (mp_ID->GetMPIRank()==0) *ap_indexStart = a_subsetNum;
666  // For the other machines, we must search for the first index falling in their range belonging to this
667  // subset (a subset being starting at a_subsetNum with a step equal to the number of subsets, a_nbSubsets)
668  else
669  {
670  // Compute the modulo of the first index of this machine minus the subset number with respect to the number of subsets
671  int64_t modulo = (m_mpi1stEvent-a_subsetNum) % a_nbSubsets;
672  // If this modulo is null, then the index start is the first index
673  if (modulo==0) *ap_indexStart = m_mpi1stEvent;
674  // Otherwise, the index start is equal to the first index plus the number of subsets minus the modulo
675  else *ap_indexStart = m_mpi1stEvent + (a_nbSubsets - modulo);
676  }
677 
678  // For index stop, we simply get the last event of the MPI instance (+1 because the for loop is exclusive)
679  *ap_indexStop = m_mpiLastEvent + 1;
680 }
681 
682 // =====================================================================
683 // ---------------------------------------------------------------------
684 // ---------------------------------------------------------------------
685 // =====================================================================
686 
688 {
690  Cerr("*****vDataFile::GetMaxRingDiff() -> This function is not implemented for the used system" << endl);
691  Cerr(" (this error may be prompted if the present function is erroneously called for a SPECT system)" << endl);
692  return -1;
693 }
694 
695 // =====================================================================
696 // ---------------------------------------------------------------------
697 // ---------------------------------------------------------------------
698 // =====================================================================
699 
701 {
702  // Verbose
704 
705  // Close all multithreaded datafiles before merging
706  for (int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
707  if (m2p_dataFile[th]) m2p_dataFile[th]->close();
708 
709  // If the output file doesn't exist yet, simply rename the first temporary file name using the ouput file name
710  if (!ifstream(m_dataFileName))
711  {
712  // If only one projection is required (i.e one threads && no projection of frame or gates)...
713  if(mp_ID->GetNbThreadsForProjection()==1 // No multithreading so no multiple tmp datafiles
714  && mp_ID->GetNbTimeFrames()
716  * mp_ID->GetNb2ndMotImgsForLMS() == 1)
717  {
718  // rename the first temporary file name to the global name
719  string tmp_file_name = m_dataFileName + "_0";
720 
721  // ... then just rename the first temporary file name using the ouput file name
722  rename(tmp_file_name.c_str(),m_dataFileName.c_str());
723  // no need to concatenate, so we leave here.
724  return 0 ;
725  }
726  }
727 
728  // Create the final output file which will concatenate the events inside the thread-specific data files
729  ofstream merged_file(m_dataFileName.c_str(), ios::out | ios::binary | ios::app);
730 
731  // Concatenation : generate input file ("data_file") to read the buffer of the thread-specific data files and store the information in the final output file
732  for (int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
733  {
734  // Build thread file name
735  stringstream ss; ss << th;
736  string file_name = m_dataFileName;
737  file_name.append("_").append(ss.str());
738  // Open it
739  // Note SS: Maybe we can use the m2p_dataFile[th] here by just rewarding to the beginning of the file ?
740  // Note TM: There were some issues involving the use of rdbuf and concatenation of the file in this case (ifstream were needed instead of fstream for some reasons)
741  // But we should have another look on how the projection data writing works with the implementation of the new analytical simulator.
742  ifstream data_file(file_name.c_str(), ios::binary | ios::in);
743 
744  if (!data_file)
745  {
746  Cerr(endl);
747  Cerr("***** vDataFile::PROJ_WriteData() -> Input temporary thread file '" << file_name << "' is missing or corrupted !" << endl);
748  return 1;
749  }
750 
751  // Concatenate it to the merged file
752  merged_file << data_file.rdbuf();
753  // Close file
754  data_file.close();
755 
756  // Re-open datafiles (needed if projecting frame/gates, as the contents of the temporary datafile are copied to the main datafile after each frame/gate)
757  m2p_dataFile[th]->open( file_name.c_str(), ios::binary | ios::out | ios::trunc);
758  }
759 
760  // Close merged file
761  merged_file.close();
762 
763  return 0;
764 }
765 
766 // =====================================================================
767 // ---------------------------------------------------------------------
768 // ---------------------------------------------------------------------
769 // =====================================================================
770 
772 {
773  // Verbose
775  if (m_verbose>=VERBOSE_DETAIL) Cout("vDataFile::PROJ_DeleteTmpDataFile() ..." << endl);
776  // Generate input file ("data_file") to read the buffer of the thread-specific data files and store the information in the final output file
777  for (int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
778  {
779  // Build thread file name
780  stringstream ss; ss << th;
781 
782  if (m2p_dataFile[th]) m2p_dataFile[th]->close();
783 
784  string file_name = m_dataFileName;
785  file_name.append("_").append(ss.str());
786 
787  // Remove temporary file for data output writing (Projection script only)
788  ifstream fcheck(file_name.c_str());
789  if(fcheck.good())
790  {
791  fcheck.close();
792  #ifdef _WIN32
793  string dos_instruction = "del " + file_name;
794  system(dos_instruction.c_str());
795  #else
796  remove(file_name.c_str());
797  #endif
798  }
799  }
800  // End
801  return 0;
802 }
803 
804 // =====================================================================
805 // ---------------------------------------------------------------------
806 // ---------------------------------------------------------------------
807 // =====================================================================
808 
809 vEvent* vDataFile::PROJ_GenerateEvent(int a_idxElt1, int a_idxElt2, int a_th)
810 {
812  // Only 1 line required for projection/sensitivity generation
813  m2p_BufferEvent[a_th]->SetNbLines(1);
814  m2p_BufferEvent[a_th]->SetID1(0, a_idxElt1);
815  m2p_BufferEvent[a_th]->SetID2(0, a_idxElt2);
816  // Return the event
817  return m2p_BufferEvent[a_th];
818 }
819 
820 // =====================================================================
821 // ---------------------------------------------------------------------
822 // ---------------------------------------------------------------------
823 // =====================================================================
824 
826 {
827  // Simply switch between the different data types
828  string data_type = "";
829  if (m_dataType==TYPE_CT) data_type = "CT";
830  else if (m_dataType==TYPE_PET) data_type = "PET";
831  else if (m_dataType==TYPE_SPECT) data_type = "SPECT";
832  else data_type = "unknown";
833  return data_type;
834 }
835 
836 // =====================================================================
837 // ---------------------------------------------------------------------
838 // ---------------------------------------------------------------------
839 // =====================================================================
840 
842 {
843  // Simply switch between the different data modes
844  string data_mode = "";
845  if (m_dataMode==MODE_HISTOGRAM) data_mode = "histogram";
846  else if (m_dataMode==MODE_LIST) data_mode = "list-mode";
847  else if (m_dataMode==MODE_NORMALIZATION) data_mode = "normalization";
848  else data_mode = "unknown";
849  return data_mode;
850 }
851 
852 // =====================================================================
853 // ---------------------------------------------------------------------
854 // ---------------------------------------------------------------------
855 // =====================================================================
856 
858 {
859  // Simply switch between the different data specs
860  string data_spec = "";
861  if (m_dataSpec==SPEC_EMISSION) data_spec = "emission";
862  else if (m_dataSpec==SPEC_TRANSMISSION) data_spec = "transmission";
863  else data_spec = "unknown";
864  return data_spec;
865 }
866 
867 // =====================================================================
868 // ---------------------------------------------------------------------
869 // ---------------------------------------------------------------------
870 // =====================================================================
everything ... be careful when file is larger than memory
#define KEYWORD_OPTIONAL_SUCCESS
This class is designed to be a mother virtual class for DataFile.
void GetEventIndexStartAndStop(int64_t *ap_indexStart, int64_t *ap_indexStop, int a_subsetNum=0, int a_NbSubsets=1)
#define MODE_HISTOGRAM
void SetNbLines(uint16_t a_value)
#define MODE_NORMALIZATION
#define Cerr(MESSAGE)
int CheckParameters()
Check the initialization of member variables Call the CheckSpecificParameters() function implemente...
virtual int CheckFileSizeConsistency()=0
int SetParametersFrom(vDataFile *ap_DataFile)
int ReadInfoInHeader(bool a_affectQuantificationFlag=true)
int SetCalibrationFactor(int a_bed, FLTNB a_calibrationFactor)
virtual int ReadSpecificInfoInHeader(bool a_affectQuantificationFlag=true)=0
int CheckConsistencyWithAnotherBedDataFile(vDataFile *ap_DataFile)
static sOutputManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
virtual ~vDataFile()
vDataFile destructor.
virtual int GetMaxRingDiff()
Return an error by default. This function is surcharged by the PET (and CT) scanner daughter class...
int Open(const std::string &filename, size_t mappedBytes=WholeFile, CacheHint hint=Normal)
open file, mappedBytes = 0 maps the whole file
int InitializeMappedFile()
Check the datafile existency, map it to memory and get the raw char* pointer. .
virtual int CheckSpecificConsistencyWithAnotherDataFile(vDataFile *ap_DataFile)=0
int PROJ_WriteData()
Write/Merge chunk of data in a general data file.
vEvent * GetEvent(int64_t a_eventIndex, int a_th=0)
int CloseFile()
Close as many binary file stream for writing.
#define DEBUG_VERBOSE(IGNORED1, IGNORED2)
virtual int CheckSpecificParameters()=0
This function is implemented in child classes Check specific parameters of child classes...
Singleton class that manages output writing on disk (images, sinograms, etc). It also manages loggi...
vDataFile()
vDataFile constructor.
int GetMPISize()
Get the MPI size (the number of MPI instances)
int OpenFileForWriting(string a_suffix="")
vEvent * PROJ_GenerateEvent(int idx_elt1, int idx_elt2, int a_th)
virtual void DescribeSpecific()=0
A pure virtual function used to describe the specific parts of the datafile.
#define KEYWORD_MANDATORY
#define KEYWORD_OPTIONAL
#define SPEC_TRANSMISSION
void SetID2(int a_line, uint32_t a_value)
Mother class for the Event objects.
int GetNb2ndMotImgsForLMS()
call the eponym function from the oDynamicDataManager object
const unsigned char * GetData() const
raw access
void Describe()
A function used to describe the generic parts of the datafile.
int GetNbThreadsForProjection()
Get the number of threads used for projections.
virtual vEvent * GetEventSpecific(char *ap_buffer, int a_th)=0
Portable read-only memory mapping (Windows and Linux)
int PROJ_DeleteTmpDataFile()
Delete temporary datafile used for multithreaded output writing if needed.
int GetVerbose()
Get the verbose level.
virtual int Shuffle(int64_t)
!!!\ This function has been modified to be used specifically with a
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...
int SetAcquisitionTime(int a_bed, FLTNB a_timeStartInSec, FLTNB a_durationInSec, string a_GateListDurationsInSec)
#define Cout(MESSAGE)
virtual int SetSpecificParametersFrom(vDataFile *ap_DataFile)=0
oImageDimensionsAndQuantification * mp_ID
void SetID1(int a_line, uint32_t a_value)