CASToR  3.0
Tomographic Reconstruction (PET/SPECT/CT)
iDataFilePET.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 "iDataFilePET.hh"
32 
33 // =====================================================================
34 // ---------------------------------------------------------------------
35 // ---------------------------------------------------------------------
36 // =====================================================================
37 
39 {
40  // Set all members to default values
44  m_maxAxialDiffmm = -1.;
45  m_isotope = "unknown";
46  m_TOFResolutionInPs = -1.;
47  m_nbTOFBins = -1;
48  m_TOFBinSizeInPs = -1.;
50  m_eventKindFlag = false;
51  m_atnCorrectionFlag = false;
53  m_normCorrectionFlag = false;
55  m_scatCorrectionFlag = false;
57  m_randCorrectionFlag = false;
59  m_TOFInfoFlag = false;
60  m_ignoreTOFFlag = false;
62 }
63 
64 // =====================================================================
65 // ---------------------------------------------------------------------
66 // ---------------------------------------------------------------------
67 // =====================================================================
68 
70 
71 // =====================================================================
72 // ---------------------------------------------------------------------
73 // ---------------------------------------------------------------------
74 // =====================================================================
75 
76 int iDataFilePET::ReadSpecificInfoInHeader(bool a_affectQuantificationFlag)
77 {
78  // Verbose
80  if (m_verbose>=VERBOSE_DETAIL) Cout("iDataFilePET::ReadSpecificInfoInHeader() -> Read information specific to PET" << endl);
81  // Read optional fields in the header, check if errors (issue during data reading/conversion (==1) )
82  if (ReadDataASCIIFile(m_headerFileName, "Maximum number of lines per event", &m_maxNumberOfLinesPerEvent, 1, KEYWORD_OPTIONAL)==1 ||
83  ReadDataASCIIFile(m_headerFileName, "Maximum axial difference mm", &m_maxAxialDiffmm, 1, KEYWORD_OPTIONAL)==1 ||
85  ReadDataASCIIFile(m_headerFileName, "TOF information flag", &m_TOFInfoFlag, 1, KEYWORD_OPTIONAL)==1 ||
86  ReadDataASCIIFile(m_headerFileName, "List TOF measurement range (ps)", &m_TOFMeasurementRangeInPs, 1, KEYWORD_OPTIONAL)==1 ||
87  ReadDataASCIIFile(m_headerFileName, "List TOF quantization bin size (ps)", &m_TOFQuantizationBinSizeInPs, 1, KEYWORD_OPTIONAL)==1 ||
88  ReadDataASCIIFile(m_headerFileName, "Histo TOF number of bins", &m_nbTOFBins, 1, KEYWORD_OPTIONAL)==1 ||
89  ReadDataASCIIFile(m_headerFileName, "Histo TOF bin size (ps)", &m_TOFBinSizeInPs, 1, KEYWORD_OPTIONAL)==1 ||
90  ReadDataASCIIFile(m_headerFileName, "Coincidence kind flag", &m_eventKindFlag, 1, KEYWORD_OPTIONAL)==1 ||
91  ReadDataASCIIFile(m_headerFileName, "Attenuation correction flag", &m_atnCorrectionFlag, 1, KEYWORD_OPTIONAL)==1 ||
92  ReadDataASCIIFile(m_headerFileName, "Normalization correction flag", &m_normCorrectionFlag, 1, KEYWORD_OPTIONAL)==1 ||
93  ReadDataASCIIFile(m_headerFileName, "Scatter correction flag", &m_scatCorrectionFlag, 1, KEYWORD_OPTIONAL)==1 ||
94  ReadDataASCIIFile(m_headerFileName, "Random correction flag", &m_randCorrectionFlag, 1, KEYWORD_OPTIONAL)==1 ||
96  {
97  Cerr("***** iDataFilePET::ReadSpecificInfoInHeader() -> Error while reading optional fields in the header data file !" << endl);
98  return 1;
99  }
100  // Give the PET isotope to the oImageDimensionsAndQuantification that manages the quantification factors
101  if (a_affectQuantificationFlag && mp_ID->SetPETIsotope(m_bedIndex, m_isotope))
102  {
103  Cerr("***** iDataFilePET::ReadSpecificInfoInHeader() -> A problem occurred while setting the isotope to oImageDimensionsAndQuantification !" << endl);
104  return 1;
105  }
106  // End
107  return 0;
108 }
109 
110 // =====================================================================
111 // ---------------------------------------------------------------------
112 // ---------------------------------------------------------------------
113 // =====================================================================
114 
116 {
117  iDataFilePET* p_DataFilePET = (dynamic_cast<iDataFilePET*>(ap_DataFile));
119  m_maxAxialDiffmm = p_DataFilePET->GetMaxAxialDiffmm();
120  m_isotope = p_DataFilePET->GetIsotope();
121  m_TOFResolutionInPs = p_DataFilePET->GetTOFResolutionInPs();
122  m_nbTOFBins = p_DataFilePET->GetNbTOFBins();
123  m_TOFBinSizeInPs = p_DataFilePET->GetTOFBinSizeInPs();
125  m_TOFInfoFlag = p_DataFilePET->GetTOFInfoFlag();
126  m_eventKindFlag = p_DataFilePET->GetEventKindFlag();
127  m_atnCorrectionFlag = p_DataFilePET->GetAtnCorrectionFlag();
128  m_normCorrectionFlag = p_DataFilePET->GetNormCorrectionFlag();
129  m_scatCorrectionFlag = p_DataFilePET->GetScatCorrectionFlag();
130  m_randCorrectionFlag = p_DataFilePET->GetRandCorrectionFlag();
132  // End
133  return 0;
134 }
135 
136 // =====================================================================
137 // ---------------------------------------------------------------------
138 // ---------------------------------------------------------------------
139 // =====================================================================
140 
142 {
143  // Verbose
145  if (m_verbose>=VERBOSE_DETAIL) Cout("iDataFilePET::ComputeSizeEvent() -> In bytes" << endl);
146 
147  // For MODE_LIST events
148  if (m_dataMode == MODE_LIST)
149  {
150  // Size of the mandatory element in a list-mode event: Time + max_nb_lines*2*crystalID
151  m_sizeEvent = sizeof(uint32_t) + m_maxNumberOfLinesPerEvent*2*sizeof(uint32_t);
152  // Number of lines
153  if (m_maxNumberOfLinesPerEvent>1) m_sizeEvent += sizeof(uint16_t);
154  // Optional flags
155  if (m_eventKindFlag) m_sizeEvent += sizeof(uint8_t);
156  if (m_atnCorrectionFlag) m_sizeEvent += sizeof(FLTNBDATA);
160  if (m_TOFInfoFlag) m_sizeEvent += sizeof(FLTNBDATA);
161  // POI availability in each direction
162  for (int i=0 ; i<3; i++) if (mp_POIDirectionFlag[i]) m_sizeEvent += 2*sizeof(FLTNBDATA);
163  }
164  // For MODE_HISTOGRAM events
165  else if (m_dataMode == MODE_HISTOGRAM)
166  {
167  // Size of the mandatory element in a histo event: Time + nbBinsTOF*event_value + max_nb_line*2*crystalID
168  m_sizeEvent = sizeof(uint32_t) + m_nbTOFBins*sizeof(FLTNBDATA) + m_maxNumberOfLinesPerEvent*2*sizeof(uint32_t);
169  // Number of lines
170  if (m_maxNumberOfLinesPerEvent>1) m_sizeEvent += sizeof(uint16_t);
171  // Optional flags
172  if (m_atnCorrectionFlag) m_sizeEvent += sizeof(FLTNBDATA);
176  }
177  // For MODE_NORMALIZATION events
178  else if (m_dataMode == MODE_NORMALIZATION)
179  {
180  // max_nb_lines*2*crystalID
181  m_sizeEvent = m_maxNumberOfLinesPerEvent*2*sizeof(uint32_t);
182  // Number of lines
183  if (m_maxNumberOfLinesPerEvent>1) m_sizeEvent += sizeof(uint16_t);
184  // Optional flag for normalization
186  // Optional flag for attenuation
187  if (m_atnCorrectionFlag) m_sizeEvent += sizeof(FLTNBDATA);
188  }
189  // Unknown event type
190  else
191  {
192  Cerr("***** iDataFilePET::ComputeSizeEvent() -> Unknown event mode !" << endl);
193  return 1;
194  }
195 
196  // Check
197  if (m_sizeEvent<=0)
198  {
199  Cerr("***** iDataFilePET::ComputeSizeEvent() -> Error, the Event size in bytes should be >= 0 !" << endl;);
200  return 1;
201  }
202 
203  // Verbose
204  if (m_verbose>=VERBOSE_DETAIL) Cout(" --> Event size = " << m_sizeEvent << " bytes" << endl);
205  // End
206  return 0;
207 }
208 
209 // =====================================================================
210 // ---------------------------------------------------------------------
211 // ---------------------------------------------------------------------
212 // =====================================================================
213 
215 {
216  // Verbose
219  {
220  if (m_dataMode==MODE_HISTOGRAM) Cout("iDataFilePET::PrepareDataFile() -> Build histogram events" << endl);
221  else if (m_dataMode==MODE_LIST) Cout("iDataFilePET::PrepareDataFile() -> Build listmode events" << endl);
222  else if (m_dataMode==MODE_NORMALIZATION) Cout("iDataFilePET::PrepareDataFile() -> Build normalization events" << endl);
223  }
224 
225  // ==============================================================================
226  // Allocate event buffers (one for each thread)
227  // ==============================================================================
228  if (m_verbose>=VERBOSE_DETAIL) Cout(" --> Allocating an event buffer for each thread" << endl);
229  // Instanciation of the event buffer according to the data type
231 
232  // Allocate the events per each thread
233  for (int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
234  {
235 
236  // For MODE_LIST events
237  if (m_dataMode == MODE_LIST)
238  {
239  m2p_BufferEvent[th] = new iEventListPET();
240  // If TOF, convert and transmit information about the total range of TOF measurements ( conversion from delta time into delta length )
242  {
243  ((iEventListPET*)m2p_BufferEvent[th])->SetHasTOFInfo(true);
244  ((iEventListPET*)m2p_BufferEvent[th])->SetTOFMeasurementRangeInPs(m_TOFMeasurementRangeInPs);
245  }
246  }
247  // For MODE_HISTOGRAM events
248  else if (m_dataMode == MODE_HISTOGRAM)
249  {
250  m2p_BufferEvent[th] = new iEventHistoPET();
251  // If we ignore the TOF information, then the event buffer will have only one TOF bin;
252  // the TOF contributions will be sum up when reading the event.
253  if (m_ignoreTOFFlag) ((iEventHistoPET*)m2p_BufferEvent[th])->SetEventNbTOFBins(1);
254  else ((iEventHistoPET*)m2p_BufferEvent[th])->SetEventNbTOFBins(m_nbTOFBins);
255  }
256  // For MODE_NORMALIZATION events
257  else if (m_dataMode == MODE_NORMALIZATION)
258  {
259  m2p_BufferEvent[th] = new iEventNorm();
260  }
261 
262  // Set the maximum number of lines per event
264 
265  // Allocate crystal IDs
266  if (m2p_BufferEvent[th]->AllocateID())
267  {
268  Cerr("*****iDataFilePET::PrepareDataFile() -> Error while trying to allocate memory for the Event object for thread " << th << " !" << endl;);
269  return 1;
270  }
271  }
272 
273  // ==============================================================================
274  // Deal with specific corrections
275  // ==============================================================================
276 
277  // In case of attenuation correction flag, see if we ignore this correction
279  {
280  // Affect the ignored flag from the ignored corrections list processed by the oImageDimensionsAndQuantification
282  // Verbose
284  {
285  if (m_ignoreAttnCorrectionFlag) Cout(" --> Ignore attenuation correction" << endl);
286  else Cout(" --> Correct for attenuation" << endl);
287  }
288  }
289  // In case of normalization correction flag, see if we ignore this correction
291  {
292  // Affect the ignored flag from the ignored corrections list processed by the oImageDimensionsAndQuantification
294  // Verbose
296  {
297  if (m_ignoreNormCorrectionFlag) Cout(" --> Ignore normalization correction" << endl);
298  else Cout(" --> Correct for normalization" << endl);
299  }
300  }
301  // In case of scatter correction flag, see if we ignore this correction
303  {
304  // Affect the ignored flag from the ignored corrections list processed by the oImageDimensionsAndQuantification
306  // Verbose
308  {
309  if (m_ignoreScatCorrectionFlag) Cout(" --> Ignore scatter correction" << endl);
310  else Cout(" --> Correct for scatter events" << endl);
311  }
312  }
313  // In case of random correction flag, see if we ignore this correction
315  {
316  // Affect the ignored flag from the ignored corrections list processed by the oImageDimensionsAndQuantification
318  // Verbose
320  {
321  if (m_ignoreRandCorrectionFlag) Cout(" --> Ignore random correction" << endl);
322  else Cout(" --> Correct for random events" << endl);
323  }
324  }
325 
326  // ==============================================================================
327  // Deal with TOF
328  // ==============================================================================
329 
330  // TOF information availability and use
331  if (m_TOFInfoFlag)
332  {
333  // Special case when TOF is ignored but we are in list-mode, we have scatter correction factors and we do not ignore them.
334  // In this case, the scatter correction will be completely wrong, so we make the code crash here
336  {
337  Cerr("***** iDataFilePET::PrepareDataFile() -> Scatter correction for list-mode TOF data will be erroneous if TOF information is ignored in the projections !" << endl);
338  return 1;
339  }
340  // Verbose
342  {
343  if (m_ignoreTOFFlag) Cout(" --> TOF information available but ignored " << endl);
344  else Cout(" --> Use TOF information" << endl);
345  }
346  }
347 
348  // Normal end
349  return 0;
350 }
351 
352 // =====================================================================
353 // ---------------------------------------------------------------------
354 // ---------------------------------------------------------------------
355 // =====================================================================
356 
357 vEvent* iDataFilePET::GetEventSpecific(char* ap_buffer, int a_th)
358 {
360 
361  // Work on a copy of the input pointer
362  char* file_position = ap_buffer;
363 
364  // For MODE_LIST PET data
365  if (m_dataMode == MODE_LIST)
366  {
367  // Cast the event pointer
368  iEventListPET* event = (dynamic_cast<iEventListPET*>(m2p_BufferEvent[a_th]));
369  // Mandatory time field: [uint32_t (time)]
370  event->SetTimeInMs(*reinterpret_cast<uint32_t*>(file_position));
371  file_position += sizeof(uint32_t);
372  // Optional attenuation correction field: [FLTNBDATA (attnCorrectionFactor)]
374  {
375  if (!m_ignoreAttnCorrectionFlag) event->SetAttenuationCorrectionFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
376  file_position += sizeof(FLTNBDATA);
377  }
378  // Optional kind: [uint8_t kind]
379  if (m_eventKindFlag)
380  {
381  event->SetKind(*reinterpret_cast<uint8_t*>(file_position));
382  file_position += sizeof(uint8_t);
383  }
384  // Optional scatter correction field: [FLTNBDATA (scatter)]
386  {
387  if (!m_ignoreScatCorrectionFlag) event->SetScatterRate(0, *reinterpret_cast<FLTNBDATA*>(file_position));
388  file_position += sizeof(FLTNBDATA);
389  }
390  // Optional random correction field: [FLTNBDATA (random)]
392  {
393  if (!m_ignoreRandCorrectionFlag) event->SetRandomRate(*reinterpret_cast<FLTNBDATA*>(file_position));
394  file_position += sizeof(FLTNBDATA);
395  }
396  // Optional normalization correction field: [FLTNBDATA (norm)]
398  {
399  if (!m_ignoreNormCorrectionFlag) event->SetNormalizationFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
400  file_position += sizeof(FLTNBDATA);
401  }
402  // Optional TOF information field: [FLTNBDATA (TOF)]
403  if (m_TOFInfoFlag)
404  {
405  if (!m_ignoreTOFFlag) event->SetTOFMeasurementInPs(*reinterpret_cast<FLTNBDATA*>(file_position));
406  file_position += sizeof(FLTNBDATA);
407  }
408  // Optional POI correction fields: [FLTNBDATA (POI1[3])] [FLTNBDATA (POI2[3])]
409  for (int i=0; i<3; i++)
410  {
411  if (mp_POIDirectionFlag[i])
412  {
413  if (!m_ignorePOIFlag) event->SetPOI1(i,*reinterpret_cast<FLTNBDATA*>(file_position));
414  file_position += sizeof(FLTNBDATA);
415  if (!m_ignorePOIFlag) event->SetPOI2(i,*reinterpret_cast<FLTNBDATA*>(file_position));
416  file_position += sizeof(FLTNBDATA);
417  }
418  }
419  // Mandatory nb contributing LORs if m_maxNumberOfLinesPerEvent>1: [uint16_t nbLines]
421  {
422  event->SetNbLines(*reinterpret_cast<uint16_t*>(file_position));
423  file_position += sizeof(uint16_t);
424  }
425  // Mandatory crystal IDs: [uint32_t (ID1)] [uint32_t (ID2)]
426  for (int i=0 ; i<event->GetNbLines() ; i++)
427  {
428  event->SetID1(i, *reinterpret_cast<uint32_t*>(file_position));
429  file_position += sizeof(uint32_t);
430  event->SetID2(i, *reinterpret_cast<uint32_t*>(file_position));
431  file_position += sizeof(uint32_t);
432  }
433  }
434 
435  // For MODE_HISTOGRAM PET data
436  else if (m_dataMode == MODE_HISTOGRAM)
437  {
438  // Cast the event pointer
439  iEventHistoPET* event = (dynamic_cast<iEventHistoPET*>(m2p_BufferEvent[a_th]));
440  // Mandatory time field: [uint32_t (time)]
441  event->SetTimeInMs(*reinterpret_cast<uint32_t*>(file_position));
442  file_position += sizeof(uint32_t);
443  // Optional attenuation correction field: [FLTNBDATA (attnCorrectionFactor)]
445  {
446  if (!m_ignoreAttnCorrectionFlag) event->SetAttenuationCorrectionFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
447  file_position += sizeof(FLTNBDATA);
448  }
449 
450  // Optional random correction field: [FLTNBDATA (random)]
452  {
453  if (!m_ignoreRandCorrectionFlag) event->SetRandomRate(*reinterpret_cast<FLTNBDATA*>(file_position));
454  file_position += sizeof(FLTNBDATA);
455  }
456 
457  // Optional normalization correction field: [FLTNBDATA (norm)]
459  {
460  if (!m_ignoreNormCorrectionFlag) event->SetNormalizationFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
461  file_position += sizeof(FLTNBDATA);
462  }
463  // If we ignore the TOF information, then we have to sum up the bins' contributions
464  if (m_ignoreTOFFlag)
465  {
466  // Compute the total of event values and scatter rates
467  FLTNBDATA total_event_value = 0.;
468  FLTNBDATA total_scatter_rate = 0.;
469  for (int tb=0 ; tb<m_nbTOFBins ; tb++)
470  {
471  // Mandatory bin value: [FLTNBDATA bin value]
472  total_event_value += *reinterpret_cast<FLTNBDATA*>(file_position);
473  file_position += sizeof(FLTNBDATA);
474  // Optional scatter correction field: [FLTNBDATA (scatter)]
476  {
477  total_scatter_rate += *reinterpret_cast<FLTNBDATA*>(file_position);
478  file_position += sizeof(FLTNBDATA);
479  }
480  }
481  // Affect the total to the event
482  event->SetEventValue(0,total_event_value);
483  if (!m_ignoreScatCorrectionFlag) event->SetScatterRate(0,total_scatter_rate);
484  }
485  // Otherwise we set all different TOF bin contributions
486  else
487  {
488  for (int tb=0 ; tb<m_nbTOFBins ; tb++)
489  {
490  // Mandatory bin value: [FLTNBDATA bin value]
491  event->SetEventValue(tb, *reinterpret_cast<FLTNBDATA*>(file_position));
492  file_position += sizeof(FLTNBDATA);
493  // Optional scatter correction field: [FLTNBDATA (scatter)]
495  {
496  if (!m_ignoreScatCorrectionFlag) event->SetScatterRate(tb, *reinterpret_cast<FLTNBDATA*>(file_position));
497  file_position += sizeof(FLTNBDATA);
498  }
499  }
500  }
501  // Mandatory nb contributing LORs if m_maxNumberOfLinesPerEvent>1: [uint16_t nbLines]
503  {
504  event->SetNbLines(*reinterpret_cast<uint16_t*>(file_position));
505  file_position += sizeof(uint16_t);
506  }
507  // Mandatory crystal IDs: [uint32_t (c1)] [uint32_t (c2)]
508  for (int i=0 ; i<event->GetNbLines() ; i++)
509  {
510  event->SetID1(i, *reinterpret_cast<uint32_t*>(file_position));
511  file_position += sizeof(uint32_t);
512  event->SetID2(i, *reinterpret_cast<uint32_t*>(file_position));
513  file_position += sizeof(uint32_t);
514  }
515  }
516 
517  // For MODE_NORMALIZATION PET data
518  else if (m_dataMode == MODE_NORMALIZATION)
519  {
520  // Cast the event pointer
521  iEventNorm* event = (dynamic_cast<iEventNorm*>(m2p_BufferEvent[a_th]));
522  // Optional attenuation correction field: [FLTNBDATA (norm)]
524  {
525  if (!m_ignoreAttnCorrectionFlag) event->SetAttenuationCorrectionFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
526  file_position += sizeof(FLTNBDATA);
527  }
528  // Optional normalization correction field: [FLTNBDATA (norm)]
530  {
531  if (!m_ignoreNormCorrectionFlag) event->SetNormalizationFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
532  file_position += sizeof(FLTNBDATA);
533  }
534  // Mandatory nb contributing LORs if m_maxNumberOfLinesPerEvent>1: [uint16_t nbLines]
536  {
537  event->SetNbLines(*reinterpret_cast<uint16_t*>(file_position));
538  file_position += sizeof(uint16_t);
539  }
540  // Mandatory crystal IDs: [uint32_t (c1)] [uint32_t (c2)]
541  for (int i=0 ; i<event->GetNbLines() ; i++)
542  {
543  event->SetID1(i, *reinterpret_cast<uint32_t*>(file_position));
544  file_position += sizeof(uint32_t);
545  event->SetID2(i, *reinterpret_cast<uint32_t*>(file_position));
546  file_position += sizeof(uint32_t);
547  }
548  }
549 
550  // Return the updated event
551  return m2p_BufferEvent[a_th];
552 }
553 
554 // =====================================================================
555 // ---------------------------------------------------------------------
556 // ---------------------------------------------------------------------
557 // =====================================================================
558 
560 {
562  if (m_verbose==0) return;
563  // Describe the datafile
564  Cout("iDataFilePET::DescribeSpecific() -> Here is some specific content of the PET datafile" << endl);
565  Cout(" --> Isotope: " << m_isotope << endl);
566  if (m_TOFInfoFlag)
567  {
568  Cout(" --> TOF resolution: " << m_TOFResolutionInPs << " ps" << endl);
569  if (m_dataMode==MODE_LIST)
570  {
571  Cout(" --> TOF measurement range (for list-mode data): " << m_TOFMeasurementRangeInPs << " ps" << endl);
573  Cout(" --> TOF quantization bin size (for list-mode data): " << m_TOFQuantizationBinSizeInPs << " ps" << endl);
574  else
575  Cout(" --> TOF quantization bin size (for list-mode data) not set " << endl);
576  }
577  else if (m_dataMode==MODE_HISTOGRAM)
578  {
579  Cout(" --> Number of TOF bins: " << m_nbTOFBins << endl);
580  Cout(" --> TOF bin size: " << m_TOFBinSizeInPs << " ps" << endl);
581  }
582  }
583  if (m_dataMode==MODE_LIST && m_eventKindFlag) Cout(" --> Event kind is present" << endl);
584  if (m_scatCorrectionFlag) Cout(" --> Scatter correction is present" << endl);
585  if (m_randCorrectionFlag) Cout(" --> Random correction is present" << endl);
586  if (m_atnCorrectionFlag) Cout(" --> Attenuation correction is present" << endl);
587  if (m_normCorrectionFlag) Cout(" --> Normalization correction is present" << endl);
588  if (m_maxNumberOfLinesPerEvent>1) Cout(" --> Maximum number of lines per event: " << m_maxNumberOfLinesPerEvent << endl);
589 }
590 
591 // =====================================================================
592 // ---------------------------------------------------------------------
593 // ---------------------------------------------------------------------
594 // =====================================================================
595 
597 {
599  // Error if m_dataType != PET
600  if (m_dataType != TYPE_PET)
601  {
602  Cerr("***** iDataFilePET::CheckSpecificParameters() -> Data type should be PET !'" << endl);
603  return 1;
604  }
605  // Check if Maximum ring difference has been initialized, use default value (negative) otherwise.
606  if (m_maxAxialDiffmm < 0.)
607  {
608  m_maxAxialDiffmm = -1.;
609  }
610  // Some checks for POI use
611  if (m_POIInfoFlag)
612  {
613  // Not compatible with histogram data
615  {
616  Cerr("***** iDataFilePET::CheckSpecificParameters() -> POI correction flag is enabled while the data are histogrammed, no sense !" << endl);
617  return 1;
618  }
619  // For each direction (radial, tangential and axial), look at the resolution. If not negative, the info should be the datafile
620  for (int i=0; i<3; i++) if (mp_POIResolution[i]>=0.) mp_POIDirectionFlag[i] = true;
621  }
622  // Some checks for TOF use
623  if (m_TOFInfoFlag)
624  {
625  // Check if the resolution was provided
626  if (m_TOFResolutionInPs<0.)
627  {
628  Cerr("***** iDataFilePET::CheckSpecificParameters() -> TOF information is used while there is no TOF resolution specified in the datafile header !" << endl);
629  return 1;
630  }
631  // For histogram data
633  {
634  // Check if the number of bins has been provided
635  if (m_nbTOFBins<=1)
636  {
637  Cerr("***** iDataFilePET::CheckSpecificParameters() -> TOF information is used while there is only one TOF bin (specified in the datafile header) !" << endl);
638  return 1;
639  }
640  // Check if the bin size has been provided
641  if (m_TOFBinSizeInPs<=0.)
642  {
643  Cerr("***** iDataFilePET::CheckSpecificParameters() -> TOF information is used while there is no bin size specified in the datafile header !" << endl);
644  return 1;
645  }
646  }
647  // For list mode data
648  else if (m_dataMode==MODE_LIST)
649  {
650  // Check whether the TOF measurement range has been set
652  {
653  Cerr("***** iDataFilePET::CheckSpecificParameters() -> TOF measurement range not set !" << endl);
654  return 1;
655  }
656  // set the number of TOF bins to 1
657  m_nbTOFBins = 1;
658  return 0;
659  }
660  }
661  else
662  {
663  // Set the number of TOF bins to 1
664  m_nbTOFBins = 1;
665  }
666  // End
667  return 0;
668 }
669 
670 // =====================================================================
671 // ---------------------------------------------------------------------
672 // ---------------------------------------------------------------------
673 // =====================================================================
674 
676 {
678 
679  // Create the stream
680  fstream* p_file = new fstream( m_dataFileName.c_str(), ios::binary| ios::in );
681  // Check that datafile exists
682  if (!p_file->is_open())
683  {
684  Cerr("***** iDataFilePET::CheckFileSizeConsistency() -> Failed to open input file '" << m_dataFileName.c_str() << "' !" << endl);
685  Cerr(" (Provided in the data file header: " << m_headerFileName << ")" << endl);
686  return 1;
687  }
688  // Get file size in bytes
689  p_file->seekg(0, ios::end);
690  int64_t sizeInBytes = p_file->tellg();
691  // Close stream and delete it
692  p_file->close();
693  delete p_file;
694  // Check datafile self-consistency
695  if (m_nbEvents*m_sizeEvent != sizeInBytes)
696  {
697  Cerr("--------------------------------------------------------------------------------------------------------------------------------------" << endl);
698  Cerr("***** iDataFilePET::CheckFileSizeConsistency() -> DataFile size is not consistent with the information provided by the user/datafile !" << endl);
699  Cerr(" --> Expected size : "<< m_nbEvents*m_sizeEvent << endl);
700  Cerr(" --> Actual size : "<< sizeInBytes << endl << endl);
701  Cerr(" ADDITIONAL INFORMATION ABOUT THE DATAFILE INITIALIZATION : " << endl);
702  if (m_maxNumberOfLinesPerEvent > 1) Cerr(" --> Compression enabled. Each event should contain " << m_maxNumberOfLinesPerEvent <<
703  "LORs, or an equivalent number of LOR + garbage LORs" << endl);
704  else Cerr(" --> No compression in the data" << endl);
705  if (m_eventKindFlag) Cerr(" --> Coincidence kind term is enabled" << endl);
706  else Cerr(" --> No information about the kind of coincidences in the data" << endl);
707  if (m_normCorrectionFlag) Cerr(" --> Normalization correction term is enabled" << endl);
708  else Cerr(" --> No normalization correction term in the data" << endl);
709  if (m_atnCorrectionFlag) Cerr(" --> Attenuation correction term is enabled" << endl);
710  else Cerr(" --> No attenuation correction term in the data" << endl);
711  if (m_scatCorrectionFlag) Cerr(" --> Scatter correction term is enabled" << endl);
712  else Cerr(" --> No scatter correction term in the data" << endl);
713  if (m_randCorrectionFlag) Cerr(" --> Random correction term is enabled" << endl);
714  else Cerr(" --> No random correction term in the data" << endl);
715  if (m_TOFInfoFlag) Cerr(" --> TOF information is enabled. Resolution is: " << m_TOFResolutionInPs << " ps"<< endl);
716  else Cerr(" --> No TOF information in the data" << endl);
717  Cerr(" --> Calibration factor value is: " << m_calibrationFactor << endl);
718  if (mp_POIResolution[0]<0.) Cerr(" --> No POI enabled on the radial axis" << endl);
719  else Cerr(" --> POI resolution on the radial axis is: " << mp_POIResolution[0] << endl);
720  if (mp_POIResolution[1]<0.) Cerr(" --> No POI enabled on the tangential axis" << endl);
721  else Cerr(" --> POI resolution on the tangential axis is: " << mp_POIResolution[1] << endl);
722  if (mp_POIResolution[2]<0.) Cerr(" --> No POI enabled on the axial axis" << endl);
723  else Cerr(" --> POI resolution on the axial axis is: " << mp_POIResolution[2] << endl);
724  Cerr("--------------------------------------------------------------------------------------------------------------------------------------" << endl);
725  return 1;
726  }
727  // End
728  return 0;
729 }
730 
731 // =====================================================================
732 // ---------------------------------------------------------------------
733 // ---------------------------------------------------------------------
734 // =====================================================================
735 
737 {
739  // Dynamic cast the vDataFile to a iDataFilePET
740  iDataFilePET* p_data_file = (dynamic_cast<iDataFilePET*>(ap_DataFile));
741  // Check maximum number of lines per event
743  {
744  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Maximum numbers of lines by event are inconsistent !" << endl);
745  return 1;
746  }
747  // Check maximum ring difference
748  if (m_maxAxialDiffmm!=p_data_file->GetMaxAxialDiffmm())
749  {
750  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Maximum ring differences are inconsistent !" << endl);
751  return 1;
752  }
753  // Check isotope
754  if (m_isotope!=p_data_file->GetIsotope())
755  {
756  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Isotopes are inconsistent !" << endl);
757  return 1;
758  }
759  // Check event kind flag
760  if (m_eventKindFlag!=p_data_file->GetEventKindFlag())
761  {
762  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Event kind flags are inconsistent !" << endl);
763  return 1;
764  }
765  // Check attenuation correction flag
766  if (m_atnCorrectionFlag!=p_data_file->GetAtnCorrectionFlag())
767  {
768  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Attenuation correction flags are inconsistent !" << endl);
769  return 1;
770  }
771  // Check normalization correction flag
772  if (m_normCorrectionFlag!=p_data_file->GetNormCorrectionFlag())
773  {
774  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Normalization correction flags are inconsistent !" << endl);
775  return 1;
776  }
777  // Check scatter correction flag
778  if (m_scatCorrectionFlag!=p_data_file->GetScatCorrectionFlag())
779  {
780  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Scatter correction flags are inconsistent !" << endl);
781  return 1;
782  }
783  // Check random correction flag
784  if (m_randCorrectionFlag!=p_data_file->GetRandCorrectionFlag())
785  {
786  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Random correction flags are inconsistent !" << endl);
787  return 1;
788  }
789  // Check TOF info flag
790  if (m_TOFInfoFlag!=p_data_file->GetTOFInfoFlag())
791  {
792  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> TOF information flags are inconsistent !" << endl);
793  return 1;
794  }
795  // Check TOF resolution
796  if (m_TOFResolutionInPs!=p_data_file->GetTOFResolutionInPs())
797  {
798  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> TOF resolutions are inconsistent !" << endl);
799  return 1;
800  }
801  // Check number of TOF bins
802  if (m_nbTOFBins!=p_data_file->GetNbTOFBins())
803  {
804  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Numbers of TOF bins are inconsistent !" << endl);
805  return 1;
806  }
807  // Check TOF bin size
808  if (m_TOFBinSizeInPs!=p_data_file->GetTOFBinSizeInPs())
809  {
810  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> TOF bin sizes are inconsistent !" << endl);
811  return 1;
812  }
813  // Check TOF measurement range
815  {
816  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> TOF measurement ranges are inconsistent !" << endl);
817  return 1;
818  }
819  // Check TOF quantization bin size
821  {
822  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> TOF quantization bin sizes are inconsistent !" << endl);
823  return 1;
824  }
825  // Check data mode
826  if (m_dataMode!=p_data_file->GetDataMode())
827  {
828  Cerr("***** iDataFilePET::CheckSpecificConsistencyWithAnotherDataFile() -> Data modes are inconsistent (list-mode or histogram) !" << endl);
829  return 1;
830  }
831  // End
832  return 0;
833 }
834 
835 // =====================================================================
836 // ---------------------------------------------------------------------
837 // ---------------------------------------------------------------------
838 // =====================================================================
839 
841 {
843  if (m_verbose>=VERBOSE_DETAIL) Cout("iDataFilePET::PROJ_InitFile() -> Initialize datafile for writing"<< endl);
844 
845  m_nbEvents = 0; //Std initialization for projection
846  m_nbTOFBins = 1; // Initialization of this variable required for PROJ_Write functions
847 
848  // Default time initialization if image dimensions object has not been initialized
849  if(mp_ID->IsInitialized())
850  {
852 
853  for(uint16_t fr=0 ; fr<mp_ID->GetNbTimeFrames() ; fr++)
855 
856  // Instanciate a fstream datafile for each thread
857  m2p_dataFile = new fstream*[mp_ID->GetNbThreadsForProjection()];
858  }
859  else
860  {
861  m_startTimeInSec = 0.;
862  m_durationInSec = 1.;
863  m2p_dataFile = new fstream*[1];
864  }
865 
866 
867 
868  // Set name of the projection data header
869  sOutputManager* p_OutMgr;
870  p_OutMgr = sOutputManager::GetInstance();
871  string path_name = p_OutMgr->GetPathName();
872  string img_name = p_OutMgr->GetBaseName();
873  m_headerFileName = path_name.append(img_name).append("_df").append(".Cdh");
874 
875  for (int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
876  {
877  m_dataFileName = m_headerFileName.substr(0, m_headerFileName.find_last_of(".")).append(".Cdf"); // Generate datafile name from header file
878 
879  // We'll write projeted data in several files (corresponding to the number of thread) to be concatenated at the end of the projection process.
880  stringstream ss;
881  ss << th;
882  string datafile_name = m_dataFileName;
883  datafile_name.append("_").append(ss.str());
884 
885  m2p_dataFile[th] = new fstream( datafile_name.c_str(), ios::binary | ios::out | ios::trunc);
886  }
887 
888 
889  // Check there is no existing datafile with such name. Remove it otherwise
890  ifstream fcheck(m_dataFileName.c_str());
891  if(fcheck.good())
892  {
893  fcheck.close();
894  #ifdef _WIN32
895  string dos_instruction = "del " + m_dataFileName;
896  system(dos_instruction.c_str());
897  #else
898  remove(m_dataFileName.c_str());
899  #endif
900  }
901 
902  if (m_verbose>=VERBOSE_DETAIL) Cout(" --> Output datafile name :" << m_dataFileName << endl);
903 
904  return 0;
905 }
906 
907 // =====================================================================
908 // ---------------------------------------------------------------------
909 // ---------------------------------------------------------------------
910 // =====================================================================
911 
912 int iDataFilePET::WriteEvent(vEvent* ap_Event, int a_th)
913 {
915 
916  if (m_dataMode == MODE_LIST)
917  {
918  if (WriteListEvent((iEventListPET*)ap_Event, a_th))
919  {
920  Cerr("*****iDataFilePET::WriteEvent() -> Error while trying to write projection datafile (list-mode)" << endl;);
921  return 1;
922  }
923  }
924 
925  if (m_dataMode == MODE_HISTOGRAM)
926  {
927  if (WriteHistoEvent((iEventHistoPET*)ap_Event, a_th))
928  {
929  Cerr("*****iDataFilePET::WriteEvent() -> Error while trying to write projection datafile (histogram)" << endl;);
930  return 1;
931  }
932  }
933 
934  return 0;
935 }
936 
937 // =====================================================================
938 // ---------------------------------------------------------------------
939 // ---------------------------------------------------------------------
940 // =====================================================================
941 
943 {
945 
946  // Write sequentially each field of the event according to the type of the event.
947  m2p_dataFile[a_th]->clear();
948 
949  uint32_t time = ap_Event->GetTimeInMs();
950  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&time), sizeof(uint32_t));
951 
953  {
954  FLTNBDATA atn_corr_factor = ap_Event->GetAtnCorrFactor();
955  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&atn_corr_factor), sizeof(FLTNBDATA));
956  }
957 
959  {
960  FLTNBDATA rdm_rate = ap_Event->GetEventRdmRate();
961  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&rdm_rate), sizeof(FLTNBDATA));
962  }
963 
965  {
966  FLTNBDATA norm_corr_factor = ap_Event->GetNormFactor();
967  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&norm_corr_factor), sizeof(FLTNBDATA));
968  }
969 
970  for(int b=0 ; b<m_nbTOFBins ; b++)
971  {
972  FLTNBDATA event_value = ap_Event->GetEventValue(b);
973  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&event_value), sizeof(FLTNBDATA));
975  {
976  FLTNBDATA scat_rate = ap_Event->GetEventScatRate(b);
977  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&scat_rate), sizeof(FLTNBDATA));
978  }
979  }
980 
981  uint16_t nb_lines = ap_Event->GetNbLines();
982  // Write the number of lines only if the m_maxNumberOfLinesPerEvent is above 1
983  if (m_maxNumberOfLinesPerEvent>1) m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&nb_lines), sizeof(uint16_t));
984 
985  for(int i=0 ; i<nb_lines ; i++)
986  {
987  uint32_t id1 = ap_Event->GetID1(i);
988  uint32_t id2 = ap_Event->GetID2(i);
989  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id1), sizeof(uint32_t));
990  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id2), sizeof(uint32_t));
991  }
992 
993  // 0-filling if needed (nb lines inferior to the max number for PET data with compression)
994  if(nb_lines<m_maxNumberOfLinesPerEvent)
995  for(int i=0 ; i<m_maxNumberOfLinesPerEvent-nb_lines ; i++)
996  {
997  uint32_t gbg = 0;
998  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&gbg), sizeof(uint32_t));
999  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&gbg), sizeof(uint32_t));
1000  }
1001 
1002  return 0;
1003 }
1004 
1005 // =====================================================================
1006 // ---------------------------------------------------------------------
1007 // ---------------------------------------------------------------------
1008 // =====================================================================
1009 
1011 {
1013 
1014  // Write sequentially each field of the event according to the type of the event.
1015  m2p_dataFile[a_th]->clear();
1016 
1017  uint32_t time = ap_Event->GetTimeInMs();
1018  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&time), sizeof(uint32_t));
1019 
1020 
1022  {
1023  FLTNBDATA atn_corr_factor = ap_Event->GetAtnCorrFactor();
1024  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&atn_corr_factor), sizeof(FLTNBDATA));
1025  }
1026 
1027  if(m_eventKindFlag)
1028  {
1029  uint8_t event_kind = ap_Event->GetKind();
1030  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&event_kind), sizeof(uint8_t));
1031  }
1032 
1034  {
1035  FLTNBDATA scat_rate = ap_Event->GetEventScatRate(0);
1036  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&scat_rate), sizeof(FLTNBDATA));
1037  }
1038 
1040  {
1041  FLTNBDATA rdm_rate = ap_Event->GetEventRdmRate();
1042  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&rdm_rate), sizeof(FLTNBDATA));
1043  }
1044 
1046  {
1047  FLTNBDATA norm_corr_factor = ap_Event->GetNormFactor();
1048  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&norm_corr_factor), sizeof(FLTNBDATA));
1049  }
1050 
1051  if(m_TOFInfoFlag)
1052  {
1053  FLTNBDATA TOF_measurement = ap_Event->GetTOFMeasurementInPs();
1054  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&TOF_measurement), sizeof(FLTNBDATA));
1055  }
1056 
1057 
1058  if(mp_POIResolution[0]>0)
1059  {
1060  FLTNBDATA POI_1 = ap_Event->GetPOI1(0);
1061  FLTNBDATA POI_2 = ap_Event->GetPOI2(0);
1062  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI_1), sizeof(FLTNBDATA));
1063  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI_2), sizeof(FLTNBDATA));
1064  }
1065  if(mp_POIResolution[1]>0)
1066  {
1067  FLTNBDATA POI_1 = ap_Event->GetPOI1(1);
1068  FLTNBDATA POI_2 = ap_Event->GetPOI2(1);
1069  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI_1), sizeof(FLTNBDATA));
1070  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI_2), sizeof(FLTNBDATA));
1071  }
1072  if(mp_POIResolution[2]>0)
1073  {
1074  FLTNBDATA POI_1 = ap_Event->GetPOI1(2);
1075  FLTNBDATA POI_2 = ap_Event->GetPOI2(2);
1076  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI_1), sizeof(FLTNBDATA));
1077  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI_2), sizeof(FLTNBDATA));
1078  }
1079 
1080  uint16_t nb_lines = ap_Event->GetNbLines();
1081  // Write the number of lines only if the m_maxNumberOfLinesPerEvent is above 1
1082  if (m_maxNumberOfLinesPerEvent>1) m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&nb_lines), sizeof(uint16_t));
1083 
1084  for(int i=0 ; i<nb_lines ; i++)
1085  {
1086  uint32_t id1 = ap_Event->GetID1(i);
1087  uint32_t id2 = ap_Event->GetID2(i);
1088  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id1), sizeof(uint32_t));
1089  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id2), sizeof(uint32_t));
1090  }
1091 
1092  // 0-filling if needed (nb lines inferior to the max number for PET data with compression)
1093  if(nb_lines<m_maxNumberOfLinesPerEvent)
1094  for(int i=0 ; i<m_maxNumberOfLinesPerEvent-nb_lines ; i++)
1095  {
1096  uint32_t gbg = 0;
1097  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&gbg), sizeof(uint32_t));
1098  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&gbg), sizeof(uint32_t));
1099  }
1100 
1101  return 0;
1102 }
1103 
1104 // =====================================================================
1105 // ---------------------------------------------------------------------
1106 // ---------------------------------------------------------------------
1107 // =====================================================================
1108 
1110 {
1111  // Verbose
1113  if (m_verbose>=VERBOSE_NORMAL) Cout("iDataFilePET::WriteHeader() -> Write header file '" << m_headerFileName << "'" << endl);
1114  // Open file
1115  fstream headerFile;
1116  headerFile.open(m_headerFileName.c_str(), ios::out);
1117 
1118  if (!headerFile.is_open())
1119  {
1120  Cerr("***** iDataFilePET::WriteHeader() -> Failed to open output header file '" << m_headerFileName << "' !" << endl);
1121  return 1;
1122  }
1123 
1124  // Data file name
1125  headerFile << "Data filename: " << GetFileFromPath(m_dataFileName) << endl;
1126  // Number of events
1127  headerFile << "Number of events: " << m_nbEvents << endl;
1128  // Data mode
1129  if (m_dataMode==MODE_HISTOGRAM) headerFile << "Data mode: histogram" << endl;
1130  else if (m_dataMode==MODE_LIST) headerFile << "Data mode: list-mode" << endl;
1131  else if (m_dataMode==MODE_NORMALIZATION) headerFile << "Data mode: normalization" << endl;
1132  // PET data type
1133  headerFile << "Data type: PET" << endl;
1134  // Acquisition start time in seconds
1135  headerFile << "Start time (s): " << m_startTimeInSec << endl;
1136  // Acquisition duration in seconds
1137  headerFile << "Duration (s): " << m_durationInSec << endl;
1138  // Scanner name
1139  headerFile << "Scanner name: " << sScannerManager::GetInstance()->GetScannerName() << endl;
1140  // Maximum axial difference
1141  if(m_maxAxialDiffmm > 0.)
1142  headerFile << "Maximum axial difference mm: " << m_maxAxialDiffmm << endl;
1143  // Maximum number of lines per event (write it only if higher than 1
1144  if (m_maxNumberOfLinesPerEvent >1) headerFile << "Maximum number of lines per event: " << m_maxNumberOfLinesPerEvent << endl;
1145 
1146  // Calibration factor
1147  headerFile << "Calibration factor: " << m_calibrationFactor << endl;
1148  // Isotope
1149  headerFile << "Isotope: " << m_isotope << endl;
1150  // TOF info
1151  if (m_TOFInfoFlag)
1152  {
1153  // Flag
1154  headerFile << "TOF information flag: 1" << endl;
1155  // TOF resolution
1156  headerFile << "TOF resolution (ps): " << m_TOFResolutionInPs << endl;
1157  // List-mode TOF measurement range
1158  if (m_dataMode == MODE_LIST)
1159  {
1160  headerFile << "List TOF measurement range (ps): " << m_TOFMeasurementRangeInPs << endl;
1161  if (m_TOFQuantizationBinSizeInPs>0.) headerFile << "List TOF quantization bin size (ps): " << m_TOFQuantizationBinSizeInPs << endl;
1162  }
1163  // Histogram
1164  else if (m_dataMode == MODE_HISTOGRAM)
1165  {
1166  // Number of TOF bins
1167  headerFile << "Histo TOF number of bins: " << m_nbTOFBins << endl;
1168  // TOF bin size
1169  headerFile << "Histo TOF bin size (ps): " << m_TOFBinSizeInPs << endl;
1170  }
1171  }
1172  // Event kind
1173  if (m_eventKindFlag)
1174  {
1175  // Error if histogram data are used
1177  {
1178  Cerr("***** iDataFilePET::WriteHeader -> Request for writing event type in histogram mode (this field is specific to list-mode) !" << endl);
1179  return 1;
1180  }
1181  else headerFile << "Coincidence kind flag: " << m_eventKindFlag << endl;
1182  }
1183  // Correction flags
1184  if (m_atnCorrectionFlag)
1185  headerFile << "Attenuation correction flag: " << m_atnCorrectionFlag << endl;
1187  headerFile << "Normalization correction flag: " << m_normCorrectionFlag << endl;
1189  headerFile << "Scatter correction flag: " << m_scatCorrectionFlag << endl;
1191  headerFile << "Random correction flag: " << m_randCorrectionFlag << endl;
1192  // Close file
1193  headerFile.close();
1194  // End
1195  return 0;
1196 }
1197 
1198 // =====================================================================
1199 // ---------------------------------------------------------------------
1200 // ---------------------------------------------------------------------
1201 // =====================================================================
1202 
1204 {
1205  // Verbose
1207  if (m_verbose>=VERBOSE_DETAIL) Cout("PROJ_GetScannerSpecificParameters() ..."<< endl);
1208  // Get pointers to SPECT specific parameters in scanner
1209  if (sScannerManager::GetInstance()->PROJ_GetPETSpecificParameters(&m_maxAxialDiffmm) )
1210  {
1211  Cerr("***** iDataFilePET::PROJ_GetScannerSpecificParameters() -> An error occurred while trying to get PET geometric parameters from the scanner object !" << endl);
1212  return 1;
1213  }
1214  // End
1215  return 0;
1216 }
1217 
1218 // =====================================================================
1219 // ---------------------------------------------------------------------
1220 // ---------------------------------------------------------------------
1221 // =====================================================================
int WriteEvent(vEvent *ap_Event, int a_th)
Write event according to the chosen type of data.
bool m_randCorrectionFlag
This class is designed to be a mother virtual class for DataFile.
Definition: vDataFile.hh:102
bool GetNormCorrectionFlag()
Simply return m_normCorrectionFlag.
int SetPETIsotope(int a_bed, const string &a_isotope)
Set the PET isotope for the provided bed.
static sScannerManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
#define VERBOSE_DEBUG_EVENT
bool GetTOFInfoFlag()
#define MODE_HISTOGRAM
Definition: vDataFile.hh:58
#define TYPE_PET
Definition: vDataFile.hh:73
FLTNB GetTOFMeasurementRangeInPs()
void SetNbLines(uint16_t a_value)
Set the number of lines of the Event.
Definition: vEvent.hh:153
FLTNB m_TOFMeasurementRangeInPs
int64_t m_sizeEvent
Definition: vDataFile.hh:597
bool mp_POIDirectionFlag[3]
Definition: vDataFile.hh:593
string m_dataFileName
Definition: vDataFile.hh:577
FLTNB GetFrameTimeStartInSec(int a_bed, int a_frame)
Get the frame time start for the given bed, in seconds as a FLTNB.
#define MODE_LIST
Definition: vDataFile.hh:56
int PROJ_GetScannerSpecificParameters()
Get PET specific parameters for projections from the scanner object, through the scannerManager.
#define MODE_NORMALIZATION
Definition: vDataFile.hh:60
bool m_ignoreNormCorrectionFlag
bool m_ignoreTOFFlag
void DescribeSpecific()
Implementation of the pure virtual eponym function that simply prints info about the datafile...
FLTNB GetEventScatRate(int a_bin)
FLTNB m_maxAxialDiffmm
uint32_t GetID2(int a_line)
Definition: vEvent.hh:107
#define VERBOSE_DETAIL
int CheckSpecificConsistencyWithAnotherDataFile(vDataFile *ap_DataFile)
Check consistency between &#39;this&#39; and the provided datafile, for specific characteristics.
FLTNB m_durationInSec
Definition: vDataFile.hh:583
iDataFilePET()
iDataFilePET constructor. Initialize the member variables to their default values.
Definition: iDataFilePET.cc:38
bool GetIgnoreAttnCorrectionFlag()
Get the boolean that says if the attenuation correction is ignored or not.
int ReadSpecificInfoInHeader(bool a_affectQuantificationFlag)
Read through the header file and gather specific PET information.
Definition: iDataFilePET.cc:76
bool IsInitialized()
Returns true if the object has been initialized.
string m_headerFileName
Definition: vDataFile.hh:576
int CheckSpecificParameters()
Check parameters specific to PET data.
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.
vEvent * GetEventSpecific(char *ap_buffer, int a_th)
Read an event from the position pointed by &#39;ap_buffer&#39;, parse the generic or modality-specific inform...
bool m_ignoreScatCorrectionFlag
int ComputeSizeEvent()
Computation of the size of each event according to the mandatory/optional correction fields...
Declaration of class iDataFilePET.
int m_dataSpec
Definition: vDataFile.hh:581
FLTNB m_startTimeInSec
Definition: vDataFile.hh:582
bool m_eventKindFlag
string GetFileFromPath(const string &a_pathToFile)
Simply return the file from a path string passed in parameter.
Definition: gOptions.cc:1152
string GetIsotope()
bool GetIgnoreNormCorrectionFlag()
Get the boolean that says if the normalization correction is ignored or not.
FLTNB m_TOFBinSizeInPs
bool GetIgnoreRandCorrectionFlag()
Get the boolean that says if the random correction is ignored or not.
#define FLTNBDATA
Definition: gVariables.hh:87
void SetAttenuationCorrectionFactor(FLTNBDATA a_value)
Cast the FLTNBDATA value passed as parameter in FLTNB, and set it to the attenuation correction facto...
Definition: iEventNorm.hh:88
Inherit from iEventPET. Class for PET list-mode events.
FLTNB GetEventValue(int a_bin)
#define Cerr(MESSAGE)
const string & GetPathName()
Inherit from iEventPET. Class for PET histogram mode events.
#define VERBOSE_DEBUG_LIGHT
bool m_ignorePOIFlag
Definition: vDataFile.hh:592
~iDataFilePET()
iDataFilePET destructor.
Definition: iDataFilePET.cc:69
Singleton class that manages output writing on disk (images, sinograms, etc). It also manages loggi...
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
bool m_ignoreAttnCorrectionFlag
FLTNB GetTOFQuantizationBinSizeInPs()
int m_dataType
Definition: vDataFile.hh:580
int64_t m_nbEvents
Definition: vDataFile.hh:578
bool GetScatCorrectionFlag()
Simply return m_scatCorrectionFlag.
int SetSpecificParametersFrom(vDataFile *ap_DataFile)
Initialize all parameters specific to PET from the provided datafile.
oImageDimensionsAndQuantification * mp_ID
Definition: vDataFile.hh:572
uint16_t GetMaxNumberOfLinesPerEvent()
fstream ** m2p_dataFile
Definition: vDataFile.hh:598
bool GetEventKindFlag()
Simply return m_eventKindFlag.
#define VERBOSE_NORMAL
uint8_t GetKind()
FLTNB GetNormFactor()
Definition: iEventPET.hh:84
int WriteHistoEvent(iEventHistoPET *ap_Event, int a_th)
Write a PET histogram event.
int WriteHeader()
Generate a header file according to the data output information.
int m_bedIndex
Definition: vDataFile.hh:585
int PROJ_InitFile()
Initialize the fstream objets for output writing as well as some other variables specific to the Proj...
FLTNB m_TOFResolutionInPs
FLTNB m_TOFQuantizationBinSizeInPs
#define KEYWORD_OPTIONAL
Definition: gOptions.hh:49
FLTNB * GetPOI2()
Inherit from vEvent. Used for normalization events for sensitivity computation.
Definition: iEventNorm.hh:42
FLTNB GetTOFBinSizeInPs()
FLTNB GetTOFResolutionInPs()
int PrepareDataFile()
Store different kind of information inside arrays (data relative to specific correction as well as ba...
FLTNB mp_POIResolution[3]
Definition: vDataFile.hh:594
const string & GetBaseName()
uint16_t GetNbLines()
Definition: vEvent.hh:93
void SetTimeInMs(uint32_t a_value)
Set the timestamp of the Event.
Definition: vEvent.hh:138
FLTNB GetMaxAxialDiffmm()
Mother class for the Event objects.
Definition: vEvent.hh:42
int GetDataMode()
Definition: vDataFile.hh:299
string m_isotope
int GetNbTimeFrames()
Get the number of time frames.
FLTNB GetAtnCorrFactor()
Definition: iEventPET.hh:90
vEvent ** m2p_BufferEvent
Definition: vDataFile.hh:599
bool GetRandCorrectionFlag()
Simply return m_randCorrectionFlag.
bool m_POIInfoFlag
Definition: vDataFile.hh:591
#define SPEC_EMISSION
Definition: vDataFile.hh:90
uint32_t GetID1(int a_line)
Definition: vEvent.hh:100
FLTNB * GetPOI1()
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 GetNbTOFBins()
#define DEBUG_VERBOSE(IGNORED1, IGNORED2)
int CheckFileSizeConsistency()
This function is implemented in child classes Check if file size is consistent. ...
#define Cout(MESSAGE)
FLTNB m_calibrationFactor
Definition: vDataFile.hh:584
FLTNB GetEventRdmRate()
Definition: iEventPET.hh:78
FLTNB GetFrameDurationInSec(int a_bed, int a_frame)
Get the frame duration for the given bed, in seconds as a FLTNB.
bool m_atnCorrectionFlag
bool m_normCorrectionFlag
uint16_t m_maxNumberOfLinesPerEvent
bool GetAtnCorrectionFlag()
Simply return m_atnCorrectionFlag.
Inherit from vDataFile. Class that manages the reading of a PET input file (header + data)...
Definition: iDataFilePET.hh:43
bool m_scatCorrectionFlag
FLTNB GetEventScatRate(int a_bin)
int m_verbose
Definition: vDataFile.hh:573
uint32_t GetTimeInMs()
Definition: vEvent.hh:87
FLTNB GetTOFMeasurementInPs()
bool m_ignoreRandCorrectionFlag
int WriteListEvent(iEventListPET *ap_Event, int a_th=0)
Write a PET list-mode event.