#include "PndFtsHoughSpace.h" #include #include "TMath.h" #include #include #include #include #include // FTS #include "PndFtsHit.h" #include "FairHit.h" // (Hough) tracking #include "PndTrackCand.h" #include "PndTrack.h" #include "FairTrackParP.h" #include "PndFtsHoughTrackCand.h" // histogramming / plotting #include "TH1.h" #include "TH2.h" #include "TGraph.h" // peak finder #include "TSpectrum2.h" // root IO #include "FairRunAna.h" #include "FairRootManager.h" #include "FairRuntimeDb.h" #include "FairTask.h" #include "PndFtsHit.h" #include "TString.h" #include "FairHit.h" #include "PndFtsHit.h" #include "PndFtsTube.h" #include "FairEventHeader.h" ClassImp(PndFtsHoughSpace); std::ostream& operator <<(std::ostream& os, const IdxPath& outVector){ os << "["; Int_t lastIdx = outVector.size()-1; if(lastIdx < 0){ os << "]" ; return os; } for (UInt_t iVec = 0; iVec < lastIdx; ++iVec){ os << outVector[iVec] << ", "; } os << outVector[lastIdx] << "]"; return os; } std::ostream& operator <<(std::ostream& os, const HitIdxPathMap& outMap) { os << '\n'; if(outMap.begin() == outMap.end()){ os << "{ , [] }"; return os; } for (HitIdxPathMap::const_iterator itMap = outMap.begin(); itMap != outMap.end(); ++itMap){ os << "{ "<< itMap->first << ", "; os << itMap->second; os << " }\n\n"; } return os; } inline void PndFtsHoughSpace::AddHitToHS(UInt_t hitId, Double_t rho) { const PndFtsHit *const hitToAdd = fTrackerTask->GetFtsHit(hitId); const Int_t tubeIdToAdd = hitToAdd->GetTubeID(); if (kFALSE == IsHitFromTubeIdAlreadyAdded(tubeIdToAdd)) { fHitId.push_back(PndTrackCandHit(fFtsBranchId, hitId, rho)); } } inline void PndFtsHoughSpace::AddHitToHS(FairLink link, Double_t rho) { const PndFtsHit *const hitToAdd = fTrackerTask->GetFtsHit(link.GetIndex()); const Int_t tubeIdToAdd = hitToAdd->GetTubeID(); if (kFALSE == IsHitFromTubeIdAlreadyAdded(tubeIdToAdd)) { fHitId.push_back(PndTrackCandHit(link.GetType(), link.GetIndex(), rho)); } } inline Bool_t PndFtsHoughSpace::IsHitFromTubeIdAlreadyAdded(const Int_t tubeIdToAdd) { // return kFALSE; // uncomment this line to switch off testing for duplicates for (int iTestHit = 0; iTestHit < GetNHits(); ++iTestHit) { const PndFtsHit *const myTestHit = getHitFromHS(iTestHit); const Int_t tubeIdTestHit = myTestHit->GetTubeID(); if ( tubeIdToAdd == tubeIdTestHit ) return kTRUE; } // for loop over all hits which have already been added to the Hough space return kFALSE; }; PndFtsHoughSpace::PndFtsHoughSpace( const char *name, const Int_t refIndex, PndFtsHoughSpaceBinning binning, Double_t zRefPos, Double_t interceptZx, PndFtsHoughTrackCand *associatedTrackCand, PndFtsHoughTrackerTask *trackerTask ) : fTrackerTask(trackerTask), fRefIndex(refIndex), fZRefPos(zRefPos), fInterceptZx(interceptZx), TH2S(name, name, binning.getNBinsTheta(), binning.getThetaRadLow(), binning.getThetaRadHigh(), binning.getNBinsY(),binning.getYLow(),binning.getYHigh()), // set from tracker task fFtsBranchId(0), fVerbose(0), fField(0), fAssociatedTrackCand(associatedTrackCand) { if (0==fTrackerTask){ std::cerr << "PndFtsHoughSpace FATAL ERROR Tracker task pointer not set.\n"; } else { fVerbose = fTrackerTask->GetVerbose(); if(3getFtsBranchId(); fField = fTrackerTask->getMagneticFieldPtr(); setParametersForHsOption(); filterInputHits(); } } PndFtsHoughSpace::~PndFtsHoughSpace() { } Bool_t PndFtsHoughSpace::setParametersForHsOption() { // use option instead of GetName() or fName (even though it is the same) const TString option = GetName(); fKeepBConstant = kTRUE; // kFALSE only for testing // set parameters according to the Hough transform I want to do if ("lineBeforeDipole" == option) { // make sure hits are not shifted for line hough transform if (0!=fInterceptZx) { std::cout << "PndFtsHoughSpace: " << "fInterceptZx was set to " << fInterceptZx << " That is not correct for line HT of stations before dipole field!\n"; std::cout << "Will set interceptZx to 0 for " << option << '\n'; fInterceptZx = 0.; } fUseNonSkewedStraws = kTRUE; fUseSkewedStraws = kFALSE; // Line for stations 1+2 fOnlyUseHitsFromZ = 100.; // Set = 100. if you want to use all FTS hits, higher if you want to exclude hits that are closer to the interaction point than the value fOnlyUseHitsUpToZ = 380.; // Set = 1000. if you want to use all FTS hits, lower if you want to exclude hits that are further away from the interaction point than the value GetXaxis()->SetTitle("#theta [rad]"); GetYaxis()->SetTitle("x [cm]"); } else if ("parabola" == option) { fUseNonSkewedStraws = kTRUE; fUseSkewedStraws = kFALSE; // parabola for stations 3-5 fOnlyUseHitsFromZ = 380.; // Set = 100. if you want to use all FTS hits, higher if you want to exclude hits that are closer to the interaction point than the value fOnlyUseHitsUpToZ = 630.; // Set = 1000. if you want to use all FTS hits, lower if you want to exclude hits that are further away from the interaction point than the value GetXaxis()->SetTitle("#theta [rad]"); GetYaxis()->SetTitle("x_{LP} [cm]"); } else if ("parabolapz" == option) { fUseNonSkewedStraws = kTRUE; fUseSkewedStraws = kFALSE; // parabola for stations 3-5 fOnlyUseHitsFromZ = 380.; // Set = 100. if you want to use all FTS hits, higher if you want to exclude hits that are closer to the interaction point than the value fOnlyUseHitsUpToZ = 630.; // Set = 1000. if you want to use all FTS hits, lower if you want to exclude hits that are further away from the interaction point than the value GetXaxis()->SetTitle("#theta [rad]"); GetYaxis()->SetTitle("x_{LP} [cm]"); } else if ("lineBehindDipole" == option) { // make sure hits are not shifted for line hough transform if (0!=fInterceptZx) { std::cout << "PndFtsHoughSpace: " << "fInterceptZx was set to " << fInterceptZx << " That is not correct for line HT of stations after dipole field!\n"; std::cout << "Will set interceptZx to 0 for " << option << '\n'; fInterceptZx = 0.; } fUseNonSkewedStraws = kTRUE; fUseSkewedStraws = kFALSE; // Line for stations 5+6 fOnlyUseHitsFromZ = 550.; // Set = 100. if you want to use all FTS hits, higher if you want to exclude hits that are closer to the interaction point than the value fOnlyUseHitsUpToZ = 1000.; // Set = 1000. if you want to use all FTS hits, lower if you want to exclude hits that are further away from the interaction point than the value GetXaxis()->SetTitle("#theta [rad]"); GetYaxis()->SetTitle("x [cm]"); } else if ("lineZy" == option) { // make sure hits are not shifted for line hough transform if (0!=fInterceptZx) { std::cout << "PndFtsHoughSpace: " << "fInterceptZx was set to " << fInterceptZx << " That is not correct for line HT of all stations in zy plane!\n"; std::cout << "Will set interceptZx to 0 for " << option << '\n'; fInterceptZx = 0.; } fUseNonSkewedStraws = kFALSE; fUseSkewedStraws = kTRUE; // Line for all FTS stations fOnlyUseHitsFromZ = 100.; // Set = 100. if you want to use all FTS hits, higher if you want to exclude hits that are closer to the interaction point than the value fOnlyUseHitsUpToZ = 1000.; // Set = 1000. if you want to use all FTS hits, lower if you want to exclude hits that are further away from the interaction point than the value GetXaxis()->SetTitle("#theta [rad]"); GetYaxis()->SetTitle("y [cm]"); } else { throwError("in PndFtsHoughSpace! option " + option + " is not implemented!"); } if (3GetNFtsHits() << "\n"; } for (int iHit = 0; iHit < fTrackerTask->GetNFtsHits(); iHit++) { const PndFtsHit *const myHit = fTrackerTask->GetFtsHit(iHit); // Skip hits from skewed or non-skewed straws (if I wish not to use them) if (0 != myHit->GetSkewed()) { // hit comes from skewed straw if (kFALSE == fUseSkewedStraws) { if (3 lastBinY) { // we go up in the second value, therefore, we need to add to the yValue yCorrect = iCorrect; } else { yCorrect = -iCorrect; } const Int_t interpolateBinX = lastBinX+xCorrect; const Int_t interpolateBinY = lastBinY+yCorrect; const Int_t interpolatedGlobalBin = GetBin(interpolateBinX,interpolateBinY); AddBinContent(interpolatedGlobalBin); // save interpolated globalBin into path vector ptrThetaYIdxPathVec->push_back(interpolatedGlobalBin); if (8=0) // -1 would mean over- or underflow { if (5GetSaveDebugInfo()) { WriteHistoOfHoughSpace(); WriteHistoOfAllPaths(); WriteHistoOfAllPathsForEachMcTruthTrack(); } } TH2S PndFtsHoughSpace::MakeEmptyHistoOfSameDimensions(TString specifier, Int_t index) const { // for getting rid of warning about potential memory leak (same name for mutliple different histos) static Int_t histoCounter = 0; TString newname = GetName(); newname += histoCounter; // std::cout<& peaksToPlot) const { // test if we need to do anything here Bool_t saveEachSeparately = !(fTrackerTask->GetSaveDebugInfo() % PndFtsHoughTrackerTask::kEachFoundPeakSeparately); Bool_t saveAllTogether = !(fTrackerTask->GetSaveDebugInfo() % PndFtsHoughTrackerTask::kAllFoundPeaksTogether); if ( (kTRUE == saveEachSeparately) && (kTRUE == saveAllTogether) )return; // write out histograms containing found peaks // filling all peaks in separate histos and all together in one histo TH2S allPeaks = MakeEmptyHistoOfSameDimensions("AllPeaks"); for (UInt_t iPeak = 0; iPeak < peaksToPlot.size(); ++iPeak) { TH2S onePeak = MakeEmptyHistoOfSameDimensions("Peak", iPeak); const Double_t currHeight = peaksToPlot[iPeak].getHeight(); const std::set& binsInPeak = peaksToPlot[iPeak].getBins(); for (std::set::iterator itBin = binsInPeak.begin(); itBin != binsInPeak.end(); ++itBin) { onePeak.SetBinContent(*itBin, currHeight); allPeaks.SetBinContent(*itBin, currHeight); } TString outNameOne = GetDebugOutName(onePeak.GetTitle(), currHeight); if ( kTRUE == saveEachSeparately ) onePeak.SaveAs(outNameOne, "LEGO2"); } TString outNameAll = GetDebugOutName(allPeaks.GetTitle()); if ( kTRUE == saveAllTogether ) allPeaks.SaveAs(outNameAll, "LEGO2"); } void PndFtsHoughSpace::WriteHistoOfAllPaths() const { // test if we need to do anything here Bool_t saveExclusively = !(fTrackerTask->GetSaveDebugInfo() % PndFtsHoughTrackerTask::kHitCurvesExclusively); Bool_t saveProjected = !(fTrackerTask->GetSaveDebugInfo() % PndFtsHoughTrackerTask::kHitCurvesProjected); if ( (kTRUE == saveExclusively) && (kTRUE == saveProjected) )return; // filling each path in separate histo for (HitIdxPathMap::const_iterator itPath = fHitThetaYIdxPath.begin(); itPath != fHitThetaYIdxPath.end(); ++itPath) { const Int_t currHit = itPath->first; TH2S onePathProjected = MakeEmptyHistoOfSameDimensions("PathProjected", currHit); TH2S onePathExclusively = MakeEmptyHistoOfSameDimensions("PathExclusively", currHit); const IdxPath& currPath = itPath->second; Int_t lastBinNumber = -1; for (Int_t iGlobalBin = 0; iGlobalBin < currPath.size(); ++iGlobalBin) { const Int_t currBinNumber = currPath[iGlobalBin]; // warn if we accidently saved the same bin twice in the path if ( currBinNumber == lastBinNumber ) std::cerr << "FATAL! Bin " << currBinNumber << " twice in a row! in hit " << currHit << '\n'; lastBinNumber = currBinNumber; if ( kTRUE == saveProjected){ const Double_t currHeight = GetBinContent(currBinNumber); // get height of Hough space onePathProjected.SetBinContent(currBinNumber, currHeight); } if ( kTRUE == saveExclusively){ Int_t currBinX = 0, currBinY = 0, notUsedBinZ = 0; GetBinXYZ(currBinNumber, currBinX, currBinY, notUsedBinZ); // Find currBinX and currBinY from globalBin const Double_t currXVal = GetXaxis()->GetBinCenter(currBinX); const Double_t currYVal = GetYaxis()->GetBinCenter(currBinY); onePathExclusively.Fill(currXVal,currYVal); // exclusive fill } } TString outNameProj = GetDebugOutName(onePathProjected.GetTitle()); if ( kTRUE == saveProjected ) onePathProjected.SaveAs(outNameProj, "LEGO2"); TString outNameExcl = GetDebugOutName(onePathExclusively.GetTitle()); if ( kTRUE == saveExclusively ) onePathExclusively.SaveAs(outNameExcl, "LEGO2"); } } void PndFtsHoughSpace::WriteHistoOfAllPathsForEachMcTruthTrack() const { // test if we need to do anything here Bool_t saveExclusively = !(fTrackerTask->GetSaveDebugInfo() % PndFtsHoughTrackerTask::kMcTruthPeaksExclusively); Bool_t saveProjected = !(fTrackerTask->GetSaveDebugInfo() % PndFtsHoughTrackerTask::kMcTruthPeaksProjected); if ( (kTRUE == saveExclusively) && (kTRUE == saveProjected) )return; // create map collecting histos of all hit indices from same Mc truth track std::map > mcTruthIdHistos; for (HitIdxPathMap::const_iterator itPath = fHitThetaYIdxPath.begin(); itPath != fHitThetaYIdxPath.end(); ++itPath) { // figure out to which MC Truth track hit belongs const Int_t currHit = itPath->first; const Int_t hitId = getHitIdFromHS(currHit); const Int_t mcTruthId = fTrackerTask->getMcTruthIdForHitId(hitId); // if MC truth index not yet in map add new histo std::map >::iterator itFind; itFind = mcTruthIdHistos.find(mcTruthId); if ( mcTruthIdHistos.end() == itFind ){// not found TH2S newHisto = MakeEmptyHistoOfSameDimensions("McTruthPeak projected", mcTruthId); TH2S newHisto2 = MakeEmptyHistoOfSameDimensions("McTruthPeak exclusive", mcTruthId); std::pair histoPair( newHisto, newHisto2 ); std::pair > mcTruthIdHistosPair( mcTruthId, histoPair ); mcTruthIdHistos.insert( mcTruthIdHistosPair ); itFind = mcTruthIdHistos.find(mcTruthId); // now histos can be found in map } // Fill current path into correct histo (first as projection, second as if only hits from same mc truth track were filled) const IdxPath& currPath = itPath->second; for (Int_t iGlobalBin = 0; iGlobalBin < currPath.size(); ++iGlobalBin) { Int_t currBinNumber = currPath[iGlobalBin]; std::pair& histoPair = itFind->second; if ( kTRUE == saveProjected ){ const Double_t currHeight = GetBinContent(currBinNumber); // get height of Hough space histoPair.first.SetBinContent(currBinNumber, currHeight); // projection } if ( kTRUE == saveExclusively ){ Int_t currBinX = 0, currBinY = 0, notUsedBinZ = 0; GetBinXYZ(currBinNumber, currBinX, currBinY, notUsedBinZ); // Find currBinX and currBinY from globalBin const Double_t currXVal = GetXaxis()->GetBinCenter(currBinX); const Double_t currYVal = GetYaxis()->GetBinCenter(currBinY); histoPair.second.Fill(currXVal,currYVal); // exclusive fill } } } // loop over all histos that have been created for ( std::map >::const_iterator itHisto = mcTruthIdHistos.begin(); itHisto != mcTruthIdHistos.end(); ++itHisto) { const std::pair& histoPair = itHisto->second; TString outNameProjection = GetDebugOutName(histoPair.first.GetTitle()); TString outNameExclusive = GetDebugOutName(histoPair.second.GetTitle()); if ( kTRUE == saveProjected ) histoPair.first.SaveAs(outNameProjection, "LEGO2"); if ( kTRUE == saveExclusively ) histoPair.second.SaveAs(outNameExclusive, "LEGO2"); } } void PndFtsHoughSpace::WriteHistoOfHoughSpace() const{ if (0 != fTrackerTask->GetSaveDebugInfo() % PndFtsHoughTrackerTask::kHoughSpaces) return; // Int_t index = fHoughSpaces->GetEntriesFast(); // PndFtsHoughSpace* myHoughSpace = new ((*fHoughSpaces)[index])PndFtsHoughSpace(*houghSpace); TString title = GetTitle(); title += " histo"; TString outName = GetDebugOutName(title); SaveAs(outName, "LEGO2"); // resulting files need to have PndFtsHoughSpace replaced with TH2S // sed -i 's/PndFtsHoughSpace/TH2S/g' *.rtg // fOutFile = FairRootManager::Instance()->GetOutFile(); // if (0==fOutFile) // { // std::cout << "WriteHistograms: Cannot get outfile.\n"; // } // else // { // // fOutFile->cd(); // // fOutFile->cd("PndFtsHoughTrackerTask"); // if(3GetName(); // TString histNameNew = houghSpace->GetName(); // histNameNew+=fEventNr; // houghSpace->SetName(histNameNew); // houghSpace->Write(); // houghSpace->SetName(histNameOld); // } // // fOutFile->cd(); // } } void PndFtsHoughSpace::AddHitsToTrackletByCalculating(PndFtsHoughTracklet *currentTracklet, Int_t locmax){ /////////////////////////////////////////// // TODO this is messy, because the code is very similar to FillHoughSpace. Probably, I should find a way to merge it // add hits which are in the peak to the tracklet // 1 calculate the 2nd value for the next higher/lower theta bin of peak theta // 2 If peak 2nd value is within [min hit 2nd value - half width, max hit 2nd value + half width] add the hit to the tracklet // 3 otherwise the hit is not in the peak // This is more complicated to check, but also true // A calculate the 2nd value for peak theta // B If hit 2nd value is within [peak 2nd value - peakSecondHw, peak 2nd value + peakSecondHw] add the hit // C If hit 2nd value is < peak 2nd value - peakSecondHw, hit is in peak if the 2nd value of the next higher/lower theta bin is >= peak 2nd value // D If hit 2nd value is > peak 2nd value + peakSecondHw, hit is in peak if the 2nd value of the next lower/higher theta bin is <= peak 2nd value // E otherwise the hit is not in the peak const Int_t xfirst = fXaxis.GetFirst(); const Int_t xlast = fXaxis.GetLast(); const Int_t yfirst = fYaxis.GetFirst(); const Int_t ylast = fYaxis.GetLast(); // 1 calculate the 2nd value for the next higher/lower theta bin of peak theta UInt_t thetaBinLo = locmax-1; UInt_t thetaBinHi = locmax+1; // special case if we are at the edge of the Hough space if (thetaBinLo>xfirst) { thetaBinLo=xfirst; } if (thetaBinHi>xlast) { thetaBinHi=xlast; } // get theta values const Double_t thetaRadLo = fXaxis.GetBinCenter(thetaBinLo); const Double_t thetaRadHi = fXaxis.GetBinCenter(thetaBinHi); // for storing the values to be calculated in Hough transform (yValue = offset for line, yValue = Q/pzx for parabola) Double_t yValLo = 0.; Double_t yValHi = 0.; for (int iHit = 0; iHit < GetNHits(); iHit++) { const PndFtsHit* myHit = getHitFromHS(iHit); // get hit position const TVector3 hitPos = GetRawOrCalculatedHitPos(myHit); Double_t hitXLabSys = hitPos.X(); Double_t hitYLabSys = hitPos.Y(); Double_t hitZLabSys = hitPos.Z(); Double_t hitXShifted = hitXLabSys - fInterceptZx; // shifts all x positions of hits so that they go through x=0 at z=zOffset (for parabola) Double_t hitZShifted = hitZLabSys - fZRefPos; // z coordinate in local coordinate system (for parabola and for line) // y component of B field Double_t By = getByFromBField(hitXLabSys, hitYLabSys, hitZLabSys); const TString option = GetName(); if ("parabola" == option) { // Use shifted x and shifted z for parabola yValLo = equationParabola(thetaRadLo, hitZShifted, hitXShifted, By); yValHi = equationParabola(thetaRadHi, hitZShifted, hitXShifted, By); if (9getSecondVal(); if ( (yMin-yMinHw <= peakSecondVal) && (yMax+yMaxHw >= peakSecondVal) ){ currentTracklet->AddHit(fFtsBranchId, getHitIdFromHS(iHit), hitZLabSys); } } // loop over hits } std::vector PndFtsHoughSpace::FindAllPeaksBinsWoMergingWithSearchWindow(const UInt_t minHeight, const Int_t vicinityLength) { std::vector tracklets; // for output // check if Hough space has at least one entry if (1>GetEntries()) { if(1GetFirst()+vicinityLength; // Int_t zlast = fZaxis->GetLast()-vicinityLength; // find all peaks that have a height >= minHeight Double_t currentHeight; locmax = locmay = locmaz = 0; // for (binz=zfirst;binz<=zlast;binz++) { for (biny=yfirst;biny<=ylast;biny++) { for (binx=xfirst;binx<=xlast;binx++) { currentHeight = 0.; // iterate over vicinity for (Int_t xVicinityBin = -vicinityLength; xVicinityBin <= vicinityLength; ++xVicinityBin) { for (Int_t yVicinityBin = -vicinityLength; yVicinityBin <= vicinityLength; ++yVicinityBin) { binNumber = GetBin(binx+xVicinityBin,biny+yVicinityBin); //,binz); currentHeight += 1./(1.+std::max(abs(xVicinityBin),abs(yVicinityBin)))*GetBinContent(binNumber); // linear, unendlich norm // currentHeight += 1./(1.+abs(xVicinity) +abs(yVicinity))*houghspace->GetBinContent(binNumber); // linear // currentHeight += 1./(1.+pow(max(xVicinity,yVicinity),2))*houghspace->GetBinContent(binNumber); // quadratic, unendlich norm } } if (currentHeight >= minHeight) { locmax = binx; locmay = biny; // locmaz = binz; // get values corresponding to the peak Double_t peakThetaVal = fXaxis.GetBinCenter(locmax); Double_t peakSecondVal = fYaxis.GetBinCenter(locmay); Int_t binmaxglobal = Fill(peakThetaVal, peakSecondVal, 0); // returns binnumber without modifying the histogram Double_t peakThetaHw = fXaxis.GetBinWidth(peakThetaVal)/2.; Double_t peakSecondHw = fYaxis.GetBinWidth(peakSecondVal)/2.; // create tracklet and push it back to output PndFtsHoughTracklet currentTracklet(fZRefPos, fTrackerTask); currentTracklet.SetHoughTransformResults(peakThetaVal, peakSecondVal, currentHeight, peakThetaHw, peakSecondHw); // Add hits to tracklet AddHitsToTrackletByCalculating(¤tTracklet, locmax); tracklets.push_back(currentTracklet); } // height is big enough } // x loop } // y loop // } // z loop if (1 PndFtsHoughSpace::FindAllPeaksScanPathsMergeBins(const UInt_t minHeight) { std::vector tracklets; // for output // check if Hough space has at least one entry if (1>GetEntries()) { if(1 this reduces the 2d peak finding to nHits 1d problems plus peak merging. // require bin height >= minHeight // and that we are on a rising edge std::vector< PndFtsHoughSpacePeak > peaksForOneHit; // stores (possible) peaks for one hit std::vector< PndFtsHoughSpacePeak > mergedPeaksForAllHits; // stores merged peaks for all hits mergedPeaksForAllHits.clear(); // hit loop for (HitIdxPathMap::const_iterator itMap = fHitThetaYIdxPath.begin(); itMap != fHitThetaYIdxPath.end(); ++itMap){ const Int_t hitIdx = itMap->first; IdxPath path = itMap->second; peaksForOneHit.clear(); // loop over bins along the path for (Int_t iGlobalBin = 0; iGlobalBin < path.size(); ++iGlobalBin){ // current bin const Int_t currBinNumber = path[iGlobalBin]; const Int_t currHeight = GetBinContent(currBinNumber); // check if we already found a peak candidate const Int_t nPeaksSoFar = peaksForOneHit.size(); if ( 0 < nPeaksSoFar ){ // if we already have a peak, we might need to continue building it PndFtsHoughSpacePeak& currPeak = peaksForOneHit[nPeaksSoFar-1]; // get last peak if ( kFALSE == currPeak.isFinished() ){ // continue building up current peak if ( currHeight < currPeak.getHeight() ) currPeak.setFinished(kTRUE); if ( currHeight == currPeak.getHeight() ) currPeak.addBin(currBinNumber, hitIdx); if ( currHeight > currPeak.getHeight() ) currPeak.replaceBins(currHeight, currBinNumber, hitIdx); continue; // do not create a new peak as we were building an old one } } // we have already >= 1 peaks if ( minHeight <= currHeight ) { // Bin could belong to a peak // Make sure we are not on a falling edge by checking that the previous position was strictly lower! // previous bin const Int_t prevIdx = std::max(0, iGlobalBin-1); // make sure we stay within bounds of vector const Int_t prevBinNumber = path[prevIdx]; const Int_t prevHeight = GetBinContent(prevBinNumber); Bool_t rising = prevHeight < currHeight; if ( 0 == iGlobalBin ) rising = kTRUE; // always save if we are at the beginning if ( kTRUE == rising ){ // we are on rising edge // Add a new peak (only if we do not continue a nonfinished existing one) // either we did not have any peaks or the last peak was already finished PndFtsHoughSpacePeak newPeak(currHeight, currBinNumber, hitIdx); peaksForOneHit.push_back(newPeak); } } }// loop over bins along the path // now merge peaksForOneHit with mergedPeaksForAllHits // loop over found peaks for latest hit and all merged hits, compare if they have overlaps, if so merge for (UInt_t iPeaksForOneHit = 0; iPeaksForOneHit < peaksForOneHit.size(); ++iPeaksForOneHit){ Bool_t merged = kFALSE; for (UInt_t iPeaksForAllHits = 0; iPeaksForAllHits < mergedPeaksForAllHits.size(); ++iPeaksForAllHits){ if ( mergedPeaksForAllHits[iPeaksForAllHits].binsOverlapWith(peaksForOneHit[iPeaksForOneHit]) ) { mergedPeaksForAllHits[iPeaksForAllHits].mergeWith(peaksForOneHit[iPeaksForOneHit]); merged = kTRUE; //continue; // skip checking with all other peaks as they cannot overlap anymore (TODO Check if that is true) } } if ( kFALSE==merged ) mergedPeaksForAllHits.push_back(peaksForOneHit[iPeaksForOneHit]); // add peaks which could not be merged with preexisting ones } }// hit loop if ( 0 < fTrackerTask->GetSaveDebugInfo() ) WriteHistoOfAllPeaks(mergedPeaksForAllHits); // Build up tracklets from peaks by going through vector of merged peaks for (UInt_t iPeaks = 0; iPeaks < mergedPeaksForAllHits.size(); ++iPeaks){ const Double_t currentHeight = mergedPeaksForAllHits[iPeaks].getHeight(); const std::set& binsInPeak = mergedPeaksForAllHits[iPeaks].getBins(); // calculate center and halfwidth (HW) in theta and in secondVal for all global bins in peak // save min and max values Double_t minThetaVal = 0., maxThetaVal = 0., minSecondVal = 0., maxSecondVal = 0.; for (std::set< Int_t >::iterator itBin = binsInPeak.begin(); itBin != binsInPeak.end(); ++itBin){ Int_t currentBinX = 0, currentBinY = 0, currentBinZ = 0; GetBinXYZ(*itBin, currentBinX, currentBinY, currentBinZ); // get bin numbers for x, y (and z) axis // get values for corresponding to global bin number const Double_t currThetaVal = fXaxis.GetBinCenter(currentBinX); const Double_t currSecondVal = fYaxis.GetBinCenter(currentBinY); if ( binsInPeak.begin() == itBin ){ // initialize values if this is the first bin minThetaVal = currThetaVal; maxThetaVal = currThetaVal; minSecondVal = currSecondVal; maxSecondVal = currSecondVal; } else { // save min and max minThetaVal = std::min(minThetaVal,currThetaVal); maxThetaVal = std::max(maxThetaVal,currThetaVal); minSecondVal = std::min(minSecondVal,currSecondVal); maxSecondVal = std::max(maxSecondVal,currSecondVal); } } const Double_t peakThetaVal = (maxThetaVal + minThetaVal)/2.; const Double_t peakSecondVal = (maxSecondVal + minSecondVal)/2.; const Double_t peakThetaHw = (maxThetaVal - minThetaVal)/2. + fXaxis.GetBinWidth(peakThetaVal)/2.; const Double_t peakSecondHw = (maxSecondVal - minSecondVal)/2. + fYaxis.GetBinWidth(peakSecondVal)/2.; // create tracklet, add hits and push it back to output PndFtsHoughTracklet currentTracklet(fZRefPos, fTrackerTask); currentTracklet.SetHoughTransformResults(peakThetaVal, peakSecondVal, currentHeight, peakThetaHw, peakSecondHw); // add hits to tracklet const std::set& hitIdsInPeak = mergedPeaksForAllHits[iPeaks].getHitIds(); for (std::set< Int_t >::iterator itHitId= hitIdsInPeak.begin(); itHitId != hitIdsInPeak.end(); ++itHitId){ const Int_t hitIndex = getHitIdFromHS(*itHitId); const PndFtsHit* myHit = getHitFromHS(*itHitId); // get hit position const TVector3 hitPos = GetRawOrCalculatedHitPos(myHit); Double_t hitZLabSys = hitPos.Z(); currentTracklet.AddHit(fFtsBranchId, hitIndex, hitZLabSys); } tracklets.push_back(currentTracklet); } if (1 PndFtsHoughSpace::FindAllPeaksScanPathsMergeBinsCalculatingPaths(const UInt_t minHeight) { std::vector tracklets; // for output // check if Hough space has at least one entry if (1>GetEntries()) { if(1GetFirst(); // Int_t zlast = fZaxis->GetLast(); // find all peaks that have a height >= minHeight // go from low to high in theta <- SUPER IMPORTANT Int_t currBinNumber; Double_t currHeight; Int_t peakBinX = 0; Int_t peakBinY = 0; Int_t peakBinZ = 0; // location of maximum (x,y,z) for (Int_t currBinX=xFirstBin; currBinX<=xLastBin; ++currBinX) { for (Int_t currBinY=yFirstBin; currBinY<=yLastBin; ++currBinY) { // for (binz=zfirst;binz<=zlast;binz++) { currBinNumber = GetBin(currBinX,currBinY); // binz currHeight = GetBinContent(currBinNumber); if (minHeight > currHeight) { // currBinNumber is not high enough to be considered a peak SetBinContent(currBinNumber,0); // DEBUG: Uncomment this if you want to produce nice Hough space plots for demonstration continue; } // I found a potential peak, so I check the neighbors in next higher theta bins // I save the currently highest peak // I set the last visited peak = current peak and move to the next neighbor // if neighbor < highest peak and neighbor <= last peak, but above the minHeight, I set it to 0. I save its height as the last height. // if neighbor is higher than the last peak, I set the last visited bin to 0 and move on // if neighbor is the same height as last peak, I find the middle and set all others to 0 and I widen the errors of the middle bin Int_t iBinX = 0; // for moving to neighbors in x direction // save info of highest peak found while searching neighbors Int_t combinedPeakBinXLow=currBinX; // saves in which x (thetaRad) bin a peak starts Int_t combinedPeakBinXHigh=currBinX; // saves in which x (thetaRad) bin a peak ends Double_t combinedPeakHeight=currHeight; // save info of last visited neighbor Int_t lastVisitedBinX = currBinX; Int_t lastVisitedBinNumber = currBinNumber; Double_t lastVisitedHeight = currHeight; // storing the current neighbor bin Int_t currNeighborBinX = currBinX; Int_t currNeighborBinNumber = currBinNumber; Double_t currNeighborHeight = currHeight; do{ ++iBinX; // to move along the x bins // set current neighbor currNeighborBinX = currBinX+iBinX; if (currNeighborBinX>xLastBin){ break; } currNeighborBinNumber = GetBin(currNeighborBinX,currBinY); // binz currNeighborHeight = GetBinContent(currNeighborBinNumber); if (minHeight > currNeighborHeight){ // end of peak region in x direction found, I can get out of the loop SetBinContent(currNeighborBinNumber,0); // DEBUG: Uncomment this if you want to produce nice Hough space plots for demonstration break; } if (currNeighborHeight > combinedPeakHeight){ // actually peak starts with neighbor (or even later), but current bin is not in peak for (Int_t xBinToDel=combinedPeakBinXLow; xBinToDel<= combinedPeakBinXHigh; ++xBinToDel){ Int_t BinNumberToDel = GetBin(xBinToDel,currBinY); SetBinContent(BinNumberToDel,0); } combinedPeakBinXLow = currNeighborBinX; combinedPeakBinXHigh = currNeighborBinX; combinedPeakHeight = currNeighborHeight; } else if (currNeighborHeight < combinedPeakHeight){ if (currNeighborHeight <= lastVisitedHeight){ // peak is dropping, delete current bin (which is at the falling edge of the peak) SetBinContent(currNeighborBinNumber,0); } else { // next peak starts rising, I can end the loop break; } } else if (currNeighborHeight == combinedPeakHeight){ // peak is spread over several bins combinedPeakBinXHigh = currNeighborBinX; } lastVisitedBinX = currNeighborBinX; lastVisitedBinNumber = currNeighborBinNumber; lastVisitedHeight = currNeighborHeight; } while(kTRUE); // DEBUG: uncomment this if you want to produce nice Hough space plots for demonstration // remove the peak which was found, otherwise it (or parts of it) might be found again for (Int_t xBinToDel=combinedPeakBinXLow; xBinToDel<= combinedPeakBinXHigh; ++xBinToDel){ Int_t BinNumberToDel = GetBin(xBinToDel,currBinY); SetBinContent(BinNumberToDel,0); } // peak is in the middle peakBinX = (combinedPeakBinXHigh+combinedPeakBinXLow)/2; // if sum is not an even number, I have to correct for that later peakBinY = currBinY; // locmaz = binz; // get values corresponding to the peak Double_t peakThetaVal = fXaxis.GetBinCenter(peakBinX); Double_t peakSecondVal = fYaxis.GetBinCenter(peakBinY); // correct peak value if mean for peak cannot be divided by 2 without remainder if (0!=(combinedPeakBinXHigh+combinedPeakBinXLow)%2){ peakThetaVal+=fXaxis.GetBinWidth(peakThetaVal)/2.; } // get full width of peak = (highest bin + halfwidth) - (lowest bin - halfwidth) Double_t combinedPeakThetaLowEdge = fXaxis.GetBinCenter(combinedPeakBinXLow) - fXaxis.GetBinWidth(combinedPeakBinXLow)/2.; Double_t combinedPeakThetaHighEdge = fXaxis.GetBinCenter(combinedPeakBinXHigh) + fXaxis.GetBinWidth(combinedPeakBinXHigh)/2.; Double_t peakThetaHw = (combinedPeakThetaHighEdge-combinedPeakThetaLowEdge)/2.; Double_t peakSecondHw = fYaxis.GetBinWidth(peakSecondVal)/2.; // create tracklet and push it back to output PndFtsHoughTracklet currentTracklet(fZRefPos, fTrackerTask); currentTracklet.SetHoughTransformResults(peakThetaVal, peakSecondVal, currHeight, peakThetaHw, peakSecondHw); /////////////////////////////////////////// // TODO this is messy, because the code is very similar to FillHoughSpace. Probably, I should find a way to merge it // add hits which are in the peak to the tracklet // 1 calculate the 2nd value for the next higher/lower theta bin of combined peak theta // 2 If peak 2nd value is within [min hit 2nd value - half width, max hit 2nd value + half width] add the hit to the tracklet // 3 otherwise the hit is not in the peak // This is more complicated to check, but also true // A calculate the 2nd value for peak theta // B If hit 2nd value is within [peak 2nd value - peakSecondHw, peak 2nd value + peakSecondHw] add the hit // C If hit 2nd value is < peak 2nd value - peakSecondHw, hit is in peak if the 2nd value of the next higher/lower theta bin is >= peak 2nd value // D If hit 2nd value is > peak 2nd value + peakSecondHw, hit is in peak if the 2nd value of the next lower/higher theta bin is <= peak 2nd value // E otherwise the hit is not in the peak // 1 calculate the 2nd value for the next higher/lower theta bin of peak theta UInt_t thetaBinLo = combinedPeakBinXLow-1; UInt_t thetaBinHi = combinedPeakBinXHigh+1; // special case if we are at the edge of the Hough space if (thetaBinLo>xFirstBin) { thetaBinLo=xFirstBin; } if (thetaBinHi>xLastBin) { thetaBinHi=xLastBin; } // get theta values const Double_t thetaRadLo = fXaxis.GetBinCenter(thetaBinLo); const Double_t thetaRadHi = fXaxis.GetBinCenter(thetaBinHi); // for storing the values to be calculated in Hough transform (yValue = offset for line, yValue = Q/pzx for parabola) Double_t yValLo = 0.; Double_t yValHi = 0.; for (int iHit = 0; iHit < GetNHits(); iHit++) { const PndFtsHit* myHit = getHitFromHS(iHit); // get hit position const TVector3 hitPos = GetRawOrCalculatedHitPos(myHit); Double_t hitXLabSys = hitPos.X(); Double_t hitYLabSys = hitPos.Y(); Double_t hitZLabSys = hitPos.Z(); Double_t hitXShifted = hitXLabSys - fInterceptZx; // shifts all x positions of hits so that they go through x=0 at z=zOffset (for parabola) Double_t hitZShifted = hitZLabSys - fZRefPos; // z coordinate in local coordinate system (for parabola and for line) // y component of B field Double_t By = getByFromBField(hitXLabSys, hitYLabSys, hitZLabSys); const TString option = GetName(); if ("parabola" == option) { // Use shifted x and shifted z for parabola yValLo = equationParabola(thetaRadLo, hitZShifted, hitXShifted, By); yValHi = equationParabola(thetaRadHi, hitZShifted, hitXShifted, By); if (9= peakSecondVal) ){ Int_t hitIndex = fHitId.at(iHit).GetHitId(); currentTracklet.AddHit(fFtsBranchId, hitIndex, hitZLabSys); } } // loop over hits ///////////////////////////////////////////////// tracklets.push_back(currentTracklet); // } // z loop } // y loop } // x loop if (1 PndFtsHoughSpace::FindAllPeaksWithTSpectrum2(const UInt_t minHeight) { std::vector tracklets; // for output // check if Hough space has at least one entry if (1>GetEntries()) { if(1Fill(peakTheta, peakSecond, 0); // returns binnumber without modifying the histogram if (1 PndFtsHoughSpace::FindAllPeaksBlanko(const UInt_t minHeight) { std::vector tracklets; // for output // check if Hough space has at least one entry if (1>GetEntries()) { if(1minHeight, merge peaks // find bin >= minHeight, then merge with neighboring bins of equal height, set surrounding bins to 0 (otherwise tail of peaks will be found in addition to peak itself)