diff --git a/Recon/include/Recon/ParticleFlow.h b/Recon/include/Recon/ParticleFlow.h index dc2d2911b..b61e93bfb 100644 --- a/Recon/include/Recon/ParticleFlow.h +++ b/Recon/include/Recon/ParticleFlow.h @@ -13,6 +13,13 @@ #include "Framework/EventProcessor.h" //Needed to declare processor #include "TGraph.h" +#include "SimCore/Event/SimParticle.h" +#include "SimCore/Event/SimTrackerHit.h" +#include "Recon/Event/CaloCluster.h" +#include "Ecal/Event/EcalCluster.h" +#include "Hcal/Event/HcalCluster.h" +#include "Recon/Event/PFCandidate.h" + namespace recon { /** @@ -36,6 +43,10 @@ class ParticleFlow : public framework::Producer { virtual void onProcessEnd(); + void FillCandTrack(ldmx::PFCandidate &cand, const ldmx::SimTrackerHit &tk); + void FillCandEMCalo(ldmx::PFCandidate &cand, const ldmx::CaloCluster &em); + void FillCandHadCalo(ldmx::PFCandidate &cand, const ldmx::CaloCluster &had); + private: // specific verbosity of this producer int verbose_{0}; @@ -49,6 +60,8 @@ class ParticleFlow : public framework::Producer { std::string inputTrackCollName_; // name of collection for PF outputs std::string outputCollName_; + // configuration + bool singleParticle_; }; } // namespace recon diff --git a/Recon/python/pfReco.py b/Recon/python/pfReco.py index 372fd9374..30ce40f1c 100644 --- a/Recon/python/pfReco.py +++ b/Recon/python/pfReco.py @@ -49,6 +49,7 @@ def __init__(self, name='PFlow') : self.inputHcalCollName = 'PFHcalClusters' self.inputTrackCollName = 'PFTracks' self.outputCollName = 'PFCandidates' + self.singleParticle = False class pfTruthProducer(ldmxcfg.Producer) : """Configuration for track selector for particle reco""" diff --git a/Recon/src/Recon/DBScanClusterBuilder.cxx b/Recon/src/Recon/DBScanClusterBuilder.cxx index 96ccf0004..6c33ce235 100644 --- a/Recon/src/Recon/DBScanClusterBuilder.cxx +++ b/Recon/src/Recon/DBScanClusterBuilder.cxx @@ -82,9 +82,9 @@ namespace recon { float e(0),x(0),y(0),z(0),xx(0),yy(0),zz(0),n(0); float w = 1; // weight float sumw = 0; - std::vector xvals{}; - std::vector yvals{}; - std::vector zvals{}; + // std::vector xvals{}; + // std::vector yvals{}; + // std::vector zvals{}; std::vector raw_xvals{}; std::vector raw_yvals{}; std::vector raw_zvals{}; @@ -102,9 +102,9 @@ namespace recon { zz += w * h->getZPos() * h->getZPos(); n += 1; sumw += w; - xvals.push_back(x); - yvals.push_back(y); - zvals.push_back(z); + // xvals.push_back(x); // unused + // yvals.push_back(y); + // zvals.push_back(z); raw_xvals.push_back(h->getXPos()); raw_yvals.push_back(h->getYPos()); raw_zvals.push_back(h->getZPos()); @@ -128,20 +128,28 @@ namespace recon { cl->setHitValsZ(raw_zvals); cl->setHitValsE(raw_evals); - if (xvals.size()>2){ - for(int i=0; i2){ + // skip fits for 'vertical' clusters + std::vector sortedZ = raw_zvals; + std::sort(sortedZ.begin(), sortedZ.end()); + if (sortedZ[sortedZ.size()-1] - sortedZ[0] > 1e3){ + + for(int i=0; isetDXDZ( r_xz->Value(1) ); + cl->setEDXDZ( r_xz->ParError(1) ); + + TGraph gyz(raw_zvals.size(), raw_zvals.data(), raw_yvals.data()); + auto r_yz = gyz.Fit("pol1","SQ"); // p0 + x*p1 + cl->setDYDZ( r_yz->Value(1) ); + cl->setEDYDZ( r_yz->ParError(1) ); } - TGraph gxz(zvals.size(), zvals.data(), xvals.data()); - auto r_xz = gxz.Fit("pol1","SQ"); // p0 + x*p1 - cl->setDXDZ( r_xz->Value(1) ); - cl->setEDXDZ( r_xz->ParError(1) ); - TGraph gyz(zvals.size(), zvals.data(), yvals.data()); - auto r_yz = gyz.Fit("pol1","SQ"); // p0 + x*p1 - cl->setDYDZ( r_yz->Value(1) ); - cl->setEDYDZ( r_yz->ParError(1) ); } return; } diff --git a/Recon/src/Recon/PFTrackProducer.cxx b/Recon/src/Recon/PFTrackProducer.cxx index ec5db2753..3d1b80965 100644 --- a/Recon/src/Recon/PFTrackProducer.cxx +++ b/Recon/src/Recon/PFTrackProducer.cxx @@ -10,6 +10,11 @@ void PFTrackProducer::configure(framework::config::Parameters& ps) { outputTrackCollName_ = ps.getParameter("outputTrackCollName"); } +double getP(const ldmx::SimTrackerHit &tk){ + std::vector pxyz = tk.getMomentum(); + return sqrt(pow(pxyz[0],2)+pow(pxyz[1],2)+pow(pxyz[2],2)); +} + void PFTrackProducer::produce(framework::Event& event) { if (!event.exists(inputTrackCollName_)) return; @@ -26,7 +31,7 @@ void PFTrackProducer::produce(framework::Event& event) { } std::sort(pfTracks.begin(), pfTracks.end(), [](ldmx::SimTrackerHit a, ldmx::SimTrackerHit b) { - return a.getEnergy() > b.getEnergy(); + return getP(a) > getP(b); }); event.add(outputTrackCollName_, pfTracks); } diff --git a/Recon/src/Recon/ParticleFlow.cxx b/Recon/src/Recon/ParticleFlow.cxx index 689b356c9..02c848955 100644 --- a/Recon/src/Recon/ParticleFlow.cxx +++ b/Recon/src/Recon/ParticleFlow.cxx @@ -1,21 +1,19 @@ #include "Recon/ParticleFlow.h" -#include "SimCore/Event/SimParticle.h" -#include "SimCore/Event/SimTrackerHit.h" -#include "Recon/Event/CaloCluster.h" -#include "Ecal/Event/EcalCluster.h" -#include "Hcal/Event/HcalCluster.h" -#include "Recon/Event/PFCandidate.h" #include namespace recon { void ParticleFlow::configure(framework::config::Parameters& ps) { + // I/O inputEcalCollName_ = ps.getParameter("inputEcalCollName"); inputHcalCollName_ = ps.getParameter("inputHcalCollName"); inputTrackCollName_ = ps.getParameter("inputTrackCollName"); outputCollName_ = ps.getParameter("outputCollName"); - //from jason + // Algorithm configuration + singleParticle_ = ps.getParameter("singleParticle"); + + // Calibration factors, from jason std::vector em1{250.0,750.0,1250.0,1750.0,2250.0,2750.0,3250.0,3750.0,4250.0,4750.0,5250.0,5750.}; std::vector em2{1.175,1.02,0.99,0.985,0.975,0.975,0.96,0.94,0.87,0.8,0.73,0.665}; std::vector h1{25.0,75.0,125.0,175.0,225.0,275.0,325.0,375.0,425.0}; @@ -24,6 +22,75 @@ void ParticleFlow::configure(framework::config::Parameters& ps) { hCorr_ = new TGraph(h1.size(), h1.data(), h2.data()); } +void ParticleFlow::FillCandTrack(ldmx::PFCandidate &cand, const ldmx::SimTrackerHit &tk){ + // TODO: smear + std::vector xyz = tk.getPosition(); + std::vector pxyz = tk.getMomentum(); + float ecalZ = 248; + float ecalX = xyz[0] + pxyz[0]/pxyz[2] * (ecalZ - xyz[2]); + float ecalY = xyz[1] + pxyz[1]/pxyz[2] * (ecalZ - xyz[2]); + cand.setEcalPositionXYZ(ecalX, ecalY, ecalZ); + cand.setTrackPxPyPz(pxyz[0], pxyz[1], pxyz[2]); + // also use this object to set truth info + cand.setTruthEcalXYZ(ecalX, ecalY, ecalZ); + cand.setTruthPxPyPz(pxyz[0], pxyz[1], pxyz[2]); + float m2 = pow(tk.getEnergy(),2) - pow(pxyz[0],2) - pow(pxyz[1],2) - pow(pxyz[2],2); + if(m2<0) m2=0; + cand.setTruthMass(sqrt(m2)); + cand.setTruthEnergy(tk.getEnergy()); + cand.setTruthPdgId(tk.getPdgID()); + cand.setPID( cand.getPID() | 1 ); +} +void ParticleFlow::FillCandEMCalo(ldmx::PFCandidate &cand, const ldmx::CaloCluster &em){ + float corr = 1.; + float e = em.getEnergy(); + if (eGetX()[0]){ + corr = eCorr_->GetX()[0]; + } else if (e>eCorr_->GetX()[eCorr_->GetN()-1]){ + corr = eCorr_->GetX()[eCorr_->GetN()-1]; + } else { + corr = eCorr_->Eval(e); + } + cand.setEcalEnergy( e*corr ); + cand.setEcalRawEnergy( e ); + cand.setEcalClusterXYZ(em.getCentroidX(), + em.getCentroidY(), + em.getCentroidZ()); + cand.setEcalClusterEXYZ(em.getRMSX(), + em.getRMSY(), + em.getRMSZ()); + cand.setEcalClusterDXDZ(em.getDXDZ()); + cand.setEcalClusterDYDZ(em.getDYDZ()); + cand.setEcalClusterEDXDZ(em.getEDXDZ()); + cand.setEcalClusterEDYDZ(em.getEDYDZ()); + cand.setPID( cand.getPID() | 2 ); +} +void ParticleFlow::FillCandHadCalo(ldmx::PFCandidate &cand, const ldmx::CaloCluster &had){ + float corr = 1.; + float e = had.getEnergy(); + if (eGetX()[0]){ + corr = hCorr_->GetX()[0]; + } else if (e>hCorr_->GetX()[hCorr_->GetN()-1]){ + corr = hCorr_->GetX()[hCorr_->GetN()-1]; + } else { + corr = hCorr_->Eval(e); + } + cand.setHcalEnergy( e*corr ); + cand.setHcalRawEnergy( e ); + cand.setHcalClusterXYZ(had.getCentroidX(), + had.getCentroidY(), + had.getCentroidZ()); + cand.setHcalClusterEXYZ(had.getRMSX(), + had.getRMSY(), + had.getRMSZ()); + cand.setHcalClusterDXDZ(had.getDXDZ()); + cand.setHcalClusterDYDZ(had.getDYDZ()); + cand.setHcalClusterEDXDZ(had.getEDXDZ()); + cand.setHcalClusterEDYDZ(had.getEDYDZ()); + cand.setPID( cand.getPID() | 4 ); +} + + void ParticleFlow::produce(framework::Event& event) { if (!event.exists(inputTrackCollName_)) return; @@ -32,142 +99,267 @@ void ParticleFlow::produce(framework::Event& event) { const auto ecalClusters = event.getCollection(inputEcalCollName_); const auto hcalClusters = event.getCollection(inputHcalCollName_); const auto tracks = event.getCollection(inputTrackCollName_); - - //std::cout << ecalClusters.size() << " " << hcalClusters.size() << " " << tracks.size() << std::endl; - - /* - 1. Build links maps at the Tk/Ecal and Hcal/Hcal interfaces - 2. Categorize tracks as: Ecal-matched, (Side) Hcal-matched, unmatched - 3. Categorize Ecal clusters as: Hcal-matched, unmatched - 4a. (Upstream?) Categorize tracks with dedx? - 4b. (Upstream?) Categorize ecal clusters as: EM/Had-like - 4c. (Upstream?) Categorize hcal clusters as: EM/Had-like - 5. Build candidates by category, moving from Tk-Ecal-Hcal - */ - - // track-calo linking - std::map > tkCaloMap; - for(int i=0; i pfCands; + if(!singleParticle_){ + /* + 1. Build links maps at the Tk/Ecal and Hcal/Hcal interfaces + 2. Categorize tracks as: Ecal-matched, (Side) Hcal-matched, unmatched + 3. Categorize Ecal clusters as: Hcal-matched, unmatched + 4a. (Upstream?) Categorize tracks with dedx? + 4b. (Upstream?) Categorize ecal clusters as: EM/Had-like + 4c. (Upstream?) Categorize hcal clusters as: EM/Had-like + 5. Build candidates by category, moving from Tk-Ecal-Hcal + */ + + // + // track-calo linking + // + std::map > tkCaloMap; + std::map > caloTkMap; + std::map, float > tkEMDist; + //std::vector unmatchedTracks; + for(int i=0; i xyz = tk.getPosition(); + const std::vector pxyz = tk.getMomentum(); + const float p = sqrt(pow(pxyz[0],2)+pow(pxyz[1],2)+pow(pxyz[2],2)); + //float bestMatchVal = 9e9; + for(int j=0; j 0.3*p && ecal.getEnergy() < 2*p); + //if (isMatch && dist < bestMatchVal) bestMatchVal = dist; + if(isMatch){ + if (tkCaloMap.count(i)) tkCaloMap[i].push_back(j); + else tkCaloMap[i] = {j}; + if (caloTkMap.count(j)) caloTkMap[j].push_back(i); + else caloTkMap[j] = {i}; + } } } - } - // em-hadcalo linking - std::map > emHadCaloMap; - for(int i=0; i > emHadCaloMap; + std::map, float > EMHadDist; + for(int i=0; i > tkHadCaloMap; - for(int i=0; i > tkHadCaloMap; + // for(int i=0; i tkIsEMLinked (tracks.size(), false); + std::vector EMIsTkLinked (ecalClusters.size(), false); + std::map tkEMPairs{}; + for(int i=0; i pfCands; - // Single-particle builder - ldmx::PFCandidate pf; - int pid=0; - if (tracks.size()){ - const auto& tk = tracks[0]; - // TODO: smear - std::vector xyz = tk.getPosition(); - std::vector pxyz = tk.getMomentum(); - float ecalZ = 248; - float ecalX = xyz[0] + pxyz[0]/pxyz[2] * (ecalZ - xyz[2]); - float ecalY = xyz[1] + pxyz[1]/pxyz[2] * (ecalZ - xyz[2]); - pf.setEcalPositionXYZ(ecalX, ecalY, ecalZ); - pf.setTrackPxPyPz(pxyz[0], pxyz[1], pxyz[2]); - pid += 1; - // also use this object to set truth info - pf.setTruthEcalXYZ(ecalX, ecalY, ecalZ); - pf.setTruthPxPyPz(pxyz[0], pxyz[1], pxyz[2]); - float m2 = pow(tk.getEnergy(),2) - pow(pxyz[0],2) - pow(pxyz[1],2) - pow(pxyz[2],2); - if(m2<0) m2=0; - pf.setTruthMass(sqrt(m2)); - pf.setTruthEnergy(tk.getEnergy()); - pf.setTruthPdgId(tk.getPdgID()); - } - if (ecalClusters.size()){ - const auto& em = ecalClusters[0]; - float corr = 1.; - float e = em.getEnergy(); - if (eGetX()[0]){ - corr = eCorr_->GetX()[0]; - } else if (e>eCorr_->GetX()[eCorr_->GetN()-1]){ - corr = eCorr_->GetX()[eCorr_->GetN()-1]; - } else { - corr = eCorr_->Eval(e); + + // track / ecal cluster arbitration + std::vector EMIsHadLinked (ecalClusters.size(), false); + std::vector HadIsEMLinked (hcalClusters.size(), false); + std::map EMHadPairs{}; + for(int i=0; iGetX()[0]){ - corr = hCorr_->GetX()[0]; - } else if (e>hCorr_->GetX()[hCorr_->GetN()-1]){ - corr = hCorr_->GetX()[hCorr_->GetN()-1]; - } else { - corr = hCorr_->Eval(e); + + // can consider combining satellite clusters here... + // define some "primary cluster" ID criterion + // and can add fails to the primaries + + // + // Begin building pf candidates from tracks + // + // std::vector chargedMatch; + // std::vector chargedUnmatch; + for(int i=0; i emMatch; + // std::vector emUnmatch; + for(int i=0; i hadOnly; + for(int i=0; i caloMatchedTks; + // std::vector unmatchedTks; + // std::vector emUsed (ecalClusters.size(), false); + // for(int i=0; i hadUsed (hcalClusters.size(), false); + // for(int i=0; i unmatchedEMs; + // for(int i=0; i