CASToR  1.1
Tomographic Reconstruction (PET/SPECT)
 All Classes Files Functions Variables Typedefs Macros Groups Pages
iDataFileSPECT.cc
Go to the documentation of this file.
1 
9 #include "iDataFileSPECT.hh"
10 
11 // =====================================================================
12 // ---------------------------------------------------------------------
13 // ---------------------------------------------------------------------
14 // =====================================================================
15 
17 {
18  // Set all members to default values
20  m_isotope = "unknown";
21  mp_nbOfBins[0] = 1;
22  mp_nbOfBins[1] = 1;
24  mp_angles = NULL;
25  m_nbHeads = 1;
27  m_eventKindFlag = false;
28  m_normCorrectionFlag = false;
30  m_scatCorrectionFlag = false;
33 }
34 
35 // =====================================================================
36 // ---------------------------------------------------------------------
37 // ---------------------------------------------------------------------
38 // =====================================================================
39 
41 {
42  if (mp_angles) delete[] mp_angles;
44 }
45 
46 // =====================================================================
47 // ---------------------------------------------------------------------
48 // ---------------------------------------------------------------------
49 // =====================================================================
50 
51 int iDataFileSPECT::ReadSpecificInfoInHeader(bool a_affectQuantificationFlag)
52 {
54  // Verbose
55  if (m_verbose>=VERBOSE_DETAIL) Cout("iDataFileSPECT::ReadSpecificInfoInHeader() -> Read information specific to SPECT" << endl);
56 
57  // Create pointers dedicated to recover the addresses of the member variables of the scanner object
58  FLTNB* p_angles = NULL;
59  FLTNB* p_CORtoDetectorDistance = NULL;
60  FLTNB p_pixSizeXY[2]; // not used here
61 
62  // Get Geometric parameters recovered from the scanner object
63  sScannerManager* p_scannermanager;
64  p_scannermanager = sScannerManager::GetInstance();
66  &m_nbHeads,
67  mp_nbOfBins,
68  p_pixSizeXY,
69  p_angles,
70  p_CORtoDetectorDistance,
72 
73  // Check m_nbOfProjections first before allocating projection angles and radius using this variable
74  if (m_nbOfProjections==0)
75  {
76  Cerr("***** iDataFileSPECT::ReadSpecificInfoInHeader() -> Number of projections should be strictly positive !" << endl);
77  return 1;
78  }
79 
80  // Allocation and initialization of Projection angles and Center of rotation to SPECT detector surface distance (radius) :
83 
84  // Recover values
85  for (int a=0 ; a<m_nbOfProjections ; a++)
86  {
87  mp_angles[a] = p_angles[a];
88  mp_CORtoDetectorDistance[a] = p_CORtoDetectorDistance[a];
89  }
90 
91  // Feedback to user
93  {
94  Cout(" --> Provided projection angles | distance Center of Rotation (COR) to detector: " << endl);
95  for (int a=0 ; a<m_nbOfProjections ; a++) Cout(" " << mp_angles[a] << " | " << mp_CORtoDetectorDistance[a] << endl);
96  }
97 
98  // Read optional fields in the header, check if errors (issue during data reading/conversion (==1) )
99  if (ReadDataASCIIFile(m_headerFileName, "Isotope", &m_isotope, 1, 0) == 1 ||
100  ReadDataASCIIFile(m_headerFileName, "Event kind flag", &m_eventKindFlag, 1, 0) == 1 ||
101  ReadDataASCIIFile(m_headerFileName, "Normalization correction flag", &m_normCorrectionFlag, 1, 0) == 1 ||
102  ReadDataASCIIFile(m_headerFileName, "Scatter correction flag", &m_scatCorrectionFlag, 1, 0) == 1 )
103  {
104  Cerr("***** iDataFileSPECT::ReadSpecificInfoInHeader() -> Error while reading optional fields in the header data file !" << endl);
105  return 1;
106  }
107 
108  // Give the SPECT isotope to the oImageDimensionsAndQuantification that manages the quantification factors
109  if (a_affectQuantificationFlag && mp_ID->SetSPECTIsotope(m_bedIndex, m_isotope))
110  {
111  Cerr("***** iDataFileSPECT::ReadSpecificInfoInHeader() -> A problem occured while setting the isotope to oImageDimensionsAndQuantification !" << endl);
112  return 1;
113  }
114 
115  // Normal end
116  return 0;
117 }
118 
119 // =====================================================================
120 // ---------------------------------------------------------------------
121 // ---------------------------------------------------------------------
122 // =====================================================================
123 
125 {
127  // Verbose
128  if (m_verbose>=VERBOSE_DETAIL) Cout("iDataFileSPECT::ComputeSizeEvent() -> In bytes" << endl);
129 
130  // For MODE_LIST events
131  if (m_dataMode == MODE_LIST)
132  {
133  // Size of the mandatory element in a list-mode event: Time + 2*crystalID
134  m_sizeEvent = sizeof(uint32_t) + 2*sizeof(uint32_t);
135  // Optional flags
136  if (m_eventKindFlag) m_sizeEvent += sizeof(FLTNBDATA);
139  for (int i=0 ; i<3; i++)
140  {
141  // POI available for this direction
142  if (mp_POIDirectionFlag[i]) m_sizeEvent += sizeof(FLTNBDATA);
143  }
144  }
145  // For MODE_HISTOGRAM events
147  {
148  // Size of the mandatory element in a histo event: Time + event_value + 2*crystalID
149  m_sizeEvent = sizeof(uint32_t) + sizeof(FLTNBDATA) + 2*sizeof(uint32_t);
150  // Optional flags
153  }
154  // Unknown event type
155  else
156  {
157  Cerr("***** iDataFileSPECT::ComputeSizeEvent() -> Unknown event mode !" << endl);
158  return 1;
159  }
160 
161  // Check
162  if (m_sizeEvent<=0)
163  {
164  Cerr("***** iDataFileSPECT::ComputeSizeEvent() -> Error, the Event size in bytes should be >= 0 !" << endl;);
165  return 1;
166  }
167 
168  // Verbose
169  if (m_verbose>=VERBOSE_DETAIL) Cout(" --> Event size: " << m_sizeEvent << " bytes" << endl);
170  // End
171  return 0;
172 }
173 
174 // =====================================================================
175 // ---------------------------------------------------------------------
176 // ---------------------------------------------------------------------
177 // =====================================================================
178 
180 {
182  // Verbose
184  {
185  if (m_dataMode==MODE_HISTOGRAM) Cout("iDataFileSPECT::PrepareDataFile() -> Build histogram events" << endl);
186  else if (m_dataMode==MODE_LIST) Cout("iDataFileSPECT::PrepareDataFile() -> Build listmode events" << endl);
187  else if (m_dataMode==MODE_NORMALIZATION) Cout("iDataFileSPECT::PrepareDataFile() -> Build normalization events" << endl);
188  }
189 
190  // ==============================================================================
191  // Allocate event buffers (one for each thread)
192  // ==============================================================================
193 
194  if (m_verbose>=VERBOSE_DETAIL) Cout(" --> Allocate an event buffer for each thread" << endl);
195  // Instanciation of the event buffer according to the data type
197 
198  // Allocate the events per each thread
199  for (int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
200  {
201  // For MODE_LIST events
202  if (m_dataMode == MODE_LIST)
203  {
204  m2p_BufferEvent[th] = new iEventListSPECT();
205  }
206  // For MODE_HISTOGRAM events
207  if (m_dataMode == MODE_HISTOGRAM)
208  {
209  m2p_BufferEvent[th] = new iEventHistoSPECT();
210  }
211  // Allocate crystal/view IDs
212  if (m2p_BufferEvent[th]->AllocateID())
213  {
214  Cerr("*****iDataFileSPECT::PrepareDataFile() -> Error while trying to allocate memory for the Event object!" << endl);
215  return 1;
216  }
217  }
218 
219  // ==============================================================================
220  // Deal with specific corrections
221  // ==============================================================================
222 
223  // In case of normalization correction flag, see if we ignore this correction
225  {
226  // Affect the ignored flag from the ignored corrections list processed by the oImageDimensionsAndQuantification
228  // Verbose
230  {
231  if (m_ignoreNormCorrectionFlag) Cout(" --> Ignore normalization correction" << endl);
232  else Cout(" --> Correct for normalization" << endl);
233  }
234  }
235  // In case of scatter correction flag, see if we ignore this correction
237  {
238  // Affect the ignored flag from the ignored corrections list processed by the oImageDimensionsAndQuantification
240  // Verbose
242  {
243  if (m_ignoreScatCorrectionFlag) Cout(" --> Ignore scatter correction" << endl);
244  else Cout(" --> Correct for scatter events" << endl);
245  }
246  }
247 
248  // Normal end
249  return 0;
250 }
251 
252 // =====================================================================
253 // ---------------------------------------------------------------------
254 // ---------------------------------------------------------------------
255 // =====================================================================
256 
257 vEvent* iDataFileSPECT::GetEventFromBuffer(char* ap_buffer, int a_th)
258 {
260 
261  // Work on a copy of the input pointer
262  char* file_position = ap_buffer;
263 
264  // For MODE_LIST SPECT data
265  if (m_dataMode == MODE_LIST)
266  {
267  // Cast the event pointer
268  iEventListSPECT* event = (dynamic_cast<iEventListSPECT*>(m2p_BufferEvent[a_th]));
269  // Mandatory time field: [uint32_t (time)]
270  event->SetTimeInMs(*reinterpret_cast<uint32_t*>(file_position));
271  file_position += sizeof(uint32_t);
272  // Optional kind: [uint8_t kind]
273  if (m_eventKindFlag)
274  {
275  event->SetKind(*reinterpret_cast<uint8_t*>(file_position));
276  file_position += sizeof(uint8_t);
277  }
278  // Optional scatter correction field: [FLTNBDATA (scatter)]
280  {
281  if (!m_ignoreScatCorrectionFlag) event->SetScatterRate(*reinterpret_cast<FLTNBDATA*>(file_position));
282  file_position += sizeof(FLTNBDATA);
283  }
284  // Optional normalization correction field: [FLTNBDATA (norm)]
286  {
287  if (!m_ignoreNormCorrectionFlag) event->SetNormalizationFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
288  file_position += sizeof(FLTNBDATA);
289  }
290  // Optional POI correction field: [FLTNBDATA (POI1[3])]
291  for (int i=0; i<3; i++)
292  {
293  if (mp_POIDirectionFlag[i])
294  {
295  if (!m_ignorePOIFlag) event->SetPOI(i,*reinterpret_cast<FLTNBDATA*>(file_position));
296  file_position += sizeof(FLTNBDATA);
297  }
298  }
299  // Mandatory angular projection ID: [uint32_t (ID1)]
300  event->SetID1(0, *reinterpret_cast<uint32_t*>(file_position));
301  file_position += sizeof(uint32_t);
302  // Mandatory crystal ID: [uint32_t (ID2)]
303  event->SetID2(0, *reinterpret_cast<uint32_t*>(file_position));
304  file_position += sizeof(uint32_t);
305  }
306 
307  // For MODE_HISTOGRAM SPECT DATA
308  if (m_dataMode == MODE_HISTOGRAM)
309  {
310  // Cast the event pointer
311  iEventHistoSPECT* event = (dynamic_cast<iEventHistoSPECT*>(m2p_BufferEvent[a_th]));
312  // Mandatory time field: [uint32_t (time)]
313  event->SetTimeInMs(*reinterpret_cast<uint32_t*>(file_position));
314  file_position += sizeof(uint32_t);
315  // Mandatory bin value: [FLTNBDATA bin value]
316  event->SetEventValue(0, *reinterpret_cast<FLTNBDATA*>(file_position));
317  file_position += sizeof(FLTNBDATA);
318  // Optional scatter correction field: [FLTNBDATA (scatter)]
320  {
321  if (!m_ignoreScatCorrectionFlag) event->SetScatterRate(*reinterpret_cast<FLTNBDATA*>(file_position));
322  file_position += sizeof(FLTNBDATA);
323  }
324  // Optional normalization correction field: [FLTNBDATA (norm)]
326  {
327  if (!m_ignoreNormCorrectionFlag) event->SetNormalizationFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
328  file_position += sizeof(FLTNBDATA);
329  }
330  // Mandatory angular projection ID: [uint32_t (ID1)]
331  event->SetID1(0, *reinterpret_cast<uint32_t*>(file_position));
332  file_position += sizeof(uint32_t);
333  // Mandatory crystal ID: [uint32_t (ID2)]
334  event->SetID2(0, *reinterpret_cast<uint32_t*>(file_position));
335  file_position += sizeof(uint32_t);
336  }
337 
338  // Return the updated event
339  return m2p_BufferEvent[a_th];
340 }
341 
342 // =====================================================================
343 // ---------------------------------------------------------------------
344 // ---------------------------------------------------------------------
345 // =====================================================================
346 
348 {
350  // Error if m_dataType != SPECT
351  if (m_dataType != TYPE_SPECT)
352  {
353  Cerr("***** iDataFileSPECT::CheckSpecificParameters() -> Data type should be SPECT !'" << endl);
354  return 1;
355  }
356  // Check number of projections
357  if (m_nbOfProjections == 0)
358  {
359  Cerr("***** iDataFileSPECT::CheckSpecificParameters() -> Number of projections not initialized (should be >0) !" << endl);
360  return 1;
361  }
362  // Check projection angles
363  if (mp_angles == NULL)
364  {
365  Cerr("***** iDataFileSPECT::CheckSpecificParameters() -> Projection angles not initialized !" << endl);
366  return 1;
367  }
368  // End
369  return 0;
370 }
371 
372 // =====================================================================
373 // ---------------------------------------------------------------------
374 // ---------------------------------------------------------------------
375 // =====================================================================
376 
378 {
380 
381  // Check datafile self-consistency
382  m2p_dataFile[0]->seekg(0, ios::end);
383  int64_t sizeInBytes = m2p_dataFile[0]->tellg();
384  if (m_totalNbEvents*m_sizeEvent != sizeInBytes)
385  {
386  Cerr("----------------------------------------------------------------------------------------------------------------------------------------" << endl);
387  Cerr("***** iDataFileSPECT::CheckFileSizeConsistency() -> Datafile size is not consistent with the information provided by the user/datafile !" << endl);
388  Cerr(" --> Expected size: "<< m_totalNbEvents*m_sizeEvent << endl);
389  Cerr(" --> Actual size: "<< sizeInBytes << endl << endl);
390  Cerr(" ADDITIONAL INFORMATION ABOUT THE DATAFILE INITIALIZATION" << endl);
391  if (m_eventKindFlag) Cerr(" --> Coincidence kind term is enabled" << endl);
392  else Cerr(" --> No information about the kind of coincidences in the data" << endl);
393  if (m_normCorrectionFlag) Cerr(" --> Normalization correction term is enabled" << endl);
394  else Cerr(" --> No normalization correction term in the data" << endl);
395  if (m_scatCorrectionFlag) Cerr(" --> Scatter correction term is enabled" << endl);
396  else Cerr(" --> No scatter correction term in the data" << endl);
397  Cerr(" --> Calibration factor value is: " << m_calibrationFactor << endl);
398  Cerr(" --> Number of bins are equal to " << mp_nbOfBins[0] << "," << mp_nbOfBins[1] << " for transaxial,axial axis respectively" << endl);
399  if (mp_POIResolution[0]<0.) Cerr(" --> No POI enabled on the radial axis" << endl);
400  else Cerr(" --> POI resolution on the radial axis is: " << mp_POIResolution[0] << endl);
401  if (mp_POIResolution[1]<0.) Cerr(" --> No POI enabled on the tangential axis" << endl);
402  else Cerr(" --> POI resolution on the tangential axis is: " << mp_POIResolution[1] << endl);
403  if (mp_POIResolution[2]<0.) Cerr(" --> No POI enabled on the axial axis" << endl);
404  else Cerr(" --> POI resolution on the axial axis is: " << mp_POIResolution[2] << endl);
405  Cerr("----------------------------------------------------------------------------------------------------------------------------------------" << endl);
406  return 1;
407  }
408 
409  // Depending on the verbosity, output all the datafile initialization information as feedback for the user
411  {
412  Cout("------------------------------------------------- Datafile initialization -------------------------------------------------" << endl);
413  if (m_eventKindFlag) Cout(" --> Coincidence kind term is enabled" << endl);
414  else Cout(" --> No information about the kind of coincidences in the data" << endl);
415  if (m_normCorrectionFlag) Cout(" --> Normalization correction term is enabled" << endl);
416  else Cout(" --> No normalization correction terms in the data" << endl);
417  if (m_scatCorrectionFlag) Cout(" --> Scatter correction term is enabled" << endl);
418  else Cout(" --> No scatter correction terms in the data" << endl);
419  Cout(" --> Calibration factor value is: " << m_calibrationFactor << endl);
420  Cout(" --> Number of bins are equal to " << mp_nbOfBins[0] << "," << mp_nbOfBins[1] << " for transaxial,axial axis respectively" << endl);
421  if (mp_POIResolution[0]<0.) Cout(" --> No POI enabled on the radial axis" << endl);
422  else Cout(" --> POI resolution on the radial axis is: " << mp_POIResolution[0] << endl);
423  if (mp_POIResolution[1]<0.) Cout(" --> No POI enabled on the tangential axis" << endl);
424  else Cout(" --> POI resolution on the tangential axis is: " << mp_POIResolution[1] << endl);
425  if (mp_POIResolution[2]<0.) Cout(" --> No POI enabled on the axial axis" << endl);
426  else Cout(" --> POI resolution on the axial axis is: " << mp_POIResolution[2] << endl);
427  Cout("---------------------------------------------------------------------------------------------------------------------------" << endl);
428  }
429 
430  // End
431  return 0;
432 }
433 
434 // =====================================================================
435 // ---------------------------------------------------------------------
436 // ---------------------------------------------------------------------
437 // =====================================================================
438 
440 {
442  // Dynamic cast the vDataFile to a iDataFilePET
443  iDataFileSPECT* p_data_file = (dynamic_cast<iDataFileSPECT*>(ap_Datafile));
444  // Check isotope
445  if (m_isotope!=p_data_file->GetIsotope())
446  {
447  Cerr("***** iDataFileSPECT::CheckSpecificConsistencyWithAnotherDatafile() -> Isotopes are inconsistent !" << endl);
448  return 1;
449  }
450  // Check event kind flag
451  if (m_eventKindFlag!=p_data_file->GetEventKindFlag())
452  {
453  Cerr("***** iDataFileSPECT::CheckSpecificConsistencyWithAnotherDatafile() -> Event kind flags are inconsistent !" << endl);
454  return 1;
455  }
456  // Check normalization correction flag
457  if (m_normCorrectionFlag!=p_data_file->GetNormCorrectionFlag())
458  {
459  Cerr("***** iDataFileSPECT::CheckSpecificConsistencyWithAnotherDatafile() -> Normalization correction flags are inconsistent !" << endl);
460  return 1;
461  }
462  // Check scatter correction flag
463  if (m_scatCorrectionFlag!=p_data_file->GetScatCorrectionFlag())
464  {
465  Cerr("***** iDataFileSPECT::CheckSpecificConsistencyWithAnotherDatafile() -> Scatter correction flags are inconsistent !" << endl);
466  return 1;
467  }
468  // End
469  return 0;
470 }
471 
472 // =====================================================================
473 // ---------------------------------------------------------------------
474 // ---------------------------------------------------------------------
475 // =====================================================================
476 
478 {
480  // Check
481  if (m_nbOfProjections == 0)
482  {
483  Cerr("***** iDataFileSPECT::InitAngles() -> Number of projection angles not initialized !'" << endl);
484  return 1;
485  }
486  // Allocate
488  // Affect
489  for (uint16_t a=0 ; a<m_nbOfProjections ; a++) mp_angles[a] = ap_angles[a];
490  // End
491  return 0;
492 }
493 
494 // =====================================================================
495 // ---------------------------------------------------------------------
496 // ---------------------------------------------------------------------
497 // =====================================================================
498 
499 int iDataFileSPECT::InitCorToDetectorDistance(FLTNB* ap_CORtoDetectorDistance)
500 {
502  // Check
503  if (m_nbOfProjections == 0)
504  {
505  Cerr("***** iDataFileSPECT::InitAngles() -> Number of projection angles not initialized !'" << endl);
506  return 1;
507  }
508  // Allocate
510  // Affect
511  for (uint16_t a=0 ; a<m_nbOfProjections ; a++) mp_CORtoDetectorDistance[a] = ap_CORtoDetectorDistance[a];
512  // End
513  return 0;
514 }
515 
516 
517 
518 
519 
520 
521 
522 
523 
524 
525 
526 
527 
528 //PROJECTION SCRIPT FUNCTIONS
529 // =====================================================================
530 // ---------------------------------------------------------------------
531 // ---------------------------------------------------------------------
532 // =====================================================================
533 
534 /*
535  \fn PROJ_InitFile()
536  \brief Initialize the fstream objets for output writing as well as some other variables specific to the Projection script (Event-based correction flags, Estimated size of data file)
537  \todo warn the user a datafile with the same name will be erased (eventually add an option to disable the warning)
538  \return 0 if success, and positive value otherwise.
539 */
541 {
542  if(m_verbose >=3) Cout("iDataFileSPECT::PROJ_InitFile() ..." << endl);
543 
544  m_startTimeInSec = 0.; //Std initialization for projection
545  m_durationInSec = 1.; //Std initialization for projection
546  m_totalNbEvents = 0; //Std initialization for projection
547  m_calibrationFactor = 1.;
548  m_isotope = "unknown";
549  m_scatCorrectionFlag = false;
550  m_normCorrectionFlag = false;
551  mp_POIResolution[0] = -1.;
552  mp_POIResolution[1] = -1.;
553  mp_POIResolution[2] = -1.;
554 
555  // Instanciate a fstream datafile for each thread
556  m2p_dataFile = new fstream*[mp_ID->GetNbThreadsForProjection()];
557 
558  // Set name of the projection data header
559  sOutputManager* p_OutMgr;
560  p_OutMgr = sOutputManager::GetInstance();
561  string path_name = p_OutMgr->GetPathName();
562  string img_name = p_OutMgr->GetBaseName();
563  m_headerFileName = path_name.append(img_name).append("_CstrProj").append(".Cdh");
564 
565  for (int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
566  {
567  m_dataFileName = m_headerFileName.substr(0, m_headerFileName.find_last_of(".")).append(".Cdf"); // Generate datafile name from header file
568 
569  // Projeted data will be written in several files (corresponding to the number of thread) to be concatenated at the end of the projection process.
570  stringstream ss;
571  ss << th;
572 
573  string datafile_name = m_dataFileName;
574  datafile_name.append("_").append(ss.str());
575 
576  m2p_dataFile[th] = new fstream( datafile_name.c_str(), ios::binary | ios::out | ios::trunc);
577  }
578 
579  //remove content from the output data file, in case it already exists
580  //todo warn the user a datafile with the same name will be erased (eventually add an option to disable the warning)
581  ofstream output_file(m_dataFileName.c_str(), ios::out | ios::trunc);
582  output_file.close();
583 
584  if(m_verbose>=3) Cout("iDataFileSPECT::PROJ_InitFile()-> output datafile name :" << m_dataFileName << endl);
585 
586  return 0;
587 }
588 
589 
590 
591 
592 // =====================================================================
593 // ---------------------------------------------------------------------
594 // ---------------------------------------------------------------------
595 // =====================================================================
596 /*
597  \fn PROJ_WriteEvent(vEvent* ap_Event, int a_th)
598  \param ap_Event : event containing the data to write
599  \param a_th : index of the thread from which the function was called
600  \brief Write event according to the chosen type of data
601  \todo Depending of the RAM load FLAG, either write the data in *nbThreads* different files which will be concatenated at the end (current implementation),
602  or write data in buffers, to be flushed at the end of projection loop.
603  \todo Projection for list-mode
604  \return 0 if success, and positive value otherwise.
605 */
606 int iDataFileSPECT::PROJ_WriteEvent(vEvent* ap_Event, int a_th)
607 {
608  #ifdef CASTOR_VERBOSE
609  // Verbose
610  if(m_verbose>=4) Cout("iDataFileSPECT::PROJ_WriteEvent() ..."<< endl);
611  #endif
612 
613  if(m_dataMode == MODE_LIST)
614  {
615  // TODO should create as many vEvent as (int)fp.
616  if(PROJ_WriteListEvent((iEventListSPECT*)ap_Event, a_th))
617  {
618  Cerr("*****iDataFileSPECT::PROJ_WriteEvent() -> Error while trying to write projection datafile (list-mode)" << endl);
619  return 1;
620  }
621  }
622 
624  {
625  if(PROJ_WriteHistoEvent((iEventHistoSPECT*)ap_Event, a_th))
626  {
627  Cerr("*****iDataFileSPECT::PROJ_WriteEvent() -> Error while trying to write projection datafile (histogram)" << endl);
628  return 1;
629  }
630  }
631 
632  return 0;
633 }
634 
635 
636 // =====================================================================
637 // ---------------------------------------------------------------------
638 // ---------------------------------------------------------------------
639 // =====================================================================
640 /*
641  \fn PROJ_WriteHistoEvent()
642  \param ap_Event : event containing the data to write
643  \param a_th : index of the thread from which the function was called
644  \brief Write a SPECT histogram event
645  \return 0 if success, and positive value otherwise.
646 */
648 {
649  #ifdef CASTOR_VERBOSE
650  // Verbose
651  if(m_verbose>=4) Cout("iDataFileSPECT::PROJ_WriteHistoEvent() ..."<< endl);
652  #endif
653 
654  // Write sequentially each field of the event according to the type of the event.
655  m2p_dataFile[a_th]->clear();
656 
657  uint32_t time = ap_Event->GetTimeInMs();
658  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&time), sizeof(uint32_t));
659 
660  FLTNB event_value = ap_Event->GetEventValue(0);
661  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&event_value), sizeof(FLTNB));
662 
664  {
665  FLTNB scat_rate = ap_Event->GetEventScatRate();
666  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&scat_rate), sizeof(FLTNB));
667  }
668 
670  {
671  FLTNB norm_corr_factor = ap_Event->GetNormFactor();
672  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&norm_corr_factor), sizeof(FLTNB));
673  }
674 
675  uint32_t id1 = ap_Event->GetID1(0);
676  uint32_t id2 = ap_Event->GetID2(0);
677  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id1), sizeof(uint32_t));
678  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id2), sizeof(uint32_t));
679 
680  return 0;
681 }
682 
683 
684 // =====================================================================
685 // ---------------------------------------------------------------------
686 // ---------------------------------------------------------------------
687 // =====================================================================
688 /*
689  \fn PROJ_WriteListEvent()
690  \param ap_Event : event containing the data to write
691  \param a_th : index of the thread from which the function was called
692  \brief Write a SPECT list-mode event
693  \return 0 if success, and positive value otherwise.
694 */
696 {
697  #ifdef CASTOR_VERBOSE
698  // Verbose
699  if(m_verbose>=4) Cout("iDataFileSPECT::PROJ_WriteListEvent() ..."<< endl);
700  #endif
701 
702  // Write sequentially each field of the event according to the type of the event.
703  m2p_dataFile[a_th]->clear();
704 
705  uint32_t time = ap_Event->GetTimeInMs();
706  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&time), sizeof(uint32_t));
707 
708  if(m_eventKindFlag)
709  {
710  uint8_t event_kind = ap_Event->GetKind();
711  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&event_kind), sizeof(uint8_t));
712  }
713 
715  {
716  FLTNB scat_rate = ap_Event->GetEventScatRate();
717  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&scat_rate), sizeof(FLTNB));
718  }
719 
721  {
722  FLTNB norm_corr_factor = ap_Event->GetNormFactor();
723  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&norm_corr_factor), sizeof(FLTNB));
724  }
725 
726  if(mp_POIResolution[0]>0)
727  {
728  FLTNB POI = ap_Event->GetPOI(0);
729  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI), sizeof(FLTNB));
730  }
731 
732  if(mp_POIResolution[1]>0)
733  {
734  FLTNB POI = ap_Event->GetPOI(1);
735  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI), sizeof(FLTNB));
736  }
737 
738  if(mp_POIResolution[2]>0)
739  {
740  FLTNB POI = ap_Event->GetPOI(2);
741  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI), sizeof(FLTNB));
742  }
743 
744  uint32_t id1 = ap_Event->GetID1(0);
745  uint32_t id2 = ap_Event->GetID2(0);
746  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id1), sizeof(uint32_t));
747  m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id2), sizeof(uint32_t));
748 
749  return 0;
750 }
751 
752 
753 
754 
755 
756 // =====================================================================
757 // ---------------------------------------------------------------------
758 // ---------------------------------------------------------------------
759 // =====================================================================
760 /*
761  \fn PROJ_WriteHeader()
762  \brief Generate a header file according to the projection and data output informations.
763  Used by Projection algorithm.
764  \return 0 if success, and positive value otherwise.
765 */
767 {
768  // Verbose
769  if(m_verbose>=3) Cout("iDataFileSPECT::PROJ_WriteHeader() ..."<< endl);
770 
771  fstream headerFile;
772  stringstream ss;
773 
774  headerFile.open(m_headerFileName.c_str(), ios::out);
775 
776  headerFile << "Data filename:" << " " << GetFileFromPath(m_dataFileName).c_str() << endl;
777  headerFile << "Number of events:" << " " << m_totalNbEvents << endl;
778 
779  //- Flag: list-mode or histogram mode
780  headerFile << "Data mode:" << " " << m_dataMode << endl;
781  // Flag: PET, SPECT or TRANSMISSION
782  headerFile << "Data type: " << " " << "SPECT" << endl;
783 
784  headerFile << "Start time (s):" << " " << m_startTimeInSec << endl;
785 
786  headerFile << "Duration (s):" << " " << m_durationInSec << endl;
787 
788  sScannerManager* p_scannermanager;
789  p_scannermanager = sScannerManager::GetInstance();
790 
791  headerFile << "Scanner name:" << " " << p_scannermanager->GetScannerName() << endl;
792 
793 
794  if(mp_nbOfBins[0] != 0 && mp_nbOfBins[1] != 0)
795  headerFile << "Number of bins:" << " " << mp_nbOfBins[0] << "," << mp_nbOfBins[1] << endl;
796 
797  headerFile << "Number of projections:" << " " << m_nbOfProjections << endl;
798 
799  headerFile << "Projection angles:" << " ";
800 
801  headerFile << mp_angles[0];
802  for(int a=1 ; a<m_nbOfProjections ; a++)
803  headerFile << ", " << mp_angles[a];
804 
805  headerFile << endl;
806  if(m_nbHeads>1)
807  {
808  headerFile << "Global distance camera surface to COR:" << " " << mp_CORtoDetectorDistance[0];
809  for(int h=1 ; h<m_nbHeads ; h++) headerFile << "," << mp_CORtoDetectorDistance[h] << endl;
810  headerFile << endl;
811  }
812 
813  else if(mp_CORtoDetectorDistance[0] > 0)
814  headerFile << "Global distance camera surface to COR:" << " " << mp_CORtoDetectorDistance[0] << endl;
815 
816  // Optional fields
817  headerFile << "Calibration factor:" << " " << m_calibrationFactor << endl;
818  headerFile << "Isotope:" << " " << m_isotope << endl;
819  headerFile << "DOI capability:" << " " << mp_POIResolution[0] << "," << mp_POIResolution[1] << "," << mp_POIResolution[2] << endl;
820  headerFile << "Normalization correction flag:" << " " << m_normCorrectionFlag << endl;
821  headerFile << "Scatter correction flag:" << " " << m_scatCorrectionFlag << endl;
822  string rot_direction = (m_headRotDirection == GEO_ROT_CCW) ? "CCW" : "CW";
823  headerFile << "Head rotation direction:" << " " << rot_direction << endl;
824 
825  headerFile.close();
826 
827  return 0;
828 }
829 
830 
831 
832 // =====================================================================
833 // ---------------------------------------------------------------------
834 // ---------------------------------------------------------------------
835 // =====================================================================
836 /*
837  \fn PROJ_GetScannerSpecificParameters()
838  \brief Get SPECT specific parameters for projections from the scanner object, through the scannerManager.
839  \return 0 if success, positive value otherwise
840 */
842 {
843  // Verbose
844  if(m_verbose>=3) Cout("iDataFileSPECT::PROJ_GetScannerSpecificParameters() ..."<< endl);
845 
846  sScannerManager* p_scannermanager;
847  p_scannermanager = sScannerManager::GetInstance();
848 
849  // Create pointers dedicated to recover the addresses of the member variables of the scanner object
850  FLTNB* p_angles = NULL;
851  FLTNB* p_CORtoDetectorDistance = NULL;
852  FLTNB p_pixSizeXY[2] ; // not used here
853 
854  // Get pointers to SPECT specific parameters in scanner
855  if(p_scannermanager->GetSPECTSpecificParameters(&m_nbOfProjections, &m_nbHeads, mp_nbOfBins, p_pixSizeXY, p_angles, p_CORtoDetectorDistance, &m_headRotDirection) )
856  {
857  Cerr("*****iDataFileSPECT::PROJ_GetScannerSpecificParameters() -> An error occurred while trying to get SPECT geometric parameters from the scanner object !" << endl);
858  return 1;
859  }
860 
861  // In projection, mp_CORtoDetectorDistance is allocated according to the number of heads, and not the number of projections
862  // (Projection does not currently allow to set a radius specific to the projection angles)
864 
865  // Retrieve SPECT distance between the detector and center of rotation
866  for(int h=0 ; h<m_nbHeads ; h++)
867  mp_CORtoDetectorDistance[h] = p_CORtoDetectorDistance[0];
868 
869  // Retrieve projection angles
871 
872  for(int a=0 ; a<m_nbOfProjections ; a++)
873  mp_angles[a] = p_angles[a];
874 
875  return 0;
876 }
This class is designed to be a mother virtual class for Datafile.
Definition: vDataFile.hh:67
int SetSPECTIsotope(int a_bed, const string &a_isotope)
Set the SPECT 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
#define MODE_HISTOGRAM
Definition: vDataFile.hh:36
bool GetNormCorrectionFlag()
Simply return m_normCorrectionFlag.
int64_t m_sizeEvent
Definition: vDataFile.hh:528
bool mp_POIDirectionFlag[3]
Definition: vDataFile.hh:534
string m_dataFileName
Definition: vDataFile.hh:520
int InitAngles(FLTNB *ap_angles)
allocate memory for the mp_angles variable using m_nbProjections and initialize the projection angles...
int CheckSpecificConsistencyWithAnotherDatafile(vDataFile *ap_Datafile)
Check consistency between 'this' and the provided datafile, for specific characteristics.
#define MODE_LIST
Definition: vDataFile.hh:34
int ReadSpecificInfoInHeader(bool a_affectQuantificationFlag)
Read through the header file and recover specific SPECT information.
#define FLTNB
Definition: gVariables.hh:55
#define MODE_NORMALIZATION
Definition: vDataFile.hh:38
bool GetEventKindFlag()
Simply return m_eventKindFlag.
iDataFileSPECT()
iDataFileSPECT constructor. Initialize the member variables to their default values.
uint32_t GetID2(int a_line)
Definition: vEvent.hh:88
#define VERBOSE_DETAIL
#define GEO_ROT_CCW
Definition: vScanner.hh:30
FLTNB GetEventValue(int a_bin)
FLTNB m_durationInSec
Definition: vDataFile.hh:525
Inherit from iEventSPECT. Class for SPECT histogram mode events.
int PROJ_WriteListEvent(iEventListSPECT *ap_Event, int a_th)
Write a SPECT list-mode event.
string m_headerFileName
Definition: vDataFile.hh:519
int m_dataMode
Definition: vDataFile.hh:522
static sOutputManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
#define TYPE_SPECT
Definition: vDataFile.hh:53
FLTNB m_startTimeInSec
Definition: vDataFile.hh:524
int GetSPECTSpecificParameters(uint16_t *ap_nbOfProjections, uint16_t *ap_nbHeads, uint16_t *ap_nbOfBins, FLTNB *ap_pixSizeXY, FLTNB *&ap_angles, FLTNB *&ap_CORtoDetectorDistance, int *ap_headRotDirection)
Transfer geometric information recovered from the datafile to the scanner object. ...
Declaration of class iDataFileSPECT.
string GetFileFromPath(const string &a_pathToFile)
Simply return the file from a path string passed in parameter.
Definition: gOptions.cc:1119
~iDataFileSPECT()
iDataFileSPECT destructor.
uint16_t m_nbOfProjections
bool GetIgnoreNormCorrectionFlag()
Get the boolean that says if the normalization correction is ignored or not.
#define FLTNBDATA
Definition: gVariables.hh:59
int PROJ_WriteEvent(vEvent *ap_Event, int a_th)
Write event according to the chosen type of data.
int PROJ_GetScannerSpecificParameters()
Get SPECT specific parameters for projections from the scanner object, through the scannerManager...
#define Cerr(MESSAGE)
const string & GetPathName()
int ComputeSizeEvent()
Computation of the size of each event according to the mandatory/optional correction fields...
#define VERBOSE_DEBUG_LIGHT
bool m_ignorePOIFlag
Definition: vDataFile.hh:533
Singleton class that manages output writing on disk (images, sinograms, etc). It also manages loggi...
int CheckSpecificParameters()
Check parameters specific to SPECT data.
int CheckFileSizeConsistency()
This function is implemented in child classes Check if file size is consistent. ...
int ReadDataASCIIFile(const string &a_file, const string &a_keyword, T *ap_return, int a_nbElts, bool a_mandatoryFlag)
Look for "a_nbElts" elts in the "a_file" file matching the "a_keyword" string passed as parameter a...
Definition: gOptions.cc:111
Singleton class that Instantiate and initialize the scanner object.
int m_dataType
Definition: vDataFile.hh:523
int InitCorToDetectorDistance(FLTNB *ap_CORtoDetectorDistance)
allocate memory for the ap_CORtoDetectorDistance variable using m_nbProjections, and initialize the p...
oImageDimensionsAndQuantification * mp_ID
Definition: vDataFile.hh:514
fstream ** m2p_dataFile
Definition: vDataFile.hh:518
Inherit from vDataFile. Class that manages the reading of a SPECT input file (header + data)...
#define VERBOSE_NORMAL
int m_bedIndex
Definition: vDataFile.hh:527
vEvent * GetEventFromBuffer(char *ap_buffer, int a_th)
Read an event from the position pointed by 'ap_buffer', parse the generic or modality-specific inform...
FLTNB GetNormFactor()
Definition: iEventSPECT.hh:60
FLTNB mp_POIResolution[3]
Definition: vDataFile.hh:535
int PROJ_InitFile()
Initialize the fstream objets for output writing as well as some other variables specific to the Proj...
bool m_ignoreNormCorrectionFlag
FLTNB * mp_CORtoDetectorDistance
const string & GetBaseName()
void SetTimeInMs(uint32_t a_value)
Set the timestamp of the Event.
Definition: vEvent.hh:119
int PROJ_WriteHistoEvent(iEventHistoSPECT *ap_Event, int a_th)
Write a SPECT histogram event.
Mother class for the Event objects.
Definition: vEvent.hh:23
vEvent ** m2p_BufferEvent
Definition: vDataFile.hh:538
uint32_t GetID1(int a_line)
Definition: vEvent.hh:81
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.
#define DEBUG_VERBOSE(IGNORED1, IGNORED2)
#define Cout(MESSAGE)
FLTNB m_calibrationFactor
Definition: vDataFile.hh:526
int PROJ_WriteHeader()
Generate a header file according to the projection and data output informations. Used by Projection...
int PrepareDataFile()
Store different kind of information inside arrays (data relative to specific correction as well as ba...
bool m_ignoreScatCorrectionFlag
int m_verbose
Definition: vDataFile.hh:515
uint16_t mp_nbOfBins[2]
uint32_t GetTimeInMs()
Definition: vEvent.hh:68
int64_t m_totalNbEvents
Definition: vDataFile.hh:521
#define GEO_ROT_CW
Definition: vScanner.hh:28
FLTNB GetEventScatRate()
Definition: iEventSPECT.hh:66
bool GetScatCorrectionFlag()
Simply return m_scatCorrectionFlag.
Inherit from iEventSPECT. Class for SPECT list-mode events.