/** * @file * @author Christian Simon * @since 2017-07-03 */ #include "CbmTofSignalBuffer.h" #include "CbmTofDigiExp.h" #include "CbmMatch.h" #include "FairLogger.h" #include // --------------------------------------------------------------------------- CbmTofSignalBuffer::CbmTofSignalBuffer(Int_t iNChannels) : fChannelBuffer(), fMergedDigiIndices(), fbIgnoreInterference(kFALSE) { for(Int_t iChIndex = 0; iChIndex < iNChannels; iChIndex++) { fChannelBuffer.emplace(iChIndex, std::vector()); fMergedDigiIndices.emplace(iChIndex, std::set()); } for(auto & itChannel : fChannelBuffer) { (itChannel.second).reserve(10); } } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- CbmTofSignalBuffer::~CbmTofSignalBuffer() { // There should be no need to delete anything from the channel buffer at this // point. All digis should have been read out and sent to the DAQ buffer. for(auto & itChannel : fChannelBuffer) { for(auto itDigi = (itChannel.second).cbegin(); itDigi != (itChannel.second).cend(); ) { if(*itDigi) { delete *itDigi; } ++itDigi; } } } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- void CbmTofSignalBuffer::Fill(Int_t iChannelAddress, CbmTofDigiExp*& Digi) { if(0 > iChannelAddress || fChannelBuffer.size() <= iChannelAddress) { LOG(FATAL)<& tDigiVector = fChannelBuffer.at(iChannelAddress); CbmTofDigiExp* tNewDigi(NULL); if(!fbIgnoreInterference) { // Loop over all digis in the buffer with the same channel address. // Pick the first to which the interference criterion applies and merge the // two signals. for(auto itBufferedDigi = tDigiVector.begin(); itBufferedDigi != tDigiVector.end(); ) { if(CheckInterference(Digi, *itBufferedDigi)) { // Create a merged digi object. Modify(*itBufferedDigi, Digi, tNewDigi, iChannelAddress); // Delete the parents of the merged digi object. if(*itBufferedDigi) { delete *itBufferedDigi; } // Calling std::vector::erase on an element in the middle of the container // evokes a left-shift reallocation of all elements on the right-hand side // of the deleted one. To avoid this inefficiency, we overwrite the current // element with the last element and then pop the latter. *itBufferedDigi = tDigiVector.back(); tDigiVector.pop_back(); delete Digi; bDataFound = kTRUE; break; } else { ++itBufferedDigi; } } } if(bDataFound) { Fill(iChannelAddress, tNewDigi); } else { tDigiVector.push_back(Digi); } } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- Int_t CbmTofSignalBuffer::ReadOutData(Int_t iChannelAddress, Double_t dTimeLimit, std::vector& DigiVector) { if(!DigiVector.empty()) { DigiVector.clear(); } if(0 > iChannelAddress || fChannelBuffer.size() <= iChannelAddress) { LOG(FATAL)<& tBufferVector = fChannelBuffer.at(iChannelAddress); // Loop over all digis in the buffer with the same channel address. for(auto itBufferedDigi = tBufferVector.begin(); itBufferedDigi != tBufferVector.end(); ) { CbmTofDigiExp* tDigi = *itBufferedDigi; if(tDigi->GetTime() + tDigi->GetTot() < dTimeLimit || 0. > dTimeLimit) { iNDigis++; DigiVector.push_back(tDigi); *itBufferedDigi = tBufferVector.back(); tBufferVector.pop_back(); } else { ++itBufferedDigi; } } // Time-sort the output vector w.r.t. leading edge time. // This is needed for proper TDC channel dead time treatment in class CbmTofCounter. // Since the buffer is a vector of pointers to objects and not a vector of objects // a lambda function is used here to implement the sorting. sort(DigiVector.begin(), DigiVector.end(), [] (const CbmTofDigiExp* Digi1, const CbmTofDigiExp* Digi2) { return Digi1->GetTime() < Digi2->GetTime();}); return iNDigis; } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- Bool_t CbmTofSignalBuffer::CheckInterference(CbmTofDigiExp* FirstDigi, CbmTofDigiExp* SecondDigi) { if(FirstDigi->GetTime() + FirstDigi->GetTot() < SecondDigi->GetTime()) { return kFALSE; } if(SecondDigi->GetTime() + SecondDigi->GetTot() < FirstDigi->GetTime()) { return kFALSE; } return kTRUE; } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- void CbmTofSignalBuffer::Modify(CbmTofDigiExp* OldDigi1, CbmTofDigiExp* OldDigi2, CbmTofDigiExp*& NewDigi, Int_t iChannelAddress) { NewDigi = new CbmTofDigiExp(); NewDigi->SetAddress(OldDigi1->GetAddress()); Int_t iNewUniqueID(0); Double_t dNewLeadingEdgeTime(0.); // The earliest of the two leading edges becomes the new leading edge. if(OldDigi1->GetTime() <= OldDigi2->GetTime()) { iNewUniqueID = OldDigi1->GetUniqueID(); dNewLeadingEdgeTime = OldDigi1->GetTime(); (fMergedDigiIndices.at(iChannelAddress)).emplace(OldDigi2->GetUniqueID()); } else { iNewUniqueID = OldDigi2->GetUniqueID(); dNewLeadingEdgeTime = OldDigi2->GetTime(); (fMergedDigiIndices.at(iChannelAddress)).emplace(OldDigi1->GetUniqueID()); } // The latest of the two trailing edges becomes the new trailing edge. Double_t dNewTrailingEdgeTime = std::max(OldDigi1->GetTime() + OldDigi1->GetTot(), OldDigi2->GetTime() + OldDigi2->GetTot()); NewDigi->SetTime(dNewLeadingEdgeTime); NewDigi->SetTot(dNewTrailingEdgeTime - dNewLeadingEdgeTime); NewDigi->SetUniqueID(iNewUniqueID); // Add all CbmLink objects of the parent digis to the new digi. CbmMatch* tNewMatch = new CbmMatch(); tNewMatch->AddLinks(*OldDigi1->GetMatch()); tNewMatch->AddLinks(*OldDigi2->GetMatch()); NewDigi->SetMatch(tNewMatch); } // --------------------------------------------------------------------------- ClassImp(CbmTofSignalBuffer)