CASToR  1.1
Tomographic Reconstruction (PET/SPECT)
 All Classes Files Functions Variables Typedefs Macros Groups Pages
vDataFile.cc
Go to the documentation of this file.
1 
2 /*
3  Implementation of class vDataFile
4 
5  - separators: X
6  - doxygen: X
7  - default initialization: X
8  - CASTOR_DEBUG: X
9  - CASTOR_VERBOSE: X
10 */
11 
19 #include "vDataFile.hh"
20 
21 // =====================================================================
22 // ---------------------------------------------------------------------
23 // ---------------------------------------------------------------------
24 // =====================================================================
25 
27 {
28  mp_ID = NULL;
29  m_verbose = -1;
30 
31  // Variables related to the acquisition
32  m2p_dataFile = NULL;
33  m_headerFileName = "";
34  m_dataFileName = "";
35  m_scannerName = "";
38  m_totalNbEvents = -1;
39  m_dataType = -1;
40  m_bedIndex = -1;
41  m_startTimeInSec = 0.;
42  m_durationInSec = -1.;
44  m_sizeEvent = -1;
45 
46  // Default POI (meaning we do not have any)
47  mp_POIResolution[0] = -1.;
48  mp_POIResolution[1] = -1.;
49  mp_POIResolution[2] = -1.;
50  mp_POIDirectionFlag[0] = false;
51  mp_POIDirectionFlag[1] = false;
52  mp_POIDirectionFlag[2] = false;
53  m_POIInfoFlag = false;
54  m_ignorePOIFlag = false;
55 
56  // Variable related to Buffer/Container arrays
57  m2p_BufferEvent = NULL;
58  mp_arrayEvents = NULL;
60  m_mpi1stEvent = -1;
61  m_mpiLastEvent = -1;
62  m_mpiNbEvents = -1;
66  m_percentageLoad = -1;
67  m_requestBufferFilling = false;
70  mp_overBufferRange = NULL;
72 }
73 
74 // =====================================================================
75 // ---------------------------------------------------------------------
76 // ---------------------------------------------------------------------
77 // =====================================================================
78 
80 {
81  // Free array event buffer
82  if (m_sizeArrayEvents > 0) if (mp_arrayEvents != NULL) delete mp_arrayEvents;
83 
84  // Free the (char**) m2p_bufferEventFromFile
86  {
87  for(int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
89  delete[] m2p_bufferEventFromFile;
90  }
91  // Free the (vEvent) buffer event
92  if (m2p_BufferEvent)
93  {
94  for(int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
95  if (m2p_BufferEvent[th]) delete m2p_BufferEvent[th];
96  delete[] m2p_BufferEvent;
97  }
98  // Close datafiles and delete them
99  if (m2p_dataFile)
100  {
101  for(int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
102  if (m2p_dataFile[th]) m2p_dataFile[th]->close();
103  delete m2p_dataFile;
104  }
105  // Destroy the boolean tabs that are used to organize and synchronize buffer reading
108  // Destroy events reading counters, but print out before that
110  {
111  // Verbose
112  if (m_verbose>=4)
113  {
114  Cout("vDataFile::~vDataFile() -> Number of events directly read from file for each thread" << endl);
115  int64_t total = 0;
116  for (int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
117  {
118  Cout(" --> Thread " << th+1 << " | " << mp_nbEventsReadFromFile[th] << " events read from file" << endl);
119  total += mp_nbEventsReadFromFile[th];
120  }
121  Cout(" --> Total number of events read from file: " << total << endl);
122  Cout(" --> Number of events in the datafile: " << m_totalNbEvents << endl);
123  }
124  // Free memory
126  }
127 }
128 
129 // =====================================================================
130 // ---------------------------------------------------------------------
131 // ---------------------------------------------------------------------
132 // =====================================================================
133 
134 int vDataFile::ReadInfoInHeader(bool a_affectQuantificationFlag)
135 {
136  if (m_verbose>=3) Cout("vDataFile::ReadInfoInHeader() -> Read datafile header from '" << m_headerFileName << " ...'" << endl);
137 
138  // Read mandatory general fields in the header, check if errors (either mandatory tag not found or issue during data reading/conversion (==1) )
140  {
141  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while trying to read number of events in the header data file !" << endl);
142  return 1;
143  }
145  {
146  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while trying to read scanner name in the header data file !" << endl);
147  return 1;
148  }
149 
150  // Get data file name
152  {
153  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while trying to read data filename in the header data file !" << endl);
154  return 1;
155  }
156  // 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
157  // files are side by side).
158  // This is currently only unix compatible...
159  if (m_dataFileName.substr(0,1)!=OS_SEP && m_headerFileName.find(OS_SEP)!=string::npos)
160  {
161  // Extract the path from the header file name
162  size_t last_slash = m_headerFileName.find_last_of(OS_SEP);
163  // Paste the path to the data file name
164  m_dataFileName = m_headerFileName.substr(0,last_slash+1) + m_dataFileName;
165  }
166 
167  // For data mode, multiple declarations are allowed, so we get the mode as a string and do some checks
168  string data_mode = "";
169  if (ReadDataASCIIFile(m_headerFileName, "Data mode", &data_mode, 1, KEYWORD_MANDATORY) )
170  {
171  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while trying to read data mode in the header data file !" << endl);
172  return 1;
173  }
174  if ( data_mode=="LIST" || data_mode=="LISTMODE" || data_mode=="LIST-MODE" ||
175  data_mode=="list" || data_mode=="listmode" || data_mode=="list-mode" || data_mode=="0" ) m_dataMode = MODE_LIST;
176  else if ( data_mode=="HISTOGRAM" || data_mode=="histogram" || data_mode=="Histogram" ||
177  data_mode=="HISTO" || data_mode=="histo" || data_mode=="Histo" || data_mode=="1" ) m_dataMode = MODE_HISTOGRAM;
178  else if ( data_mode=="NORMALIZATION" || data_mode=="normalization" || data_mode=="Normalization" ||
179  data_mode=="NORM" || data_mode=="norm" || data_mode=="Norm" || data_mode=="2" ) m_dataMode = MODE_NORMALIZATION;
180  else
181  {
182  Cerr("***** vDataFile::ReadInfoInHeader() -> Unknown data mode '" << data_mode << "' found in header file !" << endl);
183  return 1;
184  }
185 
186  // For data type, multiple declarations are allowed, so we get the mode as a string and do some checks
187  string data_type = "";
188  if (ReadDataASCIIFile(m_headerFileName, "Data type", &data_type, 1, KEYWORD_MANDATORY) )
189  {
190  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while trying to read data type in the header data file !" << endl);
191  return 1;
192  }
193  if ( data_type=="PET" || data_type=="pet" || data_type=="0" ) m_dataType = TYPE_PET;
194  else if ( data_type=="SPECT" || data_type=="spect" || data_type=="1" ) m_dataType = TYPE_SPECT;
195  else if ( data_type=="TRANSMISSION" || data_type=="transmission" || data_type=="Transmission" ||
196  data_type=="trans" || data_type=="TRANS" || data_type=="2" ) m_dataType = TYPE_TRANSMISSION;
197  else
198  {
199  Cerr("***** vDataFile::ReadInfoInHeader() -> Unknown data type '" << data_type << "' found in header file !" << endl);
200  return 1;
201  }
202 
203  // Get start time and duration (optional for the normalization mode
205  {
207  {
208  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while trying to read acquisition start time in the header data file !" << endl);
209  return 1;
210  }
212  {
213  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while trying to read acquisition stop time in the header data file !" << endl);
214  return 1;
215  }
216  }
217  else
218  {
219  if (ReadDataASCIIFile(m_headerFileName, "Start time (s)", &m_startTimeInSec, 1, KEYWORD_OPTIONAL) == 1 )
220  {
221  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while reading acquisition start time in the header data file !" << endl);
222  return 1;
223  }
224  if (ReadDataASCIIFile(m_headerFileName, "Duration (s)", &m_durationInSec, 1, KEYWORD_OPTIONAL) == 1 )
225  {
226  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while reading acquisition stop time in the header data file !" << endl);
227  return 1;
228  }
229  }
230 
231  // Set the acquisition timing to the quantification factors
232  if (a_affectQuantificationFlag && mp_ID->SetAcquisitionTime(m_bedIndex, m_startTimeInSec, m_durationInSec))
233  {
234  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while passing acquisition start and stop time to the ImageDimensionsAndQuantification !" << endl);
235  return 1;
236  }
237 
238  // Read optional fields in the header, check if errors (issue during data reading/conversion (==1) )
239  if (ReadDataASCIIFile(m_headerFileName, "Calibration factor", &m_calibrationFactor, 1, KEYWORD_OPTIONAL) == 1 ||
241  ReadDataASCIIFile(m_headerFileName, "POI correction flag", &m_POIInfoFlag, 3, KEYWORD_OPTIONAL) == 1 )
242  {
243  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while reading optional field in the header data file !" << endl);
244  return 1;
245  }
246 
247  // Read fields specific to the modality (call to the related function implemented in child classes)
248  if (ReadSpecificInfoInHeader(a_affectQuantificationFlag) )
249  {
250  Cerr("***** vDataFile::ReadInfoInHeader() -> Error while trying to read modality-specific informations from the header data file !" << endl);
251  return 1;
252  }
253 
254  // Give the calibration factor to the oImageDimensionsAndQuantification that manages the quantification factors
255  if (a_affectQuantificationFlag && mp_ID->SetCalibrationFactor(m_bedIndex, m_calibrationFactor))
256  {
257  Cerr("***** vDataFile::ReadSpecificInfoInHeader() -> A problem occured while setting the calibration factor to oImageDimensionsAndQuantification !" << endl);
258  return 1;
259  }
260 
261  return 0;
262 }
263 
264 // =====================================================================
265 // ---------------------------------------------------------------------
266 // ---------------------------------------------------------------------
267 // =====================================================================
268 
270 {
271  // Verbose
272  if(m_verbose >=3) Cout("vDataFile::CheckParameters() ..." << endl);
273  // Check mandatory parameters
274  if (mp_ID == NULL)
275  {
276  Cerr("***** vDataFile::CheckParameters() -> Error : ImageDimensionsAndQuantification object not initialized !" << endl);
277  return 1;
278  }
279  if (m_headerFileName == "")
280  {
281  Cerr("***** vDataFile::CheckParameters() -> Error : string containing path to header file not initialized !" << endl);
282  return 1;
283  }
284  if (m_dataFileName == "")
285  {
286  Cerr("***** vDataFile::CheckParameters() -> Error : string containing path to raw data file not initialized !" << endl);
287  return 1;
288  }
289  if (m_percentageLoad<0 || m_percentageLoad>100)
290  {
291  Cerr("***** vDataFile::CheckParameters() -> Percentage load of the data file incorrectly set !" << endl);
292  return 1;
293  }
294  if (m_totalNbEvents<0)
295  {
296  Cerr("***** vDataFile::CheckParameters() -> Number of events incorrectly initialized !" << endl);
297  return 1;
298  }
300  {
301  Cerr("***** vDataFile::CheckParameters() -> Data mode incorrectly initialized !" << endl);
302  return 1;
303  }
305  {
306  Cerr("***** vDataFile::CheckParameters() -> Acquisition duration (s) incorrectly initialized !" << endl);
307  return 1;
308  }
310  {
311  Cerr("***** vDataFile::CheckParameters() -> Data type incorrectly initialized !" << endl);
312  return 1;
313  }
314  if (m_bedIndex<0)
315  {
316  Cerr("***** vDataFile::CheckParameters() -> Bed position index incorrectly initialized !" << endl);
317  return 1;
318  }
319  if (m_verbose<0)
320  {
321  Cerr("***** vDataFile::CheckParameters() -> Verbosity incorrectly initialized !" << endl);
322  return 1;
323  }
324  // Call to the related function implemented in child classes
326  {
327  Cerr("***** vDataFile::CheckParameters() -> Error while checking specific parameters !" << endl);
328  return 1;
329  }
330  // End
331  return 0;
332 }
333 
334 // =====================================================================
335 // ---------------------------------------------------------------------
336 // ---------------------------------------------------------------------
337 // =====================================================================
338 
340 {
341  // Check data type
342  if (m_dataType!=ap_Datafile->GetDataType())
343  {
344  Cerr("***** vDataFile::CheckConsistencyWithAnotherBedDatafile() -> Data types are inconsistent !" << endl);
345  return 1;
346  }
347  // Check data mode
348  if (m_dataMode!=ap_Datafile->GetDataMode())
349  {
350  Cerr("***** vDataFile::CheckConsistencyWithAnotherBedDatafile() -> Data modes are inconsistent !" << endl);
351  return 1;
352  }
353  // For histogram and normalization modes, check the number of events
355  {
356  Cerr("***** vDataFile::CheckConsistencyWithAnotherBedDatafile() -> Total number of events are inconsistent !" << endl);
357  return 1;
358  }
359  // Check the scanner name
360  if (m_scannerName!=ap_Datafile->GetScannerName())
361  {
362  Cerr("***** vDataFile::CheckConsistencyWithAnotherBedDatafile() -> Scanner names are inconsistent !" << endl);
363  return 1;
364  }
365  // Check that the bed displacement is more than 0. in the scanner
366  if (sScannerManager::GetInstance()->GetScannerObject()->GetMultiBedDisplacementInMm()<=0.)
367  {
368  Cerr("***** vDataFile::CheckConsistencyWithAnotherBedDatafile() -> Bed displacement between two successive bed positions must be strictly positive !" << endl);
369  return 1;
370  }
371  // Check the calibration factor
372  if (m_calibrationFactor!=ap_Datafile->GetCalibrationFactor())
373  {
374  Cerr("***** vDataFile::CheckConsistencyWithAnotherBedDatafile() -> Calibration factors are inconsistent !" << endl);
375  return 1;
376  }
377  // Check event size
378  if (m_sizeEvent!=ap_Datafile->GetEventSize())
379  {
380  Cerr("***** vDataFile::CheckConsistencyWithAnotherBedDatafile() -> Events sizes are inconsistent !" << endl);
381  return 1;
382  }
383  // Check POI info flag
384  if (m_POIInfoFlag!=ap_Datafile->GetPOIInfoFlag())
385  {
386  Cerr("***** vDataFile::CheckConsistencyWithAnotherBedDatafile() -> POI flags are inconsistent !" << endl);
387  return 1;
388  }
389  // Check POI resolutions
390  if ( (mp_POIResolution[0]!=ap_Datafile->GetPOIResolution()[0]) ||
391  (mp_POIResolution[1]!=ap_Datafile->GetPOIResolution()[1]) ||
392  (mp_POIResolution[2]!=ap_Datafile->GetPOIResolution()[2]) )
393  {
394  Cerr("***** vDataFile::CheckConsistencyWithAnotherBedDatafile() -> POI resolutions are inconsistent !" << endl);
395  return 1;
396  }
397  // Call specific function
399  {
400  Cerr("***** vDataFile::CheckConsistencyWithAnotherBedDatafile() -> Inconsistency detected for specific characteristics !" << endl);
401  return 1;
402  }
403  // End
404  return 0;
405 }
406 
407 // =====================================================================
408 // ---------------------------------------------------------------------
409 // ---------------------------------------------------------------------
410 // =====================================================================
411 
413 {
414  if (m_verbose>=3) Cout("vDataFile::InitializeFile() ..." << endl);
415 
416  // Instantiate as many file streams as threads
417  m2p_dataFile = new fstream*[mp_ID->GetNbThreadsForProjection()];
418  for (int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
419  {
420  m2p_dataFile[th] = new fstream( m_dataFileName.c_str(), ios::binary| ios::in );
421  // If the datafile does not exist, notify to the user and exit program.
422  if (!m2p_dataFile[th]->is_open())
423  {
424  Cerr("***** vDataFile::InitializeFile() -> Error reading the input data file at the path: '" << m_dataFileName.c_str() << "'" << endl);
425  Cerr(" (provided in the data file header: " << m_headerFileName << ")" << endl);
426  return 1;
427  }
428  }
429  // Check file size consistency here (this is a pure virtual function implemented by children)
431  {
432  Cerr("***** vDataFile::InitializeFile() -> A problem occured while checking file size consistency !" << endl);
433  return 1;
434  }
435  // Initialization of the buffer related to direct data reading from file (during reconstruction)
437  for (int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
438  {
439  m2p_bufferEventFromFile[th] = new char[m_sizeEvent];
440  }
441  // Initialization of the boolean tab used to know if any thread is currently reading into the file buffer
442  mp_currentlyReadingBuffer = (bool*)malloc(mp_ID->GetNbThreadsForProjection()*sizeof(bool));
443  for (int th=0; th<mp_ID->GetNbThreadsForProjection(); th++) mp_currentlyReadingBuffer[th] = false;
444  // Initialization of the boolean tab used to know if some threads are under the file buffer range
445  mp_overBufferRange = (bool*)malloc(mp_ID->GetNbThreadsForProjection()*sizeof(bool));
446  for (int th=0; th<mp_ID->GetNbThreadsForProjection(); th++) mp_overBufferRange[th] = false;
447  // Initialization of the counters for how many events are read directly from file
448  mp_nbEventsReadFromFile = (int64_t*)malloc(mp_ID->GetNbThreadsForProjection()*sizeof(int64_t));
449  for (int th=0; th<mp_ID->GetNbThreadsForProjection(); th++) mp_nbEventsReadFromFile[th] = 0;
450 
451  // ------------------ Compute here the piece of file that each MPI instance manages --------------------
452 
453  // 1. Compute the number of events that each instance has to manage
454  int64_t instance_size = m_totalNbEvents / mp_ID->GetMPISize();
455  // All instances manage an equal part of the file but the last one which also manages the few last events
456  if (mp_ID->GetMPIRank()!=mp_ID->GetMPISize()-1) m_mpiNbEvents = instance_size;
457  else m_mpiNbEvents = instance_size + (m_totalNbEvents - instance_size*mp_ID->GetMPISize());
458  // 2. Compute the first event managed by the instance
459  m_mpi1stEvent = mp_ID->GetMPIRank() * instance_size;
460  // 3. Compute the last event managed by the instance
461  m_mpiLastEvent = m_mpi1stEvent + m_mpiNbEvents - 1;
462 
463  // Instanciation of the array of preloaded events (if enabled)
464  if (m_percentageLoad>0)
465  {
466  if (m_verbose>=3)
467  {
468  Cout(" --> Allocating memory for the datafile" << endl);
469  Cout(" --> Number of events in memory: " << m_mpiNbEvents << endl);
470  }
471  // Computation of the exact size of the buffer of preloaded events from the provided percentage load
472  m_sizeArrayEvents = (((int64_t)m_percentageLoad) * m_mpiNbEvents) / 100;
473  // Compute the number of bytes
474  int64_t nb_bytes_to_load = m_sizeArrayEvents*m_sizeEvent;
475  // Verbose to say that we proceed to the first reading of the datafile
476  if (m_verbose>=3) Cout(" --> Load of " << m_percentageLoad << "% of the datafile (" << nb_bytes_to_load << " bytes)" << endl);
477  // Instantiate the array of events in which the file content is directly copied
478  mp_arrayEvents = new char [nb_bytes_to_load];
479  }
480  else m_sizeArrayEvents = 0;
481 
482  // End
483  return 0;
484 }
485 
486 // =====================================================================
487 // ---------------------------------------------------------------------
488 // ---------------------------------------------------------------------
489 // =====================================================================
490 
492 {
493  // Reset the range indices only if the percentage is strictly between 0 and 100.
494  // For the case 0, it is simply a security.
495  // For the case 100, it would force the buffer to be re-read again...
496  // The purpose of this function is to be called before a loop over the datafile, so that all
497  // threads will have to deal with event indices always inside or above the range (never under).
498  // This is important to avoid that the thread 0 filling the buffer is ahead of other threads, leading to the other threads
499  // not benefiting from the file buffer. There is a mechanism in the GetEvent() function so that the thread 0 waits for the
500  // other threads to be over the buffer range before loading a new portion of the data file into the buffer.
501  if (m_percentageLoad>0 && m_percentageLoad<100)
502  {
503  m_1stIdxArrayEvents = -1;
505  }
506 }
507 
508 // =====================================================================
509 // ---------------------------------------------------------------------
510 // ---------------------------------------------------------------------
511 // =====================================================================
512 
513 int vDataFile::FillBuffer(int64_t a_eventIndex)
514 {
515  #ifdef CASTOR_VERBOSE
516  if (m_verbose >=4) Cout("vDataFile::FillBuffer() ..." << endl);
517  #endif
518 
519  // Important note: m_mpiLastEvent/m_lastIdxArrayEvent are the last event indices INCLUDED in the instance/buffer
520 
521  // Note: This function is called from the GetEvent() function inside the iterations, but only by thread #0
522  int thread_0 = 0;
523 
524  // Seek to the appropriate position in the input data file
525  m2p_dataFile[thread_0]->seekg(m_sizeEvent*a_eventIndex);
526 
527  // Compute the last event index that can be loaded into the buffer (included; not excluded)
528  int64_t last_included_event_that_can_be_loaded = a_eventIndex + m_sizeArrayEvents - 1;
529 
530  // This is the number of events that will be loaded
531  int64_t nb_events_to_load = 0;
532  // If the number of remaining events to be loaded is less than the buffer capacity, we only load until m_mpiLastEvent is reached
533  if (last_included_event_that_can_be_loaded > m_mpiLastEvent) nb_events_to_load = m_mpiLastEvent + 1 - a_eventIndex;
534  // Otherwise we fully load the buffer
535  else nb_events_to_load = m_sizeArrayEvents;
536 
537  // Read the data
538  m2p_dataFile[thread_0]->read(mp_arrayEvents, nb_events_to_load*m_sizeEvent);
539 
540  // Todo: histogram/SPECT only!!!!!!!!!!!!!!
541  //Shuffle( nb_events_to_load );
542 
543  // Check if the reading was successfull
544  if (!(*m2p_dataFile[thread_0]))
545  {
546  Cerr("***** vDataFile::FillBuffer() -> Failed to read " << nb_events_to_load << " events in datafile (only read " << m2p_dataFile[thread_0]->gcount() << " events) !" << endl);
547  return 1;
548  }
549 
550  // Update the buffer first and last indices
551  m_1stIdxArrayEvents = a_eventIndex;
552  m_lastIdxArrayEvents = m_1stIdxArrayEvents + nb_events_to_load - 1;
553 
554  // Verbose
555  #ifdef CASTOR_VERBOSE
556  if (m_verbose >=4) Cout("vDataFile::FillBuffer() completed" << endl);
557  #endif
558 
559  // End
560  return 0;
561 }
562 
563 // =====================================================================
564 // ---------------------------------------------------------------------
565 // ---------------------------------------------------------------------
566 // =====================================================================
567 
568 int vDataFile::Shuffle( int64_t nb_events_to_load )
569 {
570 /*
571  // Buffer storing ordered indices from ( 0 ) to ( nb_events_to_load - 1 )
572  int64_t *rndmIdx = new int64_t[ nb_events_to_load ];
573  std::iota( rndmIdx, rndmIdx + nb_events_to_load, 0 );
574 
575  // Initializing random
576  std::random_device rd;
577  std::mt19937 rndm( rd() );
578  rndm.seed( 1100001001 );
579 
580  // Shuffling the buffer of indices
581  std::shuffle( rndmIdx, rndmIdx + nb_events_to_load, rndm );
582 
583  // Creating a tmp buffer
584  char *mp_arrayEvents_tmp = new char[ nb_events_to_load*m_sizeEvent ];
585 
586  // Copy sorted buffer to shuffled buffer
587  for( int64_t i = 0; i < nb_events_to_load; ++i )
588  {
589  for( int64_t j = 0; j < m_sizeEvent; ++j )
590  {
591  mp_arrayEvents_tmp[ i * m_sizeEvent + j ] = mp_arrayEvents[ rndmIdx[ i ] * m_sizeEvent + j ];
592  }
593  }
594 
595  // Freeing memory
596  delete[] rndmIdx;
597  delete[] mp_arrayEvents;
598 
599  mp_arrayEvents = mp_arrayEvents_tmp;
600 */
601  return 0;
602 }
603 
604 // =====================================================================
605 // ---------------------------------------------------------------------
606 // ---------------------------------------------------------------------
607 // =====================================================================
608 
609 vEvent* vDataFile::GetEventWithAscendingOrderAssumption(int64_t a_eventIndex, int64_t a_eventIndexLimit, int a_th)
610 {
611  // With the assumption that this function is called from a loop over event indices in an ascending order, the implementation
612  // is as follows:
613  // - The ResetBufferRange() function MUST be called before launching the loop over event indices
614  // - Thread 0 is a particular case: it is the only one able to fill the buffer, and to do that it waits for the other threads to be above the current range.
615  // - The other threads read directly from the file if the first thread is currently filling the buffer, or if below or above the current range. In the latter
616  // case, they set a boolean flag saying they are above so that the thread 0 can know it. Otherwise they read from the buffer.
617  // See the comments at the beginning of the GetEventWithoutOrderAssumption() function for details about motivations, etc.
618 
619  #ifdef CASTOR_VERBOSE
620  if (m_verbose >=4) Cout("vDataFile::GetEventWithAscendingOrderAssumption() ..." << endl);
621  #endif
622 
623  // Particular case for an empty buffer (-load 0): read the event directly from the file, whatever the thread number
624  if (m_sizeArrayEvents==0) return GetEventFromFile(a_eventIndex, a_th);
625 
626  // Special treatment for the first thread (it is the only one allowed to refill the buffer)
627  if (a_th==0)
628  {
629  // If the event index is below the current indices range loaded in memory, it is not normal as only this thread refills the buffer
630  if (a_eventIndex<m_1stIdxArrayEvents)
631  {
632  Cerr("***** vDataFile::GetEventWithAscendingOrderAssumption() -> The requested event index is below the current range of indices loaded in memory !" << endl);
633  Cerr(" --> Note that this situation should never happen if this function is being called within an ascending ordered loop on event indices, AND if" << endl);
634  Cerr(" the vDataFile::ResetBufferRange() function has been called before performing the loop. So if this is really the case, then please report" << endl);
635  Cerr(" the bug." << endl);
636  return NULL;
637  }
638  // Else if the event is above the current indices range, then this first thread has to refill the buffer
639  else if (a_eventIndex>m_lastIdxArrayEvents)
640  {
641  // Here, the thread has to wait for all others to be over the current buffer range
642  bool all_threads_over_range = true;
643  for (int th=1; th<mp_ID->GetNbThreadsForProjection(); th++)
644  all_threads_over_range = all_threads_over_range && mp_overBufferRange[th];
645  while (!all_threads_over_range)
646  {
647  all_threads_over_range = true;
648  for (int th=1; th<mp_ID->GetNbThreadsForProjection(); th++)
649  all_threads_over_range = all_threads_over_range && mp_overBufferRange[th];
650  }
651  // Now we are good, so we notify that the first thread is currently filling the buffer
653  // Now the first thread can safely fill the buffer from the current event index, because all threads are above the range and they know the first
654  // thread will refill the buffer
655  if (FillBuffer(a_eventIndex))
656  {
657  Cerr("***** vDataFile::GetEventWithAscendingOrderAssumption() -> An error occured while filling the buffer from datafile !" << endl);
658  return NULL;
659  }
660  // Say that the first thread is done filling the buffer
661  m_currentlyFillingBuffer = false;
662  }
663  // Get address of the event to recover from the array buffer
664  char* event_address_in_array = mp_arrayEvents + (a_eventIndex-m_1stIdxArrayEvents)*m_sizeEvent;
665  // And read from the buffer
666  return GetEventFromBuffer(event_address_in_array, a_th);
667  }
668  // For the other threads
669  else
670  {
671  // The event pointer that will be returned
672  vEvent* p_event;
673  // We first check if the thread 0 is currently filling the buffer; in that case then read from file
675  {
676  // In this case, we still say that the thread is over the buffer range. In case this thread finishes its part of the loop
677  // while the first thread is filling the buffer, the first thread won't be blocked into waiting for all threads to be over
678  // the range.
679  mp_nbEventsReadFromFile[a_th]++;
680  p_event = GetEventFromFile(a_eventIndex, a_th);
681  }
682  // Else if the event index is below the current indices range
683  else if (a_eventIndex<m_1stIdxArrayEvents)
684  {
685  // This situation may still occur in some cases: right after a buffer filling and if the number of subsets is high. This
686  // is because the new portion of the data file loaded by the thread 0 is not strictly contiguous to the previous portion
687  // due to subsets and multi-threading (in case of a block thread sequence higher than 1 or a high number of threads). In
688  // this case we read directly from the file.
689  mp_overBufferRange[a_th] = false;
690  mp_nbEventsReadFromFile[a_th]++;
691  p_event = GetEventFromFile(a_eventIndex, a_th);
692  }
693  // Else if the event index is above the current indices range
694  else if (a_eventIndex>m_lastIdxArrayEvents)
695  {
696  // We say that this thread is above the current range, so that the thread 0 knows that
697  mp_overBufferRange[a_th] = true;
698  // And we read directly from the file
699  mp_nbEventsReadFromFile[a_th]++;
700  p_event = GetEventFromFile(a_eventIndex, a_th);
701  }
702  // Else, we can safely read from the buffer
703  else
704  {
705  // We check again here that the first thread is not reading into the buffer in case it started between now and the first check.
706  // This allows to catch some potential bad behaviors in extrem conditions (a lot of threads with a very small load percentage).
708  {
709  mp_nbEventsReadFromFile[a_th]++;
710  p_event = GetEventFromFile(a_eventIndex, a_th);
711  }
712  else
713  {
714  // Say that we are not above range
715  mp_overBufferRange[a_th] = false;
716  // Compute the adress into the buffer
717  char* event_address_in_array = mp_arrayEvents + (a_eventIndex-m_1stIdxArrayEvents)*m_sizeEvent;
718  // Get the event
719  p_event = GetEventFromBuffer(event_address_in_array, a_th);
720  }
721  }
722  // If the current index is over the provided limit index, we say that this thread is over the buffer range to avoid thread 0 to be stuck
723  if (a_eventIndex >= a_eventIndexLimit) mp_overBufferRange[a_th] = true;
724  // Return the event
725  return p_event;
726  }
727 }
728 
729 // =====================================================================
730 // ---------------------------------------------------------------------
731 // ---------------------------------------------------------------------
732 // =====================================================================
733 
734 vEvent* vDataFile::GetEventWithoutOrderAssumption(int64_t a_eventIndex, int a_th)
735 {
736  // Without any assumption about the order of event indices, the implementation of this function is quite
737  // tricky when we want genericity and efficiency! We absolutely want that only one thread deals with the
738  // buffer filling (the first thread) while others are not blocked during this process and can still read
739  // events directly from the file. Under these restrictions, multiple strategies were tested, but the current
740  // one is the most efficient and stable one. The most stressful situation for this function is when using
741  // many threads with a small load percentage. The use of OpenMP locks, in many different ways has always
742  // lead to rare occurences (1-2%) of segmentation fault (load percentage typically between 1 to 10 and 16
743  // threads), which could not be explained but also not tolerated... The current implementation uses home-made
744  // locks at multiple levels but which does not hamper the efficiency. It has been validated with intense testing
745  // (1500 reconstructions of the PET benchmark with a number of threads randomly chosen between 50 to 120 and a load
746  // percentage of 2%; note that if somebody has such a powerfull computer with such a small amount of RAM, it would
747  // be quite a paradoxal situation, but nonetheless, we wanted to stress this function at most). The results are:
748  // 1 segmentation fault and 2 runs with a few pixels variating up to 0.2% (basically, it is one event at one moment
749  // that succeeds in passing between the test of m_requestBufferFilling and the affectation of mp_currentlyReadingBuffer,
750  // so that it runs through the GetEventFromBuffer function while the first thread also succeed to pass between the
751  // checks and is filling the buffer at the same time; plus in order to give a corrupted event, the buffer has to be
752  // changed right before the thread read at this memory location; with such rare stuff in such rare conditions, we feel
753  // this function is sufficiently robust with respect to the restrictions we assume at the beginning; still, if
754  // someone has something better, we take it!).
755  // Anyway, if you want to get events inside an ascending ordered loop over events, then use the GetEventWithAscendingOrderAssumption()
756  // function instead. It is more efficient and has the same failure rate in the same chaotic conditions (a lot of threads with a very
757  // small load percentage. But do not forget to call the ResetBufferRange() function before the loop. However, note that this function
758  // is not yet compatible with the use of MPI.
759 
760  #ifdef CASTOR_VERBOSE
761  if (m_verbose >=4) Cout("vDataFile::GetEventWithoutOrderAssumption() ..." << endl);
762  #endif
763 
764  // Particular case for an empty buffer (-load 0): read the event directly from the file, whatever the thread number
765  if (m_sizeArrayEvents==0) return GetEventFromFile(a_eventIndex, a_th);
766 
767  // Special treatment for the first thread (it is the only one allowed to refill the buffer)
768  if (a_th==0)
769  {
770  // If the event is outside the current buffer, then the thread refills the buffer
771  if (a_eventIndex<m_1stIdxArrayEvents || a_eventIndex>m_lastIdxArrayEvents)
772  {
773  // Say that the first thread is requesting to fill the buffer
774  m_requestBufferFilling = true;
775  // Now this thread will wait for all other threads to declare that they are not currently reading into the buffer (otherwise
776  // the reading of the event by the other threads may be corrupted). The other thread are now aware that the first thread is
777  // waiting so they will not read from the buffer once finished their current reading.
778  bool all_threads_not_reading_buffer = true;
779  for (int th=1; th<mp_ID->GetNbThreadsForProjection(); th++)
780  all_threads_not_reading_buffer = all_threads_not_reading_buffer && !mp_currentlyReadingBuffer[th];
781  while (!all_threads_not_reading_buffer)
782  {
783  all_threads_not_reading_buffer = true;
784  for (int th=1; th<mp_ID->GetNbThreadsForProjection(); th++)
785  all_threads_not_reading_buffer = all_threads_not_reading_buffer && !mp_currentlyReadingBuffer[th];
786  }
787  // We are good, so say that the first thread is currently filling the buffer (this is needed below, see explanations)
789  // Now the first thread can safely fill the buffer from the current event index, because as all threads know it was waiting for
790  // filling the buffer, they know read directly from the file
791  if (FillBuffer(a_eventIndex))
792  {
793  Cerr("***** vDataFile::GetEventWithoutOrderAssumption() -> An error occured while filling the buffer from datafile !" << endl);
794  return NULL;
795  }
796  // Say that the first thread is done filling the buffer
797  m_currentlyFillingBuffer = false;
798  // No more request to fill the buffer
799  m_requestBufferFilling = false;
800  }
801  // Get address of the event to recover from the array buffer
802  char* event_address_in_array = mp_arrayEvents + (a_eventIndex-m_1stIdxArrayEvents)*m_sizeEvent;
803  // And read from the buffer
804  return GetEventFromBuffer(event_address_in_array, a_th);
805  }
806  // For the other threads
807  else
808  {
809  // If out of buffer range, then read from file (we must check at first if the first thread is currently filling the buffer, otherwise
810  // the range 1st and last indices may not reflect the actual range; then we cannot use here the m_requestBufferFilling flag instead,
811  // because some compiler optimization might merge this if section with the next one, and we absolutely need the next one to be alone,
812  // and right befre the first instruction of the else section setting the mp_currentlyReadingBuffer[a_th] flag to true.
813  if (m_currentlyFillingBuffer || a_eventIndex<m_1stIdxArrayEvents || a_eventIndex>m_lastIdxArrayEvents)
814  {
815  mp_nbEventsReadFromFile[a_th]++;
816  return GetEventFromFile(a_eventIndex, a_th);
817  }
818  // Else if request filling, then read from file (this check has to be separated from the one above, otherwise if there is no buffer
819  // filling request, between the time this thread do the checks and set the currentlyReadingBuffer to true, the thread0 may have
820  // enaugh time to start the filling of the buffer, creating erroneous lines, also may be due to some compiler optimizations reversing
821  // some checks; at least, this version is stable)
822  else if (m_requestBufferFilling)
823  {
824  mp_nbEventsReadFromFile[a_th]++;
825  return GetEventFromFile(a_eventIndex, a_th);
826  }
827  // Else, we can safely read from the buffer
828  else
829  {
830  // Say that this thread is reading into the buffer
831  mp_currentlyReadingBuffer[a_th] = true;
832  // Compute the adress into the buffer
833  char* event_address_in_array = mp_arrayEvents + (a_eventIndex-m_1stIdxArrayEvents)*m_sizeEvent;
834  // Get the event
835  vEvent* p_event = GetEventFromBuffer(event_address_in_array, a_th);
836  // Say that the thread has done reading into the buffer
837  mp_currentlyReadingBuffer[a_th] = false;
838  // Return the event
839  return p_event;
840  }
841  }
842 }
843 
844 // =====================================================================
845 // ---------------------------------------------------------------------
846 // ---------------------------------------------------------------------
847 // =====================================================================
848 
849 vEvent* vDataFile::GetEventFromFile(int64_t a_eventIndex, int a_th)
850 {
851  #ifdef CASTOR_VERBOSE
852  if (m_verbose >=4) Cout("vDataFile::GetEventFromFile() ..." << endl);
853  #endif
854 
855  // Seek to the position and read the event
856  m2p_dataFile[a_th]->seekg((int64_t)m_sizeEvent*a_eventIndex);
858  // Check the reading
859  if (!(*m2p_dataFile[a_th]))
860  {
861  Cerr("***** vDataFile::GetEventFromFile() -> Failed to read one event in datafile !" << endl);
862  return NULL;
863  }
864  // Pass the pointer to the event to the interpretor function (implemented by children)
865  return GetEventFromBuffer(m2p_bufferEventFromFile[a_th], a_th);
866 }
867 
868 // =====================================================================
869 // ---------------------------------------------------------------------
870 // ---------------------------------------------------------------------
871 // =====================================================================
872 
873 void vDataFile::GetEventIndexStartAndStop( int64_t* ap_indexStart, int64_t* ap_indexStop, int a_subsetNum, int a_nbSubsets )
874 {
875  #ifdef CASTOR_VERBOSE
876  if (m_verbose >=4) Cout("vDataFile::GetEventIndexStartAndStop() ..." << endl);
877  #endif
878  // Basically here, the index start for a single MPI instance will be the current subset number.
879  // If multiple instances are used, the whole datafile is split into equal-size concatenated pieces.
880  // So for each instance, we just have to found the first index falling in its range (assuming that
881  // the event index step is always equal to the number of subsets).
882 
883  // For the first machine, index start is the current subset number
884  if (mp_ID->GetMPIRank()==0) *ap_indexStart = a_subsetNum;
885  // For the other machines, we must search for the first index falling in their range belonging to this
886  // subset (a subset being starting at a_subsetNum with a step equal to the number of subsets, a_nbSubsets)
887  else
888  {
889  // Compute the modulo of the first index of this machine minus the subset number with respect to the number of subsets
890  int64_t modulo = (m_mpi1stEvent-a_subsetNum) % a_nbSubsets;
891  // If this modulo is null, then the index start is the first index
892  if (modulo==0) *ap_indexStart = m_mpi1stEvent;
893  // Otherwise, the index start is equal to the first index plus the number of subsets minus the modulo
894  else *ap_indexStart = m_mpi1stEvent + (a_nbSubsets - modulo);
895  }
896 
897  // For index stop, we simply get the last event of the MPI instance (+1 because the for loop is exclusive)
898  *ap_indexStop = m_mpiLastEvent + 1;
899 }
900 
901 // =====================================================================
902 // ---------------------------------------------------------------------
903 // ---------------------------------------------------------------------
904 // =====================================================================
905 
907 {
908  Cerr("*****vDataFile::GetMaxRingDiff() ->This function is not implemented for the used system" << endl);
909  Cerr(" (this error may be prompted if the present function is erroneously called for a SPECT system)" << endl);
910  return -1;
911 }
912 
913 /************************************************
914 * PROJECTION SCRIPT FUNCTIONS
915 ************************************************/
916 
917 // =====================================================================
918 // ---------------------------------------------------------------------
919 // ---------------------------------------------------------------------
920 // =====================================================================
921 /*
922  \fn PROJ_WriteData()
923  \brief Write/Merge chunk of data in a general data file.
924  \todo check if some file manipulations are correctly done
925  \todo adapt to the data loading/writing in RAM
926  \return 0 if success, and positive value otherwise.
927 */
929 {
930  if (m_verbose >=2) Cout("vDataFile::PROJ_WriteData() ..." << endl);
931 
932  // Close all multithreaded datafiles before merging
933  for (int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
934  if (m2p_dataFile[th]) m2p_dataFile[th]->close();
935 
936 
937  // If the output file doesn't exist yet, simply rename the first temporary file name using the ouput file name
938  if (!ifstream(m_dataFileName))
939  {
940  // If only one projection is required (i.e one threads && no projection of frame or gates)...
941  if(mp_ID->GetNbThreadsForProjection()==1 // No multithreading so no multiple tmp datafiles
942  && mp_ID->GetNbTimeFrames()*
944  mp_ID->GetSensNbCardGates() == 1)
945  {
946  // rename the first temporary file name to the global name
947  string tmp_file_name = m_dataFileName + "_0";
948 
949  // ... then just rename the first temporary file name using the ouput file name
950  rename(tmp_file_name.c_str(),m_dataFileName.c_str());
951  // no need to concatenate, so we leave here.
952  return 0 ;
953  }
954  }
955 
956  // Create the final output file which will concatenate the events inside the thread-specific data files
957  ofstream merged_file(m_dataFileName.c_str(), ios::out | ios::binary | ios::app);
958 
959  // 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
960  for (int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
961  {
962  // Build thread file name
963  stringstream ss; ss << th;
964  string file_name = m_dataFileName;
965  file_name.append("_").append(ss.str());
966  // Open it
967  // Note SS: Maybe we can use the m2p_dataFile[th] here by just rewarding to the beginning of the file ?
968  // 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)
969  // But we should have another look on how the projection data writing works with the implementation of the new analytical simulator.
970  ifstream data_file(file_name.c_str(), ios::binary | ios::in);
971 
972  if (!data_file)
973  {
974  Cerr(endl);
975  Cerr("***** vDataFile::PROJ_ConcatenateMthDatafile() -> Input temporary thread file '" << file_name << "' is missing or corrupted !" << endl);
976  return 1;
977  }
978 
979  // Concatenate it to the merged file
980  merged_file << data_file.rdbuf();
981  // Close file
982  data_file.close();
983 
984  // 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)
985  m2p_dataFile[th]->open( file_name.c_str(), ios::binary | ios::out | ios::trunc);
986  }
987 
988  // Close merged file
989  merged_file.close();
990 
991  return 0;
992 }
993 
994 
995 
996 
997 
998 
999 // =====================================================================
1000 // ---------------------------------------------------------------------
1001 // ---------------------------------------------------------------------
1002 // =====================================================================
1003 /*
1004  \fn PROJ_DeleteTmpDatafile()
1005  \brief Delete temporary datafile used for multithreaded output writing if needed
1006  \return 0 if success, and positive value otherwise.
1007 */
1009 {
1010  if (m_verbose >=3) Cout("vDataFile::PROJ_DeleteTmpDatafile() ..." << endl);
1011 
1012  // Generate input file ("data_file") to read the buffer of the thread-specific data files and store the information in the final output file
1013  for (int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
1014  {
1015  // Build thread file name
1016  stringstream ss; ss << th;
1017 
1018  if (m2p_dataFile[th]) m2p_dataFile[th]->close();
1019 
1020  string file_name = m_dataFileName;
1021  file_name.append("_").append(ss.str());
1022 
1023  // Remove temporary file for data output writing (Projection script only)
1024  ifstream fcheck(file_name.c_str());
1025  if(fcheck.good())
1026  {
1027  fcheck.close();
1028  #ifdef _WIN32
1029  string dos_instruction = "del " + file_name;
1030  system(dos_instruction.c_str());
1031  #else
1032  remove(file_name.c_str());
1033  #endif
1034  }
1035  }
1036 
1037  return 0;
1038 }
1039 
1040 
1041 
1042 
1043 // =====================================================================
1044 // ---------------------------------------------------------------------
1045 // ---------------------------------------------------------------------
1046 // =====================================================================
1047 /*
1048  \fn PROJ_GenerateEvent(int idx_elt1, int idx_elt2, int a_th)
1049  \param idx_elt1 : first ID of the event
1050  \param idx_elt2 : second ID of the event
1051  \param a_th : index of the thread from which the function was called
1052  \brief Generate a standard event and set up its ID
1053  Used by the projection, list-mode sensitivity generation, and datafile converter scripts
1054  \return the thread specific m2p_BufferEvent array containing the event
1055 */
1056 vEvent* vDataFile::PROJ_GenerateEvent(int a_idxElt1, int a_idxElt2, int a_th)
1057 {
1058  #ifdef CASTOR_VERBOSE
1059  if (m_verbose >=4) Cout("vDataFile::PROJ_GenerateEvent() ..." << endl);
1060  #endif
1061 
1062  // Only 1 line required for projection/sensitivity generation
1063  m2p_BufferEvent[a_th]->SetNbLines(1);
1064  m2p_BufferEvent[a_th]->SetID1(0, a_idxElt1);
1065  m2p_BufferEvent[a_th]->SetID2(0, a_idxElt2);
1066 
1067  return m2p_BufferEvent[a_th];
1068 }
int64_t GetEventSize()
Definition: vDataFile.hh:298
This class is designed to be a mother virtual class for Datafile.
Definition: vDataFile.hh:67
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)
Compute the index start and stop of the events loop with respect to the current subset and MPI size a...
Definition: vDataFile.cc:873
#define MODE_HISTOGRAM
Definition: vDataFile.hh:36
#define TYPE_PET
Definition: vDataFile.hh:51
void SetNbLines(uint16_t a_value)
Set the number of lines of the Event.
Definition: vEvent.hh:134
int64_t m_sizeEvent
Definition: vDataFile.hh:528
bool mp_POIDirectionFlag[3]
Definition: vDataFile.hh:534
string m_dataFileName
Definition: vDataFile.hh:520
#define TYPE_UNKNOWN
Definition: vDataFile.hh:49
#define MODE_LIST
Definition: vDataFile.hh:34
vEvent * GetEventWithoutOrderAssumption(int64_t a_eventIndex, int a_th)
According to the current part of the datafile loaded in memory, either read from this buffer or direc...
Definition: vDataFile.cc:734
#define MODE_NORMALIZATION
Definition: vDataFile.hh:38
int CheckParameters()
Check the initialization of member variables Call the CheckSpecificParameters() function implemente...
Definition: vDataFile.cc:269
virtual vEvent * GetEventFromBuffer(char *ap_buffer, int a_th)=0
This function is implemented in child classes Read an event from the position pointed by 'ap_buffer...
FLTNB GetCalibrationFactor()
Definition: vDataFile.hh:327
bool GetPOIInfoFlag()
Definition: vDataFile.hh:339
bool * mp_overBufferRange
Definition: vDataFile.hh:551
int64_t m_1stIdxArrayEvents
Definition: vDataFile.hh:544
virtual int CheckFileSizeConsistency()=0
int ReadInfoInHeader(bool a_affectQuantificationFlag=true)
Read and check general information from the header datafile Call the ReadSpecificInformationInHeade...
Definition: vDataFile.cc:134
int SetCalibrationFactor(int a_bed, FLTNB a_calibrationFactor)
Set the calibration factor for the provided bed.
FLTNB m_durationInSec
Definition: vDataFile.hh:525
#define TYPE_TRANSMISSION
Definition: vDataFile.hh:55
int64_t GetSize()
Definition: vDataFile.hh:292
string m_headerFileName
Definition: vDataFile.hh:519
char * mp_arrayEvents
Definition: vDataFile.hh:539
int m_dataMode
Definition: vDataFile.hh:522
#define TYPE_SPECT
Definition: vDataFile.hh:53
bool m_requestBufferFilling
Definition: vDataFile.hh:548
virtual ~vDataFile()
vDataFile destructor.
Definition: vDataFile.cc:79
virtual int GetMaxRingDiff()
Return an error by default. This function is surcharged by the PET (and CT) scanner daughter class...
Definition: vDataFile.cc:906
FLTNB m_startTimeInSec
Definition: vDataFile.hh:524
int64_t m_mpi1stEvent
Definition: vDataFile.hh:541
int PROJ_WriteData()
Write/Merge chunk of data in a general data file.
Definition: vDataFile.cc:928
int64_t m_mpiLastEvent
Definition: vDataFile.hh:542
#define Cerr(MESSAGE)
bool m_ignorePOIFlag
Definition: vDataFile.hh:533
int64_t m_sizeArrayEvents
Definition: vDataFile.hh:546
virtual int CheckSpecificParameters()=0
This function is implemented in child classes Check specific parameters of child classes...
vDataFile()
vDataFile constructor.
Definition: vDataFile.cc:26
Declaration of class vDataFile.
int ReadDataASCIIFile(const string &a_file, const string &a_keyword, T *ap_return, int a_nbElts, bool a_mandatoryFlag)
Look for "a_nbElts" elts in the "a_file" file matching the "a_keyword" string passed as parameter a...
Definition: gOptions.cc:111
void ResetBufferRange()
Simply set the m_1stIdxArrayEvents and m_lastIdxArrayEvents to -1 only if the percentage load is stri...
Definition: vDataFile.cc:491
int GetMPISize()
Get the MPI size (the number of MPI instances)
int m_dataType
Definition: vDataFile.hh:523
oImageDimensionsAndQuantification * mp_ID
Definition: vDataFile.hh:514
int GetSensNbRespGates()
call the eponym function from the oDynamicDataManager object
int CheckConsistencyWithAnotherBedDatafile(vDataFile *ap_Datafile)
Check consistency between 'this' and the provided datafile as two bed positions.
Definition: vDataFile.cc:339
virtual int ReadSpecificInfoInHeader(bool a_affectQuantificationFlag=true)=0
This function is implemented in child classes Read and check modality-specific information from the...
fstream ** m2p_dataFile
Definition: vDataFile.hh:518
FLTNB * GetPOIResolution()
Definition: vDataFile.hh:333
int m_percentageLoad
Definition: vDataFile.hh:547
int GetDataType()
Definition: vDataFile.hh:286
int64_t * mp_nbEventsReadFromFile
Definition: vDataFile.hh:552
string GetScannerName()
Definition: vDataFile.hh:469
vEvent * PROJ_GenerateEvent(int idx_elt1, int idx_elt2, int a_th)
Generate a standard event and set up its ID Used by the projection, list-mode sensitivity generatio...
Definition: vDataFile.cc:1056
int m_bedIndex
Definition: vDataFile.hh:527
int PROJ_DeleteTmpDatafile()
Delete temporary datafile used for multithreaded output writing if needed.
Definition: vDataFile.cc:1008
vEvent * GetEventWithAscendingOrderAssumption(int64_t a_eventIndex, int64_t a_eventIndexLimit, int a_th)
According to the current part of the datafile loaded in memory, either read from this buffer or direc...
Definition: vDataFile.cc:609
#define KEYWORD_MANDATORY
Definition: gOptions.hh:25
vEvent * GetEventFromFile(int64_t a_eventIndex, int a_th)
Return the a_eventIndex event from the datafile.
Definition: vDataFile.cc:849
bool m_currentlyFillingBuffer
Definition: vDataFile.hh:549
#define KEYWORD_OPTIONAL
Definition: gOptions.hh:27
virtual int CheckSpecificConsistencyWithAnotherDatafile(vDataFile *ap_Datafile)=0
Check consistency between 'this' and the provided datafile, for specific characteristics.
int FillBuffer(int64_t a_eventIndex)
Fill 'mp_arrayEvents' from the 'a_eventIndex' position in the data file. The filling process stops ...
Definition: vDataFile.cc:513
FLTNB mp_POIResolution[3]
Definition: vDataFile.hh:535
void SetID2(int a_line, uint32_t a_value)
Set the indice associated with the line index for the 2nd ID of the Event.
Definition: vEvent.hh:150
#define OS_SEP
bool * mp_currentlyReadingBuffer
Definition: vDataFile.hh:550
Mother class for the Event objects.
Definition: vEvent.hh:23
int GetDataMode()
Definition: vDataFile.hh:280
int GetNbTimeFrames()
Get the number of time frames.
vEvent ** m2p_BufferEvent
Definition: vDataFile.hh:538
bool m_POIInfoFlag
Definition: vDataFile.hh:532
int SetAcquisitionTime(int a_bed, FLTNB a_timeStartInSec, FLTNB a_durationInSec)
Set the acquisition time if not already set by the SetTimeFrames()
int GetNbThreadsForProjection()
Get the number of threads used for projections.
int64_t m_mpiNbEvents
Definition: vDataFile.hh:543
int InitializeFile()
Instantiate the fstream objets for input reading and check if the related datafile's existence and co...
Definition: vDataFile.cc:412
#define MODE_UNKNOWN
Definition: vDataFile.hh:32
char ** m2p_bufferEventFromFile
Definition: vDataFile.hh:540
#define Cout(MESSAGE)
string m_scannerName
Definition: vDataFile.hh:529
FLTNB m_calibrationFactor
Definition: vDataFile.hh:526
int64_t m_lastIdxArrayEvents
Definition: vDataFile.hh:545
virtual int Shuffle(int64_t)
Definition: vDataFile.cc:568
int m_verbose
Definition: vDataFile.hh:515
int GetMPIRank()
Get the MPI instance number (the rank)
int64_t m_totalNbEvents
Definition: vDataFile.hh:521
void SetID1(int a_line, uint32_t a_value)
Set the indice associated with the line index for the 1st ID of the Event.
Definition: vEvent.hh:142