![]() |
CASToR
1.0
Tomographic Reconstruction (PET/SPECT)
|
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 }