/** * @file * @author Christian Simon * @since 2018-07-05 */ #include "CbmTofBuildPointEvents.h" #include "CbmTimeSlice.h" #include "CbmMCEventList.h" #include "CbmTofPoint.h" #include "CbmTofDigiExp.h" #include "CbmTofHit.h" #include "CbmMatch.h" #include "CbmTofGeoHandler.h" #include "CbmTofDef.h" #include "FairLogger.h" #include "FairRootManager.h" #include "FairFileSource.h" #include "TClonesArray.h" #include "TMath.h" #include #include // --------------------------------------------------------------------------- CbmTofBuildPointEvents::CbmTofBuildPointEvents() : FairTask("TofBuildPointEvents"), fFileSource(NULL), fTimeSliceHeader(NULL), fInputMCEventList(NULL), fOutputMCEventList(NULL), fTofInputPoints(NULL), fTofInputDigis(NULL), fTofInputHits(NULL), fTofInputHitDigiMatch(NULL), fTofInputHitPointMatch(NULL), fTofInputPointHitMatch(NULL), fTofOutputPoints(NULL), fTofOutputDigis(NULL), fTofOutputHits(NULL), fTofOutputHitDigiMatch(NULL), fTofOutputHitPointMatch(NULL), fTofOutputPointHitMatch(NULL), fdEventWindow(0.), fNominalTriggerCounterMultiplicity(), fiTriggerMultiplicity(0), fGeoHandler(new CbmTofGeoHandler()), fbMCEventBuilding(kFALSE), fiNEvents(0), fbProcessHits(kFALSE), fiFileIndex(0), fInactiveCounterSides() { fGeoHandler->Init(kFALSE); } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- CbmTofBuildPointEvents::~CbmTofBuildPointEvents() { if(fGeoHandler) { delete fGeoHandler; } } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- void CbmTofBuildPointEvents::Exec(Option_t*) { if(fbMCEventBuilding) { std::map, std::set> EventPoints; for(Int_t iPoint = 0; iPoint < fTofInputPoints->GetEntriesFast(); iPoint++) { const CbmTofPoint* tPoint = dynamic_cast(fTofInputPoints->At(iPoint)); Int_t iFileID = tPoint->GetUniqueID(); Int_t iEventID = tPoint->GetEventID(); // Do not build events for dark points. if(-1 < iEventID) { auto & CurrentEventPoints = EventPoints[std::make_pair(iFileID, iEventID)]; CurrentEventPoints.emplace(iPoint); } } for(auto const & EventMapPair : EventPoints) { const std::set& CurrentEventPoints = EventMapPair.second; std::set CounterMultiplicity; for(auto const & iPoint : CurrentEventPoints) { const CbmTofPoint* tPoint = dynamic_cast(fTofInputPoints->At(iPoint)); Int_t iDetectorID = tPoint->GetDetectorID(); CounterMultiplicity.emplace(iDetectorID); } std::set ActualTriggerCounterMultiplicity; std::set_intersection(CounterMultiplicity.begin(), CounterMultiplicity.end(), fNominalTriggerCounterMultiplicity.begin(), fNominalTriggerCounterMultiplicity.end(), std::inserter(ActualTriggerCounterMultiplicity, ActualTriggerCounterMultiplicity.begin())); if(ActualTriggerCounterMultiplicity.size() >= fiTriggerMultiplicity) { FindEventObjects(CurrentEventPoints, kFALSE); FairRootManager::Instance()->Fill(); fiNEvents++; fOutputMCEventList->Clear(""); fTofOutputPoints->Delete(); fTofOutputDigis->Delete(); if(fbProcessHits) { fTofOutputHits->Delete(); fTofOutputHitDigiMatch->Delete(); fTofOutputHitPointMatch->Delete(); fTofOutputPointHitMatch->Delete(); } } } } else { std::set CurrentEventPoints; std::set CounterMultiplicity; // Make sure that the time stamp of the first point in every time slice // is considered a hypothetical event start time. Double_t dEventStartTime = DBL_MIN; for(Int_t iPoint = 0; iPoint < fTofInputPoints->GetEntriesFast(); iPoint++) { const CbmTofPoint* tPoint = dynamic_cast(fTofInputPoints->At(iPoint)); Int_t iDetectorID = tPoint->GetDetectorID(); Double_t dPointTime = tPoint->GetTime(); if(dPointTime - dEventStartTime > fdEventWindow) { std::set ActualTriggerCounterMultiplicity; std::set_intersection(CounterMultiplicity.begin(), CounterMultiplicity.end(), fNominalTriggerCounterMultiplicity.begin(), fNominalTriggerCounterMultiplicity.end(), std::inserter(ActualTriggerCounterMultiplicity, ActualTriggerCounterMultiplicity.begin())); if(ActualTriggerCounterMultiplicity.size() >= fiTriggerMultiplicity) { FindEventObjects(CurrentEventPoints, kTRUE); FairRootManager::Instance()->Fill(); fiNEvents++; fOutputMCEventList->Clear(""); fTofOutputPoints->Delete(); fTofOutputDigis->Delete(); if(fbProcessHits) { fTofOutputHits->Delete(); fTofOutputHitDigiMatch->Delete(); fTofOutputHitPointMatch->Delete(); fTofOutputPointHitMatch->Delete(); } } CounterMultiplicity.clear(); CurrentEventPoints.clear(); dEventStartTime = dPointTime; } CounterMultiplicity.emplace(iDetectorID); CurrentEventPoints.emplace(iPoint); // Force a check of the event building condition when the last point in // the input timeslice is being processed. The event building process // is limited to one timeslice only, i.e. an event must not comprise points // from subsequent timeslices. if(fTofInputPoints->GetEntriesFast() - 1 == iPoint) { std::set ActualTriggerCounterMultiplicity; std::set_intersection(CounterMultiplicity.begin(), CounterMultiplicity.end(), fNominalTriggerCounterMultiplicity.begin(), fNominalTriggerCounterMultiplicity.end(), std::inserter(ActualTriggerCounterMultiplicity, ActualTriggerCounterMultiplicity.begin())); if(ActualTriggerCounterMultiplicity.size() >= fiTriggerMultiplicity) { FindEventObjects(CurrentEventPoints, kTRUE); FairRootManager::Instance()->Fill(); fiNEvents++; fOutputMCEventList->Clear(""); fTofOutputPoints->Delete(); fTofOutputDigis->Delete(); if(fbProcessHits) { fTofOutputHits->Delete(); fTofOutputHitDigiMatch->Delete(); fTofOutputHitPointMatch->Delete(); fTofOutputPointHitMatch->Delete(); } } } } } } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- InitStatus CbmTofBuildPointEvents::Init() { if(!FairRootManager::Instance()) { LOG(ERROR)<<"FairRootManager not found."<(FairRootManager::Instance()->GetSource()); if(!fFileSource) { LOG(ERROR)<<"Could not get pointer to FairFileSource."<(FairRootManager::Instance()->GetObject("TimeSlice.")); if(!fTimeSliceHeader) { LOG(ERROR)<<"Could not retrieve branch 'TimeSlice.' from FairRootManager."<(FairRootManager::Instance()->GetObject("MCEventList.")); if(!fInputMCEventList) { LOG(ERROR)<<"Could not retrieve branch 'MCEventList.' from FairRootManager."<Register("EventList.", "EventList", fOutputMCEventList, IsOutputBranchPersistent("EventList.")); TString tInputPointBranchName = "ATofPointTB"; TString tInputDigiBranchName = "ATofDigiExp"; TString tInputHitBranchName = "ATofHit"; TString tInputHitDigiMatchBranchName = "ATofDigiMatch"; TString tInputHitPointMatchBranchName = "ATofHitMatch"; TString tInputPointHitMatchBranchName = "ATofPointMatch"; TString tOutputPointBranchName = "TofPointTB"; TString tOutputDigiBranchName = "TofDigiExp"; TString tOutputHitBranchName = "TofHit"; TString tOutputHitDigiMatchBranchName = "TofDigiMatch"; TString tOutputHitPointMatchBranchName = "TofHitMatch"; TString tOutputPointHitMatchBranchName = "TofPointMatch"; fTofInputPoints = dynamic_cast(FairRootManager::Instance()->GetObject(tInputPointBranchName)); if(!fTofInputPoints) { LOG(ERROR)<(FairRootManager::Instance()->GetObject(tInputDigiBranchName)); if(!fTofInputDigis) { LOG(ERROR)<(FairRootManager::Instance()->GetObject(tInputHitBranchName)); if(fTofInputHits) { fTofInputHitDigiMatch = dynamic_cast(FairRootManager::Instance()->GetObject(tInputHitDigiMatchBranchName)); if(!fTofInputHitDigiMatch) { LOG(ERROR)<(FairRootManager::Instance()->GetObject(tInputHitPointMatchBranchName)); if(!fTofInputHitPointMatch) { LOG(ERROR)<(FairRootManager::Instance()->GetObject(tInputPointHitMatchBranchName)); if(!fTofInputPointHitMatch) { LOG(ERROR)<Register(tOutputPointBranchName, "TOF event points", fTofOutputPoints, IsOutputBranchPersistent(tOutputPointBranchName)); FairRootManager::Instance()->Register(tOutputDigiBranchName, "TOF event digis", fTofOutputDigis, IsOutputBranchPersistent(tOutputDigiBranchName)); if(fbProcessHits) { FairRootManager::Instance()->Register(tOutputHitBranchName, "TOF event hits", fTofOutputHits, IsOutputBranchPersistent(tOutputHitBranchName)); FairRootManager::Instance()->Register(tOutputHitDigiMatchBranchName, "TOF event hit->digi match", fTofOutputHitDigiMatch, IsOutputBranchPersistent(tOutputHitDigiMatchBranchName)); FairRootManager::Instance()->Register(tOutputHitPointMatchBranchName, "TOF event hit->point match", fTofOutputHitPointMatch, IsOutputBranchPersistent(tOutputHitPointMatchBranchName)); FairRootManager::Instance()->Register(tOutputPointHitMatchBranchName, "TOF event point->hit match", fTofOutputPointHitMatch, IsOutputBranchPersistent(tOutputPointHitMatchBranchName)); } if(0. >= fdEventWindow) { fbMCEventBuilding = kTRUE; } fiTriggerMultiplicity = TMath::Abs(fiTriggerMultiplicity); if(fNominalTriggerCounterMultiplicity.size() < fiTriggerMultiplicity) { fiTriggerMultiplicity = fNominalTriggerCounterMultiplicity.size(); } return kSUCCESS; } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- void CbmTofBuildPointEvents::SetTriggerCounter(Int_t iModuleType, Int_t iModuleIndex, Int_t iCounterIndex) { CbmTofDetectorInfo tCounterInfo(kTof, iModuleType, iModuleIndex, iCounterIndex, 0, 0); Int_t iDetectorID = fGeoHandler->GetDetIdPointer()->SetDetectorInfo(tCounterInfo); fNominalTriggerCounterMultiplicity.emplace(iDetectorID); } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- void CbmTofBuildPointEvents::FindEventObjects(const std::set& CurrentEventPoints, Bool_t bCoverTimeRange) { std::set CurrentEventDigis; std::set CurrentEventHits; for(Int_t iDigi = 0; iDigi < fTofInputDigis->GetEntriesFast(); iDigi++) { const CbmTofDigiExp* tDigi = dynamic_cast(fTofInputDigis->At(iDigi)); Int_t iNPointLinks = tDigi->GetMatch()->GetNofLinks(); for(Int_t iLink = 0; iLink < iNPointLinks; iLink++) { const CbmLink& tLink = tDigi->GetMatch()->GetLink(iLink); Int_t iPoint = tLink.GetIndex(); // The MC point referred to has been associated with the current event. if(CurrentEventPoints.find(iPoint) != CurrentEventPoints.end()) { CurrentEventDigis.emplace(iDigi); } } } if(fbProcessHits) { for(Int_t iHit = 0; iHit < fTofInputHits->GetEntriesFast(); iHit++) { const CbmTofHit* tHit = dynamic_cast(fTofInputHits->At(iHit)); const CbmMatch* tHitPointMatch = dynamic_cast(fTofInputHitPointMatch->At(iHit)); Int_t iNPointLinks = tHitPointMatch->GetNofLinks(); for(Int_t iLink = 0; iLink < iNPointLinks; iLink++) { const CbmLink& tLink = tHitPointMatch->GetLink(iLink); Int_t iPoint = tLink.GetIndex(); // The MC point referred to has been associated with the current event. if(CurrentEventPoints.find(iPoint) != CurrentEventPoints.end()) { CurrentEventHits.emplace(iHit); } } } // If an event time window is being applied for event construction, make // sure that all hit objects which are time-wise arranged between the // earliest and the latest hit referring to a MC point within the event // window are attached to the current event. if(bCoverTimeRange) { Int_t iEarliestHit(0); Int_t iLatestHit(0); if(CurrentEventHits.size()) { iEarliestHit = *CurrentEventHits.cbegin(); iLatestHit = *CurrentEventHits.cend(); for(Int_t iHit = iEarliestHit + 1; iHit < iLatestHit; iHit++) { CurrentEventHits.emplace(iHit); } } } // All hit-to-digi backlinks within the newly constructed event need to be // valid. The ideal hit building in 'CbmTofClusterMC' creates a hit // from all digis which refer to a given MC point. However, it is possible // that a hit which was not built originally for a given MC point is // also composed of digis which carry information about that point (due to // inter- and across-event interference) besides digis which do not // carry such information. The digis not referring to the MC point have // not been added to 'CurrentEventDigis' yet. If they were not written // to the output event, some hit-to-digi backlinks in "TofDigiMatch" would // point to unavailable data. The analysis classes, however, require all // digi objects referred to in "TofDigiMatch" to be available in the input // array. for(auto const & iHit : CurrentEventHits) { const CbmMatch* tHitDigiMatch = dynamic_cast(fTofInputHitDigiMatch->At(iHit)); Int_t iNDigiLinks = tHitDigiMatch->GetNofLinks(); for(Int_t iLink = 0; iLink < iNDigiLinks; iLink++) { const CbmLink& tLink = tHitDigiMatch->GetLink(iLink); Int_t iDigi = tLink.GetIndex(); // The digi referred to is always available in the current timeslice // as required by the ideal hit building. CurrentEventDigis.emplace(iDigi); } } } // If an event time window is being applied for event construction, make // sure that all digi objects which are time-wise arranged between the // earliest and the latest digi referring to a MC point within the event // window are attached to the current event. if(bCoverTimeRange) { Int_t iEarliestDigi(0); Int_t iLatestDigi(0); if(CurrentEventDigis.size()) { iEarliestDigi = *CurrentEventDigis.cbegin(); iLatestDigi = *CurrentEventDigis.cend(); for(Int_t iDigi = iEarliestDigi + 1; iDigi < iLatestDigi; iDigi++) { CurrentEventDigis.emplace(iDigi); } } } Int_t iOutputTreeEntry = FairRootManager::Instance()->GetOutTree()->GetEntries(); std::map IndexMapPoints; std::map IndexMapDigis; std::map IndexMapHits; for(auto const & iPoint : CurrentEventPoints) { IndexMapPoints.emplace(iPoint, IndexMapPoints.size()); } for(auto const & iDigi : CurrentEventDigis) { IndexMapDigis.emplace(iDigi, IndexMapDigis.size()); } for(auto const & iHit : CurrentEventHits) { IndexMapHits.emplace(iHit, IndexMapHits.size()); } std::set> MCEventSet; // Write MC points and point-to-hit forward references to the output array. for(auto const & iInputPoint : CurrentEventPoints) { Int_t iOutputPoint = fTofOutputPoints->GetEntriesFast(); const CbmTofPoint* tInputPoint = dynamic_cast(fTofInputPoints->At(iInputPoint)); CbmTofPoint* tOutputPoint = new((*fTofOutputPoints)[iOutputPoint]) CbmTofPoint(*tInputPoint); // Collect original MC event affiliations of points attributed to the current // reconstructed event. Int_t iFileID = tInputPoint->GetUniqueID(); Int_t iEventID = tInputPoint->GetEventID(); if(-1 < iFileID && -1 < iEventID) { MCEventSet.emplace(iFileID, iEventID); } if(fbProcessHits) { const CbmMatch* tInputPointHitMatch = dynamic_cast(fTofInputPointHitMatch->At(iInputPoint)); CbmMatch* tOutputPointHitMatch = new((*fTofOutputPointHitMatch)[iOutputPoint]) CbmMatch(*tInputPointHitMatch); Int_t iNHitLinks = tOutputPointHitMatch->GetNofLinks(); for(Int_t iLink = 0; iLink < iNHitLinks; iLink++) { CbmLink& tLink = tOutputPointHitMatch->GetLink(iLink); // If the analysis chain is not parallelized, 'CbmLink::fFile' is set to // '0' (default value of 'CbmTofBuildPointEvents::fiFileIndex') for all // objects that are stored in the same SINGLE output file. tLink.SetFile(fiFileIndex); tLink.SetEntry(iOutputTreeEntry); tLink.SetIndex(IndexMapHits.at(tLink.GetIndex())); } } } // Write digis and digi-to-point backward references to the output array. for(auto const & iInputDigi : CurrentEventDigis) { Int_t iOutputDigi = fTofOutputDigis->GetEntriesFast(); const CbmTofDigiExp* tInputDigi = dynamic_cast(fTofInputDigis->At(iInputDigi)); Int_t iInputDigiModuleType = tInputDigi->GetType(); Int_t iInputDigiModuleIndex = tInputDigi->GetSm(); Int_t iInputDigiCounterIndex = tInputDigi->GetRpc(); Int_t iInputDigiCounterSide = tInputDigi->GetSide(); Int_t iInputDigiAddress = tInputDigi->GetAddress(); Double_t dInputDigiTime = tInputDigi->GetTime(); Double_t dInputDigiToT = tInputDigi->GetTot(); auto CounterSideTuple = std::make_tuple(iInputDigiModuleType, iInputDigiModuleIndex, iInputDigiCounterIndex, iInputDigiCounterSide); if(fInactiveCounterSides.find(CounterSideTuple) != fInactiveCounterSides.end()) { continue; } CbmTofDigiExp* tOutputDigi = new((*fTofOutputDigis)[iOutputDigi]) CbmTofDigiExp(); tOutputDigi->SetAddress(iInputDigiAddress); tOutputDigi->SetTime(dInputDigiTime); tOutputDigi->SetTot(dInputDigiToT); const CbmMatch* tInputDigiPointMatch = tInputDigi->GetMatch(); CbmMatch* tOutputDigiPointMatch = new CbmMatch(*tInputDigiPointMatch); tOutputDigi->SetMatch(tOutputDigiPointMatch); Int_t iNPointLinks = tOutputDigiPointMatch->GetNofLinks(); for(Int_t iLink = 0; iLink < iNPointLinks; iLink++) { CbmLink& tLink = tOutputDigiPointMatch->GetLink(iLink); // Either the referenced MC point is not contained in the same input // timeslice as the referencing digi (in which case 'CbmLink::fIndex' // already equals '-1') or it is not associated with the current event // (in which case 'CbmLink::fIndex' needs to be set to '-1'). // The file ID in 'CbmLink::fFile' is not reset for unavailable/unassigned // MC points according to 'fiFileIndex' because then their // ID pair (file, event) might not be unique anymore. // The variable 'FairMCPoint::fEventId' is extracted from MC points which // are unassigned but available and stored in 'CbmLink::fEntry'. if(CurrentEventPoints.find(tLink.GetIndex()) == CurrentEventPoints.end()) { if(-1 != tLink.GetIndex()) { const CbmTofPoint* tPoint = dynamic_cast(fTofInputPoints->At(tLink.GetIndex())); tLink.SetEntry(tPoint->GetEventID()); tLink.SetIndex(-1); } } else { tLink.SetFile(fiFileIndex); tLink.SetEntry(iOutputTreeEntry); tLink.SetIndex(IndexMapPoints.at(tLink.GetIndex())); } } } // Write hits, hit-to-digi and hit-to-point backward references to the output array. for(auto const & iInputHit : CurrentEventHits) { Int_t iOutputHit = fTofOutputHits->GetEntriesFast(); const CbmTofHit* tInputHit = dynamic_cast(fTofInputHits->At(iInputHit)); // All copy constructors in the 'CbmTofHit'->'CbmPixelHit'->'CbmHit' inheritance // chain only make shallow copies of the objects, i.e. the pointer member variable // 'CbmHit::fMatch' is nullified upon copy construction (which is the desired // behavior here). CbmTofHit* tOutputHit = new((*fTofOutputHits)[iOutputHit]) CbmTofHit(*tInputHit); const CbmMatch* tInputHitDigiMatch = dynamic_cast(fTofInputHitDigiMatch->At(iInputHit)); CbmMatch* tOutputHitDigiMatch = new((*fTofOutputHitDigiMatch)[iOutputHit]) CbmMatch(*tInputHitDigiMatch); Int_t iNDigiLinks = tOutputHitDigiMatch->GetNofLinks(); // All digi objects referenced by hits assigned to the current event are // written to the output array. for(Int_t iLink = 0; iLink < iNDigiLinks; iLink++) { CbmLink& tLink = tOutputHitDigiMatch->GetLink(iLink); tLink.SetFile(fiFileIndex); tLink.SetEntry(iOutputTreeEntry); tLink.SetIndex(IndexMapDigis.at(tLink.GetIndex())); } const CbmMatch* tInputHitPointMatch = dynamic_cast(fTofInputHitPointMatch->At(iInputHit)); CbmMatch* tOutputHitPointMatch = new((*fTofOutputHitPointMatch)[iOutputHit]) CbmMatch(*tInputHitPointMatch); Int_t iNPointLinks = tOutputHitPointMatch->GetNofLinks(); for(Int_t iLink = 0; iLink < iNPointLinks; iLink++) { CbmLink& tLink = tOutputHitPointMatch->GetLink(iLink); // Either the referenced MC point is not contained in the same input // timeslice as the referencing hit (in which case 'CbmLink::fIndex' // already equals -'tof::link_PointInDifferentTS') or it is not associated // with the current event (in which case 'CbmLink::fIndex' needs to be set // to -'tof::link_PointInDifferentTS'). // Following 'CbmTofMatchReco', all other member variables of 'CbmLink' // need to be marked with 'tof::link_PointInDifferentTS' for unassigned // points as well. if(CurrentEventPoints.find(tLink.GetIndex()) == CurrentEventPoints.end()) { if(-tof::link_PointInDifferentTS != tLink.GetIndex()) { tLink.SetFile(-tof::link_PointInDifferentTS); tLink.SetEntry(-tof::link_PointInDifferentTS); tLink.SetIndex(-tof::link_PointInDifferentTS); tLink.SetUniqueID(tof::link_PointInDifferentTS); } } else { tLink.SetFile(fiFileIndex); tLink.SetEntry(iOutputTreeEntry); tLink.SetIndex(IndexMapPoints.at(tLink.GetIndex())); } } } // Read the respective start times of the original MC events contributing to // the reconstructed event from the input MC event list and make them // available in the output MC event list. for(auto const & MCEvent : MCEventSet) { Int_t iFileIndex = MCEvent.first; Int_t iEventIndex = MCEvent.second; Double_t dStartTime = fInputMCEventList->GetEventTime(iEventIndex, iFileIndex); if(-1. != dStartTime) { fOutputMCEventList->Insert(iEventIndex, iFileIndex, dStartTime); } else { LOG(FATAL)<Sort(); } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- void CbmTofBuildPointEvents::SetIgnoreCounterSide(Int_t iModuleType, Int_t iModuleIndex, Int_t iCounterIndex, Int_t iCounterSide) { fInactiveCounterSides.emplace(std::make_tuple(iModuleType, iModuleIndex, iCounterIndex, iCounterSide)); } // --------------------------------------------------------------------------- ClassImp(CbmTofBuildPointEvents)