CASToR  3.2
Tomographic Reconstruction (PET/SPECT/CT)
src/datafile/iDataFilePET.cc
Go to the documentation of this file.
1 
9 #include "iDataFilePET.hh"
10 
11 // =====================================================================
12 // ---------------------------------------------------------------------
13 // ---------------------------------------------------------------------
14 // =====================================================================
15 
17 {
18  // Set all members to default values
22  m_maxAxialDiffmm = -1.;
23  m_isotope = "unknown";
24  m_TOFResolutionInPs = -1.;
25  m_nbTOFBins = -1;
26  m_TOFBinSizeInPs = -1.;
28  m_eventKindFlag = false;
29  m_atnCorrectionFlag = false;
31  m_normCorrectionFlag = false;
33  m_scatCorrectionFlag = false;
35  m_randCorrectionFlag = false;
37  m_TOFInfoFlag = false;
38  m_ignoreTOFFlag = false;
41 }
42 
43 // =====================================================================
44 // ---------------------------------------------------------------------
45 // ---------------------------------------------------------------------
46 // =====================================================================
47 
49 
50 // =====================================================================
51 // ---------------------------------------------------------------------
52 // ---------------------------------------------------------------------
53 // =====================================================================
54 
55 int iDataFilePET::ReadSpecificInfoInHeader(bool a_affectQuantificationFlag)
56 {
57  // Verbose
59  if (m_verbose>=VERBOSE_DETAIL) Cout("iDataFilePET::ReadSpecificInfoInHeader() -> Read information specific to PET" << endl);
60  // Read optional fields in the header, check if errors (issue during data reading/conversion (==1) )
61  if (ReadDataASCIIFile(m_headerFileName, "Maximum number of lines per event", &m_maxNumberOfLinesPerEvent, 1, KEYWORD_OPTIONAL)==1 ||
62  ReadDataASCIIFile(m_headerFileName, "Maximum axial difference mm", &m_maxAxialDiffmm, 1, KEYWORD_OPTIONAL)==1 ||
64  ReadDataASCIIFile(m_headerFileName, "TOF information flag", &m_TOFInfoFlag, 1, KEYWORD_OPTIONAL)==1 ||
65  ReadDataASCIIFile(m_headerFileName, "List TOF measurement range (ps)", &m_TOFMeasurementRangeInPs, 1, KEYWORD_OPTIONAL)==1 ||
66  ReadDataASCIIFile(m_headerFileName, "List TOF quantization bin size (ps)", &m_TOFQuantizationBinSizeInPs, 1, KEYWORD_OPTIONAL)==1 ||
67  ReadDataASCIIFile(m_headerFileName, "Histo TOF number of bins", &m_nbTOFBins, 1, KEYWORD_OPTIONAL)==1 ||
68  ReadDataASCIIFile(m_headerFileName, "Histo TOF bin size (ps)", &m_TOFBinSizeInPs, 1, KEYWORD_OPTIONAL)==1 ||
69  ReadDataASCIIFile(m_headerFileName, "Coincidence kind flag", &m_eventKindFlag, 1, KEYWORD_OPTIONAL)==1 ||
70  ReadDataASCIIFile(m_headerFileName, "Attenuation correction flag", &m_atnCorrectionFlag, 1, KEYWORD_OPTIONAL)==1 ||
71  ReadDataASCIIFile(m_headerFileName, "Normalization correction flag", &m_normCorrectionFlag, 1, KEYWORD_OPTIONAL)==1 ||
72  ReadDataASCIIFile(m_headerFileName, "Scatter correction flag", &m_scatCorrectionFlag, 1, KEYWORD_OPTIONAL)==1 ||
73  ReadDataASCIIFile(m_headerFileName, "Random correction flag", &m_randCorrectionFlag, 1, KEYWORD_OPTIONAL)==1 ||
75  ReadDataASCIIFile(m_headerFileName, "Per event TOF resolution flag", &m_perEventTOFResolutionFlag, 1, KEYWORD_OPTIONAL) == 1 )
76  {
77  Cerr("***** iDataFilePET::ReadSpecificInfoInHeader() -> Error while reading optional fields in the header data file !" << endl);
78  return 1;
79  }
80  // Give the PET isotope to the oImageDimensionsAndQuantification that manages the quantification factors
81  if (a_affectQuantificationFlag && mp_ID->SetPETIsotope(m_bedIndex, m_isotope))
82  {
83  Cerr("***** iDataFilePET::ReadSpecificInfoInHeader() -> A problem occurred while setting the isotope to oImageDimensionsAndQuantification !" << endl);
84  return 1;
85  }
86  // End
87  return 0;
88 }
89 
90 // =====================================================================
91 // ---------------------------------------------------------------------
92 // ---------------------------------------------------------------------
93 // =====================================================================
94 
96 {
97  iDataFilePET* p_DataFilePET = (dynamic_cast<iDataFilePET*>(ap_DataFile));
99  m_maxAxialDiffmm = p_DataFilePET->GetMaxAxialDiffmm();
100  m_isotope = p_DataFilePET->GetIsotope();
101  m_TOFResolutionInPs = p_DataFilePET->GetTOFResolutionInPs();
102  m_nbTOFBins = p_DataFilePET->GetNbTOFBins();
103  m_TOFBinSizeInPs = p_DataFilePET->GetTOFBinSizeInPs();
105  m_TOFInfoFlag = p_DataFilePET->GetTOFInfoFlag();
106  m_eventKindFlag = p_DataFilePET->GetEventKindFlag();
107  m_atnCorrectionFlag = p_DataFilePET->GetAtnCorrectionFlag();
108  m_normCorrectionFlag = p_DataFilePET->GetNormCorrectionFlag();
109  m_scatCorrectionFlag = p_DataFilePET->GetScatCorrectionFlag();
110  m_randCorrectionFlag = p_DataFilePET->GetRandCorrectionFlag();
113  // End
114  return 0;
115 }
116 
117 // =====================================================================
118 // ---------------------------------------------------------------------
119 // ---------------------------------------------------------------------
120 // =====================================================================
121 
123 {
124  // Verbose
126  if (m_verbose>=VERBOSE_DETAIL) Cout("iDataFilePET::ComputeSizeEvent() -> In bytes" << endl);
127 
128  // For MODE_LIST events
129  if (m_dataMode == MODE_LIST)
130  {
131  // Size of the mandatory element in a list-mode event: Time + max_nb_lines*2*crystalID
132  m_sizeEvent = sizeof(uint32_t) + m_maxNumberOfLinesPerEvent*2*sizeof(uint32_t);
133  // Number of lines
134  if (m_maxNumberOfLinesPerEvent>1) m_sizeEvent += sizeof(uint16_t);
135  // Optional flags
136  if (m_eventKindFlag) m_sizeEvent += sizeof(uint8_t);
137  if (m_atnCorrectionFlag) m_sizeEvent += sizeof(FLTNBDATA);
141  if (m_TOFInfoFlag) m_sizeEvent += sizeof(FLTNBDATA);
142  // POI availability in each direction
143  for (int i=0 ; i<3; i++) if (mp_POIDirectionFlag[i]) m_sizeEvent += 2*sizeof(FLTNBDATA);
145  }
146  // For MODE_HISTOGRAM events
147  else if (m_dataMode == MODE_HISTOGRAM)
148  {
149  // Size of the mandatory element in a histo event: Time + nbBinsTOF*event_value + max_nb_line*2*crystalID
150  m_sizeEvent = sizeof(uint32_t) + m_nbTOFBins*sizeof(FLTNBDATA) + m_maxNumberOfLinesPerEvent*2*sizeof(uint32_t);
151  // Number of lines
152  if (m_maxNumberOfLinesPerEvent>1) m_sizeEvent += sizeof(uint16_t);
153  // Optional flags
154  if (m_atnCorrectionFlag) m_sizeEvent += sizeof(FLTNBDATA);
158  }
159  // For MODE_NORMALIZATION events
160  else if (m_dataMode == MODE_NORMALIZATION)
161  {
162  // max_nb_lines*2*crystalID
163  m_sizeEvent = m_maxNumberOfLinesPerEvent*2*sizeof(uint32_t);
164  // Number of lines
165  if (m_maxNumberOfLinesPerEvent>1) m_sizeEvent += sizeof(uint16_t);
166  // Optional flag for normalization
168  // Optional flag for attenuation
169  if (m_atnCorrectionFlag) m_sizeEvent += sizeof(FLTNBDATA);
170  }
171  // Unknown event type
172  else
173  {
174  Cerr("***** iDataFilePET::ComputeSizeEvent() -> Unknown event mode !" << endl);
175  return 1;
176  }
177 
178  // Add optional custom data
181 
182  // Check
183  if (m_sizeEvent<=0)
184  {
185  Cerr("***** iDataFilePET::ComputeSizeEvent() -> Error, the Event size in bytes should be >= 0 !" << endl;);
186  return 1;
187  }
188 
189  // Verbose
190  if (m_verbose>=VERBOSE_DETAIL) Cout(" --> Event size = " << m_sizeEvent << " bytes" << endl);
191  // End
192  return 0;
193 }
194 
195 // =====================================================================
196 // ---------------------------------------------------------------------
197 // ---------------------------------------------------------------------
198 // =====================================================================
199 
201 {
202  // Verbose
205  {
206  if (m_dataMode==MODE_HISTOGRAM) Cout("iDataFilePET::PrepareDataFile() -> Build histogram events" << endl);
207  else if (m_dataMode==MODE_LIST) Cout("iDataFilePET::PrepareDataFile() -> Build listmode events" << endl);
208  else if (m_dataMode==MODE_NORMALIZATION) Cout("iDataFilePET::PrepareDataFile() -> Build normalization events" << endl);
209  }
210 
211  // ==============================================================================
212  // Allocate event buffers (one for each thread)
213  // ==============================================================================
214  if (m_verbose>=VERBOSE_DETAIL) Cout(" --> Allocating an event buffer for each thread" << endl);
215  // Instanciation of the event buffer according to the data type
217 
218  // Allocate the events per each thread
219  for (int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
220  {
221 
222  // For MODE_LIST events
223  if (m_dataMode == MODE_LIST)
224  {
225  m2p_BufferEvent[th] = new iEventListPET();
226  // If TOF, convert and transmit information about the total range of TOF measurements ( conversion from delta time into delta length )
228  {
229  ((iEventListPET*)m2p_BufferEvent[th])->SetHasTOFInfo(true);
230  ((iEventListPET*)m2p_BufferEvent[th])->SetTOFMeasurementRangeInPs(m_TOFMeasurementRangeInPs);
231  }
232  }
233  // For MODE_HISTOGRAM events
234  else if (m_dataMode == MODE_HISTOGRAM)
235  {
236  m2p_BufferEvent[th] = new iEventHistoPET();
237  // If we ignore the TOF information, then the event buffer will have only one TOF bin;
238  // the TOF contributions will be sum up when reading the event.
239  if (m_ignoreTOFFlag) ((iEventHistoPET*)m2p_BufferEvent[th])->SetEventNbTOFBins(1);
240  else ((iEventHistoPET*)m2p_BufferEvent[th])->SetEventNbTOFBins(m_nbTOFBins);
241  }
242  // For MODE_NORMALIZATION events
243  else if (m_dataMode == MODE_NORMALIZATION)
244  {
245  m2p_BufferEvent[th] = new iEventNorm();
246  }
247 
248  // Set the maximum number of lines per event
250 
251  // Allocate crystal IDs
252  if (m2p_BufferEvent[th]->AllocateID())
253  {
254  Cerr("*****iDataFilePET::PrepareDataFile() -> Error while trying to allocate memory for the Event object for thread " << th << " !" << endl;);
255  return 1;
256  }
257 
258  // Allocate memory for optional custom fields
261 
262  if (m2p_BufferEvent[th]->GetNbCustomINTData()>0)
263  {
264  if(m2p_BufferEvent[th]->AllocateCustomINTData() >0)
265  {
266  Cerr("*****iDataFilePET::PrepareDataFile() -> Error while trying to allocate memory for the custom Event INT fields for thread " << th << " !" << endl;);
267  return 1;
268  }
269  }
270  if (m2p_BufferEvent[th]->GetNbCustomFLTData()>0)
271  {
272  if(m2p_BufferEvent[th]->AllocateCustomFLTData() >0)
273  {
274  Cerr("*****iDataFilePET::PrepareDataFile() -> Error while trying to allocate memory for the custom Event FLT fields for thread " << th << " !" << endl;);
275  return 1;
276  }
277  }
278  }
279 
280  // ==============================================================================
281  // Deal with specific corrections
282  // ==============================================================================
283 
284  // In case of attenuation correction flag, see if we ignore this correction
286  {
287  // Affect the ignored flag from the ignored corrections list processed by the oImageDimensionsAndQuantification
289  // Verbose
291  {
292  if (m_ignoreAttnCorrectionFlag) Cout(" --> Ignore attenuation correction" << endl);
293  else Cout(" --> Correct for attenuation" << endl);
294  }
295  }
296  // In case of normalization correction flag, see if we ignore this correction
298  {
299  // Affect the ignored flag from the ignored corrections list processed by the oImageDimensionsAndQuantification
301  // Verbose
303  {
304  if (m_ignoreNormCorrectionFlag) Cout(" --> Ignore normalization correction" << endl);
305  else Cout(" --> Correct for normalization" << endl);
306  }
307  }
308  // In case of scatter correction flag, see if we ignore this correction
310  {
311  // Affect the ignored flag from the ignored corrections list processed by the oImageDimensionsAndQuantification
313  // Verbose
315  {
316  if (m_ignoreScatCorrectionFlag) Cout(" --> Ignore scatter correction" << endl);
317  else Cout(" --> Correct for scatter events" << endl);
318  }
319  }
320  // In case of random correction flag, see if we ignore this correction
322  {
323  // Affect the ignored flag from the ignored corrections list processed by the oImageDimensionsAndQuantification
325  // Verbose
327  {
328  if (m_ignoreRandCorrectionFlag) Cout(" --> Ignore random correction" << endl);
329  else Cout(" --> Correct for random events" << endl);
330  }
331  }
332 
333  // ==============================================================================
334  // Deal with TOF
335  // ==============================================================================
336 
337  // TOF information availability and use
338  if (m_TOFInfoFlag)
339  {
340  // Special case when TOF is ignored but we are in list-mode, we have scatter correction factors and we do not ignore them.
341  // In this case, the scatter correction will be completely wrong, so we make the code crash here
343  {
344  Cerr("***** iDataFilePET::PrepareDataFile() -> Scatter correction for list-mode TOF data will be erroneous if TOF information is ignored in the projections !" << endl);
345  return 1;
346  }
347  // Verbose
349  {
350  if (m_ignoreTOFFlag) Cout(" --> TOF information available but ignored " << endl);
351  else Cout(" --> Use TOF information" << endl);
352  }
353  }
354 
355  // Normal end
356  return 0;
357 }
358 
359 // =====================================================================
360 // ---------------------------------------------------------------------
361 // ---------------------------------------------------------------------
362 // =====================================================================
363 
364 vEvent* iDataFilePET::GetEventSpecific(char* ap_buffer, int a_th)
365 {
367 
368  // Work on a copy of the input pointer
369  char* file_position = ap_buffer;
370 
371  // For MODE_LIST PET data
372  if (m_dataMode == MODE_LIST)
373  {
374  // Cast the event pointer
375  iEventListPET* event = (dynamic_cast<iEventListPET*>(m2p_BufferEvent[a_th]));
376  // Mandatory time field: [uint32_t (time)]
377  event->SetTimeInMs(*reinterpret_cast<uint32_t*>(file_position));
378  file_position += sizeof(uint32_t);
379  // Optional attenuation correction field: [FLTNBDATA (attnCorrectionFactor)]
381  {
382  if (!m_ignoreAttnCorrectionFlag) event->SetAttenuationCorrectionFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
383  file_position += sizeof(FLTNBDATA);
384  }
385  // Optional kind: [uint8_t kind]
386  if (m_eventKindFlag)
387  {
388  event->SetKind(*reinterpret_cast<uint8_t*>(file_position));
389  file_position += sizeof(uint8_t);
390  }
391  // Optional scatter correction field: [FLTNBDATA (scatter)]
393  {
394  if (!m_ignoreScatCorrectionFlag) event->SetScatterRate(0, *reinterpret_cast<FLTNBDATA*>(file_position));
395  file_position += sizeof(FLTNBDATA);
396  }
397  // Optional random correction field: [FLTNBDATA (random)]
399  {
400  if (!m_ignoreRandCorrectionFlag) event->SetRandomRate(*reinterpret_cast<FLTNBDATA*>(file_position));
401  file_position += sizeof(FLTNBDATA);
402  }
403  // Optional normalization correction field: [FLTNBDATA (norm)]
405  {
406  if (!m_ignoreNormCorrectionFlag) event->SetNormalizationFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
407  file_position += sizeof(FLTNBDATA);
408  }
409  // Optional TOF information field: [FLTNBDATA (TOF)]
410  if (m_TOFInfoFlag)
411  {
412  if (!m_ignoreTOFFlag) event->SetTOFMeasurementInPs(*reinterpret_cast<FLTNBDATA*>(file_position));
413  file_position += sizeof(FLTNBDATA);
414  }
415 
416  // Optional TOF information field: [FLTNBDATA (TOF)]
418  {
419  if (!m_ignoreTOFFlag) event->SetTOFEventResolutionInPs(*reinterpret_cast<FLTNBDATA*>(file_position));
420  file_position += sizeof(FLTNBDATA);
421  }
422 
423  // Optional POI correction fields: [FLTNBDATA (POI1[3])] [FLTNBDATA (POI2[3])]
424  for (int i=0; i<3; i++)
425  {
426  if (mp_POIDirectionFlag[i])
427  {
428  if (!m_ignorePOIFlag) event->SetPOI1(i,*reinterpret_cast<FLTNBDATA*>(file_position));
429  file_position += sizeof(FLTNBDATA);
430  if (!m_ignorePOIFlag) event->SetPOI2(i,*reinterpret_cast<FLTNBDATA*>(file_position));
431  file_position += sizeof(FLTNBDATA);
432  }
433  }
434  // Mandatory nb contributing LORs if m_maxNumberOfLinesPerEvent>1: [uint16_t nbLines]
436  {
437  event->SetNbLines(*reinterpret_cast<uint16_t*>(file_position));
438  file_position += sizeof(uint16_t);
439  }
440  // Mandatory crystal IDs: [uint32_t (ID1)] [uint32_t (ID2)]
441  for (int i=0 ; i<event->GetNbLines() ; i++)
442  {
443  event->SetID1(i, *reinterpret_cast<uint32_t*>(file_position));
444  file_position += sizeof(uint32_t);
445  event->SetID2(i, *reinterpret_cast<uint32_t*>(file_position));
446  file_position += sizeof(uint32_t);
447  }
448 
449  // Custom fields
450  if(m_nbCustomFLTData>0)
451  {
452  for(int i=0 ; i<m_nbCustomFLTData ; i++)
453  {
454  event->SetCustomFLTData(i, *reinterpret_cast<EVTFLTDATA*>(file_position));
455  file_position += sizeof(EVTFLTDATA);
456  }
457  }
458 
459  if(m_nbCustomINTData>0)
460  {
461  for(int i=0 ; i<m_nbCustomINTData ; i++)
462  {
463  event->SetCustomINTData(i, *reinterpret_cast<EVTINTDATA*>(file_position));
464  file_position += sizeof(EVTINTDATA);
465  }
466  }
467  }
468 
469  // For MODE_HISTOGRAM PET data
470  else if (m_dataMode == MODE_HISTOGRAM)
471  {
472  // Cast the event pointer
473  iEventHistoPET* event = (dynamic_cast<iEventHistoPET*>(m2p_BufferEvent[a_th]));
474  // Mandatory time field: [uint32_t (time)]
475  event->SetTimeInMs(*reinterpret_cast<uint32_t*>(file_position));
476  file_position += sizeof(uint32_t);
477  // Optional attenuation correction field: [FLTNBDATA (attnCorrectionFactor)]
479  {
480  if (!m_ignoreAttnCorrectionFlag) event->SetAttenuationCorrectionFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
481  file_position += sizeof(FLTNBDATA);
482  }
483 
484  // Optional random correction field: [FLTNBDATA (random)]
486  {
487  if (!m_ignoreRandCorrectionFlag) event->SetRandomRate(*reinterpret_cast<FLTNBDATA*>(file_position));
488  file_position += sizeof(FLTNBDATA);
489  }
490 
491  // Optional normalization correction field: [FLTNBDATA (norm)]
493  {
494  if (!m_ignoreNormCorrectionFlag) event->SetNormalizationFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
495  file_position += sizeof(FLTNBDATA);
496  }
497  // If we ignore the TOF information, then we have to sum up the bins' contributions
498  if (m_ignoreTOFFlag)
499  {
500  // Compute the total of event values and scatter rates
501  FLTNBDATA total_event_value = 0.;
502  FLTNBDATA total_scatter_rate = 0.;
503  for (int tb=0 ; tb<m_nbTOFBins ; tb++)
504  {
505  // Mandatory bin value: [FLTNBDATA bin value]
506  total_event_value += *reinterpret_cast<FLTNBDATA*>(file_position);
507  file_position += sizeof(FLTNBDATA);
508  // Optional scatter correction field: [FLTNBDATA (scatter)]
510  {
511  total_scatter_rate += *reinterpret_cast<FLTNBDATA*>(file_position);
512  file_position += sizeof(FLTNBDATA);
513  }
514  }
515  // Affect the total to the event
516  event->SetEventValue(0,total_event_value);
517  if (!m_ignoreScatCorrectionFlag) event->SetScatterRate(0,total_scatter_rate);
518  }
519  // Otherwise we set all different TOF bin contributions
520  else
521  {
522  for (int tb=0 ; tb<m_nbTOFBins ; tb++)
523  {
524  // Mandatory bin value: [FLTNBDATA bin value]
525  event->SetEventValue(tb, *reinterpret_cast<FLTNBDATA*>(file_position));
526  file_position += sizeof(FLTNBDATA);
527  // Optional scatter correction field: [FLTNBDATA (scatter)]
529  {
530  if (!m_ignoreScatCorrectionFlag) event->SetScatterRate(tb, *reinterpret_cast<FLTNBDATA*>(file_position));
531  file_position += sizeof(FLTNBDATA);
532  }
533  }
534  }
535  // Mandatory nb contributing LORs if m_maxNumberOfLinesPerEvent>1: [uint16_t nbLines]
537  {
538  event->SetNbLines(*reinterpret_cast<uint16_t*>(file_position));
539  file_position += sizeof(uint16_t);
540  }
541  // Mandatory crystal IDs: [uint32_t (c1)] [uint32_t (c2)]
542  for (int i=0 ; i<event->GetNbLines() ; i++)
543  {
544  event->SetID1(i, *reinterpret_cast<uint32_t*>(file_position));
545  file_position += sizeof(uint32_t);
546  event->SetID2(i, *reinterpret_cast<uint32_t*>(file_position));
547  file_position += sizeof(uint32_t);
548  }
549 
550  // Custom fields
551  if(m_nbCustomFLTData>0)
552  {
553  for(int i=0 ; i<m_nbCustomFLTData ; i++)
554  {
555  event->SetCustomFLTData(i, *reinterpret_cast<EVTFLTDATA*>(file_position));
556  file_position += sizeof(EVTFLTDATA);
557  }
558  }
559 
560  if(m_nbCustomINTData>0)
561  {
562  for(int i=0 ; i<m_nbCustomINTData ; i++)
563  {
564  event->SetCustomINTData(i, *reinterpret_cast<EVTINTDATA*>(file_position));
565  file_position += sizeof(EVTINTDATA);
566  }
567  }
568  }
569 
570  // For MODE_NORMALIZATION PET data
571  else if (m_dataMode == MODE_NORMALIZATION)
572  {
573  // Cast the event pointer
574  iEventNorm* event = (dynamic_cast<iEventNorm*>(m2p_BufferEvent[a_th]));
575  // Optional attenuation correction field: [FLTNBDATA (norm)]
577  {
578  if (!m_ignoreAttnCorrectionFlag) event->SetAttenuationCorrectionFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
579  file_position += sizeof(FLTNBDATA);
580  }
581  // Optional normalization correction field: [FLTNBDATA (norm)]
583  {
584  if (!m_ignoreNormCorrectionFlag) event->SetNormalizationFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
585  file_position += sizeof(FLTNBDATA);
586  }
587  // Mandatory nb contributing LORs if m_maxNumberOfLinesPerEvent>1: [uint16_t nbLines]
589  {
590  event->SetNbLines(*reinterpret_cast<uint16_t*>(file_position));
591  file_position += sizeof(uint16_t);
592  }
593  // Mandatory crystal IDs: [uint32_t (c1)] [uint32_t (c2)]
594  for (int i=0 ; i<event->GetNbLines() ; i++)
595  {
596  event->SetID1(i, *reinterpret_cast<uint32_t*>(file_position));
597  file_position += sizeof(uint32_t);
598  event->SetID2(i, *reinterpret_cast<uint32_t*>(file_position));
599  file_position += sizeof(uint32_t);
600  }
601  // Custom fields
602  if(m_nbCustomFLTData>0)
603  {
604  for(int i=0 ; i<m_nbCustomFLTData ; i++)
605  {
606  event->SetCustomFLTData(i, *reinterpret_cast<EVTFLTDATA*>(file_position));
607  file_position += sizeof(EVTFLTDATA);
608  }
609  }
610 
611  if(m_nbCustomINTData>0)
612  {
613  for(int i=0 ; i<m_nbCustomINTData ; i++)
614  {
615  event->SetCustomINTData(i, *reinterpret_cast<EVTINTDATA*>(file_position));
616  file_position += sizeof(EVTINTDATA);
617  }
618  }
619  }
620 
621  // Return the updated event
622  return m2p_BufferEvent[a_th];
623 }
624 
625 // =====================================================================
626 // ---------------------------------------------------------------------
627 // ---------------------------------------------------------------------
628 // =====================================================================
629 
631 {
633  if (m_verbose==0) return;
634  // Describe the datafile
635  Cout("iDataFilePET::DescribeSpecific() -> Here is some specific content of the PET datafile" << endl);
636  Cout(" --> Isotope: " << m_isotope << endl);
637  if (m_TOFInfoFlag)
638  {
639  Cout(" --> TOF resolution: " << m_TOFResolutionInPs << " ps" << endl);
640  if (m_dataMode==MODE_LIST)
641  {
642  Cout(" --> TOF measurement range (for list-mode data): " << m_TOFMeasurementRangeInPs << " ps" << endl);
644  Cout(" --> TOF quantization bin size (for list-mode data): " << m_TOFQuantizationBinSizeInPs << " ps" << endl);
645  else
646  Cout(" --> TOF quantization bin size (for list-mode data) not set " << endl);
647 
649  Cout(" --> Using per event TOF resolution data");
650  }
651  else if (m_dataMode==MODE_HISTOGRAM)
652  {
653  Cout(" --> Number of TOF bins: " << m_nbTOFBins << endl);
654  Cout(" --> TOF bin size: " << m_TOFBinSizeInPs << " ps" << endl);
655  }
656  }
657  if (m_dataMode==MODE_LIST && m_eventKindFlag) Cout(" --> Event kind is present" << endl);
658  if (m_scatCorrectionFlag) Cout(" --> Scatter correction is present" << endl);
659  if (m_randCorrectionFlag) Cout(" --> Random correction is present" << endl);
660  if (m_atnCorrectionFlag) Cout(" --> Attenuation correction is present" << endl);
661  if (m_normCorrectionFlag) Cout(" --> Normalization correction is present" << endl);
662  if (m_maxNumberOfLinesPerEvent>1) Cout(" --> Maximum number of lines per event: " << m_maxNumberOfLinesPerEvent << endl);
663  if (m_perEventTOFResolutionFlag) Cout(" --> Per event TOF resolution is present" << endl);
664 }
665 
666 // =====================================================================
667 // ---------------------------------------------------------------------
668 // ---------------------------------------------------------------------
669 // =====================================================================
670 
672 {
674  // Error if m_dataType != PET
675  if (m_dataType != TYPE_PET)
676  {
677  Cerr("***** iDataFilePET::CheckSpecificParameters() -> Data type should be PET !'" << endl);
678  return 1;
679  }
680  // Check if Maximum ring difference has been initialized, use default value (negative) otherwise.
681  if (m_maxAxialDiffmm < 0.)
682  {
683  m_maxAxialDiffmm = -1.;
684  }
685  // Some checks for POI use
686  if (m_POIInfoFlag)
687  {
688  // Not compatible with histogram data
690  {
691  Cerr("***** iDataFilePET::CheckSpecificParameters() -> POI correction flag is enabled while the data are histogrammed, no sense !" << endl);
692  return 1;
693  }
694  // For each direction (radial, tangential and axial), look at the resolution. If not negative, the info should be the datafile
695  for (int i=0; i<3; i++) if (mp_POIResolution[i]>=0.) mp_POIDirectionFlag[i] = true;
696  }
697  // Some checks for TOF use
698  if (m_TOFInfoFlag)
699  {
700  // Check if the resolution was provided
702  {
703  Cerr("***** iDataFilePET::CheckSpecificParameters() -> TOF information is used while there is no TOF resolution specified in the datafile header !" << endl);
704  return 1;
705  }
706  // For histogram data
708  {
709  // Check if the number of bins has been provided
710  if (m_nbTOFBins<=1)
711  {
712  Cerr("***** iDataFilePET::CheckSpecificParameters() -> TOF information is used while there is only one TOF bin (specified in the datafile header) !" << endl);
713  return 1;
714  }
715  // Check if the bin size has been provided
716  if (m_TOFBinSizeInPs<=0.)
717  {
718  Cerr("***** iDataFilePET::CheckSpecificParameters() -> TOF information is used while there is no bin size specified in the datafile header !" << endl);
719  return 1;
720  }
722  {
723  Cerr("***** iDataFilePET::CheckSpecificParameters() -> Per event TOF resolution data only works in list mode !" << endl);
724  return 1;
725  }
726  }
727  // For list mode data
728  else if (m_dataMode==MODE_LIST)
729  {
730  // Check whether the TOF measurement range has been set
732  {
733  Cerr("***** iDataFilePET::CheckSpecificParameters() -> TOF measurement range not set !" << endl);
734  return 1;
735  }
737  {
738  Cerr("***** iDataFilePET::CheckSpecificParameters() -> Both per event and global TOF resolution are set. Remove global value !" << endl);
739  return 1;
740  }
741  // set the number of TOF bins to 1
742  m_nbTOFBins = 1;
743  return 0;
744  }
745  }
746  else
747  {
748  // Set the number of TOF bins to 1
749  m_nbTOFBins = 1;
750  }
751 
752  // End
753  return 0;
754 }
755 
756 // =====================================================================
757 // ---------------------------------------------------------------------
758 // ---------------------------------------------------------------------
759 // =====================================================================
760 
762 {
764 
765  // Create the stream
766  fstream* p_file = new fstream( m_dataFileName.c_str(), ios::binary| ios::in );
767  // Check that datafile exists
768  if (!p_file->is_open())
769  {
770  Cerr("***** iDataFilePET::CheckFileSizeConsistency() -> Failed to open input file '" << m_dataFileName.c_str() << "' !" << endl);
771  Cerr(" (Provided in the data file header: " << m_headerFileName << ")" << endl);
772  return 1;
773  }
774  // Get file size in bytes
775  p_file->seekg(0, ios::end);
776  int64_t sizeInBytes = p_file->tellg();
777  // Close stream and delete it
778  p_file->close();
779  delete p_file;
780  // Check datafile self-consistency
781  if (m_nbEvents*m_sizeEvent != sizeInBytes)
782  {
783  Cerr("--------------------------------------------------------------------------------------------------------------------------------------" << endl);
784  Cerr("***** iDataFilePET::CheckFileSizeConsistency() -> DataFile size is not consistent with the information provided by the user/datafile !" << endl);
785  Cerr(" --> Expected size : "<< m_nbEvents*m_sizeEvent << endl);
786  Cerr(" --> Actual size : "<< sizeInBytes << endl << endl);
787  Cerr(" ADDITIONAL INFORMATION ABOUT THE DATAFILE INITIALIZATION : " << endl);
788  if (m_maxNumberOfLinesPerEvent > 1) Cerr(" --> Compression enabled. Each event should contain " << m_maxNumberOfLinesPerEvent <<
789  "LORs, or an equivalent number of LOR + garbage LORs" << endl);
790  else Cerr(" --> No compression in the data" << endl);
791  if (m_eventKindFlag) Cerr(" --> Coincidence kind term is enabled" << endl);
792  else Cerr(" --> No information about the kind of coincidences in the data" << endl);
793  if (m_normCorrectionFlag) Cerr(" --> Normalization correction term is enabled" << endl);
794  else Cerr(" --> No normalization correction term in the data" << endl);
795  if (m_atnCorrectionFlag) Cerr(" --> Attenuation correction term is enabled" << endl);
796  else Cerr(" --> No attenuation correction term in the data" << endl);
797  if (m_scatCorrectionFlag) Cerr(" --> Scatter correction term is enabled" << endl);
798  else Cerr(" --> No scatter correction term in the data" << endl);
799  if (m_randCorrectionFlag) Cerr(" --> Random correction term is enabled" << endl);
800  else Cerr(" --> No random correction term in the data" << endl);
801  if (m_TOFInfoFlag) Cerr(" --> TOF information is enabled. Resolution is: " << m_TOFResolutionInPs << " ps"<< endl);
802  else Cerr(" --> No TOF information in the data" << endl);
803  Cerr(" --> Calibration factor value is: " << m_calibrationFactor << endl);
804  if (mp_POIResolution[0]<0.) Cerr(" --> No POI enabled on the radial axis" << endl);
805  else Cerr(" --> POI resolution on the radial axis is: " << mp_POIResolution[0] << endl);
806  if (mp_POIResolution[1]<0.) Cerr(" --> No POI enabled on the tangential axis" << endl);
807  else Cerr(" --> POI resolution on the tangential axis is: " << mp_POIResolution[1] << endl);
808  if (mp_POIResolution[2]<0.) Cerr(" --> No POI enabled on the axial axis" << endl);
809  else Cerr(" --> POI resolution on the axial axis is: " << mp_POIResolution[2] << endl);
810  if (m_perEventTOFResolutionFlag) Cerr(" --> Per event TOF standard deviation is enabled" << endl);
811  else Cerr(" --> No per event TOF standard deviation in the data" << endl);
812  Cerr("--------------------------------------------------------------------------------------------------------------------------------------" << endl);
813  return 1;
814  }
815  // End
816  return 0;
817 }
818 
819 // =====================================================================
820 // ---------------------------------------------------------------------
821 // ---------------------------------------------------------------------
822 // =====================================================================
823 
825 {
827  // Dynamic cast the vDataFile to a iDataFilePET
828  iDataFilePET* p_data_file = (dynamic_cast<iDataFilePET*>(ap_DataFile));
829  // Check maximum number of lines per event
831  {
832  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Maximum numbers of lines by event are inconsistent !" << endl);
833  return 1;
834  }
835  // Check maximum ring difference
836  if (m_maxAxialDiffmm!=p_data_file->GetMaxAxialDiffmm())
837  {
838  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Maximum ring differences are inconsistent !" << endl);
839  return 1;
840  }
841  // Check isotope
842  if (m_isotope!=p_data_file->GetIsotope())
843  {
844  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Isotopes are inconsistent !" << endl);
845  return 1;
846  }
847  // Check event kind flag
848  if (m_eventKindFlag!=p_data_file->GetEventKindFlag())
849  {
850  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Event kind flags are inconsistent !" << endl);
851  return 1;
852  }
853  // Check attenuation correction flag
854  if (m_atnCorrectionFlag!=p_data_file->GetAtnCorrectionFlag())
855  {
856  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Attenuation correction flags are inconsistent !" << endl);
857  return 1;
858  }
859  // Check normalization correction flag
860  if (m_normCorrectionFlag!=p_data_file->GetNormCorrectionFlag())
861  {
862  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Normalization correction flags are inconsistent !" << endl);
863  return 1;
864  }
865  // Check scatter correction flag
866  if (m_scatCorrectionFlag!=p_data_file->GetScatCorrectionFlag())
867  {
868  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Scatter correction flags are inconsistent !" << endl);
869  return 1;
870  }
871  // Check random correction flag
872  if (m_randCorrectionFlag!=p_data_file->GetRandCorrectionFlag())
873  {
874  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Random correction flags are inconsistent !" << endl);
875  return 1;
876  }
877  // Check TOF info flag
878  if (m_TOFInfoFlag!=p_data_file->GetTOFInfoFlag())
879  {
880  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> TOF information flags are inconsistent !" << endl);
881  return 1;
882  }
883  // Check TOF resolution
884  if (m_TOFResolutionInPs!=p_data_file->GetTOFResolutionInPs())
885  {
886  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> TOF resolutions are inconsistent !" << endl);
887  return 1;
888  }
889  // Check number of TOF bins
890  if (m_nbTOFBins!=p_data_file->GetNbTOFBins())
891  {
892  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Numbers of TOF bins are inconsistent !" << endl);
893  return 1;
894  }
895  // Check TOF bin size
896  if (m_TOFBinSizeInPs!=p_data_file->GetTOFBinSizeInPs())
897  {
898  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> TOF bin sizes are inconsistent !" << endl);
899  return 1;
900  }
901  // Check TOF measurement range
903  {
904  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> TOF measurement ranges are inconsistent !" << endl);
905  return 1;
906  }
907  // Check TOF quantization bin size
909  {
910  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> TOF quantization bin sizes are inconsistent !" << endl);
911  return 1;
912  }
913  // Check per event TOF resolution
915  {
916  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Per event TOF resolution flags are inconsistent (list-mode or histogram) !" << endl);
917  return 1;
918  }
919  // Check data mode
920  if (m_dataMode!=p_data_file->GetDataMode())
921  {
922  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Data modes are inconsistent (list-mode or histogram) !" << endl);
923  return 1;
924  }
925 
926  // End
927  return 0;
928 }
929 
930 // =====================================================================
931 // ---------------------------------------------------------------------
932 // ---------------------------------------------------------------------
933 // =====================================================================
934 
936 {
938  if (m_verbose>=VERBOSE_DETAIL) Cout("iDataFilePET::PROJ_InitFile() -> Initialize datafile for writing"<< endl);
939 
940  m_nbEvents = 0; //Std initialization for projection
941  m_nbTOFBins = 1; // Initialization of this variable required for PROJ_Write functions
942 
943  // Default time initialization if image dimensions object has not been initialized
944  if(mp_ID->IsInitialized())
945  {
947 
948  for(uint16_t fr=0 ; fr<mp_ID->GetNbTimeFrames() ; fr++)
950 
951  // Instanciate a fstream datafile for each thread
952  m2p_dataFile = new fstream*[mp_ID->GetNbThreadsForProjection()];
953  }
954  else
955  {
956  m_startTimeInSec = 0.;
957  m_durationInSec = 1.;
958  m2p_dataFile = new fstream*[1];
959  }
960 
961 
962 
963  // Set name of the projection data header
964  sOutputManager* p_OutMgr;
965  p_OutMgr = sOutputManager::GetInstance();
966  string path_name = p_OutMgr->GetPathName();
967  string img_name = p_OutMgr->GetBaseName();
968  m_headerFileName = path_name.append(img_name).append("_df").append(".Cdh");
969 
970  for (int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
971  {
972  m_dataFileName = m_headerFileName.substr(0, m_headerFileName.find_last_of(".")).append(".Cdf"); // Generate datafile name from header file
973 
974  // We'll write projeted data in several files (corresponding to the number of thread) to be concatenated at the end of the projection process.
975  stringstream ss;
976  ss << th;
977  string datafile_name = m_dataFileName;
978  datafile_name.append("_").append(ss.str());
979 
980  m2p_dataFile[th] = new fstream( datafile_name.c_str(), ios::binary | ios::out | ios::trunc);
981  }
982 
983 
984  // Check there is no existing datafile with such name. Remove it otherwise
985  ifstream fcheck(m_dataFileName.c_str());
986  if(fcheck.good())
987  {
988  fcheck.close();
989  #ifdef _WIN32
990  string dos_instruction = "del " + m_dataFileName;
991  system(dos_instruction.c_str());
992  #else
993  remove(m_dataFileName.c_str());
994  #endif
995  }
996 
997  if (m_verbose>=VERBOSE_DETAIL) Cout(" --> Output datafile name :" << m_dataFileName << endl);
998 
999  return 0;
1000 }
1001 
1002 // =====================================================================
1003 // ---------------------------------------------------------------------
1004 // ---------------------------------------------------------------------
1005 // =====================================================================
1006 
1007 int iDataFilePET::WriteEvent(vEvent* ap_Event, int a_th)
1008 {
1010 
1011  if (m_dataMode == MODE_LIST)
1012  {
1013  if (WriteListEvent((iEventListPET*)ap_Event, a_th))
1014  {
1015  Cerr("*****iDataFilePET::WriteEvent() -> Error while trying to write projection datafile (list-mode)" << endl;);
1016  return 1;
1017  }
1018  }
1019 
1020  if (m_dataMode == MODE_HISTOGRAM)
1021  {
1022  if (WriteHistoEvent((iEventHistoPET*)ap_Event, a_th))
1023  {
1024  Cerr("*****iDataFilePET::WriteEvent() -> Error while trying to write projection datafile (histogram)" << endl;);
1025  return 1;
1026  }
1027  }
1028 
1030  {
1031  if (WriteNormEvent((iEventNorm*)ap_Event, a_th))
1032  {
1033  Cerr("*****iDataFilePET::WriteEvent() -> Error while trying to write projection datafile (histogram)" << endl;);
1034  return 1;
1035  }
1036  }
1037 
1038  return 0;
1039 }
1040 
1041 // =====================================================================
1042 // ---------------------------------------------------------------------
1043 // ---------------------------------------------------------------------
1044 // =====================================================================
1045 
1046 int iDataFilePET::WriteHistoEvent(iEventHistoPET* ap_Event, int a_th)
1047 {
1049 
1050  // Write sequentially each field of the event according to the type of the event.
1051  m2p_dataFile[a_th]->clear();
1052 
1053  uint32_t time = ap_Event->GetTimeInMs();
1054  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&time), sizeof(uint32_t));
1055 
1057  {
1058  FLTNBDATA atn_corr_factor = ap_Event->GetAtnCorrFactor();
1059  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&atn_corr_factor), sizeof(FLTNBDATA));
1060  }
1061 
1063  {
1064  FLTNBDATA rdm_rate = ap_Event->GetEventRdmRate();
1065  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&rdm_rate), sizeof(FLTNBDATA));
1066  }
1067 
1069  {
1070  FLTNBDATA norm_corr_factor = ap_Event->GetNormFactor();
1071  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&norm_corr_factor), sizeof(FLTNBDATA));
1072  }
1073 
1074  for(int b=0 ; b<m_nbTOFBins ; b++)
1075  {
1076  FLTNBDATA event_value = ap_Event->GetEventValue(b);
1077  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&event_value), sizeof(FLTNBDATA));
1079  {
1080  FLTNBDATA scat_rate = ap_Event->GetEventScatRate(b);
1081  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&scat_rate), sizeof(FLTNBDATA));
1082  }
1083  }
1084 
1085  uint16_t nb_lines = ap_Event->GetNbLines();
1086  // Write the number of lines only if the m_maxNumberOfLinesPerEvent is above 1
1087  if (m_maxNumberOfLinesPerEvent>1) m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&nb_lines), sizeof(uint16_t));
1088 
1089  for(int i=0 ; i<nb_lines ; i++)
1090  {
1091  uint32_t id1 = ap_Event->GetID1(i);
1092  uint32_t id2 = ap_Event->GetID2(i);
1093  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id1), sizeof(uint32_t));
1094  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id2), sizeof(uint32_t));
1095  }
1096 
1097  // Custom fields
1098  if(m_nbCustomINTData>0)
1099  {
1100  for(int i=0 ; i<m_nbCustomINTData ; i++)
1101  {
1102  EVTINTDATA cst_data = ap_Event->GetCustomINTData( i );
1103  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&cst_data), sizeof(EVTINTDATA));
1104  }
1105  }
1106 
1107  if(m_nbCustomFLTData>0)
1108  {
1109  for(int i=0 ; i<m_nbCustomFLTData ; i++)
1110  {
1111  EVTFLTDATA cst_data = ap_Event->GetCustomFLTData( i );
1112  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&cst_data), sizeof(EVTINTDATA));
1113  }
1114  }
1115 
1116  // 0-filling if needed (nb lines inferior to the max number for PET data with compression)
1117  if(nb_lines<m_maxNumberOfLinesPerEvent)
1118  for(int i=0 ; i<m_maxNumberOfLinesPerEvent-nb_lines ; i++)
1119  {
1120  uint32_t gbg = 0;
1121  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&gbg), sizeof(uint32_t));
1122  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&gbg), sizeof(uint32_t));
1123  }
1124 
1125  return 0;
1126 }
1127 
1128 // =====================================================================
1129 // ---------------------------------------------------------------------
1130 // ---------------------------------------------------------------------
1131 // =====================================================================
1132 
1133 int iDataFilePET::WriteListEvent(iEventListPET* ap_Event, int a_th)
1134 {
1136 
1137  // Write sequentially each field of the event according to the type of the event.
1138  m2p_dataFile[a_th]->clear();
1139 
1140  uint32_t time = ap_Event->GetTimeInMs();
1141  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&time), sizeof(uint32_t));
1142 
1143 
1145  {
1146  FLTNBDATA atn_corr_factor = ap_Event->GetAtnCorrFactor();
1147  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&atn_corr_factor), sizeof(FLTNBDATA));
1148  }
1149 
1150  if(m_eventKindFlag)
1151  {
1152  uint8_t event_kind = ap_Event->GetKind();
1153  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&event_kind), sizeof(uint8_t));
1154  }
1155 
1157  {
1158  FLTNBDATA scat_rate = ap_Event->GetEventScatRate(0);
1159  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&scat_rate), sizeof(FLTNBDATA));
1160  }
1161 
1163  {
1164  FLTNBDATA rdm_rate = ap_Event->GetEventRdmRate();
1165  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&rdm_rate), sizeof(FLTNBDATA));
1166  }
1167 
1169  {
1170  FLTNBDATA norm_corr_factor = ap_Event->GetNormFactor();
1171  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&norm_corr_factor), sizeof(FLTNBDATA));
1172  }
1173 
1174  if(m_TOFInfoFlag)
1175  {
1176  FLTNBDATA TOF_measurement = ap_Event->GetTOFMeasurementInPs();
1177  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&TOF_measurement), sizeof(FLTNBDATA));
1178  }
1179 
1181  {
1182  FLTNBDATA TOFResolution = ap_Event->GetTOFEventResolutionInPs();
1183  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&TOFResolution), sizeof(FLTNBDATA));
1184  }
1185 
1186  if(mp_POIResolution[0]>0)
1187  {
1188  FLTNBDATA POI_1 = ap_Event->GetPOI1(0);
1189  FLTNBDATA POI_2 = ap_Event->GetPOI2(0);
1190  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI_1), sizeof(FLTNBDATA));
1191  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI_2), sizeof(FLTNBDATA));
1192  }
1193  if(mp_POIResolution[1]>0)
1194  {
1195  FLTNBDATA POI_1 = ap_Event->GetPOI1(1);
1196  FLTNBDATA POI_2 = ap_Event->GetPOI2(1);
1197  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI_1), sizeof(FLTNBDATA));
1198  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI_2), sizeof(FLTNBDATA));
1199  }
1200  if(mp_POIResolution[2]>0)
1201  {
1202  FLTNBDATA POI_1 = ap_Event->GetPOI1(2);
1203  FLTNBDATA POI_2 = ap_Event->GetPOI2(2);
1204  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI_1), sizeof(FLTNBDATA));
1205  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI_2), sizeof(FLTNBDATA));
1206  }
1207 
1208  uint16_t nb_lines = ap_Event->GetNbLines();
1209  // Write the number of lines only if the m_maxNumberOfLinesPerEvent is above 1
1210  if (m_maxNumberOfLinesPerEvent>1) m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&nb_lines), sizeof(uint16_t));
1211 
1212  for(int i=0 ; i<nb_lines ; i++)
1213  {
1214  uint32_t id1 = ap_Event->GetID1(i);
1215  uint32_t id2 = ap_Event->GetID2(i);
1216  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id1), sizeof(uint32_t));
1217  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id2), sizeof(uint32_t));
1218  }
1219 
1220  // Custom fields
1221  if(m_nbCustomINTData>0)
1222  {
1223  for(int i=0 ; i<m_nbCustomINTData ; i++)
1224  {
1225  EVTINTDATA cst_data = ap_Event->GetCustomINTData( i );
1226  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&cst_data), sizeof(EVTINTDATA));
1227  }
1228  }
1229 
1230  if(m_nbCustomFLTData>0)
1231  {
1232  for(int i=0 ; i<m_nbCustomFLTData ; i++)
1233  {
1234  EVTFLTDATA cst_data = ap_Event->GetCustomFLTData( i );
1235  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&cst_data), sizeof(EVTINTDATA));
1236  }
1237  }
1238 
1239  // 0-filling if needed (nb lines inferior to the max number for PET data with compression)
1240  if(nb_lines<m_maxNumberOfLinesPerEvent)
1241  for(int i=0 ; i<m_maxNumberOfLinesPerEvent-nb_lines ; i++)
1242  {
1243  uint32_t gbg = 0;
1244  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&gbg), sizeof(uint32_t));
1245  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&gbg), sizeof(uint32_t));
1246  }
1247 
1248 
1249 
1250  return 0;
1251 }
1252 
1253 
1254 
1255 
1256 // =====================================================================
1257 // ---------------------------------------------------------------------
1258 // ---------------------------------------------------------------------
1259 // =====================================================================
1260 
1261 int iDataFilePET::WriteNormEvent(iEventNorm* ap_Event, int a_th)
1262 {
1264 
1265  // Write sequentially each field of the event according to the type of the event.
1266  m2p_dataFile[a_th]->clear();
1267 
1269  {
1270  FLTNBDATA atn_corr_factor = ap_Event->GetAttenuationCorrectionFactor();
1271  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&atn_corr_factor), sizeof(FLTNBDATA));
1272  }
1273 
1275  {
1276  FLTNBDATA norm_corr_factor = ap_Event->GetNormalizationFactor();
1277  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&norm_corr_factor), sizeof(FLTNBDATA));
1278  }
1279 
1280  uint16_t nb_lines = ap_Event->GetNbLines();
1281  // Write the number of lines only if the m_maxNumberOfLinesPerEvent is above 1
1282  if (m_maxNumberOfLinesPerEvent>1) m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&nb_lines), sizeof(uint16_t));
1283 
1284  for(int i=0 ; i<nb_lines ; i++)
1285  {
1286  uint32_t id1 = ap_Event->GetID1(i);
1287  uint32_t id2 = ap_Event->GetID2(i);
1288  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id1), sizeof(uint32_t));
1289  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id2), sizeof(uint32_t));
1290  }
1291 
1292  // Custom fields
1293  if(m_nbCustomINTData>0)
1294  {
1295  for(int i=0 ; i<m_nbCustomINTData ; i++)
1296  {
1297  EVTINTDATA cst_data = ap_Event->GetCustomINTData( i );
1298  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&cst_data), sizeof(EVTINTDATA));
1299  }
1300  }
1301 
1302  if(m_nbCustomFLTData>0)
1303  {
1304  for(int i=0 ; i<m_nbCustomFLTData ; i++)
1305  {
1306  EVTFLTDATA cst_data = ap_Event->GetCustomFLTData( i );
1307  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&cst_data), sizeof(EVTINTDATA));
1308  }
1309  }
1310 
1311  // 0-filling if needed (nb lines inferior to the max number for PET data with compression)
1312  if(nb_lines<m_maxNumberOfLinesPerEvent)
1313  for(int i=0 ; i<m_maxNumberOfLinesPerEvent-nb_lines ; i++)
1314  {
1315  uint32_t gbg = 0;
1316  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&gbg), sizeof(uint32_t));
1317  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&gbg), sizeof(uint32_t));
1318  }
1319 
1320  return 0;
1321 }
1322 
1323 
1324 
1325 
1326 // =====================================================================
1327 // ---------------------------------------------------------------------
1328 // ---------------------------------------------------------------------
1329 // =====================================================================
1330 
1332 {
1333  // Verbose
1335  if (m_verbose>=VERBOSE_NORMAL) Cout("iDataFilePET::WriteHeader() -> Write header file '" << m_headerFileName << "'" << endl);
1336  // Open file
1337  fstream headerFile;
1338  headerFile.open(m_headerFileName.c_str(), ios::out);
1339 
1340  if (!headerFile.is_open())
1341  {
1342  Cerr("***** iDataFilePET::WriteHeader() -> Failed to open output header file '" << m_headerFileName << "' !" << endl);
1343  return 1;
1344  }
1345 
1346  // Data file name
1347  headerFile << "Data filename: " << GetFileFromPath(m_dataFileName) << endl;
1348  // Number of events
1349  headerFile << "Number of events: " << m_nbEvents << endl;
1350  // Data mode
1351  if (m_dataMode==MODE_HISTOGRAM) headerFile << "Data mode: histogram" << endl;
1352  else if (m_dataMode==MODE_LIST) headerFile << "Data mode: list-mode" << endl;
1353  else if (m_dataMode==MODE_NORMALIZATION) headerFile << "Data mode: normalization" << endl;
1354  // PET data type
1355  headerFile << "Data type: PET" << endl;
1356  // Acquisition start time in seconds
1357  headerFile << "Start time (s): " << m_startTimeInSec << endl;
1358  // Acquisition duration in seconds
1359  headerFile << "Duration (s): " << m_durationInSec << endl;
1360  // Scanner name
1361  headerFile << "Scanner name: " << sScannerManager::GetInstance()->GetScannerName() << endl;
1362  // Maximum axial difference
1363  if(m_maxAxialDiffmm > 0.)
1364  headerFile << "Maximum axial difference mm: " << m_maxAxialDiffmm << endl;
1365  // Maximum number of lines per event (write it only if higher than 1
1366  if (m_maxNumberOfLinesPerEvent >1) headerFile << "Maximum number of lines per event: " << m_maxNumberOfLinesPerEvent << endl;
1367 
1368  // Calibration factor
1369  headerFile << "Calibration factor: " << m_calibrationFactor << endl;
1370  // Isotope
1371  headerFile << "Isotope: " << m_isotope << endl;
1372  // TOF info
1373  if (m_TOFInfoFlag)
1374  {
1375  // Flag
1376  headerFile << "TOF information flag: 1" << endl;
1377  // TOF resolution
1379  {
1380  headerFile << "Per event TOF resolution flag: 1" << endl;
1381  }
1382  else
1383  {
1384  headerFile << "TOF resolution (ps): " << m_TOFResolutionInPs << endl;
1385  }
1386  // List-mode TOF measurement range
1387  if (m_dataMode == MODE_LIST)
1388  {
1389  headerFile << "List TOF measurement range (ps): " << m_TOFMeasurementRangeInPs << endl;
1390  if (m_TOFQuantizationBinSizeInPs>0.) headerFile << "List TOF quantization bin size (ps): " << m_TOFQuantizationBinSizeInPs << endl;
1391  }
1392  // Histogram
1393  else if (m_dataMode == MODE_HISTOGRAM)
1394  {
1395  // Number of TOF bins
1396  headerFile << "Histo TOF number of bins: " << m_nbTOFBins << endl;
1397  // TOF bin size
1398  headerFile << "Histo TOF bin size (ps): " << m_TOFBinSizeInPs << endl;
1399  }
1400  }
1401  // Event kind
1402  if (m_eventKindFlag)
1403  {
1404  // Error if histogram data are used
1406  {
1407  Cerr("***** iDataFilePET::WriteHeader -> Request for writing event type in histogram mode (this field is specific to list-mode) !" << endl);
1408  return 1;
1409  }
1410  else headerFile << "Coincidence kind flag: " << m_eventKindFlag << endl;
1411  }
1412  // Correction flags
1413  if (m_atnCorrectionFlag)
1414  headerFile << "Attenuation correction flag: " << m_atnCorrectionFlag << endl;
1416  headerFile << "Normalization correction flag: " << m_normCorrectionFlag << endl;
1418  headerFile << "Scatter correction flag: " << m_scatCorrectionFlag << endl;
1420  headerFile << "Random correction flag: " << m_randCorrectionFlag << endl;
1421  // Close file
1422  headerFile.close();
1423  // End
1424  return 0;
1425 }
1426 
1427 // =====================================================================
1428 // ---------------------------------------------------------------------
1429 // ---------------------------------------------------------------------
1430 // =====================================================================
1431 
1433 {
1434  // Verbose
1436  if (m_verbose>=VERBOSE_DETAIL) Cout("PROJ_GetScannerSpecificParameters() ..."<< endl);
1437  // Get pointers to SPECT specific parameters in scanner
1438  if (sScannerManager::GetInstance()->PROJ_GetPETSpecificParameters(&m_maxAxialDiffmm) )
1439  {
1440  Cerr("***** iDataFilePET::PROJ_GetScannerSpecificParameters() -> An error occurred while trying to get PET geometric parameters from the scanner object !" << endl);
1441  return 1;
1442  }
1443  // End
1444  return 0;
1445 }
1446 
1447 // =====================================================================
1448 // ---------------------------------------------------------------------
1449 // ---------------------------------------------------------------------
1450 // =====================================================================
int WriteEvent(vEvent *ap_Event, int a_th)
virtual EVTFLTDATA * GetCustomFLTData()
uint32_t GetID2(int a_line)
This class is designed to be a mother virtual class for DataFile.
bool GetNormCorrectionFlag()
Simply return m_normCorrectionFlag.
static sScannerManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
#define MODE_HISTOGRAM
void SetNbLines(uint16_t a_value)
#define EVTINTDATA
int PROJ_GetScannerSpecificParameters()
Get PET specific parameters for projections from the scanner object, through the scannerManager.
#define MODE_NORMALIZATION
#define Cerr(MESSAGE)
void DescribeSpecific()
Implementation of the pure virtual eponym function that simply prints info about the datafile...
int WriteNormEvent(iEventNorm *ap_Event, int a_th)
int CheckSpecificConsistencyWithAnotherDataFile(vDataFile *ap_DataFile)
iDataFilePET()
iDataFilePET constructor. Initialize the member variables to their default values.
bool GetIgnoreAttnCorrectionFlag()
Get the boolean that says if the attenuation correction is ignored or not.
FLTNB GetTOFEventResolutionInPs() const
Get TOF resolution in ps.
int ReadSpecificInfoInHeader(bool a_affectQuantificationFlag)
bool IsInitialized()
Returns true if the object has been initialized.
int CheckSpecificParameters()
Check parameters specific to PET data.
static sOutputManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
vEvent * GetEventSpecific(char *ap_buffer, int a_th)
int ComputeSizeEvent()
Computation of the size of each event according to the mandatory/optional correction fields...
bool GetIgnoreNormCorrectionFlag()
Get the boolean that says if the normalization correction is ignored or not.
bool GetIgnoreRandCorrectionFlag()
Get the boolean that says if the random correction is ignored or not.
void SetAttenuationCorrectionFactor(FLTNBDATA a_value)
Cast the FLTNBDATA value passed as parameter in FLTNB, and set it to the attenuation correction facto...
Inherit from iEventPET. Class for PET list-mode events.
Inherit from iEventPET. Class for PET histogram mode events.
bool GetPerEventTOFResolutionFlag() const
Simply return m_perEventTOFResolutionFlag.
~iDataFilePET()
iDataFilePET destructor.
#define DEBUG_VERBOSE(IGNORED1, IGNORED2)
virtual void SetNbCustomFLTData(int a_value)
initialize the number of custom INT data with a_value
Singleton class that manages output writing on disk (images, sinograms, etc). It also manages loggi...
bool GetScatCorrectionFlag()
Simply return m_scatCorrectionFlag.
int SetSpecificParametersFrom(vDataFile *ap_DataFile)
bool GetEventKindFlag()
Simply return m_eventKindFlag.
int WriteHistoEvent(iEventHistoPET *ap_Event, int a_th)
int WriteHeader()
Generate a header file according to the data output information.
int PROJ_InitFile()
Initialize the fstream objets for output writing as well as some other variables specific to the Proj...
#define KEYWORD_OPTIONAL
Inherit from vEvent. Used for normalization events for sensitivity computation.
int PrepareDataFile()
Store different kind of information inside arrays (data relative to specific correction as well as ba...
#define EVTFLTDATA
void SetTimeInMs(uint32_t a_value)
virtual void SetNbCustomINTData(int a_value)
initialize the number of custom INT data with a_value
Mother class for the Event objects.
FLTNB GetTOFResolutionInPs(int a_reso)
bool GetRandCorrectionFlag()
Simply return m_randCorrectionFlag.
int GetNbThreadsForProjection()
Get the number of threads used for projections.
bool GetIgnoreScatCorrectionFlag()
Get the boolean that says if the scatter correction is ignored or not.
int CheckFileSizeConsistency()
This function is implemented in child classes Check if file size is consistent. ...
uint32_t GetID1(int a_line)
string GetFileFromPath(const string &a_pathToFile)
Simply return the file from a path string passed in parameter.
virtual EVTINTDATA * GetCustomINTData()
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...
bool GetAtnCorrectionFlag()
Simply return m_atnCorrectionFlag.
Inherit from vDataFile. Class that manages the reading of a PET input file (header + data)...
#define Cout(MESSAGE)
int WriteListEvent(iEventListPET *ap_Event, int a_th=0)
oImageDimensionsAndQuantification * mp_ID