CASToR  1.0
Tomographic Reconstruction (PET/SPECT)
iDataFileSPECT.cc
Go to the documentation of this file.
00001 
00002 /*
00003   Implementation of class iDataFileSPECT
00004 
00005   - separators: X
00006   - doxygen: X
00007   - default initialization: X
00008   - CASTOR_DEBUG: X
00009   - CASTOR_VERBOSE: X
00010 */
00011 
00012 
00013 
00022 #include "iDataFileSPECT.hh"
00023 
00024 
00025 
00026 // =====================================================================
00027 // ---------------------------------------------------------------------
00028 // ---------------------------------------------------------------------
00029 // =====================================================================
00030 /*
00031   \brief iDataFileSPECT constructor. 
00032          Initialize the member variables to their default values.
00033 */
00034 iDataFileSPECT::iDataFileSPECT() : vDataFile() 
00035 {
00036   m_dataType = TYPE_SPECT;
00037   m_isotope = "unknown";
00038   mp_nbOfBins[0] = 1;
00039   mp_nbOfBins[1] = 1;
00040   m_nbOfProjections = 0;
00041   mp_angles = NULL;
00042   m_nbHeads = 1;
00043   mp_CORtoDetectorDistance = NULL;
00044   m_eventKindFlag = false;
00045   m_normCorrectionFlag = false;
00046   m_ignoreNormCorrectionFlag = false;
00047   m_scatCorrectionFlag = false;
00048   m_ignoreScatCorrectionFlag = false;
00049   m_headRotDirection = GEO_ROT_CW;
00050 }
00051 
00052 
00053 
00054 // =====================================================================
00055 // ---------------------------------------------------------------------
00056 // ---------------------------------------------------------------------
00057 // =====================================================================
00058 /*
00059   \brief iDataFileSPECT destructor. 
00060 */
00061 iDataFileSPECT::~iDataFileSPECT() 
00062 {
00063   if (mp_angles) delete[] mp_angles;
00064   if (mp_CORtoDetectorDistance) delete[] mp_CORtoDetectorDistance;
00065 }
00066 
00067 
00068 
00069 
00070 // =====================================================================
00071 // ---------------------------------------------------------------------
00072 // ---------------------------------------------------------------------
00073 // =====================================================================
00074 /*
00075   \fn ReadSpecificInfoInHeader()
00076   \brief Read through the header file and recover specific SPECT information.
00077   \return 0 is success, positive value otherwise
00078 */
00079 int iDataFileSPECT::ReadSpecificInfoInHeader()
00080 {
00081   // Verbose
00082   if (m_verbose>=3) Cout("iDataFileSPECT::ReadSpecificInfoInHeader() ..." << endl);
00083   
00084   // Create pointers dedicated to recover the addresses of the member variables of the scanner object
00085   FLTNB* p_angles = NULL;
00086   FLTNB* p_CORtoDetectorDistance = NULL; 
00087   FLTNB p_pixSizeXY[2]; // not used here
00088   
00089   // Get Geometric parameters recovered from the scanner object
00090   sScannerManager* p_scannermanager;
00091   p_scannermanager = sScannerManager::GetInstance(); 
00092   p_scannermanager->GetSPECTSpecificParameters(&m_nbOfProjections, 
00093                                                &m_nbHeads, 
00094                                                 mp_nbOfBins, 
00095                                                 p_pixSizeXY, 
00096                                                 p_angles, 
00097                                                 p_CORtoDetectorDistance,
00098                                                &m_headRotDirection);
00099   
00100   // Check mp_nbOfBins[2]
00101   /*
00102   if(mp_nbOfBins[0] == 0 || mp_nbOfBins[1] == 0)
00103   {
00104     Cerr("***** iDataFileSPECT::ReadSpecificInfoInHeader() -> Error, number of bins should be >0 '" << endl);
00105     return 1;
00106   }
00107 */
00108   // Check m_nbOfProjections first before allocating projection angles and radius using this variable
00109   if(m_nbOfProjections == 0)
00110   {
00111     Cerr("***** iDataFileSPECT::ReadSpecificInfoInHeader() -> Error, number of projections should be >0 '" << endl);
00112     return 1;
00113   }
00114   
00115   // Allocation and initialization of Projection angles and Center of rotation to SPECT detector surface distance (radius) :
00116   mp_angles = new FLTNB[m_nbOfProjections];
00117   mp_CORtoDetectorDistance = new FLTNB[m_nbOfProjections];
00118 
00119   // Recover values
00120   for(int a=0 ; a<m_nbOfProjections ; a++)
00121   {
00122     mp_angles[a] = p_angles[a];
00123     mp_CORtoDetectorDistance[a] = p_CORtoDetectorDistance[a];
00124   }
00125 
00126   // Feedback to user
00127   if(m_verbose ==3) 
00128   {
00129     Cout("iDataFileSPECT::ReadSpecificInfoInHeader() -> Provided projection angles ; distance Center of Rotation (COR) to detector: "<< endl);
00130     for(int a=0 ; a<m_nbOfProjections ; a++)
00131       Cout(mp_angles[a] << " ; "  << mp_CORtoDetectorDistance[a] << endl);
00132     Cout(endl);
00133   }
00134   
00135 
00136   // Read optional fields in the header, check if errors (issue during data reading/conversion (==1) )
00137   if (ReadDataASCIIFile(m_headerFileName, "Isotope", &m_isotope, 1, 0)==1 ||
00138       ReadDataASCIIFile(m_headerFileName, "Event kind flag", &m_eventKindFlag, 1, 0)==1 ||
00139       ReadDataASCIIFile(m_headerFileName, "Normalization correction flag", &m_normCorrectionFlag, 1, 0)==1 ||
00140       ReadDataASCIIFile(m_headerFileName, "Scatter correction flag", &m_scatCorrectionFlag, 1, 0)==1 )
00141       {
00142         Cerr("***** iDataFileSPECT::ReadSpecificInfoInHeader() -> Error while reading optional field in the header data file '" << endl);
00143         return 1;
00144       }
00145 
00146   // Give the SPECT isotope to the oImageDimensionsAndQuantification that manages the quantification factors
00147   if (m_dataMode!=MODE_NORMALIZATION && mp_ID->SetSPECTIsotope(m_bedIndex, m_isotope))
00148   {
00149     Cerr("***** iDataFileSPECT::ReadSpecificInfoInHeader() -> A problem occured while setting the isotope to oImageDimensionsAndQuantification !" << endl);
00150     return 1;
00151   }
00152   
00153   return 0;
00154 }
00155 
00156 
00157 
00158 
00159 // =====================================================================
00160 // ---------------------------------------------------------------------
00161 // ---------------------------------------------------------------------
00162 // =====================================================================
00163 /*
00164   \fn ComputeSizeEvent()
00165   \brief Computation of the size of each event according to the mandatory/optional correction fields
00166   \return 0 is success, positive value otherwise
00167 */
00168 int iDataFileSPECT::ComputeSizeEvent()
00169 {
00170   // Verbose
00171   if (m_verbose>=3) Cout("iDataFileSPECT::ComputeSizeEvent() ..." << endl);
00172 
00173   // For MODE_LIST events
00174   if (m_dataMode == MODE_LIST) 
00175   {
00176     // Size of the mandatory element in a list-mode event:
00177     // Time + 2*crystalID
00178     m_sizeEvent = sizeof(uint32_t) + 2*sizeof(uint32_t);
00179     // Optional flags
00180     if (m_eventKindFlag) m_sizeEvent += sizeof(FLTNBDATA);
00181     if (m_scatCorrectionFlag) m_sizeEvent += sizeof(FLTNBDATA);
00182     if (m_normCorrectionFlag) m_sizeEvent += sizeof(FLTNBDATA);
00183     for (int i=0 ; i<3; i++)
00184     {
00185       // POI available for this direction
00186       if (mp_POIDirectionFlag[i]) m_sizeEvent += sizeof(FLTNBDATA);
00187     }
00188   }
00189 
00190   // For MODE_HISTOGRAM events
00191   if(m_dataMode == MODE_HISTOGRAM)
00192   {
00193     // Size of the mandatory element in a histo event:
00194     // Time + event_value + 2*crystalID
00195     m_sizeEvent = sizeof(uint32_t) + sizeof(FLTNBDATA) + 2*sizeof(uint32_t);
00196     // Optional flags
00197     if (m_scatCorrectionFlag) m_sizeEvent += sizeof(FLTNBDATA);
00198     if (m_normCorrectionFlag) m_sizeEvent += sizeof(FLTNBDATA);
00199   }
00200 
00201   // Verbose
00202   if (m_verbose>=3) Cout("  --> Event size: " << m_sizeEvent << " bytes" << endl);
00203 
00204   return 0;
00205 }
00206 
00207 
00208 
00209 // =====================================================================
00210 // ---------------------------------------------------------------------
00211 // ---------------------------------------------------------------------
00212 // =====================================================================
00213 /*
00214   \fn PrepareDataFile()
00215   \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)
00216          Use the flag provided by the user to determine how the data has to be sorted (preloaded or read on the fly)
00217   \return 0 is success, positive value otherwise
00218 */
00219 int iDataFileSPECT::PrepareDataFile()
00220 {
00221   // Verbose
00222   if (m_verbose>=2)
00223   {
00224     if (m_dataMode==MODE_HISTOGRAM) Cout("iDataFileSPECT::PrepareDataFile() -> Build histogram events" << endl);
00225     else if (m_dataMode==MODE_LIST) Cout("iDataFileSPECT::PrepareDataFile() -> Build listmode events" << endl);
00226     else if (m_dataMode==MODE_NORMALIZATION) Cout("iDataFileSPECT::PrepareDataFile() -> Build normalization events" << endl);
00227   }
00228 
00229   // ==============================================================================
00230   // Allocate event buffers (one for each thread)
00231   // ==============================================================================
00232 
00233   if (m_verbose>=3) Cout("  --> Allocate an event buffer for each thread" << endl);
00234   // Instanciation of the event buffer according to the data type
00235   m2p_BufferEvent = new vEvent*[mp_ID->GetNbThreadsForProjection()];
00236   
00237   // Allocate the events per each thread
00238   for (int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
00239   {
00240     // For MODE_LIST events
00241     if (m_dataMode == MODE_LIST) 
00242     {
00243       m2p_BufferEvent[th] = new iEventListSPECT();
00244     }
00245     // For MODE_HISTOGRAM events
00246     if (m_dataMode == MODE_HISTOGRAM)
00247     {
00248       m2p_BufferEvent[th] = new iEventHistoSPECT();
00249     }
00250     // Allocate crystal/view IDs
00251     if (m2p_BufferEvent[th]->AllocateID())
00252     {
00253       Cerr("*****iDataFileSPECT::PrepareDataFile() -> Error while trying to allocate memory for the Event object!" << endl);
00254       return 1;
00255     }
00256   }
00257 
00258   // ==============================================================================
00259   // Deal with specific corrections
00260   // ==============================================================================
00261 
00262   // In case of normalization correction flag, see if we ignore this correction
00263   if (m_normCorrectionFlag)
00264   {
00265     // Affect the ignored flag from the ignored corrections list processed by the oImageDimensionsAndQuantification
00266     m_ignoreNormCorrectionFlag = mp_ID->GetIgnoreNormCorrectionFlag();
00267     // Verbose
00268     if (m_verbose>=2)
00269     {
00270       if (m_ignoreNormCorrectionFlag) Cout("  --> Ignore normalization correction" << endl);
00271       else Cout("  --> Correct for normalization" << endl);
00272     }
00273   }
00274   // In case of scatter correction flag, see if we ignore this correction
00275   if (m_scatCorrectionFlag)
00276   {
00277     // Affect the ignored flag from the ignored corrections list processed by the oImageDimensionsAndQuantification
00278     m_ignoreScatCorrectionFlag = mp_ID->GetIgnoreScatCorrectionFlag();
00279     // Verbose
00280     if (m_verbose>=2)
00281     {
00282       if (m_ignoreScatCorrectionFlag) Cout("  --> Ignore scatter correction" << endl);
00283       else Cout("  --> Correct for scatter events" << endl);
00284     }
00285   }
00286 
00287   // Normal end
00288   return 0;
00289 }
00290 
00291 
00292 
00293 // =====================================================================
00294 // ---------------------------------------------------------------------
00295 // ---------------------------------------------------------------------
00296 // =====================================================================
00297 /*
00298   \fn GetEventFromBuffer()
00299   \param ap_buffer : address pointing to the event to recover
00300   \param a_th : index of the thread from which the function was called
00301   \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
00302   \return the thread-specific  'm2p_BufferEvent' object containing the modality-specific information for the event
00303 */
00304 vEvent* iDataFileSPECT::GetEventFromBuffer(char* ap_buffer, int a_th)
00305 {
00306   #ifdef CASTOR_VERBOSE
00307   // Verbose
00308   if(m_verbose>=4) Cout("iDataFileSPECT::GetEventFromBuffer() ..." << endl);
00309   #endif
00310 
00311   // Work on a copy of the input pointer
00312   char* file_position = ap_buffer;
00313 
00314   // For MODE_LIST SPECT data
00315   if (m_dataMode == MODE_LIST)
00316   {
00317     // Cast the event pointer
00318     iEventListSPECT* event = (dynamic_cast<iEventListSPECT*>(m2p_BufferEvent[a_th]));
00319     // Mandatory time field: [uint32_t (time)]
00320     event->SetTimeInMs(*reinterpret_cast<uint32_t*>(file_position)); 
00321     file_position += sizeof(uint32_t);
00322     // Optional kind: [uint8_t kind]
00323     if (m_eventKindFlag)
00324     {
00325       event->SetKind(*reinterpret_cast<uint8_t*>(file_position));
00326       file_position += sizeof(uint8_t);
00327     }
00328     // Optional scatter correction field: [FLTNBDATA (scatter)]
00329     if (m_scatCorrectionFlag)
00330     {
00331       if (!m_ignoreScatCorrectionFlag) event->SetScatterRate(*reinterpret_cast<FLTNBDATA*>(file_position)); 
00332       file_position += sizeof(FLTNBDATA);
00333     }
00334     // Optional normalization correction field: [FLTNBDATA (norm)]
00335     if (m_normCorrectionFlag)
00336     {
00337       if (!m_ignoreNormCorrectionFlag) event->SetNormalizationFactor(*reinterpret_cast<FLTNBDATA*>(file_position)); 
00338       file_position += sizeof(FLTNBDATA);
00339     }
00340     // Optional POI correction field: [FLTNBDATA (POI1[3])]
00341     for (int i=0; i<3; i++)
00342     {
00343       if (mp_POIDirectionFlag[i])
00344       {
00345         if (!m_ignorePOIFlag) event->SetPOI(i,*reinterpret_cast<FLTNBDATA*>(file_position)); 
00346         file_position += sizeof(FLTNBDATA);
00347       }
00348     }
00349     // Mandatory angular projection ID: [uint32_t (ID1)]
00350     event->SetID1(0, *reinterpret_cast<uint32_t*>(file_position)); 
00351     file_position += sizeof(uint32_t);
00352     // Mandatory crystal ID: [uint32_t (ID2)]
00353     event->SetID2(0, *reinterpret_cast<uint32_t*>(file_position)); 
00354     file_position += sizeof(uint32_t);
00355   }
00356 
00357   // For MODE_HISTOGRAM SPECT DATA
00358   if (m_dataMode == MODE_HISTOGRAM) 
00359   {
00360     // Cast the event pointer
00361     iEventHistoSPECT* event = (dynamic_cast<iEventHistoSPECT*>(m2p_BufferEvent[a_th]));
00362     // Mandatory time field: [uint32_t (time)]
00363     event->SetTimeInMs(*reinterpret_cast<uint32_t*>(file_position)); 
00364     file_position += sizeof(uint32_t);
00365     // Mandatory bin value: [FLTNBDATA bin value]
00366     event->SetEventValue(0, *reinterpret_cast<FLTNBDATA*>(file_position));
00367     file_position += sizeof(FLTNBDATA);
00368     // Optional scatter correction field: [FLTNBDATA (scatter)]
00369     if (m_scatCorrectionFlag)
00370     {
00371       if (!m_ignoreScatCorrectionFlag) event->SetScatterRate(*reinterpret_cast<FLTNBDATA*>(file_position));
00372       file_position += sizeof(FLTNBDATA);
00373     }
00374     // Optional normalization correction field: [FLTNBDATA (norm)]
00375     if (m_normCorrectionFlag)
00376     {
00377       if (!m_ignoreNormCorrectionFlag) event->SetNormalizationFactor(*reinterpret_cast<FLTNBDATA*>(file_position));
00378       file_position += sizeof(FLTNBDATA);
00379     }
00380     // Mandatory angular projection ID: [uint32_t (ID1)]
00381     event->SetID1(0, *reinterpret_cast<uint32_t*>(file_position)); 
00382     file_position += sizeof(uint32_t);
00383     // Mandatory crystal ID: [uint32_t (ID2)]
00384     event->SetID2(0, *reinterpret_cast<uint32_t*>(file_position)); 
00385     file_position += sizeof(uint32_t);
00386   }
00387 
00388   // Return the updated event
00389   return m2p_BufferEvent[a_th];
00390 }
00391 
00392 // =====================================================================
00393 // ---------------------------------------------------------------------
00394 // ---------------------------------------------------------------------
00395 // =====================================================================
00396 /*
00397   \fn CheckSpecificParameters()
00398   \brief  Check parameters specific to SPECT data
00399   \return 0 if success, and positive value otherwise.
00400 */
00401 int iDataFileSPECT::CheckSpecificParameters()
00402 {
00403   // Verbose
00404   if (m_verbose>=3) Cout("iDataFileSPECT::CheckSpecificParameters()" << endl);
00405   
00406   // Error if m_dataType != SPECT
00407   if (m_dataType != TYPE_SPECT)
00408   {
00409     Cerr("***** iDataFileSPECT::CheckSpecificParameters() -> Error, Data type should be SPECT (=1) !'" << endl);
00410     return 1;
00411   }
00412 
00413   if (m_nbOfProjections == 0)
00414   {
00415     Cerr("***** iDataFileSPECT::CheckSpecificParameters() -> Error, number of projections not initialized (should be >0) !'" << endl);
00416     return 1;
00417   }
00418   
00419   if (mp_angles == NULL)
00420   {
00421     Cerr("***** iDataFileSPECT::CheckSpecificParameters() -> Error, Projection angles not initialized !'" << endl);
00422     return 1;
00423   }
00424   
00425   
00426   return 0;
00427 }
00428 
00429 
00430 
00431 // =====================================================================
00432 // ---------------------------------------------------------------------
00433 // ---------------------------------------------------------------------
00434 // =====================================================================
00435 /*
00436   \fn CheckFileSizeConsistency()
00437   \brief  This function is implemented in child classes
00438           Check if file size is consistent.
00439   \return 0 if success, and positive value otherwise.
00440 */
00441 int iDataFileSPECT::CheckFileSizeConsistency()
00442 {
00443   if(m_verbose >=3) Cout("iDataFileSPECT::CheckFileSizeConsistency() ..." << endl);
00444   
00445   // CHECK IF DATAFILE SIZE CORRESPONDS TO THE USER DATA INITIALIZATION 
00446   m2p_dataFile[0]->seekg(0, ios::end);
00447   int64_t sizeInBytes = m2p_dataFile[0]->tellg();
00448         
00449   if (m_totalNbEvents*m_sizeEvent != sizeInBytes)
00450   {
00451     Cerr("-----------------------------------------------------------------------------------------------------------------------------------------------" << endl);
00452     Cerr("***** iDataFileSPECT::CheckFileSizeConsistency() -> Error : Datafile size is not consistent with the information provided by the user/datafile!" << endl);
00453     Cerr("***** iDataFileSPECT::CheckFileSizeConsistency() -> Expected size : "<< m_totalNbEvents*m_sizeEvent << endl);
00454     Cerr("***** iDataFileSPECT::CheckFileSizeConsistency() -> Actual size : "<< sizeInBytes << endl << endl);
00455 
00456     Cerr("***** iDataFileSPECT::CheckFileSizeConsistency() -> ADDITIONAL INFORMATION ABOUT THE DATAFILE INITIALIZATION : " << endl);
00457 
00458 
00459     if(m_eventKindFlag)
00460       Cerr("      iDataFileSPECT::CheckFileSizeConsistency() -> Coincidence kind (trues, scatter, ...) term is enabled " << endl);
00461     else
00462       Cerr("      iDataFileSPECT::CheckFileSizeConsistency() -> No informations about the kind of coincidences in the data " << endl);
00463       
00464     if(m_normCorrectionFlag)
00465       Cerr("      iDataFileSPECT::CheckFileSizeConsistency() -> Normalization correction term is enabled " << endl);
00466     else
00467       Cerr("      iDataFileSPECT::CheckFileSizeConsistency() -> No normalization correction terms in the data " << endl);
00468       
00469     if(m_scatCorrectionFlag)
00470       Cerr("      iDataFileSPECT::CheckFileSizeConsistency() -> Scatter correction term is enabled " << endl);
00471     else
00472       Cerr("      iDataFileSPECT::CheckFileSizeConsistency() -> No scatter correction terms in the data " << endl);
00473 
00474     Cerr("      iDataFileSPECT::CheckFileSizeConsistency() -> Calibration factor value is : " << m_calibrationFactor << endl);
00475     Cerr("      iDataFileSPECT::CheckFileSizeConsistency() -> Number of bins are equal to "<<mp_nbOfBins[0]<<","<< mp_nbOfBins[1]<<" for X,Y axis respectively." << endl);
00476 
00477     if(mp_POIResolution[0]<0)
00478       Cerr("      iDataFileSPECT::CheckFileSizeConsistency() -> No POI enabled on the X axis " << endl);
00479     else
00480       Cerr("      iDataFileSPECT::CheckFileSizeConsistency() -> POI resolution on the X axis is : " << mp_POIResolution[0] << endl);
00481 
00482     if(mp_POIResolution[1]<0)
00483       Cerr("      iDataFileSPECT::CheckFileSizeConsistency() -> No POI enabled on the Y axis " << endl);
00484     else
00485       Cerr("      iDataFileSPECT::CheckFileSizeConsistency() -> POI resolution on the Y axis is : " << mp_POIResolution[1] << endl);
00486 
00487     if(mp_POIResolution[2]<0)
00488       Cerr("      iDataFileSPECT::CheckFileSizeConsistency() -> No POI enabled on the Z axis " << endl);
00489     else
00490       Cerr("      iDataFileSPECT::CheckFileSizeConsistency() -> POI resolution on the Z axis is : " << mp_POIResolution[2] << endl);
00491     Cerr("---------------------------------------------------------------------------------------------------------------------------------------------" << endl);
00492 
00493     return 1;
00494   }
00495 
00496 
00497 
00498   // Depending on the verbosity, output all the datafile initialization information as feedback for the user
00499   if(m_verbose >=4)
00500   {
00501     Cout("----------------------------------------------------------------Datafile initialization -------------------------------------------------------------" << endl);
00502 
00503     if(m_eventKindFlag)
00504       Cout("  --> Coincidence kind (trues, scatter, ...) term is enabled " << endl);
00505     else
00506       Cout("  --> No informations about the kind of coincidences in the data " << endl);
00507       
00508     if(m_normCorrectionFlag)
00509       Cout("  --> Normalization correction term is enabled " << endl);
00510     else
00511       Cout("  --> No normalization correction terms in the data " << endl);
00512       
00513     if(m_scatCorrectionFlag)
00514       Cout("  --> Scatter correction term is enabled " << endl);
00515     else
00516       Cout("  --> No scatter correction terms in the data " << endl);
00517 
00518     Cout("  --> Calibration factor value is : " << m_calibrationFactor << endl);
00519     Cout("  --> Number of bins are equal to "<<mp_nbOfBins[0]<<","<< mp_nbOfBins[1]<<" for X,Y axis respectively." << endl);
00520 
00521     if(mp_POIResolution[0]<0)
00522       Cout("  --> No POI enabled on the X axis " << endl);
00523     else
00524       Cout("  --> POI resolution on the X axis is : " << mp_POIResolution[0] << endl);
00525 
00526     if(mp_POIResolution[1]<0)
00527       Cout("  --> No POI enabled on the Y axis " << endl);
00528     else
00529       Cout("  --> POI resolution on the Y axis is : " << mp_POIResolution[1] << endl);
00530 
00531     if(mp_POIResolution[2]<0)
00532       Cout("  --> No POI enabled on the Z axis " << endl);
00533     else
00534       Cout("  --> POI resolution on the Z axis is : " << mp_POIResolution[2] << endl);
00535     Cout("---------------------------------------------------------------------------------------------------------------------------------------------" << endl << endl);
00536     
00537   }
00538 
00539   // End
00540   return 0;
00541 }
00542 
00543 
00544 
00545 
00546 // =====================================================================
00547 // ---------------------------------------------------------------------
00548 // ---------------------------------------------------------------------
00549 // =====================================================================
00550 /*
00551   \fn      iDataFileSPECT::InitAngles()
00552   \param   ap_angles
00553   \brief   allocate memory for the mp_angles variable using m_nbProjections
00554            and initialize the projection angles with the provided list of values
00555   \return  0 if success, positive value otherwise
00556 */
00557 int iDataFileSPECT::InitAngles(FLTNB* ap_angles)
00558 {
00559   if(m_nbOfProjections == 0)
00560   {
00561     Cerr("***** iDataFileSPECT::InitAngles() -> Error, number of projection angles not initialized !'" << endl);
00562     return 1;
00563   }
00564   
00565   mp_angles = new FLTNB[m_nbOfProjections];
00566   
00567   for(size_t a=0 ; a<m_nbOfProjections ; a++)
00568     mp_angles[a] = ap_angles[a];
00569 
00570   return 0;
00571 }
00572 
00573 
00574 
00575 
00576 // =====================================================================
00577 // ---------------------------------------------------------------------
00578 // ---------------------------------------------------------------------
00579 // =====================================================================
00580 /*
00581   \fn      iDataFileSPECT::InitCorToDetectorDistance()
00582   \param   ap_CORtoDetectorDistance
00583   \brief   allocate memory for the ap_CORtoDetectorDistance variable
00584            using m_nbProjections, and initialize the projection angles
00585            with the provided list of values
00586   \return  0 if success, positive value otherwise
00587 */
00588 int iDataFileSPECT::InitCorToDetectorDistance(FLTNB* ap_CORtoDetectorDistance)
00589 {
00590   if(m_nbOfProjections == 0)
00591   {
00592     Cerr("***** iDataFileSPECT::InitAngles() -> Error, number of projection angles not initialized !'" << endl);
00593     return 1;
00594   }
00595 
00596   mp_CORtoDetectorDistance = new FLTNB[m_nbOfProjections];
00597 
00598   for(size_t a=0 ; a<m_nbOfProjections ; a++)
00599     mp_CORtoDetectorDistance[a] = ap_CORtoDetectorDistance[a];
00600 
00601   return 0;
00602 }
00603     
00604     
00605     
00606     
00607 //PROJECTION SCRIPT FUNCTIONS
00608 // =====================================================================
00609 // ---------------------------------------------------------------------
00610 // ---------------------------------------------------------------------
00611 // =====================================================================
00612 
00613 /*
00614   \fn PROJ_InitFile()
00615   \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)
00616   \todo warn the user a datafile with the same name will be erased (eventually add an option to disable the warning)
00617   \return 0 if success, and positive value otherwise.
00618 */
00619 int iDataFileSPECT::PROJ_InitFile()
00620 {
00621   if(m_verbose >=3) Cout("iDataFileSPECT::PROJ_InitFile() ..." << endl);
00622   
00623   m_startTimeInSec = 0.; //Std initialization for projection
00624   m_durationInSec = 1.; //Std initialization for projection
00625   m_totalNbEvents = 0; //Std initialization for projection
00626   m_calibrationFactor =  1.;
00627   m_isotope = "unknown";
00628   m_scatCorrectionFlag = false;
00629   m_normCorrectionFlag = false;
00630   mp_POIResolution[0] = -1.;
00631   mp_POIResolution[1] = -1.;
00632   mp_POIResolution[2] = -1.;
00633 
00634   // Instanciate a fstream datafile for each thread
00635   m2p_dataFile = new fstream*[mp_ID->GetNbThreadsForProjection()];
00636 
00637   // Set name of the projection data header
00638   sOutputManager* p_OutMgr;
00639   p_OutMgr = sOutputManager::GetInstance();
00640   string path_name = p_OutMgr->GetPathName();
00641   string img_name = p_OutMgr->GetBaseName();
00642   m_headerFileName = path_name.append(img_name).append("_CstrProj").append(".Cdh");
00643   
00644   for (int th=0 ; th<mp_ID->GetNbThreadsForProjection() ; th++)
00645   {
00646     m_dataFileName = m_headerFileName.substr(0, m_headerFileName.find_last_of(".")).append(".Cdf"); // Generate datafile name from header file
00647 
00648     // Projeted data will be written in several files (corresponding to the number of thread) to be concatenated at the end of the projection process.   
00649     stringstream ss;
00650     ss << th;
00651 
00652     string datafile_name = m_dataFileName;
00653     datafile_name.append("_").append(ss.str());
00654     
00655     m2p_dataFile[th] = new fstream( datafile_name.c_str(), ios::binary | ios::out | ios::trunc);
00656   }
00657 
00658   //remove content from the output data file, in case it already exists
00659   //todo warn the user a datafile with the same name will be erased (eventually add an option to disable the warning)
00660   ofstream output_file(m_dataFileName.c_str(), ios::out | ios::trunc);
00661   output_file.close();
00662   
00663   if(m_verbose>=3) Cout("iDataFileSPECT::PROJ_InitFile()-> output datafile name :" << m_dataFileName << endl); 
00664     
00665   return 0;
00666 }
00667 
00668 
00669 
00670 
00671 // =====================================================================
00672 // ---------------------------------------------------------------------
00673 // ---------------------------------------------------------------------
00674 // =====================================================================
00675 /*
00676   \fn PROJ_WriteEvent(vEvent* ap_Event, int a_th)
00677   \param ap_Event : event containing the data to write
00678   \param a_th : index of the thread from which the function was called
00679   \brief  Write event according to the chosen type of data
00680   \todo   Depending of the RAM load FLAG, either write the data in *nbThreads* different files which will be concatenated at the end (current implementation), 
00681           or write data in buffers, to be flushed at the end of projection loop.
00682   \todo   Projection for list-mode
00683   \return 0 if success, and positive value otherwise.
00684 */
00685 int iDataFileSPECT::PROJ_WriteEvent(vEvent* ap_Event, int a_th)
00686 {
00687   #ifdef CASTOR_VERBOSE
00688   // Verbose
00689   if(m_verbose>=4) Cout("iDataFileSPECT::PROJ_WriteEvent() ..."<< endl); 
00690   #endif
00691   
00692   if(m_dataMode == MODE_LIST) 
00693   {
00694     // TODO should create as many vEvent as (int)fp.
00695     if(PROJ_WriteListEvent((iEventListSPECT*)ap_Event, a_th))
00696     {
00697       Cerr("*****iDataFileSPECT::PROJ_WriteEvent() -> Error while trying to write projection datafile (list-mode)" << endl);
00698       return 1;
00699     }
00700   }
00701 
00702   if(m_dataMode == MODE_HISTOGRAM)
00703   {
00704     if(PROJ_WriteHistoEvent((iEventHistoSPECT*)ap_Event, a_th))
00705     {
00706       Cerr("*****iDataFileSPECT::PROJ_WriteEvent() -> Error while trying to write projection datafile (histogram)" << endl);
00707       return 1;
00708     }
00709   }
00710 
00711   return 0;
00712 }
00713 
00714 
00715 // =====================================================================
00716 // ---------------------------------------------------------------------
00717 // ---------------------------------------------------------------------
00718 // =====================================================================
00719 /*
00720   \fn PROJ_WriteHistoEvent()
00721   \param ap_Event : event containing the data to write
00722   \param a_th : index of the thread from which the function was called
00723   \brief  Write a SPECT histogram event
00724   \return 0 if success, and positive value otherwise.
00725 */
00726 int iDataFileSPECT::PROJ_WriteHistoEvent(iEventHistoSPECT* ap_Event, int a_th)
00727 {
00728   #ifdef CASTOR_VERBOSE
00729   // Verbose
00730   if(m_verbose>=4) Cout("iDataFileSPECT::PROJ_WriteHistoEvent() ..."<< endl); 
00731   #endif
00732   
00733   // Write sequentially each field of the event according to the type of the event.
00734   m2p_dataFile[a_th]->clear();
00735   
00736   uint32_t time = ap_Event->GetTimeInMs();
00737   m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&time), sizeof(uint32_t));
00738   
00739   FLTNB event_value = ap_Event->GetEventValue(0);
00740   m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&event_value), sizeof(FLTNB));
00741 
00742   if(m_scatCorrectionFlag)   
00743   {
00744     FLTNB scat_rate = ap_Event->GetEventScatRate();
00745     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&scat_rate), sizeof(FLTNB));
00746   }
00747   
00748   if(m_normCorrectionFlag)   
00749   {
00750     FLTNB norm_corr_factor = ap_Event->GetNormFactor();
00751     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&norm_corr_factor), sizeof(FLTNB));
00752   }
00753 
00754   uint32_t id1 = ap_Event->GetID1(0);
00755   uint32_t id2 = ap_Event->GetID2(0);
00756   m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id1), sizeof(uint32_t));
00757   m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id2), sizeof(uint32_t));
00758 
00759   return 0;
00760 }
00761 
00762 
00763 // =====================================================================
00764 // ---------------------------------------------------------------------
00765 // ---------------------------------------------------------------------
00766 // =====================================================================
00767 /*
00768   \fn PROJ_WriteListEvent()
00769   \param ap_Event : event containing the data to write
00770   \param a_th : index of the thread from which the function was called
00771   \brief  Write a SPECT list-mode event
00772   \return 0 if success, and positive value otherwise.
00773 */
00774 int iDataFileSPECT::PROJ_WriteListEvent(iEventListSPECT* ap_Event, int a_th)
00775 {
00776   #ifdef CASTOR_VERBOSE
00777   // Verbose
00778   if(m_verbose>=4) Cout("iDataFileSPECT::PROJ_WriteListEvent() ..."<< endl); 
00779   #endif
00780   
00781   // Write sequentially each field of the event according to the type of the event.
00782   m2p_dataFile[a_th]->clear();
00783   
00784   uint32_t time = ap_Event->GetTimeInMs();
00785   m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&time), sizeof(uint32_t));
00786 
00787   if(m_eventKindFlag) 
00788   {
00789     uint8_t event_kind = ap_Event->GetKind();
00790     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&event_kind), sizeof(uint8_t));
00791   }
00792   
00793   if(m_scatCorrectionFlag)   
00794   {
00795     FLTNB scat_rate = ap_Event->GetEventScatRate();
00796     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&scat_rate), sizeof(FLTNB));
00797   }
00798   
00799   if(m_normCorrectionFlag)   
00800   {
00801     FLTNB norm_corr_factor = ap_Event->GetNormFactor();
00802     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&norm_corr_factor), sizeof(FLTNB));
00803   }
00804   
00805   if(mp_POIResolution[0]>0)
00806   {
00807     FLTNB POI = ap_Event->GetPOI(0);
00808     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI), sizeof(FLTNB));
00809   }
00810 
00811   if(mp_POIResolution[1]>0)
00812   {
00813     FLTNB POI = ap_Event->GetPOI(1);
00814     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI), sizeof(FLTNB));
00815   }
00816 
00817   if(mp_POIResolution[2]>0)
00818   {
00819     FLTNB POI = ap_Event->GetPOI(2);
00820     m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&POI), sizeof(FLTNB));
00821   }
00822 
00823   uint32_t id1 = ap_Event->GetID1(0);
00824   uint32_t id2 = ap_Event->GetID2(0);
00825   m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id1), sizeof(uint32_t));
00826   m2p_dataFile[a_th]->write(reinterpret_cast<char*>(&id2), sizeof(uint32_t));
00827 
00828   return 0;
00829 }
00830 
00831 
00832 
00833 
00834 
00835 // =====================================================================
00836 // ---------------------------------------------------------------------
00837 // ---------------------------------------------------------------------
00838 // =====================================================================
00839 /*
00840   \fn PROJ_WriteHeader()
00841   \brief  Generate a header file according to the projection and data output informations.
00842           Used by Projection algorithm.
00843   \return 0 if success, and positive value otherwise.
00844 */
00845 int iDataFileSPECT::PROJ_WriteHeader()
00846 {
00847   // Verbose
00848   if(m_verbose>=3) Cout("iDataFileSPECT::PROJ_WriteHeader() ..."<< endl); 
00849 
00850   fstream headerFile;
00851   stringstream ss;
00852   
00853   headerFile.open(m_headerFileName.c_str(), ios::out);
00854 
00855   headerFile << "Data filename:" << "    " << GetFileFromPath(m_dataFileName).c_str() << endl; 
00856   headerFile << "Number of events:" << "    " << m_totalNbEvents << endl; 
00857 
00858   //- Flag: list-mode or histogram mode
00859   headerFile << "Data mode:" << "    " << m_dataMode << endl; 
00860   // Flag: PET, SPECT or TRANSMISSION
00861   headerFile << "Data type: " << "    " << "SPECT" << endl;
00862 
00863   headerFile << "Start time (s):" << "    " << m_startTimeInSec << endl; 
00864 
00865   headerFile << "Duration (s):" << "    " << m_durationInSec << endl; 
00866 
00867   sScannerManager* p_scannermanager; 
00868   p_scannermanager = sScannerManager::GetInstance(); 
00869 
00870   headerFile << "Scanner name:" << "    " << p_scannermanager->GetScannerName() << endl; 
00871 
00872   
00873   if(mp_nbOfBins[0] != 0 && mp_nbOfBins[1] != 0)
00874     headerFile << "Number of bins:" << "    " << mp_nbOfBins[0] << "," << mp_nbOfBins[1] << endl; 
00875   
00876   headerFile << "Number of projections:" << "    " << m_nbOfProjections << endl; 
00877 
00878   headerFile << "Projection angles:" << "    "; 
00879   
00880   headerFile << mp_angles[0]; 
00881   for(int a=1 ; a<m_nbOfProjections ; a++)
00882     headerFile << ", " << mp_angles[a]; 
00883 
00884   headerFile << endl;
00885   if(m_nbHeads>1)
00886   {
00887     headerFile << "Global distance camera surface to COR:" << "    " << mp_CORtoDetectorDistance[0];
00888     for(int h=1 ; h<m_nbHeads ; h++) headerFile << "," << mp_CORtoDetectorDistance[h] << endl;
00889     headerFile << endl;
00890   }
00891   
00892   else if(mp_CORtoDetectorDistance[0] > 0)
00893     headerFile << "Global distance camera surface to COR:" << "    " << mp_CORtoDetectorDistance[0] << endl;
00894   
00895   // Optional fields
00896   headerFile << "Calibration factor:" << "    " << m_calibrationFactor << endl;
00897   headerFile << "Isotope:" << "    " << m_isotope << endl; 
00898   headerFile << "DOI capability:" << "    " << mp_POIResolution[0] << "," << mp_POIResolution[1] << "," << mp_POIResolution[2] << endl; 
00899   headerFile << "Normalization correction flag:" << "    " << m_normCorrectionFlag << endl; 
00900   headerFile << "Scatter correction flag:" << "    " << m_scatCorrectionFlag << endl; 
00901   string rot_direction = (m_headRotDirection == GEO_ROT_CCW) ? "CCW" : "CW";
00902   headerFile << "Head rotation direction:" << "    " << rot_direction << endl; 
00903   
00904   headerFile.close();
00905 
00906   return 0;
00907 }
00908 
00909 
00910 
00911 // =====================================================================
00912 // ---------------------------------------------------------------------
00913 // ---------------------------------------------------------------------
00914 // =====================================================================
00915 /*
00916   \fn PROJ_GetScannerSpecificParameters()
00917   \brief Get SPECT specific parameters for projections from the scanner object, through the scannerManager.
00918   \return 0 if success, positive value otherwise
00919 */
00920 int iDataFileSPECT::PROJ_GetScannerSpecificParameters()
00921 {
00922   // Verbose
00923   if(m_verbose>=3) Cout("iDataFileSPECT::PROJ_GetScannerSpecificParameters() ..."<< endl); 
00924   
00925   sScannerManager* p_scannermanager;
00926   p_scannermanager = sScannerManager::GetInstance(); 
00927    
00928   // Create pointers dedicated to recover the addresses of the member variables of the scanner object
00929   FLTNB* p_angles = NULL;
00930   FLTNB* p_CORtoDetectorDistance = NULL; 
00931   FLTNB p_pixSizeXY[2] ; // not used here
00932   
00933   // Get pointers to SPECT specific parameters in scanner
00934   if(p_scannermanager->GetSPECTSpecificParameters(&m_nbOfProjections, &m_nbHeads, mp_nbOfBins, p_pixSizeXY, p_angles, p_CORtoDetectorDistance, &m_headRotDirection) )
00935   {
00936     Cerr("*****iDataFileSPECT::PROJ_GetScannerSpecificParameters() -> An error occurred while trying to get SPECT geometric parameters from the scanner object !" << endl);
00937     return 1;
00938   }
00939 
00940   // In projection, mp_CORtoDetectorDistance is allocated according to the number of heads, and not the number of projections
00941   // (Projection does not currently allow to set a radius specific to the projection angles)
00942   mp_CORtoDetectorDistance = new FLTNB[m_nbHeads];
00943 
00944   // Retrieve SPECT distance between the detector and center of rotation
00945   for(int h=0 ; h<m_nbHeads ; h++)
00946     mp_CORtoDetectorDistance[h] = p_CORtoDetectorDistance[0];
00947 
00948   // Retrieve projection angles
00949   mp_angles = new FLTNB[m_nbOfProjections];
00950 
00951   for(int a=0 ; a<m_nbOfProjections ; a++)
00952     mp_angles[a] = p_angles[a];
00953       
00954   return 0;
00955 }
 All Classes Files Functions Variables Typedefs Defines