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