CASToR  1.0
Tomographic Reconstruction (PET/SPECT)
iDataFilePET.cc
Go to the documentation of this file.
00001 
00002 /*
00003   Implementation of class iDataFilePET
00004 
00005   - separators: X
00006   - doxygen: X
00007   - default initialization: X
00008   - CASTOR_DEBUG: none
00009   - CASTOR_VERBOSE: X
00010 */
00011 
00020 #include "iDataFilePET.hh"
00021 
00022 // =====================================================================
00023 // ---------------------------------------------------------------------
00024 // ---------------------------------------------------------------------
00025 // =====================================================================
00026 /*
00027   \brief iDataFilePET constructor. 
00028          Initialize the member variables to their default values.
00029 */
00030 iDataFilePET::iDataFilePET() : vDataFile() 
00031 {
00032   // Read optional fields in the header
00033   m_dataType = TYPE_PET;
00034   m_maxNumberOfLinesPerEvent = 1;
00035   m_maxRingDiff = -1;
00036   m_isotope = "unknown";
00037   m_resolutionTOF = -1.;
00038   m_nbBinsTOF = -1;
00039   m_binSizeTOF = -1.;
00040   m_eventKindFlag = false;
00041   m_atnCorrectionFlag = false;
00042   m_ignoreAttnCorrectionFlag = false;
00043   m_normCorrectionFlag = false;
00044   m_ignoreNormCorrectionFlag = false;
00045   m_scatCorrectionFlag = false;
00046   m_ignoreScatCorrectionFlag = false;
00047   m_randCorrectionFlag = false;
00048   m_ignoreRandCorrectionFlag = false;
00049   m_TOFInfoFlag = false;
00050   m_ignoreTOFFlag = false;
00051 }
00052 
00053 
00054 // =====================================================================
00055 // ---------------------------------------------------------------------
00056 // ---------------------------------------------------------------------
00057 // =====================================================================
00058 /*
00059   \brief iDataFilePET destructor. 
00060 */
00061 iDataFilePET::~iDataFilePET() {}
00062 
00063 
00064 
00065 // =====================================================================
00066 // ---------------------------------------------------------------------
00067 // ---------------------------------------------------------------------
00068 // =====================================================================
00069 /*
00070   \fn ReadSpecificInfoInHeader()
00071   \brief Read through the header file and gather specific PET information. 
00072   \return 0 is success, positive value otherwise
00073 */
00074 int iDataFilePET::ReadSpecificInfoInHeader()
00075 { 
00076   if(m_verbose >=3) Cout("iDataFilePET::ReadSpecificInfoInHeader()... " << endl);
00077   
00078   // Read optional fields in the header, check if errors (issue during data reading/conversion (==1) )
00079   if (ReadDataASCIIFile(m_headerFileName, "Maximum number of lines per event", &m_maxNumberOfLinesPerEvent, 1, KEYWORD_OPTIONAL)==1 ||
00080       ReadDataASCIIFile(m_headerFileName, "Maximum ring difference", &m_maxRingDiff, 1, KEYWORD_OPTIONAL)==1 ||
00081       ReadDataASCIIFile(m_headerFileName, "TOF resolution", &m_resolutionTOF, 1, KEYWORD_OPTIONAL)==1 ||
00082       ReadDataASCIIFile(m_headerFileName, "TOF correction flag", &m_TOFInfoFlag, 1, KEYWORD_OPTIONAL)==1 ||
00083       ReadDataASCIIFile(m_headerFileName, "Histo TOF bin", &m_nbBinsTOF, 1, KEYWORD_OPTIONAL)==1 ||
00084       ReadDataASCIIFile(m_headerFileName, "Histo TOF size", &m_binSizeTOF, 1, KEYWORD_OPTIONAL)==1 ||
00085       ReadDataASCIIFile(m_headerFileName, "Coincidence kind flag", &m_eventKindFlag, 1, KEYWORD_OPTIONAL)==1 ||
00086       ReadDataASCIIFile(m_headerFileName, "Attenuation correction flag", &m_atnCorrectionFlag, 1, KEYWORD_OPTIONAL)==1 ||
00087       ReadDataASCIIFile(m_headerFileName, "Normalization correction flag", &m_normCorrectionFlag, 1, KEYWORD_OPTIONAL)==1 ||
00088       ReadDataASCIIFile(m_headerFileName, "Scatter correction flag", &m_scatCorrectionFlag, 1, KEYWORD_OPTIONAL)==1 ||
00089       ReadDataASCIIFile(m_headerFileName, "Random correction flag", &m_randCorrectionFlag, 1, KEYWORD_OPTIONAL)==1 ||
00090       ReadDataASCIIFile(m_headerFileName, "Isotope", &m_isotope, 1, KEYWORD_OPTIONAL)==1 )
00091   {
00092     Cerr("***** iDataFilePET::ReadSpecificInfoInHeader() -> Error while reading optional field in the header data file '" << endl);
00093     return 1;
00094   }
00095 
00096   // Give the PET isotope to the oImageDimensionsAndQuantification that manages the quantification factors
00097   if (m_dataMode!=MODE_NORMALIZATION && mp_ID->SetPETIsotope(m_bedIndex, m_isotope))
00098   {
00099     Cerr("***** iDataFilePET::ReadSpecificInfoInHeader() -> A problem occured while setting the isotope to oImageDimensionsAndQuantification !" << endl);
00100     return 1;
00101   }
00102 
00103   return 0;
00104 }
00105 
00106 
00107 // =====================================================================
00108 // ---------------------------------------------------------------------
00109 // ---------------------------------------------------------------------
00110 // =====================================================================
00111 /*
00112   \fn ComputeSizeEvent()
00113   \brief Computation of the size of each event according to the mandatory/optional correction fields
00114   \todo Additionnal optionnal fields (physiological info (Phy field) & energy info)
00115   \return 0 is success, positive value otherwise
00116 */
00117 int iDataFilePET::ComputeSizeEvent()
00118 {
00119   // Verbose
00120   if (m_verbose>=3) Cout("iDataFilePET::ComputeSizeEvent() ..." << endl);
00121 
00122   // For MODE_LIST events
00123   if (m_dataMode == MODE_LIST) 
00124   {
00125     // Size of the mandatory element in a list-mode event:
00126     
00127     // Time + max_nb_lines*2*crystalID
00128     m_sizeEvent = sizeof(uint32_t) + m_maxNumberOfLinesPerEvent*2*sizeof(uint32_t);
00129     
00130     // Number of lines
00131     if (m_maxNumberOfLinesPerEvent>1) m_sizeEvent += sizeof(uint16_t);
00132 
00133     // Optional flags
00134     if (m_eventKindFlag) m_sizeEvent += sizeof(uint8_t);
00135     if (m_atnCorrectionFlag) m_sizeEvent += sizeof(FLTNBDATA);
00136     if (m_scatCorrectionFlag) m_sizeEvent += sizeof(FLTNBDATA);
00137     if (m_randCorrectionFlag) m_sizeEvent += sizeof(FLTNBDATA);
00138     if (m_normCorrectionFlag) m_sizeEvent += sizeof(FLTNBDATA);
00139     if (m_TOFInfoFlag) m_sizeEvent += sizeof(uint32_t);
00140     
00141     // POI availability in each direction
00142     for (int i=0 ; i<3; i++) if (mp_POIDirectionFlag[i]) m_sizeEvent += 2*sizeof(FLTNBDATA);
00143   }
00144   // For MODE_HISTOGRAM events
00145   else if (m_dataMode == MODE_HISTOGRAM)
00146   {
00147     // Size of the mandatory element in a histo event:
00148     
00149     // Time + nbBinsTOF*event_value + max_nb_line*2*crystalID
00150     m_sizeEvent = sizeof(uint32_t) + m_nbBinsTOF*sizeof(FLTNBDATA) + m_maxNumberOfLinesPerEvent*2*sizeof(uint32_t);
00151     
00152     // Number of lines
00153     if (m_maxNumberOfLinesPerEvent>1) m_sizeEvent += sizeof(uint16_t);
00154     
00155     // Optional flags
00156     if (m_atnCorrectionFlag) m_sizeEvent += sizeof(FLTNBDATA);
00157     if (m_randCorrectionFlag) m_sizeEvent += sizeof(FLTNBDATA);
00158     if (m_normCorrectionFlag) m_sizeEvent += sizeof(FLTNBDATA);
00159     if (m_scatCorrectionFlag) m_sizeEvent += m_nbBinsTOF*sizeof(FLTNBDATA);
00160   }
00161   // For MODE_NORMALIZATION events
00162   else if (m_dataMode == MODE_NORMALIZATION)
00163   {
00164     // max_nb_lines*2*crystalID
00165     m_sizeEvent = m_maxNumberOfLinesPerEvent*2*sizeof(uint32_t);
00166     // Number of lines
00167     if (m_maxNumberOfLinesPerEvent>1) m_sizeEvent += sizeof(uint16_t);
00168     // Optional flag for normalization
00169     if (m_normCorrectionFlag) m_sizeEvent += sizeof(FLTNBDATA);
00170     // Optional flag for attenuation
00171     if (m_atnCorrectionFlag) m_sizeEvent += sizeof(FLTNBDATA);
00172   }
00173   // Unknown event type
00174   else
00175   {
00176     Cerr("***** iDataFilePET::ComputeSizeEvent() -> Unknown event mode !" << endl);
00177     return 1;
00178   }
00179 
00180   if(m_verbose >=3) Cout("iDataFilePET::ComputeSizeEvent() -> Event size = " << m_sizeEvent << " bytes" << endl);
00181 
00182   if (m_sizeEvent <= 0) 
00183   {
00184     Cerr("***** iDataFilePET::ComputeSizeEvent() -> Error, the Event size in bytes should be >= 0 !" << endl;);
00185     return 1;
00186   }
00187 
00188   return 0;
00189 }
00190 
00191 // =====================================================================
00192 // ---------------------------------------------------------------------
00193 // ---------------------------------------------------------------------
00194 // =====================================================================
00195 /*
00196   \fn PrepareDataFile()
00197   \brief Store different kind of information inside arrays (data relative to specific correction as well as basic raw data for the case data is loaded in RAM)
00198          Use the flag provided by the user to determine how the data has to be sorted (preloaded or read on the fly)
00199   \return 0 is success, positive value otherwise
00200 */
00201 int iDataFilePET::PrepareDataFile()
00202 {
00203   // Verbose
00204   if (m_verbose>=2)
00205   {
00206     if (m_dataMode==MODE_HISTOGRAM) Cout("iDataFilePET::PrepareDataFile() -> Build histogram events" << endl);
00207     else if (m_dataMode==MODE_LIST) Cout("iDataFilePET::PrepareDataFile() -> Build listmode events" << endl);
00208     else if (m_dataMode==MODE_NORMALIZATION) Cout("iDataFilePET::PrepareDataFile() -> Build normalization events" << endl);
00209   }
00210 
00211   // ==============================================================================
00212   // Allocate event buffers (one for each thread)
00213   // ==============================================================================
00214   if (m_verbose>=3) Cout("  --> Allocating an event buffer for each thread" << endl);
00215   // Instanciation of the event buffer according to the data type
00216   m2p_BufferEvent = new vEvent*[mp_ID->GetNbThreadsForProjection()];
00217   
00218   // Allocate the events per each thread
00219   for (int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
00220   {
00221     
00222     // For MODE_LIST events
00223     if (m_dataMode == MODE_LIST) 
00224     {
00225       m2p_BufferEvent[th] = new iEventListPET();
00226     }
00227     // For MODE_HISTOGRAM events
00228     else if (m_dataMode == MODE_HISTOGRAM)
00229     {
00230       m2p_BufferEvent[th] = new iEventHistoPET();
00231       // If we ignore the TOF information, then the event buffer will have only one TOF bin;
00232       // the TOF contributions will be sum up when reading the event.
00233       if (m_ignoreTOFFlag) ((iEventHistoPET*)m2p_BufferEvent[th])->SetEventNbTOFBins(1);
00234       else ((iEventHistoPET*)m2p_BufferEvent[th])->SetEventNbTOFBins(m_nbBinsTOF);
00235     }
00236     // For MODE_NORMALIZATION events
00237     else if (m_dataMode == MODE_NORMALIZATION)
00238     {
00239       m2p_BufferEvent[th] = new iEventNorm();
00240     }
00241 
00242     // Set the maximum number of lines per event
00243     m2p_BufferEvent[th]->SetNbLines(m_maxNumberOfLinesPerEvent);
00244     
00245     // Allocate crystal IDs
00246     if (m2p_BufferEvent[th]->AllocateID())
00247     {
00248       Cerr("*****iDataFilePET::PrepareDataFile() -> Error while trying to allocate memory for the Event object for thread " << th << " !" << endl;);
00249       return 1;
00250     }
00251   }
00252 
00253 
00254   // ==============================================================================
00255   // Deal with specific corrections
00256   // ==============================================================================
00257 
00258   // In case of attenuation correction flag, see if we ignore this correction
00259   if (m_atnCorrectionFlag)
00260   {
00261     // Affect the ignored flag from the ignored corrections list processed by the oImageDimensionsAndQuantification
00262     m_ignoreAttnCorrectionFlag = mp_ID->GetIgnoreAttnCorrectionFlag();
00263     // Verbose
00264     if (m_verbose>=2)
00265     {
00266       if (m_ignoreAttnCorrectionFlag) Cout("  --> Ignore attenuation correction" << endl);
00267       else Cout("  --> Correct for attenuation" << endl);
00268     }
00269   }
00270   // In case of normalization correction flag, see if we ignore this correction
00271   if (m_normCorrectionFlag)
00272   {
00273     // Affect the ignored flag from the ignored corrections list processed by the oImageDimensionsAndQuantification
00274     m_ignoreNormCorrectionFlag = mp_ID->GetIgnoreNormCorrectionFlag();
00275     // Verbose
00276     if (m_verbose>=2)
00277     {
00278       if (m_ignoreNormCorrectionFlag) Cout("  --> Ignore normalization correction" << endl);
00279       else Cout("  --> Correct for normalization" << endl);
00280     }
00281   }
00282   // In case of scatter correction flag, see if we ignore this correction
00283   if (m_scatCorrectionFlag)
00284   {
00285     // Affect the ignored flag from the ignored corrections list processed by the oImageDimensionsAndQuantification
00286     m_ignoreScatCorrectionFlag = mp_ID->GetIgnoreScatCorrectionFlag();
00287     // Verbose
00288     if (m_verbose>=2)
00289     {
00290       if (m_ignoreScatCorrectionFlag) Cout("  --> Ignore scatter correction" << endl);
00291       else Cout("  --> Correct for scatter events" << endl);
00292     }
00293   }
00294   // In case of random correction flag, see if we ignore this correction
00295   if (m_randCorrectionFlag)
00296   {
00297     // Affect the ignored flag from the ignored corrections list processed by the oImageDimensionsAndQuantification
00298     m_ignoreRandCorrectionFlag = mp_ID->GetIgnoreRandCorrectionFlag();
00299     // Verbose
00300     if (m_verbose>=2)
00301     {
00302       if (m_ignoreRandCorrectionFlag) Cout("  --> Ignore random correction" << endl);
00303       else Cout("  --> Correct for random events" << endl);
00304     }
00305   }
00306 
00307   // Normal end
00308   return 0;
00309 }
00310 // =====================================================================
00311 // ---------------------------------------------------------------------
00312 // ---------------------------------------------------------------------
00313 // =====================================================================
00314 /*
00315   \fn GetEventFromBuffer(char* ap_buffer, int a_th)
00316   \param ap_buffer : address pointing to the event to recover
00317   \param a_th : index of the thread from which the function was called
00318   \brief Read an event from the position pointed by 'ap_buffer', parse the generic or modality-specific information, and store them in the (multithreaded) 'm2p_BufferEvent' object
00319   \return the thread-specific  'm2p_BufferEvent' object containing the modality-specific information for the event
00320 */
00321 vEvent* iDataFilePET::GetEventFromBuffer(char* ap_buffer, int a_th)
00322 {
00323   #ifdef CASTOR_VERBOSE
00324   // Verbose
00325   if(m_verbose>=4) Cout("iDataFilePET::GetEventFromBuffer() ..." << endl);
00326   #endif
00327 
00328   // Work on a copy of the input pointer
00329   char* file_position = ap_buffer;
00330 
00331   // For MODE_LIST PET data
00332   if (m_dataMode == MODE_LIST)
00333   {
00334     // Cast the event pointer
00335     iEventListPET* event = (dynamic_cast<iEventListPET*>(m2p_BufferEvent[a_th]));
00336     // Mandatory time field: [uint32_t (time)]
00337     event->SetTimeInMs(*reinterpret_cast<uint32_t*>(file_position)); 
00338     file_position += sizeof(uint32_t);
00339     // Optional attenuation correction field: [FLTNBDATA (attnCorrectionFactor)]
00340     if (m_atnCorrectionFlag)
00341     {
00342       if (!m_ignoreAttnCorrectionFlag) event->SetAttenuationCorrectionFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
00343       file_position += sizeof(FLTNBDATA);
00344     }
00345     // Optional kind: [uint8_t kind]
00346     if (m_eventKindFlag)
00347     {
00348       event->SetKind(*reinterpret_cast<uint8_t*>(file_position));
00349       file_position += sizeof(uint8_t);
00350     }
00351     // Optional scatter correction field: [FLTNBDATA (scatter)]
00352     if (m_scatCorrectionFlag)
00353     {
00354       if (!m_ignoreScatCorrectionFlag) event->SetScatterRate(0, *reinterpret_cast<FLTNBDATA*>(file_position)); 
00355       file_position += sizeof(FLTNBDATA);
00356     }
00357     // Optional random correction field: [FLTNBDATA (random)]
00358     if (m_randCorrectionFlag)
00359     {
00360       if (!m_ignoreRandCorrectionFlag) event->SetRandomRate(*reinterpret_cast<FLTNBDATA*>(file_position)); 
00361       file_position += sizeof(FLTNBDATA);
00362     }
00363     // Optional normalization correction field: [FLTNBDATA (norm)]
00364     if (m_normCorrectionFlag)
00365     {
00366       if (!m_ignoreNormCorrectionFlag) event->SetNormalizationFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
00367       file_position += sizeof(FLTNBDATA);
00368     }
00369     // Optional TOF correction field: [uint32_t (TOF)]
00370     if (m_TOFInfoFlag)
00371     {
00372       if (!m_ignoreTOFFlag) event->SetTOFMeasurement(*reinterpret_cast<uint32_t*>(file_position)); 
00373       file_position += sizeof(uint32_t);
00374     }
00375     // Optional POI correction fields: [FLTNBDATA (POI1[3])] [FLTNBDATA (POI2[3])]
00376     for (int i=0; i<3; i++)
00377     {
00378       if (mp_POIDirectionFlag[i])
00379       {
00380         if (!m_ignorePOIFlag) event->SetPOI1(i,*reinterpret_cast<FLTNBDATA*>(file_position)); 
00381         file_position += sizeof(FLTNBDATA);
00382         if (!m_ignorePOIFlag) event->SetPOI2(i,*reinterpret_cast<FLTNBDATA*>(file_position)); 
00383         file_position += sizeof(FLTNBDATA);
00384       }
00385     }
00386     // Mandatory nb contributing LORs if m_maxNumberOfLinesPerEvent>1: [uint16_t nbLines]
00387     if (m_maxNumberOfLinesPerEvent>1)
00388     {
00389       event->SetNbLines(*reinterpret_cast<uint16_t*>(file_position));
00390       file_position += sizeof(uint16_t);
00391     }
00392     // Mandatory crystal IDs: [uint32_t (ID1)] [uint32_t (ID2)]
00393     for (int i=0 ; i<event->GetNbLines() ; i++)
00394     {
00395       event->SetID1(i, *reinterpret_cast<uint32_t*>(file_position)); 
00396       file_position += sizeof(uint32_t);
00397       event->SetID2(i, *reinterpret_cast<uint32_t*>(file_position)); 
00398       file_position += sizeof(uint32_t);
00399     }
00400   }
00401 
00402   // For MODE_HISTOGRAM PET data
00403   else if (m_dataMode == MODE_HISTOGRAM) 
00404   {
00405     // Cast the event pointer
00406     iEventHistoPET* event = (dynamic_cast<iEventHistoPET*>(m2p_BufferEvent[a_th]));
00407     // Mandatory time field: [uint32_t (time)]
00408     event->SetTimeInMs(*reinterpret_cast<uint32_t*>(file_position)); 
00409     file_position += sizeof(uint32_t);
00410     // Optional attenuation correction field: [FLTNBDATA (attnCorrectionFactor)]
00411     if (m_atnCorrectionFlag)
00412     {
00413       if (!m_ignoreAttnCorrectionFlag) event->SetAttenuationCorrectionFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
00414       file_position += sizeof(FLTNBDATA);
00415     }
00416 
00417     // Optional random correction field: [FLTNBDATA (random)]
00418     if (m_randCorrectionFlag)
00419     {
00420       if (!m_ignoreRandCorrectionFlag) event->SetRandomRate(*reinterpret_cast<FLTNBDATA*>(file_position));
00421       file_position += sizeof(FLTNBDATA);
00422     }
00423 
00424     // Optional normalization correction field: [FLTNBDATA (norm)]
00425     if (m_normCorrectionFlag)
00426     {
00427       if (!m_ignoreNormCorrectionFlag) event->SetNormalizationFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
00428       file_position += sizeof(FLTNBDATA);
00429     }
00430     // If we ignore the TOF correction, then we have to sum up the bins' contributions
00431     if (m_ignoreTOFFlag)
00432     {
00433       // Compute the total of event values and scatter rates
00434       FLTNBDATA total_event_value = 0.;
00435       FLTNBDATA total_scatter_rate = 0.;
00436       for (int tb=0 ; tb<m_nbBinsTOF ; tb++)
00437       {
00438         // Mandatory bin value: [FLTNBDATA bin value]
00439         total_event_value += *reinterpret_cast<FLTNBDATA*>(file_position);
00440         file_position += sizeof(FLTNBDATA);
00441         // Optional scatter correction field: [FLTNBDATA (scatter)]
00442         if (m_scatCorrectionFlag)
00443         {
00444           total_scatter_rate += *reinterpret_cast<FLTNBDATA*>(file_position);
00445           file_position += sizeof(FLTNBDATA);
00446         }
00447       }
00448       // Affect the total to the event
00449       event->SetEventValue(0,total_event_value);
00450       if (!m_ignoreScatCorrectionFlag) event->SetScatterRate(0,total_scatter_rate);
00451     }
00452     // Otherwise we set all different TOF bin contributions
00453     else
00454     {
00455       for (int tb=0 ; tb<m_nbBinsTOF ; tb++)
00456       {
00457         // Mandatory bin value: [FLTNBDATA bin value]
00458         event->SetEventValue(tb, *reinterpret_cast<FLTNBDATA*>(file_position));
00459         file_position += sizeof(FLTNBDATA);
00460         // Optional scatter correction field: [FLTNBDATA (scatter)]
00461         if (m_scatCorrectionFlag)
00462         {
00463           if (!m_ignoreScatCorrectionFlag) event->SetScatterRate(tb, *reinterpret_cast<FLTNBDATA*>(file_position));
00464           file_position += sizeof(FLTNBDATA);
00465         }
00466       }
00467     }
00468     // Mandatory nb contributing LORs if m_maxNumberOfLinesPerEvent>1: [uint16_t nbLines]
00469     if (m_maxNumberOfLinesPerEvent>1)
00470     {
00471       event->SetNbLines(*reinterpret_cast<uint16_t*>(file_position));
00472       file_position += sizeof(uint16_t);
00473     }
00474     // Mandatory crystal IDs: [uint32_t (c1)] [uint32_t (c2)]
00475     for (int i=0 ; i<event->GetNbLines() ; i++)
00476     {
00477       event->SetID1(i, *reinterpret_cast<uint32_t*>(file_position));
00478       file_position += sizeof(uint32_t);
00479       event->SetID2(i, *reinterpret_cast<uint32_t*>(file_position));
00480       file_position += sizeof(uint32_t); 
00481     }
00482   }
00483 
00484   // For MODE_NORMALIZATION PET data
00485   else if (m_dataMode == MODE_NORMALIZATION)
00486   {
00487     // Cast the event pointer
00488     iEventNorm* event = (dynamic_cast<iEventNorm*>(m2p_BufferEvent[a_th]));
00489     // Optional attenuation correction field: [FLTNBDATA (norm)]
00490     if (m_atnCorrectionFlag)
00491     {
00492       if (!m_ignoreAttnCorrectionFlag) event->SetAttenuationCorrectionFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
00493       file_position += sizeof(FLTNBDATA);
00494     }
00495     // Optional normalization correction field: [FLTNBDATA (norm)]
00496     if (m_normCorrectionFlag)
00497     {
00498       if (!m_ignoreNormCorrectionFlag) event->SetNormalizationFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
00499       file_position += sizeof(FLTNBDATA);
00500     }
00501     // Mandatory nb contributing LORs if m_maxNumberOfLinesPerEvent>1: [uint16_t nbLines]
00502     if (m_maxNumberOfLinesPerEvent>1)
00503     {
00504       event->SetNbLines(*reinterpret_cast<uint16_t*>(file_position));
00505       file_position += sizeof(uint16_t);
00506     }
00507     // Mandatory crystal IDs: [uint32_t (c1)] [uint32_t (c2)]
00508     for (int i=0 ; i<event->GetNbLines() ; i++)
00509     {
00510       event->SetID1(i, *reinterpret_cast<uint32_t*>(file_position));
00511       file_position += sizeof(uint32_t);
00512       event->SetID2(i, *reinterpret_cast<uint32_t*>(file_position));
00513       file_position += sizeof(uint32_t); 
00514     }
00515   }
00516 
00517   // Return the updated event
00518   return m2p_BufferEvent[a_th];
00519 }
00520 
00521 
00522 
00523 
00524 // =====================================================================
00525 // ---------------------------------------------------------------------
00526 // ---------------------------------------------------------------------
00527 // =====================================================================
00528 /*
00529   \fn CheckSpecificParameters()
00530   \brief Check parameters specific to PET data
00531   \todo Adapt m_maxRingDiff initialization for scanner with several layers of crystals (not necessary the same nb of rings)
00532   \return 0 if success, and positive value otherwise.
00533 */
00534 int iDataFilePET::CheckSpecificParameters()
00535 {
00536   if(m_verbose>=3) Cout("iDataFilePET::CheckSpecificParameters() ..." << endl);
00537 
00538   sScannerManager* p_scannermanager;
00539   p_scannermanager = sScannerManager::GetInstance(); 
00540   
00541   // Error if m_dataType != PET
00542   if (m_dataType != TYPE_PET)
00543   {
00544     Cerr("***** iDataFilePET::CheckSpecificParameters() -> Error, Data type should be PET (=0) !'" << endl);
00545     return 1;
00546   }
00547   
00548   // Check if Maximum ring difference has been initialized, use the default value from the scanner otherwise.
00549   if (m_maxRingDiff < 0)
00550   {
00551     if (m_verbose>3) Cout("iDataFilePET::CheckSpecificParameters() -> Initialize maxRingDiff with the scanner default value" << endl);
00552     m_maxRingDiff = p_scannermanager->GetScannerLayerNbRings(0); //TODO maybe throw error here if returned value is incorrect 
00553                                                                  //TODO  how to deal with scanner with different layers (possibly different number of rings as well)
00554   }
00555   
00556   // Some checks for POI use
00557   if (m_POIInfoFlag)
00558   {
00559     // Not compatible with histogram data
00560     if (m_dataMode==MODE_HISTOGRAM)
00561     {
00562       Cerr("***** iDataFilePET::CheckSpecificParameters() -> POI correction flag is enabled while the data are histogrammed, no sense !" << endl);
00563       return 1;
00564     }
00565     // For each direction (radial, tangential and axial), look at the resolution. If not negative, the info should be the datafile
00566     for (int i=0; i<3; i++) if (mp_POIResolution[i]>=0.) mp_POIDirectionFlag[i] = true;
00567   }
00568   
00569   // Some checks for TOF use
00570   if (m_TOFInfoFlag)
00571   {
00572     // Check if the resolution was provided
00573     if (m_resolutionTOF<0.)
00574     {
00575       Cerr("***** iDataFilePET::CheckSpecificParameters() -> TOF correction is on while there is no TOF resolution specified in the datafile header !" << endl);
00576       return 1;
00577     }
00578     // For histogram data
00579     if (m_dataMode==MODE_HISTOGRAM)
00580     {
00581       // Check if the number of bins has been provided
00582       if (m_nbBinsTOF<=1)
00583       {
00584         Cerr("***** iDataFilePET::CheckSpecificParameters() -> TOF correction is on while there is only one TOF bin (specified in the datafile header) !" << endl);
00585         return 1;
00586       }
00587       // Check if the bin size has been provided
00588       if (m_binSizeTOF<=0.)
00589       {
00590         Cerr("***** iDataFilePET::CheckSpecificParameters() -> TOF correction is on while there is no bin size specified in the datafile header !" << endl);
00591         return 1;
00592       }
00593     }
00594   }
00595   else
00596   {
00597     // Set the number of TOF bins to 1
00598     m_nbBinsTOF = 1;
00599   }
00600   
00601   // End
00602   return 0;
00603 }
00604 // =====================================================================
00605 // ---------------------------------------------------------------------
00606 // ---------------------------------------------------------------------
00607 // =====================================================================
00608 /*
00609   \fn CheckFileConsistency()
00610   \brief  This function is implemented in child classes
00611           Check if file size is consistent.
00612   \return 0 if success, and positive value otherwise.
00613 */
00614 int iDataFilePET::CheckFileSizeConsistency()
00615 {
00616   if (m_verbose >=3) Cout("iDataFilePET::CheckFileSizeConsistency() ..." << endl);
00617     
00618   // CHECK IF DATAFILE SIZE CORRESPONDS TO THE USER DATA INITIALIZATION 
00619   m2p_dataFile[0]->seekg(0, ios::end);
00620   int64_t sizeInBytes = m2p_dataFile[0]->tellg();
00621 
00622   if (m_totalNbEvents*m_sizeEvent != sizeInBytes)
00623   {
00624     Cerr("---------------------------------------------------------------------------------------------------------------------------------------------" << endl);
00625     Cerr("***** iDataFilePET::CheckFileSizeConsistency() -> Error : Datafile size is not consistent with the information provided by the user/datafile!" << endl);
00626     Cerr("***** iDataFilePET::CheckFileSizeConsistency() -> Expected size : "<< m_totalNbEvents*m_sizeEvent << endl);
00627     Cerr("***** iDataFilePET::CheckFileSizeConsistency() -> Actual size : "<< sizeInBytes << endl << endl);
00628 
00629     // TODO : Perhaps always write the following depending on verbose (feedback for the user)
00630     Cerr("***** iDataFilePET::CheckFileSizeConsistency() -> ADDITIONAL INFORMATION ABOUT THE DATAFILE INITIALIZATION : " << endl);
00631 
00632     if(m_maxNumberOfLinesPerEvent > 1)
00633       Cerr("      iDataFilePET::CheckFileSizeConsistency() -> Compression enabled. Each event should contain " << m_maxNumberOfLinesPerEvent << "LORs, or an equivalent number of LOR + garbage LORs" << endl);
00634     else
00635       Cerr("      iDataFilePET::CheckFileSizeConsistency() -> No compression in the data (1 LOR by event in the data) " << endl);
00636       
00637     if(m_eventKindFlag)
00638       Cerr("      iDataFilePET::CheckFileSizeConsistency() -> Coincidence kind (trues, scatter, random, ...) term is enabled " << endl);
00639     else
00640       Cerr("      iDataFilePET::CheckFileSizeConsistency() -> No informations about the kind of coincidences in the data " << endl);
00641       
00642     if(m_normCorrectionFlag)
00643       Cerr("      iDataFilePET::CheckFileSizeConsistency() -> Normalization correction term is enabled " << endl);
00644     else
00645       Cerr("      iDataFilePET::CheckFileSizeConsistency() -> No normalization correction terms in the data " << endl);
00646       
00647     if(m_atnCorrectionFlag)
00648       Cerr("      iDataFilePET::CheckFileSizeConsistency() -> Attenuation correction term is enabled " << endl);
00649     else
00650       Cerr("      iDataFilePET::CheckFileSizeConsistency() -> No attenuation correction terms in the data " << endl);
00651       
00652     if(m_scatCorrectionFlag)
00653       Cerr("      iDataFilePET::CheckFileSizeConsistency() -> Scatter correction term is enabled " << endl);
00654     else
00655       Cerr("      iDataFilePET::CheckFileSizeConsistency() -> No scatter correction terms in the data " << endl);
00656 
00657     if(m_randCorrectionFlag)
00658       Cerr("      iDataFilePET::CheckFileSizeConsistency() -> Random correction term is enabled " << endl);
00659     else
00660       Cerr("      iDataFilePET::CheckFileSizeConsistency() -> No random correction terms in the data " << endl);
00661 
00662     if(m_TOFInfoFlag)
00663       Cerr("      iDataFilePET::CheckFileSizeConsistency() -> TOF correction is enabled. Resolution is : " << m_resolutionTOF << " ps."<< endl);
00664     else
00665       Cerr("      iDataFilePET::CheckFileSizeConsistency() -> No TOF correction in the data " << endl);
00666 
00667     Cerr("      iDataFilePET::CheckFileSizeConsistency() -> Calibration factor value is : " << m_calibrationFactor << endl);
00668 
00669     if(mp_POIResolution[0]<0)
00670       Cerr("      iDataFilePET::CheckFileSizeConsistency() -> No POI enabled on the X axis " << endl);
00671     else
00672       Cerr("      iDataFilePET::CheckFileSizeConsistency() -> POI resolution on the X axis is : " << mp_POIResolution[0] << endl);
00673 
00674     if(mp_POIResolution[1]<0)
00675       Cerr("      iDataFilePET::CheckFileSizeConsistency() -> No POI enabled on the Y axis " << endl);
00676     else
00677       Cerr("      iDataFilePET::CheckFileSizeConsistency() -> POI resolution on the Y axis is : " << mp_POIResolution[1] << endl);
00678 
00679     if(mp_POIResolution[2]<0)
00680       Cerr("      iDataFilePET::CheckFileSizeConsistency() -> No POI enabled on the Z axis " << endl);
00681     else
00682       Cerr("      iDataFilePET::CheckFileSizeConsistency() -> POI resolution on the Z axis is : " << mp_POIResolution[2] << endl);
00683     Cerr("---------------------------------------------------------------------------------------------------------------------------------------------" << endl);
00684     
00685     return 1;
00686   }
00687   
00688   // Depending on the verbosity, output all the datafile initialization information as feedback for the user
00689   if (m_verbose>=4)
00690   {
00691     Cout("----------------------------------------------------------------Datafile initialization -------------------------------------------------------------" << endl);
00692 
00693     if(m_maxNumberOfLinesPerEvent > 1)
00694       Cout("  --> Compression enabled. Each event should contain " << m_maxNumberOfLinesPerEvent << "LORs, or an equivalent number of LOR + garbage LORs" << endl);
00695     else
00696       Cout("  --> No compression in the data (1 LOR by event in the data) " << endl);
00697 
00698     if(m_eventKindFlag)
00699       Cout("  --> Coincidence kind (trues, scatter, random, ...) term is enabled " << endl);
00700     else
00701       Cout("  --> No informations about the kind of coincidences in the data " << endl);
00702 
00703     if(m_normCorrectionFlag)
00704       Cout("  --> Normalization correction term is enabled " << endl);
00705     else
00706       Cout("  --> No normalization correction terms in the data " << endl);
00707 
00708     if(m_atnCorrectionFlag)
00709       Cout("  --> Attenuation correction term is enabled " << endl);
00710     else
00711       Cout("  --> No attenuation correction terms in the data " << endl);
00712 
00713     if(m_scatCorrectionFlag)
00714       Cout("  --> Scatter correction term is enabled " << endl);
00715     else
00716       Cout("  --> No scatter correction terms in the data " << endl);
00717 
00718     if(m_randCorrectionFlag)
00719       Cout("  --> Random correction term is enabled " << endl);
00720     else
00721       Cout("  --> No random correction terms in the data " << endl);
00722 
00723     if(m_TOFInfoFlag)
00724       Cout("  --> TOF correction is enabled. Resolution is : " << m_resolutionTOF << " ps."<< endl);
00725     else
00726       Cout("  --> No TOF correction in the data " << endl);
00727 
00728     Cout("  --> Calibration factor value is : " << m_calibrationFactor << endl);
00729 
00730     if(mp_POIResolution[0]<0)
00731       Cout("  --> No POI enabled on the X axis " << endl);
00732     else
00733       Cout("  --> POI resolution on the X axis is : " << mp_POIResolution[0] << endl);
00734 
00735     if(mp_POIResolution[1]<0)
00736       Cout("  --> No POI enabled on the Y axis " << endl);
00737     else
00738       Cout("  --> POI resolution on the Y axis is : " << mp_POIResolution[1] << endl);
00739 
00740     if(mp_POIResolution[2]<0)
00741       Cout("  --> No POI enabled on the Z axis " << endl);
00742     else
00743       Cout("  --> POI resolution on the Z axis is : " << mp_POIResolution[2] << endl);
00744     Cout("---------------------------------------------------------------------------------------------------------------------------------------------" << endl << endl);
00745   }
00746   
00747   // End
00748   return 0;
00749 }
00750 
00751 
00752 
00753 
00754 //PROJECTION SCRIPT FUNCTIONS
00755 // =====================================================================
00756 // ---------------------------------------------------------------------
00757 // ---------------------------------------------------------------------
00758 // =====================================================================
00759 
00760 
00761 /*
00762   \fn PROJ_InitFile()
00763   \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)
00764   \todo Adapt m_maxRingDiff initialization for scanner with several layers of crystals (not necessary the same nb of rings)
00765   \todo warn the user a datafile with the same name will be erased (eventually add an option to disable the warning)
00766   \return 0 if success, and positive value otherwise.
00767 */
00768 int iDataFilePET::PROJ_InitFile()
00769 {
00770   if(m_verbose>=3) Cout("iDataFilePET::PROJ_InitFile() ..."<< endl); 
00771     
00772   m_startTimeInSec = 0.; //Std initialization for projection
00773   m_durationInSec = 1.; //Std initialization for projection
00774   m_totalNbEvents = 0; //Std initialization for projection
00775   m_nbBinsTOF = 1; // Initialization of this variable required for PROJ_Write functions
00776   m_isotope = "unknown";
00777 
00778   // Instanciate a fstream datafile for each thread
00779   m2p_dataFile = new fstream*[mp_ID->GetNbThreadsForProjection()];
00780 
00781   // Set name of the projection data header
00782   sOutputManager* p_OutMgr;
00783   p_OutMgr = sOutputManager::GetInstance();
00784   string path_name = p_OutMgr->GetPathName();
00785   string img_name = p_OutMgr->GetBaseName();
00786   m_headerFileName = path_name.append(img_name).append("_CstrProj").append(".Cdh");
00787 
00788   for (int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
00789   {
00790     m_dataFileName = m_headerFileName.substr(0, m_headerFileName.find_last_of(".")).append(".Cdf"); // Generate datafile name from header file
00791     
00792     // We'll write projeted data in several files (corresponding to the number of thread) to be concatenated at the end of the projection process.   
00793     stringstream ss;
00794     ss << th;
00795     string datafile_name = m_dataFileName;
00796     datafile_name.append("_").append(ss.str());
00797     
00798     m2p_dataFile[th] = new fstream( datafile_name.c_str(), ios::binary | ios::out | ios::trunc);
00799   }
00800 
00801 
00802   // Check there is no existing datafile with such name. Remove it otherwise
00803   ifstream fcheck(m_dataFileName.c_str());
00804   if(fcheck.good())
00805   {
00806     fcheck.close();
00807     #ifdef _WIN32
00808     string dos_instruction = "del " + m_dataFileName;
00809     system(dos_instruction.c_str());
00810     #else
00811     remove(m_dataFileName.c_str());
00812     #endif
00813   }
00814   
00815   if(m_verbose>=3) Cout("iDataFilePET::PROJ_InitFile()-> output datafile name :" << m_dataFileName << endl); 
00816     
00817   return 0;
00818 }
00819 
00820 
00821 
00822 // =====================================================================
00823 // ---------------------------------------------------------------------
00824 // ---------------------------------------------------------------------
00825 // =====================================================================
00826 /*
00827   \fn PROJ_WriteEvent(vEvent* ap_Event, FLTNB fp, int a_th, uint32_t a_time)
00828   \param ap_Event : event containing the data to write
00829   \param a_th
00830   \brief  Write event according to the chosen type of data
00831   \todo   Depending of the RAM load FLAG, either write the data in *nbThreads* different files which will be concatenated at the end (current implementation), 
00832           or write data in buffers, to be flushed at the end of projection loop.
00833   \todo   Projection for list-mode
00834   \return 0 if success, and positive value otherwise.
00835 */
00836 int iDataFilePET::PROJ_WriteEvent(vEvent* ap_Event, int a_th)
00837 {
00838   #ifdef CASTOR_VERBOSE
00839   // Verbose
00840   if(m_verbose>=4) Cout("iDataFilePET::PROJ_WriteEvent() ..."<< endl); 
00841   #endif
00842   
00843   if(m_dataMode == MODE_LIST) 
00844   {
00845     if(PROJ_WriteListEvent((iEventListPET*)ap_Event, a_th))
00846     {
00847       Cerr("*****iDataFilePET::PROJ_WriteEvent() -> Error while trying to write projection datafile (list-mode)" << endl;);
00848       return 1;
00849     }
00850   }
00851 
00852   if(m_dataMode == MODE_HISTOGRAM)
00853   {
00854     if(PROJ_WriteHistoEvent((iEventHistoPET*)ap_Event, a_th))
00855     {
00856       Cerr("*****iDataFilePET::PROJ_WriteEvent() -> Error while trying to write projection datafile (histogram)" << endl;);
00857       return 1;
00858     }
00859   }
00860 
00861   return 0;
00862 }
00863 
00864 // =====================================================================
00865 // ---------------------------------------------------------------------
00866 // ---------------------------------------------------------------------
00867 // =====================================================================
00868 /*
00869   \fn PROJ_WriteHistoEvent()
00870   \param ap_Event : event containing the data to write
00871   \param a_th : index of the thread from which the function was called
00872   \brief  Write a PET histogram event
00873   \return 0 if success, and positive value otherwise.
00874 */
00875 int iDataFilePET::PROJ_WriteHistoEvent(iEventHistoPET* ap_Event, int a_th)
00876 {
00877   #ifdef CASTOR_VERBOSE
00878   // Verbose
00879   if(m_verbose>=4) Cout("iDataFilePET::PROJ_WriteHistoEvent() ..."<< endl);
00880   #endif
00881 
00882   // Write sequentially each field of the event according to the type of the event.
00883   m2p_dataFile[a_th]->clear();
00884   
00885   uint32_t time = ap_Event->GetTimeInMs();
00886   m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&time), sizeof(uint32_t));
00887   
00888   if(m_atnCorrectionFlag)
00889   {
00890     FLTNB atn_corr_factor = ap_Event->GetAtnCorrFactor(); 
00891     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&atn_corr_factor), sizeof(FLTNB));
00892   }
00893   
00894   if(m_randCorrectionFlag) 
00895   {
00896     FLTNB rdm_rate = ap_Event->GetEventRdmRate();
00897     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&rdm_rate), sizeof(FLTNB));
00898   }
00899   
00900   if(m_normCorrectionFlag)   
00901   {
00902     FLTNB norm_corr_factor = ap_Event->GetNormFactor();
00903     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&norm_corr_factor), sizeof(FLTNB));
00904   }
00905   
00906   for(int b=0 ; b<m_nbBinsTOF ; b++)
00907   {
00908     FLTNB event_value = ap_Event->GetEventValue(b);
00909     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&event_value), sizeof(FLTNB));
00910     if(m_scatCorrectionFlag) 
00911     {
00912       FLTNB scat_rate = ap_Event->GetEventScatRate(b);
00913       m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&scat_rate), sizeof(FLTNB));
00914     }
00915   }
00916   
00917   uint16_t nb_lines = ap_Event->GetNbLines();
00918   // Write the number of lines only if the m_maxNumberOfLinesPerEvent is above 1
00919   if (m_maxNumberOfLinesPerEvent>1) m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&nb_lines), sizeof(uint16_t));
00920 
00921   for(int i=0 ; i<nb_lines ; i++)
00922   {
00923     uint32_t id1 = ap_Event->GetID1(i);
00924     uint32_t id2 = ap_Event->GetID2(i);
00925     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id1), sizeof(uint32_t));
00926     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id2), sizeof(uint32_t));
00927   }
00928 
00929   // 0-filling if needed (nb lines inferior to the max number for PET data with compression)
00930   if(nb_lines<m_maxNumberOfLinesPerEvent)
00931     for(int i=0 ; i<m_maxNumberOfLinesPerEvent-nb_lines ; i++)
00932     {
00933       uint32_t gbg = 0;
00934       m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&gbg), sizeof(uint32_t));
00935       m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&gbg), sizeof(uint32_t));
00936     }
00937 
00938   return 0;
00939 }
00940 
00941 
00942 
00943 
00944 // =====================================================================
00945 // ---------------------------------------------------------------------
00946 // ---------------------------------------------------------------------
00947 // =====================================================================
00948 /*
00949   \fn PROJ_WriteListEvent()
00950   \param ap_Event : event containing the data to write
00951   \param a_th : index of the thread from which the function was called
00952   \brief  Write a PET list-mode event
00953   \return 0 if success, and positive value otherwise.
00954 */
00955 int iDataFilePET::PROJ_WriteListEvent(iEventListPET* ap_Event, int a_th)
00956 {
00957   #ifdef CASTOR_VERBOSE
00958   // Verbose
00959   if(m_verbose>=4) Cout("iDataFilePET::PROJ_WriteListEvent() ..."<< endl);
00960   #endif
00961 
00962   // Write sequentially each field of the event according to the type of the event.
00963   m2p_dataFile[a_th]->clear();
00964   
00965   uint32_t time = ap_Event->GetTimeInMs();
00966   m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&time), sizeof(uint32_t));
00967   
00968   
00969   if(m_atnCorrectionFlag)
00970   {
00971     FLTNB atn_corr_factor = ap_Event->GetAtnCorrFactor(); 
00972     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&atn_corr_factor), sizeof(FLTNB));
00973   }
00974   
00975   if(m_eventKindFlag) 
00976   {
00977     uint8_t event_kind = ap_Event->GetKind();
00978     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&event_kind), sizeof(uint8_t));
00979   }
00980   
00981   if(m_scatCorrectionFlag)   
00982   {
00983     FLTNB scat_rate = ap_Event->GetEventScatRate(0);
00984     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&scat_rate), sizeof(FLTNB));
00985   }
00986   
00987   if(m_randCorrectionFlag) 
00988   {
00989     FLTNB rdm_rate = ap_Event->GetEventRdmRate();
00990     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&rdm_rate), sizeof(FLTNB));
00991   }
00992   
00993   if(m_normCorrectionFlag)   
00994   {
00995     FLTNB norm_corr_factor = ap_Event->GetNormFactor();
00996     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&norm_corr_factor), sizeof(FLTNB));
00997   }
00998     
00999   if(m_TOFInfoFlag)
01000   {
01001     uint32_t TOF_measurement = ap_Event->GetTOFMeasurement();
01002     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&TOF_measurement), sizeof(uint32_t));
01003   }
01004   
01005   
01006   if(mp_POIResolution[0]>0)
01007   {
01008     FLTNB POI_1 = ap_Event->GetPOI1(0);
01009     FLTNB POI_2 = ap_Event->GetPOI2(0);
01010     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI_1), sizeof(FLTNB));
01011     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI_2), sizeof(FLTNB));
01012   }
01013   if(mp_POIResolution[1]>0)
01014   {
01015     FLTNB POI_1 = ap_Event->GetPOI1(1);
01016     FLTNB POI_2 = ap_Event->GetPOI2(1);
01017     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI_1), sizeof(FLTNB));
01018     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI_2), sizeof(FLTNB));
01019   }
01020   if(mp_POIResolution[2]>0)
01021   {
01022     FLTNB POI_1 = ap_Event->GetPOI1(2);
01023     FLTNB POI_2 = ap_Event->GetPOI2(2);
01024     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI_1), sizeof(FLTNB));
01025     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI_2), sizeof(FLTNB));
01026   }
01027   
01028   uint16_t nb_lines = ap_Event->GetNbLines();
01029   // Write the number of lines only if the m_maxNumberOfLinesPerEvent is above 1
01030   if (m_maxNumberOfLinesPerEvent>1) m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&nb_lines), sizeof(uint16_t));
01031 
01032   for(int i=0 ; i<nb_lines ; i++)
01033   {
01034     uint32_t id1 = ap_Event->GetID1(i);
01035     uint32_t id2 = ap_Event->GetID2(i);
01036     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id1), sizeof(uint32_t));
01037     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id2), sizeof(uint32_t));
01038   }
01039   
01040   // 0-filling if needed (nb lines inferior to the max number for PET data with compression)
01041   if(nb_lines<m_maxNumberOfLinesPerEvent)
01042     for(int i=0 ; i<m_maxNumberOfLinesPerEvent-nb_lines ; i++)
01043     {
01044       uint32_t gbg = 0;
01045       m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&gbg), sizeof(uint32_t));
01046       m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&gbg), sizeof(uint32_t));
01047     }
01048 
01049   return 0;
01050 }
01051 
01052 
01053 
01054 
01055 // =====================================================================
01056 // ---------------------------------------------------------------------
01057 // ---------------------------------------------------------------------
01058 // =====================================================================
01059 /*
01060   \fn PROJ_WriteHeader()
01061   \brief  Generate a header file according to the projection and data output informations.
01062           Used by Projection algorithm.
01063   \todo   Use Interfile format
01064   \return 0 if success, and positive value otherwise.
01065 */
01066 int iDataFilePET::PROJ_WriteHeader()
01067 {
01068   if(m_verbose>=3) Cout("PROJ_WriteHeader() ..."<< endl);
01069   
01070   fstream headerFile;
01071   stringstream ss;
01072 
01073   headerFile.open(m_headerFileName.c_str(), ios::out);
01074 
01075   // ----- MANDATORY FLAGS ----- // 
01076   headerFile << "Data filename:" << "    " << GetFileFromPath(m_dataFileName).c_str() << endl; 
01077   headerFile << "Number of events:" << "    " << m_totalNbEvents << endl; 
01078 
01079   //- Flag: list-mode or histogram mode
01080   headerFile << "Data mode:" << "    " << m_dataMode << endl; 
01081   // Flag: PET, SPECT or TRANSMISSION
01082   headerFile << "Data type: " << "    " << "PET" << endl;
01083 
01084   headerFile << "Start time (s):" << "    " << m_startTimeInSec << endl; 
01085   
01086   headerFile << "Duration (s):" << "    " << m_durationInSec << endl; 
01087 
01088   sScannerManager* p_scannermanager; 
01089   p_scannermanager = sScannerManager::GetInstance(); 
01090 
01091   headerFile << "Scanner name:" << "    " << p_scannermanager->GetScannerName() << endl; 
01092   
01093   headerFile << "Maximum ring difference:" << "    " << m_maxRingDiff << endl; 
01094   
01095   // Only write this field if different than default value
01096   if(m_maxNumberOfLinesPerEvent >1)
01097     headerFile << "Maximum number of lines per event:" << "    " << m_maxNumberOfLinesPerEvent << endl; 
01098     
01099     
01100   
01101   // ----- OPTIONNAL FLAGS ----- // 
01102   headerFile << "Calibration factor:" << "    " << m_calibrationFactor << endl;
01103 
01104   if (m_isotope != "unknown") headerFile << "Isotope:" << "    " << m_isotope << endl; 
01105     
01106     
01107 
01108   // ----- TOF info ----- // 
01109   if(m_TOFInfoFlag)
01110   {
01111     if(m_dataMode == MODE_LIST) 
01112     {
01113       if(m_resolutionTOF <= 0.) // Check if TOF resolution (list-mode) initialized, error otherwise
01114       { 
01115         Cerr("***** iDataFilePET::PROJ_WriteHeader -> Error : TOF resolution (mm) for list-mode not initialized, while TOF correction flag is enabled!" << endl);
01116         return 1;
01117       }
01118       else
01119         headerFile << "TOF resolution:" << "    " << m_resolutionTOF << endl; 
01120     }
01121     else if (m_dataMode == MODE_HISTOGRAM) 
01122     {
01123       if(m_binSizeTOF > 0.) // Check if TOF bin size (histogram) initialized, error otherwise
01124       { 
01125         Cerr("***** iDataFilePET::PROJ_WriteHeader -> Error : TOF bin size for histogram mode not initialized, while TOF correction flag is enabled!" << endl);
01126         return 1;
01127       }
01128       else
01129       {
01130         headerFile << "Histo TOF bin:" << "    " << m_nbBinsTOF << endl; 
01131         headerFile << "Histo TOF size:" << "    " << m_binSizeTOF << endl; 
01132       }
01133     }
01134     else
01135     { 
01136       Cerr("***** iDataFilePET::PROJ_WriteHeader -> Error : Datafile mode unknown (should be 0 (list-mode) or histogram (1))!" << endl);
01137       return 1;
01138     }
01139   }
01140   
01141   
01142   // ----- POI info ----- // 
01143   if (mp_POIResolution[0]>0. || mp_POIResolution[1]>0. || mp_POIResolution[2]>0.)
01144   {
01145     // Error if histogram data are used
01146     if (m_dataMode==MODE_HISTOGRAM)
01147     {
01148       Cerr("***** iDataFilePET::PROJ_WriteHeader -> Request for writing POI resolution in histogram mode (this field is specific to list-mode) !" << endl);
01149       return 1;
01150     }
01151     else
01152       headerFile << "DOI capability:" << "    " << mp_POIResolution[0] << "," << mp_POIResolution[1] << "," << mp_POIResolution[2] << endl;
01153   }
01154 
01155 
01156   // ----- Event kind ----- // 
01157   if (m_eventKindFlag)
01158   {
01159     // Error if histogram data are used
01160     if(m_dataMode==MODE_HISTOGRAM)
01161     {
01162       Cerr("***** iDataFilePET::PROJ_WriteHeader -> Request for writing event type in histogram mode (this field is specific to list-mode) !" << endl);
01163       return 1;
01164     }
01165     else 
01166       headerFile << "Coincidence kind informations flag:" << "    " << m_eventKindFlag << endl;
01167   }
01168  
01169  
01170    // ----- Correction flags ----- // 
01171    
01172   if(m_atnCorrectionFlag)
01173     headerFile << "Attenuation correction flag:" << "    " << m_atnCorrectionFlag << endl;  //TODO Should be computed during projection
01174     
01175   if(m_normCorrectionFlag)
01176     headerFile << "Normalization correction flag:" << "    " << m_normCorrectionFlag << endl; 
01177 
01178   if(m_scatCorrectionFlag)
01179     headerFile << "Scatter correction flag:" << "    " << m_scatCorrectionFlag << endl; 
01180     
01181   if(m_randCorrectionFlag)
01182     headerFile << "Random correction flag:" << "    " << m_randCorrectionFlag << endl; 
01183   
01184   headerFile.close();
01185 
01186   return 0;
01187 }
01188 
01189 
01190 
01191 
01192 // =====================================================================
01193 // ---------------------------------------------------------------------
01194 // ---------------------------------------------------------------------
01195 // =====================================================================
01196 /*
01197   \fn PROJ_GetScannerSpecificParameters()
01198   \brief Get PET specific parameters for projections from the scanner object, through the scannerManager.
01199   \return 0 if success, positive value otherwise
01200 */
01201 int iDataFilePET::PROJ_GetScannerSpecificParameters()
01202 {
01203   if(m_verbose>=3) Cout("PROJ_GetScannerSpecificParameters() ..."<< endl);
01204   sScannerManager* p_scannermanager;
01205   p_scannermanager = sScannerManager::GetInstance(); 
01206    
01207   // Get pointers to SPECT specific parameters in scanner
01208   if(p_scannermanager->PROJ_GetPETSpecificParameters(&m_maxRingDiff) )
01209   {
01210     Cerr("***** iDataFilePET::PROJ_GetScannerSpecificParameters() -> An error occurred while trying to get PET geometric parameters from the scanner object !" << endl);
01211     return 1;
01212   }
01213 
01214   return 0;
01215 }
 All Classes Files Functions Variables Typedefs Defines