From 94de2a2228d9ddb1ba8c238eb72a3befbe863276 Mon Sep 17 00:00:00 2001 From: Kenneth Long Date: Thu, 15 Jul 2021 15:07:14 +0200 Subject: [PATCH 01/17] Update SC class --- .../CaloAnalysis/interface/SimCluster.h | 59 +++++++-- SimDataFormats/CaloAnalysis/src/SimCluster.cc | 114 +++++++++++++++++- .../CaloAnalysis/src/classes_def.xml | 3 +- 3 files changed, 166 insertions(+), 10 deletions(-) diff --git a/SimDataFormats/CaloAnalysis/interface/SimCluster.h b/SimDataFormats/CaloAnalysis/interface/SimCluster.h index 30b75545cc0dd..5983b020a0c8a 100644 --- a/SimDataFormats/CaloAnalysis/interface/SimCluster.h +++ b/SimDataFormats/CaloAnalysis/interface/SimCluster.h @@ -9,6 +9,7 @@ #include "SimDataFormats/Track/interface/SimTrack.h" #include +#include "DataFormats/GeometryVector/interface/GlobalPoint.h" // // Forward declarations // @@ -43,20 +44,23 @@ class SimCluster { SimCluster(); SimCluster(const SimTrack &simtrk); - SimCluster(EncodedEventId eventID, uint32_t particleID); // for PU + SimCluster(EncodedEventId eventID, uint32_t particleID); // for PU + SimCluster(const std::vector &simtrks, int pdgId = 0); // for merged clusters // destructor ~SimCluster(); /** @brief PDG ID. * - * Returns the PDG ID of the first associated gen particle. If there are no - * gen particles associated then it returns type() from the first SimTrack. */ + * Returns the PDG ID. If not id is set, the id of first associated gen particle is returned. If + * there are no gen particles associated then it returns type() from the first SimTrack. */ int pdgId() const { - if (genParticles_.empty()) - return g4Tracks_[0].type(); - else + if (pdgId_ != 0) + return pdgId_; + else if (!genParticles_.empty()) return (*genParticles_.begin())->pdgId(); + else + return g4Tracks_[0].type(); } /** @brief Signal source, crossing number. @@ -65,9 +69,11 @@ class SimCluster { * SimTracks from different crossings in the SimCluster. */ EncodedEventId eventId() const { return event_; } + void merge(); + uint64_t particleId() const { return particleId_; } - // Setters for G4 and reco::GenParticle + // Setters for G4 and reco::GenParticle,2 void addGenParticle(const reco::GenParticleRef &ref) { genParticles_.push_back(ref); } void addG4Track(const SimTrack &t) { g4Tracks_.push_back(t); } /// iterators @@ -180,6 +186,19 @@ class SimCluster { /** @brief add rechit energy */ void addHitEnergy(float energy) { energies_.emplace_back(energy); } + /** @brief Same as addRecHitAndFraction but when the hit is already registered, the fraction + * is increased. */ + void addDuplicateRecHitAndFraction(uint32_t hit, float fraction) { + std::vector::iterator it = std::find(hits_.begin(), hits_.end(), hit); + if (it == hits_.end()) { + // not added yet + addRecHitAndFraction(hit, fraction); + } else { + int i = std::distance(hits_.begin(), it); + fractions_[i] += fraction; + } + } + /** @brief Returns list of rechit IDs and fractions for this SimCluster */ std::vector> hits_and_fractions() const { std::vector> result; @@ -215,10 +234,30 @@ class SimCluster { /** @brief add simhit's energy to cluster */ void addSimHit(const PCaloHit &hit) { simhit_energy_ += hit.energy(); } + void setImpactPoint(const math::XYZTLorentzVectorF &point) { impactPoint_ = point; } + const math::XYZTLorentzVectorF &impactPoint() const { return impactPoint_; } + + void setImpactMomentum(const math::XYZTLorentzVectorF &mom) { impactMomentum_ = mom; } + const math::XYZTLorentzVectorF &impactMomentum() const { return impactMomentum_; } + + math::XYZTLorentzVectorF impactMomentumMuOnly() const; + math::XYZTLorentzVectorF impactMomentumNoMu() const; + + const std::vector &subImpactPoints() const { return subImpacts_; } + void setSubImpactPoints(const std::vector &p) { subImpacts_ = p; } + + void setPdgId(int id) { pdgId_ = id; } + + bool hasHGCALHit() const; + bool allHitsHGCAL() const; + + SimCluster operator+(const SimCluster&); + SimCluster& operator+=(const SimCluster&); private: uint64_t nsimhits_; EncodedEventId event_; + int pdgId_; uint32_t particleId_; float simhit_energy_; std::vector hits_; @@ -230,6 +269,12 @@ class SimCluster { /// references to G4 and reco::GenParticle tracks std::vector g4Tracks_; reco::GenParticleRefVector genParticles_; + + //no need to make this all double + math::XYZTLorentzVectorF impactPoint_; + math::XYZTLorentzVectorF impactMomentum_; + + std::vector subImpacts_; }; #endif // SimDataFormats_SimCluster_H diff --git a/SimDataFormats/CaloAnalysis/src/SimCluster.cc b/SimDataFormats/CaloAnalysis/src/SimCluster.cc index d901cd1f29947..cfd7db5cbe3e2 100644 --- a/SimDataFormats/CaloAnalysis/src/SimCluster.cc +++ b/SimDataFormats/CaloAnalysis/src/SimCluster.cc @@ -3,6 +3,10 @@ #include "DataFormats/HepMCCandidate/interface/GenParticle.h" #include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "DataFormats/DetId/interface/DetId.h" +#include "DataFormats/ForwardDetId/interface/ForwardSubdetector.h" +#include "DataFormats/ForwardDetId/interface/HFNoseDetId.h" +#include "DataFormats/HcalDetId/interface/HcalDetId.h" #include @@ -10,6 +14,10 @@ const unsigned int SimCluster::longLivedTag = 65536; SimCluster::SimCluster() { // No operation + + impactPoint_ = math::XYZTLorentzVectorF(0, 0, 0, 0); + impactMomentum_ = math::XYZTLorentzVectorF(0, 0, 0, 0); + pdgId_ = 0; } SimCluster::SimCluster(const SimTrack &simtrk) { @@ -19,6 +27,7 @@ SimCluster::SimCluster(const SimTrack &simtrk) { theMomentum_.SetPxPyPzE( simtrk.momentum().px(), simtrk.momentum().py(), simtrk.momentum().pz(), simtrk.momentum().E()); + pdgId_ = simtrk.type(); } SimCluster::SimCluster(EncodedEventId eventID, uint32_t particleID) { @@ -26,11 +35,112 @@ SimCluster::SimCluster(EncodedEventId eventID, uint32_t particleID) { particleId_ = particleID; } +SimCluster::SimCluster(const std::vector &simtrks, int pdgId) { + if (simtrks.size() > 0) { + double sumPx = 0.; + double sumPy = 0.; + double sumPz = 0.; + double sumE = 0.; + + for (const SimTrack &t : simtrks) { + addG4Track(t); + sumPx += t.momentum().px(); + sumPy += t.momentum().py(); + sumPz += t.momentum().pz(); + sumE += t.momentum().E(); + } + + theMomentum_.SetPxPyPzE(sumPx, sumPy, sumPz, sumE); + + // set event and particle ID (!= pdgID) from the first track for consistency + event_ = simtrks[0].eventId(); + particleId_ = simtrks[0].trackId(); + } + + pdgId_ = pdgId; +} + +math::XYZTLorentzVectorF SimCluster::impactMomentumMuOnly() const { + math::XYZTLorentzVectorF mom; + for (auto& t : g4Tracks_) { + if (std::abs(t.type()) == 13) + mom += t.getMomentumAtBoundary(); + } + return mom; +} + +math::XYZTLorentzVectorF SimCluster::impactMomentumNoMu() const { + math::XYZTLorentzVectorF mom; + for (auto& t : g4Tracks_) { + if (std::abs(t.type()) != 13) + mom += t.getMomentumAtBoundary(); + } + return mom; +} + +SimCluster SimCluster::operator+(const SimCluster& toAdd) { + SimCluster orig = *this; + return orig += toAdd; +} + +SimCluster& SimCluster::operator+=(const SimCluster& toMerge) { + for (auto& track : toMerge.g4Tracks()) + this->addG4Track(track); + + for (auto& hit_and_e : toMerge.hits_and_fractions()) + this->addDuplicateRecHitAndFraction(hit_and_e.first, hit_and_e.second); + + auto& mergeMom = toMerge.impactMomentum(); + float sumE = impactMomentum_.energy() + mergeMom.energy(); + impactPoint_ = (impactPoint_*impactMomentum_.energy() + mergeMom.energy()*toMerge.impactPoint())/sumE; + + this->impactMomentum_ += mergeMom; + return *this; +} + +// At least one simHit in the HGCAL +bool SimCluster::allHitsHGCAL() const { + for (const auto& hitsAndEnergies : hits_and_fractions()) { + const DetId id = hitsAndEnergies.first; + bool forward = id.det() == DetId::HGCalEE + || id.det() == DetId::HGCalHSi + || id.det() == DetId::HGCalHSc + || (id.det() == DetId::Forward && id.subdetId() != static_cast(HFNose)) + || (id.det() == DetId::Hcal && id.subdetId() == HcalSubdetector::HcalEndcap); + + if(!forward) + return false; + } + return true; +} + +bool SimCluster::hasHGCALHit() const { + for (const auto& hitsAndEnergies : hits_and_fractions()) { + const DetId id = hitsAndEnergies.first; + bool forward = id.det() == DetId::HGCalEE + || id.det() == DetId::HGCalHSi + || id.det() == DetId::HGCalHSc + || (id.det() == DetId::Forward && id.subdetId() != static_cast(HFNose)) + || (id.det() == DetId::Hcal && id.subdetId() == HcalSubdetector::HcalEndcap); + + if(forward) + return true; + } + return false; +} + SimCluster::~SimCluster() {} std::ostream &operator<<(std::ostream &s, SimCluster const &tp) { - s << "CP momentum, q, ID, & Event #: " << tp.p4() << " " << tp.charge() << " " << tp.pdgId() << " " - << tp.eventId().bunchCrossing() << "." << tp.eventId().event() << std::endl; + s << "SC momentum(eta,phi,pt,m), q, ID, & Event #: " << tp.p4().Eta() << ", " << tp.p4().Phi() << ", " << tp.p4().Pt() + << ", " << tp.p4().M() << " " + << " " << tp.charge() << " " << tp.pdgId() << " " << tp.eventId().bunchCrossing() << "." << tp.eventId().event() + << std::endl; + + s << "Impact position (eta,phi,z,t) " << tp.impactPoint().Eta() << " " << tp.impactPoint().Phi() << " " + << tp.impactPoint().Z() << " " << tp.impactPoint().M() << std::endl; + s << "Impact momentum (eta,phi,pt,M) " << tp.impactMomentum().Eta() << " " << tp.impactMomentum().Phi() << " " + << tp.impactMomentum().Pt() << " " << tp.impactMomentum().M() << std::endl; for (SimCluster::genp_iterator hepT = tp.genParticle_begin(); hepT != tp.genParticle_end(); ++hepT) { s << " HepMC Track Momentum " << (*hepT)->momentum().rho() << std::endl; diff --git a/SimDataFormats/CaloAnalysis/src/classes_def.xml b/SimDataFormats/CaloAnalysis/src/classes_def.xml index 89a2b4c9f5aaf..8b6272336f55b 100644 --- a/SimDataFormats/CaloAnalysis/src/classes_def.xml +++ b/SimDataFormats/CaloAnalysis/src/classes_def.xml @@ -8,7 +8,8 @@ - + + From f9654625a1274d11c1216131853be87a5ca99e66 Mon Sep 17 00:00:00 2001 From: Kenneth Long Date: Thu, 15 Jul 2021 16:27:01 +0200 Subject: [PATCH 02/17] Pull most things one by one --- DPGAnalysis/CommonNanoAOD/BuildFile.xml | 6 + .../CommonNanoAOD/plugins/BuildFile.xml | 19 + .../plugins/HitPositionTableProducer.cc | 119 ++ DPGAnalysis/HGCalNanoAOD/BuildFile.xml | 6 + .../HGCalNanoAOD/plugins/BuildFile.xml | 18 + .../ObjectIndexFromAssociationProducer.cc | 33 + ...dexFromOneToManyQualAssociationProducer.cc | 21 + .../SimClusterRecEnergyTableProducer.cc | 7 + .../SimpleHGCFlatTableProducerPlugins.cc | 21 + .../HGCalNanoAOD/python/caloParticles_cff.py | 20 + .../python/hgcRecHitSimAssociations_cff.py | 103 ++ .../HGCalNanoAOD/python/hgcRecHits_cff.py | 82 ++ .../HGCalNanoAOD/python/hgcSimHits_cff.py | 68 + .../HGCalNanoAOD/python/hgcSimTracks_cff.py | 41 + .../HGCalNanoAOD/python/layerClusters_cff.py | 33 + .../HGCalNanoAOD/python/nanoHGCML_cff.py | 54 + .../HGCalNanoAOD/python/simClusters_cff.py | 80 ++ .../HGCalNanoAOD/test/nanoMLGSD_cfg.py | 117 ++ DPGAnalysis/HGCalNanoAOD/test/nanoML_cfg.py | 116 ++ DPGAnalysis/PFNanoAOD/plugins/BuildFile.xml | 16 + .../PFObjectIndexToAssociationProducer.cc | 13 + ...implePFParticleFlatTableProducerPlugins.cc | 7 + DPGAnalysis/PFNanoAOD/python/pfCands_cff.py | 32 + DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py | 43 + DPGAnalysis/TrackNanoAOD/BuildFile.xml | 6 + .../TrackNanoAOD/plugins/BuildFile.xml | 18 + .../SimpleTrackFlatTableProducerPlugins.cc | 18 + .../TrackPositionAtHGCALTableProducer.cc | 65 + .../TrackNanoAOD/python/trackSimHits_cff.py | 53 + .../python/trackingParticles_cff.py | 28 + DPGAnalysis/TrackNanoAOD/python/tracks_cff.py | 54 + .../TrackNanoAOD/test/nanoMLGSD_cfg.py | 118 ++ DPGAnalysis/TrackNanoAOD/test/nanoML_cfg.py | 120 ++ HGCSimTruth/HGCSimTruth/.DS_Store | Bin 0 -> 8196 bytes HGCSimTruth/HGCSimTruth/._.DS_Store | Bin 0 -> 120 bytes HGCSimTruth/HGCSimTruth/BuildFile.xml | 25 + .../HGCSimTruth/interface/SimClusterTools.h | 42 + HGCSimTruth/HGCSimTruth/plugins/BuildFile.xml | 25 + .../HGCSimTruth/plugins/HGCSimTruth.cc | 722 ++++++++++ .../plugins/SimClusterTreeMerger.cc | 1280 +++++++++++++++++ ...ngParticleSimClusterAssociationProducer.cc | 102 ++ .../HGCSimTruth/src/SimClusterTools.cpp | 121 ++ HGCSimTruth/HGCSimTruth/test/digi.py | 198 +++ HGCSimTruth/HGCSimTruth/test/gen_sim.py | 256 ++++ HGCSimTruth/HGCSimTruth/test/plots.py | 237 +++ HGCSimTruth/HGCSimTruth/test/reco.py | 160 +++ .../test/testTPtoSCAssociationAlgo.py | 51 + .../test/testTPtoSCAssociationProd.py | 71 + .../ObjectIndexFromAssociationProducer.h | 55 + ...ndexFromOneToManyQualAssociationProducer.h | 76 + .../ObjectPropertyFromIndexMapTableProducer.h | 74 + .../interface/SimpleFlatTableProducer.h | 5 + PhysicsTools/NanoAOD/plugins/BuildFile.xml | 4 + .../plugins/SimpleFlatTableProducerPlugins.cc | 2 +- RecoHGCal/GraphReco/BuildFile.xml | 18 + RecoHGCal/GraphReco/README.md | 83 ++ RecoHGCal/GraphReco/bin/BuildFile.xml | 6 + RecoHGCal/GraphReco/bin/plotTestOutput.cpp | 116 ++ .../interface/HGCalParticlePropagator.h | 54 + .../interface/HGCalTrackPropagator.h | 214 +++ .../GraphReco/interface/InferenceWindow.h | 41 + RecoHGCal/GraphReco/interface/NTupleWindow.h | 215 +++ RecoHGCal/GraphReco/interface/WindowBase.h | 305 ++++ RecoHGCal/GraphReco/plugins/BuildFile.xml | 20 + .../GraphReco/plugins/WindowInference.cc | 207 +++ RecoHGCal/GraphReco/plugins/WindowNTupler.cc | 383 +++++ .../plugins/peprCandidateFromHitProducer.cc | 372 +++++ .../peprCandidateFromHitProducer_cfi.py | 39 + .../GraphReco/python/windowInference_cfi.py | 41 + .../GraphReco/python/windowNTupler_cfi.py | 42 + .../GraphReco/src/HGCalParticlePropagator.cpp | 137 ++ RecoHGCal/GraphReco/src/InferenceWindow.cpp | 33 + RecoHGCal/GraphReco/src/NTupleWindow.cpp | 657 +++++++++ RecoHGCal/GraphReco/src/WindowBase.cpp | 238 +++ RecoHGCal/GraphReco/src/classes.h | 26 + RecoHGCal/GraphReco/src/classes_def.xml | 8 + RecoHGCal/GraphReco/test/GSD_GUN.py | 306 ++++ RecoHGCal/GraphReco/test/RECO_pf.py | 178 +++ .../GraphReco/test/cmssw_oc_forward_client.sh | 59 + .../GraphReco/test/create_dummy_graph.py | 52 + .../GraphReco/test/windowInference_cfg.py | 68 + RecoHGCal/GraphReco/test/windowNTuple_cfg.py | 90 ++ .../SimHitToSimTrackAssociationProducer.cc | 145 ++ .../Associations/src/classes_def.xml | 4 + .../CaloAnalysis/interface/SimCluster.h | 1 - SimDataFormats/CaloAnalysis/src/SimCluster.cc | 28 +- SimDataFormats/PFAnalysis/BuildFile.xml | 12 + .../PFAnalysis/interface/PFTruthParticle.h | 136 ++ .../PFAnalysis/interface/PFTruthParticleFwd.h | 16 + .../PFAnalysis/src/PFTruthParticle.cc | 48 + SimDataFormats/PFAnalysis/src/classes.h | 8 + SimDataFormats/PFAnalysis/src/classes_def.xml | 14 + 92 files changed, 9454 insertions(+), 27 deletions(-) create mode 100644 DPGAnalysis/CommonNanoAOD/BuildFile.xml create mode 100644 DPGAnalysis/CommonNanoAOD/plugins/BuildFile.xml create mode 100644 DPGAnalysis/CommonNanoAOD/plugins/HitPositionTableProducer.cc create mode 100644 DPGAnalysis/HGCalNanoAOD/BuildFile.xml create mode 100644 DPGAnalysis/HGCalNanoAOD/plugins/BuildFile.xml create mode 100644 DPGAnalysis/HGCalNanoAOD/plugins/ObjectIndexFromAssociationProducer.cc create mode 100644 DPGAnalysis/HGCalNanoAOD/plugins/ObjectIndexFromOneToManyQualAssociationProducer.cc create mode 100644 DPGAnalysis/HGCalNanoAOD/plugins/SimClusterRecEnergyTableProducer.cc create mode 100644 DPGAnalysis/HGCalNanoAOD/plugins/SimpleHGCFlatTableProducerPlugins.cc create mode 100644 DPGAnalysis/HGCalNanoAOD/python/caloParticles_cff.py create mode 100644 DPGAnalysis/HGCalNanoAOD/python/hgcRecHitSimAssociations_cff.py create mode 100644 DPGAnalysis/HGCalNanoAOD/python/hgcRecHits_cff.py create mode 100644 DPGAnalysis/HGCalNanoAOD/python/hgcSimHits_cff.py create mode 100644 DPGAnalysis/HGCalNanoAOD/python/hgcSimTracks_cff.py create mode 100644 DPGAnalysis/HGCalNanoAOD/python/layerClusters_cff.py create mode 100644 DPGAnalysis/HGCalNanoAOD/python/nanoHGCML_cff.py create mode 100644 DPGAnalysis/HGCalNanoAOD/python/simClusters_cff.py create mode 100644 DPGAnalysis/HGCalNanoAOD/test/nanoMLGSD_cfg.py create mode 100644 DPGAnalysis/HGCalNanoAOD/test/nanoML_cfg.py create mode 100644 DPGAnalysis/PFNanoAOD/plugins/BuildFile.xml create mode 100644 DPGAnalysis/PFNanoAOD/plugins/PFObjectIndexToAssociationProducer.cc create mode 100644 DPGAnalysis/PFNanoAOD/plugins/SimplePFParticleFlatTableProducerPlugins.cc create mode 100644 DPGAnalysis/PFNanoAOD/python/pfCands_cff.py create mode 100644 DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py create mode 100644 DPGAnalysis/TrackNanoAOD/BuildFile.xml create mode 100644 DPGAnalysis/TrackNanoAOD/plugins/BuildFile.xml create mode 100644 DPGAnalysis/TrackNanoAOD/plugins/SimpleTrackFlatTableProducerPlugins.cc create mode 100644 DPGAnalysis/TrackNanoAOD/plugins/TrackPositionAtHGCALTableProducer.cc create mode 100644 DPGAnalysis/TrackNanoAOD/python/trackSimHits_cff.py create mode 100644 DPGAnalysis/TrackNanoAOD/python/trackingParticles_cff.py create mode 100644 DPGAnalysis/TrackNanoAOD/python/tracks_cff.py create mode 100644 DPGAnalysis/TrackNanoAOD/test/nanoMLGSD_cfg.py create mode 100644 DPGAnalysis/TrackNanoAOD/test/nanoML_cfg.py create mode 100644 HGCSimTruth/HGCSimTruth/.DS_Store create mode 100644 HGCSimTruth/HGCSimTruth/._.DS_Store create mode 100644 HGCSimTruth/HGCSimTruth/BuildFile.xml create mode 100644 HGCSimTruth/HGCSimTruth/interface/SimClusterTools.h create mode 100644 HGCSimTruth/HGCSimTruth/plugins/BuildFile.xml create mode 100644 HGCSimTruth/HGCSimTruth/plugins/HGCSimTruth.cc create mode 100644 HGCSimTruth/HGCSimTruth/plugins/SimClusterTreeMerger.cc create mode 100644 HGCSimTruth/HGCSimTruth/plugins/TrackingParticleSimClusterAssociationProducer.cc create mode 100644 HGCSimTruth/HGCSimTruth/src/SimClusterTools.cpp create mode 100644 HGCSimTruth/HGCSimTruth/test/digi.py create mode 100644 HGCSimTruth/HGCSimTruth/test/gen_sim.py create mode 100644 HGCSimTruth/HGCSimTruth/test/plots.py create mode 100644 HGCSimTruth/HGCSimTruth/test/reco.py create mode 100644 HGCSimTruth/HGCSimTruth/test/testTPtoSCAssociationAlgo.py create mode 100644 HGCSimTruth/HGCSimTruth/test/testTPtoSCAssociationProd.py create mode 100644 PhysicsTools/NanoAOD/interface/ObjectIndexFromAssociationProducer.h create mode 100644 PhysicsTools/NanoAOD/interface/ObjectIndexFromOneToManyQualAssociationProducer.h create mode 100644 PhysicsTools/NanoAOD/interface/ObjectPropertyFromIndexMapTableProducer.h create mode 100644 RecoHGCal/GraphReco/BuildFile.xml create mode 100644 RecoHGCal/GraphReco/README.md create mode 100644 RecoHGCal/GraphReco/bin/BuildFile.xml create mode 100644 RecoHGCal/GraphReco/bin/plotTestOutput.cpp create mode 100644 RecoHGCal/GraphReco/interface/HGCalParticlePropagator.h create mode 100644 RecoHGCal/GraphReco/interface/HGCalTrackPropagator.h create mode 100644 RecoHGCal/GraphReco/interface/InferenceWindow.h create mode 100644 RecoHGCal/GraphReco/interface/NTupleWindow.h create mode 100644 RecoHGCal/GraphReco/interface/WindowBase.h create mode 100644 RecoHGCal/GraphReco/plugins/BuildFile.xml create mode 100644 RecoHGCal/GraphReco/plugins/WindowInference.cc create mode 100644 RecoHGCal/GraphReco/plugins/WindowNTupler.cc create mode 100644 RecoHGCal/GraphReco/plugins/peprCandidateFromHitProducer.cc create mode 100644 RecoHGCal/GraphReco/python/peprCandidateFromHitProducer_cfi.py create mode 100644 RecoHGCal/GraphReco/python/windowInference_cfi.py create mode 100644 RecoHGCal/GraphReco/python/windowNTupler_cfi.py create mode 100644 RecoHGCal/GraphReco/src/HGCalParticlePropagator.cpp create mode 100644 RecoHGCal/GraphReco/src/InferenceWindow.cpp create mode 100644 RecoHGCal/GraphReco/src/NTupleWindow.cpp create mode 100644 RecoHGCal/GraphReco/src/WindowBase.cpp create mode 100644 RecoHGCal/GraphReco/src/classes.h create mode 100644 RecoHGCal/GraphReco/src/classes_def.xml create mode 100644 RecoHGCal/GraphReco/test/GSD_GUN.py create mode 100644 RecoHGCal/GraphReco/test/RECO_pf.py create mode 100755 RecoHGCal/GraphReco/test/cmssw_oc_forward_client.sh create mode 100644 RecoHGCal/GraphReco/test/create_dummy_graph.py create mode 100644 RecoHGCal/GraphReco/test/windowInference_cfg.py create mode 100644 RecoHGCal/GraphReco/test/windowNTuple_cfg.py create mode 100644 SimDataFormats/Associations/plugins/SimHitToSimTrackAssociationProducer.cc create mode 100644 SimDataFormats/PFAnalysis/BuildFile.xml create mode 100644 SimDataFormats/PFAnalysis/interface/PFTruthParticle.h create mode 100644 SimDataFormats/PFAnalysis/interface/PFTruthParticleFwd.h create mode 100644 SimDataFormats/PFAnalysis/src/PFTruthParticle.cc create mode 100644 SimDataFormats/PFAnalysis/src/classes.h create mode 100644 SimDataFormats/PFAnalysis/src/classes_def.xml diff --git a/DPGAnalysis/CommonNanoAOD/BuildFile.xml b/DPGAnalysis/CommonNanoAOD/BuildFile.xml new file mode 100644 index 0000000000000..6cc75a882ba98 --- /dev/null +++ b/DPGAnalysis/CommonNanoAOD/BuildFile.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/DPGAnalysis/CommonNanoAOD/plugins/BuildFile.xml b/DPGAnalysis/CommonNanoAOD/plugins/BuildFile.xml new file mode 100644 index 0000000000000..dc57b6da53c8e --- /dev/null +++ b/DPGAnalysis/CommonNanoAOD/plugins/BuildFile.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/DPGAnalysis/CommonNanoAOD/plugins/HitPositionTableProducer.cc b/DPGAnalysis/CommonNanoAOD/plugins/HitPositionTableProducer.cc new file mode 100644 index 0000000000000..f86ee30ea25d5 --- /dev/null +++ b/DPGAnalysis/CommonNanoAOD/plugins/HitPositionTableProducer.cc @@ -0,0 +1,119 @@ +#include "FWCore/Framework/interface/stream/EDProducer.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "DataFormats/NanoAOD/interface/FlatTable.h" +#include "DataFormats/Common/interface/View.h" +#include "SimDataFormats/CaloHit/interface/PCaloHitContainer.h" +#include "SimDataFormats/TrackingHit/interface/PSimHit.h" +#include "CommonTools/Utils/interface/StringCutObjectSelector.h" + +#include "DataFormats/ForwardDetId/interface/HGCalDetId.h" +#include "DataFormats/ForwardDetId/interface/HGCScintillatorDetId.h" +#include "DataFormats/ForwardDetId/interface/HGCSiliconDetId.h" + +#include "DataFormats/GeometryVector/interface/GlobalPoint.h" +#include "Geometry/CaloGeometry/interface/CaloGeometry.h" +#include "Geometry/HGCalGeometry/interface/HGCalGeometry.h" +#include "Geometry/Records/interface/CaloGeometryRecord.h" +#include "Geometry/CommonDetUnit/interface/GlobalTrackingGeometry.h" +#include "Geometry/TrackerGeometryBuilder/interface/TrackerGeometry.h" +#include "Geometry/CSCGeometry/interface/CSCGeometry.h" +#include "Geometry/Records/interface/GlobalTrackingGeometryRecord.h" +#include "SimDataFormats/TrackingHit/interface/PSimHit.h" +#include "DataFormats/CaloRecHit/interface/CaloRecHit.h" +#include "DataFormats/HGCRecHit/interface/HGCRecHitCollections.h" +#include "RecoLocalCalo/HGCalRecAlgos/interface/RecHitTools.h" + +#include +#include + +template +class HitPositionTableProducer : public edm::stream::EDProducer<> { +public: + HitPositionTableProducer(edm::ParameterSet const& params) + : name_(params.getParameter("name")), + doc_(params.getParameter("doc")), + src_(consumes(params.getParameter("src"))), + cut_(params.getParameter("cut"), true) { + produces(); + } + + ~HitPositionTableProducer() override {} + + void beginRun(const edm::Run&, const edm::EventSetup& iSetup) override { + // TODO: check that the geometry exists + iSetup.get().get(caloGeom_); + rhtools_.setGeometry(*caloGeom_); + iSetup.get().get("idealForDigi", trackGeom_); + // Believe this is ideal, but we're not so precise here... + iSetup.get().get(globalGeom_); + } + + GlobalPoint positionFromHit(const PCaloHit& hit) { + DetId id = hit.id(); + return positionFromDetId(id); + } + + GlobalPoint positionFromHit(const CaloRecHit& hit) { return positionFromDetId(hit.detid()); } + + // Should really only be used for HGCAL + GlobalPoint positionFromDetId(DetId id) { + DetId::Detector det = id.det(); + if (det == DetId::Hcal || det == DetId::HGCalEE || det == DetId::HGCalHSi || det == DetId::HGCalHSc) { + return rhtools_.getPosition(id); + } else { + throw cms::Exception("HitPositionTableProducer") << "Unsupported DetId type"; + } + } + + GlobalPoint positionFromHit(const PSimHit& hit) { + auto detId = DetId(hit.detUnitId()); + auto surface = detId.det() == DetId::Muon ? globalGeom_->idToDet(hit.detUnitId())->surface() + : trackGeom_->idToDet(hit.detUnitId())->surface(); + GlobalPoint position = surface.toGlobal(hit.localPosition()); + return position; + } + + void produce(edm::Event& iEvent, const edm::EventSetup& iSetup) override { + edm::Handle objs; + iEvent.getByToken(src_, objs); + + std::vector xvals; + std::vector yvals; + std::vector zvals; + for (const auto& obj : *objs) { + if (cut_(obj)) { + auto position = positionFromHit(obj); + xvals.emplace_back(position.x()); + yvals.emplace_back(position.y()); + zvals.emplace_back(position.z()); + } + } + + auto tab = std::make_unique(xvals.size(), name_, false, true); + tab->addColumn("x", xvals, "x position"); + tab->addColumn("y", yvals, "y position"); + tab->addColumn("z", zvals, "z position"); + + iEvent.put(std::move(tab)); + } + +protected: + const std::string name_, doc_; + const edm::EDGetTokenT src_; + const StringCutObjectSelector cut_; + edm::ESHandle caloGeom_; + edm::ESHandle trackGeom_; + edm::ESHandle globalGeom_; + hgcal::RecHitTools rhtools_; +}; + +#include "FWCore/Framework/interface/MakerMacros.h" +typedef HitPositionTableProducer> PCaloHitPositionTableProducer; +typedef HitPositionTableProducer> PSimHitPositionTableProducer; +typedef HitPositionTableProducer HGCRecHitPositionTableProducer; +DEFINE_FWK_MODULE(HGCRecHitPositionTableProducer); +DEFINE_FWK_MODULE(PCaloHitPositionTableProducer); +DEFINE_FWK_MODULE(PSimHitPositionTableProducer); diff --git a/DPGAnalysis/HGCalNanoAOD/BuildFile.xml b/DPGAnalysis/HGCalNanoAOD/BuildFile.xml new file mode 100644 index 0000000000000..6cc75a882ba98 --- /dev/null +++ b/DPGAnalysis/HGCalNanoAOD/BuildFile.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/DPGAnalysis/HGCalNanoAOD/plugins/BuildFile.xml b/DPGAnalysis/HGCalNanoAOD/plugins/BuildFile.xml new file mode 100644 index 0000000000000..f5ae82be55fc7 --- /dev/null +++ b/DPGAnalysis/HGCalNanoAOD/plugins/BuildFile.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/DPGAnalysis/HGCalNanoAOD/plugins/ObjectIndexFromAssociationProducer.cc b/DPGAnalysis/HGCalNanoAOD/plugins/ObjectIndexFromAssociationProducer.cc new file mode 100644 index 0000000000000..49c1e6d5236e8 --- /dev/null +++ b/DPGAnalysis/HGCalNanoAOD/plugins/ObjectIndexFromAssociationProducer.cc @@ -0,0 +1,33 @@ +#include "PhysicsTools/NanoAOD/interface/ObjectIndexFromAssociationProducer.h" +#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" +#include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" +#include "SimDataFormats/CaloAnalysis/interface/CaloParticle.h" +#include "SimDataFormats/CaloAnalysis/interface/CaloParticleFwd.h" +#include "SimDataFormats/Track/interface/SimTrack.h" +#include "SimDataFormats/Track/interface/SimTrackContainer.h" +#include "SimDataFormats/CaloHit/interface/PCaloHitContainer.h" +#include "DataFormats/CaloRecHit/interface/CaloRecHit.h" +#include "DataFormats/CaloRecHit/interface/CaloCluster.h" +#include "DataFormats/HGCRecHit/interface/HGCRecHitCollections.h" +#include "DataFormats/ParticleFlowCandidate/interface/PFCandidateFwd.h" +#include "DataFormats/ParticleFlowCandidate/interface/PFCandidate.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +typedef ObjectIndexFromAssociationTableProducer + SimTrackToSimClusterIndexTableProducer; +typedef ObjectIndexFromAssociationTableProducer + CaloHitToSimClusterIndexTableProducer; +typedef ObjectIndexFromAssociationTableProducer, reco::PFCandidateCollection> + CaloRecHitToPFCandIndexTableProducer; +typedef ObjectIndexFromAssociationTableProducer, SimClusterCollection> + CaloRecHitToBestSimClusterIndexTableProducer; +typedef ObjectIndexFromAssociationTableProducer + SimClusterToCaloParticleIndexTableProducer; +typedef ObjectIndexFromAssociationTableProducer + SimClusterToSimClusterIndexTableProducer; +DEFINE_FWK_MODULE(SimTrackToSimClusterIndexTableProducer); +DEFINE_FWK_MODULE(CaloHitToSimClusterIndexTableProducer); +DEFINE_FWK_MODULE(SimClusterToCaloParticleIndexTableProducer); +DEFINE_FWK_MODULE(SimClusterToSimClusterIndexTableProducer); +DEFINE_FWK_MODULE(CaloRecHitToPFCandIndexTableProducer); +DEFINE_FWK_MODULE(CaloRecHitToBestSimClusterIndexTableProducer); diff --git a/DPGAnalysis/HGCalNanoAOD/plugins/ObjectIndexFromOneToManyQualAssociationProducer.cc b/DPGAnalysis/HGCalNanoAOD/plugins/ObjectIndexFromOneToManyQualAssociationProducer.cc new file mode 100644 index 0000000000000..2a210527206c9 --- /dev/null +++ b/DPGAnalysis/HGCalNanoAOD/plugins/ObjectIndexFromOneToManyQualAssociationProducer.cc @@ -0,0 +1,21 @@ +#include "PhysicsTools/NanoAOD/interface/ObjectIndexFromOneToManyQualAssociationProducer.h" +#include "DataFormats/CaloRecHit/interface/CaloCluster.h" +#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" +#include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" +#include "DataFormats/HGCRecHit/interface/HGCRecHitCollections.h" +#include "DataFormats/CaloRecHit/interface/CaloCluster.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +typedef ObjectIndexFromOneToManyQualAssociationTableProducer, SimClusterCollection> + LayerClusterToSimClusterIndexTableProducer; +typedef ObjectIndexFromOneToManyQualAssociationTableProducer + CaloRecHitToSimClusterIndexTableProducer; +typedef ObjectIndexFromOneToManyQualAssociationTableProducer> + HGCRecHitToLayerClusterIndexTableProducer; +typedef ObjectIndexFromOneToManyQualAssociationTableProducer + SimClusterToSimClustersIndexTableProducer; + +DEFINE_FWK_MODULE(LayerClusterToSimClusterIndexTableProducer); +DEFINE_FWK_MODULE(HGCRecHitToLayerClusterIndexTableProducer); +DEFINE_FWK_MODULE(CaloRecHitToSimClusterIndexTableProducer); +DEFINE_FWK_MODULE(SimClusterToSimClustersIndexTableProducer); diff --git a/DPGAnalysis/HGCalNanoAOD/plugins/SimClusterRecEnergyTableProducer.cc b/DPGAnalysis/HGCalNanoAOD/plugins/SimClusterRecEnergyTableProducer.cc new file mode 100644 index 0000000000000..295f71418841d --- /dev/null +++ b/DPGAnalysis/HGCalNanoAOD/plugins/SimClusterRecEnergyTableProducer.cc @@ -0,0 +1,7 @@ +#include "PhysicsTools/NanoAOD/interface/ObjectPropertyFromIndexMapTableProducer.h" +#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" +#include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +typedef ObjectPropertyFromIndexMapTableProducer SimClusterRecEnergyTableProducer; +DEFINE_FWK_MODULE(SimClusterRecEnergyTableProducer); diff --git a/DPGAnalysis/HGCalNanoAOD/plugins/SimpleHGCFlatTableProducerPlugins.cc b/DPGAnalysis/HGCalNanoAOD/plugins/SimpleHGCFlatTableProducerPlugins.cc new file mode 100644 index 0000000000000..e968d485c64ff --- /dev/null +++ b/DPGAnalysis/HGCalNanoAOD/plugins/SimpleHGCFlatTableProducerPlugins.cc @@ -0,0 +1,21 @@ +#include "PhysicsTools/NanoAOD/interface/SimpleFlatTableProducer.h" + +#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" +typedef SimpleFlatTableProducer SimpleSimClusterFlatTableProducer; + +#include "SimDataFormats/CaloHit/interface/PCaloHit.h" +typedef SimpleFlatTableProducer SimplePCaloHitFlatTableProducer; +#include "DataFormats/CaloRecHit/interface/CaloRecHit.h" +typedef SimpleFlatTableProducer SimpleCaloRecHitFlatTableProducer; + +#include "SimDataFormats/CaloAnalysis/interface/CaloParticle.h" +typedef SimpleFlatTableProducer SimpleCaloParticleFlatTableProducer; + +#include "DataFormats/CaloRecHit/interface/CaloCluster.h" +typedef SimpleFlatTableProducer SimpleCaloClusterFlatTableProducer; +#include "FWCore/Framework/interface/MakerMacros.h" +DEFINE_FWK_MODULE(SimplePCaloHitFlatTableProducer); +DEFINE_FWK_MODULE(SimpleCaloRecHitFlatTableProducer); +DEFINE_FWK_MODULE(SimpleSimClusterFlatTableProducer); +DEFINE_FWK_MODULE(SimpleCaloParticleFlatTableProducer); +DEFINE_FWK_MODULE(SimpleCaloClusterFlatTableProducer); diff --git a/DPGAnalysis/HGCalNanoAOD/python/caloParticles_cff.py b/DPGAnalysis/HGCalNanoAOD/python/caloParticles_cff.py new file mode 100644 index 0000000000000..91617d618bded --- /dev/null +++ b/DPGAnalysis/HGCalNanoAOD/python/caloParticles_cff.py @@ -0,0 +1,20 @@ +import FWCore.ParameterSet.Config as cms +from PhysicsTools.NanoAOD.common_cff import CandVars,Var + +caloParticleTable = cms.EDProducer("SimpleCaloParticleFlatTableProducer", + src = cms.InputTag("mix:MergedCaloTruth"), + cut = cms.string(""), + name = cms.string("CaloPart"), + doc = cms.string("CaloPart"), + singleton = cms.bool(False), # the number of entries is variable + extension = cms.bool(False), # this is the main table for the muons + variables = cms.PSet(CandVars, + simEnergy = Var('simEnergy', 'int', precision=-1, doc='Number of associated gen particles'), + nGenPart = Var('genParticles().size()', 'int', precision=-1, doc='Number of associated gen particles'), + GenPartIdx = Var('? genParticles.size() ? genParticles().at(0).key() : -1', 'int', precision=-1, doc='Number of associated gen particles'), + nSimHit = Var('numberOfSimHits', 'int', precision=-1, doc='Number of simhits'), + trackId = Var('g4Tracks().at(0).trackId', 'int', precision=-1, doc='Geant4 track ID of first track'), + nSimTrack = Var('g4Tracks().size', 'int', precision=-1, doc='Number of associated simtracks'), + ) +) + diff --git a/DPGAnalysis/HGCalNanoAOD/python/hgcRecHitSimAssociations_cff.py b/DPGAnalysis/HGCalNanoAOD/python/hgcRecHitSimAssociations_cff.py new file mode 100644 index 0000000000000..8fae4b33520cf --- /dev/null +++ b/DPGAnalysis/HGCalNanoAOD/python/hgcRecHitSimAssociations_cff.py @@ -0,0 +1,103 @@ +import FWCore.ParameterSet.Config as cms +from PhysicsTools.NanoAOD.common_cff import Var,P3Vars +from DPGAnalysis.HGCalNanoAOD.hgcRecHits_cff import * + +hgcRecHitsToSimClusters = cms.EDProducer("SimClusterRecHitAssociationProducer", + caloRecHits = cms.VInputTag("hgcRecHits"), + simClusters = cms.InputTag("mix:MergedCaloTruth"), +) + +hgcRecHitsToMergedSimClusters = cms.EDProducer("SimClusterRecHitAssociationProducer", + caloRecHits = cms.VInputTag("hgcRecHits"), + simClusters = cms.InputTag("hgcSimTruth"), +) + +hgcRecHitsToMergedDRSimClusters = cms.EDProducer("SimClusterRecHitAssociationProducer", + caloRecHits = cms.VInputTag("hgcRecHits"), + simClusters = cms.InputTag("hgcSimTruthDR"), +) + +hgcRecHitsToSimClusterTable = cms.EDProducer("CaloRecHitToSimClusterIndexTableProducer", + cut = hgcRecHitsTable.cut, + src = hgcRecHitsTable.src, + objName = hgcRecHitsTable.name, + branchName = cms.string("SimCluster"), + objMap = cms.InputTag("hgcRecHitsToSimClusters:hgcRecHitsToSimClus"), + docString = cms.string("All SimCluster responsible for sim energy in RecHit DetId (ordered by fraction of energy)") +) + +hgcRecHitsToBestSimClusterTable = cms.EDProducer("CaloRecHitToBestSimClusterIndexTableProducer", + cut = hgcRecHitsTable.cut, + src = hgcRecHitsTable.src, + objName = hgcRecHitsTable.name, + branchName = cms.string("BestSimCluster"), + objMap = cms.InputTag("hgcRecHitsToSimClusters:hgcRecHitsToBestSimClus"), + docString = cms.string("SimCluster responsible for most sim energy in RecHit DetId") +) + +hgcRecHitsToMergedSimClusterTable = cms.EDProducer("CaloRecHitToSimClusterIndexTableProducer", + cut = hgcRecHitsTable.cut, + src = hgcRecHitsTable.src, + objName = hgcRecHitsTable.name, + branchName = cms.string("MergedSimCluster"), + objMap = cms.InputTag("hgcRecHitsToMergedSimClusters:hgcRecHitsToSimClus"), + docString = cms.string("MergedSimClusters ordered by most sim energy in RecHit DetId") +) + +hgcRecHitsToBestMergedSimClusterTable = cms.EDProducer("CaloRecHitToBestSimClusterIndexTableProducer", + cut = hgcRecHitsTable.cut, + src = hgcRecHitsTable.src, + objName = hgcRecHitsTable.name, + branchName = cms.string("BestMergedSimCluster"), + objMap = cms.InputTag("hgcRecHitsToMergedSimClusters:hgcRecHitsToBestSimClus"), + docString = cms.string("MergedSimCluster responsible for most sim energy in RecHit DetId") +) + +hgcRecHitsToMergedDRSimClusterTable = cms.EDProducer("CaloRecHitToSimClusterIndexTableProducer", + cut = hgcRecHitsTable.cut, + src = hgcRecHitsTable.src, + objName = hgcRecHitsTable.name, + branchName = cms.string("MergedByDRSimCluster"), + objMap = cms.InputTag("hgcRecHitsToMergedDRSimClusters:hgcRecHitsToSimClus"), + docString = cms.string("MergedSimCluster responsible for most sim energy in RecHit DetId") +) + +hgcRecHitsToBestMergedDRSimClusterTable = cms.EDProducer("CaloRecHitToBestSimClusterIndexTableProducer", + cut = hgcRecHitsTable.cut, + src = hgcRecHitsTable.src, + objName = hgcRecHitsTable.name, + branchName = cms.string("BestMergedByDRSimCluster"), + objMap = cms.InputTag("hgcRecHitsToMergedDRSimClusters:hgcRecHitsToBestSimClus"), + docString = cms.string("MergedSimCluster (DeltaR merger) responsible for most sim energy in RecHit DetId") +) + +simClusterRecEnergyTable = cms.EDProducer("SimClusterRecEnergyTableProducer", + src = cms.InputTag("mix:MergedCaloTruth"), + cut = cms.string(""), + objName = cms.string("SimCluster"), + branchName = cms.string("recEnergy"), + valueMap = cms.InputTag("hgcRecHitsToSimClusters"), + docString = cms.string("SimCluster deposited reconstructed energy associated to SimCluster") +) + +mergedSimClusterRecEnergyTable = cms.EDProducer("SimClusterRecEnergyTableProducer", + src = cms.InputTag("hgcSimTruth"), + cut = cms.string(""), + objName = cms.string("MergedSimCluster"), + branchName = cms.string("recEnergy"), + valueMap = cms.InputTag("hgcRecHitsToMergedSimClusters"), + docString = cms.string("SimCluster deposited reconstructed energy associated to SimCluster") +) + +hgcRecHitSimAssociationSequence = cms.Sequence(hgcRecHitsToSimClusters + +hgcRecHitsToMergedSimClusters + +hgcRecHitsToMergedDRSimClusters + +simClusterRecEnergyTable + +mergedSimClusterRecEnergyTable + +hgcRecHitsToSimClusterTable + +hgcRecHitsToBestSimClusterTable + +hgcRecHitsToMergedSimClusterTable + +hgcRecHitsToBestMergedSimClusterTable + +hgcRecHitsToMergedDRSimClusterTable + +hgcRecHitsToBestMergedDRSimClusterTable +) diff --git a/DPGAnalysis/HGCalNanoAOD/python/hgcRecHits_cff.py b/DPGAnalysis/HGCalNanoAOD/python/hgcRecHits_cff.py new file mode 100644 index 0000000000000..f378a107d2ecd --- /dev/null +++ b/DPGAnalysis/HGCalNanoAOD/python/hgcRecHits_cff.py @@ -0,0 +1,82 @@ +import FWCore.ParameterSet.Config as cms +from PhysicsTools.NanoAOD.common_cff import Var,P3Vars + +hgcRecHits = cms.EDProducer("HGCRecHitCollectionMerger", + src = cms.VInputTag("HGCalRecHit:HGCEERecHits", + "HGCalRecHit:HGCHEFRecHits", "HGCalRecHit:HGCHEBRecHits", + ) +) + +hgcRecHitsTable = cms.EDProducer("SimpleCaloRecHitFlatTableProducer", + src = cms.InputTag("hgcRecHits"), + cut = cms.string(""), + name = cms.string("RecHitHGC"), + doc = cms.string("HGCAL RecHits"), + singleton = cms.bool(False), # the number of entries is variable + extension = cms.bool(False), # this is the main table for the muons + variables = cms.PSet( + detId = Var('detid().rawId()', 'int', precision=-1, doc='detId'), + energy = Var('energy', 'float', precision=14, doc='energy'), + time = Var('time', 'float', precision=14, doc='hit time'), + ) +) + +hgcRecHitsToPFCands = cms.EDProducer("RecHitToPFCandAssociationProducer", + caloRecHits = cms.VInputTag("hgcRecHits"), + pfCands = cms.InputTag("particleFlow"), +) + +hgcRecHitsToPFCandTable = cms.EDProducer("CaloRecHitToPFCandIndexTableProducer", + cut = hgcRecHitsTable.cut, + src = hgcRecHitsTable.src, + objName = hgcRecHitsTable.name, + branchName = cms.string("PFCand"), + objMap = cms.InputTag("hgcRecHitsToPFCands:hgcRecHitsToPFCand"), + docString = cms.string("PFCand with most associated energy in RecHit DetId") +) + +hgcRecHitsToPFTICLCands = cms.EDProducer("RecHitToPFCandAssociationProducer", + caloRecHits = cms.VInputTag("hgcRecHits"), + pfCands = cms.InputTag("pfTICL"), +) + +hgcRecHitsToPFTICLCandTable = cms.EDProducer("CaloRecHitToPFCandIndexTableProducer", + cut = hgcRecHitsTable.cut, + src = hgcRecHitsTable.src, + objName = hgcRecHitsTable.name, + branchName = cms.string("PFTICLCand"), + objMap = cms.InputTag("hgcRecHitsToPFTICLCands:hgcRecHitsToPFCand"), + docString = cms.string("PFTICLCand with most associated energy in RecHit DetId") +) + +hgcRecHitsToLayerClusters = cms.EDProducer("RecHitToLayerClusterAssociationProducer", + caloRecHits = cms.VInputTag("hgcRecHits"), + layerClusters = cms.InputTag("hgcalLayerClusters"), +) + +hgcRecHitsToLayerClusterTable = cms.EDProducer("HGCRecHitToLayerClusterIndexTableProducer", + cut = hgcRecHitsTable.cut, + src = hgcRecHitsTable.src, + objName = hgcRecHitsTable.name, + branchName = cms.string("LayerCluster"), + objMap = cms.InputTag("hgcRecHitsToLayerClusters:hgcRecHitsToLayerCluster"), + docString = cms.string("LayerCluster assigned largest RecHit fraction") +) + +hgcRecHitsPositionTable = cms.EDProducer("HGCRecHitPositionTableProducer", + src = hgcRecHitsTable.src, + cut = hgcRecHitsTable.cut, + name = hgcRecHitsTable.name, + doc = hgcRecHitsTable.doc, +) + +hgcRecHitsSequence = cms.Sequence(hgcRecHits + +hgcRecHitsTable + +hgcRecHitsToPFCands + +hgcRecHitsToPFCandTable + +hgcRecHitsToPFTICLCands + +hgcRecHitsToPFTICLCandTable + +hgcRecHitsToLayerClusters + +hgcRecHitsToLayerClusterTable + +hgcRecHitsPositionTable +) diff --git a/DPGAnalysis/HGCalNanoAOD/python/hgcSimHits_cff.py b/DPGAnalysis/HGCalNanoAOD/python/hgcSimHits_cff.py new file mode 100644 index 0000000000000..e9beb4ee24a08 --- /dev/null +++ b/DPGAnalysis/HGCalNanoAOD/python/hgcSimHits_cff.py @@ -0,0 +1,68 @@ +import FWCore.ParameterSet.Config as cms +from PhysicsTools.NanoAOD.common_cff import Var,P3Vars + +hgcEESimHitsTable = cms.EDProducer("SimplePCaloHitFlatTableProducer", + src = cms.InputTag("g4SimHits:HGCHitsEE"), + cut = cms.string(""), + name = cms.string("SimHitHGCEE"), + doc = cms.string("Geant4 SimHits in HGCAL Electromagnetic endcap"), + singleton = cms.bool(False), # the number of entries is variable + extension = cms.bool(False), # this is the main table for the muons + variables = cms.PSet( + detId = Var('id', 'int', precision=-1, doc='detId'), + energy = Var('energy', 'float', precision=14, doc='energy'), + trackId = Var('geantTrackId', 'int', precision=-1, doc='Geant4 track ID'), + ) +) + +hgcEEHitsToSimClusterTable = cms.EDProducer("CaloHitToSimClusterIndexTableProducer", + cut = hgcEESimHitsTable.cut, + src = hgcEESimHitsTable.src, + objName = hgcEESimHitsTable.name, + branchName = cms.string("SimCluster"), + objMap = cms.InputTag("mix:simHitHGCEEToSimCluster"), + docString = cms.string("SimCluster containing SimHit") +) + +hgcHEfrontSimHitsTable = hgcEESimHitsTable.clone() +hgcHEfrontSimHitsTable.src = "g4SimHits:HGCHitsHEfront" +hgcHEfrontSimHitsTable.name = "SimHitHGCHEF" + +hgcHEfrontHitsToSimClusterTable = hgcEEHitsToSimClusterTable.clone() +hgcHEfrontHitsToSimClusterTable.src = hgcHEfrontSimHitsTable.src +hgcHEfrontHitsToSimClusterTable.objName = hgcHEfrontSimHitsTable.name +hgcHEfrontHitsToSimClusterTable.objMap = "mix:simHitHGCHEfrontToSimCluster" + +hgcHEbackSimHitsTable = hgcEESimHitsTable.clone() +hgcHEbackSimHitsTable.src = "g4SimHits:HGCHitsHEback" +hgcHEbackSimHitsTable.name = "SimHitHGCHEB" + +hgcHEbackHitsToSimClusterTable = hgcEEHitsToSimClusterTable.clone() +hgcHEbackHitsToSimClusterTable.src = hgcHEbackSimHitsTable.src +hgcHEbackHitsToSimClusterTable.objName = hgcHEbackSimHitsTable.name +hgcHEbackHitsToSimClusterTable.objMap = "mix:simHitHGCHEbackToSimCluster" + +hgcEESimHitsPositionTable = cms.EDProducer("PCaloHitPositionTableProducer", + src = hgcEESimHitsTable.src, + cut = hgcEESimHitsTable.cut, + name = hgcEESimHitsTable.name, + doc = hgcEESimHitsTable.doc, +) + +hgcHEfrontSimHitsPositionTable = hgcEESimHitsPositionTable.clone() +hgcHEfrontSimHitsPositionTable.name = hgcHEfrontSimHitsTable.name +hgcHEfrontSimHitsPositionTable.src = hgcHEfrontSimHitsTable.src + +hgcHEbackSimHitsPositionTable = hgcEESimHitsPositionTable.clone() +hgcHEbackSimHitsPositionTable.name = hgcHEbackSimHitsTable.name +hgcHEbackSimHitsPositionTable.src = hgcHEbackSimHitsTable.src + +hgcSimHitsSequence = cms.Sequence(hgcEESimHitsTable+hgcHEbackSimHitsTable+hgcHEfrontSimHitsTable + +hgcEESimHitsPositionTable + +hgcHEfrontSimHitsPositionTable + +hgcHEbackSimHitsPositionTable + +hgcEEHitsToSimClusterTable + +hgcHEfrontHitsToSimClusterTable + +hgcHEbackHitsToSimClusterTable + +hgcHEfrontSimHitsTable+hgcHEbackSimHitsTable) + diff --git a/DPGAnalysis/HGCalNanoAOD/python/hgcSimTracks_cff.py b/DPGAnalysis/HGCalNanoAOD/python/hgcSimTracks_cff.py new file mode 100644 index 0000000000000..8a9870c44bb0c --- /dev/null +++ b/DPGAnalysis/HGCalNanoAOD/python/hgcSimTracks_cff.py @@ -0,0 +1,41 @@ +import FWCore.ParameterSet.Config as cms +from PhysicsTools.NanoAOD.common_cff import Var + +simTrackTable = cms.EDProducer("SimpleSimTrackFlatTableProducer", + src = cms.InputTag("g4SimHits"), + cut = cms.string("abs(momentum().eta) > 1.52 || abs(getMomentumAtBoundary().eta()) > 1.52"), + name = cms.string("SimTrack"), + doc = cms.string("Geant4 sim tracks in HGCAL Electromagnetic endcap"), + singleton = cms.bool(False), # the number of entries is variable + extension = cms.bool(False), # this is the main table for the muons + variables = cms.PSet( + crossedBoundary = Var('crossedBoundary', 'bool', doc='track crossed boundary'), + pdgId = Var('type', 'int', doc='pdgId (track type)'), + charge = Var('charge', 'int', doc='ID'), + trackId = Var('trackId', 'int', precision=-1, doc='ID'), + trackIdAtBoundary = Var('getIDAtBoundary', 'int', precision=-1, doc='ID at boundary crossing'), + pt = Var('momentum().pt()', 'float', precision=14, doc='pt'), + eta = Var('momentum().eta()', 'float', precision=14, doc='eta'), + phi = Var('momentum().phi()', 'float', precision=14, doc='phi'), + lastPos_x = Var('trackerSurfacePosition().x()', 'float', precision=14, doc='x position at HGCAL boundary'), + lastPos_y = Var('trackerSurfacePosition().y()', 'float', precision=14, doc='y position at HGCAL boundary'), + lastPos_z = Var('trackerSurfacePosition().z()', 'float', precision=14, doc='z position at HGCAL boundary'), + boundaryPos_x = Var('getPositionAtBoundary().x()', 'float', precision=14, doc='x position at HGCAL boundary'), + boundaryPos_y = Var('getPositionAtBoundary().y()', 'float', precision=14, doc='y position at HGCAL boundary'), + boundaryPos_z = Var('getPositionAtBoundary().z()', 'float', precision=14, doc='z position at HGCAL boundary'), + boundaryMomentum_pt = Var('getMomentumAtBoundary().pt()', 'float', precision=14, doc='pt at HGCAL boundary'), + boundaryMomentum_eta = Var('getMomentumAtBoundary().eta()', 'float', precision=14, doc='eta position at HGCAL boundary'), + boundaryMomentum_phi = Var('getMomentumAtBoundary().phi()', 'float', precision=14, doc='phi position at HGCAL boundary'), + ) +) + +simTrackToSimClusterTable = cms.EDProducer("SimTrackToSimClusterIndexTableProducer", + cut = simTrackTable.cut, + src = simTrackTable.src, + objName = simTrackTable.name, + branchName = cms.string("SimCluster"), + objMap = cms.InputTag("mix:simTrackToSimCluster"), + docString = cms.string("SimCluster containing track") +) + +simTrackTables = cms.Sequence(simTrackTable+simTrackToSimClusterTable) diff --git a/DPGAnalysis/HGCalNanoAOD/python/layerClusters_cff.py b/DPGAnalysis/HGCalNanoAOD/python/layerClusters_cff.py new file mode 100644 index 0000000000000..555337ce94d5d --- /dev/null +++ b/DPGAnalysis/HGCalNanoAOD/python/layerClusters_cff.py @@ -0,0 +1,33 @@ +import FWCore.ParameterSet.Config as cms +from PhysicsTools.NanoAOD.common_cff import P3Vars,Var + +layerClusterTable = cms.EDProducer("SimpleCaloClusterFlatTableProducer", + src = cms.InputTag("hgcalLayerClusters"), + cut = cms.string(""), + name = cms.string("LayerCluster"), + doc = cms.string("LayerCluster information"), + singleton = cms.bool(False), # the number of entries is variable + extension = cms.bool(False), # this is the main table for the muons + variables = cms.PSet( + eta = Var("eta", float,precision=12), + phi = Var("phi", float, precision=12), + energy = Var("energy", float, precision=14), + x = Var('position().x()', 'float', precision=14, doc='x position'), + y = Var('position.y()', 'float', precision=14, doc='y position'), + z = Var('position.z()', 'float', precision=14, doc='z position'), + nHits = Var('size', 'int', precision=14, doc='number of rechits'), + seedDetId = Var('seed().rawId()', 'int', precision=-1, doc='detId of seed hit'), + ) +) + +layerClusterToSimClusterTable = cms.EDProducer("LayerClusterToSimClusterIndexTableProducer", + cut = layerClusterTable.cut, + src = layerClusterTable.src, + objName = layerClusterTable.name, + branchName = cms.string("SimCluster"), + objMap = cms.InputTag("layerClusterCaloParticleAssociationProducer"), + docString = cms.string("Index of SimCluster matched to LayerCluster") +) + +layerClusterTables = cms.Sequence(layerClusterTable+layerClusterToSimClusterTable) + diff --git a/DPGAnalysis/HGCalNanoAOD/python/nanoHGCML_cff.py b/DPGAnalysis/HGCalNanoAOD/python/nanoHGCML_cff.py new file mode 100644 index 0000000000000..62521907b64f0 --- /dev/null +++ b/DPGAnalysis/HGCalNanoAOD/python/nanoHGCML_cff.py @@ -0,0 +1,54 @@ +from __future__ import print_function +import FWCore.ParameterSet.Config as cms +from PhysicsTools.NanoAOD.common_cff import * +from PhysicsTools.NanoAOD.genparticles_cff import genParticleTable +from PhysicsTools.NanoAOD.genVertex_cff import * +from DPGAnalysis.HGCalNanoAOD.hgcSimHits_cff import * +from DPGAnalysis.HGCalNanoAOD.hgcSimTracks_cff import * +from DPGAnalysis.HGCalNanoAOD.hgcRecHits_cff import * +from DPGAnalysis.HGCalNanoAOD.hgcRecHitSimAssociations_cff import * +from DPGAnalysis.HGCalNanoAOD.simClusters_cff import * +from DPGAnalysis.HGCalNanoAOD.layerClusters_cff import * +from DPGAnalysis.HGCalNanoAOD.caloParticles_cff import * +from DPGAnalysis.TrackNanoAOD.trackSimHits_cff import * +from DPGAnalysis.TrackNanoAOD.trackingParticles_cff import * +from DPGAnalysis.TrackNanoAOD.tracks_cff import * +from DPGAnalysis.PFNanoAOD.pfCands_cff import * +from DPGAnalysis.PFNanoAOD.pfTruth_cff import * + +nanoMetadata = cms.EDProducer("UniqueStringProducer", + strings = cms.PSet( + tag = cms.string("untagged"), + ) +) + +genParticleTable.src = "genParticles" +genParticleTable.variables = cms.PSet(genParticleTable.variables, + charge = CandVars.charge) + +nanoHGCMLSequence = cms.Sequence(nanoMetadata+genVertexTables+genParticleTable+ + trackingParticleTable+caloParticleTable+simClusterTables+ + layerClusterTables+ + simTrackTables+hgcSimHitsSequence+trackerSimHitTables) + +nanoHGCMLRecoSequence = cms.Sequence(hgcRecHitsSequence+hgcRecHitSimAssociationSequence+ + pfCandTable+pfTruth+pfTICLCandTable+trackTables) + +def customizeReco(process): + process.nanoHGCMLSequence.insert(1, nanoHGCMLRecoSequence) + return process + +def customizeNoMergedCaloTruth(process): + process.nanoHGCMLSequence.remove(simClusterTable) + process.nanoHGCMLSequence.remove(simClusterToCaloPartTable) + process.nanoHGCMLSequence.remove(hgcEEHitsToSimClusterTable) + process.nanoHGCMLSequence.remove(hgcHEfrontHitsToSimClusterTable) + process.nanoHGCMLSequence.remove(hgcHEbackHitsToSimClusterTable) + process.nanoHGCMLSequence.remove(simTrackToSimClusterTable) + + process.nanoHGCMLSequence.remove(caloParticleTable) + return process + +def customizeMergedSimClusters(process): + process.nanoHGCMLSequence.insert(1, mergedSimClusterTables) + return process diff --git a/DPGAnalysis/HGCalNanoAOD/python/simClusters_cff.py b/DPGAnalysis/HGCalNanoAOD/python/simClusters_cff.py new file mode 100644 index 0000000000000..70e729773de41 --- /dev/null +++ b/DPGAnalysis/HGCalNanoAOD/python/simClusters_cff.py @@ -0,0 +1,80 @@ +import FWCore.ParameterSet.Config as cms +from PhysicsTools.NanoAOD.common_cff import CandVars,Var + +simClusterTable = cms.EDProducer("SimpleSimClusterFlatTableProducer", + src = cms.InputTag("mix:MergedCaloTruth"), + cut = cms.string(""), + name = cms.string("SimCluster"), + doc = cms.string("SimCluster information"), + singleton = cms.bool(False), # the number of entries is variable + extension = cms.bool(False), # this is the main table for the muons + variables = cms.PSet(CandVars, + lastPos_x = Var('g4Tracks.at(0).trackerSurfacePosition().x()', 'float', precision=14, doc='track x final position'), + lastPos_y = Var('g4Tracks.at(0).trackerSurfacePosition().y()', 'float', precision=14, doc='track y final position'), + lastPos_z = Var('g4Tracks.at(0).trackerSurfacePosition().z()', 'float', precision=14, doc='track z final position'), + # NOTE: This is the cms-pepr approach, which is needed for merged simclusters + impactPoint_x = Var('impactPoint().x()', 'float', precision=14, doc='x position'), + impactPoint_y = Var('impactPoint().y()', 'float', precision=14, doc='y position'), + impactPoint_z = Var('impactPoint().z()', 'float', precision=14, doc='z position'), + impactPoint_t = Var('impactPoint().t()', 'float', precision=14, doc='Impact time'), + impactPoint_eta = Var('impactPoint().eta()', 'float', precision=14, doc='eta at boundary'), + impactPoint_phi = Var('impactPoint().phi()', 'float', precision=14, doc='phi at boundary'), + # For stupid reasons lost on me, the nsimhits_ variable is uninitialized, and hits_ (which are really simhits) + # are often referred to as rechits in the SimCluster class + nHits = Var('numberOfRecHits', 'int', precision=-1, doc='number of simhits'), + sumHitEnergy = Var('energy', 'float', precision=14, doc='total energy of simhits'), + boundaryPmag = Var('impactMomentum.P()', 'float', precision=14, doc='magnitude of the boundary 3-momentum vector'), + boundaryP4 = Var('impactMomentum.mag()', 'float', precision=14, doc='magnitude of four vector'), + boundaryEnergy = Var('impactMomentum.energy()', 'float', precision=14, doc='magnitude of four vector'), + boundaryEnergyNoMu = Var('impactMomentumNoMu.energy()', 'float', precision=14, doc='magnitude of four vector'), + boundaryPt = Var('impactMomentum.pt()', 'float', precision=14, doc='magnitude of four vector'), + trackId = Var('g4Tracks().at(0).trackId()', 'int', precision=-1, doc='Geant track id'), + trackIdAtBoundary = Var('g4Tracks().at(0).getIDAtBoundary()', 'int', precision=-1, doc='Track ID at boundary'), + hasHGCALHit = Var('hasHGCALHit', 'bool', doc='Has at least 1 simHit in HGCAL'), + allHitsHGCAL = Var('allHitsHGCAL', 'bool', doc='all simHits are in HGCAL'), + onHGCFrontFace = Var('abs(impactPoint().z()) - 322 < 1', 'bool', doc='SimCluster position is consistent with the front of the HGCAL'), + isTrainable = Var('numberOfRecHits > 5 && allHitsHGCAL', 'bool', doc='Should be used for training'), + ) +) + +simClusterToCaloPartTable = cms.EDProducer("SimClusterToCaloParticleIndexTableProducer", + cut = simClusterTable.cut, + src = simClusterTable.src, + objName = simClusterTable.name, + branchName = cms.string("CaloPart"), + objMap = cms.InputTag("mix:simClusterToCaloParticle"), + docString = cms.string("Index of CaloPart containing SimCluster") +) + +hgcSimTruth = cms.EDProducer("simmerger") +hgcSimTruthDR = cms.EDProducer("HGCTruthProducer") + +simClusterToMergedSCTable = cms.EDProducer("SimClusterToSimClusterIndexTableProducer", + cut = simClusterTable.cut, + src = simClusterTable.src, + objName = simClusterTable.name, + branchName = cms.string("MergedSimCluster"), + objMap = cms.InputTag("hgcSimTruth"), + docString = cms.string("Index of Merged SimCluster containing SimCluster") +) + +mergedSimClusterTable = simClusterTable.clone() +mergedSimClusterTable.src = "hgcSimTruth" +mergedSimClusterTable.name = "MergedSimCluster" + +mergedSimClusterDRTable = simClusterTable.clone() +mergedSimClusterDRTable.src = "hgcSimTruthDR" +mergedSimClusterDRTable.name = "MergedByDRSimCluster" + +mergedToUnmergedSCTable = cms.EDProducer("SimClusterToSimClustersIndexTableProducer", + cut = mergedSimClusterTable.cut, + src = mergedSimClusterTable.src, + objName = mergedSimClusterTable.name, + branchName = cms.string("SimCluster"), + objMap = cms.InputTag("hgcSimTruth"), + docString = cms.string("Index of Merged SimCluster containing SimCluster") +) + +simClusterTables = cms.Sequence(simClusterTable+simClusterToCaloPartTable) + +mergedSimClusterTables = cms.Sequence(hgcSimTruth+mergedSimClusterTable+hgcSimTruthDR+mergedSimClusterDRTable+mergedToUnmergedSCTable+simClusterToMergedSCTable) diff --git a/DPGAnalysis/HGCalNanoAOD/test/nanoMLGSD_cfg.py b/DPGAnalysis/HGCalNanoAOD/test/nanoMLGSD_cfg.py new file mode 100644 index 0000000000000..425a24eab4d35 --- /dev/null +++ b/DPGAnalysis/HGCalNanoAOD/test/nanoMLGSD_cfg.py @@ -0,0 +1,117 @@ +# Auto generated configuration file +# using: +# Revision: 1.19 +# Source: /local/reps/CMSSW/CMSSW/Configuration/Applications/python/ConfigBuilder.py,v +# with command line options: step1 --filein file:test.root --fileout testNanoML.root --mc --eventcontent NANOAODSIM --datatier NANOAODSIM --conditions auto:mc --step NANO +import FWCore.ParameterSet.Config as cms +from FWCore.ParameterSet.VarParsing import VarParsing + + +process = cms.Process('NANO') +options = VarParsing('python') +options.setDefault('outputFile', 'testNanoML.root') +options.parseArguments() + +# import of standard configurations +process.load('Configuration.StandardSequences.Services_cff') +process.load('SimGeneral.HepPDTESSource.pythiapdt_cfi') +process.load('FWCore.MessageService.MessageLogger_cfi') +process.load('Configuration.EventContent.EventContent_cff') +process.load('SimGeneral.MixingModule.mixNoPU_cfi') +process.load('Configuration.Geometry.GeometryExtended2026D49Reco_cff') +process.load('Configuration.Geometry.GeometryExtended2026D49_cff') +process.load('Configuration.StandardSequences.MagneticField_cff') +process.load('DPGAnalysis.HGCalNanoAOD.nanoHGCML_cff') +process.load('Configuration.StandardSequences.EndOfProcess_cff') +process.load('Configuration.StandardSequences.FrontierConditions_GlobalTag_cff') + +process.maxEvents = cms.untracked.PSet( + input = cms.untracked.int32(-1), + output = cms.optional.untracked.allowed(cms.int32,cms.PSet) +) + +# Input source +process.source = cms.Source("PoolSource", + fileNames = cms.untracked.vstring(options.inputFiles), + secondaryFileNames = cms.untracked.vstring() +) + +process.options = cms.untracked.PSet( + FailPath = cms.untracked.vstring(), + IgnoreCompletely = cms.untracked.vstring(), + Rethrow = cms.untracked.vstring(), + SkipEvent = cms.untracked.vstring(), + allowUnscheduled = cms.obsolete.untracked.bool, + canDeleteEarly = cms.untracked.vstring(), + emptyRunLumiMode = cms.obsolete.untracked.string, + eventSetup = cms.untracked.PSet( + forceNumberOfConcurrentIOVs = cms.untracked.PSet( + allowAnyLabel_=cms.required.untracked.uint32 + ), + numberOfConcurrentIOVs = cms.untracked.uint32(1) + ), + fileMode = cms.untracked.string('FULLMERGE'), + forceEventSetupCacheClearOnNewRun = cms.untracked.bool(False), + makeTriggerResults = cms.obsolete.untracked.bool, + numberOfConcurrentLuminosityBlocks = cms.untracked.uint32(1), + numberOfConcurrentRuns = cms.untracked.uint32(1), + numberOfStreams = cms.untracked.uint32(0), + numberOfThreads = cms.untracked.uint32(1), + printDependencies = cms.untracked.bool(False), + sizeOfStackForThreadsInKB = cms.optional.untracked.uint32, + throwIfIllegalParameter = cms.untracked.bool(True), + wantSummary = cms.untracked.bool(False) +) + +# Production Info +process.configurationMetadata = cms.untracked.PSet( + annotation = cms.untracked.string('step1 nevts:1'), + name = cms.untracked.string('Applications'), + version = cms.untracked.string('$Revision: 1.19 $') +) + +# Output definition + +process.NANOAODSIMoutput = cms.OutputModule("NanoAODOutputModule", + compressionAlgorithm = cms.untracked.string('LZMA'), + compressionLevel = cms.untracked.int32(9), + dataset = cms.untracked.PSet( + dataTier = cms.untracked.string('NANOAODSIM'), + filterName = cms.untracked.string('') + ), + fileName = cms.untracked.string(options.outputFile), + outputCommands = process.NANOAODSIMEventContent.outputCommands +) + +process.NANOAODSIMoutput.outputCommands.remove("keep edmTriggerResults_*_*_*") + +# Additional output definition + +# Other statements +from Configuration.AlCa.GlobalTag import GlobalTag +process.GlobalTag = GlobalTag(process.GlobalTag, 'auto:mc', '') + +# Path and EndPath definitions +process.nanoAOD_step = cms.Path(process.nanoHGCMLSequence) +process.endjob_step = cms.EndPath(process.endOfProcess) +process.NANOAODSIMoutput_step = cms.EndPath(process.NANOAODSIMoutput) + +# Schedule definition +process.schedule = cms.Schedule(process.nanoAOD_step,process.endjob_step,process.NANOAODSIMoutput_step) +from PhysicsTools.PatAlgos.tools.helpers import associatePatAlgosToolsTask +associatePatAlgosToolsTask(process) + +# customisation of the process. +from DPGAnalysis.HGCalNanoAOD.nanoHGCML_cff import customizeReco +#process = customizeReco(process) + +# End of customisation functions + + +# Customisation from command line + +# Add early deletion of temporary data products to reduce peak memory need +from Configuration.StandardSequences.earlyDeleteSettings_cff import customiseEarlyDelete +process = customiseEarlyDelete(process) +# End adding early deletion + diff --git a/DPGAnalysis/HGCalNanoAOD/test/nanoML_cfg.py b/DPGAnalysis/HGCalNanoAOD/test/nanoML_cfg.py new file mode 100644 index 0000000000000..fc1de4ff88a5d --- /dev/null +++ b/DPGAnalysis/HGCalNanoAOD/test/nanoML_cfg.py @@ -0,0 +1,116 @@ +# Auto generated configuration file +# using: +# Revision: 1.19 +# Source: /local/reps/CMSSW/CMSSW/Configuration/Applications/python/ConfigBuilder.py,v +# with command line options: step1 --filein file:test.root --fileout testNanoML.root --mc --eventcontent NANOAODSIM --datatier NANOAODSIM --conditions auto:mc --step NANO +import FWCore.ParameterSet.Config as cms +from FWCore.ParameterSet.VarParsing import VarParsing + + +process = cms.Process('NANO') +options = VarParsing('python') +options.setDefault('outputFile', 'testNanoML.root') +options.parseArguments() + +# import of standard configurations +process.load('Configuration.StandardSequences.Services_cff') +process.load('SimGeneral.HepPDTESSource.pythiapdt_cfi') +process.load('FWCore.MessageService.MessageLogger_cfi') +process.load('Configuration.EventContent.EventContent_cff') +process.load('SimGeneral.MixingModule.mixNoPU_cfi') +process.load('Configuration.Geometry.GeometryExtended2026D49Reco_cff') +process.load('Configuration.Geometry.GeometryExtended2026D49_cff') +process.load('Configuration.StandardSequences.MagneticField_cff') +process.load('DPGAnalysis.HGCalNanoAOD.nanoHGCML_cff') +process.load('Configuration.StandardSequences.EndOfProcess_cff') +process.load('Configuration.StandardSequences.FrontierConditions_GlobalTag_cff') + +process.maxEvents = cms.untracked.PSet( + input = cms.untracked.int32(-1), + output = cms.optional.untracked.allowed(cms.int32,cms.PSet) +) + +# Input source +process.source = cms.Source("PoolSource", + fileNames = cms.untracked.vstring(options.inputFiles), + secondaryFileNames = cms.untracked.vstring() +) + +process.options = cms.untracked.PSet( + FailPath = cms.untracked.vstring(), + IgnoreCompletely = cms.untracked.vstring(), + Rethrow = cms.untracked.vstring(), + SkipEvent = cms.untracked.vstring(), + allowUnscheduled = cms.obsolete.untracked.bool, + canDeleteEarly = cms.untracked.vstring(), + emptyRunLumiMode = cms.obsolete.untracked.string, + eventSetup = cms.untracked.PSet( + forceNumberOfConcurrentIOVs = cms.untracked.PSet( + allowAnyLabel_=cms.required.untracked.uint32 + ), + numberOfConcurrentIOVs = cms.untracked.uint32(1) + ), + fileMode = cms.untracked.string('FULLMERGE'), + forceEventSetupCacheClearOnNewRun = cms.untracked.bool(False), + makeTriggerResults = cms.obsolete.untracked.bool, + numberOfConcurrentLuminosityBlocks = cms.untracked.uint32(1), + numberOfConcurrentRuns = cms.untracked.uint32(1), + numberOfStreams = cms.untracked.uint32(0), + numberOfThreads = cms.untracked.uint32(1), + printDependencies = cms.untracked.bool(False), + sizeOfStackForThreadsInKB = cms.optional.untracked.uint32, + throwIfIllegalParameter = cms.untracked.bool(True), + wantSummary = cms.untracked.bool(False) +) + +# Production Info +process.configurationMetadata = cms.untracked.PSet( + annotation = cms.untracked.string('step1 nevts:1'), + name = cms.untracked.string('Applications'), + version = cms.untracked.string('$Revision: 1.19 $') +) + +# Output definition + +process.NANOAODSIMoutput = cms.OutputModule("NanoAODOutputModule", + compressionAlgorithm = cms.untracked.string('LZMA'), + compressionLevel = cms.untracked.int32(9), + dataset = cms.untracked.PSet( + dataTier = cms.untracked.string('NANOAODSIM'), + filterName = cms.untracked.string('') + ), + fileName = cms.untracked.string(options.outputFile), + outputCommands = process.NANOAODSIMEventContent.outputCommands +) + +process.NANOAODSIMoutput.outputCommands.remove("keep edmTriggerResults_*_*_*") + +# Additional output definition + +# Other statements +from Configuration.AlCa.GlobalTag import GlobalTag +process.GlobalTag = GlobalTag(process.GlobalTag, 'auto:mc', '') + +# Path and EndPath definitions +process.nanoAOD_step = cms.Path(process.nanoHGCMLSequence) +process.endjob_step = cms.EndPath(process.endOfProcess) +process.NANOAODSIMoutput_step = cms.EndPath(process.NANOAODSIMoutput) + +# Schedule definition +process.schedule = cms.Schedule(process.nanoAOD_step,process.endjob_step,process.NANOAODSIMoutput_step) +from PhysicsTools.PatAlgos.tools.helpers import associatePatAlgosToolsTask +associatePatAlgosToolsTask(process) + +# customisation of the process. +from DPGAnalysis.HGCalNanoAOD.nanoHGCML_cff import customizeReco +process = customizeReco(process) + +# End of customisation functions + + +# Customisation from command line + +# Add early deletion of temporary data products to reduce peak memory need +from Configuration.StandardSequences.earlyDeleteSettings_cff import customiseEarlyDelete +process = customiseEarlyDelete(process) +# End adding early deletion diff --git a/DPGAnalysis/PFNanoAOD/plugins/BuildFile.xml b/DPGAnalysis/PFNanoAOD/plugins/BuildFile.xml new file mode 100644 index 0000000000000..41c6681105b76 --- /dev/null +++ b/DPGAnalysis/PFNanoAOD/plugins/BuildFile.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/DPGAnalysis/PFNanoAOD/plugins/PFObjectIndexToAssociationProducer.cc b/DPGAnalysis/PFNanoAOD/plugins/PFObjectIndexToAssociationProducer.cc new file mode 100644 index 0000000000000..c603853fadd1f --- /dev/null +++ b/DPGAnalysis/PFNanoAOD/plugins/PFObjectIndexToAssociationProducer.cc @@ -0,0 +1,13 @@ +#include "PhysicsTools/NanoAOD/interface/ObjectIndexFromAssociationProducer.h" +#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" +#include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" +#include "SimDataFormats/PFAnalysis/interface/PFTruthParticleFwd.h" +#include "SimDataFormats/PFAnalysis/interface/PFTruthParticle.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +typedef ObjectIndexFromAssociationTableProducer + SimClusterToPFTruthParticleIndexTableProducer; +typedef ObjectIndexFromAssociationTableProducer + TrackingParticleToPFTruthParticleIndexTableProducer; +DEFINE_FWK_MODULE(TrackingParticleToPFTruthParticleIndexTableProducer); +DEFINE_FWK_MODULE(SimClusterToPFTruthParticleIndexTableProducer); diff --git a/DPGAnalysis/PFNanoAOD/plugins/SimplePFParticleFlatTableProducerPlugins.cc b/DPGAnalysis/PFNanoAOD/plugins/SimplePFParticleFlatTableProducerPlugins.cc new file mode 100644 index 0000000000000..6d906e216ae44 --- /dev/null +++ b/DPGAnalysis/PFNanoAOD/plugins/SimplePFParticleFlatTableProducerPlugins.cc @@ -0,0 +1,7 @@ +#include "PhysicsTools/NanoAOD/interface/SimpleFlatTableProducer.h" + +#include "SimDataFormats/PFAnalysis/interface/PFTruthParticle.h" +typedef SimpleFlatTableProducer SimplePFTruthParticleFlatTableProducer; + +#include "FWCore/Framework/interface/MakerMacros.h" +DEFINE_FWK_MODULE(SimplePFTruthParticleFlatTableProducer); diff --git a/DPGAnalysis/PFNanoAOD/python/pfCands_cff.py b/DPGAnalysis/PFNanoAOD/python/pfCands_cff.py new file mode 100644 index 0000000000000..8b5aafaee8a1c --- /dev/null +++ b/DPGAnalysis/PFNanoAOD/python/pfCands_cff.py @@ -0,0 +1,32 @@ +import FWCore.ParameterSet.Config as cms +from PhysicsTools.NanoAOD.common_cff import CandVars,Var + +pfCandTable = cms.EDProducer("SimpleCandidateFlatTableProducer", + src = cms.InputTag("particleFlow"), + cut = cms.string(""), + name = cms.string("PFCand"), + doc = cms.string("ParticleFlow candidates"), + singleton = cms.bool(False), # the number of entries is variable + extension = cms.bool(False), # this is the main table for the muons + variables = cms.PSet(CandVars, + Vtx_x = Var('vertex().x()', 'float', precision=14, doc='vertex x pos'), + Vtx_y = Var('vertex().y()', 'float', precision=14, doc='vertex y pos'), + Vtx_z = Var('vertex().z()', 'float', precision=14, doc='vertex z pos'), + ) +) + +pfTICLCandTable = cms.EDProducer("SimpleCandidateFlatTableProducer", + src = cms.InputTag("pfTICL"), + cut = cms.string(""), + name = cms.string("PFTICLCand"), + doc = cms.string("ParticleFlow candidates"), + singleton = cms.bool(False), # the number of entries is variable + extension = cms.bool(False), + variables = cms.PSet(CandVars, + Vtx_x = Var('vertex().x()', 'float', precision=14, doc='vertex x pos'), + Vtx_y = Var('vertex().y()', 'float', precision=14, doc='vertex y pos'), + Vtx_z = Var('vertex().z()', 'float', precision=14, doc='vertex z pos'), + ) +) + +pfCandTables = cms.Sequence(pfCandTable+pfTICLCandTable) diff --git a/DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py b/DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py new file mode 100644 index 0000000000000..80107c1b9ed68 --- /dev/null +++ b/DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py @@ -0,0 +1,43 @@ +import FWCore.ParameterSet.Config as cms +from PhysicsTools.NanoAOD.common_cff import CandVars,Var +from DPGAnalysis.HGCalNanoAOD.simClusters_cff import simClusterTable +from DPGAnalysis.TrackNanoAOD.trackingParticles_cff import trackingParticleTable + +pfTruthParticles = cms.EDProducer("PFTruthParticleProducer", + simClusters = cms.InputTag("mix:MergedCaloTruth"), + trackingParticles= cms.InputTag("mix:MergedTrackTruth"), +) + +pfTruthTable = cms.EDProducer("SimplePFTruthParticleFlatTableProducer", + src = cms.InputTag("pfTruthParticles"), + cut = cms.string(""), + name = cms.string("PFTruthPart"), + doc = cms.string("PFTruthParticles"), + singleton = cms.bool(False), # the number of entries is variable + extension = cms.bool(False), # this is the main table for the muons + variables = cms.PSet(CandVars, + nSimCluster = Var("nSimCluster", 'int', precision=-1, doc='Number of associated SimClusters'), + nTrackingPart = Var("nTrackingParticle", 'int', precision=-1, doc='Number of associated SimClusters'), + ) +) + +simClusterToPFTruthTable = cms.EDProducer("SimClusterToPFTruthParticleIndexTableProducer", + cut = cms.string(""), + src = cms.InputTag("mix:MergedCaloTruth"), + objName = simClusterTable.name, + branchName = pfTruthTable.name, + objMap = cms.InputTag("pfTruthParticles:simClusToPFTruth"), + docString = cms.string("PFTruth particle to which the SimCluster is associated") +) + +trackingPartToPFTruthTable = cms.EDProducer("TrackingParticleToPFTruthParticleIndexTableProducer", + cut = cms.string(""), + src = cms.InputTag("mix:MergedTrackTruth"), + objName = trackingParticleTable.name, + branchName = pfTruthTable.name, + objMap = cms.InputTag("pfTruthParticles:trackingPartToPFTruth"), + docString = cms.string("PFTruth particle to which the TrackingPart is associated") +) + +pfTruth = cms.Sequence(pfTruthParticles+pfTruthTable+simClusterToPFTruthTable+trackingPartToPFTruthTable) + diff --git a/DPGAnalysis/TrackNanoAOD/BuildFile.xml b/DPGAnalysis/TrackNanoAOD/BuildFile.xml new file mode 100644 index 0000000000000..6cc75a882ba98 --- /dev/null +++ b/DPGAnalysis/TrackNanoAOD/BuildFile.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/DPGAnalysis/TrackNanoAOD/plugins/BuildFile.xml b/DPGAnalysis/TrackNanoAOD/plugins/BuildFile.xml new file mode 100644 index 0000000000000..eba77cbba8b36 --- /dev/null +++ b/DPGAnalysis/TrackNanoAOD/plugins/BuildFile.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/DPGAnalysis/TrackNanoAOD/plugins/SimpleTrackFlatTableProducerPlugins.cc b/DPGAnalysis/TrackNanoAOD/plugins/SimpleTrackFlatTableProducerPlugins.cc new file mode 100644 index 0000000000000..b23e57e8bebaf --- /dev/null +++ b/DPGAnalysis/TrackNanoAOD/plugins/SimpleTrackFlatTableProducerPlugins.cc @@ -0,0 +1,18 @@ +#include "PhysicsTools/NanoAOD/interface/SimpleFlatTableProducer.h" + +#include "SimDataFormats/TrackingHit/interface/PSimHit.h" +typedef SimpleFlatTableProducer SimplePSimHitFlatTableProducer; + +#include "SimDataFormats/TrackingAnalysis/interface/TrackingParticle.h" +typedef SimpleFlatTableProducer SimpleTrackingParticleFlatTableProducer; + +#include "SimDataFormats/Track/interface/SimTrack.h" +typedef SimpleFlatTableProducer SimpleSimTrackFlatTableProducer; +#include "DataFormats/TrackReco/interface/Track.h" +typedef SimpleFlatTableProducer SimpleTrackFlatTableProducer; + +#include "FWCore/Framework/interface/MakerMacros.h" +DEFINE_FWK_MODULE(SimplePSimHitFlatTableProducer); +DEFINE_FWK_MODULE(SimpleSimTrackFlatTableProducer); +DEFINE_FWK_MODULE(SimpleTrackingParticleFlatTableProducer); +DEFINE_FWK_MODULE(SimpleTrackFlatTableProducer); diff --git a/DPGAnalysis/TrackNanoAOD/plugins/TrackPositionAtHGCALTableProducer.cc b/DPGAnalysis/TrackNanoAOD/plugins/TrackPositionAtHGCALTableProducer.cc new file mode 100644 index 0000000000000..603a6a22b5f23 --- /dev/null +++ b/DPGAnalysis/TrackNanoAOD/plugins/TrackPositionAtHGCALTableProducer.cc @@ -0,0 +1,65 @@ +#include "FWCore/Framework/interface/stream/EDProducer.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "DataFormats/NanoAOD/interface/FlatTable.h" +#include "DataFormats/Common/interface/View.h" +#include "CommonTools/Utils/interface/StringCutObjectSelector.h" +#include "RecoHGCal/GraphReco/interface/HGCalTrackPropagator.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include + +class TrackPositionAtHGCALTableProducer : public edm::stream::EDProducer<> { +public: + TrackPositionAtHGCALTableProducer(edm::ParameterSet const& params) + : name_(params.getParameter("name")), + src_(consumes(params.getParameter("src"))), + cut_(params.getParameter("cut"), true) { + produces(); + } + + ~TrackPositionAtHGCALTableProducer() override {} + + void beginRun(const edm::Run&, const edm::EventSetup& iSetup) override { + trackprop_.getEventSetup(iSetup); + } + + void produce(edm::Event& iEvent, const edm::EventSetup& iSetup) override { + edm::Handle objs; + iEvent.getByToken(src_, objs); + + std::vector xvals; + std::vector yvals; + std::vector zvals; + std::vector phis; + std::vector etas; + for (const auto& obj : *objs) { + if (cut_(obj)) { + auto prop = trackprop_.propagateObject(obj); + xvals.emplace_back(prop.pos.x()); + yvals.emplace_back(prop.pos.y()); + zvals.emplace_back(prop.pos.z()); + etas.emplace_back(prop.pos.eta()); + phis.emplace_back(prop.pos.phi()); + } + } + + auto tab = std::make_unique(xvals.size(), name_, false, true); + tab->addColumn("HGCFront_x", xvals, "x position at front face of HGCAL"); + tab->addColumn("HGCFront_y", yvals, "y position at front face of HGCAL"); + tab->addColumn("HGCFront_z", zvals, "z position at front face of HGCAL"); + tab->addColumn("HGCFront_eta", etas, "eta position at front face of HGCAL"); + tab->addColumn("HGCFront_phi", phis, "phi position at front face of HGCAL"); + + iEvent.put(std::move(tab)); + } + +protected: + const std::string name_; + const edm::EDGetTokenT src_; + const StringCutObjectSelector cut_; + HGCalTrackPropagator trackprop_; +}; + +DEFINE_FWK_MODULE(TrackPositionAtHGCALTableProducer); diff --git a/DPGAnalysis/TrackNanoAOD/python/trackSimHits_cff.py b/DPGAnalysis/TrackNanoAOD/python/trackSimHits_cff.py new file mode 100644 index 0000000000000..2067b9a50ca79 --- /dev/null +++ b/DPGAnalysis/TrackNanoAOD/python/trackSimHits_cff.py @@ -0,0 +1,53 @@ +import FWCore.ParameterSet.Config as cms +from PhysicsTools.NanoAOD.common_cff import CandVars,Var + +trackerHitsPixelEndcapLowTofTable = cms.EDProducer("SimplePSimHitFlatTableProducer", + src = cms.InputTag("g4SimHits:TrackerHitsPixelEndcapLowTof"), + cut = cms.string(""), + name = cms.string("SimHitPixelECLowTof"), + doc = cms.string("Geant4 SimHits in tracker endcap"), + singleton = cms.bool(False), # the number of entries is variable + extension = cms.bool(False), # this is the main table for the muons + variables = cms.PSet( + detId = Var('detUnitId', 'int', precision=-1, doc='detId'), + energy = Var('energyLoss', 'float', precision=14, doc='energy'), + pMag = Var('pabs', 'float', precision=14, doc='magnitude of momentum'), + trackId = Var('trackId', 'int', precision=-1, doc='Geant4 track ID'), + pdgId = Var('particleType', 'int', doc='PDG ID of associated track'), + ) +) + +trackerHitsPixelEndcapLowTofPositionTable = cms.EDProducer("PSimHitPositionTableProducer", + src = trackerHitsPixelEndcapLowTofTable.src, + cut = trackerHitsPixelEndcapLowTofTable.cut, + name = trackerHitsPixelEndcapLowTofTable.name, + doc = trackerHitsPixelEndcapLowTofTable.doc, +) + +trackerHitsPixelBarrelLowTofTable = trackerHitsPixelEndcapLowTofTable.clone() +trackerHitsPixelBarrelLowTofTable.src = "g4SimHits:TrackerHitsPixelBarrelLowTof" +trackerHitsPixelBarrelLowTofTable.name = "SimHitPixelLowTof" +trackerHitsPixelBarrelLowTofTable.doc = "Geant4 SimHits in pixel barrel" + +trackerHitsPixelBarrelLowTofPositionTable = cms.EDProducer("PSimHitPositionTableProducer", + src = trackerHitsPixelBarrelLowTofTable.src, + cut = trackerHitsPixelBarrelLowTofTable.cut, + name = trackerHitsPixelBarrelLowTofTable.name, + doc = trackerHitsPixelBarrelLowTofTable.doc, +) + +muonCSCHitsTable = trackerHitsPixelEndcapLowTofTable.clone() +muonCSCHitsTable.src = "g4SimHits:MuonCSCHits" +muonCSCHitsTable.name = "SimHitMuonCSC" +muonCSCHitsTable.doc = "Geant4 SimHits in Muon CSCs" + +muonCSCHitsPositionTable = cms.EDProducer("PSimHitPositionTableProducer", + src = muonCSCHitsTable.src, + cut = muonCSCHitsTable.cut, + name = muonCSCHitsTable.name, + doc = muonCSCHitsTable.doc, +) + +trackerSimHitTables = cms.Sequence(trackerHitsPixelEndcapLowTofTable+trackerHitsPixelEndcapLowTofPositionTable+ + trackerHitsPixelBarrelLowTofTable+trackerHitsPixelBarrelLowTofPositionTable+ + muonCSCHitsTable+muonCSCHitsPositionTable) diff --git a/DPGAnalysis/TrackNanoAOD/python/trackingParticles_cff.py b/DPGAnalysis/TrackNanoAOD/python/trackingParticles_cff.py new file mode 100644 index 0000000000000..c2c7e4f4d72e0 --- /dev/null +++ b/DPGAnalysis/TrackNanoAOD/python/trackingParticles_cff.py @@ -0,0 +1,28 @@ +import FWCore.ParameterSet.Config as cms +from PhysicsTools.NanoAOD.common_cff import CandVars,Var + +trackingParticleTable = cms.EDProducer("SimpleTrackingParticleFlatTableProducer", + src = cms.InputTag("mix:MergedTrackTruth"), + cut = cms.string(""), + name = cms.string("TrackingPart"), + doc = cms.string("TrackingPart"), + singleton = cms.bool(False), # the number of entries is variable + extension = cms.bool(False), # this is the main table for the muons + variables = cms.PSet(CandVars, + nGenPart = Var('genParticles().size()', 'int', precision=-1, doc='Number of associated gen particles'), + GenPartIdx = Var('? genParticles.size() ? genParticles().at(0).key() : -1', 'int', precision=-1, doc='Number of associated gen particles'), + trackId = Var('g4Tracks.at(0).trackId', 'int', precision=-1, doc='Geant4 track ID of first track'), + nSimTrack = Var('g4Tracks().size', 'int', precision=-1, doc='Number of associated simtracks'), + Vtx_x = Var('vx()', 'float', precision=14, doc='parent vertex x pos'), + Vtx_y = Var('vy()', 'float', precision=14, doc='parent vertex y pos'), + Vtx_z = Var('vz()', 'float', precision=14, doc='parent vertex z pos'), + Vtx_t = Var('parentVertex().position().T()', 'float', precision=14, doc='parent vertex time'), + nDecayVtx = Var('decayVertices().size()', 'int', precision=-1, doc='number of decay vertices'), + DecayVtx_y = Var('? decayVertices().size() > 0 ? decayVertices().at(0).position().x : 10000', 'float', precision=14, doc='x position of first decay vertex'), + DecayVtx_x = Var('? decayVertices().size() > 0 ? decayVertices().at(0).position().y : 10000', 'float', precision=14, doc='y position of first decay vertex'), + DecayVtx_z = Var('? decayVertices().size() > 0 ? decayVertices().at(0).position().z : 10000', 'float', precision=14, doc='z position of first decay vertex'), + DecayVtx_t = Var('? decayVertices().size() > 0 ? decayVertices().at(0).position().t : 10000', 'float', precision=14, doc='time of first decay vertex'), + ) +) + + diff --git a/DPGAnalysis/TrackNanoAOD/python/tracks_cff.py b/DPGAnalysis/TrackNanoAOD/python/tracks_cff.py new file mode 100644 index 0000000000000..819f0afab71c0 --- /dev/null +++ b/DPGAnalysis/TrackNanoAOD/python/tracks_cff.py @@ -0,0 +1,54 @@ +import FWCore.ParameterSet.Config as cms +from PhysicsTools.NanoAOD.common_cff import P3Vars,Var + +generalTrackTable = cms.EDProducer("SimpleTrackFlatTableProducer", + src = cms.InputTag("generalTracks"), + cut = cms.string(""), + name = cms.string("Track"), + doc = cms.string("reco::Track"), + singleton = cms.bool(False), # the number of entries is variable + extension = cms.bool(False), # this is the main table for the muons + variables = cms.PSet(P3Vars, + charge = Var("charge", int, doc="electric charge"), + normChiSq = Var("normalizedChi2", float, precision=14, doc="Chi^2/ndof"), + numberOfValidHits = Var('numberOfValidHits()', 'int', precision=-1, doc='Number of valid hits in track'), + numberOfLostHits = Var('numberOfLostHits()', 'int', precision=-1, doc='Number of lost hits in track'), + Vtx_x = Var('vx()', 'float', precision=14, doc='parent vertex x pos'), + Vtx_y = Var('vy()', 'float', precision=14, doc='parent vertex y pos'), + Vtx_z = Var('vz()', 'float', precision=14, doc='parent vertex z pos'), + Vtx_t = Var('t0', 'float', precision=14, doc='parent vertex time'), + # Be careful here, this isn't really a decay vertex + DecayVtx_y = Var('outerPosition().x()', 'float', precision=14, doc='x position of first decay vertex'), + DecayVtx_x = Var('outerPosition().y()', 'float', precision=14, doc='y position of first decay vertex'), + DecayVtx_z = Var('outerPosition().z()', 'float', precision=14, doc='z position of first decay vertex'), + DecayVtx_t = Var('0', 'float', precision=14, doc='DUMMY VALUE! for time of first decay vertex'), + ) +) + +generalTrackHGCPositionTable = cms.EDProducer("TrackPositionAtHGCALTableProducer", + src = generalTrackTable.src, + name = generalTrackTable.name, + cut = generalTrackTable.cut, +) + +trackConversionsTable = generalTrackTable.clone() +trackConversionsTable.src = "conversionStepTracks" +trackConversionsTable.name = "TrackConv" + +trackDisplacedTable = cms.EDProducer("SimpleTrackFlatTableProducer", + src = cms.InputTag("displacedTracks"), + cut = cms.string(""), + name = cms.string("TrackDisp"), + doc = cms.string("reco::Track"), + singleton = cms.bool(False), # the number of entries is variable + extension = cms.bool(False), # this is the main table for the muons + variables = cms.PSet(P3Vars, + charge = Var("charge", int, doc="electric charge"), + Vtx_x = Var('vx()', 'float', precision=14, doc='parent vertex x pos'), + Vtx_y = Var('vy()', 'float', precision=14, doc='parent vertex y pos'), + Vtx_z = Var('vz()', 'float', precision=14, doc='parent vertex z pos'), + Vtx_t = Var('t0', 'float', precision=14, doc='parent vertex time'), + ) +) + +trackTables = cms.Sequence(generalTrackTable+generalTrackHGCPositionTable+trackConversionsTable+trackDisplacedTable) diff --git a/DPGAnalysis/TrackNanoAOD/test/nanoMLGSD_cfg.py b/DPGAnalysis/TrackNanoAOD/test/nanoMLGSD_cfg.py new file mode 100644 index 0000000000000..a696831220612 --- /dev/null +++ b/DPGAnalysis/TrackNanoAOD/test/nanoMLGSD_cfg.py @@ -0,0 +1,118 @@ +# Auto generated configuration file +# using: +# Revision: 1.19 +# Source: /local/reps/CMSSW/CMSSW/Configuration/Applications/python/ConfigBuilder.py,v +# with command line options: step1 --filein file:test.root --fileout testNanoML.root --mc --eventcontent NANOAODSIM --datatier NANOAODSIM --conditions auto:mc --step NANO +import FWCore.ParameterSet.Config as cms +from FWCore.ParameterSet.VarParsing import VarParsing + + +process = cms.Process('NANO') +options = VarParsing('python') +options.setDefault('outputFile', 'testNanoML.root') +options.parseArguments() + +# import of standard configurations +process.load('Configuration.StandardSequences.Services_cff') +process.load('SimGeneral.HepPDTESSource.pythiapdt_cfi') +process.load('FWCore.MessageService.MessageLogger_cfi') +process.load('Configuration.EventContent.EventContent_cff') +process.load('SimGeneral.MixingModule.mixNoPU_cfi') +process.load('Configuration.Geometry.GeometryExtended2026D49Reco_cff') +process.load('Configuration.Geometry.GeometryExtended2026D49_cff') +process.load('Configuration.StandardSequences.MagneticField_cff') +process.load('PhysicsTools.NanoAOD.nanoHGCML_cff') +process.load('Configuration.StandardSequences.EndOfProcess_cff') +process.load('Configuration.StandardSequences.FrontierConditions_GlobalTag_cff') + +process.maxEvents = cms.untracked.PSet( + input = cms.untracked.int32(-1), + output = cms.optional.untracked.allowed(cms.int32,cms.PSet) +) + +# Input source +process.source = cms.Source("PoolSource", + fileNames = cms.untracked.vstring(options.inputFiles), + secondaryFileNames = cms.untracked.vstring() +) + +process.options = cms.untracked.PSet( + FailPath = cms.untracked.vstring(), + IgnoreCompletely = cms.untracked.vstring(), + Rethrow = cms.untracked.vstring(), + SkipEvent = cms.untracked.vstring(), + allowUnscheduled = cms.obsolete.untracked.bool, + canDeleteEarly = cms.untracked.vstring(), + emptyRunLumiMode = cms.obsolete.untracked.string, + eventSetup = cms.untracked.PSet( + forceNumberOfConcurrentIOVs = cms.untracked.PSet( + allowAnyLabel_=cms.required.untracked.uint32 + ), + numberOfConcurrentIOVs = cms.untracked.uint32(1) + ), + fileMode = cms.untracked.string('FULLMERGE'), + forceEventSetupCacheClearOnNewRun = cms.untracked.bool(False), + makeTriggerResults = cms.obsolete.untracked.bool, + numberOfConcurrentLuminosityBlocks = cms.untracked.uint32(1), + numberOfConcurrentRuns = cms.untracked.uint32(1), + numberOfStreams = cms.untracked.uint32(0), + numberOfThreads = cms.untracked.uint32(1), + printDependencies = cms.untracked.bool(False), + sizeOfStackForThreadsInKB = cms.optional.untracked.uint32, + throwIfIllegalParameter = cms.untracked.bool(True), + wantSummary = cms.untracked.bool(False) +) + +# Production Info +process.configurationMetadata = cms.untracked.PSet( + annotation = cms.untracked.string('step1 nevts:1'), + name = cms.untracked.string('Applications'), + version = cms.untracked.string('$Revision: 1.19 $') +) + +# Output definition + +process.NANOAODSIMoutput = cms.OutputModule("NanoAODOutputModule", + compressionAlgorithm = cms.untracked.string('LZMA'), + compressionLevel = cms.untracked.int32(9), + dataset = cms.untracked.PSet( + dataTier = cms.untracked.string('NANOAODSIM'), + filterName = cms.untracked.string('') + ), + fileName = cms.untracked.string(options.outputFile), + outputCommands = process.NANOAODSIMEventContent.outputCommands +) + +process.NANOAODSIMoutput.outputCommands.remove("keep edmTriggerResults_*_*_*") + +# Additional output definition + +# Other statements +from Configuration.AlCa.GlobalTag import GlobalTag +process.GlobalTag = GlobalTag(process.GlobalTag, 'auto:mc', '') + +# Path and EndPath definitions +process.nanoAOD_step = cms.Path(process.nanoHGCMLSequence) +process.endjob_step = cms.EndPath(process.endOfProcess) +process.NANOAODSIMoutput_step = cms.EndPath(process.NANOAODSIMoutput) + +# Schedule definition +process.schedule = cms.Schedule(process.nanoAOD_step,process.endjob_step,process.NANOAODSIMoutput_step) +from PhysicsTools.PatAlgos.tools.helpers import associatePatAlgosToolsTask +associatePatAlgosToolsTask(process) + +# customisation of the process. + +# End of customisation functions +from PhysicsTools.NanoAOD.nanoHGCML_cff import customizeNoMergedCaloTruth,customizeMergedSimClusters +# Uncomment if you didn't schedule SimClusters/CaloParticles +# process = customizeNoMergedCaloTruth(process) +# merged simclusters (turn off if you aren't running through PEPR) +process = customizeMergedSimClusters(process) + +# Customisation from command line + +# Add early deletion of temporary data products to reduce peak memory need +from Configuration.StandardSequences.earlyDeleteSettings_cff import customiseEarlyDelete +process = customiseEarlyDelete(process) +# End adding early deletion diff --git a/DPGAnalysis/TrackNanoAOD/test/nanoML_cfg.py b/DPGAnalysis/TrackNanoAOD/test/nanoML_cfg.py new file mode 100644 index 0000000000000..c3e61dbb2b302 --- /dev/null +++ b/DPGAnalysis/TrackNanoAOD/test/nanoML_cfg.py @@ -0,0 +1,120 @@ +# Auto generated configuration file +# using: +# Revision: 1.19 +# Source: /local/reps/CMSSW/CMSSW/Configuration/Applications/python/ConfigBuilder.py,v +# with command line options: step1 --filein file:test.root --fileout testNanoML.root --mc --eventcontent NANOAODSIM --datatier NANOAODSIM --conditions auto:mc --step NANO +import FWCore.ParameterSet.Config as cms +from FWCore.ParameterSet.VarParsing import VarParsing + + +process = cms.Process('NANO') +options = VarParsing('python') +options.setDefault('outputFile', 'testNanoML.root') +options.parseArguments() + +# import of standard configurations +process.load('Configuration.StandardSequences.Services_cff') +process.load('SimGeneral.HepPDTESSource.pythiapdt_cfi') +process.load('FWCore.MessageService.MessageLogger_cfi') +process.load('Configuration.EventContent.EventContent_cff') +process.load('SimGeneral.MixingModule.mixNoPU_cfi') +process.load('Configuration.Geometry.GeometryExtended2026D49Reco_cff') +process.load('Configuration.Geometry.GeometryExtended2026D49_cff') +process.load('Configuration.StandardSequences.MagneticField_cff') +process.load('PhysicsTools.NanoAOD.nanoHGCML_cff') +process.load('Configuration.StandardSequences.EndOfProcess_cff') +process.load('Configuration.StandardSequences.FrontierConditions_GlobalTag_cff') + +process.maxEvents = cms.untracked.PSet( + input = cms.untracked.int32(-1), + output = cms.optional.untracked.allowed(cms.int32,cms.PSet) +) + +# Input source +process.source = cms.Source("PoolSource", + fileNames = cms.untracked.vstring(options.inputFiles), + secondaryFileNames = cms.untracked.vstring() +) + +process.options = cms.untracked.PSet( + FailPath = cms.untracked.vstring(), + IgnoreCompletely = cms.untracked.vstring(), + Rethrow = cms.untracked.vstring(), + SkipEvent = cms.untracked.vstring(), + allowUnscheduled = cms.obsolete.untracked.bool, + canDeleteEarly = cms.untracked.vstring(), + emptyRunLumiMode = cms.obsolete.untracked.string, + eventSetup = cms.untracked.PSet( + forceNumberOfConcurrentIOVs = cms.untracked.PSet( + allowAnyLabel_=cms.required.untracked.uint32 + ), + numberOfConcurrentIOVs = cms.untracked.uint32(1) + ), + fileMode = cms.untracked.string('FULLMERGE'), + forceEventSetupCacheClearOnNewRun = cms.untracked.bool(False), + makeTriggerResults = cms.obsolete.untracked.bool, + numberOfConcurrentLuminosityBlocks = cms.untracked.uint32(1), + numberOfConcurrentRuns = cms.untracked.uint32(1), + numberOfStreams = cms.untracked.uint32(0), + numberOfThreads = cms.untracked.uint32(1), + printDependencies = cms.untracked.bool(False), + sizeOfStackForThreadsInKB = cms.optional.untracked.uint32, + throwIfIllegalParameter = cms.untracked.bool(True), + wantSummary = cms.untracked.bool(False) +) + +# Production Info +process.configurationMetadata = cms.untracked.PSet( + annotation = cms.untracked.string('step1 nevts:1'), + name = cms.untracked.string('Applications'), + version = cms.untracked.string('$Revision: 1.19 $') +) + +# Output definition + +process.NANOAODSIMoutput = cms.OutputModule("NanoAODOutputModule", + compressionAlgorithm = cms.untracked.string('LZMA'), + compressionLevel = cms.untracked.int32(9), + dataset = cms.untracked.PSet( + dataTier = cms.untracked.string('NANOAODSIM'), + filterName = cms.untracked.string('') + ), + fileName = cms.untracked.string(options.outputFile), + outputCommands = process.NANOAODSIMEventContent.outputCommands +) + +process.NANOAODSIMoutput.outputCommands.remove("keep edmTriggerResults_*_*_*") + +# Additional output definition + +# Other statements +from Configuration.AlCa.GlobalTag import GlobalTag +process.GlobalTag = GlobalTag(process.GlobalTag, 'auto:mc', '') + +# Path and EndPath definitions +process.nanoAOD_step = cms.Path(process.nanoHGCMLSequence) +process.endjob_step = cms.EndPath(process.endOfProcess) +process.NANOAODSIMoutput_step = cms.EndPath(process.NANOAODSIMoutput) + +# Schedule definition +process.schedule = cms.Schedule(process.nanoAOD_step,process.endjob_step,process.NANOAODSIMoutput_step) +from PhysicsTools.PatAlgos.tools.helpers import associatePatAlgosToolsTask +associatePatAlgosToolsTask(process) + +# customisation of the process. +from PhysicsTools.NanoAOD.nanoHGCML_cff import customizeReco,customizeMergedSimClusters +process = customizeReco(process) +# Uncomment if you didn't schedule SimClusters/CaloParticles +# process = customizeNoMergedCaloTruth(process) +# merged simclusters (turn off if you aren't running through PEPR) +process = customizeMergedSimClusters(process) + +# End of customisation functions + + +# Customisation from command line + +# Add early deletion of temporary data products to reduce peak memory need +from Configuration.StandardSequences.earlyDeleteSettings_cff import customiseEarlyDelete +process = customiseEarlyDelete(process) +# End adding early deletion diff --git a/HGCSimTruth/HGCSimTruth/.DS_Store b/HGCSimTruth/HGCSimTruth/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..d4c3b3b44335ff5dded73a0e0ff84f6d3b8f2819 GIT binary patch literal 8196 zcmeHMUu+ab82`Suz>d%|MQE=s2PYT)+QNwxiZ*y{k3wk?!nL&gJ@#&wcH?%p?C#y6 zO_ORgYNAAq#sm@*gMSi4o;1pfFMu%`|HRZpVu*=P`eb}D#;Ea|oh^R~_u_++u#?Pu zGv9pQd^5lK-A-l>0I;*D-wzN20EM!Ud@dEYNTOfln^IM%sUeBv58hbba`M#rEkAaX zb)<+8h!BVnh!BVnh!D6P5TG+#B&EW+FMFdhLLfrmjzmCw9}<*>Oowt(%HY#MMQ{Zm zDXsuPqB<89l8I2JLpdoW^-x0TN>aLFc*Q{JPWnV>mk#Bml+qnAynJ978N(Y22GME! zL|_h>mNF_M1R?}(MnL?0s=)&n3iGBThN% zYktw|)Z83joHcbLuepP!?vL~v_EyU%8TKx>PxB4;fH3ZN9E%KOUCZw^jdG4J>~d^h zGi}2S#*?u*)f&vE^(z;MVUU!lwK1;T&Vm~T3^x7Tnzl8n7OZ&7^Niu+Qn4?dik zs;!&P>lZM#p8&Ld^QdXK17)!j`!ug$*t%&C50*^N%v(mkt&JM>)ju&dRol=QYr02O zE13=z^X9Rl=|9GkiW0am#( z6`avgTBjF8PIsv4VG+4c^ZZ?7hE22jl)}dv8f(?1>NZ8$Cwe<{oo1CxuacV`z>rL* zWQ&VqrwN*23v|PND1Z%RcphGW6L1nv!#Q{#K88==bNCXzg0JB+`~W}0ukZ)_34g)g zI0qME12$p|@5L5ei|eorH{(OtjvcrIdvPZ|f>}I>hcJgn@F+SshAw(Ij!)s!_$)q$ zFXJgZgJL5NOT0q0@P|ue4IkdB4&REb@$PNg zGye-&FVB+o>J`T;0SOdv`sF0@g@c1az6EL$G-_@Nh~}nZ*Z)RmSm3 zjOKF$f0U`F##lo<5nrYdQ+U{19$%>toq1I-*6KBJ#;b|BENHG>$KrezkyHtq4{TtJ z*AR5JGT4pVv4_}~#Q_||A>4;~)QNk;ID*HBdqpf^ z87J|HfP>HAi}(_;@D+R&U&qrkIM*}HHYxG!HO`f?u5CH?FlnY4dZTgFy6q9DmNSfr z`~TL;@Bg>`I-&_i2t)|{djzm1lg)IJf2A+ExN9dUAE7Lgu$z=JaG~OchX86{{lk#z d2{IKv=}=BeNg7K3`9nZ-{zvD3z`Q%V_y-{k@Kyi- literal 0 HcmV?d00001 diff --git a/HGCSimTruth/HGCSimTruth/._.DS_Store b/HGCSimTruth/HGCSimTruth/._.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..a5b28df1cbc6e15bd0d35cdadd0c2e65d5131c7d GIT binary patch literal 120 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}u^SMB_!U6R08`;00ODZ-jv*mIP;rnB Iur73U08|YJ=l}o! literal 0 HcmV?d00001 diff --git a/HGCSimTruth/HGCSimTruth/BuildFile.xml b/HGCSimTruth/HGCSimTruth/BuildFile.xml new file mode 100644 index 0000000000000..4383c46093a58 --- /dev/null +++ b/HGCSimTruth/HGCSimTruth/BuildFile.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/HGCSimTruth/HGCSimTruth/interface/SimClusterTools.h b/HGCSimTruth/HGCSimTruth/interface/SimClusterTools.h new file mode 100644 index 0000000000000..589d534a1d6da --- /dev/null +++ b/HGCSimTruth/HGCSimTruth/interface/SimClusterTools.h @@ -0,0 +1,42 @@ +/* + * SimClusterTools.h + * + * Created on: 16 Dec 2019 + * Author: jkiesele + */ + +#ifndef PRODUCTION_HGCALSIM_CMSSW_JKIESELE_CMSSW_11_0_0_PRE9_SRC_RECOHGCAL_GRAPHRECO_INTERFACE_SIMCLUSTERTOOLS_H_ +#define PRODUCTION_HGCALSIM_CMSSW_JKIESELE_CMSSW_11_0_0_PRE9_SRC_RECOHGCAL_GRAPHRECO_INTERFACE_SIMCLUSTERTOOLS_H_ + +#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" +#include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" +#include "RecoLocalCalo/HGCalRecAlgos/interface/RecHitTools.h" +#include "DataFormats/HGCRecHit/interface/HGCRecHitCollections.h" +#include "DataFormats/Math/interface/deltaR.h" +#include "DataFormats/Math/interface/deltaPhi.h" +#include +#include + +class SimClusterTools { +public: + SimClusterTools() : recHitTools_(0), detid_to_rh_index_(0), allrechits_(0), considerhitdistance_(0.1) {} + + void recalculatePosition(SimCluster& cluster, const double& assigned_time) const; + + //has at least one hit in the hgcal + bool isHGCal(const SimCluster& cluster)const; + + void setRechitTools(const hgcal::RecHitTools& rht) { recHitTools_ = &rht; } + + void setRechitVector(const std::vector& rhv) { allrechits_ = &rhv; } + + void setIndexMap(const std::unordered_map& idxmap) { detid_to_rh_index_ = &idxmap; } + +private: + const hgcal::RecHitTools* recHitTools_; + const std::unordered_map* detid_to_rh_index_; + const std::vector* allrechits_; + float considerhitdistance_; +}; + +#endif /* PRODUCTION_HGCALSIM_CMSSW_JKIESELE_CMSSW_11_0_0_PRE9_SRC_RECOHGCAL_GRAPHRECO_INTERFACE_SIMCLUSTERTOOLS_H_ */ diff --git a/HGCSimTruth/HGCSimTruth/plugins/BuildFile.xml b/HGCSimTruth/HGCSimTruth/plugins/BuildFile.xml new file mode 100644 index 0000000000000..0b4c0b3575559 --- /dev/null +++ b/HGCSimTruth/HGCSimTruth/plugins/BuildFile.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HGCSimTruth/HGCSimTruth/plugins/HGCSimTruth.cc b/HGCSimTruth/HGCSimTruth/plugins/HGCSimTruth.cc new file mode 100644 index 0000000000000..455ad8064821c --- /dev/null +++ b/HGCSimTruth/HGCSimTruth/plugins/HGCSimTruth.cc @@ -0,0 +1,722 @@ +/* + * CMSSW module to create the trees used for the HH2bbtautau analysis. + * Disclainer: This prototype is not meant for creating an official PR. Major refactoring ahead. + */ + +#include + +#include "FWCore/Framework/interface/ConsumesCollector.h" +#include "FWCore/Framework/interface/ESHandle.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/Framework/interface/ProducerBase.h" +#include "FWCore/Framework/interface/stream/EDProducer.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/Utilities/interface/InputTag.h" +#include "FWCore/Utilities/interface/StreamID.h" + +#include "DataFormats/ForwardDetId/interface/HGCalDetId.h" +#include "DataFormats/HcalDetId/interface/HcalDetId.h" +#include "DataFormats/HcalDetId/interface/HcalTestNumbering.h" +#include "DataFormats/HGCRecHit/interface/HGCRecHitCollections.h" +#include "DataFormats/HepMCCandidate/interface/GenParticle.h" +#include "DataFormats/Math/interface/deltaR.h" +#include "DataFormats/Math/interface/deltaPhi.h" +#include "DataFormats/SiPixelDetId/interface/PixelSubdetector.h" +#include "DataFormats/SiStripDetId/interface/StripSubdetector.h" + +#include "SimDataFormats/CaloAnalysis/interface/CaloParticle.h" +#include "SimDataFormats/CaloAnalysis/interface/CaloParticleFwd.h" +#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" +#include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" +#include "SimDataFormats/CaloHit/interface/PCaloHit.h" +#include "SimDataFormats/CaloHit/interface/PCaloHitContainer.h" +#include "SimDataFormats/CaloTest/interface/HGCalTestNumbering.h" +#include "SimDataFormats/GeneratorProducts/interface/HepMCProduct.h" +#include "SimDataFormats/Vertex/interface/SimVertex.h" + +#include "SimGeneral/MixingModule/interface/DigiAccumulatorMixMod.h" +#include "SimGeneral/MixingModule/interface/DigiAccumulatorMixModFactory.h" +#include "SimGeneral/MixingModule/interface/PileUpEventPrincipal.h" +#include "SimGeneral/TrackingAnalysis/interface/EncodedTruthId.h" + +#include "Geometry/CaloGeometry/interface/CaloGeometry.h" +#include "Geometry/HGCalGeometry/interface/HGCalGeometry.h" +#include "Geometry/HcalCommonData/interface/HcalHitRelabeller.h" +#include "Geometry/HcalTowerAlgo/interface/HcalGeometry.h" +#include "Geometry/Records/interface/CaloGeometryRecord.h" +#include "DataFormats/Common/interface/Association.h" +#include "FWCore/Utilities/interface/transform.h" + +#include "RecoLocalCalo/HGCalRecAlgos/interface/RecHitTools.h" + +#include "HGCSimTruth/HGCSimTruth/interface/SimClusterTools.h" +#include "DataFormats/Common/interface/AssociationMap.h" +#include "DataFormats/Common/interface/OneToManyWithQualityGeneric.h" + +#include "TMath.h" +#include "TCanvas.h" +#include "TH1F.h" + +float getShowerRadius(float f, float r1, float f1) { + float a = r1 / (sqrt(2) * TMath::ErfInverse(f1 - 0.00001)); + return a * sqrt(2) * TMath::ErfInverse(f - 0.00001); +} + +float getShowerRadius(float f, float r1, float f1, float r2, float f2) { + float d1 = getShowerRadius(f, r1, f1); + float d2 = getShowerRadius(f, r2, f2); + return (d1 + d2) / 2.f; +} + +float getShowerRadius(float f, float r1, float f1, float r2, float f2, float r3, float f3) { + float d1 = getShowerRadius(f, r1, f1); + float d2 = getShowerRadius(f, r2, f2); + float d3 = getShowerRadius(f, r3, f3); + return (d1 + d2 + d3) / 3.f; +} + +int commonAncestorPdgId(const std::vector>& v1, const std::vector>& v2) { + // integer pairs represent the vertex id in the graph and the pdg id of the corresponding particle + // to get the pdg id of the first common ancestor, walk through v1 and check if any vertex id is + // contained in v2, and if so, return the pdg id (should be the same for the matching elements) + for (const auto& p1 : v1) { + for (const auto& p2 : v2) { + if (p1.first == p2.first) { + return p1.second; + } + } + } + return 0; +} + +struct ChainIndex { + ChainIndex(int iSC, ChainIndex* prev, ChainIndex* next) : iSC(iSC), prev(prev), next(next) {} + + ChainIndex(int iSC) : ChainIndex(iSC, nullptr, nullptr) {} + + ChainIndex(const ChainIndex& o) : ChainIndex(o.iSC, o.prev, o.next) {} + + bool operator==(const ChainIndex& o) const { return o.iSC == iSC; } + + int iSC; + ChainIndex* prev; + ChainIndex* next; +}; + +typedef std::pair IdxAndFraction; +typedef edm::AssociationMap> SimClusterToSimClusters; + +class HGCTruthProducer : public edm::stream::EDProducer<> { +public: + static void fillDescriptions(edm::ConfigurationDescriptions&); + + explicit HGCTruthProducer(const edm::ParameterSet&); + ~HGCTruthProducer(); + + virtual void beginStream(edm::StreamID) override; + virtual void endStream() override; + virtual void produce(edm::Event&, const edm::EventSetup&) override; + + void determineSimClusterGroups(const SimClusterCollection&, + std::vector>&, + std::unique_ptr>&, + std::unique_ptr>&) const; + + bool checkSimClusterMerging(int, + int, + const SimClusterCollection&, + const std::unique_ptr>&, + const std::unique_ptr>&) const; + + void mergeSimClusters(const SimClusterCollection&, + const std::vector>&, + std::unique_ptr&, + const std::vector&, + const std::unordered_map&) const; + +private: + float showerContainment_; + float minEta_; + float maxEta_; + int minHitsRadius_; + float maxDeltaEtaGroup_; + bool verbose_; + + edm::EDGetTokenT> caloParticleToken_; + edm::EDGetTokenT> simClusterToken_; + std::vector> recHitTokens_; + //std::vector simHitTags_ + //std::vector> simHitTokens_; + + hgcal::RecHitTools recHitTools_; +}; + +void HGCTruthProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + + desc.add("minEta", 1.52); + desc.add("maxEta", 3.00); + desc.add("minHitsRadius", 5); + desc.add("maxDeltaEtaGroup", 0.15); + desc.addUntracked("verbose", false); + desc.add("caloParticleCollection", edm::InputTag("mix", "MergedCaloTruth")); + desc.add("simClusterCollection", edm::InputTag("mix", "MergedCaloTruth")); + desc.add>("recHitCollections", + { + edm::InputTag("HGCalRecHit", "HGCEERecHits"), + edm::InputTag("HGCalRecHit", "HGCHEFRecHits"), + edm::InputTag("HGCalRecHit", "HGCHEBRecHits"), + }); + //desc.add>("simHitCollections", + // { + // edm::InputTag("g4SimHits", "HGCHitsEE"), + // edm::InputTag("g4SimHits", "HGCHitsHEfront"), + // edm::InputTag("g4SimHits", "HGCHitsHEback"), + // }); + + + descriptions.add("hgcTruthProducer", desc); +} + +HGCTruthProducer::HGCTruthProducer(const edm::ParameterSet& params) + : showerContainment_(0.6827), + minEta_(params.getParameter("minEta")), + maxEta_(params.getParameter("maxEta")), + minHitsRadius_(params.getParameter("minHitsRadius")), + maxDeltaEtaGroup_(params.getParameter("maxDeltaEtaGroup")), + verbose_(params.getUntrackedParameter("verbose")), + caloParticleToken_( + consumes>(params.getParameter("caloParticleCollection"))), + simClusterToken_(consumes>(params.getParameter("simClusterCollection"))), + recHitTokens_(edm::vector_transform(params.getParameter>("recHitCollections"), + [this](const edm::InputTag& tag) {return consumes(tag); })) { + //simHitTags_(pset.getParameter>("simHitCollections")), + //simHitTokens_(edm::vector_transform(caloSimHitTags_, + // [this](const edm::InputTag& tag) {return consumes>(tag); })) { + if (verbose_) { + std::cout << "running TreeWriter in verbose mode" << std::endl; + } + + // define products + produces>(); // SimClusters + produces>(); // radii + produces>(); // rechit-base four-momenta of merged clusters + + //for (auto& tag : simHitTags_) { + // std::string label = tag.instance(); + // produces>(label+"ToSimClus"); + //} + produces>(); + produces(); +} + +HGCTruthProducer::~HGCTruthProducer() {} + +void HGCTruthProducer::beginStream(edm::StreamID) {} + +void HGCTruthProducer::endStream() {} + +void HGCTruthProducer::produce(edm::Event& event, const edm::EventSetup& setup) { + std::cout << "HGCTruthProducer::produce" << std::endl; + edm::ESHandle geom; + setup.get().get(geom); + recHitTools_.setGeometry(*geom); + + // create unique pointers for output products + std::unique_ptr> mergedSimClusters = std::make_unique>(); + std::unique_ptr> radii = std::make_unique>(); + std::unique_ptr> vectors = + std::make_unique>(); + + // read original SimClusters + edm::Handle> simClusterHandle; + event.getByToken(simClusterToken_, simClusterHandle); + SimClusterCollection simClusters(*simClusterHandle); + + std::vector allrechits; + std::unordered_map detid_to_rh_index; + size_t rhindex = 0; + for (auto& token : recHitTokens_) { + for (const auto& rh : event.get(token)) { + detid_to_rh_index[rh.detid()] = rhindex; + rhindex++; + allrechits.push_back(&rh); + } + } + + // determine clustering groups + std::vector> groups; + determineSimClusterGroups(simClusters, groups, radii, vectors); + + mergeSimClusters(simClusters, groups, mergedSimClusters, allrechits, detid_to_rh_index); + + std::cout << "initial simclusters " << simClusters.size() << " merged: " << mergedSimClusters->size() + << std::endl; //DEBUG Jan + + // save outputs + const auto& mergedSCHandle = event.put(std::move(mergedSimClusters)); + event.put(std::move(radii)); + event.put(std::move(vectors)); + + auto assocMap = std::make_unique(mergedSCHandle, simClusterHandle); + + std::vector mergedIndices(simClusters.size(), 0); + for (size_t i = 0; i < groups.size(); i++) { + SimClusterRef msc(mergedSCHandle, i); + float mergedE = msc->impactMomentum().energy(); + for (auto idx : groups.at(i)) { + mergedIndices.at(idx) = i; + SimClusterRef sc(simClusterHandle, idx); + float scE = sc->impactMomentum().energy(); + assocMap->insert(msc, std::make_pair(sc, mergedE/scE)); + } + } + event.put(std::move(assocMap)); + + // do the actual merging + auto assoc = std::make_unique>(mergedSCHandle); + edm::Association::Filler filler(*assoc); + filler.insert(simClusterHandle, mergedIndices.begin(), mergedIndices.end()); + filler.fill(); + event.put(std::move(assoc)); + //std::unordered_map hitDetIdToIndex; + //for (size_t s = 0; s < mergedSimClusters->size(); s++) { + // const auto& sc = mergedSimClusters->at(s); + // for (auto& hf : sc.hits_and_fractions()) { + // auto entry = hitDetIdToIndex.find(hf.first); + // // Update SimCluster assigment if detId has been found in no other SCs or if + // // SC has greater fraction of energy in DetId than the SC already found + // if (entry == hitDetIdToIndex.end() || entry->second.second < hf.second) + // hitDetIdToIndex[hf.first] = {s, hf.second}; + // } + //} + +} + +void HGCTruthProducer::determineSimClusterGroups(const SimClusterCollection& simClusters, + std::vector>& groups, + std::unique_ptr>& radii, + std::unique_ptr>& vectors) const { + // Note: In many places, the implementation is based on indices for performance purposes. To + // simplify the distinction, they are referred to as {i,j}Name, such as iSC for sim clusters or iH + // for hits. Sometimes, lists (vectors) of these indices are used. The index to those values are + // (e.g.) iiSC or iiH. + int nSimClusters = (int)simClusters.size(); + + // clear the radii vector and reserve space + radii->clear(); + radii->resize(nSimClusters); + vectors->clear(); + vectors->resize(nSimClusters); + + // for the moment, only SimClusters in the HGCal are considered + // clusters in the HCal barrel are copied unchanged + std::vector scIndices; + for (int iSC = 0; iSC < nSimClusters; iSC++) { + /* + * Note: we cannot exclude simclusters by eta here, because some of them have wrong information. + * If we remove those, their hits will be wrongly labelled as noise later. + */ + + // auto absEta = fabs(simClusters[iSC].impactPoint().eta() ); + //if (absEta == absEta && absEta >= minEta_ && absEta <= maxEta_) { + // cluster located in HGCal, store the index for treatment downstream + scIndices.push_back(iSC); + //} else { + // cluster located in HCal, only store a non-physical radius + (*radii)[iSC] = -1.; + // } + } + + // the number of sim clusters in the HGCal + int nHGCalSimClusters = (int)scIndices.size(); + + // determine simCluster radii + for (const int& iSC : scIndices) { + // create four-vectors for each hit and the summed shower vector + auto atthispointthis_is_hitsandfractions_hitsAndEnergies = simClusters[iSC].hits_and_fractions(); + int nHits = (int)atthispointthis_is_hitsandfractions_hitsAndEnergies.size(); + math::XYZTLorentzVectorD showerVector; + std::vector hitVectors; + hitVectors.resize(atthispointthis_is_hitsandfractions_hitsAndEnergies.size()); + std::vector hitVectorIndices; + hitVectorIndices.resize(atthispointthis_is_hitsandfractions_hitsAndEnergies.size()); + for (int iH = 0; iH < nHits; iH++) { + // get the hit position and create the four-vector, assuming no mass + GlobalPoint position = recHitTools_.getPosition(atthispointthis_is_hitsandfractions_hitsAndEnergies[iH].first); + float energy = atthispointthis_is_hitsandfractions_hitsAndEnergies[iH].second; + float scale = energy / position.mag(); + hitVectors[iH].SetPxPyPzE(position.x() * scale, position.y() * scale, position.z() * scale, energy); + showerVector += hitVectors[iH]; + hitVectorIndices[iH] = iH; + } + //overwrites whatever was there before + //Jan: hack in the propagated vector + showerVector = simClusters[iSC].impactPoint(); + + // sort the hit vector indices according to distance to the shower vector, closest first + // notice the change from iH to iiH as from now on, the hitVectorIndices hold indices referring + // to the actual index in hitVectors + sort( + hitVectorIndices.begin(), hitVectorIndices.end(), [&showerVector, &hitVectors](const int& iiH, const int& jjH) { + return deltaR(showerVector, hitVectors[iiH]) < deltaR(showerVector, hitVectors[jjH]); + }); + + // loop through hit vectors in order of the sorted indices until the target energy is reached + float radius = deltaR(showerVector, hitVectors[hitVectorIndices[nHits - 1]]); + if (nHits >= minHitsRadius_) { + float sumEnergy = 0.; + + for (int iiH = 0; iiH < nHits; iiH++) { + int iH = hitVectorIndices[iiH]; + sumEnergy += hitVectors[iH].E(); + // define the radius as the average of two or three guidance points close to the requested + // shower containment fraction + if (sumEnergy / showerVector.E() > showerContainment_) { + if (iiH >= 1 && iiH <= nHits - 2) { + float r1 = deltaR(showerVector, hitVectors[iH]); + float f1 = sumEnergy / showerVector.E(); + float r2 = deltaR(showerVector, hitVectors[hitVectorIndices[iiH - 1]]); + float r3 = deltaR(showerVector, hitVectors[hitVectorIndices[iiH + 1]]); + float f2 = (sumEnergy - hitVectors[hitVectorIndices[iiH - 1]].E()) / showerVector.E(); + float f3 = (sumEnergy + hitVectors[hitVectorIndices[iiH + 1]].E()) / showerVector.E(); + radius = getShowerRadius(showerContainment_, r1, f1, r2, f2, r3, f3); + } else if (iiH >= 1) { + float r1 = deltaR(showerVector, hitVectors[iH]); + float f1 = sumEnergy / showerVector.E(); + float r2 = deltaR(showerVector, hitVectors[hitVectorIndices[iiH - 1]]); + float f2 = (sumEnergy - hitVectors[hitVectorIndices[iiH - 1]].E()) / showerVector.E(); + radius = getShowerRadius(showerContainment_, r1, f1, r2, f2); + } else if (iiH <= nHits - 2) { + float r1 = deltaR(showerVector, hitVectors[iH]); + float f1 = sumEnergy / showerVector.E(); + float r3 = deltaR(showerVector, hitVectors[hitVectorIndices[iiH + 1]]); + float f3 = (sumEnergy + hitVectors[hitVectorIndices[iiH + 1]].E()) / showerVector.E(); + radius = getShowerRadius(showerContainment_, r1, f1, r3, f3); + } + } + } + } + + (*vectors)[iSC] = showerVector; + (*radii)[iSC] = radius; + } + + // sort the cluster indices by eta + sort(scIndices.begin(), scIndices.end(), [&simClusters](const int& iSC, const int& jSC) { + return simClusters[iSC].impactPoint().eta() < simClusters[jSC].impactPoint().eta(); + }); + + // define a vector of chained indices for easy lookup of closeby clusters + // this might look trivial, but the next/prev pointers are changed dynamically downstream to + // describe / close holes in the chain during cluster merging + std::vector chain; + for (int iiSC = 0; iiSC < nHGCalSimClusters; iiSC++) { + // add a new chain element + int iSC = scIndices[iiSC]; + chain.push_back(new ChainIndex(iSC)); + + // connect elements + if (iiSC > 0) { + chain[iiSC]->prev = chain[iiSC - 1]; + chain[iiSC - 1]->next = chain[iiSC]; + } + } + + while (chain.size() > 0) { + // define the merging group, seeded by the current front-most element of the chain + // (fancy talk for the sim cluster with the smallest eta that hasn't been checked yet) + std::vector chainIndices = {chain[0]}; + std::vector group = {chain[0]->iSC}; + int iG = 0; + + while (iG < (int)chainIndices.size()) { + // look for nearby clusters of the sim cluster in the group referred to by iG + // this approach mimics recursion as the group might be extended within this while loop + ChainIndex* curr = chainIndices[iG]; + + // check clusters with smaller eta + ChainIndex* prev = curr->prev; + while (prev != nullptr) { + // do nothing when the previous element is already in the group + if (std::find(group.begin(), group.end(), prev->iSC) == group.end()) { + // stop when the difference in eta is too high already + const auto& currCluster = simClusters[curr->iSC]; + const auto& prevCluster = simClusters[prev->iSC]; + auto dEta = + fabs(currCluster.impactPoint().eta() - prevCluster.impactPoint().eta()); // fabs actually not required + if (dEta > maxDeltaEtaGroup_) { + break; + } + // check if the two clusters should be merged + // TODO: shouldn't the check consider all elements already in the group? ordering issue ahead? + if (checkSimClusterMerging(curr->iSC, prev->iSC, simClusters, radii, vectors)) { + // add the element to the group + chainIndices.push_back(prev); + group.push_back(prev->iSC); + } + } + + // go backward + prev = prev->prev; + } + + // check clusters with higher eta + ChainIndex* next = curr->next; + while (next != nullptr) { + // do nothing when the next element is already in the group + if (std::find(group.begin(), group.end(), next->iSC) == group.end()) { + // stop when the difference in eta is too high already + const auto& currCluster = simClusters[curr->iSC]; + const auto& nextCluster = simClusters[next->iSC]; + auto dEta = + fabs(nextCluster.impactPoint().eta() - currCluster.impactPoint().eta()); // fabs actually not required + if (dEta > maxDeltaEtaGroup_) { + break; + } + // check if the two clusters should be merged + // TODO: see not above + if (checkSimClusterMerging(next->iSC, curr->iSC, simClusters, radii, vectors)) { + // add the element to the group + chainIndices.push_back(next); + group.push_back(next->iSC); + } + } + + // go forward + next = next->next; + } + + // remove the current element and reconnect the chain + if (curr->prev != nullptr) { + if (curr->next != nullptr) { + curr->prev->next = curr->next; + curr->next->prev = curr->prev; + } else { + curr->prev->next = nullptr; + } + } else if (curr->next != nullptr) { + curr->next->prev = nullptr; + } + + std::vector::iterator it = std::find(chain.begin(), chain.end(), curr); + delete *it; + chain.erase(it); + + // choose the next element in the group for the next iteration + iG++; + } + + // store the actual group of sim cluster indices + groups.push_back(group); + } + + // group debugging + std::cout << "created " << groups.size() << " groups" << std::endl; + double sumSize = 0.; + for (const auto& g : groups) { + sumSize += g.size(); + } + std::cout << "average size: " << (sumSize / groups.size()) << std::endl; + + // radius debugging + // { + // TCanvas* canvas = new TCanvas(); + // TH1F* hist = new TH1F(("h" + std::to_string(firstI)).c_str(), ";Radius;# Entries", 51, -0.02, 2.02); + + // int nRadii = 0; + // double sumRadius = 0.; + // for (const float &r : radii) { + // // if (isinf(r)) std::cout << "got inf radius!" << std::endl; + // hist->Fill(r); + // if (r > 0) { + // sumRadius += r; + // nRadii++; + // } + // } + // std::cout << "sum: " << sumRadius << std::endl; + // std::cout << "n radii: " << nRadii << std::endl; + // double meanRadius = sumRadius / nRadii; + // std::cout << "mean: " << meanRadius << std::endl; + // double sumDiffRadius2 = 0.; + // for (const float &r : radii) { + // if (r > 0) { + // double diffRadius = r - meanRadius; + // sumDiffRadius2 += diffRadius * diffRadius; + // } + // } + // double varianceRadius = sumDiffRadius2 / (nRadii - 1); + // double stdRadius = sqrt(varianceRadius); + // std::cout << "radius mean: " << meanRadius << ", std: " << stdRadius << std::endl; + + // hist->Draw(); + // canvas->SaveAs(("hist_" + std::to_string(firstI) + ".pdf").c_str()); + + // delete hist; + // delete canvas; + // } +} + +bool HGCTruthProducer::checkSimClusterMerging( + int iSC, + int jSC, + const SimClusterCollection& simClusters, + const std::unique_ptr>& radii, + const std::unique_ptr>& vectors) const { + // get some values + auto dR = deltaR(vectors->at(iSC), vectors->at(jSC)); + + //Jan + return dR < 0.016; + + auto radius1 = radii->at(iSC); + auto radius2 = radii->at(jSC); + + // define a combined radius using error propagation rules (as the pull is defined statistics-like) + auto combinedRadius = pow(radius1 * radius1 + radius2 * radius2, 0.5); + + // when both clusters have no radius, i.e., they are coming from single hits, make a quick + // decision solely based on dR (FREE PARAMETER) + if (combinedRadius == 0) { + return dR < 0.005; + } + + // if at least one clusters has a non-zero radius, define a pull + auto pull = dR / combinedRadius; + + // use a simple merging criterion based on the pull (FREE PARAMETER) + return pull < 0.5; + + // TODO: exploit information about common ancestors (e.g. useful for e/gamma, pi0, ...) +} + +void HGCTruthProducer::mergeSimClusters(const SimClusterCollection& simClusters, + const std::vector>& groups, + std::unique_ptr& mergedSimClusters, + const std::vector& rechits, + const std::unordered_map& rh_detid_to_idx) const { + for (std::vector group : groups) { + if (group.size() == 0) { + continue; + } + + //DEBUG >>> + + auto groupcp=group; + auto it = std::unique (groupcp.begin(),groupcp.end()); + groupcp.resize(std::distance(groupcp.begin(),it)); + + if(groupcp.size() != group.size()) + throw std::runtime_error("not unique group"); + + // <<<< DEBUG end + + // sort group elements by sim cluster energies + sort(group.begin(), group.end(), [&simClusters](const int& iSC, const int& jSC) { + return simClusters[iSC].energy() > simClusters[jSC].energy(); + }); + + // get a vector of all sim tracks, also store the total energy + ROOT::Math::LorentzVector> combinedmomentum ; + ROOT::Math::LorentzVector> combinedimpact; + std::vector mergedSCTracks; + + //std::cout << "grouping: " << std::endl; + SimCluster newsc; + for (const int& iSC : group) { + // there is currently only one track per sim clusters + newsc += simClusters[iSC]; + auto& scTracks = simClusters[iSC].g4Tracks(); + mergedSCTracks.insert(mergedSCTracks.end(), scTracks.begin(), scTracks.end()); + } + + // TODO: determine the pdg id using infos about common ancestors + // For now just take the PDG of the highest energy track + std::sort(mergedSCTracks.begin(), mergedSCTracks.end(), [](auto& t1, auto& t2) + { return t1.momentum().E() > t2.momentum().E(); }); + + int pdgId = mergedSCTracks.front().type(); + + ROOT::Math::LorentzVector> combinedmomentumD( + combinedmomentum.x(), combinedmomentum.y(), combinedmomentum.z(), combinedmomentum.t()); + //still needs to be added + newsc.setPdgId(pdgId); + + //std::cout << "ESum group: " << esum << " vs " << combinedmomentum.E() << std::endl; + + // create the cluster + mergedSimClusters->emplace_back(newsc); + auto& cluster = mergedSimClusters->back(); + + // fill hits and energy fractions + // since we merge, we have to care about duplicate hits and this might become drastically slow + // therefore, use the default addRecHitAndFraction method for the first cluster, and then + // loop over the remaining ones to invoke the slower but necessary addDuplicateRecHitAndFraction + + for (const auto& hf : simClusters[group[0]].hits_and_fractions()) { + cluster.addRecHitAndFraction(hf.first, hf.second); + } + for (int iiSC = 1; iiSC < (int)group.size(); iiSC++) { + int iSC = group[iiSC]; + for (const auto& hf : simClusters[iSC].hits_and_fractions()) { + cluster.addDuplicateRecHitAndFraction(hf.first, hf.second); + } + } + + //DEBUG >>>> + cluster.simEnergy(); + + + } +} + +DEFINE_FWK_MODULE(HGCTruthProducer); + +// unused helper methods, to be removed +// bool vectorsIntersect(const std::vector &v1, const std::vector &v2) { +// // for large vectors, it would be useful to loop through sorted indices and stop early +// // when no match of a number of v1 is possible with any element in v2, but when comparing +// // vectors of incoming vertices, i.e., parent particles, those vectors are rather small +// for (const int &i1 : v1) { +// for (const int &i2 : v2) { +// if (i1 == i2) { +// return true; +// } +// } +// } +// return false; + +// // second possible approach based on set intersections, but this one compares all elements +// // without stopping early +// // std::vector result; +// // std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), back_inserter(result)); +// // return result.size() > 0; +// } +// +// float getShowerRadius(float f, float r1, float f1, float r2, float f2) { +// float b = log(log(1.f - f2) / log(1.f - f1)) / log(r2 / r1); +// float a = - log(1.f - f1) / pow(r1, b); +// float res = pow(-log(1.f - f) / a, 1.f / b); +// if (isinf(res)) { +// std::cout << "produced inf" << std::endl; +// std::cout << "f : " << f << std::endl; +// std::cout << "r1: " << r1 << std::endl; +// std::cout << "f1: " << f1 << std::endl; +// std::cout << "r2: " << r2 << std::endl; +// std::cout << "f2: " << f2 << std::endl; +// std::cout << "--------------" << std::endl; +// } +// return pow(-log(1.f - f) / a, 1.f / b); +// } +// +// float getShowerRadius(float f, float r1, float f1, float r2, float f2, float r3, float f3) { +// float d12 = getShowerRadius(f, r1, f1, r2, f2); +// float d13 = getShowerRadius(f, r1, f1, r3, f3); +// float d23 = getShowerRadius(f, r2, f2, r3, f3); +// return (d12 + d13 + d23) / 3.f; +// } diff --git a/HGCSimTruth/HGCSimTruth/plugins/SimClusterTreeMerger.cc b/HGCSimTruth/HGCSimTruth/plugins/SimClusterTreeMerger.cc new file mode 100644 index 0000000000000..504ce553e0062 --- /dev/null +++ b/HGCSimTruth/HGCSimTruth/plugins/SimClusterTreeMerger.cc @@ -0,0 +1,1280 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using std::vector; +using std::map; +using std::unordered_map; +using std::pair; + +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/stream/EDProducer.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "DataFormats/Common/interface/Ref.h" + +#include "SimDataFormats/Track/interface/SimTrack.h" +#include "SimDataFormats/Vertex/interface/SimVertex.h" +#include "SimDataFormats/Track/interface/SimTrackContainer.h" +#include "SimDataFormats/Vertex/interface/SimVertexContainer.h" +#include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" +#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" + +#include "RecoLocalCalo/HGCalRecAlgos/interface/RecHitTools.h" + +#include "DataFormats/Common/interface/Ptr.h" +#include "DataFormats/Common/interface/View.h" +#include "SimDataFormats/CaloHit/interface/PCaloHitContainer.h" +#include "SimDataFormats/CaloHit/interface/PCaloHit.h" +#include "DataFormats/DetId/interface/DetId.h" + +#include "DataFormats/Common/interface/Association.h" +#include "DataFormats/Common/interface/AssociationMap.h" +#include "DataFormats/Common/interface/OneToManyWithQualityGeneric.h" + +#include // For std::forward_iterator_tag +#include // For std::ptrdiff_t + + +#define EDM_ML_DEBUG +#define PI 3.14159265358979323846 + +typedef edm::AssociationMap> SimClusterToSimClusters; + +/* +Yet another implementation of a 3D vector in CMSSW, but somehow +all the existing classes are missing needed functionality for the +merging algorithm. +*/ +struct Vector3D{ + Vector3D() {} + Vector3D(double x, double y, double z) : x_(x), y_(y), z_(z) {} + Vector3D(const GlobalPoint& p) : x_(p.x()), y_(p.y()), z_(p.z()) {} + Vector3D(const Vector3D& p) : x_(p.x_), y_(p.y_), z_(p.z_) {} + ~Vector3D() {} + Vector3D operator+(const Vector3D& other) const { return Vector3D(x_+other.x_, y_+other.y_, z_+other.z_); } + Vector3D operator-(const Vector3D& other) const { return Vector3D(x_-other.x_, y_-other.y_, z_-other.z_); } + Vector3D operator/(const double c){ return Vector3D(x_/c, y_/c, z_/c); } + + double norm(){ return std::sqrt(std::pow(x_,2) + std::pow(y_,2) + std::pow(z_,2)); } + double dot(const Vector3D& other){ return x_ * other.x_ + y_ * other.y_ + z_ * other.z_; } + + double x_, y_, z_; + friend std::ostream& operator<<(std::ostream& os, const Vector3D& v); + }; + +std::ostream& operator<<(std::ostream& os, const Vector3D& v){ + os << "(" << v.x_ << ", " << v.y_ << ", " << v.z_ << ")"; + return os; + } + +Vector3D operator*(const double c, const Vector3D& p){ return Vector3D(c*p.x_, c*p.y_, c*p.z_); } +vector operator+(const vector& ps, const Vector3D& q){ + vector out(ps.size()); + for (std::size_t i = 0; i < ps.size(); ++i){ + const Vector3D& p = ps[i]; + out[i] = p + q; + } + return out; + } +vector operator-(const vector& ps, const Vector3D& q){ + vector out(ps.size()); + for (std::size_t i = 0; i < ps.size(); ++i){ + const Vector3D& p = ps[i]; + out[i] = p - q; + } + return out; + } + +/* Needed for elementary 3D rotations */ +struct RotMat3D{ + RotMat3D() {} + ~RotMat3D() {} + RotMat3D( + double e11, double e12, double e13, + double e21, double e22, double e23, + double e31, double e32, double e33 + ) : + e11_(e11), e12_(e12), e13_(e13), + e21_(e21), e22_(e22), e23_(e23), + e31_(e31), e32_(e32), e33_(e33) + {} + + Vector3D dot(const Vector3D& p){ + return Vector3D( + e11_*p.x_ + e12_*p.y_ + e13_*p.z_, + e21_*p.x_ + e22_*p.y_ + e23_*p.z_, + e31_*p.x_ + e32_*p.y_ + e33_*p.z_ + ); + } + + vector dot(const vector& ps){ + vector out(ps.size()); + for (std::size_t i = 0; i < ps.size(); ++i){ + out[i] = dot(ps[i]); + } + return out; + } + + RotMat3D dot(const RotMat3D& o){ + return RotMat3D( + e11_*o.e11_ + e12_*o.e21_ + e13_*o.e31_, e11_*o.e12_ + e12_*o.e22_ + e13_*o.e32_, e11_*o.e13_ + e12_*o.e23_ + e13_*o.e33_, + e21_*o.e11_ + e22_*o.e21_ + e23_*o.e31_, e21_*o.e12_ + e22_*o.e22_ + e23_*o.e32_, e21_*o.e13_ + e22_*o.e23_ + e23_*o.e33_, + e31_*o.e11_ + e32_*o.e21_ + e33_*o.e31_, e31_*o.e12_ + e32_*o.e22_ + e33_*o.e32_, e31_*o.e13_ + e32_*o.e23_ + e33_*o.e33_ + ); + } + + RotMat3D transpose(){ + return RotMat3D( + e11_, e21_, e31_, + e12_, e22_, e32_, + e13_, e23_, e33_ + ); + } + + friend std::ostream& operator<<(std::ostream& os, const RotMat3D& m); + + double e11_, e12_, e13_, + e21_, e22_, e23_, + e31_, e32_, e33_; + }; + +std::ostream& operator<<(std::ostream& os, const RotMat3D& m){ + os << "[" << m.e11_ << ", " << m.e12_ << ", " << m.e13_ << "]\n" + << "[" << m.e21_ << ", " << m.e22_ << ", " << m.e23_ << "]\n" + << "[" << m.e31_ << ", " << m.e32_ << ", " << m.e33_ << "]"; + return os; + } + + +struct Hit { + Hit(double x, double y, double z, double t, double energy, int trackid) : + x_(x), y_(y), z_(z), t_(t), energy_(energy), trackid_(trackid) {} + ~Hit() {} + double x_; + double y_; + double z_; + double t_; + double energy_; + int trackid_; + GlobalPoint gpoint(){return GlobalPoint(x_, y_, z_);} + Vector3D vector3d(){return Vector3D(x_, y_, z_);} + }; + +/* Computes the 'average' position of a list of hits */ +Vector3D hitcentroid(vector& hits){ + if (hits.size()==0) cms::Exception("SimMerging") << "Cannot compute hit centroid for 0 hits"; + else if (hits.size()==1) return Vector3D(hits[0]->x_, hits[0]->y_, hits[0]->z_); + double summedEnergy = 0.; + for(auto hit : hits) summedEnergy += hit->energy_; + double center_x = 0., center_y = 0., center_z = 0.; + for(auto hit : hits){ + double weight = hit->energy_/summedEnergy; + center_x += weight * hit->x_; + center_y += weight * hit->y_; + center_z += weight * hit->z_; + } + return Vector3D(center_x, center_y, center_z); + } + +/* Cumulative sum of a vector */ +template +vector cumsum(const vector& input){ + T s = 0.; + vector cumulative_sum(input.size()); + for (std::size_t i = 0; i < input.size(); ++i) { + s += input[i]; + cumulative_sum[i] = s; + } + return cumulative_sum; + } + +/* +Returns a permutation of a sorted vector, which is applicable on another vector +See https://stackoverflow.com/a/17074810 +*/ +template +vector argsort( + const vector& vec, + Compare& compare) + { + vector p(vec.size()); + std::iota(p.begin(), p.end(), 0); + std::sort(p.begin(), p.end(), + [&](std::size_t i, std::size_t j){ return compare(vec[i], vec[j]); }); + return p; + } +/* Same but using a default "<" comparison */ +template +vector argsort(const vector& vec){ + vector p(vec.size()); + std::iota(p.begin(), p.end(), 0); + std::sort( + p.begin(), p.end(), + [&](std::size_t i, std::size_t j){ return vec[i] < vec[j]; } + ); + return p; + } +/* Function to apply the argsort returned from argsort(), returning a copy */ +template +std::vector apply_argsort( + const std::vector& vec, + const std::vector& p) +{ + std::vector sorted_vec(vec.size()); + std::transform(p.begin(), p.end(), sorted_vec.begin(), + [&](std::size_t i){ return vec[i]; }); + return sorted_vec; +} +/* Function to apply the argsort returned from argsort() in place */ +template +void apply_argsort_in_place( + std::vector& vec, + const std::vector& p) +{ + std::vector done(vec.size()); + for (std::size_t i = 0; i < vec.size(); ++i) + { + if (done[i]) + { + continue; + } + done[i] = true; + std::size_t prev_j = i; + std::size_t j = p[i]; + while (i != j) + { + std::swap(vec[prev_j], vec[j]); + done[j] = true; + prev_j = j; + j = p[j]; + } + } +} + +class Node { + public: + Node() : + trackid_(0), pdgid_(0), initial_energy_(0.), parent_(nullptr) + {} + Node(const SimTrack& track) { + trackid_ = track.trackId(); + initial_energy_ = track.momentum().E(); + pdgid_ = track.type(); + is_hadron_ = pdgid_ > 111; + final_z_ = track.trackerSurfacePosition().z(); + merged_trackids_.push_back(trackid_); + crossed_boundary_ = track.crossedBoundary(); + if (crossed_boundary_){ + boundary_momentum_ = track.getMomentumAtBoundary(); + boundary_position_ = Vector3D( + track.getPositionAtBoundary().x(), + track.getPositionAtBoundary().y(), + track.getPositionAtBoundary().z() + ); + } + } + ~Node() {} + + /* Number of quantities that depend on the hits */ + void calculate_shower_variables(){ + if (nhits() == 0) return; + centroid_ = ::hitcentroid(hits_); + axis_ = (centroid_-boundary_position_) / (centroid_-boundary_position_).norm(); + + // Compute the transverse distances from hits to the shower axis + vector d_to_axis; + vector d_along_axis; + vector energies; + double total_energy = 0.; + for(auto hit : hits_){ + Vector3D hit_pos = hit->vector3d() - boundary_position_; + Vector3D projection_along_axis = hit_pos.dot(axis_) * axis_; + d_along_axis.push_back(projection_along_axis.norm()); + d_to_axis.push_back((hit_pos - projection_along_axis).norm()); + energies.push_back(hit->energy_); + total_energy += hit->energy_; + } + + vector order = argsort(d_to_axis); + apply_argsort_in_place(d_to_axis, order); + vector cumsum_energies_to_axis = cumsum(apply_argsort(energies, order)); + + // Find the energy containment radii + vector thresholds = { .3, .75, .85 }; + for (std::size_t i = 0; i < cumsum_energies_to_axis.size()-1; ++i) { + double cumsum_this = cumsum_energies_to_axis[i] / total_energy; + double cumsum_next = cumsum_energies_to_axis[i+1] / total_energy; + for(auto threshold : thresholds){ + if (cumsum_next > threshold && cumsum_this < threshold) + // We just crossed a threshold, save the radius + energy_containment_radii_[threshold] = d_to_axis[i+1]; + } + } + + // Same thing, now longitudinally instead of transverse + order = argsort(d_along_axis); + apply_argsort_in_place(d_along_axis, order); + vector cumsum_energies_along_axis = cumsum(apply_argsort(energies, order)); + + thresholds = { .1, .9 }; + // Find the longitudinal energy containment quantiles + for (std::size_t i = 0; i < cumsum_energies_along_axis.size()-1; ++i) { + double cumsum_this = cumsum_energies_along_axis[i] / total_energy; + double cumsum_next = cumsum_energies_along_axis[i+1] / total_energy; + for(auto threshold : thresholds){ + if (cumsum_next > threshold && cumsum_this < threshold){ + // We just crossed a threshold, save the radius + energy_containment_longitudinally_[threshold] = d_along_axis[i+1]; + } + } + } + + // Build rotation matrix for this shower axis + // R.dot(v) will rotate v to a coordinate system where the z-axis + // is aligned with the z-axis of `axis` + // See https://en.wikipedia.org/wiki/Rotation_matrix#In_three_dimensions + double dx = atan2(axis_.y_, axis_.z_); + double dy = -asin(axis_.x_ / axis_.norm()); + rotation_ = RotMat3D( + cos(dy), 0., sin(dy), + 0., 1., 0., + -sin(dy), 0., cos(dy) + ) + .dot(RotMat3D( + 1., 0., 0., + 0., cos(dx), -sin(dx), + 0., sin(dx), cos(dx) + )); + + inv_rotation_ = rotation_.transpose(); + } + + /* Standard depth-first-search tree traversal as an iterator */ + struct Iterator { + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = Node; + using pointer = Node*; // or also value_type* + using reference = Node&; // or also value_type& + + Iterator(pointer ptr, bool verbose=false) : + m_ptr(ptr), root(ptr), depth_(0), verbose_(verbose) {} + + reference operator*() const { return *m_ptr; } + pointer operator->() { return m_ptr; } + + Iterator& operator++() { + if (m_ptr->hasChildren()){ + if (verbose_) edm::LogVerbatim("SimMerging") + << "Track " << m_ptr->trackid_ + << ": Going to first child " << m_ptr->children_[0]->trackid_ + ; + continuation_.push(m_ptr); + m_ptr = m_ptr->children_[0]; + depth_++; + } + else { + if (verbose_) edm::LogVerbatim("SimMerging") + << "Track " << m_ptr->trackid_ + << ": No children, going to next sibling" + ; + while(true){ + if (m_ptr == root){ + if (verbose_) edm::LogVerbatim("SimMerging") << "Back at the root of the iterator; quiting"; + m_ptr = nullptr; + break; + } + else if (m_ptr->hasNextSibling()){ + m_ptr = m_ptr->nextSibling(); + if (verbose_) edm::LogVerbatim("SimMerging") << "Has sibling; going to " << m_ptr->trackid_; + break; + } + if (verbose_) edm::LogVerbatim("SimMerging") << "Has no sibling; proceed popping stack"; + m_ptr = continuation_.top(); + continuation_.pop(); + depth_--; + if (verbose_) edm::LogVerbatim("SimMerging") << "Popped back to track " << m_ptr->trackid_; + } + } + return *this; + } + // Postfix increment + Iterator operator++(int) { Iterator tmp = *this; ++(*this); return tmp; } + const int depth(){return depth_;} + friend bool operator== (const Iterator& a, const Iterator& b) { return a.m_ptr == b.m_ptr; }; + friend bool operator!= (const Iterator& a, const Iterator& b) { return a.m_ptr != b.m_ptr; }; + private: + pointer m_ptr; + pointer root; + int depth_; + bool verbose_; + std::stack continuation_; + }; + Iterator begin(bool verbose=false) { return Iterator(this, verbose); } + Iterator end() { return Iterator(nullptr); } + + /* Traverses upwards */ + struct IteratorUp { + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = Node; + using pointer = Node*; // or also value_type* + using reference = Node&; // or also value_type& + IteratorUp(pointer ptr) : m_ptr(ptr) {} + reference operator*() const { return *m_ptr; } + pointer operator->() { return m_ptr; } + IteratorUp& operator++() { + m_ptr = (m_ptr->hasParent()) ? m_ptr->parent_ : nullptr ; + return *this; + } + IteratorUp operator++(int) { IteratorUp tmp = *this; ++(*this); return tmp; } + friend bool operator== (const IteratorUp& a, const IteratorUp& b) { return a.m_ptr == b.m_ptr; }; + friend bool operator!= (const IteratorUp& a, const IteratorUp& b) { return a.m_ptr != b.m_ptr; }; + private: pointer m_ptr; + }; + IteratorUp begin_up() { return IteratorUp(this); } + IteratorUp end_up() { return IteratorUp(nullptr); } + + void setParent(Node* parent) {parent_ = parent;} + void addChild(Node* child) {children_.push_back(child);} + void addHit(Hit* hit) {hits_.push_back(hit);} + int nhits(){ return hits_.size(); } + bool hasHits(){ return nhits() > 0; } + bool isLeaf(){ return children_.empty(); } + bool hasChildren(){ return !(children_.empty()); } + bool hasParent(){ return parent_ != nullptr; } + + bool hasNextSibling(){ + if (!parent_){ + // There is no parent + return false; + } + else if (parent_->children_.back() == this){ + // This was the last child + return false; + } + // else if ( (int)(parent_->children_.size()-1) == iChild_){ + // // This was the last child + // return false; + // } + return true; + } + + Node* nextSibling(){ + if (hasNextSibling()){ + vector::iterator sibling = std::find( + parent_->children_.begin(), parent_->children_.end(), this + ); + sibling++; // advance once + if (sibling == parent_->children_.end()) + // This shouldn't happen + return nullptr; + return *sibling; + } + return nullptr; + } + + /* Traverses tree and builds string representation */ + std::string stringrep(){ + std::stringstream ss; + int nTracks = 0; + int nHits = 0; + for (Node::Iterator it = begin(); it != end(); it++){ + Node& node = (*it); + for (int i = 0; i < it.depth(); ++i){ + ss << "--"; + } + ss + << "Track " << node.trackid_ + << " (" << node.nhits() << " hits)" + << "\n"; + nTracks++; + nHits += node.nhits(); + } + ss << "In total " << nTracks << " tracks with " << nHits << " hits"; + return ss.str(); + } + + /* A node is a 'leaf parent' if it has children, and all those children are leafs */ + bool isLeafParent(){ + // A leaf itself is not a leaf parent + if (isLeaf()) return false; + for(auto child : children_){ + if (child->hasChildren()) return false; + } + return true; + } + + /* + Flips all basic z quantities by -1 + Does not flip the shower properties; calculate_shower_variables must be rerun + */ + void flipz(){ + final_z_ *= -1.; + if(crossed_boundary_) boundary_position_.z_ *= -1.; + for(auto hit : hits_) hit->z_ *= -1.; + } + + bool crossed_boundary_, is_hadron_; + int trackid_, pdgid_; + double initial_energy_, final_z_; + math::XYZTLorentzVectorF boundary_momentum_; + + Vector3D centroid_, axis_, boundary_position_; + map energy_containment_radii_, energy_containment_longitudinally_; + RotMat3D rotation_, inv_rotation_; + + Node * parent_; + vector children_; + vector merged_trackids_; + vector hits_; + }; + +/* Finds a track by trackid in a tree */ +Node* find_in_tree(Node* root, int trackid){ + for(auto& track : *root){ + if (track.trackid_ == trackid){ + return &track; + } + } + throw cms::Exception("Unknown") + << "Track id " << trackid << " is not in the tree"; + } + +/* Returns a circle of Vector3D's in the xy plane */ +vector get_circle(double r, int N=30) { + vector circle(N); + for (int i = 0; i < N; ++i) { + double angle = 2.*PI * double(i)/double(N-1); + circle[i] = Vector3D(r*cos(angle), r*sin(angle), 0.); + } + return circle; + } + +/* +First rotates the 10% and 90% longitudinal energy quantile vectors +to the reference frame of the most energetic shower (should be t1) +Then calculates delta z between the end point of the first and +the beginning of the second track: + +b1------e1 + b2----------e2 + -----> + + +b1------e1 + b2----------e2 + <---- + + +b1-----------------e1 + b2-----e2 + <--------------- +*/ +double longitudinal_distance(Node& t1, Node& t2){ + // Vectors of the 10% and 90% longitudinal energy quantiles + Vector3D v1_10 = t1.boundary_position_ + t1.energy_containment_longitudinally_[.1] * t1.axis_; + Vector3D v1_90 = t1.boundary_position_ + t1.energy_containment_longitudinally_[.9] * t1.axis_; + Vector3D v2_10 = t2.boundary_position_ + t2.energy_containment_longitudinally_[.1] * t2.axis_; + Vector3D v2_90 = t2.boundary_position_ + t2.energy_containment_longitudinally_[.9] * t2.axis_; + // Rotate them + Vector3D origin = t1.boundary_position_; + Vector3D rb1 = t1.rotation_.dot(v1_10 - origin); + Vector3D re1 = t1.rotation_.dot(v1_90 - origin); + Vector3D rb2 = t1.rotation_.dot(v2_10 - origin); + Vector3D re2 = t1.rotation_.dot(v2_90 - origin); + // Fix 1 to be the lowest in z after rotating + if (rb2.z_ < rb1.z_){ std::swap(rb1, rb2); std::swap(re1, re2); } + return rb2.z_ - re1.z_; + } + +/* +Winding number calculation to determine if a point is inside a 2D polygon +(https://en.wikipedia.org/wiki/Nonzero-rule) +point: (x, y) +polygon: [ (x1, y1), ..., (xn, yn) ] +*/ +bool is_inside(const vector& px, const vector& py, double x, double y){ + int winding_number = 0; + int n_edges = px.size(); + for (int i_edge = 0; i_edge < n_edges; ++i_edge){ + int i_edge_next = (i_edge+1) % n_edges; // Loop back for last edge + double x1 = px[i_edge], x2 = px[i_edge_next], y1 = py[i_edge], y2 = py[i_edge_next]; + // Skip any edges completely to the left of x + if (x1 < x && x2 < x) continue; + // Skip any edges that don't cross the line at y=y + if ((y1 < y && y2 < y) || (y1 > y && y2 > y)) continue; + if (x1==x2){ + // Vertical edge - no need to calculate crossing point, slope is also infinite + if (x1>x) winding_number++; + } + else { + // Edges that cross the line y=y and are not vertical; + // need to calculate crossing point + if ( (y - y1) / ((y2-y1)/(x2-x1)) + x1 > x ) winding_number++; + } + } + return winding_number % 2 == 1; // false if even (out), and true if odd (in) + } + +/* Evaluates the overlap of two 2D polygons numerically */ +double polygon_overlap( + const vector& x1, const vector& y1, + const vector& x2, const vector& y2, + int nbins=50 + ){ + // First determine extrema + auto x1_minmax = std::minmax_element(x1.begin(), x1.end()); + auto x2_minmax = std::minmax_element(x2.begin(), x2.end()); + double xmin = std::min(*(x1_minmax.first), *(x2_minmax.first)); + double xmax = std::max(*(x1_minmax.second), *(x2_minmax.second)); + auto y1_minmax = std::minmax_element(y1.begin(), y1.end()); + auto y2_minmax = std::minmax_element(y2.begin(), y2.end()); + double ymin = std::min(*(y1_minmax.first), *(y2_minmax.first)); + double ymax = std::max(*(y1_minmax.second), *(y2_minmax.second)); + double x_binwidth = (xmax-xmin) / double(nbins); + double y_binwidth = (ymax-ymin) / double(nbins); + + // Count how many cells in a grid are inside polygon 2 and in both polygons + int is_inside_2 = 0, is_inside_1_and_2 = 0; + for (int i = 0; i < nbins; ++i){ + for (int j = 0; j < nbins; ++j){ + double x = xmin + i*x_binwidth + .5*x_binwidth; + double y = ymin + j*y_binwidth + .5*y_binwidth; + if (is_inside(x2, y2, x, y)){ + is_inside_2++; + if (is_inside(x1, y1, x, y)) is_inside_1_and_2++; + } + } + } + if (is_inside_1_and_2 == 0) return 0.; + return double(is_inside_1_and_2) / double(is_inside_2); + } +/* Reimplementation of function above with different input */ +double polygon_overlap(vector& polygon1, vector& polygon2, int nbins=30){ + // Convert to vector; Would have been better to not have a copy here, + // but the other algos get hard to write then + std::size_t n(polygon1.size()); + vector polygon1_x(n), polygon1_y(n), polygon2_x(n), polygon2_y(n); + for (std::size_t i=0; i calculate_shower_overlap(Node& t1, Node& t2){ + if (t1.boundary_momentum_.E() < t2.boundary_momentum_.E()) std::swap(t1,t2); + double f_radius; + if(t1.is_hadron_ != t2.is_hadron_) f_radius = .3; + else if (t1.is_hadron_ && t2.is_hadron_) f_radius = .75; + else f_radius = .85; + double t1_r = std::max(t1.energy_containment_radii_[f_radius], 1.0); + double t2_r = std::max(t2.energy_containment_radii_[f_radius], 1.0); + + Vector3D t1_b = t1.boundary_position_; + Vector3D t1_e = t1.centroid_; + Vector3D t2_b = t2.boundary_position_; + Vector3D t2_e = t2.centroid_; + + Vector3D t1_re = t1.rotation_.dot(t1_e-t1_b); + // Vector3D t2_rb = t1.rotation_.dot(t2_b-t1_b); + // Vector3D t2_re = t1.rotation_.dot(t2_e-t1_b); + + vector t1_rcircle = t1.inv_rotation_.dot(get_circle(t1_r)) + t1_re; + vector t2_rcircle = t1.rotation_.dot( + t2.inv_rotation_.dot(get_circle(t2_r)) + t2_e - t1_b + ); + double rcircle_overlap = polygon_overlap(t1_rcircle, t2_rcircle); + double deltaz = longitudinal_distance(t1, t2); + return std::make_pair(rcircle_overlap, deltaz); + } + + +class CachedOverlapFn { + public: + CachedOverlapFn() {} + ~CachedOverlapFn() {} + + pair get(Node* t1, Node* t2){ + if (t1->boundary_momentum_.E() < t2->boundary_momentum_.E()) std::swap(t1,t2); + pair p = std::make_pair(t1->trackid_, t2->trackid_); + if (cache_.count(p) == 0) + cache_[p] = calculate_shower_overlap(*t1, *t2); + return cache_[p]; + } + + /* Clears the cache for two tracks in one go */ + void clear(Node* t1, Node* t2){ + auto it = cache_.begin(); + while(it != cache_.end()){ + auto key = (*it).first; + if ( + key.first == t1->trackid_ || key.second == t1->trackid_ || + key.first == t2->trackid_ || key.second == t2->trackid_ + ) + it = cache_.erase(it); + else + it++; + } + } + + void insert(int i, int j, double a, double b){ + cache_[std::make_pair(i,j)] = std::make_pair(a,b); + } + + std::string print() const { + std::stringstream ss; + for(auto it: cache_){ + ss << "(" << it.first.first << "," << it.first.second << ") = " + << it.second.first << ", " << it.second.second << "\n" + ; + } + return ss.str(); + } + + private: + map, pair> cache_; + }; + + + +/* Remove a node from its parent's children vector */ +void break_from_parent(Node* node){ + if (!(node->hasParent())) cms::Exception("SimMerging") << "Cannot remove root node"; + vector& parents_children = node->parent_->children_; + // erase-remove idiom: https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom#Example + parents_children.erase( + std::remove(parents_children.begin(), parents_children.end(), node), + parents_children.end() + ); + } + +/* Breaks node from parent but moves its children to the children of the parent */ +void remove_intermediate_node(Node* node){ + Node* parent = node->parent_; + break_from_parent(node); + // Move children of the now-removed node to its parent + for (auto child : node->children_){ + parent->addChild(child); + child->setParent(parent); + } + } + +// _______________________________________________ +// Some functions for traversal by recursion +// These first build the whole traversal in a vector +// (as pointers, so memory usage is not too bad) + +/* Does depth first search traversal by using recursion, but not as an iterator */ +void _dfs_recursion( + Node* node, + vector>& returnable, + int depth + ) + { + returnable.push_back(std::make_pair(node, depth)); + for (auto child : node->children_){ + _dfs_recursion(child, returnable, depth+1); + } + } + +/* +Wrapper around the recursive version that only takes a node as input. +Returns a vector of pair. +Useful if you want to keep the whole traversal in memory; usually you +will want to use the iterator version of the Node class. +*/ +vector> dfs(Node* root){ + vector> returnable; + _dfs_recursion(root, returnable, 0); + return returnable; + } + +/* String representation of dfs traversal (keeps whole traversal in memory) */ +std::string dfs_stringrep(Node* root){ + std::stringstream ss; + for (auto node_depth_pair : dfs(root)){ + for (int i = 0; i < node_depth_pair.second; ++i){ + ss << "--"; + } + ss + << "Track " << node_depth_pair.first->trackid_ + << " (" << node_depth_pair.first->nhits() << " hits)" + << "\n"; + } + return ss.str(); + } + +/* Remove single-child no-hit tracks (i.e. intermediate tracks) */ +void trim_tree(Node* root){ + // Traverse once and note all tracks that should be kept: + // Either a track that has hits, or an ancestor thereof + std::set trackids_with_hits_or_parents_thereof; + for (auto& node : *root){ + if (!(node.hasHits())) continue; + // Iterate upwards and save in the set + for (auto it=node.begin_up(); it!=node.end_up(); it++){ + trackids_with_hits_or_parents_thereof.insert(it->trackid_); + } + } + // Now remove all nodes not in the set + // We'll be modifying parent-child relationships mid-loop, so we have to be a little + // careful + auto it=root->begin(); + while(it!=root->end()){ + Node& node = (*it); + if (!(trackids_with_hits_or_parents_thereof.count(node.trackid_))){ + // First remove children so the iterator will go to the next sibling + node.children_.clear(); + // Advance to next sibling (or further up the chain) + it++; + // Then break from parent (if doing this before advancing the order gets messed up) + break_from_parent(&node); + } + else{ + it++; + } + } + // Second trimming step: Remove 'intermediate' tracks + // (i.e. tracks with no hits, 1 child, and 1 parent) + // In this case it's easier to put the whole traversal in memory first, + // and avoid modifying relationships mid-loop + for (auto node_depth_pair : dfs(root)){ + Node* node = node_depth_pair.first; + if (node->hasParent() && (node->children_.size()==1) && !(node->hasHits())){ + remove_intermediate_node(node); + } + } + } + + +/* Compute a distance measure between two nodes: now simply distance between the hit centroids */ +double distance(Node* left, Node* right){ + Vector3D p1 = left->centroid_, p2 = right->centroid_; + return std::sqrt( + std::pow(p1.x_-p2.x_,2) + std::pow(p1.y_-p2.y_,2) + std::pow(p1.z_-p2.z_,2) + ); + } + +bool merge_leafparent(Node* leafparent, double min_overlap, CachedOverlapFn& overlapfn){ + edm::LogVerbatim("SimMerging") << " Merging leafparent " << leafparent->trackid_; + bool didUpdate = false; + // Copy list of potentially mergeable nodes + vector mergeable = leafparent->children_; + leafparent->children_.clear(); + // Parent itself can be mergeable, if it has hits and is not a root + if (leafparent->hasParent() && leafparent->hasHits()) mergeable.push_back(leafparent); + // Start merging + while(true){ + bool break_early = false; + bool didUpdateThisIteration = false; + double current_max_overlap = min_overlap; + pair pairToMerge; + // Compute all distances between clusters + int nMergeable = mergeable.size(); + for (int i = 0; i < nMergeable; ++i){ + Node* left = mergeable[i]; + for (int j = i+1; j < nMergeable; ++j){ + Node* right = mergeable[j]; + pair p = overlapfn.get(left, right); + double overlap = p.first; + double deltaz = p.second; + if (overlap > current_max_overlap && deltaz < 10.){ + current_max_overlap = overlap; + pairToMerge = (left->initial_energy_ > right->initial_energy_) ? + std::make_pair(left, right) : std::make_pair(right, left); + didUpdate = true; + didUpdateThisIteration = true; + if (overlap == 1.){ + // It can't get higher than 1 anyway + break_early = true; + break; + } + } + // double r = distance(left, right); + // if (r < minr){ + // minr = r; + // pairToMerge = (left->initial_energy_ > right->initial_energy_) ? + // std::make_pair(left, right) : std::make_pair(right, left); + // didUpdate = true; + // didUpdateThisIteration = true; + // } + } + if (break_early) break; + } + if (!didUpdateThisIteration) break; // Nothing to merge this iteration + // Now do the merging + edm::LogVerbatim("SimMerging") + << " Merging " << pairToMerge.second->trackid_ + << " into " << pairToMerge.first->trackid_ + ; + // Bookkeep that the track (and any previously merged tracks) is merged in + for (auto trackid : pairToMerge.second->merged_trackids_){ + pairToMerge.first->merged_trackids_.push_back(trackid); + } + // Move children + for(auto child : pairToMerge.second->children_){ + pairToMerge.first->addChild(child); + child->setParent(pairToMerge.first); + } + pairToMerge.second->children_.clear(); + // Move hits + for(auto hit : pairToMerge.second->hits_) pairToMerge.first->addHit(hit); + pairToMerge.second->hits_.clear(); + // Delete the merged-away node + break_from_parent(pairToMerge.second); + mergeable.erase( + std::remove(mergeable.begin(), mergeable.end(), pairToMerge.second), + mergeable.end() + ); + // Recompute the shower variables for newly merged node, now that it has more hits + pairToMerge.first->calculate_shower_variables(); + overlapfn.clear(pairToMerge.first, pairToMerge.second); + } + // Make a string representation of the mergeable nodes for debugging + std::string mergeableStr = ""; + if(mergeable.size()){ + std::stringstream ss; + for(auto child : mergeable) ss << child->trackid_ << ", "; + mergeableStr = ss.str(); + mergeableStr.pop_back(); mergeableStr.pop_back(); // Remove trailing comma + } + // All possible merging now done; + // Next steps depend on whether the passed node was a root + if (!(leafparent->hasParent())){ + leafparent->children_ = mergeable; + if(didUpdate) { + // Simply overwrite with the merged nodes + edm::LogVerbatim("SimMerging") + << " Root " << leafparent->trackid_ + << " is set to have the following children: " + << mergeableStr; + } + else{ + edm::LogVerbatim("SimMerging") + << " Root " << leafparent->trackid_ + << ": no further merging possible"; + } + return didUpdate; + } + else { + // Special case: If the leafparent had no hits (and was thus not included as + // a mergeable node), AND all nodes were merged into one cluster, assign the + // pdgid of the leafparent to the remaining node + if( + !(leafparent->hasHits()) + && mergeable.size()==1 + && mergeable[0]->pdgid_!=leafparent->pdgid_ + ){ + edm::LogVerbatim("SimMerging") + << " Using leafparent pdgid " << leafparent->pdgid_ + << " for track " << mergeable[0]->trackid_ + << " (rather than " << mergeable[0]->pdgid_ + << ") since all nodes were merged into one"; + mergeable[0]->pdgid_ = leafparent->pdgid_; + } + // Replace the node in the parent's children list with all merged nodes + Node* parent = leafparent->parent_; + edm::LogVerbatim("SimMerging") + << " Adding the following children to parent " << parent->trackid_ + << ": " << mergeableStr; + break_from_parent(leafparent); + for(auto child : mergeable){ + parent->addChild(child); + child->setParent(parent); + } + return true; + } + } + +void merging_algo(Node* root){ + CachedOverlapFn overlapfn; + int iIteration = -1; + bool didUpdate = true; + while(didUpdate){ + iIteration++; + edm::LogVerbatim("SimMerging") << "Iteration " << iIteration; + // Build list of leaf parents in memory + vector leafparents; + for (auto& node : *root){ + if (!(node.isLeafParent())) continue; + leafparents.push_back(&node); + } + for (auto node : leafparents){ + didUpdate = merge_leafparent(node, .3, overlapfn); + } + } + edm::LogVerbatim("SimMerging") << "Done after iteration " << iIteration; + } + +// _______________________________________________ + + +class simmerger : public edm::stream::EDProducer<> { + public: + explicit simmerger(const edm::ParameterSet&); + ~simmerger() {} + SimCluster mergedSimClusterFromTrackIds(std::vector& trackIds, + const edm::Association& simTrackToSimCluster); + private: + virtual void produce(edm::Event&, const edm::EventSetup&) override; + void beginRun(const edm::Run&, const edm::EventSetup&) override {} + hgcal::RecHitTools hgcalRecHitToolInstance_ ; + edm::EDGetTokenT> hgcalEEHitsToken_; + edm::EDGetTokenT> hgcalHEfrontHitsToken_; + edm::EDGetTokenT> hgcalHEbackHitsToken_; + edm::EDGetTokenT tokenSimTracks; + edm::EDGetTokenT tokenSimVertices; + edm::EDGetTokenT simClustersToken_; + edm::EDGetTokenT> simTrackToSimClusterToken_; + unordered_map trackIdToTrackRef_; + }; + + +simmerger::simmerger(const edm::ParameterSet& iConfig) : + hgcalEEHitsToken_(consumes>(edm::InputTag("g4SimHits", "HGCHitsEE"))), + hgcalHEfrontHitsToken_(consumes>(edm::InputTag("g4SimHits", "HGCHitsHEfront"))), + hgcalHEbackHitsToken_(consumes>(edm::InputTag("g4SimHits", "HGCHitsHEback"))), + tokenSimTracks(consumes(edm::InputTag("g4SimHits"))), + tokenSimVertices(consumes(edm::InputTag("g4SimHits"))), + simClustersToken_(consumes(edm::InputTag("mix:MergedCaloTruth"))), + simTrackToSimClusterToken_(consumes>(edm::InputTag("mix:simTrackToSimCluster"))) + { + produces(); + produces>(); + produces(); + } + +SimCluster simmerger::mergedSimClusterFromTrackIds(std::vector& trackIds, + const edm::Association& simTrackToSimCluster) { + SimCluster sc; + for (auto tid : trackIds) { + if (trackIdToTrackRef_.find(tid) == trackIdToTrackRef_.end()) + throw cms::Exception("SimClusterTreeMerger") << "Failed to find a trackId in the TrackMap."; + sc += *simTrackToSimCluster[trackIdToTrackRef_[tid]]; + } + return sc; +} + +void simmerger::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { + edm::ESHandle geom; + iSetup.get().get(geom); + hgcalRecHitToolInstance_.setGeometry(*geom); + trackIdToTrackRef_.clear(); + + auto output = std::make_unique(); + + // Create Hit instances + vector hits; + vector>> tokens = { + hgcalEEHitsToken_, + hgcalHEfrontHitsToken_, + hgcalHEbackHitsToken_ + }; + std::set trackids_with_hits; + for (edm::EDGetTokenT> token : tokens ) { + edm::Handle< edm::View > handle; + iEvent.getByToken(token, handle); + for (auto const & hit : handle->ptrs() ) { + DetId id = hit->id(); + GlobalPoint position = hgcalRecHitToolInstance_.getPosition(id); + hits.push_back(Hit( + position.x(), position.y(), position.z(), + hit->time(), hit->energy(), hit->geantTrackId() + )); + trackids_with_hits.insert(hit->geantTrackId()); + } + } + + // Build the tree + edm::Handle handleSimTracks; + iEvent.getByLabel("g4SimHits", handleSimTracks); + edm::Handle handleSimVertices; + iEvent.getByLabel("g4SimHits", handleSimVertices); + + edm::LogVerbatim("SimMerging") << "Building map"; + unordered_map trackid_to_node; + for(size_t i = 0; i < handleSimTracks->size(); i++){ + SimTrackRef track(handleSimTracks, i); + trackid_to_node.emplace(track->trackId(), Node(*track)); + trackIdToTrackRef_[track->trackId()] = track; + } + + edm::LogVerbatim("SimMerging") << "Adding hits to nodes"; + for (auto& hit : hits){ + trackid_to_node[hit.trackid_].addHit(&hit); + } + + edm::LogVerbatim("SimMerging") << "Building tree"; + Node* root(new Node()); + for(const auto& track : *handleSimTracks){ + int trackid = track.trackId(); + Node* node = &(trackid_to_node[trackid]); + // Have to get parent info via the SimVertex + SimVertex vertex = handleSimVertices.product()->at(track.vertIndex()); + bool hasParent = !(vertex.noParent()); + // Build the tree + if (hasParent){ + int parentid = vertex.parentIndex(); + edm::LogVerbatim("SimMerging") + << "Setting parent->child relationship: " + << parentid << " -> " << trackid + ; + auto it = trackid_to_node.find(parentid); + if (it != trackid_to_node.end()){ + Node* parent = &(it->second); + node->setParent(parent); + parent->addChild(node); + } + else{ + throw cms::Exception("Unknown") + << "Track id " << parentid + << " is not in the map" + ; + } + } + else{ + edm::LogVerbatim("SimMerging") << "Found parentless particle: " << node->trackid_; + root->addChild(node); + node->setParent(root); + } + } + +#ifdef EDM_ML_DEBUG + edm::LogVerbatim("SimMerging") << "Printing root " << root->trackid_; + edm::LogVerbatim("SimMerging") << root->stringrep() << "\n"; + edm::LogVerbatim("SimMerging") << "Trimming tree..."; +#endif + + trim_tree(root); + +#ifdef EDM_ML_DEBUG + edm::LogVerbatim("SimMerging") << "Printing root " << root->trackid_ << " after trimming"; + edm::LogVerbatim("SimMerging") << root->stringrep() << "\n"; +#endif + +#ifdef EDM_ML_DEBUG + edm::LogVerbatim("SimMerging") << "Splitting into positive and negative endcap"; +#endif + Node* pos(new Node()); + Node* neg(new Node()); + for(auto child: root->children_){ + if(child->final_z_ < 0.){ + child->setParent(neg); + neg->addChild(child); + } + else{ + child->setParent(pos); + pos->addChild(child); + } + } + +#ifdef EDM_ML_DEBUG + edm::LogVerbatim("SimMerging") << "Flipping all z's in negative endcap for merging algorithm"; +#endif + for (auto& node : *neg){ + node.flipz(); + node.calculate_shower_variables(); + } + + // Testing code for development + // Node* t1 = find_in_tree(neg, 411358); + // Node* t2 = find_in_tree(neg, 419854); + // edm::LogVerbatim("SimMerging") << "Found track " << t1->trackid_; + // edm::LogVerbatim("SimMerging") << "Found track " << t2->trackid_; + // t1->calculate_shower_variables(); + // t2->calculate_shower_variables(); + + // CachedOverlapFn overlapfn; + // overlapfn.get(t1, t2);; + // pair overlap = calculate_shower_overlap(*t1, *t2); + // edm::LogVerbatim("SimMerging") + // << "Overlap: " << overlap.first + // << ", dz: " << overlap.second + // ; + +#ifdef EDM_ML_DEBUG + edm::LogVerbatim("SimMerging") << "Running merging algo..."; +#endif + merging_algo(neg); + +#ifdef EDM_ML_DEBUG + edm::LogVerbatim("SimMerging") << "Printing neg " << neg->trackid_ << " after merging_algo"; + edm::LogVerbatim("SimMerging") << neg->stringrep() << "\n"; +#endif + + for (auto& node : *pos) node.calculate_shower_variables(); + merging_algo(pos); + + // Fill the output; the clusters are the remaining nodes (except the root) + edm::Handle> simTrackToSimClusterHandle; + iEvent.getByToken(simTrackToSimClusterToken_, simTrackToSimClusterHandle); + + edm::Handle simClusterHandle; + iEvent.getByToken(simClustersToken_, simClusterHandle); + + auto allChildren = pos->children_; + allChildren.insert(allChildren.begin(), neg->children_.begin(), neg->children_.end()); + + size_t i = 0; + std::vector mergedIndices(simClusterHandle->size(), 0); + std::vector> groups; + for(auto cluster : allChildren) { + SimCluster sc; + std::vector group; + for (auto tid : cluster->merged_trackids_) { + if (trackIdToTrackRef_.find(tid) == trackIdToTrackRef_.end()) + throw cms::Exception("SimClusterTreeMerger") << "Failed to find a trackId in the TrackMap."; + const auto& unmerged = (*simTrackToSimClusterHandle)[trackIdToTrackRef_[tid]]; + mergedIndices.at(unmerged.key()) = i; + sc += *unmerged; + group.push_back(unmerged); + } + std::sort(std::begin(group), std::end(group), + [](SimClusterRef a, SimClusterRef b) { return a->impactMomentum().energy() > b->impactMomentum().energy(); }); + i++; + sc.setPdgId(cluster->pdgid_); + output->push_back(sc); + groups.push_back(group); + } + + const auto& mergedSCHandle = iEvent.put(std::move(output)); + + auto assocMap = std::make_unique(mergedSCHandle, simClusterHandle); + + for (size_t i = 0; i < groups.size(); i++) { + SimClusterRef msc(mergedSCHandle, i); + float mergedE = msc->impactMomentum().energy(); + for (auto sc : groups.at(i)) { + float scE = sc->impactMomentum().energy(); + assocMap->insert(msc, std::make_pair(sc, mergedE/scE)); + } + } + iEvent.put(std::move(assocMap)); + + auto assoc = std::make_unique>(mergedSCHandle); + edm::Association::Filler filler(*assoc); + filler.insert(simClusterHandle, mergedIndices.begin(), mergedIndices.end()); + filler.fill(); + iEvent.put(std::move(assoc)); + + delete root; + delete pos; + delete neg; + } + +DEFINE_FWK_MODULE(simmerger); diff --git a/HGCSimTruth/HGCSimTruth/plugins/TrackingParticleSimClusterAssociationProducer.cc b/HGCSimTruth/HGCSimTruth/plugins/TrackingParticleSimClusterAssociationProducer.cc new file mode 100644 index 0000000000000..79edbcc78a9f7 --- /dev/null +++ b/HGCSimTruth/HGCSimTruth/plugins/TrackingParticleSimClusterAssociationProducer.cc @@ -0,0 +1,102 @@ +// system include files +#include +#include + +// user include files +#include "FWCore/Framework/interface/global/EDProducer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/Framework/interface/ESHandle.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" + +#include "SimDataFormats/Associations/interface/TrackToTrackingParticleAssociator.h" + +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "SimDataFormats/TrackingAnalysis/interface/TrackingParticle.h" +#include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" +#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" + +#include "FWCore/Utilities/interface/EDGetToken.h" +#include + +// +// class decleration +// + +typedef edm::AssociationMap> TrackingParticleToSimCluster; + +class TrackingParticleSimClusterAssociationProducer : public edm::global::EDProducer<> { +public: + explicit TrackingParticleSimClusterAssociationProducer(const edm::ParameterSet &); + ~TrackingParticleSimClusterAssociationProducer() override; + +private: + void produce(edm::StreamID, edm::Event &, const edm::EventSetup &) const override; + std::set findTrackingParticleMatch( + std::unordered_map& trackIdToTPRef, SimClusterRef scRef) const; + + edm::EDGetTokenT tpCollectionToken_; + edm::EDGetTokenT scCollectionToken_; +}; + +TrackingParticleSimClusterAssociationProducer::TrackingParticleSimClusterAssociationProducer(const edm::ParameterSet &pset) + : tpCollectionToken_(consumes(pset.getParameter("trackingParticles"))), + scCollectionToken_(consumes(pset.getParameter("simClusters"))) +{ + produces(); +} + +TrackingParticleSimClusterAssociationProducer::~TrackingParticleSimClusterAssociationProducer() {} + +// +// member functions +// + +std::set TrackingParticleSimClusterAssociationProducer::findTrackingParticleMatch( + std::unordered_map& trackIdToTPRef, SimClusterRef scRef) const { + std::set trackingParticles; + for (auto& track : scRef->g4Tracks()) { + unsigned int trackId = track.trackId(); + if (trackIdToTPRef.find(trackId) != trackIdToTPRef.end()) + trackingParticles.insert(trackIdToTPRef[trackId]); + } + return trackingParticles; +} + +// ------------ method called to produce the data ------------ +void TrackingParticleSimClusterAssociationProducer::produce(edm::StreamID, edm::Event &iEvent, const edm::EventSetup &iSetup) const { + + edm::Handle tpCollection; + iEvent.getByToken(tpCollectionToken_, tpCollection); + + edm::Handle scCollection; + iEvent.getByToken(scCollectionToken_, scCollection); + + auto out = std::make_unique(tpCollection, scCollection); + std::unordered_map trackIdToTPRef; + + for (size_t i = 0; i < tpCollection->size(); i++) { + TrackingParticleRef trackingParticle(tpCollection, i); + for (auto& track : trackingParticle->g4Tracks()) { + unsigned int trackId = track.trackId(); + trackIdToTPRef[trackId] = trackingParticle; + } + } + + // NOTE: not every trackingparticle will be in the association. + // could add empty SCs in this case, but that might be worse... + for (size_t i = 0; i < scCollection->size(); i++) { + SimClusterRef simclus(scCollection, i); + for (auto tp : findTrackingParticleMatch(trackIdToTPRef, simclus)) + out->insert(tp, simclus); + } + + iEvent.put(std::move(out)); +} + +// define this as a plug-in +DEFINE_FWK_MODULE(TrackingParticleSimClusterAssociationProducer); diff --git a/HGCSimTruth/HGCSimTruth/src/SimClusterTools.cpp b/HGCSimTruth/HGCSimTruth/src/SimClusterTools.cpp new file mode 100644 index 0000000000000..800b796522c97 --- /dev/null +++ b/HGCSimTruth/HGCSimTruth/src/SimClusterTools.cpp @@ -0,0 +1,121 @@ +/* + * SimClusterTools.cpp + * + * Created on: 16 Dec 2019 + * Author: jkiesele + */ + +#include "../interface/SimClusterTools.h" +#include "DataFormats/DetId/interface/DetId.h" +#include "DataFormats/ForwardDetId/interface/ForwardSubdetector.h" + +#include "DataFormats/ForwardDetId/interface/HGCalDetId.h" +#include "DataFormats/ForwardDetId/interface/HGCScintillatorDetId.h" +#include "DataFormats/ForwardDetId/interface/HGCSiliconDetId.h" +#include "DataFormats/HcalDetId/interface/HcalDetId.h" +#include "Geometry/HGCalGeometry/interface/HGCalGeometry.h" +#include "Geometry/HcalTowerAlgo/interface/HcalGeometry.h" +#include "Geometry/CaloGeometry/interface/CaloGeometry.h" + +#include + +void SimClusterTools::recalculatePosition(SimCluster& cluster, const double& assigned_time) const { + if (!recHitTools_) { + throw cms::Exception("recHitTools not set"); + } + + int layer = 4000; + double lowestz = 4000.; + double center_eta = 0, center_rphi = 0; + double energysum = 0; + for (const auto& hitsAndFractions : cluster.hits_and_fractions()) { + auto detid = hitsAndFractions.first; + int thislayer = recHitTools_->getLayer(detid); + auto rhpos = recHitTools_->getPosition(detid); + double thisz = fabs(rhpos.z()); + if (lowestz > thisz) { + lowestz = thisz; + } + if (thislayer < layer) + layer = thislayer; + + double energy = hitsAndFractions.second; + if (energy == 0 || energy != energy || std::isinf(energy)) + energy = 1e-4; + if (allrechits_) { + auto mapit = detid_to_rh_index_->find(detid); + if (mapit == detid_to_rh_index_->end()) + continue; + energy = allrechits_->at(mapit->second)->energy() * hitsAndFractions.second; + } + energysum += energy; + center_eta += rhpos.eta() * energy; + center_rphi += reco::deltaPhi(rhpos.phi(), cluster.impactPoint().phi()) * energy; + } + if (energysum) { + center_eta /= energysum; + center_rphi /= energysum; + center_rphi += cluster.impactPoint().phi(); + center_rphi = reco::reduceRange(center_rphi); + } + + //std::cout << "lowest layer " << layer << std::endl; + //assign position to first layer hit + math::XYZVectorF thispos(0, 0, 0); + int nhits = 0; + double layeren = 0; + //these are still energies in the accumulation step + for (const auto& hitsAndEnergies : cluster.hits_and_fractions()) { + auto detid = hitsAndEnergies.first; + + int thislayer = recHitTools_->getLayer(detid); + float thisz = fabs(recHitTools_->getPosition(detid).z()); + if (fabs(thisz - lowestz) < 0.3) { //thislayer == layer){ + + double energy = hitsAndEnergies.second; + auto ipos = recHitTools_->getPosition(detid).basicVector(); + //use rechit energies here + if (allrechits_) { + auto mapit = detid_to_rh_index_->find(detid); + if (mapit == detid_to_rh_index_->end()) + continue; + energy = allrechits_->at(mapit->second)->energy() * hitsAndEnergies.second; + } + //don't consider strays + if (reco::deltaR(center_eta, center_rphi, ipos.eta(), ipos.phi()) > considerhitdistance_) + continue; + if (energy == 0 || energy != energy || std::isinf(energy)) + energy = 1e-4; + layeren += energy; + //std::cout << "thislayer " << thislayer << " "<< ipos << " energy "<< energy<>(thispos.x(), thispos.y(), thispos.z(), assigned_time)); + + //std::cout << "new pos: " << cluster.impactPoint() << std::endl; +} + +bool SimClusterTools::isHGCal(const SimCluster& cluster)const{ + + for (const auto& hitsAndEnergies : cluster.hits_and_fractions()) { + const DetId id = hitsAndEnergies.first; + bool forward = id.det() == DetId::HGCalEE + || id.det() == DetId::HGCalHSi + || id.det() == DetId::HGCalHSc + || (id.det() == DetId::Forward && id.subdetId() != static_cast(HFNose)) + || (id.det() == DetId::Hcal && id.subdetId() == HcalSubdetector::HcalEndcap); + + if(forward) + return true; + } + return false; +} + + + + + diff --git a/HGCSimTruth/HGCSimTruth/test/digi.py b/HGCSimTruth/HGCSimTruth/test/digi.py new file mode 100644 index 0000000000000..1930787406abb --- /dev/null +++ b/HGCSimTruth/HGCSimTruth/test/digi.py @@ -0,0 +1,198 @@ +# coding: utf-8 + +""" +Event digitization for evaluating the realistic HGCal truth accumulation. +The config is based on workflows 20634.0 (ttbar with 200 pu) and 20434.0 (ttbar without pu). + +200 pu: +> runTheMatrix.py -w upgrade -l 20634.0 --command="--no_exec" --dryRun +> cmsDriver.py digi \ + --conditions auto:phase2_realistic_T14 \ + --era Phase2C8_timing_layer_bar \ + --geometry Extended2026D41 \ + --datatier GEN-SIM-DIGI \ + --eventcontent FEVTDEBUGHLT \ + -s DIGI:pdigi_valid \ + -n 10 \ + --pileup_input das:/RelValMinBias_14TeV/CMSSW_10_6_0_patch2-106X_upgrade2023_realistic_v3_2023D41noPU-v1/GEN-SIM \ + --pileup AVE_200_BX_25ns \ + --no_exec + +No pu: +(same as above without the two pileup arguments) +> runTheMatrix.py -w upgrade -l 20634.0 --command="--no_exec" --dryRun +> cmsDriver.py digi \ + --conditions auto:phase2_realistic_T14 \ + --era Phase2C8_timing_layer_bar \ + --geometry Extended2026D41 \ + --datatier GEN-SIM-DIGI \ + --eventcontent FEVTDEBUGHLT \ + -s DIGI:pdigi_valid \ + -n 10 \ + --no_exec +""" + +import os + +import FWCore.ParameterSet.Config as cms +from FWCore.ParameterSet.VarParsing import VarParsing + + +# helpers +def strip_prefix(path): + return path.split(":", 1)[-1] + + +def ensure_prefix(path, prefix="file"): + if ":" not in path: + path = "{}:{}".format(prefix.rstrip(":"), path) + return path + + +# option parsing +options = VarParsing("python") +options.setDefault("inputFiles", [""]) +options.setDefault("outputFile", "") +options.setDefault("maxEvents", 10) +options.register("pu", 0, VarParsing.multiplicity.singleton, VarParsing.varType.int, "pileup") +options.parseArguments() + +# file prefixes +input_file = ensure_prefix(options.inputFiles[0]) +output_file = options.__getattr__("outputFile", noTags=True) +if output_file: + output_file = ensure_prefix(output_file) + +# default output file +if not output_file: + basename = os.path.splitext(strip_prefix(input_file).split("_", 1)[-1])[0] + output_file = ensure_prefix("digi_{}_pu{}.root".format(basename, options.pu)) + +# create the process +from Configuration.Eras.Era_Phase2C8_timing_layer_bar_cff import Phase2C8_timing_layer_bar +process = cms.Process("DIGI", Phase2C8_timing_layer_bar) + +# pileup mixing +mixing_cfi = "mix_POISSON_average_cfi" if options.pu > 0 else "mixNoPU_cfi" + +# import of standard configurations +process.load("Configuration.StandardSequences.Services_cff") +process.load("SimGeneral.HepPDTESSource.pythiapdt_cfi") +process.load("FWCore.MessageService.MessageLogger_cfi") +process.load("Configuration.EventContent.EventContent_cff") +process.load("SimGeneral.MixingModule.{}".format(mixing_cfi)) +process.load("Configuration.Geometry.GeometryExtended2026D41Reco_cff") +process.load("Configuration.StandardSequences.MagneticField_cff") +process.load("Configuration.StandardSequences.Digi_cff") +process.load("Configuration.StandardSequences.EndOfProcess_cff") +process.load("Configuration.StandardSequences.FrontierConditions_GlobalTag_cff") + +# process options +process.options = cms.untracked.PSet( + FailPath=cms.untracked.vstring(), + IgnoreCompletely=cms.untracked.vstring(), + Rethrow=cms.untracked.vstring(), + SkipEvent=cms.untracked.vstring(), + allowUnscheduled=cms.obsolete.untracked.bool, + canDeleteEarly=cms.untracked.vstring(), + emptyRunLumiMode=cms.obsolete.untracked.string, + eventSetup=cms.untracked.PSet( + forceNumberOfConcurrentIOVs=cms.untracked.PSet(), + numberOfConcurrentIOVs=cms.untracked.uint32(1), + ), + fileMode=cms.untracked.string("FULLMERGE"), + forceEventSetupCacheClearOnNewRun=cms.untracked.bool(False), + makeTriggerResults=cms.obsolete.untracked.bool, + numberOfConcurrentLuminosityBlocks=cms.untracked.uint32(1), + numberOfConcurrentRuns=cms.untracked.uint32(1), + numberOfStreams=cms.untracked.uint32(0), + numberOfThreads=cms.untracked.uint32(1), + printDependencies=cms.untracked.bool(False), + sizeOfStackForThreadsInKB=cms.optional.untracked.uint32, + throwIfIllegalParameter=cms.untracked.bool(True), + wantSummary=cms.untracked.bool(False), +) + +# set the number of events to process +process.maxEvents = cms.untracked.PSet( + input=cms.untracked.int32(options.maxEvents), + output=cms.optional.untracked.allowed(cms.int32, cms.PSet), +) + +# global tag +from Configuration.AlCa.GlobalTag import GlobalTag +process.GlobalTag = GlobalTag(process.GlobalTag, "auto:phase2_realistic_T14", "") + +# input source +print("input file : {}".format(input_file)) +process.source = cms.Source("PoolSource", + dropDescendantsOfDroppedBranches=cms.untracked.bool(False), + fileNames=cms.untracked.vstring(input_file), + inputCommands=cms.untracked.vstring( + "keep *", + "drop *_genParticles_*_*", + "drop *_genParticlesForJets_*_*", + "drop *_kt4GenJets_*_*", + "drop *_kt6GenJets_*_*", + "drop *_iterativeCone5GenJets_*_*", + "drop *_ak4GenJets_*_*", + "drop *_ak7GenJets_*_*", + "drop *_ak8GenJets_*_*", + "drop *_ak4GenJetsNoNu_*_*", + "drop *_ak8GenJetsNoNu_*_*", + "drop *_genCandidatesForMET_*_*", + "drop *_genParticlesForMETAllVisible_*_*", + "drop *_genMetCalo_*_*", + "drop *_genMetCaloAndNonPrompt_*_*", + "drop *_genMetTrue_*_*", + "drop *_genMetIC5GenJs_*_*", + ), + secondaryFileNames=cms.untracked.vstring(), +) + +# configure the pu mixing +if options.pu > 0: + process.mix.input.nbPileupEvents.averageNumber = cms.double(options.pu) + process.mix.bunchspace = cms.int32(25) + process.mix.minBunch = cms.int32(-12) + process.mix.maxBunch = cms.int32(3) + # process.mix.input.fileNames = cms.untracked.vstring(["/store/relval/CMSSW_10_6_0_patch2/RelValMinBias_14TeV/GEN-SIM/106X_upgrade2023_realistic_v3_2023D41noPU-v1/10000/F7FE3FE9-565B-544A-855E-902BA4E3C5FD.root', '/store/relval/CMSSW_10_6_0_patch2/RelValMinBias_14TeV/GEN-SIM/106X_upgrade2023_realistic_v3_2023D41noPU-v1/10000/82584FBA-A1E6-DF48-99BA-B1759C3A190F.root', '/store/relval/CMSSW_10_6_0_patch2/RelValMinBias_14TeV/GEN-SIM/106X_upgrade2023_realistic_v3_2023D41noPU-v1/10000/F806295A-492F-EF4F-9D91-15DA8769DD72.root', '/store/relval/CMSSW_10_6_0_patch2/RelValMinBias_14TeV/GEN-SIM/106X_upgrade2023_realistic_v3_2023D41noPU-v1/10000/6FCA2E1D-D1E2-514B-8ABA-5B71A2C1E1B3.root', '/store/relval/CMSSW_10_6_0_patch2/RelValMinBias_14TeV/GEN-SIM/106X_upgrade2023_realistic_v3_2023D41noPU-v1/10000/287275CC-953A-0C4C-B352-E39EC2D571F0.root', '/store/relval/CMSSW_10_6_0_patch2/RelValMinBias_14TeV/GEN-SIM/106X_upgrade2023_realistic_v3_2023D41noPU-v1/10000/657065A5-F35B-3147-AED9-E4ACA915C982.root', '/store/relval/CMSSW_10_6_0_patch2/RelValMinBias_14TeV/GEN-SIM/106X_upgrade2023_realistic_v3_2023D41noPU-v1/10000/2C56BC73-5687-674C-8684-6C785A88DB78.root', '/store/relval/CMSSW_10_6_0_patch2/RelValMinBias_14TeV/GEN-SIM/106X_upgrade2023_realistic_v3_2023D41noPU-v1/10000/B96F4064-156C-5E47-90A0-07475310157A.root', '/store/relval/CMSSW_10_6_0_patch2/RelValMinBias_14TeV/GEN-SIM/106X_upgrade2023_realistic_v3_2023D41noPU-v1/10000/2564B36D-A0DB-6C42-9105-B1CFF44F311D.root', '/store/relval/CMSSW_10_6_0_patch2/RelValMinBias_14TeV/GEN-SIM/106X_upgrade2023_realistic_v3_2023D41noPU-v1/10000/2CB8C960-47C0-1A40-A9F7-0B62987097E0.root"]) # noqa: E501 + local_pu_dir = "/eos/user/m/mrieger/data/hgc/RelvalMinBias14" + process.mix.input.fileNames = cms.untracked.vstring([ + "file://" + os.pathl.abspath(os.path.join(local_pu_dir, elem)) + for elem in os.path.listdir(local_pu_dir) + if elem.endswith(".root") + ]) +process.mix.digitizers = cms.PSet(process.theDigitizersValid) + +# output definition +print("output file: {}".format(output_file)) +process.FEVTDEBUGHLToutput = cms.OutputModule("PoolOutputModule", + dataset=cms.untracked.PSet( + dataTier=cms.untracked.string("GEN-SIM-DIGI"), + filterName=cms.untracked.string(""), + ), + fileName=cms.untracked.string(output_file), + outputCommands=process.FEVTDEBUGHLTEventContent.outputCommands, + splitLevel=cms.untracked.int32(0), +) + +# Path and EndPath definitions +process.digitisation_step = cms.Path(process.pdigi_valid) +process.endjob_step = cms.EndPath(process.endOfProcess) +process.FEVTDEBUGHLToutput_step = cms.EndPath(process.FEVTDEBUGHLToutput) + +# schedule definition +process.schedule = cms.Schedule( + process.digitisation_step, + process.endjob_step, + process.FEVTDEBUGHLToutput_step, +) + +# add pat algos +from PhysicsTools.PatAlgos.tools.helpers import associatePatAlgosToolsTask +associatePatAlgosToolsTask(process) + +# early deletion of intermediate products +from Configuration.StandardSequences.earlyDeleteSettings_cff import customiseEarlyDelete +process = customiseEarlyDelete(process) diff --git a/HGCSimTruth/HGCSimTruth/test/gen_sim.py b/HGCSimTruth/HGCSimTruth/test/gen_sim.py new file mode 100644 index 0000000000000..10deedcfefd68 --- /dev/null +++ b/HGCSimTruth/HGCSimTruth/test/gen_sim.py @@ -0,0 +1,256 @@ +# coding: utf-8 + +""" +Event generation and simulation for evaluating the realistic HGCal truth accumulation. +The config is based on workflow 20634.0 (ttbar). + +> runTheMatrix.py -w upgrade -l 20634.0 --command="--no_exec" --dryRun +> cmsDriver.py gen_sim \ + --conditions auto:phase2_realistic_T14 \ + --era Phase2C8_timing_layer_bar \ + --geometry Extended2026D41 \ + --beamspot HLLHC14TeV \ + --datatier GEN-SIM \ + --eventcontent FEVTDEBUG \ + -s GEN,SIM \ + -n 10 \ + --no_exec +""" + +import math + +import FWCore.ParameterSet.Config as cms +from FWCore.ParameterSet.VarParsing import VarParsing + + +# helpers +def strip_prefix(path): + return path.split(":", 1)[-1] + + +def ensure_prefix(path, prefix="file", empty=True): + if ":" not in path: + path = "{}:{}".format(prefix.rstrip(":"), path) + return path + + +def calculate_rho(z, eta): + return z * math.tan(2 * math.atan(math.exp(-eta))) + + +# option parsing +options = VarParsing("python") +options.setDefault("outputFile", "") +options.setDefault("maxEvents", 10) +options.register("content", "pythia_ttbar", VarParsing.multiplicity.singleton, + VarParsing.varType.string, "event content") +options.parseArguments() + +# file prefixes +output_file = options.__getattr__("outputFile", noTags=True) +if output_file: + output_file = ensure_prefix(output_file) + +# create the process +from Configuration.Eras.Era_Phase2C8_timing_layer_bar_cff import Phase2C8_timing_layer_bar +process = cms.Process("SIM", Phase2C8_timing_layer_bar) + +# import of standard configurations +process.load("Configuration.StandardSequences.Services_cff") +process.load("SimGeneral.HepPDTESSource.pythiapdt_cfi") +process.load("FWCore.MessageService.MessageLogger_cfi") +process.load("Configuration.EventContent.EventContent_cff") +process.load("SimGeneral.MixingModule.mixNoPU_cfi") +process.load("Configuration.Geometry.GeometryExtended2026D41Reco_cff") +process.load("Configuration.Geometry.GeometryExtended2026D41_cff") +process.load("Configuration.StandardSequences.MagneticField_cff") +process.load("Configuration.StandardSequences.Generator_cff") +process.load("IOMC.EventVertexGenerators.VtxSmearedHLLHC14TeV_cfi") +process.load("GeneratorInterface.Core.genFilterSummary_cff") +process.load("Configuration.StandardSequences.SimIdeal_cff") +process.load("Configuration.StandardSequences.EndOfProcess_cff") +process.load("Configuration.StandardSequences.FrontierConditions_GlobalTag_cff") + +# process options +process.options = cms.untracked.PSet( + FailPath=cms.untracked.vstring(), + IgnoreCompletely=cms.untracked.vstring(), + Rethrow=cms.untracked.vstring(), + SkipEvent=cms.untracked.vstring(), + allowUnscheduled=cms.obsolete.untracked.bool, + canDeleteEarly=cms.untracked.vstring(), + emptyRunLumiMode=cms.obsolete.untracked.string, + eventSetup=cms.untracked.PSet( + forceNumberOfConcurrentIOVs=cms.untracked.PSet(), + numberOfConcurrentIOVs=cms.untracked.uint32(1) + ), + fileMode=cms.untracked.string("FULLMERGE"), + forceEventSetupCacheClearOnNewRun=cms.untracked.bool(False), + makeTriggerResults=cms.obsolete.untracked.bool, + numberOfConcurrentLuminosityBlocks=cms.untracked.uint32(1), + numberOfConcurrentRuns=cms.untracked.uint32(1), + numberOfStreams=cms.untracked.uint32(0), + numberOfThreads=cms.untracked.uint32(1), + printDependencies=cms.untracked.bool(False), + sizeOfStackForThreadsInKB=cms.optional.untracked.uint32, + throwIfIllegalParameter=cms.untracked.bool(True), + wantSummary=cms.untracked.bool(False), +) + +# set the number of events to generate +process.maxEvents = cms.untracked.PSet( + input=cms.untracked.int32(options.maxEvents), + output=cms.optional.untracked.allowed(cms.int32, cms.PSet), +) + +# global tag +from Configuration.AlCa.GlobalTag import GlobalTag +process.GlobalTag = GlobalTag(process.GlobalTag, "auto:phase2_realistic_T14", "") + +# trigger conditions +process.genstepfilter.triggerConditions = cms.vstring("generation_step") + +# we have no source +process.source = cms.Source("EmptySource") + +# define the generator and, when empty, create an output file name +if options.content == "pythia_ttbar": + process.generator = cms.EDFilter("Pythia8GeneratorFilter", + PythiaParameters=cms.PSet( + parameterSets=cms.vstring( + "pythia8CommonSettings", + "pythia8CUEP8M1Settings", + "processParameters", + ), + processParameters=cms.vstring( + "Top:gg2ttbar = on ", + "Top:qqbar2ttbar = on ", + "6:m0 = 175", + ), + pythia8CUEP8M1Settings=cms.vstring( + "Tune:pp 14", + "Tune:ee 7", + "MultipartonInteractions:pT0Ref = 2.4024", + "MultipartonInteractions:ecmPow = 0.25208", + "MultipartonInteractions:expPow = 1.6", + ), + pythia8CommonSettings=cms.vstring( + "Tune:preferLHAPDF = 2", + "Main:timesAllowErrors = 10000", + "Check:epTolErr = 0.01", + "Beams:setProductionScalesFromLHEF = off", + "SLHA:keepSM = on", + "SLHA:minMassSM = 1000.", + "ParticleDecays:limitTau0 = on", + "ParticleDecays:tau0Max = 10", + "ParticleDecays:allowPhotonRadiation = on", + ), + ), + comEnergy=cms.double(14000.0), + filterEfficiency=cms.untracked.double(1.0), + maxEventsToPrint=cms.untracked.int32(0), + pythiaHepMCVerbosity=cms.untracked.bool(False), + pythiaPylistVerbosity=cms.untracked.int32(0), + ) + output_file = output_file or "gensim_pythia_ttbar_n{}.root".format(options.maxEvents) + output_file = ensure_prefix(output_file) + +elif options.content.startswith("gun_"): + # interpret the event content string + opts = options.content.split("_")[1:] + + # get the particle name and ids + particle_name = opts[0] + particle_ids = { + "e": [11, -11], + "mu": [13, -13], + "g": [22], + "glu": [21], + "pi0": [111], + "pic": [211, -211], + } + if particle_name not in particle_ids: + raise ValueError("unknown particle to shoot: {}".format(particle_name)) + + # get energy and z ranges + e_range = opts[1:3] if len(opts) >= 3 else ("50", "50") + z_range = opts[3:5] if len(opts) >= 5 else ("0", "0") + + # define the generator + process.generator = cms.EDProducer("CloseByFlatDeltaRGunProducer", + # particle ids + particleIDs=cms.vint32(*particle_ids[particle_name]), + # max number of particles to shoot at a time + nParticles=cms.int32(1), + # shoot exactly the particles defined in particleIDs in that order + exactShoot=cms.bool(False), + # randomly shoot [1, nParticles] particles, each time randomly drawn from particleIDs + randomShoot=cms.bool(False), + # energy range + eMin=cms.double(float(e_range[0])), + eMax=cms.double(float(e_range[1])), + # phi range + phiMin=cms.double(-math.pi), + phiMax=cms.double(math.pi), + # eta range + etaMin=cms.double(1.52), + etaMax=cms.double(3.00), + # longitudinal gun position in cm + zMin=cms.double(float(z_range[0])), + zMax=cms.double(float(z_range[1])), + # deltaR settings + deltaRMin=cms.double(0.), + deltaRMax=cms.double(0.), + # debug flag + debug=cms.untracked.bool(True), + ) + output_file = output_file or "gensim_gun_{}_e{}To{}_z{}To{}_n{}.root".format(particle_name, + e_range[0], e_range[1], z_range[0], z_range[1], options.maxEvents) + output_file = ensure_prefix(output_file) + +else: + raise ValueError("unknown 'content' value: {}".format(options.content)) +process.ProductionFilterSequence = cms.Sequence(process.generator) + +# output definition +print("output file: {}".format(output_file)) +process.FEVTDEBUGoutput = cms.OutputModule("PoolOutputModule", + SelectEvents=cms.untracked.PSet( + SelectEvents=cms.vstring("generation_step"), + ), + dataset=cms.untracked.PSet( + dataTier=cms.untracked.string("GEN-SIM"), + filterName=cms.untracked.string("") + ), + fileName=cms.untracked.string(output_file), + outputCommands=process.FEVTDEBUGEventContent.outputCommands, + splitLevel=cms.untracked.int32(0), +) + +# Path and EndPath definitions +process.generation_step = cms.Path(process.pgen) +process.simulation_step = cms.Path(process.psim) +process.genfiltersummary_step = cms.EndPath(process.genFilterSummary) +process.endjob_step = cms.EndPath(process.endOfProcess) +process.FEVTDEBUGoutput_step = cms.EndPath(process.FEVTDEBUGoutput) + +# schedule definition +process.schedule = cms.Schedule( + process.generation_step, + process.genfiltersummary_step, + process.simulation_step, + process.endjob_step, + process.FEVTDEBUGoutput_step, +) + +# add pat algos +from PhysicsTools.PatAlgos.tools.helpers import associatePatAlgosToolsTask +associatePatAlgosToolsTask(process) + +# filter all path with the production filter sequence +for path in process.paths: + getattr(process, path).insert(0, process.ProductionFilterSequence) + +# early deletion of intermediate products +from Configuration.StandardSequences.earlyDeleteSettings_cff import customiseEarlyDelete +process = customiseEarlyDelete(process) diff --git a/HGCSimTruth/HGCSimTruth/test/plots.py b/HGCSimTruth/HGCSimTruth/test/plots.py new file mode 100644 index 0000000000000..55d205e954ed4 --- /dev/null +++ b/HGCSimTruth/HGCSimTruth/test/plots.py @@ -0,0 +1,237 @@ +# coding: utf-8 + +""" +Plots for evaluating the realistic HGCal truth accumulation. +""" + +import os +import math +from array import array + +import six + +import plotlib.root as r +import ROOT + + +colors = { + 0: ROOT.kWhite, + 22: ROOT.kRed, + 11: ROOT.kOrange, + 13: ROOT.kBlue, +} + + +def pdgid_to_color(pdg_id): + return colors.get(abs(pdg_id), colors[0]) + + +def p4_in_hgcal(p4): + return 1.52 <= abs(p4.eta()) < 3.00 + + +def fwlite_loop(path, handle_data=None, start=0, end=-1, object_type="Event"): + """ + Opens one or more ROOT files defined by *path* and yields the FWLite event. When *handle_data* + is not *None*, it is supposed to be a dictionary ``key -> {"type": ..., "label": ...}``. In that + case, the handle products are yielded as well in a dictionary, mapped to the key, as + ``(event, objects dict)``. + """ + import ROOT + ROOT.PyConfig.IgnoreCommandLineOptions = True + ROOT.gROOT.SetBatch() + ROOT.gSystem.Load("libFWCoreFWLite.so") + ROOT.gSystem.Load("libDataFormatsFWLite.so") + ROOT.FWLiteEnabler.enable() + from DataFormats.FWLite import Events, Runs, Handle # noqa: F401 + + paths = path if isinstance(path, (list, tuple)) else [path] + + handles = {} + if handle_data: + for key, data in handle_data.items(): + handles[key] = Handle(data["type"]) + + objects = locals()[object_type + "s"](paths) + for i, obj in enumerate(objects): + if i < start: + continue + if i >= end: + break + + if handle_data: + products = {} + for key, data in handle_data.items(): + obj.getByLabel(data["label"], handles[key]) + products[key] = handles[key].product() + yield obj, products + else: + yield obj + + +def plot_radii(input_file, output_file=""): + if not output_file: + postfix = os.path.splitext(os.path.basename(input_file))[0].split("_", 1)[-1] + output_file = "radii_{}.png".format(postfix) + + r.setup_style() + canvas, (pad,) = r.routines.create_canvas() + pad.cd() + + binning = (51, -0.02, 2.02) + hist = ROOT.TH1F("hist", ";SimCluster radius (#eta - #phi);# Normalized entries", *binning) + + # fill data + handles = { + "radii": {"type": "vector", "label": "mix:RealisticCaloTruth:HLT"}, + } + for event, objects in fwlite_loop(input_file, handles, end=1): + radii = objects["radii"] + for radius in radii: + hist.Fill(radius) + + n_cluster = int(hist.Integral()) + hist.Scale(1. / n_cluster) + + r.setup_hist(hist, pad=pad) + r.tools.set_color(hist, 2, "lm") + + hist.Draw("hist") + + label = r.routines.create_top_right_label("{} SimClusters".format(n_cluster), + h_offset=0.04, v_offset=0.07) + label.Draw() + + r.update_canvas(canvas) + canvas.SaveAs(output_file) + + +def plot_clusters(input_file, output_file="", description="", event=0): + if not output_file: + postfix = os.path.splitext(os.path.basename(input_file))[0].split("_", 1)[-1] + output_file = "clusters_{}_evt{}.png".format(postfix, event) + + r.setup_style() + canvas, (pad,) = r.routines.create_canvas() + pad.cd() + + # dummy histogram for axes + binning = (1, -5., 5., 1, -3.2, 5.) + dummy_hist = ROOT.TH2F("hist", ";#eta;#phi;", *binning) + + # coordinates of calo particles + cp_points = [] + + # fill data + handles = { + "radii": { + "type": "vector", + "label": "mix:RealisticCaloTruth:DIGI", + }, + "sim_clusters": { + "type": "vector", + "label": "mix:MergedCaloTruth:DIGI", + }, + "calo_particles": { + "type": "vector", + "label": "mix:MergedCaloTruth:DIGI", + }, + "shower_vectors": { + "type": "vector", + "label": "mix:RealisticCaloTruth:DIGI", + }, + "merged_clusters": { + "type": "vector", + "label": "mix:RealisticCaloTruth:DIGI", + }, + } + ellipses = [] + for event, objects in fwlite_loop(input_file, handles, start=event, end=event + 1): + radii = objects["radii"] + sim_clusters = objects["sim_clusters"] + calo_particles = objects["calo_particles"] + shower_vectors = objects["shower_vectors"] + merged_clusters = objects["merged_clusters"] + + det_ids = set() + n_sim_clusters = 0 + for radius, sim_cluster, shower_vector in six.moves.zip(radii, sim_clusters, shower_vectors): + if not p4_in_hgcal(sim_cluster.p4()): + continue + + det_ids |= set(hf.first for hf in sim_cluster.hits_and_fractions()) + n_sim_clusters += 1 + + # if abs(p4.eta()) + radius < 5 and abs(p4.phi()) + radius < 3.2: + # if len(sim_cluster.hits_and_fractions()) >= 200: + # if sim_cluster.p4().E() > 0.8: + if 1: + print sim_cluster.p4().E(), shower_vector.E(), shower_vector.Eta(), shower_vector.Phi() + # radius = 0.1 * (math.log(sim_cluster.p4().E()) + 1) + ellipse = ROOT.TEllipse(shower_vector.Eta(), shower_vector.Phi(), radius, radius) + r.setup_ellipse(ellipse, {"FillColor": pdgid_to_color(sim_cluster.pdgId())}) + ellipses.append(ellipse) + + for calo_particle in calo_particles: + cp_points.append((calo_particle.eta(), calo_particle.phi())) + + # counts for some statistics + n_rec_hits = len(det_ids) + n_calo_particles = sum(1 for cp in calo_particles if p4_in_hgcal(cp.p4())) + n_merged_clusters = len(merged_clusters) + + r.setup_hist(dummy_hist, pad=pad) + dummy_hist.Draw() + + for ellipse in sorted(ellipses, key=lambda e: -e.GetR1()): + ellipse.Draw() + + cp_graph = ROOT.TGraph(len(cp_points), array("f", [p[0] for p in cp_points]), + array("f", [p[1] for p in cp_points])) + r.setup_graph(cp_graph, {"MarkerStyle": 43, "MarkerSize": 2}) + cp_graph.Draw("P") + + # stats labels + def create_stat_label(i, j, text): + v = 0.07 + i * 0.04 + h = 0.4 + j * 0.23 + return r.routines.create_top_left_label(text, h_offset=h, v_offset=v) + + create_stat_label(0, 0, "{} RecHits".format(n_rec_hits)).Draw() + create_stat_label(0, 1, "{} CaloParticles".format(n_calo_particles)).Draw() + create_stat_label(1, 0, "{} SimClusters".format(n_sim_clusters)).Draw() + create_stat_label(1, 1, "{} Merged SCs".format(n_merged_clusters)).Draw() + + # geometry and energy label + r.routines.create_top_right_label("14 TeV (2026D41)", v_offset=-0.005).Draw() + + # cms label + for l in r.routines.create_cms_labels(postfix="Simulation"): + l.Draw() + + # optional description + if description: + if not isinstance(description, list): + description = [description] + for i, desc in enumerate(description): + r.routines.create_top_left_label(desc, h_offset=0.03, v_offset=0.07 + i * 0.04).Draw() + + # box hiding the phi labels larger than 3 + box = ROOT.TBox(-5.5, 3.5, -5.05, 5.2) + r.setup_box(box, color="white") + box.Draw() + + r.update_canvas(canvas) + canvas.SaveAs(output_file) + + +if __name__ == "__main__": + # plot_radii("digi_gun_e_e50To50_z0To0_n1_pu200.root") + # plot_clusters("digi_gun_e_e50To50_z0To0_n1_pu200.root", + # description="Electron gun, 50 GeV, 200 PU") + for i in range(5): + plot_clusters("digi_gun_e_e30To30_z0To0_n5_pu0.root", + description="Electron gun, 30 GeV, 0 PU", event=i) + # for i in range(3): + # plot_clusters("digi_gun_g_e30To30_z0To0_n5_pu0.root", + # description="Photon gun, 30 GeV, 0 PU", event=i) diff --git a/HGCSimTruth/HGCSimTruth/test/reco.py b/HGCSimTruth/HGCSimTruth/test/reco.py new file mode 100644 index 0000000000000..01689f81e9dd8 --- /dev/null +++ b/HGCSimTruth/HGCSimTruth/test/reco.py @@ -0,0 +1,160 @@ +# coding: utf-8 + +""" +Event reconstruction for evaluating the realistic HGCal truth accumulation. +The config is based on workflow 20634.0 (ttbar). + +> runTheMatrix.py -w upgrade -l 20634.0 --command="--no_exec" --dryRun +> cmsDriver.py reco \ + --conditions auto:phase2_realistic_T14 \ + --era Phase2C8_timing_layer_bar \ + --geometry Extended2026D41 \ + --datatier GEN-SIM-RECO \ + --eventcontent FEVTDEBUGHLT \ + -s RAW2DIGI,L1Reco,RECO,RECOSIM \ + -n 10 \ + --runUnscheduled \ + --no_exec +""" + +import os + +import FWCore.ParameterSet.Config as cms +from FWCore.ParameterSet.VarParsing import VarParsing + + +# helpers +def strip_prefix(path): + return path.split(":", 1)[-1] + + +def ensure_prefix(path, prefix="file", empty=True): + if ":" not in path: + path = "{}:{}".format(prefix.rstrip(":"), path) + return path + + +# option parsing +options = VarParsing("python") +options.setDefault("inputFiles", [""]) +options.setDefault("outputFile", "") +options.setDefault("maxEvents", 10) +options.parseArguments() + +# file prefixes +input_file = ensure_prefix(options.inputFiles[0]) +output_file = options.__getattr__("outputFile", noTags=True) +if output_file: + output_file = ensure_prefix(output_file) + +# default output file +if not output_file: + basename = os.path.splitext(strip_prefix(input_file).split("_", 1)[-1])[0] + output_file = ensure_prefix("reco_{}.root".format(basename)) + +# create the process +from Configuration.Eras.Era_Phase2C8_timing_layer_bar_cff import Phase2C8_timing_layer_bar +process = cms.Process("RECO", Phase2C8_timing_layer_bar) + +# import of standard configurations +process.load("Configuration.StandardSequences.Services_cff") +process.load("SimGeneral.HepPDTESSource.pythiapdt_cfi") +process.load("FWCore.MessageService.MessageLogger_cfi") +process.load("Configuration.EventContent.EventContent_cff") +process.load("Configuration.Geometry.GeometryExtended2026D41Reco_cff") +process.load("Configuration.StandardSequences.MagneticField_cff") +process.load("Configuration.StandardSequences.RawToDigi_cff") +process.load("Configuration.StandardSequences.L1Reco_cff") +process.load("Configuration.StandardSequences.Reconstruction_cff") +process.load("Configuration.StandardSequences.RecoSim_cff") +process.load("Configuration.StandardSequences.EndOfProcess_cff") +process.load("Configuration.StandardSequences.FrontierConditions_GlobalTag_cff") + +# process options +process.options = cms.untracked.PSet( + FailPath=cms.untracked.vstring(), + IgnoreCompletely=cms.untracked.vstring(), + Rethrow=cms.untracked.vstring(), + SkipEvent=cms.untracked.vstring(), + allowUnscheduled=cms.obsolete.untracked.bool, + canDeleteEarly=cms.untracked.vstring(), + emptyRunLumiMode=cms.obsolete.untracked.string, + eventSetup=cms.untracked.PSet( + forceNumberOfConcurrentIOVs=cms.untracked.PSet(), + numberOfConcurrentIOVs=cms.untracked.uint32(1) + ), + fileMode=cms.untracked.string("FULLMERGE"), + forceEventSetupCacheClearOnNewRun=cms.untracked.bool(False), + makeTriggerResults=cms.obsolete.untracked.bool, + numberOfConcurrentLuminosityBlocks=cms.untracked.uint32(1), + numberOfConcurrentRuns=cms.untracked.uint32(1), + numberOfStreams=cms.untracked.uint32(0), + numberOfThreads=cms.untracked.uint32(1), + printDependencies=cms.untracked.bool(False), + sizeOfStackForThreadsInKB=cms.optional.untracked.uint32, + throwIfIllegalParameter=cms.untracked.bool(True), + wantSummary=cms.untracked.bool(False), +) + +# set the number of events to process +process.maxEvents = cms.untracked.PSet( + input=cms.untracked.int32(options.maxEvents), + output=cms.optional.untracked.allowed(cms.int32, cms.PSet), +) + +# global tag +from Configuration.AlCa.GlobalTag import GlobalTag +process.GlobalTag = GlobalTag(process.GlobalTag, "auto:phase2_realistic_T14", "") + +# input source +process.source = cms.Source("PoolSource", + fileNames=cms.untracked.vstring(input_file), + secondaryFileNames=cms.untracked.vstring(), +) + +# HGCSimTruth +process.hgcSimTruth = cms.EDProducer("HGCSimTruth", +) + +# output definition +print("output file: {}".format(output_file)) +process.FEVTDEBUGHLToutput = cms.OutputModule("PoolOutputModule", + dataset=cms.untracked.PSet( + dataTier=cms.untracked.string("GEN-SIM-DIGI-RECO"), + filterName=cms.untracked.string(""), + ), + fileName=cms.untracked.string(output_file), + outputCommands=process.FEVTDEBUGHLTEventContent.outputCommands, + splitLevel=cms.untracked.int32(0), +) + +# Path and EndPath definitions +process.raw2digi_step = cms.Path(process.RawToDigi) +process.L1Reco_step = cms.Path(process.L1Reco) +process.reconstruction_step = cms.Path(process.reconstruction) +process.recosim_step = cms.Path(process.recosim) +process.endjob_step = cms.EndPath(process.endOfProcess) +process.FEVTDEBUGHLToutput_step = cms.EndPath(process.FEVTDEBUGHLToutput) + +# schedule definition +process.schedule = cms.Schedule( + process.raw2digi_step, + process.L1Reco_step, + process.reconstruction_step, + process.recosim_step, + process.hgcSimTruth, + process.endjob_step, + process.FEVTDEBUGHLToutput_step, +) + +# add pat algos +from PhysicsTools.PatAlgos.tools.helpers import associatePatAlgosToolsTask +associatePatAlgosToolsTask(process) + +# ensure modules run unscheduled +from FWCore.ParameterSet.Utilities import convertToUnscheduled +process = convertToUnscheduled(process) + +# early deletion of intermediate products +from Configuration.StandardSequences.earlyDeleteSettings_cff import customiseEarlyDelete +process = customiseEarlyDelete(process) diff --git a/HGCSimTruth/HGCSimTruth/test/testTPtoSCAssociationAlgo.py b/HGCSimTruth/HGCSimTruth/test/testTPtoSCAssociationAlgo.py new file mode 100644 index 0000000000000..2d94425aeb889 --- /dev/null +++ b/HGCSimTruth/HGCSimTruth/test/testTPtoSCAssociationAlgo.py @@ -0,0 +1,51 @@ +# coding: utf-8 +from DataFormats import FWLite + +def getGeantTrackIds(obj): + geantTracks = obj.g4Tracks() + return [t.trackId() for t in geantTracks] + +def makeTPtoSCMap(trackingParticles, simClusters): + tp_map = {t.g4Tracks().at(0).trackId() : t for t in trackingParticles} + tp_map = {} + tp_sc_map = {} + for tp in trackingParticles: + trackIds = getGeantTrackIds(tp) + for trackId in trackIds: + if trackId in tp_map: + print(trackId, tp_map) + raise RuntimeError("Found track mapped to multiple tracking particles") + tp_map[trackId] = tp + tp_sc_map[tp] = [] + + for sc in simClusters: + trackIds = getGeantTrackIds(sc) + for trackId in trackIds: + if trackId in tp_map: + tp = tp_map[trackId] + tp_sc_map[tp].append(sc) + + return tp_sc_map + +events = FWLite.Events("test_RECO.root") +for event in events: + tp_handle = FWLite.Handle("std::vector") + event.getByLabel("mix:MergedTrackTruth", tp_handle) + trackingParticles = tp_handle.product() + + sc_handle = FWLite.Handle("std::vector") + #event.getByLabel("mix:MergedCaloTruth", sc_handle) + event.getByLabel("hgcSimTruth", sc_handle) + simClusters = sc_handle.product() + tp_sc_map = makeTPtoSCMap(trackingParticles, simClusters) + print("Length of tracking particles is", len(trackingParticles)) + print("Length of simClusters is", len(simClusters)) + print("Length of tp-> sc is", len(tp_sc_map)) + associated_scs = set() + unassociated_tps = set() + map(lambda x: associated_scs.update(x), tp_sc_map.values()) + unassociated_tps = [k for (k,v) in tp_sc_map.iteritems() if not v] + multassociated_tps = [k for (k,v) in tp_sc_map.iteritems() if len(v) > 1] + print("Number of SCs associated to TPs", len(associated_scs)) + print("Number of unassociated TPs", len(unassociated_tps)) + print("Number of TPs associated to multiple SCs", len(multassociated_tps)) diff --git a/HGCSimTruth/HGCSimTruth/test/testTPtoSCAssociationProd.py b/HGCSimTruth/HGCSimTruth/test/testTPtoSCAssociationProd.py new file mode 100644 index 0000000000000..c164b1750977a --- /dev/null +++ b/HGCSimTruth/HGCSimTruth/test/testTPtoSCAssociationProd.py @@ -0,0 +1,71 @@ +from __future__ import print_function +from DataFormats import FWLite + +events = FWLite.Events("test_RECO.root") +#track_handle = FWLite.Handle("std::vector") +#events.getByLabel("generalTracks", track_handle) +#tracks = track_handle.product() +#t = tracks.at(0) +# +#trackAssoc_handle = FWLite.Handle("") +#events.getByLabel("trackingParticleRecoTrackAsssociation", trackAssoc_handle) +#trackAssoc = trackAssoc_handle.product() +#track_handle = FWLite.Handle("std::vector") +#events.getByLabel("generalTracks", track_handle) +#tracks = track_handle.product() +#t = tracks.at(0) + +tp_handle = FWLite.Handle("std::vector") +events.getByLabel("mix:MergedTrackTruth", tp_handle) +trackingParticles = tp_handle.product() + +sc_handle = FWLite.Handle("std::vector") +events.getByLabel("hgcSimTruth", sc_handle) +simClusters = sc_handle.product() +events.getByLabel("mix:MergedCaloTruth", sc_handle) +simClustersUnmerged = sc_handle.product() + +tpToSc_handle = FWLite.Handle("edm::AssociationMap,vector,unsigned int>>") +events.getByLabel("trackingParticleSimClusterAssociation", tpToSc_handle) +assoc = tpToSc_handle.product() + +tpToScMerged_handle = FWLite.Handle("edm::AssociationMap,vector,unsigned int>>") +events.getByLabel("trackingParticleMergedSCAssociation", tpToScMerged_handle) +mergedAssoc = tpToScMerged_handle.product() + +merged_associated_scs = [] +for entry in mergedAssoc: + tp = entry.key.get() + scs = entry.val + print("Size of SCs is", len(scs)) + + print("TP pdgId is", tp.pdgId(), "energy is", tp.energy()) + for sc in scs: + info = (sc.pdgId(), sc.energy(), sc.p()) + merged_associated_scs.append(info) + print("-->Associated SC pdgId is", sc.pdgId(), "energy is", sc.energy()) + +print("-"*80) +associated_scs = [] +for entry in assoc: + tp = entry.key.get() + scs = entry.val + + print("Size of SCs is", len(scs)) + + print("TP pdgId is", tp.pdgId(), "energy is", tp.energy()) + for sc in scs: + info = (sc.pdgId(), sc.energy(), sc.p()) + associated_scs.append(info) + print("-->Associated SC pdgId is", sc.pdgId(), "energy is", sc.energy()) + +print("Size of tracking particles is", len(trackingParticles)) +print("Size of merged simClusters is", len(simClusters)) +print("Size of unmerged simClusters is", len(simClustersUnmerged)) +print("Size of trackingParticle --> SimClustersMerged association is", len(mergedAssoc)) +print("Size of trackingParticle --> SimClusters association is", len(assoc)) +print("Number of unique associated merged simClusters is", len(set(merged_associated_scs))) +print("Number of duplicates was", len(merged_associated_scs)-len(set(merged_associated_scs))) +print("Number of unqiue associated unmerged simClusters is", len(set(associated_scs))) +print("Number of duplicates was", len(associated_scs)-len(set(associated_scs))) +print("> they are", str(set(merged_associated_scs))) diff --git a/PhysicsTools/NanoAOD/interface/ObjectIndexFromAssociationProducer.h b/PhysicsTools/NanoAOD/interface/ObjectIndexFromAssociationProducer.h new file mode 100644 index 0000000000000..ee02c1d7beb08 --- /dev/null +++ b/PhysicsTools/NanoAOD/interface/ObjectIndexFromAssociationProducer.h @@ -0,0 +1,55 @@ +#include "FWCore/Framework/interface/global/EDProducer.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "DataFormats/NanoAOD/interface/FlatTable.h" +#include "DataFormats/Common/interface/View.h" +#include "DataFormats/Common/interface/Association.h" +#include "CommonTools/Utils/interface/StringCutObjectSelector.h" +#include + +template +class ObjectIndexFromAssociationTableProducer : public edm::global::EDProducer<> { +public: + ObjectIndexFromAssociationTableProducer(edm::ParameterSet const& params) + : objName_(params.getParameter("objName")), + branchName_(params.getParameter("branchName")), + doc_(params.getParameter("docString")), + src_(consumes(params.getParameter("src"))), + objMap_(consumes>(params.getParameter("objMap"))), + cut_(params.getParameter("cut"), true) { + produces(); + } + + ~ObjectIndexFromAssociationTableProducer() override {} + + void produce(edm::StreamID id, edm::Event& iEvent, const edm::EventSetup& iSetup) const override { + edm::Handle objs; + iEvent.getByToken(src_, objs); + + edm::Handle> assoc; + iEvent.getByToken(objMap_, assoc); + + std::vector keys; + for (unsigned int i = 0; i < objs->size(); ++i) { + edm::Ref tk(objs, i); + if (cut_(*tk)) { + edm::Ref match = (*assoc)[tk]; + int key = match.isNonnull() ? match.key() : -1; + keys.emplace_back(key); + } + } + + auto tab = std::make_unique(keys.size(), objName_, false, true); + tab->addColumn(branchName_ + "Idx", keys, doc_); + + iEvent.put(std::move(tab)); + } + +protected: + const std::string objName_, branchName_, doc_; + const edm::EDGetTokenT src_; + const edm::EDGetTokenT> objMap_; + const StringCutObjectSelector cut_; +}; diff --git a/PhysicsTools/NanoAOD/interface/ObjectIndexFromOneToManyQualAssociationProducer.h b/PhysicsTools/NanoAOD/interface/ObjectIndexFromOneToManyQualAssociationProducer.h new file mode 100644 index 0000000000000..9fc9debf32d60 --- /dev/null +++ b/PhysicsTools/NanoAOD/interface/ObjectIndexFromOneToManyQualAssociationProducer.h @@ -0,0 +1,76 @@ +#include "FWCore/Framework/interface/global/EDProducer.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "DataFormats/NanoAOD/interface/FlatTable.h" +#include "DataFormats/Common/interface/View.h" +#include "CommonTools/Utils/interface/StringCutObjectSelector.h" +#include "DataFormats/Common/interface/AssociationMap.h" +#include "DataFormats/Common/interface/OneToManyWithQualityGeneric.h" +#include +#include + +template +class ObjectIndexFromOneToManyQualAssociationTableProducer : public edm::global::EDProducer<> { +public: + ObjectIndexFromOneToManyQualAssociationTableProducer(edm::ParameterSet const& params) + : objName_(params.getParameter("objName")), + branchName_(params.getParameter("branchName")), + doc_(params.getParameter("docString")), + src_(consumes(params.getParameter("src"))), + objMap_(consumes>>( + params.getParameter("objMap"))), + cut_(params.getParameter("cut"), true) { + produces("match"); + produces("count"); + } + + ~ObjectIndexFromOneToManyQualAssociationTableProducer() override {} + + void produce(edm::StreamID id, edm::Event& iEvent, const edm::EventSetup& iSetup) const override { + edm::Handle objs; + iEvent.getByToken(src_, objs); + + edm::Handle>> assoc; + iEvent.getByToken(objMap_, assoc); + //std::cout << "Size of map is " << assoc->size() << std::endl; + + std::vector keys; + std::vector qualities; + std::vector nMatches; + for (unsigned int i = 0; i < objs->size(); ++i) { + edm::Ref tk(objs, i); + int nmatch = 0; + if (cut_(*tk)) { + if (assoc->numberOfAssociations(tk)) { + auto& matchWithQual = (*assoc)[tk]; + for (auto& match : matchWithQual) { + if (match.first.isNonnull()) { + keys.emplace_back(match.first.key()); + qualities.emplace_back(match.second); + } + } + nmatch = matchWithQual.size(); + } + + nMatches.emplace_back(nmatch); + } + } + + auto tabNum = std::make_unique(nMatches.size(), objName_, false, true); + tabNum->addColumn(branchName_ + "NumMatch", nMatches, doc_); + auto tabMatches = std::make_unique(keys.size(), objName_+"_"+branchName_, false, false); + tabMatches->addColumn("MatchIdx", keys, doc_); + tabMatches->addColumn("MatchQual", qualities, doc_); + + iEvent.put(std::move(tabMatches), "match"); + iEvent.put(std::move(tabNum), "count"); + } + +protected: + const std::string objName_, branchName_, doc_; + const edm::EDGetTokenT src_; + const edm::EDGetTokenT>> objMap_; + const StringCutObjectSelector cut_; +}; diff --git a/PhysicsTools/NanoAOD/interface/ObjectPropertyFromIndexMapTableProducer.h b/PhysicsTools/NanoAOD/interface/ObjectPropertyFromIndexMapTableProducer.h new file mode 100644 index 0000000000000..c0da1f742e5f8 --- /dev/null +++ b/PhysicsTools/NanoAOD/interface/ObjectPropertyFromIndexMapTableProducer.h @@ -0,0 +1,74 @@ +#ifndef NanoAOD_ObjectPropertyFromIndexMapTableProducer_h +#define NanoAOD_ObjectPropertyFromIndexMapTableProducer_h + +#include "FWCore/Framework/interface/global/EDProducer.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "DataFormats/NanoAOD/interface/FlatTable.h" +#include "DataFormats/Common/interface/View.h" +#include "DataFormats/Common/interface/Association.h" +#include "CommonTools/Utils/interface/StringCutObjectSelector.h" +#include +#include + +template +class ObjectPropertyFromIndexMapTableProducer : public edm::global::EDProducer<> { +public: + ObjectPropertyFromIndexMapTableProducer(edm::ParameterSet const& params) + : objName_(params.getParameter("objName")), + branchName_(params.getParameter("branchName")), + doc_(params.getParameter("docString")), + src_(consumes(params.getParameter("src"))), + mapToken_(consumes>(params.getParameter("valueMap"))), + cut_(params.getParameter("cut"), true) { + produces(); + } + + ~ObjectPropertyFromIndexMapTableProducer() override {} + // + // Because I'm not sure if this can be templated, overload instead... + std::unique_ptr fillTable(const std::vector& values, const std::string& objName) const { + auto tab = std::make_unique(values.size(), objName, false, true); + tab->addColumn(branchName_, values, doc_); + return tab; + } + + // Because I'm not sure if this can be templated, overload instead... + std::unique_ptr fillTable(const std::vector& values, const std::string& objName) const { + auto tab = std::make_unique(values.size(), objName, false, true); + tab->addColumn(branchName_, values, doc_); + return tab; + } + + void produce(edm::StreamID id, edm::Event& iEvent, const edm::EventSetup& iSetup) const override { + edm::Handle objs; + iEvent.getByToken(src_, objs); + + edm::Handle> valueMap; + iEvent.getByToken(mapToken_, valueMap); + + std::vector values; + for (unsigned int i = 0; i < objs->size(); ++i) { + edm::Ref obj(objs, i); + if (cut_(*obj)) { + if (valueMap->find(i) == valueMap->end()) + throw cms::Exception("ObjectPropertyFromIndexMapTableProducer") + << "No entry in value map for candidate " << i; + values.emplace_back(valueMap->at(i)); + } + } + + auto tab = fillTable(values, objName_); + iEvent.put(std::move(tab)); + } + +protected: + const std::string objName_, branchName_, doc_; + const edm::EDGetTokenT src_; + const edm::EDGetTokenT> mapToken_; + const StringCutObjectSelector cut_; +}; + +#endif diff --git a/PhysicsTools/NanoAOD/interface/SimpleFlatTableProducer.h b/PhysicsTools/NanoAOD/interface/SimpleFlatTableProducer.h index 087fa85bdb3b9..d18f551fb1dd7 100644 --- a/PhysicsTools/NanoAOD/interface/SimpleFlatTableProducer.h +++ b/PhysicsTools/NanoAOD/interface/SimpleFlatTableProducer.h @@ -1,3 +1,6 @@ +#ifndef NanoAOD_SimpleFlatTableProducer_h +#define NanoAOD_SimpleFlatTableProducer_h + #include "FWCore/Framework/interface/stream/EDProducer.h" #include "FWCore/ParameterSet/interface/ParameterSet.h" #include "FWCore/Framework/interface/ConsumesCollector.h" @@ -271,3 +274,5 @@ class FirstObjectSimpleFlatTableProducer : public SimpleFlatTableProducerBase + + @@ -11,6 +13,8 @@ + + diff --git a/PhysicsTools/NanoAOD/plugins/SimpleFlatTableProducerPlugins.cc b/PhysicsTools/NanoAOD/plugins/SimpleFlatTableProducerPlugins.cc index 1207a565c8a40..9f0d23477ef13 100644 --- a/PhysicsTools/NanoAOD/plugins/SimpleFlatTableProducerPlugins.cc +++ b/PhysicsTools/NanoAOD/plugins/SimpleFlatTableProducerPlugins.cc @@ -24,4 +24,4 @@ DEFINE_FWK_MODULE(SimpleGenEventFlatTableProducer); DEFINE_FWK_MODULE(SimpleHTXSFlatTableProducer); DEFINE_FWK_MODULE(SimpleProtonTrackFlatTableProducer); DEFINE_FWK_MODULE(SimpleLocalTrackFlatTableProducer); -DEFINE_FWK_MODULE(SimpleXYZPointFlatTableProducer); \ No newline at end of file +DEFINE_FWK_MODULE(SimpleXYZPointFlatTableProducer); diff --git a/RecoHGCal/GraphReco/BuildFile.xml b/RecoHGCal/GraphReco/BuildFile.xml new file mode 100644 index 0000000000000..f4e0fb0962d9a --- /dev/null +++ b/RecoHGCal/GraphReco/BuildFile.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/RecoHGCal/GraphReco/README.md b/RecoHGCal/GraphReco/README.md new file mode 100644 index 0000000000000..702bab48ebeee --- /dev/null +++ b/RecoHGCal/GraphReco/README.md @@ -0,0 +1,83 @@ +# Running the pepr PF candidate producer for HGCAL + +This example demonstrates how to run the particle reconstruction in the HGCAL subdetector via inference of graph neural networks. + +## Setup + +Install CMSSW: +``` +export SCRAM_ARCH="slc7_amd64_gcc820" +cmsrel CMSSW_11_2_0_pre9 +cd CMSSW_11_2_0_pre9/src +cmsenv +scram b -j 8 +``` + +Install custom packages: +``` +git cms-init +git cms-merge-topic cms-pepr:pepr_CMSSW_11_2_0_pre9 +scram b -j 8 +``` + +This will check out the necessary packages. To use the PEPR reconstruction, you only need to add the producer to the RECO sequence: +``` +process.load(“RecoHGCal/GraphReco/python/peprCandidateFromHitProducer_cfi”) +``` +This will provide +``` +process.peprCandidateFromHitProducer +``` +and produce ```recoPFCandidates_peprCandidateFromHitProducer__RECO``` + + +## Generate events and more information + +For testing, also scripts to produce events are provided. + +First we produce GEN-SIM-DIGI (GSD) events, in this example by shooting particles (e.g. photons) +in a certain energy range towards the HGCAL subdetector via the `FlatEtaRangeGunProducer`. +``` +cd RecoHGCal/GraphReco/test +cmsRun GSD_GUN.py seed=1 outputFile="file:1_GSD.root" maxEvents=5 +``` +Once the GSD events are produced, we can run the reconstruction step: +``` +cmsRun RECO_pf.py inputFiles="file://1_GSD.root" outputFile="file:1_RECO.root" outputFileDQM="file:1_DQM.root" maxEvents=5 +``` +A dedicated **EDProducer module**, the `peprCandidateFromHitProducer` located +in the [RecoHGCAL/GraphReco](.) package, +produces PF candidates straight from rechit information, in this example via the [Object Condensation](https://arxiv.org/abs/2002.03605) method. + +The inference of trained graph neural network models is done by sending the rechit information per endcap to a custom Triton server, evaluating the model, +and retrieving the regressed energy and position of clustered particle candidates. +These candidates are subsequently turned into a PFcandidate collection named `recoPFCandidates_peprCandidateFromHitProducer__RECO`. Particle and charge identification as well as track-cluster matching are work in progress and not included yet. + +The inference time on each event will improve by orders of magnitude once dedicated Triton GPU servers are used. Right now, with only a CPU triton server, it is not advised to process full events, this will take multiple minutes. + + +The **sequence** of the producer module is as follows: +* The producer sends the rechit data to the Triton server. +* The inference itself is done on the server via the trained model that is stored there +* The results are passed back to the module where a collection of reconstructed particle candidates is created. + +### Adding the peprCandidateFromHitProducer to your favorite RECO config + +The `peprCandidateFromHitProducer` can be loaded from the [config fragment](python/peprCandidateFromHitProducer_cfi.py) and added to a RECO sequence in the usual way. Add the following line to your python config + +``` +process.load("RecoHGCal/GraphReco/python/peprCandidateFromHitProducer_cfi") +``` + +this adds the producer to the process, you should then schedule it by adding it to a scheduled sequence, for example: + +``` +process.reconstruction_step += process.peprCandidateFromHitProducer +``` + +It's not expected that you would need to change arguments from their default values, but +this can be done as for other EDProducer modules, for example + +``` +process.peprCandidateFromHitProducer.tracks = "globalMuons" # Not a very good idea, but possible +``` diff --git a/RecoHGCal/GraphReco/bin/BuildFile.xml b/RecoHGCal/GraphReco/bin/BuildFile.xml new file mode 100644 index 0000000000000..75244cb43b460 --- /dev/null +++ b/RecoHGCal/GraphReco/bin/BuildFile.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/RecoHGCal/GraphReco/bin/plotTestOutput.cpp b/RecoHGCal/GraphReco/bin/plotTestOutput.cpp new file mode 100644 index 0000000000000..695a671978d72 --- /dev/null +++ b/RecoHGCal/GraphReco/bin/plotTestOutput.cpp @@ -0,0 +1,116 @@ +/* + * plotOutput.C + * + * Created on: 27 Sep 2019 + * Author: jkiesele + */ +#include "TFile.h" +#include "TTree.h" +#include "TH2D.h" +#include "TCanvas.h" +#include + + +TCanvas * projectRechitsEtaPhi(TTree* t, + const std::vector * rh_energy, + const std::vector * rh_eta, + const std::vector * rh_phi, + const std::vector * sc_eta, + const std::vector * sc_phi, int event){ + + TCanvas * cv = new TCanvas(); + float maxenergy = 0; + for(const auto& e:*rh_energy){ + if(e>maxenergy) + maxenergy=e; + } + + std::vector colors = {kBlue,kCyan,kGreen,kOrange,kRed}; + std::vector sizes = {0.1, 0.3, 0.5, 0.7, 0.9}; + std::vector delim = {0.0, 0.02, 0.05, 0.1, 0.3, 1.0}; + + for(size_t i=0;iSetMarkerStyle(8); + t->SetMarkerColor(colors.at(i)); + t->SetMarkerSize(sizes.at(i)); + + TString cutstr="recHitEnergy >"; + cutstr+=delim.at(i)*maxenergy; + cutstr+= " && recHitEnergy <"; + cutstr+=delim.at(i+1)*maxenergy; + if(i) + t->Draw("recHitEta:recHitRelPhi",cutstr,"same",1,event); + else + t->Draw("recHitEta:recHitRelPhi",cutstr,"",1,event); + + + //continue; + + } + t->SetMarkerStyle(5); + t->SetMarkerSize(1); + t->SetMarkerColor(kBlack); + t->Draw("truthSimclusterEtas:truthSimclusterPhis","","same",1,event); + + + return cv; +} + + + + + + +int main(int argc, char* argv[]){ + + if(argc<2) + return -1; + TString infile = argv[1]; + + int maxevents=10; + if(argc>2) + maxevents=atoi(argv[2]); + + TFile f(infile,"READ"); + TTree * tree = (TTree *)f.Get("WindowNTupler/tree"); + if(!tree || tree->IsZombie()) + return -1; + int nentries = tree->GetEntries(); + + std::cout << "nentries " << nentries << std::endl; + + + std::vector * recHitEnergy=0, * recHitEta=0, * recHitRelPhi=0, * truthSimclusterEtas=0, * truthSimclusterPhis=0; + + + tree->SetBranchAddress("recHitEnergy", &recHitEnergy); + tree->SetBranchAddress("recHitEta", &recHitEta); + tree->SetBranchAddress("recHitRelPhi", &recHitRelPhi); + tree->SetBranchAddress("truthSimclusterEtas",&truthSimclusterEtas); + tree->SetBranchAddress("truthSimclusterPhis",&truthSimclusterPhis); + + TFile fout("outfile.root","RECREATE"); + for(int event=0; event < nentries;event++){ + if(event>maxevents) + break; + tree->GetEntry(event); + + auto * cv = projectRechitsEtaPhi(tree,recHitEnergy,recHitEta,recHitRelPhi,truthSimclusterEtas,truthSimclusterPhis,event); + + TString outname="projectedEtaPhi"; + outname+=event; + cv->SetTitle(outname); + cv->SetName(outname); + outname+=".pdf"; + cv->Print(outname); + cv->Write(); + delete cv; + } + fout.Close(); + +return 0; + +} + + diff --git a/RecoHGCal/GraphReco/interface/HGCalParticlePropagator.h b/RecoHGCal/GraphReco/interface/HGCalParticlePropagator.h new file mode 100644 index 0000000000000..2f8e7bf310ec8 --- /dev/null +++ b/RecoHGCal/GraphReco/interface/HGCalParticlePropagator.h @@ -0,0 +1,54 @@ +/* + * HGCalParticlePropagator.h + * + * Created on: 10 Dec 2019 + * Author: jkiesele + */ + +#ifndef PRODUCTION_HGCALSIM_CMSSW_JKIESELE_CMSSW_11_0_0_PRE9_SRC_RECOHGCAL_GRAPHRECO_INTERFACE_HGCALPARTICLEPROPAGATOR_H_ +#define PRODUCTION_HGCALSIM_CMSSW_JKIESELE_CMSSW_11_0_0_PRE9_SRC_RECOHGCAL_GRAPHRECO_INTERFACE_HGCALPARTICLEPROPAGATOR_H_ + + + +#include "DataFormats/Math/interface/LorentzVector.h" +#include "DataFormats/Math/interface/Point3D.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "DataFormats/GeometryVector/interface/GlobalPoint.h" +#include "FastSimulation/ParticlePropagator/interface/MagneticFieldMapRecord.h" +#include "TrackPropagation/RungeKutta/interface/defaultRKPropagator.h" +#include "Geometry/CommonDetUnit/interface/GeomDet.h" +#include "TrackingTools/TrajectoryState/interface/TrajectoryStateTransform.h" +#include "DataFormats/GeometrySurface/interface/BoundDisk.h" + +//#include "TrackingTools/MaterialEffects/interface/PropagatorWithMaterial.h"//use this guy directly. can do masses! + + + + +class MagneticField; + + +class HGCalParticlePropagator{ +public: + enum zpos{ negZ=0, posZ=1}; + + HGCalParticlePropagator():rkprop_(0),frontz_(0),backz_(0),setup_(false),n_failed_(0),n_propagated_(0){} + ~HGCalParticlePropagator(); + void setEventSetup(const edm::EventSetup &es); + + void propagate(math::XYZTLorentzVectorF& point, math::XYZTLorentzVectorF& momentum, int charge); + + double getHGCalZ()const; +private: + edm::ESHandle bField_; + defaultRKPropagator::Product * rkprop_; + double frontz_,backz_; + std::unique_ptr frontFaces_[2]; + bool setup_; + + //DEBUG + int n_failed_,n_propagated_; +}; + + +#endif /* PRODUCTION_HGCALSIM_CMSSW_JKIESELE_CMSSW_11_0_0_PRE9_SRC_RECOHGCAL_GRAPHRECO_INTERFACE_HGCALPARTICLEPROPAGATOR_H_ */ diff --git a/RecoHGCal/GraphReco/interface/HGCalTrackPropagator.h b/RecoHGCal/GraphReco/interface/HGCalTrackPropagator.h new file mode 100644 index 0000000000000..8908a9af39466 --- /dev/null +++ b/RecoHGCal/GraphReco/interface/HGCalTrackPropagator.h @@ -0,0 +1,214 @@ +/* + * HGCalTrackPropagator.h + * + * Created on: 28 Aug 2019 + * Author: jkiesele + */ + +#ifndef SRC_RECOHGCAL_GRAPHRECO_INTERFACE_HGCALTRACKPROPAGATOR_H_ +#define SRC_RECOHGCAL_GRAPHRECO_INTERFACE_HGCALTRACKPROPAGATOR_H_ + +#include "TrackingTools/GeomPropagators/interface/Propagator.h" +#include "Geometry/CommonDetUnit/interface/GeomDet.h" +#include "MagneticField/Engine/interface/MagneticField.h" +#include "DataFormats/TrackReco/interface/Track.h" +#include "DataFormats/GeometryVector/interface/GlobalPoint.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "DataFormats/Math/interface/LorentzVector.h" +#include "SimDataFormats/Track/interface/SimTrack.h" + +#include "DataFormats/HepMCCandidate/interface/GenParticle.h" + +#include "TrackingTools/TrajectoryState/interface/TrajectoryStateTransform.h" +#include "DataFormats/GeometrySurface/interface/BoundDisk.h" + +#include "TrackingTools/Records/interface/TrackingComponentsRecord.h" +#include "MagneticField/Engine/interface/MagneticField.h" +#include "Geometry/HGCalCommonData/interface/HGCalDDDConstants.h" + + + + +template +class ObjectWithPos{ +public: + const T * obj; + const GlobalPoint pos; + const GlobalVector momentum;//momentum at position +}; + + + + +template +class HGCalObjectPropagator{ +public: + enum zpos{ negZ=0, posZ=1}; + HGCalObjectPropagator():setup_(false){} + HGCalObjectPropagator(const edm::EventSetup &es); //sets up geometry etc. + + void getEventSetup(const edm::EventSetup &es); + + ObjectWithPos propagateObject(const T&, int charge=-200)const; + +private: + bool setup_; + edm::ESHandle bField_; + edm::ESHandle propagator_; + std::unique_ptr frontFaces_[2]; + + double frontz_,backz_; +}; + + +typedef ObjectWithPos TrackWithHGCalPos; +typedef HGCalObjectPropagator HGCalTrackPropagator ; + + + +///////////////// + + + +template +HGCalObjectPropagator::HGCalObjectPropagator(const edm::EventSetup &es){ + getEventSetup(es); +} + +template +void HGCalObjectPropagator::getEventSetup(const edm::EventSetup &es){ + //get the propagator + es.get().get(bField_); + es.get().get("PropagatorWithMaterial", propagator_); + + + //create the hgcal inner surface for both z + edm::ESHandle hdc; + es.get().get("HGCalEESensitive", hdc); + + frontz_ = hdc.product()->waferZ(1, true); + backz_ = - frontz_; + auto frontradii = hdc.product()->rangeR(frontz_, true); + + frontFaces_[posZ] = std::make_unique < GeomDet + > (Disk::build(Disk::PositionType(0, 0, frontz_), + Disk::RotationType(), + SimpleDiskBounds(frontradii.first, frontradii.second, + frontz_ - 0.5, frontz_ + 0.5)).get()); + + frontFaces_[negZ] = std::make_unique < GeomDet + > (Disk::build(Disk::PositionType(0, 0, backz_), + Disk::RotationType(), + SimpleDiskBounds(frontradii.first, frontradii.second, + backz_ - 0.5, backz_ + 0.5)).get()); + + setup_=true; +} + +template +ObjectWithPos HGCalObjectPropagator::propagateObject(const T& part, int charge)const{ + if(!setup_) + throw cms::Exception("HGCalTrackPropagator") + << "event setup not loaded"; + + + typedef TrajectoryStateOnSurface TSOS; + + math::XYZTLorentzVectorF point(part.vertex().x(),part.vertex().y(),part.vertex().z(),part.vertex().t()); + math::XYZTLorentzVectorF momentum(part.momentum().x(),part.momentum().y(),part.momentum().z(),part.momentum().T()); + + + zpos trackz = posZ; + if(momentum.z()<0) trackz = negZ; + const double caloz = trackz == posZ ? frontz_ : backz_; + + bool failed=true; + + + const double c = 2.99792458e10; //cm/s + double betazc = momentum.Beta() * momentum.z()/momentum.P() * c; + + + + double zdist = caloz - point.z(); + double timeprop = zdist/betazc; + + + if(!charge){ + auto normmom = momentum / momentum.z(); + //figure out target + normmom *= zdist; + + point = math::XYZTLorentzVectorF(normmom.x()+point.x(), + normmom.y()+point.y(), + normmom.z()+point.z(), + timeprop+point.T()); + + failed=false; + } + else{ + const MagneticField * field=bField_.product(); + + GlobalPoint gpoint(point.x(),point.y(),point.z()); + GlobalVector gmomentum(momentum.x(),momentum.y(),momentum.z()); + + if(fabs(point.z())>fabs(caloz)) + gmomentum *= -1; + + TSOS startingState( GlobalTrajectoryParameters(gpoint, + gmomentum, charge, field)); + + TSOS propState = (*propagator_).propagate( startingState, frontFaces_[trackz]->surface()); + + if (propState.isValid()){ + auto proppoint = propState.globalPosition(); + auto propmomentum = propState.globalMomentum(); + + + point = math::XYZTLorentzVectorF(proppoint.x(), + proppoint.y(), + proppoint.z(), + timeprop+point.T()); + + momentum = math::XYZTLorentzVectorF(propmomentum.x(), + propmomentum.y(), + propmomentum.z(), + momentum.T()); + + failed=false; + } + } + /* + * + const GlobalPoint pos; + const GlobalVector momentum;//momentum at position + */ + + return ObjectWithPos{&part, GlobalPoint(point.x(),point.y(),point.z()), + GlobalVector(momentum.x(),momentum.y(),momentum.z())}; + +} + +template<> +inline ObjectWithPos HGCalObjectPropagator::propagateObject(const reco::Track& t, int charge)const{ + if(!setup_) + throw cms::Exception("HGCalObjectPropagator") + << "event setup not loaded"; + zpos trackz = posZ; + if(t.pz()<0) trackz = negZ; + + + FreeTrajectoryState fts = trajectoryStateTransform::outerFreeState(t, bField_.product()); + + TrajectoryStateOnSurface tsos = (*propagator_).propagate(fts, frontFaces_[trackz]->surface()); + if (tsos.isValid()) + return ObjectWithPos{&t, tsos.globalPosition(), tsos.globalMomentum()}; + return ObjectWithPos{&t, GlobalPoint(t.vx(), t.vy(),t.vz()), + GlobalVector(t.momentum().x(),t.momentum().y(),t.momentum().z())}; + +} + + + + +#endif /* SRC_RECOHGCAL_GRAPHRECO_INTERFACE_HGCALTRACKPROPAGATOR_H_ */ diff --git a/RecoHGCal/GraphReco/interface/InferenceWindow.h b/RecoHGCal/GraphReco/interface/InferenceWindow.h new file mode 100644 index 0000000000000..ac4242380f946 --- /dev/null +++ b/RecoHGCal/GraphReco/interface/InferenceWindow.h @@ -0,0 +1,41 @@ +/* + * InferenceWindow.h + * + * Created on: 26 Sep 2019 + * Author: jkiesele + */ + +#ifndef SRC_RECOHGCAL_GRAPHRECO_INTERFACE_INFERENCEWINDOW_H_ +#define SRC_RECOHGCAL_GRAPHRECO_INTERFACE_INFERENCEWINDOW_H_ + +#include "../interface/WindowBase.h" + +class InferenceWindow: public WindowBase { +public: + + + InferenceWindow(float centerEta, float centerPhi, float outerRegionDEta, float outerRegionDPhi, + float innerRegionDEta, float innerRegionDPhi); + + ~InferenceWindow(); + + + + void evaluate(); + + void getOutput() const{}//needs output format etc. + + static std::vector createWindows(size_t nSegmentsPhi, + size_t nSegmentsEta, double minEta, double maxEta, double frameWidthEta, + double frameWidthPhi); + +private: + + InferenceWindow(){} + // + //Inference + +}; + + +#endif /* SRC_RECOHGCAL_GRAPHRECO_INTERFACE_INFERENCEWINDOW_H_ */ diff --git a/RecoHGCal/GraphReco/interface/NTupleWindow.h b/RecoHGCal/GraphReco/interface/NTupleWindow.h new file mode 100644 index 0000000000000..eb5fc42deefe8 --- /dev/null +++ b/RecoHGCal/GraphReco/interface/NTupleWindow.h @@ -0,0 +1,215 @@ +/* + * NTupleWindow.h + * + * Created on: 26 Sep 2019 + * Author: jkiesele + */ + +#ifndef SRC_RECOHGCAL_GRAPHRECO_INTERFACE_NTUPLEWINDOW_H_ +#define SRC_RECOHGCAL_GRAPHRECO_INTERFACE_NTUPLEWINDOW_H_ + +#include "../interface/WindowBase.h" +#include +#include + +class NTupleWindow: public WindowBase { +public: + + NTupleWindow(float centerEta, float centerPhi, float outerRegionDEta, float outerRegionDPhi, + float innerRegionDEta, float innerRegionDPhi); + + static void createTreeBranches(TTree* t); + + //0 associate all rechits etc + + void fillFeatureArrays(); + + //1 + void fillTruthArrays(); + //2 + void fillTiclAssignment(); + void assignTreePointers() ; + void flattenRechitFeatures(); + + //3: tree->Fill(); + + //4 + void clear(); + + static std::vector createWindows(size_t nSegmentsPhi, + size_t nSegmentsEta, double minEta, double maxEta, double frameWidthEta, + double frameWidthPhi); + + + +private: + NTupleWindow(){} + + void createDetIDHitAssociation(); + void calculateSimclusterFeatures(); + void calculateTruthFractions(); + void fillTruthAssignment(); + std::vector cleanSimclusters(); + + + //temporary for (layer cluster) fraction calculation. detID to hit index and fraction + std::unordered_map> detIDHitAsso_; + + + //can be layer clusters or rechits according to mode + std::vector recHitEnergy_; + std::vector recHitEta_; + std::vector recHitPhi_; + std::vector recHitTheta_; + std::vector recHitR_; + std::vector recHitX_; + std::vector recHitY_; + std::vector recHitZ_; + std::vector recHitDetID_; + std::vector recHitTime_; + std::vector recHitID_; + std::vector recHitPad_; + + std::vector > truthHitFractions_; + + + //hit (rechit or layer cluster) assigned to exactly one simcluster with index + std::vector truthHitAssignementIdx_; + //truth energy of assigned simcluster + std::vector truthHitAssignedEnergies_; + //truth eta of assigned simcluster + std::vector truthHitAssignedX_; + std::vector truthHitAssignedY_; + std::vector truthHitAssignedZ_; + std::vector truthHitAssignedEta_; + std::vector truthHitAssignedPhi_; + std::vector truthHitAssignedT_; + //truth energy of assigned simcluster + std::vector > truthHitAssignedPIDs_; + std::vector truthHitAssignedInner_; + std::vector truthHitAssignedDirX_; + std::vector truthHitAssignedDirY_; + std::vector truthHitAssignedDirZ_; + std::vector truthHitAssignedDirEta_; + std::vector truthHitAssignedDepEnergies_; + std::vector truthHitAssignedDirR_; + + std::vector truthSimclusterIdx_; + std::vector > truthSimclusterPIDs_; + std::vector truthSimclusterEnergies_; + std::vector truthSimclusterX_; + std::vector truthSimclusterY_; + std::vector truthSimclusterZ_; + std::vector truthSimclusterEta_; + std::vector truthSimclusterPhi_; + std::vector truthSimclusterR_; + std::vector truthSimclusterT_; + std::vector truthSimclusterDirX_; + std::vector truthSimclusterDirY_; + std::vector truthSimclusterDirZ_; + std::vector truthSimclusterDirEta_; + std::vector truthSimclusterDepEnergies_; + std::vector truthSimclusterDirR_; + std::vector truthSimclusterInnerWindow_; + + std::vector ticlHitAssignementIdx_; + std::vector ticlHitAssignedEnergies_; + + //some globals mostly for plotting + + float windowEta_, windowPhi_; + + static const bool flattenRechitFeatures_ = true; + /* + * + * recHitEnergy, + recHitEta , + recHitID, #indicator if it is track or not + recHitTheta , + recHitR , + recHitX , + recHitY , + recHitZ , + recHitTime + */ + + + enum rhLables {kEnergy=0, kEta=1, kId=2, kTheta=3, kR=4, kx=5, ky=6, kz=7, kTime=8}; + //static pointers to create branches and fill tree + static std::vector> * sp_hitFeatures_; + static std::vector * sp_recHitEnergy_; + static std::vector * sp_recHitEta_; + static std::vector * sp_recHitPhi_; + static std::vector * sp_recHitTheta_; + static std::vector * sp_recHitR_; + static std::vector * sp_recHitX_; + static std::vector * sp_recHitY_; + static std::vector * sp_recHitZ_; + static std::vector * sp_recHitDetID_; + static std::vector * sp_recHitTime_; + static std::vector * sp_recHitID_; + static std::vector * sp_recHitPad_; + //static std::vector * sp_trackFeatures_; + + static std::vector > * sp_truthHitFractions_; + static std::vector * sp_truthHitAssignementIdx_; + static std::vector * sp_truthHitAssignedEnergies_; + static std::vector * sp_truthHitAssignedX_; + static std::vector * sp_truthHitAssignedY_; + static std::vector * sp_truthHitAssignedZ_; + static std::vector * sp_truthHitAssignedEta_; + static std::vector * sp_truthHitAssignedPhi_; + static std::vector * sp_truthHitAssignedT_; + static std::vector > * sp_truthHitAssignedPIDs_; + static std::vector * sp_truthHitAssignedInner_; + static std::vector * sp_truthHitAssignedDirX_; + static std::vector * sp_truthHitAssignedDirY_; + static std::vector * sp_truthHitAssignedDirZ_; + static std::vector * sp_truthHitAssignedDirEta_; + static std::vector * sp_truthHitAssignedDepEnergies_; + static std::vector * sp_truthHitAssignedDirR_; + + static std::vector * sp_truthSimclusterIdx_; + static std::vector > * sp_truthSimclusterPIDs_; + static std::vector * sp_truthSimclusterEnergies_; + static std::vector * sp_truthSimclusterX_; + static std::vector * sp_truthSimclusterY_; + static std::vector * sp_truthSimclusterZ_; + static std::vector * sp_truthSimclusterEta_; + static std::vector * sp_truthSimclusterPhi_; + static std::vector * sp_truthSimclusterR_; + static std::vector * sp_truthSimclusterT_; + static std::vector * sp_truthSimclusterInnerWindow_; + + static std::vector * sp_truthSimclusterDirX_; + static std::vector * sp_truthSimclusterDirY_; + static std::vector * sp_truthSimclusterDirZ_; + + static std::vector * sp_truthSimclusterDirEta_; + static std::vector * sp_truthSimclusterDepEnergies_; + static std::vector * sp_truthSimclusterDirR_; + + + static std::vector * sp_ticlHitAssignementIdx_; + static std::vector * sp_ticlHitAssignedEnergies_; + + static float * sp_windowEta_; + static float * sp_windowPhi_; + +}; + +//helper + +template +std::vector keepIndices(const std::vector & v, const std::vector indices){ + std::vector out; + for(size_t ii=0;ii + */ + +#ifndef SRC_RECOHGCAL_GRAPHRECO_INTERFACE_WINDOWBASE_H_ +#define SRC_RECOHGCAL_GRAPHRECO_INTERFACE_WINDOWBASE_H_ + +#include +#include "TTree.h" +#include "DataFormats/Math/interface/deltaPhi.h" +#include "DataFormats/HGCRecHit/interface/HGCRecHitCollections.h" +#include "RecoLocalCalo/HGCalRecAlgos/interface/RecHitTools.h" +#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" +#include "DataFormats/CaloRecHit/interface/CaloClusterFwd.h" +#include "DataFormats/TrackReco/interface/Track.h" +#include "DataFormats/GeometryVector/interface/GlobalPoint.h" +#include "DataFormats/HGCalReco/interface/Trackster.h" +#include + +#include "HGCalTrackPropagator.h" + + +#define DEBUGPRINT(x) {std::cout << #x << ": " << x << std::endl;} + +struct HGCRecHitWithPos{ + HGCRecHit * hit; + GlobalPoint pos; +}; + +struct Tracksterwithpos_and_energy{ + const ticl::Trackster * trackster; + GlobalPoint pos; + float energy; + std::vector assohits; +}; + + +class WindowBase { +public: + + enum mode { + useRechits, useLayerClusters + }; + + enum particle_type{ + type_ambiguous, + type_electron, + type_photon, + type_mip, + type_charged_hadron, + type_neutral_hadron, + n_particle_types + }; + + + WindowBase(float centerEta, float centerPhi, float outerRegionDEta, float outerRegionDPhi, + float innerRegionDEta, float innerRegionDPhi); + + virtual ~WindowBase() ; + + + void setMode(mode m){ + mode_=m; + } + mode getMode()const{ + return mode_; + } + + inline bool accept(float phi, float eta) const { + return fabs(reco::deltaPhi(phi, centerPhi_)) < outerRegionDPhi_ + && fabs(eta - centerEta_) < outerRegionDEta_; + } + + bool maybeAddTrack(const TrackWithHGCalPos& t) { + //potential cuts here! + if (accept((float)t.pos.phi(), (float)t.pos.eta()) + && t.obj->pt()>1) { + tracks_.push_back(&t); + return true; + } + return false; + } + + inline bool maybeAddTrackster( + const Tracksterwithpos_and_energy & trackster) { + //potential cuts here! + if (accept(trackster.pos.phi(), trackster.pos.eta())) { + ticltracksters_.push_back(&trackster); + return true; + } + return false; + } + + inline bool maybeAddRecHit(const HGCRecHitWithPos& recHit) { + //potential cuts here! + if (accept((float) recHit.pos.phi(), (float) recHit.pos.eta()) + && recHit.hit->energy() > 0.01) { + recHits.push_back(&recHit); + return true; + } + return false; + } + + inline bool maybeAddLayerCluster( + const reco::CaloCluster & layerCluster) { + //potential cuts here! + if (accept(layerCluster.phi(), layerCluster.eta())) { + layerClusters_.push_back(&layerCluster); + return true; + } + return false; + } + + inline bool maybeAddSimCluster(const SimCluster& sc, bool isHGCal=true){ + //potential cuts here! + if (accept(sc.impactPoint().phi(),sc.impactPoint().eta()) && isHGCal){ + bool isinner=isInner(sc.impactPoint().eta(),sc.impactPoint().phi()); + if(!removeFrameSimcluster_){ + simClusters_.push_back(&sc); + simClustersInnerWindow_.push_back(isinner); + return true; + } + else if(isinner){ + simClusters_.push_back(&sc); + simClustersInnerWindow_.push_back(isinner); + return true; + } + else{ + badSimClusters_.push_back(&sc); + return false; + } + } + badSimClusters_.push_back(&sc); + return false; + } + + inline bool isInner(const float& eta, const float& phi) { + return fabs(reco::deltaPhi(phi, centerPhi_)) < innerRegionDPhi_ + && fabs(eta - centerEta_) < innerRegionDEta_; + } + + + + void clear(); + + void fillFeatureArrays(); + + + //debug functions + + void setRemoveFrameSimclusters(bool set){ + removeFrameSimcluster_=set; + } + + void printDebug()const; + + const float& getCenterEta() const { + return centerEta_; + } + + const float& getCenterPhi() const { + return centerPhi_; + } + + const float& getOuterRegionDEta() const { + return outerRegionDEta_; + } + + const float& getOuterRegionDPhi() const { + return outerRegionDPhi_; + } + + const float& getInnerRegionDEta() const { + return innerRegionDEta_; + } + + const float& getInnerRegionDPhi() const { + return innerRegionDPhi_; + } + + template + static std::vector createWindows(size_t nSegmentsPhi, + size_t nSegmentsEta, double minEta, double maxEta, double frameWidthEta, + double frameWidthPhi) ; + + const std::vector >& getHitFeatures()const { return hitFeatures_;} + +private: + + mode mode_; + + float centerEta_; + float centerPhi_; + + float outerRegionDEta_; + float outerRegionDPhi_; + + float innerRegionDEta_; + float innerRegionDPhi_; + + +protected: + + WindowBase():removeFrameSimcluster_(true){} + bool removeFrameSimcluster_; + + + std::vector ticltracksters_; + std::vector tracks_; + std::vector recHits; + std::vector layerClusters_; + std::vector simClusters_; + std::vector badSimClusters_; + std::vector simClustersInnerWindow_; + + //this is the input to the model! + std::vector > hitFeatures_; //this includes tracks! + + //for one track + void fillTrackFeatures(float*& data, const TrackWithHGCalPos *) const; + //for one rechit + void fillRecHitFeatures(float*& data, const HGCRecHitWithPos * ) const; + //for one layer cluster + void fillLayerClusterFeatures(float*& data, const reco::CaloCluster * ) const; + + + particle_type pdgToParticleType(int pdgid) const; + std::vector particleTypeToOneHot(particle_type pdgid) const; + particle_type oneHotToParticleType(const std::vector& ) const; + particle_type predictionToParticleType(const float * ) const; + std::vector pdgToOneHot(int pdgid) const; + + static const size_t nTrackFeatures_; + static const size_t nRechitFeatures_; + static const size_t nLayerClusterFeatures_; + + + + +}; + + +template +std::vector WindowBase::createWindows(size_t nSegmentsPhi, + size_t nSegmentsEta, double minEta, double maxEta, double frameWidthEta, + double frameWidthPhi) { + + if (minEta <= 0 || maxEta <= 0 || minEta >= maxEta) { + throw cms::Exception("IncorrectWindowCreationParameters") + << "minEta, maxEta must be > 0 and maxEta > minEta (negative eta will be created automatically)"; + } + if (frameWidthEta < 0 || frameWidthPhi < 0 ) { + throw cms::Exception("IncorrectWindowCreationParameters") + << "frameWidthEta, frameWidthPhi must be >= 0"; + } + + const float epsilon=1e-5; + + std::vector windows; + float phiStep = 2. * M_PI / (float) nSegmentsPhi; + float totalDPhi = (phiStep + 2. * frameWidthPhi)/2.; + float etaStep = (maxEta - minEta) / (float) nSegmentsEta; + float totalDEta = (etaStep + 2. * frameWidthEta)/2.; + + for (float phi_i = -M_PI; phi_i + epsilon < M_PI; phi_i += phiStep) { + float phiCenter = phi_i + phiStep / 2.; + for (float eta_j = minEta; eta_j + epsilon < maxEta; eta_j += etaStep) { + float etaCenter = eta_j + etaStep / 2.; + T w(etaCenter, phiCenter, totalDEta, totalDPhi, + (float)(etaStep / 2.), (float)(phiStep / 2.)); + //w.printDebug(); + windows.push_back(w); + + } + + + + float minEtaNeg = -maxEta; + float maxEtaNeg = -minEta; + for (float eta_j = minEtaNeg; eta_j + epsilon < maxEtaNeg; eta_j += + etaStep) { + + float etaCenter = eta_j + etaStep / 2.; + + T w(etaCenter, phiCenter, totalDEta, totalDPhi, + (float)(etaStep / 2.), (float)(phiStep / 2.)); + //w.printDebug(); + windows.push_back(w); + } + + } + return windows; +} + + + + + +#endif /* SRC_RECOHGCAL_GRAPHRECO_INTERFACE_WINDOWBASE_H_ */ diff --git a/RecoHGCal/GraphReco/plugins/BuildFile.xml b/RecoHGCal/GraphReco/plugins/BuildFile.xml new file mode 100644 index 0000000000000..ed7f88933058c --- /dev/null +++ b/RecoHGCal/GraphReco/plugins/BuildFile.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/RecoHGCal/GraphReco/plugins/WindowInference.cc b/RecoHGCal/GraphReco/plugins/WindowInference.cc new file mode 100644 index 0000000000000..d0f0d4f962d25 --- /dev/null +++ b/RecoHGCal/GraphReco/plugins/WindowInference.cc @@ -0,0 +1,207 @@ +/* + * CMSSW plugin that performs a Window-based inference of networks using RecHits. + * + * Author: Marcel Rieger + */ + +#include + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/Framework/interface/stream/EDAnalyzer.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/Utilities/interface/Exception.h" + +#include "DataFormats/HGCRecHit/interface/HGCRecHitCollections.h" + +#include "RecoLocalCalo/HGCalRecAlgos/interface/RecHitTools.h" + +#include "PhysicsTools/TensorFlow/interface/TensorFlow.h" + +#include "RecoHGCal/GraphReco/interface/InferenceWindow.h" + + +// macros for simplified logs +// message logger disabled for the moment +// #define INFO edm::LogInfo("WindowInference") +// #define WARNING edm::LogWarning("WindowInference") +// #define ERROR edm::LogError("WindowInference") +#define INFO std::cout << "WindowInference INFO : " +#define WARNING std::cout << "WindowInference WARNING: " +#define ERROR std::cout << "WindowInference ERROR : " + +// datastructure hold by edm::GlobalCache +struct WindowInferenceCache { + WindowInferenceCache(const edm::ParameterSet& config) : + graphDef(nullptr) { + } + + std::atomic graphDef; +}; + +class WindowInference: public edm::stream::EDAnalyzer< + edm::GlobalCache > { + public: + explicit WindowInference(const edm::ParameterSet&, + const WindowInferenceCache*); + ~WindowInference(); + + // methods for handling the global cache + static std::unique_ptr initializeGlobalCache( + const edm::ParameterSet&); + static void globalEndJob(const WindowInferenceCache*); + + private: + void beginStream(edm::StreamID); + void endStream(); + void analyze(const edm::Event&, const edm::EventSetup&); + + void fillWindows(const edm::Event&); + + + // options + std::vector recHitCollections_; + + std::string inputTensorName_; + std::string outputTensorName_; + bool batchedModel_; + size_t padSize_; + + // tokens + std::vector > recHitTokens_; + + // rechit tools + hgcal::RecHitTools recHitTools_; + + // windows + std::vector windows_; + + double minEta_; + double maxEta_; + double etaFrameWidth_; + double phiFrameWidth_; + size_t nEtaSegments_; + size_t nPhiSegments_; + + // the tensorflow session + tensorflow::Session* session_; + + +}; + +std::unique_ptr WindowInference::initializeGlobalCache( + const edm::ParameterSet& config) { + // this method is supposed to create, initialize and + //return a WindowInferenceCache instance + WindowInferenceCache* windowInferenceCache = new WindowInferenceCache( + config); + + // load the graph def and save it + std::string graphPath = config.getParameter("graphPath"); + INFO<< "loading graph from " << graphPath << std::endl; + windowInferenceCache->graphDef = tensorflow::loadGraphDef(graphPath); + + // set some global configs, such as the TF log level + tensorflow::setLogging("0"); + + return std::unique_ptr(windowInferenceCache); +} + +void WindowInference::globalEndJob( + const WindowInferenceCache* windowInferenceCache) { + // reset the graphDef + if (windowInferenceCache->graphDef != nullptr) { + delete windowInferenceCache->graphDef; + } +} + +WindowInference::WindowInference(const edm::ParameterSet& config, + const WindowInferenceCache* windowInferenceCache) : + recHitCollections_( + config.getParameter >( + "recHitCollections")), inputTensorName_( + config.getParameter("inputTensorName")), outputTensorName_( + config.getParameter("outputTensorName")), batchedModel_( + config.getParameter("batchedModel")), padSize_( + (size_t) config.getParameter("padSize")), + + //FIXME: actually these are all not needed if windows are created in the constructor! + minEta_(config.getParameter("minEta")), + maxEta_(config.getParameter("maxEta")), + etaFrameWidth_(config.getParameter("etaFrameWidth")), + phiFrameWidth_(config.getParameter("phiFrameWidth")), + nEtaSegments_((size_t)config.getParameter("nEtaSegments")), + nPhiSegments_((size_t)config.getParameter("nPhiSegments")), + session_(nullptr){ + // sanity checks for sliding windows + + + // get tokens + for (edm::InputTag& recHitCollection : recHitCollections_) { + recHitTokens_.push_back( + consumes(recHitCollection)); + } + + // mount the graphDef stored in windowInferenceCache onto the session + //FIXME + // session_ = tensorflow::createSession(windowInferenceCache->graphDef); +} + +WindowInference::~WindowInference() { +} + + +void WindowInference::beginStream(edm::StreamID streamId) { + windows_ = InferenceWindow::createWindows(nPhiSegments_,nEtaSegments_,minEta_,maxEta_,etaFrameWidth_,phiFrameWidth_); +} + +void WindowInference::endStream() { + // close the session + //FIXME + // tensorflow::closeSession(session_); + session_ = nullptr; + + + windows_.clear(); +} + +void WindowInference::analyze(const edm::Event& event, + const edm::EventSetup& setup) { + // fill rechits into windows + fillWindows(event); + + // run the evaluation per window + //for (auto & window : windows_) { + // window.evaluate(session_); + //} + + // reconstruct showers using all windows and put them into the event + //reconstructShowers(); + + // clear all windows + for (auto& window : windows_) { + window.clear(); + } +} + + + +void WindowInference::fillWindows(const edm::Event& event) { + + if (!windows_.size()) { + throw cms::Exception("NoWindows") << "no windows initialized"; + } + + //Window::mode windowmode = windows_.at(0).getMode(); + // skip layer cluster or rechit loop accordingly + + //FIXME + + +} + +//remove + +DEFINE_FWK_MODULE(WindowInference); diff --git a/RecoHGCal/GraphReco/plugins/WindowNTupler.cc b/RecoHGCal/GraphReco/plugins/WindowNTupler.cc new file mode 100644 index 0000000000000..065c2abb05ba9 --- /dev/null +++ b/RecoHGCal/GraphReco/plugins/WindowNTupler.cc @@ -0,0 +1,383 @@ +// -*- C++ -*- +// +// Package: RecoHGCal/WindowNTupler +// Class: WindowNTupler +// +/**\class WindowNTupler WindowNTupler.cc RecoHGCal/GraphReco/plugins/WindowNTupler.cc + + Description: [one line class summary] + + Implementation: + [Notes on implementation] +*/ +// +// Original Author: Jan Kieseler +// Created: Tue, 27 Aug 2019 17:25:47 GMT +// +// + + + +// system include files +#include + +// user include files +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/one/EDAnalyzer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/Utilities/interface/InputTag.h" + +#include "DataFormats/TrackReco/interface/Track.h" +#include "DataFormats/TrackReco/interface/TrackFwd.h" +#include "DataFormats/HGCRecHit/interface/HGCRecHitCollections.h" +#include "DataFormats/CaloRecHit/interface/CaloClusterFwd.h" +#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" + +#include "FWCore/ServiceRegistry/interface/Service.h" +#include "CommonTools/UtilAlgos/interface/TFileService.h" + +#include "../interface/NTupleWindow.h" +#include "DataFormats/ParticleFlowReco/interface/HGCalMultiCluster.h" +#include "HGCSimTruth/HGCSimTruth/interface/SimClusterTools.h" + +#include "SimDataFormats/TrackingAnalysis/interface/TrackingParticle.h" +#include "SimDataFormats/TrackingAnalysis/interface/TrackingParticleFwd.h" + +#include "SimDataFormats/Associations/interface/TrackAssociation.h" +#include "DataFormats/Common/interface/OneToMany.h" +#include "DataFormats/Common/interface/AssociationMap.h" + +#include +// +// class declaration +// + +// If the analyzer does not use TFileService, please remove +// the template argument to the base class so the class inherits +// from edm::one::EDAnalyzer<> +// This will improve performance in multithreaded jobs. + + +using reco::TrackCollection; +typedef edm::AssociationMap> TrackingParticleToSimCluster; + +class WindowNTupler : public edm::one::EDAnalyzer { + public: + explicit WindowNTupler(const edm::ParameterSet&); + ~WindowNTupler(); + + static void fillDescriptions(edm::ConfigurationDescriptions& descriptions); + + virtual void beginRun(edm::Run const &iEvent, edm::EventSetup const &) override; + virtual void endRun(edm::Run const &iEvent, edm::EventSetup const &) override; + + private: + virtual void beginJob() override; + virtual void analyze(const edm::Event&, const edm::EventSetup&) override; + virtual void endJob() override; + + + + Tracksterwithpos_and_energy assignPositionAndEnergy(const ticl::Trackster& , + const reco::CaloClusterCollection& )const; + + // ----------member data --------------------------- + edm::EDGetTokenT> tracksters_token_; + edm::EDGetTokenT> tracksToken_; + edm::EDGetTokenT layerClustersToken_; + edm::EDGetTokenT> simClusterToken_; + std::vector > rechitsTokens_; + //edm::EDGetTokenT trackingPartToken_; + edm::EDGetTokenT tracksToTrackingPartToken_; + edm::EDGetTokenT trackingPartToSimClusToken_; + + std::vector windows_; + hgcal::RecHitTools recHitTools_; + SimClusterTools sctools_; + HGCalTrackPropagator trackprop_; + edm::Service fs_; + TTree * outTree_; + + +}; + + +Tracksterwithpos_and_energy WindowNTupler::assignPositionAndEnergy(const ticl::Trackster& trackster, + const reco::CaloClusterCollection& caloclusters)const{ + + std::array baricenter{{0., 0., 0.}}; + float total_weight = 0.; + std::vector assohits; + if (!trackster.vertices().empty()) { + + int counter = 0; + std::for_each(std::begin(trackster.vertices()), std::end(trackster.vertices()), [&](unsigned int idx) { + auto fraction = 1.f / trackster.vertex_multiplicity(counter++); + auto weight = caloclusters.at(idx).energy() * fraction; + total_weight += weight; + baricenter[0] += caloclusters.at(idx).x() * weight; + baricenter[1] += caloclusters.at(idx).y() * weight; + baricenter[2] += caloclusters.at(idx).z() * weight; + + auto haf = caloclusters.at(idx).hitsAndFractions(); + for(const auto& hf:haf){ + assohits.push_back(hf.first); + } + + }); + std::transform( + std::begin(baricenter), std::end(baricenter), std::begin(baricenter), [&total_weight](double val) -> double { + return val / total_weight; + }); + } +//Tracksterwithpos r= + auto pos = GlobalPoint(baricenter[0], baricenter[1], baricenter[2]); + return {&trackster,pos ,total_weight,assohits}; + +} + +// +// constants, enums and typedefs +// + +// +// static data member definitions +// + +// +// constructors and destructor +// +WindowNTupler::WindowNTupler(const edm::ParameterSet& config) + : + tracksters_token_(consumes>(config.getParameter("tracksters"))), + tracksToken_(consumes>(config.getParameter("tracks"))), + layerClustersToken_(consumes(config.getParameter("layerClusters"))), + simClusterToken_(consumes>(config.getParameter("simClusters"))), + //trackingPartToken_(consumes(config.getParameter("trackingParticles"))), + tracksToTrackingPartToken_(consumes(config.getParameter("tracksToTrackingParticles"))), + trackingPartToSimClusToken_(consumes(config.getParameter("trackingParticleSimCluster"))), + outTree_(nullptr) + +/* ... */ + +{ + for (edm::InputTag& recHitCollection : config.getParameter< + std::vector >("recHitCollections")) { + rechitsTokens_.push_back( + consumes(recHitCollection)); + } + + //DEBUG INFO: has checks built in + windows_ = NTupleWindow::createWindows( + (size_t) config.getParameter("nPhiSegments"), + (size_t) config.getParameter("nEtaSegments"), + config.getParameter("minEta"), + config.getParameter("maxEta"), + config.getParameter("etaFrameWidth"), + config.getParameter("phiFrameWidth")); + + for(auto& w: windows_){ + w.setMode(WindowBase::useRechits);//FIXME make configurable + w.setRemoveFrameSimclusters(true); + } + //w.setMode(WindowBase::useLayerClusters);//FIXME make configurable + +} + + +WindowNTupler::~WindowNTupler() +{ +} + + +// +// member functions +// + +// ------------ method called for each event ------------ +void +WindowNTupler::analyze(const edm::Event& iEvent, const edm::EventSetup& iSetup) +{ + using namespace edm; + + auto inlayerclusters = iEvent.get(layerClustersToken_); + auto insimclusters = iEvent.get(simClusterToken_); + + std::vector tracksters; + auto intracksters = iEvent.get(tracksters_token_); + for(const auto& t: intracksters){ + auto twpe = assignPositionAndEnergy(t, inlayerclusters); + tracksters.push_back(twpe); + } + + + + reco::RecoToSimCollection tracksToTrackingParticles = iEvent.get(tracksToTrackingPartToken_); + TrackingParticleToSimCluster trackingPartToSimClus = iEvent.get(trackingPartToSimClusToken_); + + //get and propagate tracks + std::vector proptracks; + edm::Handle> tracksHandle; + iEvent.getByToken(tracksToken_, tracksHandle); + std::vector trackTruthIdx(tracksHandle->size(), -2); + for(size_t i = 0; i < tracksHandle->size(); i++){ + edm::RefToBase track(tracksHandle, i); + if(fabs(track->eta())< 1.5 || fabs(track->eta())>3.0) + continue; //just use potentially interesting ones + proptracks.push_back(trackprop_.propagateObject(*track)); + // I know try/catch is a bit ugly, but I don't know if there is another + // mechanism to see if the track has matched tracking particle. This is + // what they do in https://github.com/cms-sw/cmssw/blob/master/SimTracker/TrackAssociation/test/testTrackAssociator.cc#L64-L78 + std::vector> trackingPartsWithQual; + try { + trackingPartsWithQual = tracksToTrackingParticles[track]; + } + catch (edm::Exception const &) { + // No trackingParticle match, this is a fake + trackTruthIdx.at(i) = -1; + continue; + } + for (auto& tpWithQual : trackingPartsWithQual) { + TrackingParticleRef trackingPart = tpWithQual.first; + SimClusterRefVector assocSimClusters; + try { + assocSimClusters = trackingPartToSimClus[trackingPart]; + } + catch (edm::Exception const &) { + // Give a unique ID, not matching any simClusters + trackTruthIdx.at(i) = insimclusters.size()+i; + continue; + } + + // This should be a loop, but need to figure out how to assign to SC. + // Maybe also need to group multiple SCs together if they share a track + SimClusterRef simClusRef = assocSimClusters.at(0); + trackTruthIdx.at(i) = simClusRef.key(); + } + } + std::cout << "The size of the in simclusters is " << insimclusters.size() << std::endl; + for (auto i : trackTruthIdx) + std::cout << "Track truth index is " << i << std::endl; + + //get rechits, get positions and merge collections + std::vector allrechits; + for (auto & token : rechitsTokens_) { + for (const auto& rh : iEvent.get(token)) { + HGCRecHitWithPos rhp = { const_cast(&rh), recHitTools_.getPosition(rh.detid()) }; + allrechits.push_back(rhp); + } + } + std::sort(allrechits.begin(), allrechits.end(), + [](const HGCRecHitWithPos& rh1, const HGCRecHitWithPos& rh2) + { return rh1.hit->energy() > rh2.hit->energy();}); + + + + + std::vector filledtracksters(tracksters.size(),0); + std::vector filledtrack(proptracks.size(),0); + std::vector filledrechits(allrechits.size(),0); + std::vector filledlayercluster(inlayerclusters.size(),0); + + //rechits + //filledrechits vector etc + + for(auto& window : windows_){ + //attach tracks, rehits etc to windows + for(size_t it=0;it3) continue; + if(window.maybeAddTrack(proptracks.at(it))) + filledtrack.at(it)++; + } + for(size_t it=0;it3) continue; + if(window.maybeAddRecHit(allrechits.at(it))) + filledrechits.at(it)++; + } + if(window.getMode() == WindowBase::useLayerClusters){ + for(size_t it=0;it3) continue; + if(window.maybeAddLayerCluster(inlayerclusters.at(it))) + filledlayercluster.at(it)++; + } + } + for(size_t it=0;it3) continue; + if(window.maybeAddTrackster(tracksters.at(it))) + filledtracksters.at(it)++; + } + + for(size_t it=0;it3) continue; + window.maybeAddSimCluster(insimclusters.at(it),sctools_.isHGCal(insimclusters.at(it))); + + } + + //the follwing will not work yet before everything is filled + window.fillFeatureArrays(); + window.flattenRechitFeatures(); + window.fillTiclAssignment(); + + + window.fillTruthArrays(); + + window.assignTreePointers(); + + outTree_->Fill(); + window.clear(); //free memory + } + + + +} + + +// ------------ method called once each job just before starting event loop ------------ +void WindowNTupler::beginJob() { + + if (!fs_) + throw edm::Exception(edm::errors::Configuration, + "TFile Service is not registered in cfg file"); + + outTree_ = fs_->make("tree", "tree"); + NTupleWindow::createTreeBranches(outTree_); + +} + +// ------------ method called once each job just after ending the event loop ------------ +void +WindowNTupler::endJob() +{ +} + +void WindowNTupler::beginRun(edm::Run const &iEvent, edm::EventSetup const &es) { + trackprop_ .getEventSetup(es); + sctools_.setRechitTools(recHitTools_); +} +void WindowNTupler::endRun(edm::Run const &iEvent, edm::EventSetup const &es) { + +} + +// ------------ method fills 'descriptions' with the allowed parameters for the module ------------ +void +WindowNTupler::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + //The following says we do not know what parameters are allowed so do no validation + // Please change this to state exactly what you do use, even if it is no parameters + edm::ParameterSetDescription desc; + desc.setUnknown(); + descriptions.addDefault(desc); + + //Specify that only 'tracks' is allowed + //To use, remove the default given above and uncomment below + //ParameterSetDescription desc; + //desc.addUntracked("tracks","ctfWithMaterialTracks"); + //descriptions.addDefault(desc); +} + +//define this as a plug-in +DEFINE_FWK_MODULE(WindowNTupler); diff --git a/RecoHGCal/GraphReco/plugins/peprCandidateFromHitProducer.cc b/RecoHGCal/GraphReco/plugins/peprCandidateFromHitProducer.cc new file mode 100644 index 0000000000000..557d816c60f4f --- /dev/null +++ b/RecoHGCal/GraphReco/plugins/peprCandidateFromHitProducer.cc @@ -0,0 +1,372 @@ +/* + * CMSSW plugin that performs a Window-based inference of networks using RecHits and produces PF candidates. + * + * Authors: Gerrit Van Onsem + * Marcel Rieger + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/Utilities/interface/Exception.h" +#include "FWCore/ParameterSet/interface/FileInPath.h" + +#include "DataFormats/TrackReco/interface/Track.h" +#include "DataFormats/TrackReco/interface/TrackFwd.h" +#include "DataFormats/HGCRecHit/interface/HGCRecHitCollections.h" +#include "DataFormats/CaloRecHit/interface/CaloClusterFwd.h" + +#include "RecoLocalCalo/HGCalRecAlgos/interface/RecHitTools.h" + +#include "RecoHGCal/GraphReco/interface/InferenceWindow.h" + +#include "DataFormats/Common/interface/View.h" + +#include "DataFormats/ParticleFlowCandidate/interface/PFCandidateFwd.h" +#include "DataFormats/ParticleFlowCandidate/interface/PFCandidate.h" +#include "DataFormats/Candidate/interface/LeafCandidate.h" + +#include "DataFormats/HGCalReco/interface/Trackster.h" + +#include "HeterogeneousCore/SonicCore/interface/SonicEDProducer.h" +#include "HeterogeneousCore/SonicTriton/interface/TritonClient.h" + + +using namespace ticl; + +// macros for simplified logs +// message logger disabled for the moment +// #define INFO edm::LogInfo("peprCandidateFromHitProducer") +// #define WARNING edm::LogWarning("peprCandidateFromHitProducer") +// #define ERROR edm::LogError("peprCandidateFromHitProducer") +#define INFO std::cout << "peprCandidateFromHitProducer INFO : " +#define WARNING std::cout << "peprCandidateFromHitProducer WARNING: " +#define ERROR std::cout << "peprCandidateFromHitProducer ERROR : " + + +class peprCandidateFromHitProducer: public SonicEDProducer { + public: + explicit peprCandidateFromHitProducer(edm::ParameterSet const&); + ~peprCandidateFromHitProducer(); + + private: + void acquire(edm::Event const&, edm::EventSetup const&, Input&) override; + void produce(edm::Event&, edm::EventSetup const&, Output const&) override; + + void fillWindows(const edm::Event&); + void readOutput(Output const&, std::vector >&); + + // options + std::vector recHitCollections_; + + // tokens + std::vector > recHitTokens_; + edm::EDGetTokenT> tracksToken_; + + // rechit tools + hgcal::RecHitTools recHitTools_; + + double minCandEnergy_; + + // windows + std::vector windows_; + + double minEta_; + double maxEta_; + double etaFrameWidth_; + double phiFrameWidth_; + size_t nEtaSegments_; + size_t nPhiSegments_; + +}; + + +peprCandidateFromHitProducer::peprCandidateFromHitProducer(edm::ParameterSet const& config) : SonicEDProducer(config, "peprCandidate"), + recHitCollections_(config.getParameter >("recHitCollections")), + tracksToken_(consumes>(config.getParameter("tracks"))), + minCandEnergy_(config.getParameter("minCandEnergy")), + //FIXME: actually these are all not needed if windows are created in the constructor! + minEta_(config.getParameter("minEta")), + maxEta_(config.getParameter("maxEta")) + { + + // get tokens + for (edm::InputTag& recHitCollection : recHitCollections_) { + recHitTokens_.push_back(consumes(recHitCollection)); + } + + // window size and overlap in phi and eta + etaFrameWidth_ = 0.2; + phiFrameWidth_ = 0.2; + nEtaSegments_ = 1; + nPhiSegments_ = 1; + + produces(); + //produces>(); + + windows_ = InferenceWindow::createWindows(nPhiSegments_,nEtaSegments_,minEta_,maxEta_,etaFrameWidth_,phiFrameWidth_); + // FIXME, make configurable? + for(auto& w: windows_) + w.setMode(WindowBase::useRechits); + + //std::cout << " Starting server" << std::endl; + //system("/afs/cern.ch/work/g/gvonsem/public/HGCAL/ML/pepr_11_2_0_pre9/CMSSW_11_2_0_pre9/src/HeterogeneousCore/SonicTriton/test/triton start"); +} + + +peprCandidateFromHitProducer::~peprCandidateFromHitProducer() { + + //std::cout << " Stopping server" << std::endl; + //system("/afs/cern.ch/work/g/gvonsem/public/HGCAL/ML/pepr_11_2_0_pre9/CMSSW_11_2_0_pre9/src/HeterogeneousCore/SonicTriton/test/triton stop"); +} + + +void peprCandidateFromHitProducer::acquire(edm::Event const& iEvent, edm::EventSetup const& iSetup, Input& iInput) { + + //INFO << "Acquire method" << std::endl; + + edm::ESHandle geom; + iSetup.get().get(geom); + recHitTools_.setGeometry(*geom); + + // fill rechits into windows + fillWindows(iEvent); + + std::vector > hitFeatures; + //vector of number of hits per window + std::vector nhitsWindow; + + for (auto & window : windows_) { + + std::cout << " New window " << std::endl; + + nhitsWindow.push_back(window.getHitFeatures().size()); + + //append vector to previous vector + hitFeatures.insert(hitFeatures.end(),window.getHitFeatures().begin(),window.getHitFeatures().end()); + std::cout << " hitFeatures size = " << hitFeatures.size() << std::endl; + std::cout << " number of features per hit = " << hitFeatures[0].size() << std::endl; + + //break; //if quickly testing just one window + } + + //set shapes + auto& input1 = iInput.at("input_1"); + //input_1 has dims:[ -1, 9 ], this setShape command changes the variable dimension at location 0 to the total number of rechits in the windows + input1.setShape(0, hitFeatures.size()); + auto data1 = std::make_shared>(1); + auto& vdata1 = (*data1)[0]; + vdata1.reserve(input1.sizeShape()); + + std::cout << " input1.sizeShape = " << input1.sizeShape() << std::endl; + + auto& input2 = iInput.at("input_2"); + input2.setShape(0, hitFeatures.size()); + auto data2 = std::make_shared>(1); + auto& vdata2 = (*data2)[0]; + vdata2.reserve(input2.sizeShape()); + + std::cout << " input2.sizeShape = " << input2.sizeShape() << std::endl; + + //fill first input: total list of rechits of all windows + for (size_t i=0; i > candidates; + + readOutput(iOutput,candidates); + + // making candidate collection + auto pfcandidates = std::make_unique(); + //std::cout << "Creating PF candidates " << std::endl; + float E=-9999., X = -9999., Y=-9999., Z=-9999.; + + // loop over particles reconstructed in the current window + for(size_t j=0;j filledrechits(allrechits.size(),0); + + for (auto & window : windows_) { + //fill rechits in this window + for(size_t it=0;it3) continue; + if(window.maybeAddRecHit(allrechits.at(it))) + filledrechits.at(it)++; + } + + window.fillFeatureArrays(); + } + + std::cout << " windows filled" << std::endl; +} + + +void peprCandidateFromHitProducer::readOutput(Output const& iOutput, std::vector >& candidates) { + + const auto& output1 = iOutput.at("output"); + // convert from server format + const auto& tmp = output1.fromServer(); + + std::cout << "output1.shape()[0] = " << output1.shape()[0] << std::endl; + std::cout << "output1.shape()[1] = " << output1.shape()[1] << std::endl; + + for (int i = 0; i < output1.shape()[0]; ++i) { + //std::cout << "output " << i << ": "; + if(output1.shape()[1] == 16 || output1.shape()[1] == 17) { + + std::vector fulloutput; + for (int j = 0; j < output1.shape()[1]; ++j) { + fulloutput.push_back(tmp[0][output1.shape()[1] * i + j]); + } + //std::cout << "\n"; + + float E = -9999., X = -9999., Y = -9999., Z = -9999., Xrel = -9999., Yrel = -9999.; //T = -9999.; + + //input rechit position + X = fulloutput[5]; + Y = fulloutput[6]; + Z = fulloutput[7]; + E = fulloutput[10]; + //values are relative to input rechit position + Xrel = fulloutput[11]; + Yrel = fulloutput[12]; + //FIXME: is T also relative to T of rechit? Not used for now + //T = values[13]; + + X = X + Xrel; + Y = Y + Yrel; + + //positive Z of rechit means Z = 320 cm (as regressed X,Y is measured on HGCAL surface) + if ( Z > 0 ) Z = 320.; //in cm + else Z = -320.; //in cm + + //std::cout << " Storing values from the model output" << std::endl; + std::vector candidate = {E, X, Y, Z }; + //std::cout << " from output: (X,Y,Z,E) = " << "(" << X << "," << Y << "," << Z << "," << E << ")" << std::endl; + candidates.push_back( candidate ); + } + else + std::cout << " Please check model output to retrieve desired regressed properties" << std::endl; + } + + std::cout << " candidates size = " << candidates.size() << std::endl; +} + + +DEFINE_FWK_MODULE(peprCandidateFromHitProducer); diff --git a/RecoHGCal/GraphReco/python/peprCandidateFromHitProducer_cfi.py b/RecoHGCal/GraphReco/python/peprCandidateFromHitProducer_cfi.py new file mode 100644 index 0000000000000..947ab352adda0 --- /dev/null +++ b/RecoHGCal/GraphReco/python/peprCandidateFromHitProducer_cfi.py @@ -0,0 +1,39 @@ +# coding: utf-8 + +""" +Initialization file for the WindowInference module. +""" + + +__all__ = ["peprCandidateFromHitProducer"] + + +import math + +import FWCore.ParameterSet.Config as cms + + +peprCandidateFromHitProducer = cms.EDProducer("peprCandidateFromHitProducer", + # the collections of rechits to use + recHitCollections=cms.VInputTag( + cms.InputTag("HGCalRecHit", "HGCEERecHits"), + cms.InputTag("HGCalRecHit", "HGCHEFRecHits"), + cms.InputTag("HGCalRecHit", "HGCHEBRecHits"), + ), + tracks = cms.InputTag("generalTracks"), + minCandEnergy=cms.double(1.0), + minEta=cms.double(1.6), + maxEta=cms.double(3.0), + Client = cms.PSet( + mode = cms.string("PseudoAsync"), + batchSize = cms.untracked.uint32(1), + address = cms.untracked.string("dockerbuild.cern.ch"), + port = cms.untracked.uint32(8001), + timeout = cms.untracked.uint32(30), + modelName = cms.string("hgcal_oc_reco"), + modelVersion = cms.string(""), + outputs = cms.untracked.vstring("output"), + verbose = cms.untracked.bool(False), + allowedTries = cms.untracked.uint32(0), + ) +) diff --git a/RecoHGCal/GraphReco/python/windowInference_cfi.py b/RecoHGCal/GraphReco/python/windowInference_cfi.py new file mode 100644 index 0000000000000..c0b5c975194f7 --- /dev/null +++ b/RecoHGCal/GraphReco/python/windowInference_cfi.py @@ -0,0 +1,41 @@ +# coding: utf-8 + +""" +Initialization file for the WindowInference module. +""" + + +__all__ = ["windowInference"] + + +import math + +import FWCore.ParameterSet.Config as cms + + +windowInference = cms.EDAnalyzer("WindowInference", + # the collections of rechits to use + recHitCollections=cms.VInputTag( + cms.InputTag("HGCalRecHit", "HGCEERecHits"), + cms.InputTag("HGCalRecHit", "HGCHEFRecHits"), + cms.InputTag("HGCalRecHit", "HGCHEBRecHits"), + ), + inputTensorName=cms.string("input"), + outputTensorName=cms.string("output"), + # whether or not the model in the graph expects a batch dimension + batchedModel=cms.bool(True), + # dimension of the padding of the second dimension, i.e., the rec hits themselves + padSize=cms.uint32(100), + # graph to the trained model + graphPath=cms.string("graph.pb"), + + minEta=cms.double(1.6), + maxEta=cms.double(3.0), + # window size in phi and eta + etaFrameWidth=cms.double(0.1), + phiFrameWidth=cms.double(0.1), + # overlap in phi and eta + nEtaSegments=cms.uint32(3), + nPhiSegments=cms.uint32(1), + # names of the input and output tensors +) diff --git a/RecoHGCal/GraphReco/python/windowNTupler_cfi.py b/RecoHGCal/GraphReco/python/windowNTupler_cfi.py new file mode 100644 index 0000000000000..e9b09fe38f010 --- /dev/null +++ b/RecoHGCal/GraphReco/python/windowNTupler_cfi.py @@ -0,0 +1,42 @@ +# coding: utf-8 + +""" +Initialization file for the WindowNTupler module. +""" + + +__all__ = ["WindowNTupler"] + + +import math + +import FWCore.ParameterSet.Config as cms + + +WindowNTupler = cms.EDAnalyzer("WindowNTupler", + # the collections of rechits to use + recHitCollections=cms.VInputTag( + cms.InputTag("HGCalRecHit", "HGCEERecHits"), + cms.InputTag("HGCalRecHit", "HGCHEFRecHits"), + cms.InputTag("HGCalRecHit", "HGCHEBRecHits"), + ), + tracksters = cms.InputTag("ticlTrackstersMerge"), + tracks = cms.InputTag("generalTracks"), + layerClusters = cms.InputTag("hgcalLayerClusters"), + #simClusters = cms.InputTag("mix", "RealisticCaloTruth"), + simClusters = cms.InputTag("mix", "MergedCaloTruth"), + tracksToTrackingParticles = cms.InputTag("trackingParticleRecoTrackAsssociation"), + trackingParticleSimCluster = cms.InputTag("trackingParticleSimClusterAssociation"), + + removeFrameSimclusters=cms.bool(True), + + minEta=cms.double(1.4), + maxEta=cms.double(3.1), + # window size in phi and eta + etaFrameWidth=cms.double(0.1), + phiFrameWidth=cms.double(0.1), + # overlap in phi and eta + nEtaSegments=cms.uint32(1), + nPhiSegments=cms.uint32(4), + # names of the input and output tensors +) diff --git a/RecoHGCal/GraphReco/src/HGCalParticlePropagator.cpp b/RecoHGCal/GraphReco/src/HGCalParticlePropagator.cpp new file mode 100644 index 0000000000000..fdf239e9568d0 --- /dev/null +++ b/RecoHGCal/GraphReco/src/HGCalParticlePropagator.cpp @@ -0,0 +1,137 @@ + +#include "../interface/HGCalParticlePropagator.h" +#include "FWCore/Framework/interface/ESHandle.h" +#include "FastSimulation/ParticlePropagator/interface/ParticlePropagator.h" +#include "FWCore/Utilities/interface/Exception.h" +#include "Geometry/HGCalCommonData/interface/HGCalDDDConstants.h" +#include "MagneticField/Engine/interface/MagneticField.h" + +HGCalParticlePropagator::~HGCalParticlePropagator(){ + if(rkprop_) + delete rkprop_; + + std::cout << "n propagated "<< n_propagated_ << " n failed "<< n_failed_ << std::endl; +} + +void HGCalParticlePropagator::setEventSetup(const edm::EventSetup &es){ + + es.get().get(bField_); + + if(rkprop_) + delete rkprop_; + rkprop_ = new defaultRKPropagator::Product ( bField_.product(), alongMomentum, 5.e-5); + + //edm::ESHandle fieldMap; + //es.get().get(fieldMap); // <--- + //fieldMap_ = fieldMap.product(); + // + // + //PropagatorWithMaterial (PropagationDirection dir, const float mass, + // const MagneticField * mf=nullptr,const float maxDPhi=1.6, + // bool useRungeKutta=false, float ptMin=-1.,bool useOldGeoPropLogic=true); + // + // ~ + + edm::ESHandle hdc; + es.get().get("HGCalEESensitive", hdc); + + frontz_ = hdc.product()->waferZ(1, true); + backz_ = - frontz_; + auto frontradii = hdc.product()->rangeR(frontz_, true); + + frontFaces_[posZ] = std::make_unique < GeomDet + > (Disk::build(Disk::PositionType(0, 0, frontz_), + Disk::RotationType(), + SimpleDiskBounds(frontradii.first, frontradii.second, + frontz_ - 0.5, frontz_ + 0.5)).get()); + + frontFaces_[negZ] = std::make_unique < GeomDet + > (Disk::build(Disk::PositionType(0, 0, backz_), + Disk::RotationType(), + SimpleDiskBounds(frontradii.first, frontradii.second, + backz_ - 0.5, backz_ + 0.5)).get()); + + setup_=true; + +} + +void HGCalParticlePropagator::propagate(math::XYZTLorentzVectorF& point, math::XYZTLorentzVectorF& momentum, int charge){ + typedef TrajectoryStateOnSurface TSOS; + zpos trackz = posZ; + if(momentum.z()<0) trackz = negZ; + const double caloz = trackz == posZ ? frontz_ : backz_; + + bool failed=true; + + n_propagated_++; + + const double c = 2.99792458e10; //cm/s + double betazc = momentum.Beta() * momentum.z()/momentum.P() * c; + + + + double zdist = caloz - point.z(); + double timeprop = zdist/betazc; + + + if(!charge){ + auto normmom = momentum / momentum.z(); + //figure out target + normmom *= zdist; + + point = math::XYZTLorentzVectorF(normmom.x()+point.x(), + normmom.y()+point.y(), + normmom.z()+point.z(), + timeprop+point.T()); + + failed=false; + } + else{ + const MagneticField * field=bField_.product(); + auto & RKprop = rkprop_->propagator; + + GlobalPoint gpoint(point.x(),point.y(),point.z()); + GlobalVector gmomentum(momentum.x(),momentum.y(),momentum.z()); + + if(fabs(point.z())>fabs(caloz)) + gmomentum *= -1; + + TSOS startingState( GlobalTrajectoryParameters(gpoint, + gmomentum, charge, field)); + + TSOS propState = RKprop.propagate( startingState, frontFaces_[trackz]->surface()); + + if (propState.isValid()){ + auto proppoint = propState.globalPosition(); + auto propmomentum = propState.globalMomentum(); + + + point = math::XYZTLorentzVectorF(proppoint.x(), + proppoint.y(), + proppoint.z(), + timeprop+point.T()); + + momentum = math::XYZTLorentzVectorF(propmomentum.x(), + propmomentum.y(), + propmomentum.z(), + momentum.T()); + + failed=false; + } + } + if(fabs(point.z()) - fabs(getHGCalZ()) > 0.01) + failed=true; + if(failed){ + std::cout << "\n prop failed for point " << point << + ", eta: " << point.Eta() << ", phi: " << point.Phi() << + " charge " << charge << std::endl; + std::cout << "pos " << trackz << " calo z " << caloz <<" "; + std::cout << "propagate z " << point.z() << " with momentum z " << momentum.z() << " and betaz " << betazc << std::endl; + std::cout << "distance " << zdist << " time to travel " << timeprop << std::endl; + n_failed_++; + } +} + +double HGCalParticlePropagator::getHGCalZ()const{ + return frontFaces_[posZ].get()->position().z(); +} diff --git a/RecoHGCal/GraphReco/src/InferenceWindow.cpp b/RecoHGCal/GraphReco/src/InferenceWindow.cpp new file mode 100644 index 0000000000000..32707468e8b05 --- /dev/null +++ b/RecoHGCal/GraphReco/src/InferenceWindow.cpp @@ -0,0 +1,33 @@ +/* + * InferenceWindow.cpp + * + * Created on: 26 Sep 2019 + * Author: jkiesele + */ + + + +#include "../interface/InferenceWindow.h" + +InferenceWindow::InferenceWindow(float centerEta, float centerPhi, + float outerRegionDEta, float outerRegionDPhi, float innerRegionDEta, + float innerRegionDPhi) : + WindowBase(centerEta, centerPhi, outerRegionDEta, outerRegionDPhi, + innerRegionDEta, innerRegionDPhi) +/* more inits */ +{ +} + +InferenceWindow::~InferenceWindow() { + +} + +//static +std::vector InferenceWindow::createWindows(size_t nSegmentsPhi, + size_t nSegmentsEta, double minEta, double maxEta, double frameWidthEta, + double frameWidthPhi){ + return WindowBase::createWindows(nSegmentsPhi,nSegmentsEta, + minEta,maxEta,frameWidthEta,frameWidthPhi); +} + + diff --git a/RecoHGCal/GraphReco/src/NTupleWindow.cpp b/RecoHGCal/GraphReco/src/NTupleWindow.cpp new file mode 100644 index 0000000000000..f3831cb1450b9 --- /dev/null +++ b/RecoHGCal/GraphReco/src/NTupleWindow.cpp @@ -0,0 +1,657 @@ +/* + * NTupleWindow.cpp + * + * Created on: 26 Sep 2019 + * Author: jkiesele + */ + + + +#include "../interface/NTupleWindow.h" +#include "DataFormats/Math/interface/deltaR.h" + +std::vector>* NTupleWindow::sp_hitFeatures_=0; +std::vector* NTupleWindow::sp_recHitEnergy_; +std::vector* NTupleWindow::sp_recHitEta_; +std::vector* NTupleWindow::sp_recHitPhi_; +std::vector* NTupleWindow::sp_recHitTheta_; +std::vector* NTupleWindow::sp_recHitR_; +std::vector* NTupleWindow::sp_recHitX_; +std::vector* NTupleWindow::sp_recHitY_; +std::vector* NTupleWindow::sp_recHitZ_; +std::vector* NTupleWindow::sp_recHitDetID_; +std::vector* NTupleWindow::sp_recHitTime_; +std::vector* NTupleWindow::sp_recHitID_; +std::vector* NTupleWindow::sp_recHitPad_; +//std::vector* NTupleWindow::sp_trackFeatures_=0; + +std::vector > * NTupleWindow::sp_truthHitFractions_=0; +std::vector * NTupleWindow::sp_truthHitAssignementIdx_=0; +std::vector * NTupleWindow::sp_truthHitAssignedEnergies_=0; +std::vector * NTupleWindow::sp_truthHitAssignedX_=0; +std::vector * NTupleWindow::sp_truthHitAssignedY_=0; +std::vector * NTupleWindow::sp_truthHitAssignedZ_=0; +std::vector * NTupleWindow::sp_truthHitAssignedEta_=0; +std::vector * NTupleWindow::sp_truthHitAssignedPhi_=0; +std::vector * NTupleWindow::sp_truthHitAssignedT_=0; +std::vector > * NTupleWindow::sp_truthHitAssignedPIDs_=0; +std::vector * NTupleWindow::sp_truthHitAssignedInner_=0; + +std::vector * NTupleWindow::sp_truthHitAssignedDirX_=0; +std::vector * NTupleWindow::sp_truthHitAssignedDirY_=0; +std::vector * NTupleWindow::sp_truthHitAssignedDirZ_=0; +std::vector * NTupleWindow::sp_truthHitAssignedDirEta_=0; +std::vector * NTupleWindow::sp_truthHitAssignedDepEnergies_=0; +std::vector * NTupleWindow::sp_truthHitAssignedDirR_=0; + +std::vector * NTupleWindow::sp_truthSimclusterIdx_=0; +std::vector > * NTupleWindow::sp_truthSimclusterPIDs_=0; +std::vector * NTupleWindow::sp_truthSimclusterEnergies_=0; +std::vector * NTupleWindow::sp_truthSimclusterX_=0; +std::vector * NTupleWindow::sp_truthSimclusterY_=0; +std::vector * NTupleWindow::sp_truthSimclusterZ_=0; +std::vector * NTupleWindow::sp_truthSimclusterEta_=0; +std::vector * NTupleWindow::sp_truthSimclusterPhi_=0; +std::vector * NTupleWindow::sp_truthSimclusterR_=0; +std::vector * NTupleWindow::sp_truthSimclusterInnerWindow_=0; +std::vector * NTupleWindow::sp_truthSimclusterT_=0; +std::vector * NTupleWindow::sp_truthSimclusterDirX_=0; +std::vector * NTupleWindow::sp_truthSimclusterDirY_=0; +std::vector * NTupleWindow::sp_truthSimclusterDirZ_=0; +std::vector * NTupleWindow::sp_truthSimclusterDirEta_=0; +std::vector * NTupleWindow::sp_truthSimclusterDepEnergies_=0; +std::vector * NTupleWindow::sp_truthSimclusterDirR_=0; + +std::vector * NTupleWindow::sp_ticlHitAssignementIdx_=0; +std::vector * NTupleWindow::sp_ticlHitAssignedEnergies_=0; + +float * NTupleWindow::sp_windowEta_=0; +float * NTupleWindow::sp_windowPhi_=0; + +//static +std::vector NTupleWindow::createWindows(size_t nSegmentsPhi, + size_t nSegmentsEta, double minEta, double maxEta, double frameWidthEta, + double frameWidthPhi){ + return WindowBase::createWindows(nSegmentsPhi,nSegmentsEta, + minEta,maxEta,frameWidthEta,frameWidthPhi); +} + + + +void NTupleWindow::createTreeBranches(TTree* t){ + + // NTupleWindow dummy; + // dummy.assignTreePointers(); //so that the pointers are not null, maybe not needed? FIXME + + if (flattenRechitFeatures_) { + t->Branch("recHitEnergy", &sp_recHitEnergy_); + t->Branch("recHitEta", &sp_recHitEta_); + t->Branch("recHitPhi", &sp_recHitPhi_); + t->Branch("recHitTheta", &sp_recHitTheta_); + t->Branch("recHitR", &sp_recHitR_); + t->Branch("recHitX", &sp_recHitX_); + t->Branch("recHitY", &sp_recHitY_); + t->Branch("recHitZ", &sp_recHitZ_); + t->Branch("recHitDetID", &sp_recHitDetID_); + t->Branch("recHitTime", &sp_recHitTime_); + t->Branch("recHitID", &sp_recHitID_); + t->Branch("recHitPad", &sp_recHitPad_); + } + else + t->Branch("recHitFeatures", &sp_hitFeatures_); + //t->Branch("trackFeatures", &sp_trackFeatures_); + + t->Branch("truthHitFractions", &sp_truthHitFractions_); + t->Branch("truthHitAssignementIdx", &sp_truthHitAssignementIdx_); + t->Branch("truthHitAssignedEnergies", &sp_truthHitAssignedEnergies_); + t->Branch("truthHitAssignedX", &sp_truthHitAssignedX_); + t->Branch("truthHitAssignedY", &sp_truthHitAssignedY_); + t->Branch("truthHitAssignedZ", &sp_truthHitAssignedZ_); + t->Branch("truthHitAssignedEta", &sp_truthHitAssignedEta_); + t->Branch("truthHitAssignedPhi", &sp_truthHitAssignedPhi_); + t->Branch("truthHitAssignedT", &sp_truthHitAssignedT_); + t->Branch("truthHitAssignedPIDs", &sp_truthHitAssignedPIDs_); + t->Branch("truthHitAssignedInner", &sp_truthHitAssignedInner_); + t->Branch("truthHitAssignedDirX", &sp_truthHitAssignedDirX_); + t->Branch("truthHitAssignedDirY", &sp_truthHitAssignedDirY_); + t->Branch("truthHitAssignedDirZ", &sp_truthHitAssignedDirZ_); + t->Branch("truthHitAssignedDirEta", &sp_truthHitAssignedDirEta_); + t->Branch("truthHitAssignedDepEnergies", &sp_truthHitAssignedDepEnergies_); + t->Branch("truthHitAssignedDirR", &sp_truthHitAssignedDirR_); + + t->Branch("truthSimclusterIdx",&sp_truthSimclusterIdx_); + t->Branch("truthSimclusterPIDs",&sp_truthSimclusterPIDs_); + t->Branch("truthSimclusterEnergies",&sp_truthSimclusterEnergies_); + t->Branch("truthSimclusterX",&sp_truthSimclusterX_); + t->Branch("truthSimclusterY",&sp_truthSimclusterY_); + t->Branch("truthSimclusterZ",&sp_truthSimclusterZ_); + t->Branch("truthSimclusterInnerWindow",&sp_truthSimclusterInnerWindow_); + t->Branch("truthSimclusterT",&sp_truthSimclusterT_); + + t->Branch("truthSimclusterDirX",&sp_truthSimclusterDirX_); + t->Branch("truthSimclusterDirY",&sp_truthSimclusterDirY_); + t->Branch("truthSimclusterDirZ",&sp_truthSimclusterDirZ_); + t->Branch("truthSimclusterDirEta",&sp_truthSimclusterDirEta_); + t->Branch("truthSimclusterDepEnergies",&sp_truthSimclusterDepEnergies_); + t->Branch("truthSimclusterDirR",&sp_truthSimclusterDirR_); + + t->Branch("ticlHitAssignementIdx", &sp_ticlHitAssignementIdx_ ); + t->Branch("ticlHitAssignedEnergies",&sp_ticlHitAssignedEnergies_); + + t->Branch("windowEta",sp_windowEta_); + t->Branch("windowPhi",sp_windowPhi_); + +} + +NTupleWindow::NTupleWindow(float centerEta, float centerPhi, + float outerRegionDEta, float outerRegionDPhi, float innerRegionDEta, + float innerRegionDPhi) : + WindowBase(centerEta, centerPhi, outerRegionDEta, outerRegionDPhi, + innerRegionDEta, innerRegionDPhi) { + + windowEta_ = centerEta; + windowPhi_ = centerPhi; + removeFrameSimcluster_=true; +} + + +//static + +// This is not a very clear/efficient way to do this, but it's the simplest way given +// the structure we already have +void NTupleWindow::flattenRechitFeatures() { + for (size_t i = 0; i < hitFeatures_.size(); i++) { + recHitEnergy_.push_back(hitFeatures_[i][kEnergy]); + recHitEta_.push_back(hitFeatures_[i][kEta]); + recHitTheta_.push_back(hitFeatures_[i][kTheta]); + recHitR_.push_back(hitFeatures_[i][kR]); + recHitX_.push_back(hitFeatures_[i][kx]); + recHitY_.push_back(hitFeatures_[i][ky]); + recHitZ_.push_back(hitFeatures_[i][kz]); + recHitTime_.push_back(hitFeatures_[i][kTime]); + recHitID_.push_back(hitFeatures_[i][kId]); + + math::XYZTLorentzVectorF v(hitFeatures_[i][kx],hitFeatures_[i][ky],hitFeatures_[i][kz],0); + + recHitPad_.push_back(0); + recHitPhi_.push_back(v.phi()); + recHitDetID_.push_back(0); + } +} + + +void NTupleWindow::assignTreePointers() { + + sp_hitFeatures_ = &hitFeatures_; + //sp_trackFeatures_ = &hitFeatures_; + if (flattenRechitFeatures_) { + sp_recHitEnergy_ = &recHitEnergy_; + sp_recHitEta_ = &recHitEta_; + sp_recHitPhi_ = &recHitPhi_; + sp_recHitTheta_ = &recHitTheta_; + sp_recHitR_ = &recHitR_; + sp_recHitX_ = &recHitX_; + sp_recHitY_ = &recHitY_; + sp_recHitZ_ = &recHitZ_; + sp_recHitDetID_ = &recHitDetID_; + sp_recHitTime_ = &recHitTime_; + sp_recHitID_ = &recHitID_; + sp_recHitPad_ = &recHitPad_; + } + + sp_truthHitFractions_ = &truthHitFractions_; + sp_truthHitAssignementIdx_ = &truthHitAssignementIdx_; + sp_truthHitAssignedEnergies_ = &truthHitAssignedEnergies_; + sp_truthHitAssignedX_ = &truthHitAssignedX_; + sp_truthHitAssignedY_ = &truthHitAssignedY_; + sp_truthHitAssignedZ_ = &truthHitAssignedZ_; + sp_truthHitAssignedEta_ = &truthHitAssignedEta_; + sp_truthHitAssignedPhi_ = &truthHitAssignedPhi_; + sp_truthHitAssignedT_ = &truthHitAssignedT_; + sp_truthHitAssignedPIDs_ = &truthHitAssignedPIDs_; + sp_truthHitAssignedInner_ = &truthHitAssignedInner_; + sp_truthHitAssignedDirX_ = &truthHitAssignedDirX_; + sp_truthHitAssignedDirY_ = &truthHitAssignedDirY_; + sp_truthHitAssignedDirZ_ = &truthHitAssignedDirZ_; + sp_truthHitAssignedDirEta_ = &truthHitAssignedDirEta_; + sp_truthHitAssignedDepEnergies_ = &truthHitAssignedDepEnergies_; + sp_truthHitAssignedDirR_ = &truthHitAssignedDirR_; + + sp_truthSimclusterIdx_ = &truthSimclusterIdx_; + sp_truthSimclusterPIDs_ = &truthSimclusterPIDs_; + sp_truthSimclusterEnergies_ = &truthSimclusterEnergies_; + sp_truthSimclusterX_ = &truthSimclusterX_; + sp_truthSimclusterY_ = &truthSimclusterY_; + sp_truthSimclusterZ_ = &truthSimclusterZ_; + sp_truthSimclusterEta_ = &truthSimclusterEta_; + sp_truthSimclusterPhi_ = &truthSimclusterPhi_; + sp_truthSimclusterR_ = &truthSimclusterR_; + sp_truthSimclusterInnerWindow_ = &truthSimclusterInnerWindow_; + sp_truthSimclusterT_ = &truthSimclusterT_; + + sp_truthSimclusterDirX_=&truthSimclusterDirY_; + sp_truthSimclusterDirY_=&truthSimclusterDirX_; + sp_truthSimclusterDirZ_=&truthSimclusterDirZ_; + sp_truthSimclusterDirEta_=&truthSimclusterDirEta_; + sp_truthSimclusterDepEnergies_=&truthSimclusterDepEnergies_; + sp_truthSimclusterDirR_=&truthSimclusterDirR_; + + + sp_ticlHitAssignementIdx_ = &ticlHitAssignementIdx_; + sp_ticlHitAssignedEnergies_= &ticlHitAssignedEnergies_; + + sp_windowEta_ = &windowEta_; + sp_windowPhi_ = &windowPhi_; + +} + + + +void NTupleWindow::clear(){ + WindowBase::clear(); //clears rechits etc + + detIDHitAsso_.clear(); + + hitFeatures_.clear(); + recHitEnergy_.clear(); + recHitEta_.clear(); + recHitPhi_.clear(); + recHitTheta_.clear(); + recHitR_.clear(); + recHitX_.clear(); + recHitY_.clear(); + recHitZ_.clear(); + recHitDetID_.clear(); + recHitTime_.clear(); + recHitID_.clear(); + recHitPad_.clear(); + + truthHitFractions_.clear(); + truthHitAssignementIdx_.clear(); + truthHitAssignedEnergies_.clear(); + truthHitAssignedX_.clear(); + truthHitAssignedY_.clear(); + truthHitAssignedZ_.clear(); + truthHitAssignedEta_.clear(); + truthHitAssignedPhi_.clear(); + truthHitAssignedT_.clear(); + truthHitAssignedPIDs_.clear(); + truthHitAssignedInner_.clear(); + truthHitAssignedDirX_.clear(); + truthHitAssignedDirY_.clear(); + truthHitAssignedDirZ_.clear(); + truthHitAssignedDirEta_.clear(); + truthHitAssignedDepEnergies_.clear(); + truthHitAssignedDirR_.clear(); + + truthSimclusterIdx_.clear(); + truthSimclusterPIDs_.clear(); + truthSimclusterEnergies_.clear(); + truthSimclusterX_.clear(); + truthSimclusterY_.clear(); + truthSimclusterZ_.clear(); + truthSimclusterEta_.clear(); + truthSimclusterPhi_.clear(); + truthSimclusterR_.clear(); + truthSimclusterInnerWindow_.clear(); + truthSimclusterT_.clear(); + + truthSimclusterDirY_.clear(); + truthSimclusterDirX_.clear(); + truthSimclusterDirZ_.clear(); + truthSimclusterDirEta_.clear(); + truthSimclusterDepEnergies_.clear(); + truthSimclusterDirR_.clear(); + + + ticlHitAssignementIdx_.clear(); + ticlHitAssignedEnergies_.clear(); + +} + +void NTupleWindow::fillFeatureArrays(){ + //NO CUTS HERE! + WindowBase::fillFeatureArrays(); + createDetIDHitAssociation(); + +} + +void NTupleWindow::fillTruthArrays(){ + + if(ticlHitAssignementIdx_.size() < 1 || recHitEnergy_.size() < 1) + throw std::runtime_error("NTupleWindow::fillTruthArrays: first fill all reco quantities including ticl"); + + auto hits_to_keep = cleanSimclusters(); + calculateSimclusterFeatures(); + calculateTruthFractions(); + fillTruthAssignment(); + + bool keep_all=true; + for(const auto k:hits_to_keep){ + if(!k) + keep_all=false; + if(!keep_all) + break; + } + if(keep_all) + return; + //clean up after all assignments have been done + //hitFeatures_=keepIndices(hitFeatures_,hits_to_keep); // + recHitEnergy_=keepIndices(recHitEnergy_,hits_to_keep); //recHitEnergy_.clear(); + recHitEta_=keepIndices(recHitEta_,hits_to_keep); //recHitEta_.clear(); + recHitPhi_=keepIndices(recHitPhi_,hits_to_keep); //recHitPhi_.clear(); + recHitTheta_=keepIndices(recHitTheta_,hits_to_keep); //recHitTheta_.clear(); + recHitR_=keepIndices(recHitR_,hits_to_keep); //recHitR_.clear(); + recHitX_=keepIndices(recHitX_,hits_to_keep); //recHitX_.clear(); + recHitY_=keepIndices(recHitY_,hits_to_keep); //recHitY_.clear(); + recHitZ_=keepIndices(recHitZ_,hits_to_keep); //recHitZ_.clear(); + recHitDetID_=keepIndices(recHitDetID_,hits_to_keep); //recHitDetID_.clear(); + recHitTime_=keepIndices(recHitTime_,hits_to_keep); //recHitTime_.clear(); + recHitID_=keepIndices(recHitID_,hits_to_keep); //recHitID_.clear(); + recHitPad_=keepIndices(recHitPad_,hits_to_keep); //recHitPad_.clear(); + + + truthHitFractions_=keepIndices(truthHitFractions_,hits_to_keep); //truthHitFractions_.clear(); + truthHitAssignementIdx_=keepIndices(truthHitAssignementIdx_,hits_to_keep); //truthHitAssignementIdx_.clear(); + truthHitAssignedEnergies_=keepIndices(truthHitAssignedEnergies_,hits_to_keep); //truthHitAssignedEnergies_.clear(); + truthHitAssignedX_=keepIndices(truthHitAssignedX_,hits_to_keep); //truthHitAssignedX_.clear(); + truthHitAssignedY_=keepIndices(truthHitAssignedY_,hits_to_keep); //truthHitAssignedY_.clear(); + truthHitAssignedZ_=keepIndices(truthHitAssignedZ_,hits_to_keep); //truthHitAssignedZ_.clear(); + truthHitAssignedEta_=keepIndices(truthHitAssignedEta_,hits_to_keep); //truthHitAssignedEta_.clear(); + truthHitAssignedPhi_=keepIndices(truthHitAssignedPhi_,hits_to_keep); //truthHitAssignedPhi_.clear(); + truthHitAssignedT_=keepIndices(truthHitAssignedT_,hits_to_keep); //truthHitAssignedT_.clear(); + truthHitAssignedPIDs_=keepIndices(truthHitAssignedPIDs_,hits_to_keep); //truthHitAssignedPIDs_.clear(); + truthHitAssignedInner_=keepIndices(truthHitAssignedInner_,hits_to_keep); //truthHitAssignedInner_.clear(); + truthHitAssignedDirX_=keepIndices(truthHitAssignedDirX_,hits_to_keep); //truthHitAssignedDirX_.clear(); + truthHitAssignedDirY_=keepIndices(truthHitAssignedDirY_,hits_to_keep); //truthHitAssignedDirY_.clear(); + truthHitAssignedDirZ_=keepIndices(truthHitAssignedDirZ_,hits_to_keep); //truthHitAssignedDirZ_.clear(); + truthHitAssignedDirEta_=keepIndices(truthHitAssignedDirEta_,hits_to_keep); //truthHitAssignedDirEta_.clear(); + truthHitAssignedDepEnergies_=keepIndices(truthHitAssignedDepEnergies_,hits_to_keep); //truthHitAssignedDepEnergies_.clear(); + truthHitAssignedDirR_=keepIndices(truthHitAssignedDirR_,hits_to_keep); //truthHitAssignedDirR_.clear(); + + ticlHitAssignementIdx_=keepIndices(ticlHitAssignementIdx_,hits_to_keep); + ticlHitAssignedEnergies_=keepIndices(ticlHitAssignedEnergies_,hits_to_keep); +} + +void NTupleWindow::createDetIDHitAssociation(){ + detIDHitAsso_.clear(); + + for(size_t i=0;ihit->detid()]={i,1.}; + } + for(size_t i=0;ipdgId())); + const math::XYZTLorentzVectorF& scimpactpoint = simClusters_.at(i)->impactPoint(); + truthSimclusterX_.push_back(scimpactpoint.X()); + truthSimclusterY_.push_back(scimpactpoint.Y()); + truthSimclusterZ_.push_back(scimpactpoint.Z()); + truthSimclusterEta_.push_back(scimpactpoint.Eta()); + truthSimclusterPhi_.push_back(scimpactpoint.Phi()); + truthSimclusterR_.push_back(scimpactpoint.R()); + + truthSimclusterInnerWindow_.push_back(simClustersInnerWindow_.at(i) ? 1 : 0); + + truthSimclusterT_.push_back(simClusters_.at(i)->impactPoint().T()); + const math::XYZTLorentzVectorF& scimpactmom = simClusters_.at(i)->impactMomentum(); + truthSimclusterEnergies_.push_back(simClusters_.at(i)->p4().E()); + truthSimclusterDirX_.push_back(scimpactmom.X()); + truthSimclusterDirY_.push_back(scimpactmom.Y()); + truthSimclusterDirZ_.push_back(scimpactmom.Z()); + truthSimclusterDirEta_.push_back(scimpactmom.Eta()); + truthSimclusterDirR_.push_back(scimpactmom.R()); + + double dep_energy=0; + const auto& hitsandfracs = simClusters_.at(i)->hits_and_fractions(); + for(const auto& haf: hitsandfracs){ + auto pos = detIDHitAsso_.find(haf.first); + if(pos == detIDHitAsso_.end()) //edges or not included in layer clusters + continue; + int idx = pos->second.first; + float totalfrac = pos->second.second * haf.second; + dep_energy += recHitEnergy_.at(idx) * totalfrac; + } + truthSimclusterDepEnergies_.push_back(dep_energy); + + } +} + +//needs function to match truth tracks + +void NTupleWindow::calculateTruthFractions(){ + + truthHitFractions_.clear(); + truthHitFractions_.resize(hitFeatures_.size(), + std::vector(simClusters_.size(), 0)); //includes tracks + + for (size_t i_sc = 0; i_sc < simClusters_.size(); i_sc++) { + const auto& hitsandfracs = simClusters_.at(i_sc)->hits_and_fractions(); + for(const auto& haf: hitsandfracs){ + auto pos = detIDHitAsso_.find(haf.first); + if(pos == detIDHitAsso_.end()) //edges or not included in layer clusters + continue; + size_t idx = pos->second.first; + float totalfrac = pos->second.second * haf.second; + truthHitFractions_.at(idx).at(i_sc) += totalfrac; //can be more than 1-1 for layer clusters + } + } + + //associate the tracks here, such that they look like hits, simple matching + size_t trackStartIterator = recHits.size(); + + + ////match, will be improved by direct truth matching in new simclusters on longer term + ////assumption: for every track there is a simcluster, given the below-MIP thresholds in the HGCal + ///* + // * + // * this is just a temporary solution until a proper simcluster-simtrack integration exists + // * + // */ + //std::vector usedSimclusters; + + //return ; + + std::vector hassc(tracks_.size(),false); + + const double momentumscaler = 0;//as long as it's unreliable + std::vector scused(simClusters_.size(),false); + for(float minDistance=0.005;minDistance<=0.02;minDistance+=0.005){//rather strict + for(size_t i_t=0;i_timpactMomentum().E(); + double trackMomentum = tracks_.at(i_t)->obj->p(); + double distance = reco::deltaR(simClusters_.at(i_sc)->impactPoint().Eta(), + simClusters_.at(i_sc)->impactPoint().Phi(), + (float)tracks_.at(i_t)->pos.eta(), + (float)tracks_.at(i_t)->pos.phi()) + + momentumscaler*std::abs(scEnergy - trackMomentum)/(scEnergy); + + if(distance pids(n_particle_types,0); + pids.at((int)type_ambiguous) = 1;//default + truthHitAssignedPIDs_.resize(truthHitFractions_.size(), pids); + + truthHitAssignedInner_.resize(truthHitFractions_.size()); + truthHitAssignedDirX_.resize(truthHitFractions_.size()); + truthHitAssignedDirY_.resize(truthHitFractions_.size()); + truthHitAssignedDirZ_.resize(truthHitFractions_.size()); + truthHitAssignedDirEta_.resize(truthHitFractions_.size()); + truthHitAssignedDepEnergies_.resize(truthHitFractions_.size()); + truthHitAssignedDirR_.resize(truthHitFractions_.size()); + + + bool nosim = simClusters_.size() < 1; + + for (size_t i_hit = 0; i_hit < truthHitFractions_.size(); i_hit++) { + + bool allzero = std::all_of(truthHitFractions_.at(i_hit).begin(), + truthHitFractions_.at(i_hit).end(), [](float i) {return i==0;}); + + if(allzero || nosim){ + truthHitAssignementIdx_.at(i_hit) = -1; + continue; + } + size_t maxfrac_idx = std::max_element( + truthHitFractions_.at(i_hit).begin(), + truthHitFractions_.at(i_hit).end()) + - truthHitFractions_.at(i_hit).begin(); + + truthHitAssignementIdx_.at(i_hit) = maxfrac_idx; + truthHitAssignedEnergies_.at(i_hit) = truthSimclusterEnergies_.at( + maxfrac_idx); + truthHitAssignedX_.at(i_hit) = truthSimclusterX_.at(maxfrac_idx); + truthHitAssignedY_.at(i_hit) = truthSimclusterY_.at(maxfrac_idx); + truthHitAssignedZ_.at(i_hit) = truthSimclusterZ_.at(maxfrac_idx); + truthHitAssignedEta_.at(i_hit) = truthSimclusterEta_.at(maxfrac_idx); + truthHitAssignedPhi_.at(i_hit) = truthSimclusterPhi_.at(maxfrac_idx); + truthHitAssignedT_.at(i_hit) = truthSimclusterT_.at(maxfrac_idx); + truthHitAssignedPIDs_.at(i_hit) = truthSimclusterPIDs_.at(maxfrac_idx); + truthHitAssignedDirX_.at(i_hit) = truthSimclusterDirX_.at(maxfrac_idx); + truthHitAssignedDirY_.at(i_hit) = truthSimclusterDirY_.at(maxfrac_idx); + truthHitAssignedDirZ_.at(i_hit) = truthSimclusterDirZ_.at(maxfrac_idx); + truthHitAssignedDirEta_.at(i_hit) = truthSimclusterDirEta_.at(maxfrac_idx); + truthHitAssignedDepEnergies_.at(i_hit) = truthSimclusterDepEnergies_.at(maxfrac_idx); + truthHitAssignedDirR_.at(i_hit) = truthSimclusterDirR_.at(maxfrac_idx); + truthHitAssignedInner_.at(i_hit) = truthSimclusterInnerWindow_.at(maxfrac_idx); + + } +} + + +std::vector NTupleWindow::cleanSimclusters(){ + + auto rh_energycopy = recHitEnergy_; + + + //clean everything that was NOT assigned (for whatever reason) to this window + for(const auto& sc: badSimClusters_){ + float energy=0; + size_t nhits=0; + const auto& hitsandfracs = sc->hits_and_fractions(); + for(const auto& haf: hitsandfracs){ + auto pos = detIDHitAsso_.find(haf.first); + if(pos == detIDHitAsso_.end()) //edges or not included in layer clusters + continue; + size_t idx = pos->second.first; + double thisenergy = rh_energycopy.at(idx) * pos->second.second * haf.second; + recHitEnergy_.at(idx) -= thisenergy; + energy += thisenergy; + nhits++; + if(recHitEnergy_.at(idx)<=1e-9){ + recHitEnergy_.at(idx)=0; + } + } + std::cout << "removed bad sc at eta " << sc->impactPoint().Eta() << ", phi "<< sc->impactPoint().Phi() + << ", depo energy " << energy <<" in "<impactMomentum().E()<< std::endl; + } + + std::cout << "removing hits..." << std::endl; + + std::vector hits_to_keep; + + for(size_t i=0;i0) + hits_to_keep.push_back(true); + else + hits_to_keep.push_back(false); + } + + return hits_to_keep; + + // do not remove bare rechits! they are needed with original index later +// recHits = keepIndices(recHits,hits_to_keep); + + + + + //simclusters are gone and also their energy is gone +} + +void NTupleWindow::fillTiclAssignment(){//last + + + ticlHitAssignementIdx_.resize(recHitEnergy_.size(), -1); + ticlHitAssignedEnergies_.resize(recHitEnergy_.size(), -1); + + + for (size_t it=0;itassohits){ + auto pos = detIDHitAsso_.find(ID); + if(pos == detIDHitAsso_.end()) //not in window + continue; + size_t idx = pos->second.first; + ticlHitAssignementIdx_.at(idx)=it; + ticlHitAssignedEnergies_.at(idx)=ticltracksters_.at(it)->energy; + } + } + +} + diff --git a/RecoHGCal/GraphReco/src/WindowBase.cpp b/RecoHGCal/GraphReco/src/WindowBase.cpp new file mode 100644 index 0000000000000..ac33210f31383 --- /dev/null +++ b/RecoHGCal/GraphReco/src/WindowBase.cpp @@ -0,0 +1,238 @@ +/* + * WindowBase.cpp + * + * Created on: 26 Sep 2019 + * Author: jkiesele + */ + + + + +#include "FWCore/Utilities/interface/Exception.h" +#include "../interface/WindowBase.h" + + + +WindowBase::WindowBase(float centerEta, float centerPhi, float outerRegionDEta, float outerRegionDPhi, + float innerRegionDEta, float innerRegionDPhi) : + + mode_(useLayerClusters), + centerEta_(centerEta),centerPhi_(centerPhi), + outerRegionDEta_(outerRegionDEta),outerRegionDPhi_(outerRegionDPhi), + innerRegionDEta_(innerRegionDEta), innerRegionDPhi_( + innerRegionDPhi) { + + //sanity checks FIXME: add more + if (innerRegionDEta_ <= 0 || innerRegionDPhi_ <= 0) { + throw cms::Exception("IncorrectWindowParameters") + << "innerRegionDEta,innerRegionDPhi must be > 0"; + } + if (innerRegionDEta_ > outerRegionDEta_ || innerRegionDPhi_ > outerRegionDPhi_) { + throw cms::Exception("IncorrectWindowParameters") + << "innerRegionDEta,innerRegionDPhi must be <= outerRegionDEta, outerRegionDPhi"; + } + if(nTrackFeatures_ != nRechitFeatures_ || nTrackFeatures_ != nLayerClusterFeatures_){ + throw cms::Exception("IncorrectWindowParameters") + << "number of track, rechit and layer cluster features must be the same"; + } + +} + + +WindowBase::~WindowBase() { + clear(); +} + + +void WindowBase::clear() { + // this class does not own anything + tracks_.clear(); + recHits.clear(); + layerClusters_.clear(); + simClusters_.clear(); + badSimClusters_.clear(); + ticltracksters_.clear(); + hitFeatures_.clear(); +} + + + +//// private //// + +/* + * recHitEnergy, + recHitEta , + recHitID, #indicator if it is track or not + recHitTheta , + recHitR , + recHitX , + recHitY , + recHitZ , + recHitTime + */ + + +const size_t WindowBase::nTrackFeatures_=9; +void WindowBase::fillTrackFeatures(float*& data, const TrackWithHGCalPos * t) const { + *(data++) = t->obj->p(); + *(data++) = t->pos.eta(); + *(data++) = -1.; //"detid" + *(data++) = t->pos.theta(); + *(data++) = t->pos.mag(); + *(data++) = t->pos.x(); + *(data++) = t->pos.y(); + *(data++) = t->pos.z(); + *(data++) = t->obj->chi2(); +} + +/* + * recHitEnergy, + recHitEta , + recHitID, #indicator if it is track or not + recHitTheta , + recHitR , + recHitX , + recHitY , + recHitZ , + recHitTime + */ + +const size_t WindowBase::nRechitFeatures_=9; +void WindowBase::fillRecHitFeatures(float*& data, const HGCRecHitWithPos * recHit) const { + *(data++) = recHit->hit->energy(); + *(data++) = recHit->pos.eta(); + *(data++) = 0; //ID track or not + *(data++) = recHit->pos.theta(); + *(data++) = recHit->pos.mag(); + *(data++) = recHit->pos.x(); + *(data++) = recHit->pos.y(); + *(data++) = recHit->pos.z(); + *(data++) = recHit->hit->time(); +} + + +const size_t WindowBase::nLayerClusterFeatures_=9; +void WindowBase::fillLayerClusterFeatures(float*& data, const reco::CaloCluster * cl) const { + throw std::runtime_error("WindowBase::fillLayerClusterFeatures: LC not supported anymore"); +} + +void WindowBase::fillFeatureArrays(){ + //NO CUTS HERE! + + hitFeatures_.clear(); + if(getMode() == useRechits){ + for(const auto& rh:recHits){ + std::vector feats(nRechitFeatures_); + auto data = &feats.at(0); + fillRecHitFeatures(data,rh); + hitFeatures_.push_back(feats); + } + } + else{ + for(const auto& lc: layerClusters_){ + std::vector feats(nLayerClusterFeatures_); + auto data = &feats.at(0); + fillLayerClusterFeatures(data,lc); + hitFeatures_.push_back(feats); + } + } + + //return; + //add tracks LAST! + for(const auto& tr:tracks_){ + std::vector feats(nTrackFeatures_); + auto data = &feats.at(0); + fillTrackFeatures(data,tr); + hitFeatures_.push_back(feats); + } + + + +} + +WindowBase::particle_type WindowBase::pdgToParticleType(int pdgid)const{ + + /* + * enum particle_type{ + type_ambiguous, + type_electron, + type_photon, + type_mip, + type_charged_hadron, + type_neutral_hadron, + n_particle_types + }; + */ + if(pdgid == 0) + return type_ambiguous; + if(pdgid == 13 || pdgid == -13) + return type_electron; + if(pdgid == 22) + return type_photon; + if(pdgid == 13 || pdgid == -13) + return type_mip; + if (pdgid == 211 || pdgid == -211 || pdgid == 321 || pdgid == -321) //to be extended + return type_charged_hadron; + + return type_neutral_hadron; + +} + +std::vector WindowBase::particleTypeToOneHot(particle_type ptype) const{ + std::vector out((int)n_particle_types,0); + out.at((int)ptype) = 1.; + return out; +} + +WindowBase::particle_type WindowBase::oneHotToParticleType(const std::vector& v) const{ + int idx=-1; + for(int i=0;i<(int)v.size();i++){ + if(v.at(i)){ + idx=i; + break; + } + } + if(idx >= (int)n_particle_types) + throw std::out_of_range("WindowBase::oneHotToParticleType: input vector has wrong size"); + return (particle_type)idx; +} + +WindowBase::particle_type WindowBase::predictionToParticleType(const float * pred) const{ + int maxidx=-1; + float maxval=-1; + for(int i=0;i<(int)n_particle_types;i++){ + if(maxval WindowBase::pdgToOneHot(int pdgid) const{ + return particleTypeToOneHot(pdgToParticleType(pdgid) ); +} + + + +void WindowBase::printDebug()const{ + DEBUGPRINT(centerPhi_); + DEBUGPRINT(centerEta_); + DEBUGPRINT(outerRegionDEta_); + DEBUGPRINT(outerRegionDPhi_); + DEBUGPRINT(innerRegionDEta_); + DEBUGPRINT(innerRegionDPhi_); + std::cout << "coverage phi " << centerPhi_-outerRegionDPhi_ << "| " << centerPhi_-innerRegionDPhi_ << "[ :" << + centerPhi_ << ": ]" << centerPhi_+innerRegionDPhi_ << " |" << centerPhi_ + outerRegionDPhi_ << std::endl; + std::cout << "coverage eta " << centerEta_-outerRegionDEta_ << "| " << centerEta_-innerRegionDEta_ << "[ :" << + centerEta_ << ": ]" << centerEta_+innerRegionDEta_ << " |" << centerEta_+outerRegionDEta_ << std::endl; +} + + + +/// static + + + + diff --git a/RecoHGCal/GraphReco/src/classes.h b/RecoHGCal/GraphReco/src/classes.h new file mode 100644 index 0000000000000..e7f7d93b4f8ff --- /dev/null +++ b/RecoHGCal/GraphReco/src/classes.h @@ -0,0 +1,26 @@ +/* + * classes.h + * + * Created on: 27 Sep 2019 + * Author: jkiesele + */ + +#ifndef SRC_RECOHGCAL_GRAPHRECO_SRC_CLASSES_H_ +#define SRC_RECOHGCAL_GRAPHRECO_SRC_CLASSES_H_ + +#include +namespace +{ + struct dictionary_dataformats { + std::vector dummy1; + std::vector > dummy2; + std::vector > > dummy3; + std::vector dummy4; + std::vector > dummy5; + std::vector > > dummy6; + }; +} + + + +#endif /* SRC_RECOHGCAL_GRAPHRECO_SRC_CLASSES_H_ */ diff --git a/RecoHGCal/GraphReco/src/classes_def.xml b/RecoHGCal/GraphReco/src/classes_def.xml new file mode 100644 index 0000000000000..6cf963513f6d8 --- /dev/null +++ b/RecoHGCal/GraphReco/src/classes_def.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/RecoHGCal/GraphReco/test/GSD_GUN.py b/RecoHGCal/GraphReco/test/GSD_GUN.py new file mode 100644 index 0000000000000..b672c6f49769d --- /dev/null +++ b/RecoHGCal/GraphReco/test/GSD_GUN.py @@ -0,0 +1,306 @@ +# coding: utf-8 + +import os +import math + +import FWCore.ParameterSet.Config as cms +from FWCore.ParameterSet.VarParsing import VarParsing + +###### config from runTheMatrix + +from Configuration.Eras.Era_Phase2C9_cff import Phase2C9 + +process = cms.Process('HLT',Phase2C9) + +# import of standard configurations +process.load('Configuration.StandardSequences.Services_cff') +process.load('SimGeneral.HepPDTESSource.pythiapdt_cfi') +process.load('FWCore.MessageService.MessageLogger_cfi') +process.load('Configuration.EventContent.EventContent_cff') +process.load('SimGeneral.MixingModule.mix_POISSON_average_cfi') +process.load('Configuration.Geometry.GeometryExtended2026D49Reco_cff') +process.load('Configuration.Geometry.GeometryExtended2026D49_cff') +process.load('Configuration.StandardSequences.MagneticField_cff') +process.load('Configuration.StandardSequences.Generator_cff') +process.load('Configuration.StandardSequences.VtxSmearedNoSmear_cff') +process.load('GeneratorInterface.Core.genFilterSummary_cff') +process.load('Configuration.StandardSequences.SimIdeal_cff') +process.load('Configuration.StandardSequences.Digi_cff') +process.load('Configuration.StandardSequences.SimL1Emulator_cff') +process.load('Configuration.StandardSequences.L1TrackTrigger_cff') +process.load('Configuration.StandardSequences.DigiToRaw_cff') +process.load('HLTrigger.Configuration.HLT_Fake2_cff') +process.load('Configuration.StandardSequences.EndOfProcess_cff') +process.load('Configuration.StandardSequences.FrontierConditions_GlobalTag_cff') + +process.maxEvents = cms.untracked.PSet( + input = cms.untracked.int32(10), + output = cms.optional.untracked.allowed(cms.int32,cms.PSet) +) + +# Input source +process.source = cms.Source("EmptySource") + +process.options = cms.untracked.PSet( + FailPath = cms.untracked.vstring(), + IgnoreCompletely = cms.untracked.vstring(), + Rethrow = cms.untracked.vstring(), + SkipEvent = cms.untracked.vstring(), + allowUnscheduled = cms.obsolete.untracked.bool, + canDeleteEarly = cms.untracked.vstring(), + emptyRunLumiMode = cms.obsolete.untracked.string, + eventSetup = cms.untracked.PSet( + forceNumberOfConcurrentIOVs = cms.untracked.PSet( + + ), + numberOfConcurrentIOVs = cms.untracked.uint32(1) + ), + fileMode = cms.untracked.string('FULLMERGE'), + forceEventSetupCacheClearOnNewRun = cms.untracked.bool(False), + makeTriggerResults = cms.obsolete.untracked.bool, + numberOfConcurrentLuminosityBlocks = cms.untracked.uint32(1), + numberOfConcurrentRuns = cms.untracked.uint32(1), + numberOfStreams = cms.untracked.uint32(0), + numberOfThreads = cms.untracked.uint32(1), + printDependencies = cms.untracked.bool(False), + sizeOfStackForThreadsInKB = cms.optional.untracked.uint32, + throwIfIllegalParameter = cms.untracked.bool(True), + wantSummary = cms.untracked.bool(False) +) + +# Production Info +process.configurationMetadata = cms.untracked.PSet( + annotation = cms.untracked.string('TTbar_14TeV_TuneCP5_cfi nevts:10'), + name = cms.untracked.string('Applications'), + version = cms.untracked.string('$Revision: 1.19 $') +) + +# Output definition + +process.FEVTDEBUGoutput = cms.OutputModule("PoolOutputModule", + SelectEvents = cms.untracked.PSet( + SelectEvents = cms.vstring('generation_step') + ), + dataset = cms.untracked.PSet( + dataTier = cms.untracked.string('GEN-SIM'), + filterName = cms.untracked.string('') + ), + fileName = cms.untracked.string('TTbar_14TeV_TuneCP5_cfi_GEN_SIM_DIGI_L1_L1TrackTrigger_DIGI2RAW_HLT_PU.root'), + outputCommands = process.FEVTDEBUGEventContent.outputCommands, + splitLevel = cms.untracked.int32(0) +) + +# Additional output definition + +# Other statements +process.mix.input.nbPileupEvents.averageNumber = cms.double(200.000000) +process.mix.bunchspace = cms.int32(25) +process.mix.minBunch = cms.int32(-3) +process.mix.maxBunch = cms.int32(3) +process.genstepfilter.triggerConditions=cms.vstring("generation_step") +process.mix.digitizers = cms.PSet(process.theDigitizersValid) +from Configuration.AlCa.GlobalTag import GlobalTag +process.GlobalTag = GlobalTag(process.GlobalTag, 'auto:phase2_realistic_T15', '') + +process.generator = cms.EDFilter("Pythia8GeneratorFilter", + PythiaParameters = cms.PSet( + parameterSets = cms.vstring( + 'pythia8CommonSettings', + 'pythia8CP5Settings', + 'processParameters' + ), + processParameters = cms.vstring( + 'Top:gg2ttbar = on ', + 'Top:qqbar2ttbar = on ', + '6:m0 = 175 ' + ), + pythia8CP5Settings = cms.vstring( + 'Tune:pp 14', + 'Tune:ee 7', + 'MultipartonInteractions:ecmPow=0.03344', + 'MultipartonInteractions:bProfile=2', + 'MultipartonInteractions:pT0Ref=1.41', + 'MultipartonInteractions:coreRadius=0.7634', + 'MultipartonInteractions:coreFraction=0.63', + 'ColourReconnection:range=5.176', + 'SigmaTotal:zeroAXB=off', + 'SpaceShower:alphaSorder=2', + 'SpaceShower:alphaSvalue=0.118', + 'SigmaProcess:alphaSvalue=0.118', + 'SigmaProcess:alphaSorder=2', + 'MultipartonInteractions:alphaSvalue=0.118', + 'MultipartonInteractions:alphaSorder=2', + 'TimeShower:alphaSorder=2', + 'TimeShower:alphaSvalue=0.118', + 'SigmaTotal:mode = 0', + 'SigmaTotal:sigmaEl = 21.89', + 'SigmaTotal:sigmaTot = 100.309', + 'PDF:pSet=LHAPDF6:NNPDF31_nnlo_as_0118' + ), + pythia8CommonSettings = cms.vstring( + 'Tune:preferLHAPDF = 2', + 'Main:timesAllowErrors = 10000', + 'Check:epTolErr = 0.01', + 'Beams:setProductionScalesFromLHEF = off', + 'SLHA:keepSM = on', + 'SLHA:minMassSM = 1000.', + 'ParticleDecays:limitTau0 = on', + 'ParticleDecays:tau0Max = 10', + 'ParticleDecays:allowPhotonRadiation = on' + ) + ), + comEnergy = cms.double(14000.0), + filterEfficiency = cms.untracked.double(1.0), + maxEventsToPrint = cms.untracked.int32(0), + pythiaHepMCVerbosity = cms.untracked.bool(False), + pythiaPylistVerbosity = cms.untracked.int32(0) +) + + +process.ProductionFilterSequence = cms.Sequence(process.generator) + +# Path and EndPath definitions +process.generation_step = cms.Path(process.pgen) +process.simulation_step = cms.Path(process.psim) +process.digitisation_step = cms.Path(process.pdigi_valid) +process.L1simulation_step = cms.Path(process.SimL1Emulator) +process.L1TrackTrigger_step = cms.Path(process.L1TrackTrigger) +process.digi2raw_step = cms.Path(process.DigiToRaw) +process.genfiltersummary_step = cms.EndPath(process.genFilterSummary) +process.endjob_step = cms.EndPath(process.endOfProcess) +process.FEVTDEBUGoutput_step = cms.EndPath(process.FEVTDEBUGoutput) + +# Schedule definition +process.schedule = cms.Schedule(process.generation_step,process.genfiltersummary_step,process.simulation_step,process.digitisation_step,process.L1simulation_step,process.L1TrackTrigger_step,process.digi2raw_step) +process.schedule.extend(process.HLTSchedule) +process.schedule.extend([process.endjob_step,process.FEVTDEBUGoutput_step]) +from PhysicsTools.PatAlgos.tools.helpers import associatePatAlgosToolsTask +associatePatAlgosToolsTask(process) +# filter all path with the production filter sequence +for path in process.paths: + getattr(process,path).insert(0, process.ProductionFilterSequence) + +# customisation of the process. + +# Automatic addition of the customisation function from HLTrigger.Configuration.customizeHLTforMC +from HLTrigger.Configuration.customizeHLTforMC import customizeHLTforMC + +#call to customisation function customizeHLTforMC imported from HLTrigger.Configuration.customizeHLTforMC +process = customizeHLTforMC(process) + +# End of customisation functions + +# Customisation from command line + +# Add early deletion of temporary data products to reduce peak memory need +from Configuration.StandardSequences.earlyDeleteSettings_cff import customiseEarlyDelete +process = customiseEarlyDelete(process) +# End adding early deletion + + + + + + + +# option parsing +options = VarParsing('python') +options.setDefault('outputFile', 'file:partGun_PDGid22_x96_Pt1.0To100.0_GSD_1.root') +options.setDefault('maxEvents', 1) +options.register("pileup", 0, VarParsing.multiplicity.singleton, VarParsing.varType.int, + "pileup") +options.register("seed", 1, VarParsing.multiplicity.singleton, VarParsing.varType.int, + "random seed") +options.register( + 'EminFineTrack', + 10000., + VarParsing.multiplicity.singleton, + VarParsing.varType.float, + "Minimum energy in MeV for which secondary tracks in Calo will be saved" + ) +options.register( + 'EminFinePhoton', + 500., + VarParsing.multiplicity.singleton, + VarParsing.varType.float, + "Minimum energy in MeV for which secondary photons in Calo will be saved" + ) +options.register("doFineCalo", 0, VarParsing.multiplicity.singleton, VarParsing.varType.int, + "turn do fineCalo on/off") +options.register("storeHGCBoundaryCross", 1, VarParsing.multiplicity.singleton, VarParsing.varType.int, + "turn do StoreHGCBoundarCross on/off") +options.parseArguments() + +process.maxEvents.input = cms.untracked.int32(options.maxEvents) + +seed = int(options.seed)+1 +# random seeds +process.RandomNumberGeneratorService.generator.initialSeed = cms.untracked.uint32(seed) +process.RandomNumberGeneratorService.VtxSmeared.initialSeed = cms.untracked.uint32(seed) +process.RandomNumberGeneratorService.mix.initialSeed = cms.untracked.uint32(seed) + +# Input source +process.source.firstLuminosityBlock = cms.untracked.uint32(seed) + +# Output definition +process.FEVTDEBUGoutput.fileName = cms.untracked.string( + options.__getattr__("outputFile", noTags=True)) + +process.FEVTDEBUGoutput.outputCommands.append("keep *_*G4*_*_*") + +# helper +def calculate_rho(z, eta): + return z * math.tan(2 * math.atan(math.exp(-eta))) + + +process.generator = cms.EDProducer("FlatEtaRangeGunProducer", + # particle ids + #particleIDs=cms.vint32(22,22,11,-11,211,-211,13,-13), + particleIDs=cms.vint32(22), + # max number of particles to shoot at a time + nParticles=cms.int32(1), + # shoot exactly the particles defined in particleIDs in that order + exactShoot=cms.bool(False), + # randomly shoot [1, nParticles] particles, each time randomly drawn from particleIDs + randomShoot=cms.bool(False), + # energy range + eMin=cms.double(3.0), + eMax=cms.double(100.0), + # phi range + phiMin=cms.double(-math.pi), + phiMax=cms.double(math.pi), + # eta range + etaMin=cms.double(1.52), + etaMax=cms.double(3.00), + + debug=cms.untracked.bool(True), +) + +# Options for saving fine hits +process.g4SimHits.CaloSD.StoreHGCBoundaryCross = cms.bool(bool(options.storeHGCBoundaryCross)) +# Seems to be an interplay between hgcboundaryCross and fineCaloID +process.g4SimHits.CaloSD.UseFineCaloID = cms.bool(bool(options.storeHGCBoundaryCross+options.doFineCalo)) +process.g4SimHits.CaloTrkProcessing.DoFineCalo = cms.bool(bool(options.doFineCalo)) +process.g4SimHits.CaloTrkProcessing.EminFineTrack = cms.double(options.EminFineTrack) +process.g4SimHits.CaloTrkProcessing.EminFinePhoton = cms.double(options.EminFinePhoton) + + +#load and configure the appropriate pileup modules +if options.pileup > 0: + process.load("SimGeneral.MixingModule.mix_POISSON_average_cfi") + process.mix.input.nbPileupEvents.averageNumber = cms.double(options.pileup) + # process.mix.input.fileNames = cms.untracked.vstring(["/store/relval/CMSSW_10_6_0_patch2/RelValMinBias_14TeV/GEN-SIM/106X_upgrade2023_realistic_v3_2023D41noPU-v1/10000/F7FE3FE9-565B-544A-855E-902BA4E3C5FD.root', '/store/relval/CMSSW_10_6_0_patch2/RelValMinBias_14TeV/GEN-SIM/106X_upgrade2023_realistic_v3_2023D41noPU-v1/10000/82584FBA-A1E6-DF48-99BA-B1759C3A190F.root', '/store/relval/CMSSW_10_6_0_patch2/RelValMinBias_14TeV/GEN-SIM/106X_upgrade2023_realistic_v3_2023D41noPU-v1/10000/F806295A-492F-EF4F-9D91-15DA8769DD72.root', '/store/relval/CMSSW_10_6_0_patch2/RelValMinBias_14TeV/GEN-SIM/106X_upgrade2023_realistic_v3_2023D41noPU-v1/10000/6FCA2E1D-D1E2-514B-8ABA-5B71A2C1E1B3.root', '/store/relval/CMSSW_10_6_0_patch2/RelValMinBias_14TeV/GEN-SIM/106X_upgrade2023_realistic_v3_2023D41noPU-v1/10000/287275CC-953A-0C4C-B352-E39EC2D571F0.root', '/store/relval/CMSSW_10_6_0_patch2/RelValMinBias_14TeV/GEN-SIM/106X_upgrade2023_realistic_v3_2023D41noPU-v1/10000/657065A5-F35B-3147-AED9-E4ACA915C982.root', '/store/relval/CMSSW_10_6_0_patch2/RelValMinBias_14TeV/GEN-SIM/106X_upgrade2023_realistic_v3_2023D41noPU-v1/10000/2C56BC73-5687-674C-8684-6C785A88DB78.root', '/store/relval/CMSSW_10_6_0_patch2/RelValMinBias_14TeV/GEN-SIM/106X_upgrade2023_realistic_v3_2023D41noPU-v1/10000/B96F4064-156C-5E47-90A0-07475310157A.root', '/store/relval/CMSSW_10_6_0_patch2/RelValMinBias_14TeV/GEN-SIM/106X_upgrade2023_realistic_v3_2023D41noPU-v1/10000/2564B36D-A0DB-6C42-9105-B1CFF44F311D.root', '/store/relval/CMSSW_10_6_0_patch2/RelValMinBias_14TeV/GEN-SIM/106X_upgrade2023_realistic_v3_2023D41noPU-v1/10000/2CB8C960-47C0-1A40-A9F7-0B62987097E0.root"]) # noqa: E501 + local_pu_dir = "/eos/user/m/mrieger/data/hgc/RelvalMinBias14" + process.mix.input.fileNames = cms.untracked.vstring([ + "file://" + os.path.abspath(os.path.join(local_pu_dir, elem)) + for elem in os.listdir(local_pu_dir) + if elem.endswith(".root") + ]) +else: + process.load("SimGeneral.MixingModule.mixNoPU_cfi") + process.mix.digitizers = cms.PSet(process.theDigitizersValid) + # I don't think this matters, but just to be safe... + process.mix.bunchspace = cms.int32(25) + process.mix.minBunch = cms.int32(-3) + process.mix.maxBunch = cms.int32(3) + diff --git a/RecoHGCal/GraphReco/test/RECO_pf.py b/RecoHGCal/GraphReco/test/RECO_pf.py new file mode 100644 index 0000000000000..87654bbe014f5 --- /dev/null +++ b/RecoHGCal/GraphReco/test/RECO_pf.py @@ -0,0 +1,178 @@ +# coding: utf-8 +import os + +import FWCore.ParameterSet.Config as cms +from FWCore.ParameterSet.VarParsing import VarParsing +from Configuration.Eras.Era_Phase2C9_cff import Phase2C9 + +process = cms.Process('RECO',Phase2C9) + +# import of standard configurations +process.load('Configuration.StandardSequences.Services_cff') +process.load('SimGeneral.HepPDTESSource.pythiapdt_cfi') +process.load('FWCore.MessageService.MessageLogger_cfi') +process.load('Configuration.EventContent.EventContent_cff') +process.load('SimGeneral.MixingModule.mix_POISSON_average_cfi') +process.load('Configuration.Geometry.GeometryExtended2026D49Reco_cff') +process.load('Configuration.StandardSequences.MagneticField_cff') +process.load('Configuration.StandardSequences.RawToDigi_cff') +process.load('Configuration.StandardSequences.L1Reco_cff') +process.load('Configuration.StandardSequences.Reconstruction_cff') +process.load('Configuration.StandardSequences.RecoSim_cff') +process.load('Configuration.StandardSequences.EndOfProcess_cff') +process.load('Configuration.StandardSequences.FrontierConditions_GlobalTag_cff') + +process.maxEvents = cms.untracked.PSet( + input = cms.untracked.int32(10), + output = cms.optional.untracked.allowed(cms.int32,cms.PSet) +) + +# Input source +process.source = cms.Source("PoolSource", + fileNames = cms.untracked.vstring('file:step3_DIGI2RAW.root'), + secondaryFileNames = cms.untracked.vstring() +) + +process.options = cms.untracked.PSet( + FailPath = cms.untracked.vstring(), + IgnoreCompletely = cms.untracked.vstring(), + Rethrow = cms.untracked.vstring(), + SkipEvent = cms.untracked.vstring(), + allowUnscheduled = cms.obsolete.untracked.bool, + canDeleteEarly = cms.untracked.vstring(), + emptyRunLumiMode = cms.obsolete.untracked.string, + eventSetup = cms.untracked.PSet( + forceNumberOfConcurrentIOVs = cms.untracked.PSet( + + ), + numberOfConcurrentIOVs = cms.untracked.uint32(1) + ), + fileMode = cms.untracked.string('FULLMERGE'), + forceEventSetupCacheClearOnNewRun = cms.untracked.bool(False), + makeTriggerResults = cms.obsolete.untracked.bool, + numberOfConcurrentLuminosityBlocks = cms.untracked.uint32(1), + numberOfConcurrentRuns = cms.untracked.uint32(1), + numberOfStreams = cms.untracked.uint32(0), + numberOfThreads = cms.untracked.uint32(1), + printDependencies = cms.untracked.bool(False), + sizeOfStackForThreadsInKB = cms.optional.untracked.uint32, + throwIfIllegalParameter = cms.untracked.bool(True), + wantSummary = cms.untracked.bool(False) +) + +# Production Info +process.configurationMetadata = cms.untracked.PSet( + annotation = cms.untracked.string('step3 nevts:10'), + name = cms.untracked.string('Applications'), + version = cms.untracked.string('$Revision: 1.19 $') +) + +# Output definition + +process.FEVTDEBUGoutput = cms.OutputModule("PoolOutputModule", + dataset = cms.untracked.PSet( + dataTier = cms.untracked.string('GEN-SIM-RECO'), + filterName = cms.untracked.string('') + ), + fileName = cms.untracked.string('step3_RAW2DIGI_L1Reco_RECO_RECOSIM_PU.root'), + outputCommands = process.FEVTDEBUGEventContent.outputCommands, + splitLevel = cms.untracked.int32(0) +) + +# Additional output definition + +# Other statements +process.mix.input.nbPileupEvents.averageNumber = cms.double(200.000000) +process.mix.bunchspace = cms.int32(25) +process.mix.minBunch = cms.int32(-3) +process.mix.maxBunch = cms.int32(3) +from Configuration.AlCa.GlobalTag import GlobalTag +process.GlobalTag = GlobalTag(process.GlobalTag, 'auto:phase2_realistic_T15', '') + +# Path and EndPath definitions +process.raw2digi_step = cms.Path(process.RawToDigi) +process.L1Reco_step = cms.Path(process.L1Reco) +process.reconstruction_step = cms.Path(process.reconstruction) +process.recosim_step = cms.Path(process.recosim) +process.endjob_step = cms.EndPath(process.endOfProcess) +process.FEVTDEBUGoutput_step = cms.EndPath(process.FEVTDEBUGoutput) + +# Schedule definition +process.schedule = cms.Schedule(process.raw2digi_step,process.L1Reco_step,process.reconstruction_step,process.recosim_step,process.endjob_step,process.FEVTDEBUGoutput_step) +from PhysicsTools.PatAlgos.tools.helpers import associatePatAlgosToolsTask +associatePatAlgosToolsTask(process) + +#do not add changes to your config after this point (unless you know what you are doing) +from FWCore.ParameterSet.Utilities import convertToUnscheduled +process=convertToUnscheduled(process) + + +# Customisation from command line + +#Have logErrorHarvester wait for the same EDProducers to finish as those providing data for the OutputModule +from FWCore.Modules.logErrorHarvester_cff import customiseLogErrorHarvesterUsingOutputCommands +process = customiseLogErrorHarvesterUsingOutputCommands(process) + +# Add early deletion of temporary data products to reduce peak memory need +from Configuration.StandardSequences.earlyDeleteSettings_cff import customiseEarlyDelete +process = customiseEarlyDelete(process) +# End adding early deletion + +# option parsing +options = VarParsing('python') +options.setDefault('outputFile', 'file:partGun_PDGid22_x96_Pt1.0To100.0_RECO_1.root') +options.setDefault('inputFiles', "file://partGun_PDGid22_x96_Pt1.0To100.0_GSD_1.root") +options.setDefault('maxEvents', -1) +options.register('outputFileDQM', 'file:partGun_PDGid22_x96_Pt1.0To100.0_DQM_1.root', + VarParsing.multiplicity.singleton, VarParsing.varType.string, 'path to the DQM output file') +options.parseArguments() + +process.maxEvents.input = cms.untracked.int32(options.maxEvents) + + +# pepr PF candidate producer +process.load("RecoHGCal.GraphReco.peprCandidateFromHitProducer_cfi") +process.reconstruction_step += process.peprCandidateFromHitProducer + + +process.load("SimTracker.TrackAssociation.trackingParticleRecoTrackAsssociation_cfi") +# append the HGCTruthProducer to the recosim step +process.hgcSimTruth = cms.EDProducer("HGCTruthProducer", +) +process.trackingParticleMergedSCAssociation = cms.EDProducer("TrackingParticleSimClusterAssociationProducer", + simClusters = cms.InputTag("mix:MergedCaloTruth"), + trackingParticles= cms.InputTag("mix:MergedTrackTruth") + +) + +process.trackingParticleSimClusterAssociation = cms.EDProducer("TrackingParticleSimClusterAssociationProducer", + #simClusters = cms.InputTag("mix:MergedCaloTruth"), + simClusters = cms.InputTag("hgcSimTruth"), + trackingParticles= cms.InputTag("mix:MergedTrackTruth") + +) +process.recosim_step *= process.hgcSimTruth +process.recosim_step *= process.trackingParticleRecoTrackAsssociation +process.recosim_step *= process.trackingParticleSimClusterAssociation +process.recosim_step *= process.trackingParticleMergedSCAssociation + +#process.dump=cms.EDAnalyzer('EventContentAnalyzer') +#process.recosim_step += process.dump + +# Input source +process.source.fileNames = cms.untracked.vstring(options.inputFiles) + +# Output definition +process.FEVTDEBUGoutput.fileName = cms.untracked.string( + options.__getattr__("outputFile", noTags=True)) +process.FEVTDEBUGoutput.outputCommands.append("keep *_*G4*_*_*") +process.FEVTDEBUGoutput.outputCommands.append("keep *_trackingParticleRecoTrackAsssociation_*_*") +process.FEVTDEBUGoutput.outputCommands.append("keep *_MergedTrackTruth_*_*") +process.FEVTDEBUGoutput.outputCommands.append("keep *_hgcSimTruth_*_*") +process.FEVTDEBUGoutput.outputCommands.append("keep *_trackingParticleSimClusterAssociation_*_*") +process.FEVTDEBUGoutput.outputCommands.append("keep *_trackingParticleMergedSCAssociation_*_*") +process.FEVTDEBUGoutput.outputCommands.append("keep *_peprCandidateFromHitProducer_*_*") + +if hasattr(process, "DQMoutput"): + process.DQMoutput.fileName = cms.untracked.string(options.outputFileDQM) + diff --git a/RecoHGCal/GraphReco/test/cmssw_oc_forward_client.sh b/RecoHGCal/GraphReco/test/cmssw_oc_forward_client.sh new file mode 100755 index 0000000000000..e8bb3d1d445e5 --- /dev/null +++ b/RecoHGCal/GraphReco/test/cmssw_oc_forward_client.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# if [[ ! $1 ]] +# then +# echo "please specify a pipe name" +# exit -1 +# fi +if [[ $# -ne 2 ]] +then +echo "please specify a pipe name and a filename to store the container PID" +exit -1 +fi + + +#wait for server + +fifo_location="/dev/shm/${1}" +server=dockerbuild.cern.ch +port=8001 +containerpid_location="/dev/shm/${2}" + +#wait for server to be available +check=`nc -vz ${server} 8001 2>&1 | grep "Connected to"` +while [[ ! $check ]] +do +sleep 1 +check=`nc -vz ${server} 8001 2>&1 | grep "Connected to"` +done + +#clean pipes + + +sys_rm=`which rm` + +function finish { +$sys_rm -f $fifo_location "${fifo_location}_pred" +$sys_rm -f $containerpid_location +} +finish + +trap finish EXIT SIGHUP SIGKILL SIGTERM + +echo "server found... connecting to triton" +sing=`which singularity` +unset PATH +cd + +$sing run \ + -B/eos/home-j/jkiesele/singularity/triton/oc_client:/oc_client \ + /eos/home-j/jkiesele/singularity/triton/tritonserver_20.08-py3-clientsdk.sif \ + python /oc_client/triton_forward_client.py -u $server:$port -f $fifo_location -m hgcal_oc_reco & + +echo $! > $containerpid_location + +wait + + +finish + diff --git a/RecoHGCal/GraphReco/test/create_dummy_graph.py b/RecoHGCal/GraphReco/test/create_dummy_graph.py new file mode 100644 index 0000000000000..f87d34d5c20eb --- /dev/null +++ b/RecoHGCal/GraphReco/test/create_dummy_graph.py @@ -0,0 +1,52 @@ +# coding: utf-8 + +""" +Test script to create a dummy graph whose inputs and outputs resemble those of +a fully fletched graph network. The input is a batch of lists of up to 100 RecHits with +10 features per hit (energy, eta, phi, theta, r, x, y, z, detId, time), i.e., (-1, 100, 10). +The output is a vector of 15 energy fractions per hit, i.e., (-1, 100, 15). + +Usage: + +> python create_dummy_graph.py +""" + + +import os +import sys +import tensorflow as tf + + +# for one positional argument, use plain argv +if len(sys.argv) < 2: + this_file = os.path.basename(__file__) + print("usage: python {} ".format(this_file)) + sys.exit(1) + +# expand and normalize the output path +output_path = os.path.expandvars(os.path.expanduser(sys.argv[1])) +output_path = os.path.normpath(os.path.abspath(output_path)) +print("create dummy graph at {}".format(output_path)) + +# shape constants +n_rechits = 100 +n_features = 10 +n_showers = 15 + +# create the dummy graph +x_t = tf.placeholder(tf.float32, [None, n_rechits, n_features], name="input") +x_reshaped_t = tf.reshape(x_t, [-1, n_rechits * n_features]) +W_t = tf.Variable(0.01 * tf.ones([n_rechits * n_features, n_rechits * n_showers], tf.float32)) +b_t = tf.Variable(0.01 * tf.ones([n_rechits * n_showers], tf.float32)) +z_t = tf.add(tf.matmul(x_reshaped_t, W_t), b_t) +y_t = tf.reshape(z_t, [-1, n_rechits, n_showers], name="output") + +# initialize session and variables +sess = tf.Session() +sess.run(tf.global_variables_initializer()) + +# create and save the const graph +outputs = ["output"] +constant_graph = tf.graph_util.convert_variables_to_constants( + sess, sess.graph.as_graph_def(), outputs) +tf.train.write_graph(constant_graph, *os.path.split(output_path), as_text=False) diff --git a/RecoHGCal/GraphReco/test/windowInference_cfg.py b/RecoHGCal/GraphReco/test/windowInference_cfg.py new file mode 100644 index 0000000000000..873959fce5faf --- /dev/null +++ b/RecoHGCal/GraphReco/test/windowInference_cfg.py @@ -0,0 +1,68 @@ +# coding: utf-8 + +""" +Test config to run the WindowInference plugin. +""" + + +import os +import subprocess + +import FWCore.ParameterSet.Config as cms +from FWCore.ParameterSet.VarParsing import VarParsing + + +# determine the location of _this_ file +if "__file__" in globals(): + this_dir = os.path.dirname(os.path.abspath(__file__)) +else: + this_dir = os.path.expandvars("$CMSSW_BASE/src/RecoHGCal/GraphReco/test") + +# ensure that the graph exists +# if not, call the create_dummy_graph.py script in a subprocess since tensorflow complains +# when its loaded twice (once here in python, once in c++) +graph_path = os.path.join(this_dir, "graph.pb") +if not os.path.exists(graph_path): + script_path = os.path.join(this_dir, "create_dummy_graph.py") + code = subprocess.call(["python", script_path, graph_path]) + if code != 0: + raise Exception("create_dummy_graph.py failed") + +# setup minimal options +options = VarParsing("python") +options.setDefault("inputFiles", "file:///eos/cms/store/cmst3/group/hgcal/CMG_studies/hgcalsim/sim.RecoTask/closeby_1.0To100.0_idsmix_dR0.3_n5_rnd1_s1/prod5/reco_2327_n100.root") +options.parseArguments() + +# define the process to run for the Phase2 era +from Configuration.Eras.Era_Phase2C8_cff import Phase2C8 +process = cms.Process("HGR", Phase2C8) + +# standard sequences and modules +process.load("Configuration.StandardSequences.Services_cff") +process.load("FWCore.MessageService.MessageLogger_cfi") +process.load("Configuration.Geometry.GeometryExtended2023D41Reco_cff") +process.load("Configuration.StandardSequences.FrontierConditions_GlobalTag_cff") + +# minimal configuration +process.MessageLogger.cerr.FwkReport.reportEvery = 1 +process.maxEvents = cms.untracked.PSet(input=cms.untracked.int32(10)) +process.source = cms.Source("PoolSource", fileNames=cms.untracked.vstring(options.inputFiles)) + +# global tag +from Configuration.AlCa.GlobalTag import GlobalTag +process.GlobalTag = GlobalTag(process.GlobalTag, "auto:phase2_realistic", "") + +# process options +process.options = cms.untracked.PSet( + allowUnscheduled=cms.untracked.bool(True), + wantSummary=cms.untracked.bool(True), +) + +# load and configure the windowInference module +from RecoHGCal.GraphReco.windowInference_cfi import windowInference +process.windowInference = windowInference.clone( + graphPath=cms.string(graph_path), +) + +# define the path to run +process.p = cms.Path(process.windowInference) diff --git a/RecoHGCal/GraphReco/test/windowNTuple_cfg.py b/RecoHGCal/GraphReco/test/windowNTuple_cfg.py new file mode 100644 index 0000000000000..c37f07fb6f4f9 --- /dev/null +++ b/RecoHGCal/GraphReco/test/windowNTuple_cfg.py @@ -0,0 +1,90 @@ +# coding: utf-8 + +""" +Test config to run the WindowInference plugin. +""" + + +import os +import subprocess + +import FWCore.ParameterSet.Config as cms +from FWCore.ParameterSet.VarParsing import VarParsing + + +# # determine the location of _this_ file +# if "__file__" in globals(): +# this_dir = os.path.dirname(os.path.abspath(__file__)) +# else: +# this_dir = os.path.expandvars("$CMSSW_BASE/src/RecoHGCal/GraphReco/test") + +# # ensure that the graph exists +# # if not, call the create_dummy_graph.py script in a subprocess since tensorflow complains +# # when its loaded twice (once here in python, once in c++) +# graph_path = os.path.join(this_dir, "graph.pb") +# if not os.path.exists(graph_path): +# script_path = os.path.join(this_dir, "create_dummy_graph.py") +# code = subprocess.call(["python", script_path, graph_path]) +# if code != 0: +# raise Exception("create_dummy_graph.py failed") + +# setup minimal options +options = VarParsing("python") +options.setDefault("inputFiles", "file:///eos/cms/store/cmst3/group/hgcal/CMG_studies/hgcalsim/sim.RecoTask/closeby_1.0To100.0_idsmix_dR0.3_n5_rnd1_s1/prod5/reco_2327_n100.root") +options.setDefault('outputFile', 'file:windowntup.root') +options.parseArguments() + +#this one has some tracks + + +# define the process to run for the Phase2 era +from Configuration.Eras.Era_Phase2C8_cff import Phase2C8 +process = cms.Process("HGR", Phase2C8) + +# standard sequences and modules +process.load("Configuration.StandardSequences.Services_cff") +process.load("FWCore.MessageService.MessageLogger_cfi") +process.load("Configuration.Geometry.GeometryExtended2026D41Reco_cff") +process.load("Configuration.StandardSequences.FrontierConditions_GlobalTag_cff") +process.load('Configuration.StandardSequences.MagneticField_cff') +process.load('Configuration.StandardSequences.RawToDigi_cff') +process.load('Configuration.StandardSequences.L1Reco_cff') +process.load('Configuration.StandardSequences.Reconstruction_cff') +process.load('Configuration.StandardSequences.RecoSim_cff') +process.load('Configuration.StandardSequences.EndOfProcess_cff') +process.load('Configuration.StandardSequences.Validation_cff') +process.load('Configuration.StandardSequences.FrontierConditions_GlobalTag_cff') + + +# minimal configuration +process.MessageLogger.cerr.FwkReport.reportEvery = 1 +process.maxEvents = cms.untracked.PSet(input=cms.untracked.int32(100)) +process.source = cms.Source("PoolSource", fileNames=cms.untracked.vstring(options.inputFiles)) + +# global tag +from Configuration.AlCa.GlobalTag import GlobalTag +process.GlobalTag = GlobalTag(process.GlobalTag, "auto:phase2_realistic", "") + +# process options +process.options = cms.untracked.PSet( + allowUnscheduled=cms.untracked.bool(True), + wantSummary=cms.untracked.bool(True), +) + +process.TFileService = cms.Service("TFileService", fileName = cms.string( + options.__getattr__("outputFile", noTags=True))) + +# load and configure the windowInference module +from RecoHGCal.GraphReco.windowNTupler_cfi import WindowNTupler +process.WindowNTupler = WindowNTupler.clone() +process.WindowNTuplerDefaultTruth = WindowNTupler.clone() + +process.hgcSimTruth = cms.EDProducer("HGCTruthProducer", +) + +process.WindowNTupler.simClusters = "hgcSimTruth" + +process.hgcSimTruthSequence = cms.Sequence(process.hgcSimTruth) +process.dump=cms.EDAnalyzer('EventContentAnalyzer') +# define the path to run +process.p = cms.Path(process.hgcSimTruthSequence * process.WindowNTupler * process.WindowNTuplerDefaultTruth) diff --git a/SimDataFormats/Associations/plugins/SimHitToSimTrackAssociationProducer.cc b/SimDataFormats/Associations/plugins/SimHitToSimTrackAssociationProducer.cc new file mode 100644 index 0000000000000..9a2bd7c26ba84 --- /dev/null +++ b/SimDataFormats/Associations/plugins/SimHitToSimTrackAssociationProducer.cc @@ -0,0 +1,145 @@ +// system include files +//#include +//#include +// +//// user include files +//#include "FWCore/Framework/interface/stream/EDProducer.h" +// +//#include "FWCore/Framework/interface/Event.h" +//#include "FWCore/Framework/interface/MakerMacros.h" +// +//#include "FWCore/Framework/interface/ESHandle.h" +// +//#include "FWCore/ParameterSet/interface/ParameterSet.h" +// +//#include "FWCore/MessageLogger/interface/MessageLogger.h" +//#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" +//#include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" +//#include "SimDataFormats/CaloHit/interface/PCaloHit.h" +//#include "SimDataFormats/Track/interface/SimTrack.h" +// +//#include "DataFormats/Common/interface/Association.h" +//#include "DataFormats/Common/interface/AssociationMap.h" +//#include "DataFormats/Common/interface/OneToManyWithQualityGeneric.h" +//#include "DataFormats/Common/interface/RefToBase.h" +// +// +//#include "FWCore/Utilities/interface/transform.h" +//#include "FWCore/Utilities/interface/EDGetToken.h" +//#include +// +//// +//// class decleration +//// +//typedef std::pair IdxAndFraction; +//typedef edm::AssociationMap> RecHitToSimCluster; +// +//class SimClusterRecHitAssociationProducer : public edm::stream::EDProducer<> { +//public: +// explicit SimClusterRecHitAssociationProducer(const edm::ParameterSet&); +// ~SimClusterRecHitAssociationProducer() override; +// +//private: +// void produce(edm::Event&, const edm::EventSetup&) override; +// +// std::vector> simhitCollectionTokens_; +// edm::EDGetTokenT simtrackCollectionToken_; +//}; +// +//SimClusterRecHitAssociationProducer::SimClusterRecHitAssociationProducer(const edm::ParameterSet& pset) +// : +// caloRechitCollectionTokens_(edm::vector_transform( +// caloRechitTags_, [this](const edm::InputTag& tag) { return consumes(tag); })), +// scCollectionToken_(consumes(pset.getParameter("simClusters"))) { +// for (auto& tag : caloRechitTags_) { +// const std::string& label = tag.instance(); +// produces>(label + "ToBestSimClus"); +// produces(label + "ToSimClus"); +// } +// produces>(); +//} +// +//SimClusterRecHitAssociationProducer::~SimClusterRecHitAssociationProducer() {} +// +//// ------------ method called to produce the data ------------ +//void SimClusterRecHitAssociationProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { +// +// // Go ahead and put a std::unordered_map into the event +// // Also put edm::Association SimHit --> SimTrack +// // +// // Producer for Association Hit --> SimCluster reads unordered_map, then loops through hits_and_fractions of SC +// // +// // New producer for SimHit --> RecHit and RecHit --> SimHits +// // Another producer for RecHit --> SimClusters from reading associations +// // +// // Add variable in SimCluster nano table for whether it should be kept or not +// +// auto simClusterToRecEnergy = std::make_unique>(); +// edm::Handle scCollection; +// iEvent.getByToken(scCollectionToken_, scCollection); +// std::unordered_map> hitDetIdToIndices; +// +// for (size_t s = 0; s < scCollection->size(); s++) { +// const auto& sc = scCollection->at(s); +// (*simClusterToRecEnergy)[s] = 0.; +// for (auto& hf : sc.hits_and_fractions()) { +// // Can have two unique hits with the same detId +// hitDetIdToIndices[hf.first].push_back({s, hf.second}); +// } +// } +// +// std::unordered_map hitDetIdToTotalRecEnergy; +// +// for (size_t i = 0; i < caloRechitCollectionTokens_.size(); i++) { +// std::string label = caloRechitTags_.at(i).instance(); +// std::vector rechitIndices; +// +// edm::Handle caloRechitCollection; +// iEvent.getByToken(caloRechitCollectionTokens_.at(i), caloRechitCollection); +// +// auto assocMap = std::make_unique(caloRechitCollection, scCollection); +// +// for (size_t h = 0; h < caloRechitCollection->size(); h++) { +// HGCRecHitRef caloRh(caloRechitCollection, h); +// size_t id = caloRh->detid().rawId(); +// float energy = caloRh->energy(); +// hitDetIdToTotalRecEnergy[id] += energy; +// +// // Need to sort before inserting into AssociationMap +// auto match = hitDetIdToIndices.find(id); +// if (match == std::end(hitDetIdToIndices)) { +// rechitIndices.push_back(-1); +// continue; +// } +// auto& scIdxAndFrac = match->second; +// // Sort by energy fraction +// std::sort(std::begin(scIdxAndFrac), std::end(scIdxAndFrac), +// [](auto& a, auto& b) { return a.second > b.second; }); +// +// for (size_t m = 0; m < scIdxAndFrac.size(); m++) { +// float fraction = scIdxAndFrac[m].second; +// int scIdx = scIdxAndFrac[m].first; +// (*simClusterToRecEnergy)[scIdx] += energy * fraction; +// // Best match is the simCluster that carries the hit with the highest energy fraction +// // (that is, responsible for the largest deposit in the detId) +// if (m == 0) +// rechitIndices.push_back(scIdx); +// SimClusterRef simclus(scCollection, scIdx); +// assocMap->insert(caloRh, std::make_pair(simclus, fraction)); +// } +// } +// +// auto assoc = std::make_unique>(scCollection); +// edm::Association::Filler filler(*assoc); +// filler.insert(caloRechitCollection, rechitIndices.begin(), rechitIndices.end()); +// filler.fill(); +// iEvent.put(std::move(assoc), label + "ToBestSimClus"); +// iEvent.put(std::move(assocMap), label + "ToSimClus"); +// } +// iEvent.put(std::move(simClusterToRecEnergy)); +//} +// +//// define this as a plug-in +//DEFINE_FWK_MODULE(SimClusterRecHitAssociationProducer); +// diff --git a/SimDataFormats/Associations/src/classes_def.xml b/SimDataFormats/Associations/src/classes_def.xml index 83e5364cac2a8..b7cbe221a7c1d 100644 --- a/SimDataFormats/Associations/src/classes_def.xml +++ b/SimDataFormats/Associations/src/classes_def.xml @@ -52,6 +52,8 @@ + + @@ -138,4 +140,6 @@ + + diff --git a/SimDataFormats/CaloAnalysis/interface/SimCluster.h b/SimDataFormats/CaloAnalysis/interface/SimCluster.h index 5983b020a0c8a..231b4b2db7e81 100644 --- a/SimDataFormats/CaloAnalysis/interface/SimCluster.h +++ b/SimDataFormats/CaloAnalysis/interface/SimCluster.h @@ -234,7 +234,6 @@ class SimCluster { /** @brief add simhit's energy to cluster */ void addSimHit(const PCaloHit &hit) { simhit_energy_ += hit.energy(); } - void setImpactPoint(const math::XYZTLorentzVectorF &point) { impactPoint_ = point; } const math::XYZTLorentzVectorF &impactPoint() const { return impactPoint_; } void setImpactMomentum(const math::XYZTLorentzVectorF &mom) { impactMomentum_ = mom; } diff --git a/SimDataFormats/CaloAnalysis/src/SimCluster.cc b/SimDataFormats/CaloAnalysis/src/SimCluster.cc index cfd7db5cbe3e2..a9c2527f764da 100644 --- a/SimDataFormats/CaloAnalysis/src/SimCluster.cc +++ b/SimDataFormats/CaloAnalysis/src/SimCluster.cc @@ -28,6 +28,9 @@ SimCluster::SimCluster(const SimTrack &simtrk) { theMomentum_.SetPxPyPzE( simtrk.momentum().px(), simtrk.momentum().py(), simtrk.momentum().pz(), simtrk.momentum().E()); pdgId_ = simtrk.type(); + + impactMomentum_ = simtrk.getMomentumAtBoundary(); + impactPoint_ = simtrk.getPositionAtBoundary(); } SimCluster::SimCluster(EncodedEventId eventID, uint32_t particleID) { @@ -35,31 +38,6 @@ SimCluster::SimCluster(EncodedEventId eventID, uint32_t particleID) { particleId_ = particleID; } -SimCluster::SimCluster(const std::vector &simtrks, int pdgId) { - if (simtrks.size() > 0) { - double sumPx = 0.; - double sumPy = 0.; - double sumPz = 0.; - double sumE = 0.; - - for (const SimTrack &t : simtrks) { - addG4Track(t); - sumPx += t.momentum().px(); - sumPy += t.momentum().py(); - sumPz += t.momentum().pz(); - sumE += t.momentum().E(); - } - - theMomentum_.SetPxPyPzE(sumPx, sumPy, sumPz, sumE); - - // set event and particle ID (!= pdgID) from the first track for consistency - event_ = simtrks[0].eventId(); - particleId_ = simtrks[0].trackId(); - } - - pdgId_ = pdgId; -} - math::XYZTLorentzVectorF SimCluster::impactMomentumMuOnly() const { math::XYZTLorentzVectorF mom; for (auto& t : g4Tracks_) { diff --git a/SimDataFormats/PFAnalysis/BuildFile.xml b/SimDataFormats/PFAnalysis/BuildFile.xml new file mode 100644 index 0000000000000..f51d00ade2d32 --- /dev/null +++ b/SimDataFormats/PFAnalysis/BuildFile.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/SimDataFormats/PFAnalysis/interface/PFTruthParticle.h b/SimDataFormats/PFAnalysis/interface/PFTruthParticle.h new file mode 100644 index 0000000000000..50ea4f28c3902 --- /dev/null +++ b/SimDataFormats/PFAnalysis/interface/PFTruthParticle.h @@ -0,0 +1,136 @@ +#ifndef SimDataFormats_PFTruthParticle_h +#define SimDataFormats_PFTruthParticle_h + +#include +#include "SimDataFormats/TrackingAnalysis/interface/TrackingParticleFwd.h" +#include "SimDataFormats/TrackingAnalysis/interface/TrackingParticle.h" +#include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" +#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" +#include "DataFormats/Math/interface/Point3D.h" +#include "DataFormats/Math/interface/Vector3D.h" +#include "DataFormats/Math/interface/LorentzVector.h" +#include "DataFormats/HepMCCandidate/interface/GenParticle.h" + +// +// Forward declarations +// +class TrackingVertex; +class SimTrack; +class EncodedEventId; + +class PFTruthParticle { + friend std::ostream& operator<<(std::ostream& s, PFTruthParticle const& tp); + +public: + typedef math::XYZTLorentzVectorD LorentzVector; ///< Lorentz vector + typedef math::XYZPointD Point; ///< point in the space + typedef math::XYZVectorD Vector; ///< point in the space + + /** @brief Default constructor. Note that the object will be useless until it is provided + * with a SimTrack and parent TrackingVertex. + * + * Most of the methods assume there is a SimTrack and parent TrackingVertex set, so will either + * crash or give undefined results if this isn't true. This constructor should only be used to + * create a placeholder until setParentVertex() and addG4Track() can be called. + */ + PFTruthParticle(); + + PFTruthParticle(const TrackingParticleRefVector& trackingParticles, const SimClusterRefVector& simClusters); + + // destructor + ~PFTruthParticle(); + void setTrackingParticles(const TrackingParticleRefVector& refs); + void setSimClusters(const SimClusterRefVector& refs); + void setPdgId(int pdgId); + void setCharge(int charge); + void setP4(LorentzVector p4); + void addSimCluster(const SimClusterRef sc); + void addTrackingParticle(const TrackingParticleRef tp); + + SimClusterRefVector& simClusters() { return simClusters_; } + TrackingParticleRefVector& trackingParticles() { return trackingParticles_; } + size_t nSimCluster() const { return simClusters_.size(); } + size_t nTrackingParticle() const { return trackingParticles_.size(); } + + /** @brief PDG ID. + * + * Returns the PDG ID of the first associated gen particle. If there are no gen particles associated + * then it returns type() from the first SimTrack. */ + int pdgId() const { + return pdgId_; + } + + void addG4Track(const SimTrack& t); + + const std::vector& g4Tracks() const { return g4Tracks_; } + + /// @brief Electric charge. Note this is taken from the first SimTrack only. + float charge() const { return charge_; } + + /// @brief Four-momentum Lorentz vector. Note this is taken from the first SimTrack only. + const LorentzVector& p4() const { return p4_; } + + /// @brief spatial momentum vector + Vector momentum() const { return p4().Vect(); } + + /// @brief Magnitude of momentum vector. Note this is taken from the first SimTrack only. + double p() const { return p4().P(); } + + /// @brief Energy. Note this is taken from the first SimTrack only. + double energy() const { return p4().E(); } + + /// @brief Transverse energy. Note this is taken from the first SimTrack only. + double et() const { return p4().Et(); } + + /// @brief Mass. Note this is taken from the first SimTrack only. + double mass() const { return p4().M(); } + + /// @brief Mass squared. Note this is taken from the first SimTrack only. + double massSqr() const { return pow(mass(), 2); } + + /// @brief Transverse mass. Note this is taken from the first SimTrack only. + double mt() const { return p4().Mt(); } + + /// @brief Transverse mass squared. Note this is taken from the first SimTrack only. + double mtSqr() const { return p4().Mt2(); } + + /// @brief x coordinate of momentum vector. Note this is taken from the first SimTrack only. + double px() const { return p4().Px(); } + + /// @brief y coordinate of momentum vector. Note this is taken from the first SimTrack only. + double py() const { return p4().Py(); } + + /// @brief z coordinate of momentum vector. Note this is taken from the first SimTrack only. + double pz() const { return p4().Pz(); } + + /// @brief Transverse momentum. Note this is taken from the first SimTrack only. + double pt() const { return p4().Pt(); } + + /// @brief Momentum azimuthal angle. Note this is taken from the first SimTrack only. + double phi() const { return p4().Phi(); } + + /// @brief Momentum polar angle. Note this is taken from the first SimTrack only. + double theta() const { return p4().Theta(); } + + /// @brief Momentum pseudorapidity. Note this is taken from the first SimTrack only. + double eta() const { return p4().Eta(); } + + /// @brief Rapidity. Note this is taken from the first SimTrack only. + double rapidity() const { return p4().Rapidity(); } + + /// @brief Same as rapidity(). + double y() const { return rapidity(); } + +private: + /// references to G4 and reco::GenParticle tracks + int charge_; + int pdgId_; + LorentzVector p4_; + std::vector g4Tracks_; + reco::GenParticleRefVector genParticles_; + SimClusterRefVector simClusters_; + TrackingParticleRefVector trackingParticles_; +}; + +#endif // SimDataFormats_PFTruthParticle_H + diff --git a/SimDataFormats/PFAnalysis/interface/PFTruthParticleFwd.h b/SimDataFormats/PFAnalysis/interface/PFTruthParticleFwd.h new file mode 100644 index 0000000000000..45f0d5331ce29 --- /dev/null +++ b/SimDataFormats/PFAnalysis/interface/PFTruthParticleFwd.h @@ -0,0 +1,16 @@ +#ifndef CaloAnalysis_PFTruthParticleFwd_h +#define CaloAnalysis_PFTruthParticleFwd_h +#include "DataFormats/Common/interface/Ref.h" +#include "DataFormats/Common/interface/RefProd.h" +#include "DataFormats/Common/interface/RefVector.h" +#include + +class PFTruthParticle; +typedef std::vector PFTruthParticleCollection; +typedef edm::Ref PFTruthParticleRef; +typedef edm::RefVector PFTruthParticleRefVector; +typedef edm::RefProd PFTruthParticleRefProd; +typedef edm::RefVector PFTruthParticleContainer; + +#endif + diff --git a/SimDataFormats/PFAnalysis/src/PFTruthParticle.cc b/SimDataFormats/PFAnalysis/src/PFTruthParticle.cc new file mode 100644 index 0000000000000..9ca899f639d03 --- /dev/null +++ b/SimDataFormats/PFAnalysis/src/PFTruthParticle.cc @@ -0,0 +1,48 @@ +#include "SimDataFormats/PFAnalysis/interface/PFTruthParticle.h" + +#include "DataFormats/HepMCCandidate/interface/GenParticle.h" + +#include + +PFTruthParticle::PFTruthParticle() { + // No operation +} + +PFTruthParticle::~PFTruthParticle() {} + +PFTruthParticle::PFTruthParticle(const TrackingParticleRefVector& trackingParticles, const SimClusterRefVector& simClusters) { + setTrackingParticles(trackingParticles); + setSimClusters(simClusters); +} + +void PFTruthParticle::setTrackingParticles(const TrackingParticleRefVector& refs) { + for (auto& tp : refs) { + addTrackingParticle(tp); + } +} + +void PFTruthParticle::setSimClusters(const SimClusterRefVector& refs) { + for (auto& sc : refs) { + addSimCluster(sc); + } +} + +void PFTruthParticle::addSimCluster(const SimClusterRef sc) { + simClusters_.push_back(sc); + for (auto& track : sc->g4Tracks()) + g4Tracks_.push_back(track); +} + +void PFTruthParticle::addTrackingParticle(const TrackingParticleRef tp) { + trackingParticles_.push_back(tp); + for (auto& track : tp->g4Tracks()) + g4Tracks_.push_back(track); +} + +void PFTruthParticle::setPdgId(int pdgId) { pdgId_ = pdgId; } + +void PFTruthParticle::setCharge(int charge) { charge_ = charge; } + +void PFTruthParticle::setP4(LorentzVector p4) { p4_ = p4; } + +void PFTruthParticle::addG4Track(const SimTrack& t) { g4Tracks_.push_back(t); } diff --git a/SimDataFormats/PFAnalysis/src/classes.h b/SimDataFormats/PFAnalysis/src/classes.h new file mode 100644 index 0000000000000..bd8cb8e8ea3ae --- /dev/null +++ b/SimDataFormats/PFAnalysis/src/classes.h @@ -0,0 +1,8 @@ +#include "SimDataFormats/TrackingAnalysis/interface/TrackingParticle.h" +#include "SimDataFormats/TrackingAnalysis/interface/TrackingParticleFwd.h" +#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" +#include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" +#include "SimDataFormats/PFAnalysis/interface/PFTruthParticle.h" +#include "SimDataFormats/PFAnalysis/interface/PFTruthParticleFwd.h" +#include "DataFormats/Common/interface/Wrapper.h" + diff --git a/SimDataFormats/PFAnalysis/src/classes_def.xml b/SimDataFormats/PFAnalysis/src/classes_def.xml new file mode 100644 index 0000000000000..9f1a9b8d6daf1 --- /dev/null +++ b/SimDataFormats/PFAnalysis/src/classes_def.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + From 772a4f9b683f8f5088d9c191e9a6277400dd14a7 Mon Sep 17 00:00:00 2001 From: Kenneth Long Date: Thu, 15 Jul 2021 16:54:33 +0200 Subject: [PATCH 03/17] Add association dicts --- SimDataFormats/Associations/src/classes.h | 14 ++++++++ .../Associations/src/classes_def.xml | 33 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/SimDataFormats/Associations/src/classes.h b/SimDataFormats/Associations/src/classes.h index b3e3f80f3e930..7542e39cde423 100644 --- a/SimDataFormats/Associations/src/classes.h +++ b/SimDataFormats/Associations/src/classes.h @@ -15,6 +15,20 @@ #include "SimDataFormats/Associations/interface/TTTrackTruthPair.h" #include "SimDataFormats/Associations/interface/LayerClusterToSimTracksterAssociator.h" +#include "DataFormats/Common/interface/AssociationMap.h" +#include "DataFormats/Common/interface/AssociationMapHelpers.h" +#include "SimDataFormats/TrackingAnalysis/interface/TrackingParticleFwd.h" +#include "DataFormats/HGCRecHit/interface/HGCRecHit.h" +#include "DataFormats/HGCRecHit/interface/HGCRecHitCollections.h" +#include "DataFormats/CaloRecHit/interface/CaloCluster.h" + +#include "DataFormats/Common/interface/Association.h" +#include "DataFormats/Common/interface/AssociationMap.h" +#include "DataFormats/Common/interface/Handle.h" +#include "DataFormats/Common/interface/OneToManyWithQuality.h" +#include "DataFormats/Common/interface/OneToManyWithQualityGeneric.h" +#include "DataFormats/Common/interface/View.h" + namespace SimDataFormats_Associations { struct SimDataFormats_Associations { // add 'dummy' Wrapper variable for each class type you put into the Event diff --git a/SimDataFormats/Associations/src/classes_def.xml b/SimDataFormats/Associations/src/classes_def.xml index b7cbe221a7c1d..c1275c52e6a73 100644 --- a/SimDataFormats/Associations/src/classes_def.xml +++ b/SimDataFormats/Associations/src/classes_def.xml @@ -142,4 +142,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 2e566b3bf35836b5ab7cde9887cfa1bd209f9129 Mon Sep 17 00:00:00 2001 From: Kenneth Long Date: Mon, 26 Jul 2021 17:07:49 +0200 Subject: [PATCH 04/17] Sim track/cluster/hit etc matching outside CaloTruthAccumulator --- CommonTools/RecoAlgos/plugins/BuildFile.xml | 1 + .../plugins/HGCRecHitCollectionMerger.cc | 12 ++ ...RecHitToLayerClusterAssociationProducer.cc | 127 +++++++++++++++ .../RecHitToPFCandAssociationProducer.cc | 133 ++++++++++++++++ .../SimClusterRecHitAssociationProducer.cc | 137 +++++++++++++++++ .../HGCalNanoAOD/python/hgcSimHits_cff.py | 6 +- .../HGCalNanoAOD/python/hgcSimTracks_cff.py | 9 +- .../HGCalNanoAOD/python/nanoHGCML_cff.py | 10 +- .../HGCalNanoAOD/python/simClusters_cff.py | 9 +- .../plugins/SimClusterTreeMerger.cc | 2 +- .../PFTruthProducer/plugins/BuildFile.xml | 28 ++++ .../plugins/PFTruthParticleProducer.cc | 133 ++++++++++++++++ ...lusterToCaloParticleAssociationProducer.cc | 68 ++++++++ ...ToSimTrackAndClusterAssociationProducer.cc | 84 ++++++++++ ...SimTrackToSimClusterAssociationProducer.cc | 75 +++++++++ .../SimHitToSimTrackAssociationProducer.cc | 145 ------------------ 16 files changed, 822 insertions(+), 157 deletions(-) create mode 100644 CommonTools/RecoAlgos/plugins/HGCRecHitCollectionMerger.cc create mode 100644 CommonTools/RecoAlgos/plugins/RecHitToLayerClusterAssociationProducer.cc create mode 100644 CommonTools/RecoAlgos/plugins/RecHitToPFCandAssociationProducer.cc create mode 100644 CommonTools/RecoAlgos/plugins/SimClusterRecHitAssociationProducer.cc create mode 100644 RecoParticleFlow/PFTruthProducer/plugins/BuildFile.xml create mode 100644 RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc create mode 100644 SimCalorimetry/HGCalAssociatorProducers/plugins/SimClusterToCaloParticleAssociationProducer.cc create mode 100644 SimCalorimetry/HGCalAssociatorProducers/plugins/SimHitToSimTrackAndClusterAssociationProducer.cc create mode 100644 SimCalorimetry/HGCalAssociatorProducers/plugins/SimTrackToSimClusterAssociationProducer.cc delete mode 100644 SimDataFormats/Associations/plugins/SimHitToSimTrackAssociationProducer.cc diff --git a/CommonTools/RecoAlgos/plugins/BuildFile.xml b/CommonTools/RecoAlgos/plugins/BuildFile.xml index 14976ed78b0e4..1391d81bd6a18 100644 --- a/CommonTools/RecoAlgos/plugins/BuildFile.xml +++ b/CommonTools/RecoAlgos/plugins/BuildFile.xml @@ -16,4 +16,5 @@ + diff --git a/CommonTools/RecoAlgos/plugins/HGCRecHitCollectionMerger.cc b/CommonTools/RecoAlgos/plugins/HGCRecHitCollectionMerger.cc new file mode 100644 index 0000000000000..1d9177f6c0c55 --- /dev/null +++ b/CommonTools/RecoAlgos/plugins/HGCRecHitCollectionMerger.cc @@ -0,0 +1,12 @@ +#include "FWCore/Framework/interface/MakerMacros.h" +#include "CommonTools/UtilAlgos/interface/Merger.h" +#include "DataFormats/HGCRecHit/interface/HGCRecHit.h" +#include "DataFormats/HGCRecHit/interface/HGCRecHitCollections.h" +#include "DataFormats/Common/interface/CloneTrait.h" +#include "DataFormats/Common/interface/RefToBaseVector.h" +#include "DataFormats/Common/interface/CopyPolicy.h" + + +typedef Merger> HGCRecHitCollectionMerger; + +DEFINE_FWK_MODULE(HGCRecHitCollectionMerger); diff --git a/CommonTools/RecoAlgos/plugins/RecHitToLayerClusterAssociationProducer.cc b/CommonTools/RecoAlgos/plugins/RecHitToLayerClusterAssociationProducer.cc new file mode 100644 index 0000000000000..2b7a3b23fc31b --- /dev/null +++ b/CommonTools/RecoAlgos/plugins/RecHitToLayerClusterAssociationProducer.cc @@ -0,0 +1,127 @@ +// system include files +#include +#include + +// user include files +#include "FWCore/Framework/interface/stream/EDProducer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/Framework/interface/ESHandle.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" + +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "DataFormats/CaloRecHit/interface/CaloRecHit.h" +#include "DataFormats/HGCRecHit/interface/HGCRecHitCollections.h" +#include "DataFormats/CaloRecHit/interface/CaloCluster.h" + +#include "DataFormats/Common/interface/Association.h" +#include "DataFormats/Common/interface/AssociationMap.h" +#include "DataFormats/Common/interface/OneToManyWithQualityGeneric.h" + +#include "FWCore/Utilities/interface/transform.h" +#include "FWCore/Utilities/interface/EDGetToken.h" +#include + +// +// class decleration +// +typedef std::pair IdxAndFraction; +typedef edm::AssociationMap, float>> RecHitToLayerCluster; + +class RecHitToLayerClusterAssociationProducer : public edm::stream::EDProducer<> { +public: + explicit RecHitToLayerClusterAssociationProducer(const edm::ParameterSet&); + ~RecHitToLayerClusterAssociationProducer() override; + +private: + void produce(edm::Event&, const edm::EventSetup&) override; + + std::vector caloRechitTags_; + std::vector> caloRechitCollectionTokens_; + edm::EDGetTokenT> layerClusterToken_; +}; + +RecHitToLayerClusterAssociationProducer::RecHitToLayerClusterAssociationProducer(const edm::ParameterSet& pset) + : caloRechitTags_(pset.getParameter>("caloRecHits")), + caloRechitCollectionTokens_(edm::vector_transform( + caloRechitTags_, [this](const edm::InputTag& tag) { return consumes(tag); })), + layerClusterToken_(consumes>(pset.getParameter("layerClusters"))) { + for (auto& tag : caloRechitTags_) { + const std::string& label = !tag.instance().empty() ? tag.instance() : tag.label(); + produces>>(label + "ToBestLayerCluster"); + produces(label + "ToLayerCluster"); + } +} + +RecHitToLayerClusterAssociationProducer::~RecHitToLayerClusterAssociationProducer() {} + +// +// member functions +// + +// ------------ method called to produce the data ------------ +void RecHitToLayerClusterAssociationProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { + edm::Handle> lcCollection; + iEvent.getByToken(layerClusterToken_, lcCollection); + std::unordered_map> hitDetIdToIndices; + + for (size_t j = 0; j < lcCollection->size(); j++) { + for (auto& idAndFrac : (*lcCollection)[j].hitsAndFractions()) { + hitDetIdToIndices[idAndFrac.first.rawId()].push_back({j, idAndFrac.second}); + } + } + + for (size_t i = 0; i < caloRechitCollectionTokens_.size(); i++) { + std::string label = caloRechitTags_.at(i).instance(); + if (label.empty()) + label = caloRechitTags_.at(i).label(); + std::vector rechitIndices; + + edm::Handle caloRechitCollection; + iEvent.getByToken(caloRechitCollectionTokens_.at(i), caloRechitCollection); + + auto assocMap = std::make_unique(caloRechitCollection, lcCollection); + + for (size_t h = 0; h < caloRechitCollection->size(); h++) { + HGCRecHitRef caloRh(caloRechitCollection, h); + size_t id = caloRh->detid().rawId(); + + // Need to sort before inserting into AssociationMap + auto match = hitDetIdToIndices.find(id); + if (match == std::end(hitDetIdToIndices)) { + rechitIndices.push_back(-1); + continue; + } + auto& lcIdxAndFrac = match->second; + // Sort by energy fraction + std::sort(std::begin(lcIdxAndFrac), std::end(lcIdxAndFrac), + [](auto& a, auto& b) { return a.second > b.second; }); + + for (size_t m = 0; m < lcIdxAndFrac.size(); m++) { + float fraction = lcIdxAndFrac[m].second; + int lcIdx = lcIdxAndFrac[m].first; + // Best match is the layerCluster that carries the hit with the highest energy fraction + // (that is, the one responsible for the largest deposit in the detId) + if (m == 0) + rechitIndices.push_back(lcIdx); + edm::Ref> lc(lcCollection, lcIdx); + assocMap->insert(caloRh, std::make_pair(lc, fraction)); + } + } + + auto assoc = std::make_unique>>(lcCollection); + edm::Association>::Filler filler(*assoc); + filler.insert(caloRechitCollection, rechitIndices.begin(), rechitIndices.end()); + filler.fill(); + iEvent.put(std::move(assoc), label + "ToBestLayerCluster"); + iEvent.put(std::move(assocMap), label + "ToLayerCluster"); + } +} + +// define this as a plug-in +DEFINE_FWK_MODULE(RecHitToLayerClusterAssociationProducer); + diff --git a/CommonTools/RecoAlgos/plugins/RecHitToPFCandAssociationProducer.cc b/CommonTools/RecoAlgos/plugins/RecHitToPFCandAssociationProducer.cc new file mode 100644 index 0000000000000..6c01bacfac3f8 --- /dev/null +++ b/CommonTools/RecoAlgos/plugins/RecHitToPFCandAssociationProducer.cc @@ -0,0 +1,133 @@ +// system include files +#include +#include + +// user include files +#include "FWCore/Framework/interface/stream/EDProducer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/Framework/interface/ESHandle.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" + +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "SimDataFormats/TrackingAnalysis/interface/TrackingParticle.h" +#include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" +#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" +#include "DataFormats/CaloRecHit/interface/CaloRecHit.h" +#include "SimDataFormats/CaloHit/interface/PCaloHit.h" +#include "SimDataFormats/CaloHit/interface/PCaloHitContainer.h" +#include "DataFormats/HGCRecHit/interface/HGCRecHitCollections.h" + +#include "DataFormats/ParticleFlowCandidate/interface/PFCandidateFwd.h" +#include "DataFormats/ParticleFlowCandidate/interface/PFCandidate.h" +#include "DataFormats/ParticleFlowReco/interface/PFRecHit.h" +#include "DataFormats/ParticleFlowReco/interface/PFRecHitFraction.h" +#include "DataFormats/ParticleFlowReco/interface/PFBlock.h" +#include "DataFormats/ParticleFlowReco/interface/PFBlockFwd.h" +#include "DataFormats/ParticleFlowReco/interface/PFCluster.h" +#include "DataFormats/ParticleFlowReco/interface/PFClusterFwd.h" + +#include "DataFormats/Common/interface/Association.h" + +#include "FWCore/Utilities/interface/transform.h" +#include "FWCore/Utilities/interface/EDGetToken.h" +#include + +// +// class decleration +// +typedef std::pair IdxAndFraction; + +class RecHitToPFCandAssociationProducer : public edm::stream::EDProducer<> { +public: + explicit RecHitToPFCandAssociationProducer(const edm::ParameterSet&); + ~RecHitToPFCandAssociationProducer() override; + +private: + void produce(edm::Event&, const edm::EventSetup&) override; + + std::vector caloRechitTags_; + std::vector> caloSimhitCollectionTokens_; + std::vector>> caloRechitCollectionTokens_; + edm::EDGetTokenT pfCollectionToken_; +}; + +RecHitToPFCandAssociationProducer::RecHitToPFCandAssociationProducer(const edm::ParameterSet& pset) + : caloRechitTags_(pset.getParameter>("caloRecHits")), + caloRechitCollectionTokens_(edm::vector_transform( + caloRechitTags_, [this](const edm::InputTag& tag) { return consumes>(tag); })), + pfCollectionToken_(consumes(pset.getParameter("pfCands"))) { + for (auto& tag : caloRechitTags_) { + const std::string& label = !tag.instance().empty() ? tag.instance() : tag.label(); + produces>(label + "ToPFCand"); + } +} + +RecHitToPFCandAssociationProducer::~RecHitToPFCandAssociationProducer() {} + +// +// member functions +// + +// ------------ method called to produce the data ------------ +void RecHitToPFCandAssociationProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { + edm::Handle pfCollection; + iEvent.getByToken(pfCollectionToken_, pfCollection); + std::unordered_map hitDetIdToIndex; + + for (size_t j = 0; j < pfCollection->size(); j++) { + const auto& pfCand = pfCollection->at(j); + const reco::PFCandidate::ElementsInBlocks& elements = pfCand.elementsInBlocks(); + for (auto& element : elements) { + const reco::PFBlockRef blockRef = element.first; + if (!blockRef.isNonnull()) + continue; + for (const auto& block : blockRef->elements()) { + // This seems to not work for PFTICL + //if (block.type() == reco::PFBlockElement::HGCAL) { + const reco::PFClusterRef cluster = block.clusterRef(); + if (cluster.isNonnull()) { + const std::vector& rhf = cluster->recHitFractions(); + for (const auto& hf : rhf) { + auto& hit = hf.recHitRef(); + if (!hit) + throw cms::Exception("RecHitToPFCandAssociationProducer") << "Invalid RecHit ref"; + size_t detId = hit->detId(); + auto entry = hitDetIdToIndex.find(detId); + if (entry == hitDetIdToIndex.end() || entry->second.second < hf.fraction()) + hitDetIdToIndex[detId] = {j, hf.fraction()}; + } + } + } + } + } + + for (size_t i = 0; i < caloRechitCollectionTokens_.size(); i++) { + std::string label = caloRechitTags_.at(i).instance(); + if (label.empty()) + label = caloRechitTags_.at(i).label(); + std::vector rechitIndices; + + edm::Handle> caloRechitCollection; + iEvent.getByToken(caloRechitCollectionTokens_.at(i), caloRechitCollection); + + for (size_t h = 0; h < caloRechitCollection->size(); h++) { + const CaloRecHit& caloRh = caloRechitCollection->at(h); + size_t id = caloRh.detid().rawId(); + int match = hitDetIdToIndex.find(id) == hitDetIdToIndex.end() ? -1 : hitDetIdToIndex.at(id).first; + rechitIndices.push_back(match); + } + + auto assoc = std::make_unique>(pfCollection); + edm::Association::Filler filler(*assoc); + filler.insert(caloRechitCollection, rechitIndices.begin(), rechitIndices.end()); + filler.fill(); + iEvent.put(std::move(assoc), label + "ToPFCand"); + } +} + +// define this as a plug-in +DEFINE_FWK_MODULE(RecHitToPFCandAssociationProducer); diff --git a/CommonTools/RecoAlgos/plugins/SimClusterRecHitAssociationProducer.cc b/CommonTools/RecoAlgos/plugins/SimClusterRecHitAssociationProducer.cc new file mode 100644 index 0000000000000..8af6951d69787 --- /dev/null +++ b/CommonTools/RecoAlgos/plugins/SimClusterRecHitAssociationProducer.cc @@ -0,0 +1,137 @@ +// system include files +#include +#include + +// user include files +#include "FWCore/Framework/interface/stream/EDProducer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/Framework/interface/ESHandle.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" + +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" +#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" +#include "DataFormats/HGCRecHit/interface/HGCRecHit.h" +#include "DataFormats/HGCRecHit/interface/HGCRecHitCollections.h" + +#include "DataFormats/Common/interface/Association.h" +#include "DataFormats/Common/interface/AssociationMap.h" +#include "DataFormats/Common/interface/OneToManyWithQualityGeneric.h" +#include "DataFormats/Common/interface/RefToBase.h" + + +#include "FWCore/Utilities/interface/transform.h" +#include "FWCore/Utilities/interface/EDGetToken.h" +#include + +// +// class decleration +// +typedef std::pair IdxAndFraction; +typedef edm::AssociationMap> RecHitToSimCluster; + +class SimClusterRecHitAssociationProducer : public edm::stream::EDProducer<> { +public: + explicit SimClusterRecHitAssociationProducer(const edm::ParameterSet&); + ~SimClusterRecHitAssociationProducer() override; + +private: + void produce(edm::Event&, const edm::EventSetup&) override; + + std::vector caloRechitTags_; + std::vector> caloRechitCollectionTokens_; + edm::EDGetTokenT scCollectionToken_; +}; + +SimClusterRecHitAssociationProducer::SimClusterRecHitAssociationProducer(const edm::ParameterSet& pset) + : caloRechitTags_(pset.getParameter>("caloRecHits")), + caloRechitCollectionTokens_(edm::vector_transform( + caloRechitTags_, [this](const edm::InputTag& tag) { return consumes(tag); })), + scCollectionToken_(consumes(pset.getParameter("simClusters"))) { + for (auto& tag : caloRechitTags_) { + const std::string& label = !tag.instance().empty() ? tag.instance() : tag.label(); + produces>(label + "ToBestSimClus"); + produces(label + "ToSimClus"); + } + produces>(); +} + +SimClusterRecHitAssociationProducer::~SimClusterRecHitAssociationProducer() {} + +// ------------ method called to produce the data ------------ +void SimClusterRecHitAssociationProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { + auto simClusterToRecEnergy = std::make_unique>(); + edm::Handle scCollection; + iEvent.getByToken(scCollectionToken_, scCollection); + std::unordered_map> hitDetIdToIndices; + + for (size_t s = 0; s < scCollection->size(); s++) { + const auto& sc = scCollection->at(s); + // Need to initialize because not all SimClusters lead to rechits + (*simClusterToRecEnergy)[s] = 0.; + for (auto& hf : sc.hits_and_fractions()) { + // Can have two unique hits with the same detId + hitDetIdToIndices[hf.first].push_back({s, hf.second}); + } + } + + std::unordered_map hitDetIdToTotalRecEnergy; + + for (size_t i = 0; i < caloRechitCollectionTokens_.size(); i++) { + std::string label = caloRechitTags_.at(i).instance(); + if (label.empty()) + label = caloRechitTags_.at(i).label(); + std::vector rechitIndices; + + edm::Handle caloRechitCollection; + iEvent.getByToken(caloRechitCollectionTokens_.at(i), caloRechitCollection); + + auto assocMap = std::make_unique(caloRechitCollection, scCollection); + + for (size_t h = 0; h < caloRechitCollection->size(); h++) { + HGCRecHitRef caloRh(caloRechitCollection, h); + size_t id = caloRh->detid().rawId(); + float energy = caloRh->energy(); + hitDetIdToTotalRecEnergy[id] += energy; + + // Need to sort before inserting into AssociationMap + auto match = hitDetIdToIndices.find(id); + if (match == std::end(hitDetIdToIndices)) { + rechitIndices.push_back(-1); + continue; + } + auto& scIdxAndFrac = match->second; + // Sort by energy fraction + std::sort(std::begin(scIdxAndFrac), std::end(scIdxAndFrac), + [](auto& a, auto& b) { return a.second > b.second; }); + + for (size_t m = 0; m < scIdxAndFrac.size(); m++) { + float fraction = scIdxAndFrac[m].second; + int scIdx = scIdxAndFrac[m].first; + (*simClusterToRecEnergy)[scIdx] += energy * fraction; + // Best match is the simCluster that carries the hit with the highest energy fraction + // (that is, responsible for the largest deposit in the detId) + if (m == 0) + rechitIndices.push_back(scIdx); + SimClusterRef simclus(scCollection, scIdx); + assocMap->insert(caloRh, std::make_pair(simclus, fraction)); + } + } + + auto assoc = std::make_unique>(scCollection); + edm::Association::Filler filler(*assoc); + filler.insert(caloRechitCollection, rechitIndices.begin(), rechitIndices.end()); + filler.fill(); + iEvent.put(std::move(assoc), label + "ToBestSimClus"); + iEvent.put(std::move(assocMap), label + "ToSimClus"); + } + iEvent.put(std::move(simClusterToRecEnergy)); +} + +// define this as a plug-in +DEFINE_FWK_MODULE(SimClusterRecHitAssociationProducer); diff --git a/DPGAnalysis/HGCalNanoAOD/python/hgcSimHits_cff.py b/DPGAnalysis/HGCalNanoAOD/python/hgcSimHits_cff.py index e9beb4ee24a08..108c873b32d1e 100644 --- a/DPGAnalysis/HGCalNanoAOD/python/hgcSimHits_cff.py +++ b/DPGAnalysis/HGCalNanoAOD/python/hgcSimHits_cff.py @@ -61,8 +61,8 @@ +hgcEESimHitsPositionTable +hgcHEfrontSimHitsPositionTable +hgcHEbackSimHitsPositionTable - +hgcEEHitsToSimClusterTable - +hgcHEfrontHitsToSimClusterTable - +hgcHEbackHitsToSimClusterTable + #+hgcEEHitsToSimClusterTable + #+hgcHEfrontHitsToSimClusterTable + #+hgcHEbackHitsToSimClusterTable +hgcHEfrontSimHitsTable+hgcHEbackSimHitsTable) diff --git a/DPGAnalysis/HGCalNanoAOD/python/hgcSimTracks_cff.py b/DPGAnalysis/HGCalNanoAOD/python/hgcSimTracks_cff.py index 8a9870c44bb0c..18be2cd601ddf 100644 --- a/DPGAnalysis/HGCalNanoAOD/python/hgcSimTracks_cff.py +++ b/DPGAnalysis/HGCalNanoAOD/python/hgcSimTracks_cff.py @@ -29,13 +29,18 @@ ) ) +simTrackToSimCluster = cms.EDProducer("SimTrackToSimClusterAssociationProducer", + simClusters = cms.InputTag("mix:MergedCaloTruth"), + simTracks = cms.InputTag("g4SimHits"), +) + simTrackToSimClusterTable = cms.EDProducer("SimTrackToSimClusterIndexTableProducer", cut = simTrackTable.cut, src = simTrackTable.src, objName = simTrackTable.name, branchName = cms.string("SimCluster"), - objMap = cms.InputTag("mix:simTrackToSimCluster"), + objMap = cms.InputTag("simTrackToSimCluster"), docString = cms.string("SimCluster containing track") ) -simTrackTables = cms.Sequence(simTrackTable+simTrackToSimClusterTable) +simTrackTables = cms.Sequence(simTrackTable+simTrackToSimCluster+simTrackToSimClusterTable) diff --git a/DPGAnalysis/HGCalNanoAOD/python/nanoHGCML_cff.py b/DPGAnalysis/HGCalNanoAOD/python/nanoHGCML_cff.py index 62521907b64f0..d250ac0d67c8c 100644 --- a/DPGAnalysis/HGCalNanoAOD/python/nanoHGCML_cff.py +++ b/DPGAnalysis/HGCalNanoAOD/python/nanoHGCML_cff.py @@ -27,15 +27,17 @@ charge = CandVars.charge) nanoHGCMLSequence = cms.Sequence(nanoMetadata+genVertexTables+genParticleTable+ - trackingParticleTable+caloParticleTable+simClusterTables+ + trackingParticleTable+caloParticleTable+ layerClusterTables+ - simTrackTables+hgcSimHitsSequence+trackerSimHitTables) + simTrackTables+hgcSimHitsSequence+trackerSimHitTables+ + simClusterTables +) nanoHGCMLRecoSequence = cms.Sequence(hgcRecHitsSequence+hgcRecHitSimAssociationSequence+ pfCandTable+pfTruth+pfTICLCandTable+trackTables) def customizeReco(process): - process.nanoHGCMLSequence.insert(1, nanoHGCMLRecoSequence) + process.nanoHGCMLSequence.insert(-1, nanoHGCMLRecoSequence) return process def customizeNoMergedCaloTruth(process): @@ -50,5 +52,5 @@ def customizeNoMergedCaloTruth(process): return process def customizeMergedSimClusters(process): - process.nanoHGCMLSequence.insert(1, mergedSimClusterTables) + process.nanoHGCMLSequence.insert(-1, mergedSimClusterTables) return process diff --git a/DPGAnalysis/HGCalNanoAOD/python/simClusters_cff.py b/DPGAnalysis/HGCalNanoAOD/python/simClusters_cff.py index 70e729773de41..cc0f9fdf1037f 100644 --- a/DPGAnalysis/HGCalNanoAOD/python/simClusters_cff.py +++ b/DPGAnalysis/HGCalNanoAOD/python/simClusters_cff.py @@ -37,12 +37,17 @@ ) ) +simClusterToCaloPart = cms.EDProducer("SimClusterToCaloParticleAssociationProducer", + caloParticles = cms.InputTag("mix:MergedCaloTruth"), + simClusters = cms.InputTag("mix:MergedCaloTruth"), +) + simClusterToCaloPartTable = cms.EDProducer("SimClusterToCaloParticleIndexTableProducer", cut = simClusterTable.cut, src = simClusterTable.src, objName = simClusterTable.name, branchName = cms.string("CaloPart"), - objMap = cms.InputTag("mix:simClusterToCaloParticle"), + objMap = cms.InputTag("simClusterToCaloPart"), docString = cms.string("Index of CaloPart containing SimCluster") ) @@ -75,6 +80,6 @@ docString = cms.string("Index of Merged SimCluster containing SimCluster") ) -simClusterTables = cms.Sequence(simClusterTable+simClusterToCaloPartTable) +simClusterTables = cms.Sequence(simClusterTable+simClusterToCaloPart+simClusterToCaloPartTable) mergedSimClusterTables = cms.Sequence(hgcSimTruth+mergedSimClusterTable+hgcSimTruthDR+mergedSimClusterDRTable+mergedToUnmergedSCTable+simClusterToMergedSCTable) diff --git a/HGCSimTruth/HGCSimTruth/plugins/SimClusterTreeMerger.cc b/HGCSimTruth/HGCSimTruth/plugins/SimClusterTreeMerger.cc index 504ce553e0062..a1f9ef6945537 100644 --- a/HGCSimTruth/HGCSimTruth/plugins/SimClusterTreeMerger.cc +++ b/HGCSimTruth/HGCSimTruth/plugins/SimClusterTreeMerger.cc @@ -1052,7 +1052,7 @@ simmerger::simmerger(const edm::ParameterSet& iConfig) : tokenSimTracks(consumes(edm::InputTag("g4SimHits"))), tokenSimVertices(consumes(edm::InputTag("g4SimHits"))), simClustersToken_(consumes(edm::InputTag("mix:MergedCaloTruth"))), - simTrackToSimClusterToken_(consumes>(edm::InputTag("mix:simTrackToSimCluster"))) + simTrackToSimClusterToken_(consumes>(edm::InputTag("simTrackToSimCluster"))) { produces(); produces>(); diff --git a/RecoParticleFlow/PFTruthProducer/plugins/BuildFile.xml b/RecoParticleFlow/PFTruthProducer/plugins/BuildFile.xml new file mode 100644 index 0000000000000..1d1e94bd4f9e3 --- /dev/null +++ b/RecoParticleFlow/PFTruthProducer/plugins/BuildFile.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc b/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc new file mode 100644 index 0000000000000..317af99038ed8 --- /dev/null +++ b/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc @@ -0,0 +1,133 @@ +// system include files +#include +#include + +// user include files +#include "FWCore/Framework/interface/global/EDProducer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/Framework/interface/ESHandle.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" + +#include "SimDataFormats/Associations/interface/TrackToTrackingParticleAssociator.h" + +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "SimDataFormats/TrackingAnalysis/interface/TrackingParticle.h" +#include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" +#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" +#include "SimDataFormats/PFAnalysis/interface/PFTruthParticle.h" +#include "SimDataFormats/PFAnalysis/interface/PFTruthParticleFwd.h" + +#include "FWCore/Utilities/interface/EDGetToken.h" +#include + +// +// class decleration +// + +typedef edm::AssociationMap> TrackingParticleToSimCluster; + +class PFTruthParticleProducer : public edm::global::EDProducer<> { +public: + explicit PFTruthParticleProducer(const edm::ParameterSet &); + ~PFTruthParticleProducer() override; + +private: + void produce(edm::StreamID, edm::Event &, const edm::EventSetup &) const override; + std::set findTrackingParticleMatch( + std::unordered_map& trackIdToTPRef, SimClusterRef scRef) const; + + edm::EDGetTokenT tpCollectionToken_; + edm::EDGetTokenT scCollectionToken_; +}; + +PFTruthParticleProducer::PFTruthParticleProducer(const edm::ParameterSet &pset) + : tpCollectionToken_(consumes(pset.getParameter("trackingParticles"))), + scCollectionToken_(consumes(pset.getParameter("simClusters"))) +{ + produces(); + produces>("trackingPartToPFTruth"); + produces>("simClusToPFTruth"); +} + +PFTruthParticleProducer::~PFTruthParticleProducer() {} + +// +// member functions +// + +std::set PFTruthParticleProducer::findTrackingParticleMatch( + std::unordered_map& trackIdToTPRef, SimClusterRef scRef) const { + std::set trackingParticles; + for (auto& track : scRef->g4Tracks()) { + unsigned int trackId = track.trackId(); + if (trackIdToTPRef.find(trackId) != trackIdToTPRef.end()) + trackingParticles.insert(trackIdToTPRef[trackId]); + } + return trackingParticles; +} + +// ------------ method called to produce the data ------------ +void PFTruthParticleProducer::produce(edm::StreamID, edm::Event &iEvent, const edm::EventSetup &iSetup) const { + + edm::Handle tpCollection; + iEvent.getByToken(tpCollectionToken_, tpCollection); + + edm::Handle scCollection; + iEvent.getByToken(scCollectionToken_, scCollection); + + auto out = std::make_unique(); + // Not used right now, but useful for the trackID lookup later + std::unordered_map trackIdToTPRef; + + std::vector trackingIndices; + for (size_t i = 0; i < tpCollection->size(); i++) { + TrackingParticleRef trackingParticle(tpCollection, i); + PFTruthParticle particle; + particle.addTrackingParticle(trackingParticle); + particle.setCharge(trackingParticle->charge()); + particle.setPdgId(trackingParticle->pdgId()); + particle.setP4(trackingParticle->p4()); + out->push_back(particle); + trackingIndices.push_back(i); + for (auto& track : trackingParticle->g4Tracks()) { + unsigned int trackId = track.trackId(); + trackIdToTPRef[trackId] = trackingParticle; + } + } + + std::vector scIndices; + for (size_t i = 0; i < scCollection->size(); i++) { + SimClusterRef simclus(scCollection, i); + // Doesn't really do much anyway + //findTrackingParticleMatch(trackIdToTPRef, simclus)) + // For now just randomly assign the SCs as a dummy + int tpIdx = i % out->size(); + auto& pf = out->at(tpIdx); + pf.addSimCluster(simclus); + scIndices.push_back(tpIdx); + } + auto pfTruthHand = iEvent.put(std::move(out)); + + auto tpAssoc = std::make_unique>(pfTruthHand); + auto scAssoc = std::make_unique>(pfTruthHand); + + edm::Association::Filler tpFiller(*tpAssoc); + tpFiller.insert(tpCollection, trackingIndices.begin(), trackingIndices.end()); + tpFiller.fill(); + + edm::Association::Filler scFiller(*scAssoc); + scFiller.insert(scCollection, scIndices.begin(), scIndices.end()); + scFiller.fill(); + + iEvent.put(std::move(tpAssoc), "trackingPartToPFTruth"); + iEvent.put(std::move(scAssoc), "simClusToPFTruth"); +} + +// define this as a plug-in +DEFINE_FWK_MODULE(PFTruthParticleProducer); + diff --git a/SimCalorimetry/HGCalAssociatorProducers/plugins/SimClusterToCaloParticleAssociationProducer.cc b/SimCalorimetry/HGCalAssociatorProducers/plugins/SimClusterToCaloParticleAssociationProducer.cc new file mode 100644 index 0000000000000..8a43dbcfc1181 --- /dev/null +++ b/SimCalorimetry/HGCalAssociatorProducers/plugins/SimClusterToCaloParticleAssociationProducer.cc @@ -0,0 +1,68 @@ +#include + +#include "FWCore/Framework/interface/stream/EDProducer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/Framework/interface/ESHandle.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" +#include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" +#include "SimDataFormats/CaloAnalysis/interface/CaloParticle.h" +#include "SimDataFormats/CaloAnalysis/interface/CaloParticleFwd.h" +#include "DataFormats/Common/interface/Association.h" + +#include "FWCore/Utilities/interface/EDGetToken.h" +#include + +// +// class decleration +// +class SimClusterToCaloParticleAssociationProducer : public edm::stream::EDProducer<> { +public: + explicit SimClusterToCaloParticleAssociationProducer(const edm::ParameterSet&); + ~SimClusterToCaloParticleAssociationProducer() override; + +private: + void produce(edm::Event&, const edm::EventSetup&) override; + + edm::EDGetTokenT caloPartToken_; + edm::EDGetTokenT simClusterToken_; +}; + +SimClusterToCaloParticleAssociationProducer::SimClusterToCaloParticleAssociationProducer(const edm::ParameterSet& pset) + : caloPartToken_(consumes(pset.getParameter("caloParticles"))), + simClusterToken_(consumes(pset.getParameter("simClusters"))) { + produces>(); +} + +SimClusterToCaloParticleAssociationProducer::~SimClusterToCaloParticleAssociationProducer() {} + +void SimClusterToCaloParticleAssociationProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { + edm::Handle scCollection; + iEvent.getByToken(simClusterToken_, scCollection); + + edm::Handle cpCollection; + iEvent.getByToken(caloPartToken_, cpCollection); + + std::vector cpIndices(scCollection->size(), -1); + for (size_t i = 0; i < cpCollection->size(); i++) { + for (auto scRef : cpCollection->at(i).simClusters()) + cpIndices[scRef.key()] = i; + } + + auto assoc = std::make_unique>(cpCollection); + edm::Association::Filler filler(*assoc); + filler.insert(scCollection, cpIndices.begin(), cpIndices.end()); + filler.fill(); + iEvent.put(std::move(assoc)); +} + +// define this as a plug-in +DEFINE_FWK_MODULE(SimClusterToCaloParticleAssociationProducer); + + + diff --git a/SimCalorimetry/HGCalAssociatorProducers/plugins/SimHitToSimTrackAndClusterAssociationProducer.cc b/SimCalorimetry/HGCalAssociatorProducers/plugins/SimHitToSimTrackAndClusterAssociationProducer.cc new file mode 100644 index 0000000000000..c575b7682600b --- /dev/null +++ b/SimCalorimetry/HGCalAssociatorProducers/plugins/SimHitToSimTrackAndClusterAssociationProducer.cc @@ -0,0 +1,84 @@ +#include + +#include "FWCore/Framework/interface/stream/EDProducer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/Framework/interface/ESHandle.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +#include "SimDataFormats/CaloHit/interface/PCaloHit.h" +#include "SimDataFormats/Track/interface/SimTrack.h" +#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" +#include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" +#include "DataFormats/Common/interface/Association.h" + +#include "FWCore/Utilities/interface/EDGetToken.h" +#include + +// +// class decleration +// +class SimHitToSimTrackAndClusterAssociationProducer : public edm::stream::EDProducer<> { +public: + explicit SimHitToSimTrackAndClusterAssociationProducer(const edm::ParameterSet&); + ~SimHitToSimTrackAndClusterAssociationProducer() override; + +private: + void produce(edm::Event&, const edm::EventSetup&) override; + + edm::EDGetTokenT> simTrackToken_; + edm::EDGetTokenT> simHitToken_; + edm::EDGetTokenT> simTrackToSimClusterToken_; +}; + +SimHitToSimTrackAndClusterAssociationProducer::SimHitToSimTrackAndClusterAssociationProducer(const edm::ParameterSet& pset) + : simTrackToken_(consumes>(pset.getParameter("simTracks"))), + simHitToken_(consumes>(pset.getParameter("simHits"))), + simTrackToSimClusterToken_(consumes>(pset.getParameter("simTrackToSimCluster"))) { + produces>>(); + produces>(); +} + +SimHitToSimTrackAndClusterAssociationProducer::~SimHitToSimTrackAndClusterAssociationProducer() {} + +void SimHitToSimTrackAndClusterAssociationProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { + edm::Handle> shCollection; + iEvent.getByToken(simTrackToken_, shCollection); + std::unordered_map trackIdToTrackIdx; + + edm::Handle> stCollection; + iEvent.getByToken(simTrackToken_, stCollection); + + edm::Handle> stToscAssociation; + iEvent.getByToken(simTrackToSimClusterToken_, stToscAssociation); + + for (size_t i = 0; i < stCollection->size(); i++) { + trackIdToTrackIdx[stCollection->at(i).trackId()] = i; + } + + std::vector stIndices; + std::vector scIndices; + for (auto& sh : *shCollection) { + size_t id = sh.geantTrackId(); + int idx = trackIdToTrackIdx.find(id) != trackIdToTrackIdx.end() ? trackIdToTrackIdx[id] : -1; + stIndices.push_back(idx); + edm::Ref> st(stCollection, idx); + edm::Ref sc = (*stToscAssociation)[st]; + scIndices.push_back(sc.isNonnull() ? sc.key() : -1); + } + + auto assoc = std::make_unique>>(stCollection); + edm::Association>::Filler filler(*assoc); + filler.insert(shCollection, stIndices.begin(), stIndices.end()); + filler.fill(); + iEvent.put(std::move(assoc)); +} + +// define this as a plug-in +DEFINE_FWK_MODULE(SimHitToSimTrackAndClusterAssociationProducer); + + + diff --git a/SimCalorimetry/HGCalAssociatorProducers/plugins/SimTrackToSimClusterAssociationProducer.cc b/SimCalorimetry/HGCalAssociatorProducers/plugins/SimTrackToSimClusterAssociationProducer.cc new file mode 100644 index 0000000000000..f2710ae69b2b3 --- /dev/null +++ b/SimCalorimetry/HGCalAssociatorProducers/plugins/SimTrackToSimClusterAssociationProducer.cc @@ -0,0 +1,75 @@ +#include + +#include "FWCore/Framework/interface/stream/EDProducer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/Framework/interface/ESHandle.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" +#include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" +#include "SimDataFormats/Track/interface/SimTrack.h" +#include "DataFormats/Common/interface/Association.h" + +#include "FWCore/Utilities/interface/EDGetToken.h" +#include + +// +// class decleration +// +class SimTrackToSimClusterAssociationProducer : public edm::stream::EDProducer<> { +public: + explicit SimTrackToSimClusterAssociationProducer(const edm::ParameterSet&); + ~SimTrackToSimClusterAssociationProducer() override; + +private: + void produce(edm::Event&, const edm::EventSetup&) override; + + edm::EDGetTokenT> simTrackToken_; + edm::EDGetTokenT simClusterToken_; +}; + +SimTrackToSimClusterAssociationProducer::SimTrackToSimClusterAssociationProducer(const edm::ParameterSet& pset) + : simTrackToken_(consumes>(pset.getParameter("simTracks"))), + simClusterToken_(consumes(pset.getParameter("simClusters"))) { + produces>(); +} + +SimTrackToSimClusterAssociationProducer::~SimTrackToSimClusterAssociationProducer() {} + +void SimTrackToSimClusterAssociationProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { + edm::Handle scCollection; + iEvent.getByToken(simClusterToken_, scCollection); + std::unordered_map trackIdToSCIdx; + + edm::Handle> stCollection; + iEvent.getByToken(simTrackToken_, stCollection); + + for (size_t i = 0; i < scCollection->size(); i++) { + for (auto& track : scCollection->at(i).g4Tracks()) { + trackIdToSCIdx[track.trackId()] = i; + } + } + + std::vector scIndices; + for (auto& track : *stCollection) { + size_t id = track.trackId(); + int idx = trackIdToSCIdx.find(id) != trackIdToSCIdx.end() ? trackIdToSCIdx[id] : -1; + scIndices.push_back(idx); + } + + + auto assoc = std::make_unique>(scCollection); + edm::Association::Filler filler(*assoc); + filler.insert(stCollection, scIndices.begin(), scIndices.end()); + filler.fill(); + iEvent.put(std::move(assoc)); +} + +// define this as a plug-in +DEFINE_FWK_MODULE(SimTrackToSimClusterAssociationProducer); + + diff --git a/SimDataFormats/Associations/plugins/SimHitToSimTrackAssociationProducer.cc b/SimDataFormats/Associations/plugins/SimHitToSimTrackAssociationProducer.cc deleted file mode 100644 index 9a2bd7c26ba84..0000000000000 --- a/SimDataFormats/Associations/plugins/SimHitToSimTrackAssociationProducer.cc +++ /dev/null @@ -1,145 +0,0 @@ -// system include files -//#include -//#include -// -//// user include files -//#include "FWCore/Framework/interface/stream/EDProducer.h" -// -//#include "FWCore/Framework/interface/Event.h" -//#include "FWCore/Framework/interface/MakerMacros.h" -// -//#include "FWCore/Framework/interface/ESHandle.h" -// -//#include "FWCore/ParameterSet/interface/ParameterSet.h" -// -//#include "FWCore/MessageLogger/interface/MessageLogger.h" -//#include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" -//#include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" -//#include "SimDataFormats/CaloHit/interface/PCaloHit.h" -//#include "SimDataFormats/Track/interface/SimTrack.h" -// -//#include "DataFormats/Common/interface/Association.h" -//#include "DataFormats/Common/interface/AssociationMap.h" -//#include "DataFormats/Common/interface/OneToManyWithQualityGeneric.h" -//#include "DataFormats/Common/interface/RefToBase.h" -// -// -//#include "FWCore/Utilities/interface/transform.h" -//#include "FWCore/Utilities/interface/EDGetToken.h" -//#include -// -//// -//// class decleration -//// -//typedef std::pair IdxAndFraction; -//typedef edm::AssociationMap> RecHitToSimCluster; -// -//class SimClusterRecHitAssociationProducer : public edm::stream::EDProducer<> { -//public: -// explicit SimClusterRecHitAssociationProducer(const edm::ParameterSet&); -// ~SimClusterRecHitAssociationProducer() override; -// -//private: -// void produce(edm::Event&, const edm::EventSetup&) override; -// -// std::vector> simhitCollectionTokens_; -// edm::EDGetTokenT simtrackCollectionToken_; -//}; -// -//SimClusterRecHitAssociationProducer::SimClusterRecHitAssociationProducer(const edm::ParameterSet& pset) -// : -// caloRechitCollectionTokens_(edm::vector_transform( -// caloRechitTags_, [this](const edm::InputTag& tag) { return consumes(tag); })), -// scCollectionToken_(consumes(pset.getParameter("simClusters"))) { -// for (auto& tag : caloRechitTags_) { -// const std::string& label = tag.instance(); -// produces>(label + "ToBestSimClus"); -// produces(label + "ToSimClus"); -// } -// produces>(); -//} -// -//SimClusterRecHitAssociationProducer::~SimClusterRecHitAssociationProducer() {} -// -//// ------------ method called to produce the data ------------ -//void SimClusterRecHitAssociationProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { -// -// // Go ahead and put a std::unordered_map into the event -// // Also put edm::Association SimHit --> SimTrack -// // -// // Producer for Association Hit --> SimCluster reads unordered_map, then loops through hits_and_fractions of SC -// // -// // New producer for SimHit --> RecHit and RecHit --> SimHits -// // Another producer for RecHit --> SimClusters from reading associations -// // -// // Add variable in SimCluster nano table for whether it should be kept or not -// -// auto simClusterToRecEnergy = std::make_unique>(); -// edm::Handle scCollection; -// iEvent.getByToken(scCollectionToken_, scCollection); -// std::unordered_map> hitDetIdToIndices; -// -// for (size_t s = 0; s < scCollection->size(); s++) { -// const auto& sc = scCollection->at(s); -// (*simClusterToRecEnergy)[s] = 0.; -// for (auto& hf : sc.hits_and_fractions()) { -// // Can have two unique hits with the same detId -// hitDetIdToIndices[hf.first].push_back({s, hf.second}); -// } -// } -// -// std::unordered_map hitDetIdToTotalRecEnergy; -// -// for (size_t i = 0; i < caloRechitCollectionTokens_.size(); i++) { -// std::string label = caloRechitTags_.at(i).instance(); -// std::vector rechitIndices; -// -// edm::Handle caloRechitCollection; -// iEvent.getByToken(caloRechitCollectionTokens_.at(i), caloRechitCollection); -// -// auto assocMap = std::make_unique(caloRechitCollection, scCollection); -// -// for (size_t h = 0; h < caloRechitCollection->size(); h++) { -// HGCRecHitRef caloRh(caloRechitCollection, h); -// size_t id = caloRh->detid().rawId(); -// float energy = caloRh->energy(); -// hitDetIdToTotalRecEnergy[id] += energy; -// -// // Need to sort before inserting into AssociationMap -// auto match = hitDetIdToIndices.find(id); -// if (match == std::end(hitDetIdToIndices)) { -// rechitIndices.push_back(-1); -// continue; -// } -// auto& scIdxAndFrac = match->second; -// // Sort by energy fraction -// std::sort(std::begin(scIdxAndFrac), std::end(scIdxAndFrac), -// [](auto& a, auto& b) { return a.second > b.second; }); -// -// for (size_t m = 0; m < scIdxAndFrac.size(); m++) { -// float fraction = scIdxAndFrac[m].second; -// int scIdx = scIdxAndFrac[m].first; -// (*simClusterToRecEnergy)[scIdx] += energy * fraction; -// // Best match is the simCluster that carries the hit with the highest energy fraction -// // (that is, responsible for the largest deposit in the detId) -// if (m == 0) -// rechitIndices.push_back(scIdx); -// SimClusterRef simclus(scCollection, scIdx); -// assocMap->insert(caloRh, std::make_pair(simclus, fraction)); -// } -// } -// -// auto assoc = std::make_unique>(scCollection); -// edm::Association::Filler filler(*assoc); -// filler.insert(caloRechitCollection, rechitIndices.begin(), rechitIndices.end()); -// filler.fill(); -// iEvent.put(std::move(assoc), label + "ToBestSimClus"); -// iEvent.put(std::move(assocMap), label + "ToSimClus"); -// } -// iEvent.put(std::move(simClusterToRecEnergy)); -//} -// -//// define this as a plug-in -//DEFINE_FWK_MODULE(SimClusterRecHitAssociationProducer); -// From a0e8a683a46718455786bdc36e2d8e281a16be8c Mon Sep 17 00:00:00 2001 From: Nadezda Date: Tue, 15 Jun 2021 16:33:22 +0200 Subject: [PATCH 05/17] fineCalo configurable merging --- .../HGCalNanoAOD/python/simClusters_cff.py | 5 ++- .../plugins/SimClusterTreeMerger.cc | 43 ++++++++++++------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/DPGAnalysis/HGCalNanoAOD/python/simClusters_cff.py b/DPGAnalysis/HGCalNanoAOD/python/simClusters_cff.py index cc0f9fdf1037f..617f40b701584 100644 --- a/DPGAnalysis/HGCalNanoAOD/python/simClusters_cff.py +++ b/DPGAnalysis/HGCalNanoAOD/python/simClusters_cff.py @@ -51,7 +51,10 @@ docString = cms.string("Index of CaloPart containing SimCluster") ) -hgcSimTruth = cms.EDProducer("simmerger") +hgcSimTruth = cms.EDProducer("simmerger", + MergeTheresholdsTransv = cms.vdouble(0.3,0.75,0.85), #(.3, .75, .85), + MergeTheresholdsLongitud = cms.vdouble(0.1,0.9) #(.1, .9) + ) hgcSimTruthDR = cms.EDProducer("HGCTruthProducer") simClusterToMergedSCTable = cms.EDProducer("SimClusterToSimClusterIndexTableProducer", diff --git a/HGCSimTruth/HGCSimTruth/plugins/SimClusterTreeMerger.cc b/HGCSimTruth/HGCSimTruth/plugins/SimClusterTreeMerger.cc index a1f9ef6945537..3fe483f8bac15 100644 --- a/HGCSimTruth/HGCSimTruth/plugins/SimClusterTreeMerger.cc +++ b/HGCSimTruth/HGCSimTruth/plugins/SimClusterTreeMerger.cc @@ -267,7 +267,7 @@ class Node { Node() : trackid_(0), pdgid_(0), initial_energy_(0.), parent_(nullptr) {} - Node(const SimTrack& track) { + Node(const SimTrack& track,vector merging_threshold_transv,vector merging_threshold_longitud) { trackid_ = track.trackId(); initial_energy_ = track.momentum().E(); pdgid_ = track.type(); @@ -283,6 +283,8 @@ class Node { track.getPositionAtBoundary().z() ); } + merging_thresholds_transv_ = merging_threshold_transv; + merging_thresholds_longitud_ = merging_threshold_longitud; } ~Node() {} @@ -311,11 +313,11 @@ class Node { vector cumsum_energies_to_axis = cumsum(apply_argsort(energies, order)); // Find the energy containment radii - vector thresholds = { .3, .75, .85 }; + // vector thresholds = { .3, .75, .85 }; for (std::size_t i = 0; i < cumsum_energies_to_axis.size()-1; ++i) { double cumsum_this = cumsum_energies_to_axis[i] / total_energy; double cumsum_next = cumsum_energies_to_axis[i+1] / total_energy; - for(auto threshold : thresholds){ + for(auto threshold : merging_thresholds_transv_){ if (cumsum_next > threshold && cumsum_this < threshold) // We just crossed a threshold, save the radius energy_containment_radii_[threshold] = d_to_axis[i+1]; @@ -327,12 +329,12 @@ class Node { apply_argsort_in_place(d_along_axis, order); vector cumsum_energies_along_axis = cumsum(apply_argsort(energies, order)); - thresholds = { .1, .9 }; + // thresholds = { .1, .9 }; // Find the longitudinal energy containment quantiles for (std::size_t i = 0; i < cumsum_energies_along_axis.size()-1; ++i) { double cumsum_this = cumsum_energies_along_axis[i] / total_energy; double cumsum_next = cumsum_energies_along_axis[i+1] / total_energy; - for(auto threshold : thresholds){ + for(auto threshold : merging_thresholds_longitud_){ if (cumsum_next > threshold && cumsum_this < threshold){ // We just crossed a threshold, save the radius energy_containment_longitudinally_[threshold] = d_along_axis[i+1]; @@ -526,6 +528,7 @@ class Node { for(auto hit : hits_) hit->z_ *= -1.; } + bool crossed_boundary_, is_hadron_; int trackid_, pdgid_; double initial_energy_, final_z_; @@ -539,6 +542,8 @@ class Node { vector children_; vector merged_trackids_; vector hits_; + + vector merging_thresholds_transv_, merging_thresholds_longitud_; }; /* Finds a track by trackid in a tree */ @@ -582,12 +587,14 @@ b1-----------------e1 b2-----e2 <--------------- */ -double longitudinal_distance(Node& t1, Node& t2){ +double longitudinal_distance(Node& t1, Node& t2,vector longitudinal_containment){ // Vectors of the 10% and 90% longitudinal energy quantiles - Vector3D v1_10 = t1.boundary_position_ + t1.energy_containment_longitudinally_[.1] * t1.axis_; - Vector3D v1_90 = t1.boundary_position_ + t1.energy_containment_longitudinally_[.9] * t1.axis_; - Vector3D v2_10 = t2.boundary_position_ + t2.energy_containment_longitudinally_[.1] * t2.axis_; - Vector3D v2_90 = t2.boundary_position_ + t2.energy_containment_longitudinally_[.9] * t2.axis_; + double lower_quantile = longitudinal_containment[0]; + double upper_quantile = longitudinal_containment[1]; + Vector3D v1_10 = t1.boundary_position_ + t1.energy_containment_longitudinally_[lower_quantile] * t1.axis_; + Vector3D v1_90 = t1.boundary_position_ + t1.energy_containment_longitudinally_[upper_quantile] * t1.axis_; + Vector3D v2_10 = t2.boundary_position_ + t2.energy_containment_longitudinally_[lower_quantile] * t2.axis_; + Vector3D v2_90 = t2.boundary_position_ + t2.energy_containment_longitudinally_[upper_quantile] * t2.axis_; // Rotate them Vector3D origin = t1.boundary_position_; Vector3D rb1 = t1.rotation_.dot(v1_10 - origin); @@ -677,11 +684,14 @@ double polygon_overlap(vector& polygon1, vector& polygon2, i } pair calculate_shower_overlap(Node& t1, Node& t2){ + //reading energy containment thresholds : t1 and t2 both have the same thresholds of course, so it's irrelevant from which node to read them + vector transverse_containment = t1.merging_thresholds_transv_; + vector longitudinal_containment = t1.merging_thresholds_longitud_ ; if (t1.boundary_momentum_.E() < t2.boundary_momentum_.E()) std::swap(t1,t2); double f_radius; - if(t1.is_hadron_ != t2.is_hadron_) f_radius = .3; - else if (t1.is_hadron_ && t2.is_hadron_) f_radius = .75; - else f_radius = .85; + if(t1.is_hadron_ != t2.is_hadron_) f_radius = transverse_containment[0]; + else if (t1.is_hadron_ && t2.is_hadron_) f_radius = transverse_containment[1]; + else f_radius = transverse_containment[2]; double t1_r = std::max(t1.energy_containment_radii_[f_radius], 1.0); double t2_r = std::max(t2.energy_containment_radii_[f_radius], 1.0); @@ -699,7 +709,7 @@ pair calculate_shower_overlap(Node& t1, Node& t2){ t2.inv_rotation_.dot(get_circle(t2_r)) + t2_e - t1_b ); double rcircle_overlap = polygon_overlap(t1_rcircle, t2_rcircle); - double deltaz = longitudinal_distance(t1, t2); + double deltaz = longitudinal_distance(t1, t2, longitudinal_containment); return std::make_pair(rcircle_overlap, deltaz); } @@ -1042,6 +1052,7 @@ class simmerger : public edm::stream::EDProducer<> { edm::EDGetTokenT simClustersToken_; edm::EDGetTokenT> simTrackToSimClusterToken_; unordered_map trackIdToTrackRef_; + vector mergeThresholdsTransv_,mergeThresholdsLongitud_; }; @@ -1053,6 +1064,8 @@ simmerger::simmerger(const edm::ParameterSet& iConfig) : tokenSimVertices(consumes(edm::InputTag("g4SimHits"))), simClustersToken_(consumes(edm::InputTag("mix:MergedCaloTruth"))), simTrackToSimClusterToken_(consumes>(edm::InputTag("simTrackToSimCluster"))) + mergeThresholdsTransv_(iConfig.getParameter > ( "MergeTheresholdsTransv" )), + mergeThresholdsLongitud_(iConfig.getParameter > ( "MergeTheresholdsLongitud" )) { produces(); produces>(); @@ -1110,7 +1123,7 @@ void simmerger::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) { unordered_map trackid_to_node; for(size_t i = 0; i < handleSimTracks->size(); i++){ SimTrackRef track(handleSimTracks, i); - trackid_to_node.emplace(track->trackId(), Node(*track)); + trackid_to_node.emplace(track->trackId(), Node(*track, mergeThresholdsTransv_,mergeThresholdsLongitud_)); trackIdToTrackRef_[track->trackId()] = track; } From a69c9e098f8f40aa496572cf09f9093c972a5b34 Mon Sep 17 00:00:00 2001 From: Thomas Klijnsma Date: Tue, 20 Jul 2021 17:27:27 -0500 Subject: [PATCH 06/17] Fixed finecalo performance --- SimG4CMS/Calo/interface/CaloG4Hit.h | 5 +- SimG4CMS/Calo/interface/CaloHitID.h | 7 +- SimG4CMS/Calo/interface/CaloSD.h | 7 +- SimG4CMS/Calo/src/CaloHitID.cc | 16 +- SimG4CMS/Calo/src/CaloSD.cc | 241 ++++++++++++------------- SimG4CMS/Calo/src/CaloTrkProcessing.cc | 5 +- 6 files changed, 131 insertions(+), 150 deletions(-) diff --git a/SimG4CMS/Calo/interface/CaloG4Hit.h b/SimG4CMS/Calo/interface/CaloG4Hit.h index f96f2e7d4986e..2f1727ee451b0 100644 --- a/SimG4CMS/Calo/interface/CaloG4Hit.h +++ b/SimG4CMS/Calo/interface/CaloG4Hit.h @@ -67,6 +67,7 @@ class CaloG4Hit : public G4VHit { double getTimeSlice() const { return hitID.timeSlice(); } int getTimeSliceID() const { return hitID.timeSliceID(); } uint16_t getDepth() const { return hitID.depth(); } + bool isFinecaloTrackID() const { return hitID.isFinecaloTrackID(); } CaloHitID getID() const { return hitID; } void setID(uint32_t i, double d, int j, uint16_t k = 0) { hitID.setID(i, d, j, k); } @@ -98,8 +99,6 @@ class CaloG4HitLess { return (a->getUnitID() < b->getUnitID()); } else if (a->getDepth() != b->getDepth()) { return (a->getDepth() < b->getDepth()); - } else if (a->getID().fineTrackID() != b->getID().fineTrackID()) { - return (a->getID().fineTrackID() < b->getID().fineTrackID()); } else { return (a->getTimeSliceID() < b->getTimeSliceID()); } @@ -110,7 +109,7 @@ class CaloG4HitEqual { public: bool operator()(const CaloG4Hit* a, const CaloG4Hit* b) { return (a->getTrackID() == b->getTrackID() && a->getUnitID() == b->getUnitID() && a->getDepth() == b->getDepth() && - a->getTimeSliceID() == b->getTimeSliceID() && a->getID().fineTrackID() == b->getID().fineTrackID()); + a->getTimeSliceID() == b->getTimeSliceID()); } }; diff --git a/SimG4CMS/Calo/interface/CaloHitID.h b/SimG4CMS/Calo/interface/CaloHitID.h index d44a4b61f79f5..12d6a68010515 100644 --- a/SimG4CMS/Calo/interface/CaloHitID.h +++ b/SimG4CMS/Calo/interface/CaloHitID.h @@ -26,9 +26,8 @@ class CaloHitID { void reset(); void setTrackID(int trackID) { theTrackID = trackID; } - bool hasFineTrackID() const { return theFineTrackID != -1; } - void setFineTrackID(int fineTrackID) { theFineTrackID = fineTrackID; } - int fineTrackID() const { return hasFineTrackID() ? theFineTrackID : theTrackID; } + void markAsFinecaloTrackID(bool flag = true) { isFinecaloTrackID_ = flag; } + bool isFinecaloTrackID() const { return isFinecaloTrackID_; } bool operator==(const CaloHitID&) const; bool operator<(const CaloHitID&) const; @@ -42,7 +41,7 @@ class CaloHitID { uint16_t theDepth; float timeSliceUnit; bool ignoreTrackID; - int theFineTrackID; + bool isFinecaloTrackID_; }; std::ostream& operator<<(std::ostream&, const CaloHitID&); diff --git a/SimG4CMS/Calo/interface/CaloSD.h b/SimG4CMS/Calo/interface/CaloSD.h index 5b061f291bfa7..65c97ba1bffa3 100644 --- a/SimG4CMS/Calo/interface/CaloSD.h +++ b/SimG4CMS/Calo/interface/CaloSD.h @@ -28,6 +28,7 @@ #include #include +#include #include class G4Step; @@ -85,7 +86,9 @@ class CaloSD : public SensitiveCaloDetector, double getAttenuation(const G4Step* aStep, double birk1, double birk2, double birk3) const; static std::string printableDecayChain(const std::vector& decayChain); - void hitBookkeepingFineCalo(const G4Step* step, const G4Track* currentTrack, CaloG4Hit* hit); + std::string shortreprID(const CaloHitID& ID); + std::string shortreprID(const CaloG4Hit* hit); + unsigned int findBoundaryCrossingParent(const G4Track* track, bool markParentAsSaveable = true); void update(const BeginOfRun*) override; void update(const BeginOfEvent*) override; @@ -183,8 +186,10 @@ class CaloSD : public SensitiveCaloDetector, std::map hitMap; std::map tkMap; + std::unordered_map boundaryCrossingParentMap_; std::vector> reusehit; std::vector fineDetectors_; + bool doFineCaloThisStep_; }; #endif // SimG4CMS_CaloSD_h diff --git a/SimG4CMS/Calo/src/CaloHitID.cc b/SimG4CMS/Calo/src/CaloHitID.cc index 2854a27f68909..e260a67498282 100644 --- a/SimG4CMS/Calo/src/CaloHitID.cc +++ b/SimG4CMS/Calo/src/CaloHitID.cc @@ -7,7 +7,7 @@ #include CaloHitID::CaloHitID(uint32_t unitID, double timeSlice, int trackID, uint16_t depth, float tSlice, bool ignoreTkID) - : timeSliceUnit(tSlice), ignoreTrackID(ignoreTkID), theFineTrackID(-1) { + : timeSliceUnit(tSlice), ignoreTrackID(ignoreTkID), isFinecaloTrackID_(false) { setID(unitID, timeSlice, trackID, depth); } @@ -21,7 +21,7 @@ CaloHitID::CaloHitID(const CaloHitID& id) { theDepth = id.theDepth; timeSliceUnit = id.timeSliceUnit; ignoreTrackID = id.ignoreTrackID; - theFineTrackID = id.theFineTrackID; + isFinecaloTrackID_ = id.isFinecaloTrackID_; } const CaloHitID& CaloHitID::operator=(const CaloHitID& id) { @@ -32,7 +32,7 @@ const CaloHitID& CaloHitID::operator=(const CaloHitID& id) { theDepth = id.theDepth; timeSliceUnit = id.timeSliceUnit; ignoreTrackID = id.ignoreTrackID; - theFineTrackID = id.theFineTrackID; + isFinecaloTrackID_ = id.isFinecaloTrackID_; return *this; } @@ -52,12 +52,12 @@ void CaloHitID::reset() { theTrackID = -2; theTimeSliceID = (int)(theTimeSlice / timeSliceUnit); theDepth = 0; - theFineTrackID = -1; + isFinecaloTrackID_ = false; } bool CaloHitID::operator==(const CaloHitID& id) const { return ((theUnitID == id.unitID()) && (theTrackID == id.trackID() || ignoreTrackID) && - (theTimeSliceID == id.timeSliceID()) && (theDepth == id.depth()) && (fineTrackID() == id.fineTrackID())) + (theTimeSliceID == id.timeSliceID()) && (theDepth == id.depth())) ? true : false; } @@ -65,8 +65,6 @@ bool CaloHitID::operator==(const CaloHitID& id) const { bool CaloHitID::operator<(const CaloHitID& id) const { if (theTrackID != id.trackID()) { return (theTrackID > id.trackID()); - } else if (fineTrackID() != id.fineTrackID()) { - return (fineTrackID() > id.fineTrackID()); } else if (theUnitID != id.unitID()) { return (theUnitID > id.unitID()); } else if (theDepth != id.depth()) { @@ -79,8 +77,6 @@ bool CaloHitID::operator<(const CaloHitID& id) const { bool CaloHitID::operator>(const CaloHitID& id) const { if (theTrackID != id.trackID()) { return (theTrackID < id.trackID()); - } else if (fineTrackID() != id.fineTrackID()) { - return (fineTrackID() < id.fineTrackID()); } else if (theUnitID != id.unitID()) { return (theUnitID < id.unitID()); } else if (theDepth != id.depth()) { @@ -93,7 +89,5 @@ bool CaloHitID::operator>(const CaloHitID& id) const { std::ostream& operator<<(std::ostream& os, const CaloHitID& id) { os << "UnitID 0x" << std::hex << id.unitID() << std::dec << " Depth " << std::setw(6) << id.depth() << " Time " << std::setw(6) << id.timeSlice() << " TrackID " << std::setw(8) << id.trackID(); - if (id.hasFineTrackID()) - os << " fineTrackID " << id.fineTrackID(); return os; } diff --git a/SimG4CMS/Calo/src/CaloSD.cc b/SimG4CMS/Calo/src/CaloSD.cc index db80624d15d70..b85f4bb70d7aa 100644 --- a/SimG4CMS/Calo/src/CaloSD.cc +++ b/SimG4CMS/Calo/src/CaloSD.cc @@ -31,7 +31,7 @@ #include #include -//#define EDM_ML_DEBUG +// #define EDM_ML_DEBUG CaloSD::CaloSD(const std::string& name, const SensitiveDetectorCatalog& clg, @@ -115,7 +115,8 @@ CaloSD::CaloSD(const std::string& name, << " ns and if energy is above " << eminHit / CLHEP::MeV << " MeV (for depth 0) or " << eminHitD / CLHEP::MeV << " MeV (for nonzero depths);\n Time Slice Unit " << timeSlice << "\nIgnore TrackID Flag " << ignoreTrackID << " doFineCalo flag " - << doFineCalo_; + << doFineCalo_ << "\nBeam Position " << beamZ / CLHEP::cm << " cm"; + if(doFineCalo_) edm::LogVerbatim("DoFineCalo") << "Using finecalo v2"; // Treat fine calorimeters edm::LogVerbatim("CaloSim") << "CaloSD: Have a possibility of " << fineNames.size() << " fine calorimeters of which " @@ -168,6 +169,10 @@ G4bool CaloSD::ProcessHits(G4Step* aStep, G4TouchableHistory*) { << " Eprestep= " << aStep->GetPreStepPoint()->GetKineticEnergy() << " step= " << aStep->GetStepLength() << " Edep= " << aStep->GetTotalEnergyDeposit(); #endif + + // Class variable to determine whether finecalo rules should apply for this step + doFineCaloThisStep_ = (doFineCalo_ && isItFineCalo(aStep->GetPreStepPoint()->GetTouchable())); + // apply shower library or parameterisation if (isParameterized) { if (getFromLibrary(aStep)) { @@ -213,6 +218,10 @@ G4bool CaloSD::ProcessHits(G4Step* aStep, G4TouchableHistory*) { double energy = getEnergyDeposit(aStep); if (energy > 0.0) { + if (doFineCaloThisStep_) { + currentID.setID(unitID, time, findBoundaryCrossingParent(theTrack), depth); + currentID.markAsFinecaloTrackID(); + } if (G4TrackToParticleID::isGammaElectronPositron(theTrack)) { edepositEM = energy; } else { @@ -232,7 +241,7 @@ G4bool CaloSD::ProcessHits(G4Step* aStep, G4TouchableHistory*) { currentHit = createNewHit(aStep, aStep->GetTrack()); } else { #ifdef EDM_ML_DEBUG - edm::LogVerbatim("DoFineCalo") << "Not creating new hit, only updating currentHit " << currentHit->getUnitID(); + edm::LogVerbatim("DoFineCalo") << "Not creating new hit, only updating " << shortreprID(currentHit); #endif } return true; @@ -444,11 +453,11 @@ bool CaloSD::checkHit() { int CaloSD::getNumberOfHits() { return theHC->entries(); } +/* +Takes a vector of ints (representing trackIDs), and returns a formatted string +for debugging purposes +*/ std::string CaloSD::printableDecayChain(const std::vector& decayChain) { - /* - Takes a vector of ints (representing trackIDs), and returns a formatted string - for debugging purposes - */ std::stringstream ss; for (long unsigned int i = 0; i < decayChain.size(); i++) { if (i > 0) @@ -458,111 +467,91 @@ std::string CaloSD::printableDecayChain(const std::vector& decayCh return ss.str(); } -void CaloSD::hitBookkeepingFineCalo(const G4Step* step, const G4Track* currentTrack, CaloG4Hit* hit) { - /* - Performs bookkeeping: Determines what trackIDs are to be recorded for the hit (typically some - some parent trackID), and also sets the right flags on either the TrackInformation object or - the TrackWithHistory object to make sure the right track is saved to the SimTrack collection. - - `currentTrack` is the track that is currently being processed by Geant - */ - TrackInformation* trkInfo = cmsTrackInformation(currentTrack); - // Copy the class's currentID so we can freely modify it without influencing - // hits created later in possibly non-fine detectors by the same track - CaloHitID hitID = currentID; - // First check if the current currentTrack passes criteria - if (trkInfo->crossedBoundary()) { +/* Very short representation of a CaloHitID */ +std::string CaloSD::shortreprID(const CaloHitID& ID) { + std::stringstream ss; + ss << GetName() << "/" << ID.unitID() << "/trk" << ID.trackID() << "/d" << ID.depth() << "/time" << ID.timeSliceID(); + if (ID.isFinecaloTrackID()) + ss << "/FC"; + return ss.str(); +} + +/* As above, but with a hit as input */ +std::string CaloSD::shortreprID(const CaloG4Hit* hit) { return shortreprID(hit->getID()); } + +/* +Finds the boundary-crossing parent of a track, and stores it in the CaloSD's map +*/ +unsigned int CaloSD::findBoundaryCrossingParent(const G4Track* track, bool markAsSaveable) { + TrackInformation* trkInfo = cmsTrackInformation(track); + unsigned int id = track->GetTrackID(); + // First see if this track is already in the map + auto it = boundaryCrossingParentMap_.find(id); + if (it != boundaryCrossingParentMap_.end()) { #ifdef EDM_ML_DEBUG - edm::LogVerbatim("DoFineCalo") << "currentTrack " << currentTrack->GetTrackID() - << " itself has crossedBoundary=" << trkInfo->crossedBoundary() - << " ; recording it for hit " << hit->getUnitID(); + edm::LogVerbatim("DoFineCalo") << "Track " << id << " parent already cached: " << it->second; #endif - hitID.setFineTrackID(currentTrack->GetTrackID()); - hit->setID(hitID); // Actually overwrite the ID for the hit - trkInfo->storeTrack(true); - return; + return it->second; } - // currentTrack itself does not pass thresholds / does not cross boundary; go through its history to find a track that does - TrackWithHistory* recordTrackWithHistory; - // Keep track of decay chain of this track for debugging purposes - std::vector decayChain; - decayChain.push_back(currentTrack->GetTrackID()); - // Find the first parent of this track that passes the required criteria - // Start from first parent - unsigned int recordTrackID = currentTrack->GetParentID(); + // Then see if the track itself crosses the boundary + else if (trkInfo->crossedBoundary()) { #ifdef EDM_ML_DEBUG - edm::LogVerbatim("DoFineCalo") << "Trying to find the first parent of hit " << hit->getUnitID() - << " that passes saving criterion (crosses boundary or specific criterion)" - << "; starting with first parent track " << recordTrackID; + edm::LogVerbatim("DoFineCalo") << "Track " << id << " crosses boundary itself"; #endif - // Check whether this first parent actually exists - if (recordTrackID <= 0) { - // Track ID 0 is not a track; - // This means the current currentTrack has no parent, but apparently it also didn't fit saving criteria - throw cms::Exception("Unknown", "CaloSD") << "ERROR: Track " << currentTrack->GetTrackID() - << " has no parent, does not fit saving criteria, but left hit " - << hit->getUnitID() << "; recording it but it's weird!"; + boundaryCrossingParentMap_[id] = id; + trkInfo->storeTrack(true); + return id; } - // Start progressing through the track's history + // Else, traverse the history of the track + std::vector decayChain{id}; +#ifdef EDM_ML_DEBUG + edm::LogVerbatim("DoFineCalo") << "Track " << id << ": Traversing history to find boundary-crossing parent"; +#endif + unsigned int parentID = track->GetParentID(); while (true) { - // Record the decay chain for debugging purposes - decayChain.push_back(recordTrackID); - recordTrackWithHistory = m_trackManager->getTrackByID(recordTrackID); - if (recordTrackID < (unsigned int)hitID.trackID()) { - // A parent of the currentTrack has a lower trackID than the current - // hitID.trackID(). This means the current hitID.trackID() does not point - // to the earliest ancestor of the currentTrack. - // The current hitID.trackID() might not be a saved track yet, but the - // ancestor is *always* a saved track. - // Fix this by overwriting the hitID's track ID. + if (parentID == 0) + throw cms::Exception("Unknown", "CaloSD") + << "Hit end of parentage for track " << id << " without finding a boundary-crossing parent"; + // First check if this ancestor is already in the map + auto it = boundaryCrossingParentMap_.find(parentID); + if (it != boundaryCrossingParentMap_.end()) { #ifdef EDM_ML_DEBUG - edm::LogVerbatim("DoFineCalo") << "History-tracking progressed to track " << recordTrackID - << ", which is an earlier ancestor than current primary " << hitID.trackID() - << "; overwriting it."; + edm::LogVerbatim("DoFineCalo") << " Track " << parentID + << " boundary-crossing parent already cached: " << it->second; #endif - hitID.setTrackID(recordTrackID); - } - // Check if this parent fits the boundary-crossing criteria - if (recordTrackWithHistory->crossedBoundary() && recordTrackWithHistory->getIDAtBoundary() == (int)recordTrackID) { + // Store this parent also for the rest of the traversed decay chain + for (auto ancestorID : decayChain) + boundaryCrossingParentMap_[ancestorID] = it->second; #ifdef EDM_ML_DEBUG - edm::LogVerbatim("DoFineCalo") << "Recording track " << recordTrackID << " as source of hit " << hit->getUnitID() - << "; crossed boundary at pos=(" - << recordTrackWithHistory->getPositionAtBoundary().x() << "," - << recordTrackWithHistory->getPositionAtBoundary().y() << "," - << recordTrackWithHistory->getPositionAtBoundary().z() << ")" - << " mom=(" << recordTrackWithHistory->getMomentumAtBoundary().x() << "," - << recordTrackWithHistory->getMomentumAtBoundary().y() << "," - << recordTrackWithHistory->getMomentumAtBoundary().z() << "," - << recordTrackWithHistory->getMomentumAtBoundary().e() << ")" - << " id@boundary=" << recordTrackWithHistory->getIDAtBoundary() - << "; decayChain: " << printableDecayChain(decayChain); + // In debug mode, still build the rest of the decay chain for debugging + decayChain.push_back(parentID); + while (parentID != it->second) { + parentID = m_trackManager->getTrackByID(parentID, true)->parentID(); + decayChain.push_back(parentID); + } + edm::LogVerbatim("DoFineCalo") << " Full decay chain: " << printableDecayChain(decayChain); #endif - break; + return it->second; } - // This parent track did not fit criteria - go to the next parent + // If not, get this parent from the track manager (expensive) + TrackWithHistory* parentTrack = m_trackManager->getTrackByID(parentID, true); + if (parentTrack->crossedBoundary()) { + if (markAsSaveable) + parentTrack->save(); + decayChain.push_back(parentID); + // Record this boundary crossing parent for all traversed ancestors + for (auto ancestorID : decayChain) + boundaryCrossingParentMap_[ancestorID] = parentID; #ifdef EDM_ML_DEBUG - edm::LogVerbatim("DoFineCalo") << "Track " << recordTrackID << " did not cross the boundary or fit other criteria"; + edm::LogVerbatim("DoFineCalo") << " Found boundary-crossing ancestor " << parentID << " for track " << id + << "; decay chain: " << printableDecayChain(decayChain); #endif - recordTrackID = recordTrackWithHistory->parentID(); - if (recordTrackID <= 0) { - // Track ID 0 is not a track; - // This means that no parent of the currentTrack fitted the criteria - throw cms::Exception("Unknown", "CaloSD") - << "Hit " << hit->getUnitID() << " does not have any parent track that passes the criteria!" - << " decayChain so far: " << printableDecayChain(decayChain); + return parentID; } + // Next iteration + decayChain.push_back(parentID); + parentID = parentTrack->parentID(); } - // Parentage traversal done - do the bookeeping for the found ancestor track - recordTrackWithHistory->save(); - hitID.setFineTrackID(recordTrackID); - hit->setID(hitID); // Actually overwrite the ID for the hit -#ifdef EDM_ML_DEBUG - edm::LogVerbatim("DoFineCalo") << "Stored the following bookeeping for hit " << hit->getUnitID() - << " hitID.trackID()=" << hitID.trackID() - << " hitID.fineTrackID()=" << hitID.fineTrackID() - << " recordTrackWithHistory->trackID()=" << recordTrackWithHistory->trackID() - << " recordTrackWithHistory->saved()=" << recordTrackWithHistory->saved(); -#endif } CaloG4Hit* CaloSD::createNewHit(const G4Step* aStep, const G4Track* theTrack) { @@ -598,30 +587,28 @@ CaloG4Hit* CaloSD::createNewHit(const G4Step* aStep, const G4Track* theTrack) { storeHit(aHit); TrackInformation* trkInfo = cmsTrackInformation(theTrack); +<<<<<<< HEAD bool currentlyInsideFineVolume = isItFineCalo(aStep->GetPostStepPoint()->GetTouchable()); +======= +>>>>>>> 8882912224a... Fixed finecalo performance #ifdef EDM_ML_DEBUG - edm::LogVerbatim("DoFineCalo") << "Creating new hit " << aHit->getUnitID() << " using " - << (currentlyInsideFineVolume ? "FINECALO" : "normal CaloSD") - << "; currentID.trackID=" << currentID.trackID() - << " currentID.fineTrackID=" << currentID.fineTrackID() - << " isItFineCalo(aStep->GetPostStepPoint()->GetTouchable())=" - << isItFineCalo(aStep->GetPostStepPoint()->GetTouchable()) - << " isItFineCalo(aStep->GetPreStepPoint()->GetTouchable())=" - << isItFineCalo(aStep->GetPreStepPoint()->GetTouchable()) - << " theTrack=" << theTrack->GetTrackID() << " (" - << " parentTrackId=" << theTrack->GetParentID() - << " getIDonCaloSurface=" << trkInfo->getIDonCaloSurface() << ")" - << " primIDSaved=" << primIDSaved; + if (doFineCaloThisStep_) + edm::LogVerbatim("DoFineCalo") << "New hit " << shortreprID(aHit) << " using finecalo;" + << " isItFineCalo(post)=" << isItFineCalo(aStep->GetPostStepPoint()->GetTouchable()) + << " isItFineCalo(pre)=" << isItFineCalo(aStep->GetPreStepPoint()->GetTouchable()); #endif +<<<<<<< HEAD // If fine calo is activated for the current volume, perform track/hit // saving logic for fineCalo if (doFineCalo_ && currentlyInsideFineVolume) { hitBookkeepingFineCalo(aStep, theTrack, aHit); } +======= +>>>>>>> 8882912224a... Fixed finecalo performance // 'Traditional', non-fine history bookkeeping - else { + if (!doFineCaloThisStep_) { double etrack = 0; if (currentID.trackID() == primIDSaved) { // The track is saved; nothing to be done } else if (currentID.trackID() == theTrack->GetTrackID()) { @@ -795,6 +782,7 @@ void CaloSD::update(const ::EndOfEvent*) { std::vector>().swap(reusehit); if (useMap) hitMap.erase(hitMap.begin(), hitMap.end()); + boundaryCrossingParentMap_.clear(); } void CaloSD::clearHits() { @@ -902,26 +890,22 @@ bool CaloSD::saveHit(CaloG4Hit* aHit) { if (corrTOFBeam) time += correctT; - // Do track bookkeeping a little differently for fine tracking - if (doFineCalo_ && aHit->getID().hasFineTrackID()) { - tkID = aHit->getID().fineTrackID(); + // More strict bookkeeping for finecalo + if (doFineCalo_ && aHit->isFinecaloTrackID()) { #ifdef EDM_ML_DEBUG - edm::LogVerbatim("DoFineCalo") << "Saving hit " << aHit->getUnitID() << " with trackID=" << tkID; + edm::LogVerbatim("DoFineCalo") << "Saving hit " << shortreprID(aHit); #endif - // Check if the track is actually in the trackManager - if (m_trackManager) { - if (!m_trackManager->trackExists(tkID)) { - ok = false; - throw cms::Exception("Unknown", "CaloSD") - << "aHit " << aHit->getUnitID() << " has fine trackID " << tkID << ", which is NOT IN THE TRACK MANAGER"; - } - } else { - ok = false; - throw cms::Exception("Unknown", "CaloSD") << "m_trackManager not set, saveHit ok=false!"; - } - // Take the aHit-information and move it to the actual PCaloHitContainer - slave.get()->processHits( - aHit->getUnitID(), aHit->getEM() / CLHEP::GeV, aHit->getHadr() / CLHEP::GeV, time, tkID, aHit->getDepth()); + if (!m_trackManager) + throw cms::Exception("Unknown", "CaloSD") << "m_trackManager not set, needed for finecalo!"; + if (!m_trackManager->trackExists(aHit->getTrackID())) + throw cms::Exception("Unknown", "CaloSD") + << "Error on hit " << shortreprID(aHit) << ": Parent track not in track manager"; + slave.get()->processHits(aHit->getUnitID(), + aHit->getEM() / CLHEP::GeV, + aHit->getHadr() / CLHEP::GeV, + time, + aHit->getTrackID(), + aHit->getDepth()); } // Regular, not-fine way: else { @@ -939,8 +923,7 @@ bool CaloSD::saveHit(CaloG4Hit* aHit) { ok = false; } #ifdef EDM_ML_DEBUG - edm::LogVerbatim("DoFineCalo") << "Saving hit " << aHit->getUnitID() << " with trackID=" << tkID - << " (no fineTrackID)"; + edm::LogVerbatim("DoFineCalo") << "Saving hit " << shortreprID(aHit) << " with trackID=" << tkID; #endif slave.get()->processHits( aHit->getUnitID(), aHit->getEM() / CLHEP::GeV, aHit->getHadr() / CLHEP::GeV, time, tkID, aHit->getDepth()); diff --git a/SimG4CMS/Calo/src/CaloTrkProcessing.cc b/SimG4CMS/Calo/src/CaloTrkProcessing.cc index 4304e54c7752d..44bb35653208c 100644 --- a/SimG4CMS/Calo/src/CaloTrkProcessing.cc +++ b/SimG4CMS/Calo/src/CaloTrkProcessing.cc @@ -21,7 +21,7 @@ #include "DD4hep/Filter.h" #include -//#define EDM_ML_DEBUG +// #define EDM_ML_DEBUG CaloTrkProcessing::CaloTrkProcessing(const std::string& name, const edm::EventSetup& es, @@ -288,7 +288,8 @@ void CaloTrkProcessing::update(const G4Step* aStep) { trkInfo->setIDonCaloSurface( id, ical, inside, theTrack->GetDefinition()->GetPDGEncoding(), theTrack->GetMomentum().mag()); trkInfo->setCaloIDChecked(true); - trkInfo->setCrossedBoundary(theTrack); + if (!doFineCalo_) + trkInfo->setCrossedBoundary(theTrack); lastTrackID_ = id; if (theTrack->GetKineticEnergy() / CLHEP::MeV > eMin_) trkInfo->putInHistory(); From 7d9dce9134eb9994aa66c5e3ecae29ddd17d6b22 Mon Sep 17 00:00:00 2001 From: Thomas Klijnsma Date: Thu, 22 Jul 2021 14:02:07 -0500 Subject: [PATCH 07/17] format --- SimG4CMS/Calo/src/CaloSD.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SimG4CMS/Calo/src/CaloSD.cc b/SimG4CMS/Calo/src/CaloSD.cc index b85f4bb70d7aa..5d57ef5db3a61 100644 --- a/SimG4CMS/Calo/src/CaloSD.cc +++ b/SimG4CMS/Calo/src/CaloSD.cc @@ -116,7 +116,8 @@ CaloSD::CaloSD(const std::string& name, << eminHitD / CLHEP::MeV << " MeV (for nonzero depths);\n Time Slice Unit " << timeSlice << "\nIgnore TrackID Flag " << ignoreTrackID << " doFineCalo flag " << doFineCalo_ << "\nBeam Position " << beamZ / CLHEP::cm << " cm"; - if(doFineCalo_) edm::LogVerbatim("DoFineCalo") << "Using finecalo v2"; + if (doFineCalo_) + edm::LogVerbatim("DoFineCalo") << "Using finecalo v2"; // Treat fine calorimeters edm::LogVerbatim("CaloSim") << "CaloSD: Have a possibility of " << fineNames.size() << " fine calorimeters of which " From f1e08063679b39ba34c4ff2e8ae1e4bbd8b67f1c Mon Sep 17 00:00:00 2001 From: Thomas Klijnsma Date: Thu, 22 Jul 2021 13:55:02 -0500 Subject: [PATCH 08/17] No longer count reentries into the calorimeter as boundary crossings Fix merge error Fix merge errors --- .../plugins/SimClusterTreeMerger.cc | 2 +- SimG4CMS/Calo/src/CaloSD.cc | 13 ----- SimG4CMS/Calo/src/CaloTrkProcessing.cc | 48 +++++++++++++------ .../Notification/interface/TrackInformation.h | 13 +++-- 4 files changed, 44 insertions(+), 32 deletions(-) diff --git a/HGCSimTruth/HGCSimTruth/plugins/SimClusterTreeMerger.cc b/HGCSimTruth/HGCSimTruth/plugins/SimClusterTreeMerger.cc index 3fe483f8bac15..c7b1b0e71e0ad 100644 --- a/HGCSimTruth/HGCSimTruth/plugins/SimClusterTreeMerger.cc +++ b/HGCSimTruth/HGCSimTruth/plugins/SimClusterTreeMerger.cc @@ -1063,7 +1063,7 @@ simmerger::simmerger(const edm::ParameterSet& iConfig) : tokenSimTracks(consumes(edm::InputTag("g4SimHits"))), tokenSimVertices(consumes(edm::InputTag("g4SimHits"))), simClustersToken_(consumes(edm::InputTag("mix:MergedCaloTruth"))), - simTrackToSimClusterToken_(consumes>(edm::InputTag("simTrackToSimCluster"))) + simTrackToSimClusterToken_(consumes>(edm::InputTag("simTrackToSimCluster"))), mergeThresholdsTransv_(iConfig.getParameter > ( "MergeTheresholdsTransv" )), mergeThresholdsLongitud_(iConfig.getParameter > ( "MergeTheresholdsLongitud" )) { diff --git a/SimG4CMS/Calo/src/CaloSD.cc b/SimG4CMS/Calo/src/CaloSD.cc index 5d57ef5db3a61..3cb9ee7ba2698 100644 --- a/SimG4CMS/Calo/src/CaloSD.cc +++ b/SimG4CMS/Calo/src/CaloSD.cc @@ -588,11 +588,6 @@ CaloG4Hit* CaloSD::createNewHit(const G4Step* aStep, const G4Track* theTrack) { storeHit(aHit); TrackInformation* trkInfo = cmsTrackInformation(theTrack); -<<<<<<< HEAD - bool currentlyInsideFineVolume = isItFineCalo(aStep->GetPostStepPoint()->GetTouchable()); - -======= ->>>>>>> 8882912224a... Fixed finecalo performance #ifdef EDM_ML_DEBUG if (doFineCaloThisStep_) edm::LogVerbatim("DoFineCalo") << "New hit " << shortreprID(aHit) << " using finecalo;" @@ -600,14 +595,6 @@ CaloG4Hit* CaloSD::createNewHit(const G4Step* aStep, const G4Track* theTrack) { << " isItFineCalo(pre)=" << isItFineCalo(aStep->GetPreStepPoint()->GetTouchable()); #endif -<<<<<<< HEAD - // If fine calo is activated for the current volume, perform track/hit - // saving logic for fineCalo - if (doFineCalo_ && currentlyInsideFineVolume) { - hitBookkeepingFineCalo(aStep, theTrack, aHit); - } -======= ->>>>>>> 8882912224a... Fixed finecalo performance // 'Traditional', non-fine history bookkeeping if (!doFineCaloThisStep_) { double etrack = 0; diff --git a/SimG4CMS/Calo/src/CaloTrkProcessing.cc b/SimG4CMS/Calo/src/CaloTrkProcessing.cc index 44bb35653208c..5a7338b77c3c7 100644 --- a/SimG4CMS/Calo/src/CaloTrkProcessing.cc +++ b/SimG4CMS/Calo/src/CaloTrkProcessing.cc @@ -196,20 +196,22 @@ void CaloTrkProcessing::update(const G4Step* aStep) { } if (doFineCalo_) { - // Boundary-crossing logic int prestepLV = isItCalo(aStep->GetPreStepPoint()->GetTouchable(), fineDetectors_); int poststepLV = isItCalo(aStep->GetPostStepPoint()->GetTouchable(), fineDetectors_); - if (prestepLV < 0 && poststepLV >= 0 - // Allow back-scattering and filter it out later; ensure consistency during the SIM step - // && std::abs(theTrack->GetStep()->GetPreStepPoint()->GetPosition().z()) < std::abs(theTrack->GetPosition().z()) - ) { + + // Once per track, determine whether track started in fine volume + if (!trkInfo->startedInFineVolumeIsSet()) + trkInfo->setStartedInFineVolume(prestepLV >= 0); + + // Boundary-crossing logic + if (prestepLV < 0 && poststepLV >= 0) { #ifdef EDM_ML_DEBUG - edm::LogVerbatim("DoFineCalo") << "Entered fine volume " << poststepLV << ":" - << " Track " << id << " pdgid=" << theTrack->GetDefinition()->GetPDGEncoding() + edm::LogVerbatim("DoFineCalo") << "Track " << id << " entered a fine volume:" + << " pdgid=" << theTrack->GetDefinition()->GetPDGEncoding() + << " theTrack->GetCurrentStepNumber()=" << theTrack->GetCurrentStepNumber() << " prestepLV=" << prestepLV << " poststepLV=" << poststepLV << " GetKineticEnergy[GeV]=" << theTrack->GetKineticEnergy() / CLHEP::GeV - << " GetVertexKineticEnergy[GeV]=" - << theTrack->GetVertexKineticEnergy() / CLHEP::GeV << " prestepPosition[cm]=(" + << " prestepPosition[cm]=(" << theTrack->GetStep()->GetPreStepPoint()->GetPosition().x() / CLHEP::cm << "," << theTrack->GetStep()->GetPreStepPoint()->GetPosition().y() / CLHEP::cm << "," << theTrack->GetStep()->GetPreStepPoint()->GetPosition().z() / CLHEP::cm << ")" @@ -222,17 +224,33 @@ void CaloTrkProcessing::update(const G4Step* aStep) { << theTrack->GetPosition().z() / CLHEP::cm << ")" << " vertex_position[cm]=(" << theTrack->GetVertexPosition().x() / CLHEP::cm << "," << theTrack->GetVertexPosition().y() / CLHEP::cm << "," - << theTrack->GetVertexPosition().z() / CLHEP::cm << ")"; + << theTrack->GetVertexPosition().z() / CLHEP::cm << ")" + << " GetVertexKineticEnergy[GeV]=" + << theTrack->GetVertexKineticEnergy() / CLHEP::GeV; +#endif + if (!trkInfo->startedInFineVolume() && !trkInfo->crossedBoundary()) { + trkInfo->setCrossedBoundary(theTrack); +#ifdef EDM_ML_DEBUG + edm::LogVerbatim("DoFineCalo") << "Track " << id << " marked as boundary-crossing; sanity check:" + << " theTrack->GetTrackID()=" << theTrack->GetTrackID() + << " trkInfo->crossedBoundary()=" << trkInfo->crossedBoundary(); #endif - trkInfo->setCrossedBoundary(theTrack); + } +#ifdef EDM_ML_DEBUG + else { + edm::LogVerbatim("DoFineCalo") << "Track " << id << " REENTERED a fine volume;" + << " not counting this boundary crossing!"; + } +#endif + } #ifdef EDM_ML_DEBUG else if (prestepLV >= 0 && poststepLV < 0) { - edm::LogVerbatim("DoFineCalo") << "Exited fine volume " << prestepLV << ":" - << " Track " << id + edm::LogVerbatim("DoFineCalo") << "Track " << id << " exited a fine volume:" + << " theTrack->GetCurrentStepNumber()=" << theTrack->GetCurrentStepNumber() + << " prestepLV=" << prestepLV << " poststepLV=" << poststepLV << " GetKineticEnergy[GeV]=" << theTrack->GetKineticEnergy() / CLHEP::GeV - << " GetVertexKineticEnergy[GeV]=" - << theTrack->GetVertexKineticEnergy() / CLHEP::GeV << " prestepPosition[cm]=(" + << " prestepPosition[cm]=(" << theTrack->GetStep()->GetPreStepPoint()->GetPosition().x() / CLHEP::cm << "," << theTrack->GetStep()->GetPreStepPoint()->GetPosition().y() / CLHEP::cm << "," << theTrack->GetStep()->GetPreStepPoint()->GetPosition().z() / CLHEP::cm << ")" diff --git a/SimG4Core/Notification/interface/TrackInformation.h b/SimG4Core/Notification/interface/TrackInformation.h index d45c5e306058c..105f6bfcf890a 100644 --- a/SimG4Core/Notification/interface/TrackInformation.h +++ b/SimG4Core/Notification/interface/TrackInformation.h @@ -60,7 +60,6 @@ class TrackInformation : public G4VUserTrackInformation { // Boundary crossing variables void setCrossedBoundary(const G4Track *track) { crossedBoundary_ = true; - idAtBoundary_ = track->GetTrackID(); positionAtBoundary_ = math::XYZTLorentzVectorF(track->GetPosition().x() / CLHEP::cm, track->GetPosition().y() / CLHEP::cm, track->GetPosition().z() / CLHEP::cm, @@ -73,7 +72,12 @@ class TrackInformation : public G4VUserTrackInformation { bool crossedBoundary() const { return crossedBoundary_; } const math::XYZTLorentzVectorF &getPositionAtBoundary() const { return positionAtBoundary_; } const math::XYZTLorentzVectorF &getMomentumAtBoundary() const { return momentumAtBoundary_; } - int getIDAtBoundary() const { return idAtBoundary_; } + bool startedInFineVolume() const { return startedInFineVolume_; } + void setStartedInFineVolume(bool flag = true) { + startedInFineVolume_ = flag; + startedInFineVolumeIsSet_ = true; + } + bool startedInFineVolumeIsSet() { return startedInFineVolumeIsSet_; } // Generator information int genParticlePID() const { return genParticlePID_; } @@ -104,9 +108,10 @@ class TrackInformation : public G4VUserTrackInformation { int idLastVolume_; bool caloIDChecked_; bool crossedBoundary_; - bool idAtBoundary_; math::XYZTLorentzVectorF positionAtBoundary_; math::XYZTLorentzVectorF momentumAtBoundary_; + bool startedInFineVolume_; + bool startedInFineVolumeIsSet_; int genParticlePID_, caloSurfaceParticlePID_; double genParticleP_, caloSurfaceParticleP_; @@ -128,6 +133,8 @@ class TrackInformation : public G4VUserTrackInformation { idLastVolume_(-1), caloIDChecked_(false), crossedBoundary_(false), + startedInFineVolume_(false), + startedInFineVolumeIsSet_(false), genParticlePID_(-1), caloSurfaceParticlePID_(0), genParticleP_(0), From 82812ddb685dd228cf0670c5d8c45f9c9446b27a Mon Sep 17 00:00:00 2001 From: Jan Kieseler Date: Fri, 18 Jun 2021 16:50:36 +0200 Subject: [PATCH 09/17] added some members to pftruthparticle --- .../PFAnalysis/interface/PFTruthParticle.h | 40 ++++++++++--------- .../PFAnalysis/src/PFTruthParticle.cc | 2 + 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/SimDataFormats/PFAnalysis/interface/PFTruthParticle.h b/SimDataFormats/PFAnalysis/interface/PFTruthParticle.h index 50ea4f28c3902..e1ae783c6e197 100644 --- a/SimDataFormats/PFAnalysis/interface/PFTruthParticle.h +++ b/SimDataFormats/PFAnalysis/interface/PFTruthParticle.h @@ -44,6 +44,7 @@ class PFTruthParticle { void setPdgId(int pdgId); void setCharge(int charge); void setP4(LorentzVector p4); + void setVertex(LorentzVector vertex); void addSimCluster(const SimClusterRef sc); void addTrackingParticle(const TrackingParticleRef tp); @@ -64,58 +65,61 @@ class PFTruthParticle { const std::vector& g4Tracks() const { return g4Tracks_; } - /// @brief Electric charge. Note this is taken from the first SimTrack only. + /// @brief Electric charge. float charge() const { return charge_; } - /// @brief Four-momentum Lorentz vector. Note this is taken from the first SimTrack only. + /// @brief Four-momentum Lorentz vector. const LorentzVector& p4() const { return p4_; } + /// @brief Vertex XYZT. + const LorentzVector& vertex() const { return vertex_; } + /// @brief spatial momentum vector Vector momentum() const { return p4().Vect(); } - /// @brief Magnitude of momentum vector. Note this is taken from the first SimTrack only. + /// @brief Magnitude of momentum vector. double p() const { return p4().P(); } - /// @brief Energy. Note this is taken from the first SimTrack only. + /// @brief Energy. double energy() const { return p4().E(); } - /// @brief Transverse energy. Note this is taken from the first SimTrack only. + /// @brief Transverse energy. double et() const { return p4().Et(); } - /// @brief Mass. Note this is taken from the first SimTrack only. + /// @brief Mass. double mass() const { return p4().M(); } - /// @brief Mass squared. Note this is taken from the first SimTrack only. + /// @brief Mass squared. double massSqr() const { return pow(mass(), 2); } - /// @brief Transverse mass. Note this is taken from the first SimTrack only. + /// @brief Transverse mass. double mt() const { return p4().Mt(); } - /// @brief Transverse mass squared. Note this is taken from the first SimTrack only. + /// @brief Transverse mass squared. double mtSqr() const { return p4().Mt2(); } - /// @brief x coordinate of momentum vector. Note this is taken from the first SimTrack only. + /// @brief x coordinate of momentum vector. double px() const { return p4().Px(); } - /// @brief y coordinate of momentum vector. Note this is taken from the first SimTrack only. + /// @brief y coordinate of momentum vector. double py() const { return p4().Py(); } - /// @brief z coordinate of momentum vector. Note this is taken from the first SimTrack only. + /// @brief z coordinate of momentum vector. double pz() const { return p4().Pz(); } - /// @brief Transverse momentum. Note this is taken from the first SimTrack only. + /// @brief Transverse momentum. double pt() const { return p4().Pt(); } - /// @brief Momentum azimuthal angle. Note this is taken from the first SimTrack only. + /// @brief Momentum azimuthal angle. double phi() const { return p4().Phi(); } - /// @brief Momentum polar angle. Note this is taken from the first SimTrack only. + /// @brief Momentum polar angle. double theta() const { return p4().Theta(); } - /// @brief Momentum pseudorapidity. Note this is taken from the first SimTrack only. + /// @brief Momentum pseudorapidity. double eta() const { return p4().Eta(); } - /// @brief Rapidity. Note this is taken from the first SimTrack only. + /// @brief Rapidity. double rapidity() const { return p4().Rapidity(); } /// @brief Same as rapidity(). @@ -125,7 +129,7 @@ class PFTruthParticle { /// references to G4 and reco::GenParticle tracks int charge_; int pdgId_; - LorentzVector p4_; + LorentzVector p4_, vertex_; std::vector g4Tracks_; reco::GenParticleRefVector genParticles_; SimClusterRefVector simClusters_; diff --git a/SimDataFormats/PFAnalysis/src/PFTruthParticle.cc b/SimDataFormats/PFAnalysis/src/PFTruthParticle.cc index 9ca899f639d03..5b3651eb39c82 100644 --- a/SimDataFormats/PFAnalysis/src/PFTruthParticle.cc +++ b/SimDataFormats/PFAnalysis/src/PFTruthParticle.cc @@ -45,4 +45,6 @@ void PFTruthParticle::setCharge(int charge) { charge_ = charge; } void PFTruthParticle::setP4(LorentzVector p4) { p4_ = p4; } +void PFTruthParticle::setVertex(LorentzVector vertex) { vertex_ = vertex; } + void PFTruthParticle::addG4Track(const SimTrack& t) { g4Tracks_.push_back(t); } From 28baaa46b744b5354b07cf21bff81c0e03f3a3fa Mon Sep 17 00:00:00 2001 From: Jan Kieseler Date: Mon, 21 Jun 2021 17:02:58 +0200 Subject: [PATCH 10/17] a step towards pf particle --- .../plugins/PFTruthParticleProducer.cc | 241 ++++++++++++++---- .../PFAnalysis/interface/PFTruthParticle.h | 19 +- .../PFAnalysis/src/PFTruthParticle.cc | 4 +- 3 files changed, 197 insertions(+), 67 deletions(-) diff --git a/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc b/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc index 317af99038ed8..75c8634c7069c 100644 --- a/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc +++ b/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc @@ -16,17 +16,57 @@ #include "FWCore/MessageLogger/interface/MessageLogger.h" #include "SimDataFormats/TrackingAnalysis/interface/TrackingParticle.h" +#include "SimDataFormats/CaloAnalysis/interface/CaloParticle.h" +#include "SimDataFormats/CaloAnalysis/interface/CaloParticleFwd.h" #include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" #include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" #include "SimDataFormats/PFAnalysis/interface/PFTruthParticle.h" #include "SimDataFormats/PFAnalysis/interface/PFTruthParticleFwd.h" + #include "FWCore/Utilities/interface/EDGetToken.h" #include // -// class decleration +// class declaration // +/* + * + * produces in two steps PFTruthParticles. + * This producer considers truth particles one-by-one and does not + * account for possible overlaps. These will need to be resolved in a second producer + * (PFTruthParticleMerger). + * The advantage is that the plugin here can run on every single event, independent of + * pileup mixing and event density, while the second producer can be run after mixing in pileup + * + * Step A) + * Produces an ideal PFTruthParticle, without considering detector limitations. + * This is done by connecting every trackingParticle and SimCluster that originated + * from a particle passed to Geant back to it. + * No configuration options needed. + * The tracking particles should be selected by one of the standard tracking selectors, e.g.: + * https://github.com/cms-sw/cmssw/blob/master/Validation/RecoTrack/python/TrackingParticleSelectionForEfficiency_cfi.py + * + * Step B) + * The ideal PFTruthParticle gets split according to detector limitations, e.g. if + * a neutral pion splits to 2 photons and leaves to distinct photon showers, + * this step would produce 2 photons. + * + * For neutral and charged particles, stray clusters with deltaR larger than + * and tracks that contribute with less than a relative to + * the total particle energy are removed. + * + * This splitting of neutral particles depends on the granularity of the SimClusters + * in the respective subdetector. + * + * + * In case of charged particles, there are multiple options, e.g. when to split off bremsstrahlung + * for an electron. + * + * + * + * + */ typedef edm::AssociationMap> TrackingParticleToSimCluster; @@ -38,20 +78,27 @@ class PFTruthParticleProducer : public edm::global::EDProducer<> { private: void produce(edm::StreamID, edm::Event &, const edm::EventSetup &) const override; - std::set findTrackingParticleMatch( - std::unordered_map& trackIdToTPRef, SimClusterRef scRef) const; + + const SimTrack* getRoot(const SimTrack * st, + const std::vector & simtracks, + const std::vector & simvertices, + const std::map& trackIdToTrackIdxAsso ) const; edm::EDGetTokenT tpCollectionToken_; - edm::EDGetTokenT scCollectionToken_; + edm::EDGetTokenT cpCollectionToken_; + edm::EDGetTokenT > svCollectionToken_; + edm::EDGetTokenT > stCollectionToken_; + + }; PFTruthParticleProducer::PFTruthParticleProducer(const edm::ParameterSet &pset) : tpCollectionToken_(consumes(pset.getParameter("trackingParticles"))), - scCollectionToken_(consumes(pset.getParameter("simClusters"))) + cpCollectionToken_(consumes(pset.getParameter("caloParticles"))), + svCollectionToken_(consumes >(pset.getParameter("simVertices"))), + stCollectionToken_(consumes >(pset.getParameter("simTracks"))) { produces(); - produces>("trackingPartToPFTruth"); - produces>("simClusToPFTruth"); } PFTruthParticleProducer::~PFTruthParticleProducer() {} @@ -60,72 +107,154 @@ PFTruthParticleProducer::~PFTruthParticleProducer() {} // member functions // -std::set PFTruthParticleProducer::findTrackingParticleMatch( - std::unordered_map& trackIdToTPRef, SimClusterRef scRef) const { - std::set trackingParticles; - for (auto& track : scRef->g4Tracks()) { - unsigned int trackId = track.trackId(); - if (trackIdToTPRef.find(trackId) != trackIdToTPRef.end()) - trackingParticles.insert(trackIdToTPRef[trackId]); + +const SimTrack* PFTruthParticleProducer::getRoot( + const SimTrack * st, + const std::vector & simtracks, + const std::vector & simvertices, + const std::map& trackIdToTrackIdxAsso ) const{ + + SimTrack* out=st; + int vidx = out->vertIndex();//starting point + while(true){ + if(vidx<0) + break; //no vertex + const SimVertex& vertex = simvertices.at(vidx); + int stid = vertex.parentIndex();//this is Geant track ID, not vector index + int stidx = trackIdToTrackIdxAsso[stid]; //get vector index + if(stidx<0) + break; + const SimTrack & simtrack = simtracks.at(stidx); + vidx = simtrack.vertIndex(); + out=&simtrack; } - return trackingParticles; + return out; } + // ------------ method called to produce the data ------------ void PFTruthParticleProducer::produce(edm::StreamID, edm::Event &iEvent, const edm::EventSetup &iSetup) const { edm::Handle tpCollection; iEvent.getByToken(tpCollectionToken_, tpCollection); - edm::Handle scCollection; - iEvent.getByToken(scCollectionToken_, scCollection); - - auto out = std::make_unique(); - // Not used right now, but useful for the trackID lookup later - std::unordered_map trackIdToTPRef; - - std::vector trackingIndices; - for (size_t i = 0; i < tpCollection->size(); i++) { - TrackingParticleRef trackingParticle(tpCollection, i); - PFTruthParticle particle; - particle.addTrackingParticle(trackingParticle); - particle.setCharge(trackingParticle->charge()); - particle.setPdgId(trackingParticle->pdgId()); - particle.setP4(trackingParticle->p4()); - out->push_back(particle); - trackingIndices.push_back(i); - for (auto& track : trackingParticle->g4Tracks()) { - unsigned int trackId = track.trackId(); - trackIdToTPRef[trackId] = trackingParticle; + edm::Handle cpCollection; + iEvent.getByToken(cpCollectionToken_, cpCollection); + + edm::Handle > svCollection; + iEvent.getByToken(svCollectionToken_, svCollection); + + edm::Handle > stCollection; + iEvent.getByToken(stCollectionToken_, stCollection); + + std::map trackIdToTrackIdxAsso; + for(size_t i=0;isize();i++){ + trackIdToTrackIdxAsso[stCollection->at(i).trackId()] = i; + } + + //unrealistic / ideal PF Truth: create one PFParticle form Geant handover aka CaloParticle + + std::vector matchedtptocp; + PFTruthParticleCollection idealPFTruth; + + for(const auto& cp: *cpCollection){ + + TrackingParticleRefVector tprefs; + const SimClusterRefVector& screfs = cp.simClusters(); + + bool hascharged=false; + //match the tracking particle(s) + for(size_t i=0; i< tpCollection->size(); i++){ + if(std::find(matchedtptocp.begin(),matchedtptocp.end(), i) != matchedtptocp.end()) + continue; //already matched + + TrackingParticleRef tpref(tpCollection, i); + + //go through whole history + auto stp = getRoot(& tpref->g4Tracks().at(0), + *stCollection,*svCollection, trackIdToTrackIdxAsso); + + + //match + if(stp->trackId() == cp.g4Tracks().at(0).trackId() + && stp->eventId() == cp.g4Tracks().at(0).eventId()){ + matchedtptocp.push_back(i); + tprefs.push_back(tpref); + if(tpref->charge()) + hascharged=true; + } } + PFTruthParticle pftp(tprefs,screfs); + pftp.setP4(cp.p4()); + pftp.setPdgId(cp.pdgId()); + pftp.setCharge(cp.charge()); + int vidx = cp.g4Tracks().at(0).vertIndex(); + auto vertpos = svCollection->at(vidx).position(); + + pftp.setVertex(PFTruthParticle::LorentzVectorF( + vertpos.x(),vertpos.y(),vertpos.z(),vertpos.t())); + + idealPFTruth.push_back(pftp); } - std::vector scIndices; - for (size_t i = 0; i < scCollection->size(); i++) { - SimClusterRef simclus(scCollection, i); - // Doesn't really do much anyway - //findTrackingParticleMatch(trackIdToTPRef, simclus)) - // For now just randomly assign the SCs as a dummy - int tpIdx = i % out->size(); - auto& pf = out->at(tpIdx); - pf.addSimCluster(simclus); - scIndices.push_back(tpIdx); + + // --- now we have the ideal PF truth, far from realistic. + // --- this is where the actual "meat" of the implementation starts + + double softkill_relthreshold = 0.001;//just to avoid ambiguities. + double hardsplit_deltaR = 0.3; + + + std::unique_ptr PFtruth; + + //apply splitting particle by particle + //this is where the physics happens + for(const auto & pftp: idealPFTruth){ + + + //consider the ones without tracking particles // this is not the same as the ones without charge, + // because e.g. a very early converting photon would have charge 0, but two tracking particles associated + if(! pftp.trackingParticles().size()) { + for(const auto& sc: pftp.simClusters()){ + //create PF particle per SimCluster + //vertex position will remain the initial CP one (timing) + auto npftp = pftp; + npftp.trackingParticles().clear(); + npftp.simClusters().clear(); + npftp.addSimCluster(sc); + //this is now defined to be a neutral PF Particle. Even if the SC happens to be charged + npftp.setCharge(0); + npftp.setP4(sc->impactMomentum());//that's all we measure + npftp.setPdgId(sc->pdgId()); //to be discussed + PFtruth->push_back(npftp); + } + continue; + } + //remaining: the ones that have tracking particles associated + + + //some more cases, like far away brem... + + + //trim + auto trimmed_pfp = pftp; + SimClusterRefVector trimmersc; + for(auto & sc: trimmed_pfp.simClusters()){ + if(sc->impactMomentum().E() > trimmed_pfp.p4().E()){ + trimmersc.push_back(sc); + } + } + trimmed_pfp.setSimClusters(trimmersc); + //no split + PFtruth->push_back(trimmed_pfp); } - auto pfTruthHand = iEvent.put(std::move(out)); - auto tpAssoc = std::make_unique>(pfTruthHand); - auto scAssoc = std::make_unique>(pfTruthHand); - edm::Association::Filler tpFiller(*tpAssoc); - tpFiller.insert(tpCollection, trackingIndices.begin(), trackingIndices.end()); - tpFiller.fill(); - edm::Association::Filler scFiller(*scAssoc); - scFiller.insert(scCollection, scIndices.begin(), scIndices.end()); - scFiller.fill(); - iEvent.put(std::move(tpAssoc), "trackingPartToPFTruth"); - iEvent.put(std::move(scAssoc), "simClusToPFTruth"); + iEvent.put(std::move(PFtruth), "PFTruthParticles"); + + } // define this as a plug-in diff --git a/SimDataFormats/PFAnalysis/interface/PFTruthParticle.h b/SimDataFormats/PFAnalysis/interface/PFTruthParticle.h index e1ae783c6e197..01198ca496664 100644 --- a/SimDataFormats/PFAnalysis/interface/PFTruthParticle.h +++ b/SimDataFormats/PFAnalysis/interface/PFTruthParticle.h @@ -22,9 +22,8 @@ class PFTruthParticle { friend std::ostream& operator<<(std::ostream& s, PFTruthParticle const& tp); public: - typedef math::XYZTLorentzVectorD LorentzVector; ///< Lorentz vector - typedef math::XYZPointD Point; ///< point in the space - typedef math::XYZVectorD Vector; ///< point in the space + typedef math::XYZTLorentzVectorF LorentzVectorF; ///< Lorentz vector + typedef math::XYZVectorF VectorF; ///< point in the space /** @brief Default constructor. Note that the object will be useless until it is provided * with a SimTrack and parent TrackingVertex. @@ -43,13 +42,15 @@ class PFTruthParticle { void setSimClusters(const SimClusterRefVector& refs); void setPdgId(int pdgId); void setCharge(int charge); - void setP4(LorentzVector p4); - void setVertex(LorentzVector vertex); + void setP4(LorentzVectorF p4); + void setVertex(LorentzVectorF vertex); void addSimCluster(const SimClusterRef sc); void addTrackingParticle(const TrackingParticleRef tp); SimClusterRefVector& simClusters() { return simClusters_; } TrackingParticleRefVector& trackingParticles() { return trackingParticles_; } + const SimClusterRefVector& simClusters() const { return simClusters_; } + const TrackingParticleRefVector& trackingParticles() const { return trackingParticles_; } size_t nSimCluster() const { return simClusters_.size(); } size_t nTrackingParticle() const { return trackingParticles_.size(); } @@ -69,13 +70,13 @@ class PFTruthParticle { float charge() const { return charge_; } /// @brief Four-momentum Lorentz vector. - const LorentzVector& p4() const { return p4_; } + const LorentzVectorF& p4() const { return p4_; } /// @brief Vertex XYZT. - const LorentzVector& vertex() const { return vertex_; } + const LorentzVectorF& vertex() const { return vertex_; } /// @brief spatial momentum vector - Vector momentum() const { return p4().Vect(); } + VectorF momentum() const { return p4().Vect(); } /// @brief Magnitude of momentum vector. double p() const { return p4().P(); } @@ -129,7 +130,7 @@ class PFTruthParticle { /// references to G4 and reco::GenParticle tracks int charge_; int pdgId_; - LorentzVector p4_, vertex_; + LorentzVectorF p4_, vertex_; std::vector g4Tracks_; reco::GenParticleRefVector genParticles_; SimClusterRefVector simClusters_; diff --git a/SimDataFormats/PFAnalysis/src/PFTruthParticle.cc b/SimDataFormats/PFAnalysis/src/PFTruthParticle.cc index 5b3651eb39c82..b533b09c250e4 100644 --- a/SimDataFormats/PFAnalysis/src/PFTruthParticle.cc +++ b/SimDataFormats/PFAnalysis/src/PFTruthParticle.cc @@ -43,8 +43,8 @@ void PFTruthParticle::setPdgId(int pdgId) { pdgId_ = pdgId; } void PFTruthParticle::setCharge(int charge) { charge_ = charge; } -void PFTruthParticle::setP4(LorentzVector p4) { p4_ = p4; } +void PFTruthParticle::setP4(LorentzVectorF p4) { p4_ = p4; } -void PFTruthParticle::setVertex(LorentzVector vertex) { vertex_ = vertex; } +void PFTruthParticle::setVertex(LorentzVectorF vertex) { vertex_ = vertex; } void PFTruthParticle::addG4Track(const SimTrack& t) { g4Tracks_.push_back(t); } From ef169538d8a9065f46910d202f9ee707d4fddfca Mon Sep 17 00:00:00 2001 From: Jan Kieseler Date: Mon, 21 Jun 2021 17:39:16 +0200 Subject: [PATCH 11/17] fixes --- DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py | 4 +++- .../plugins/PFTruthParticleProducer.cc | 12 ++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py b/DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py index 80107c1b9ed68..e0bf7a206dc9b 100644 --- a/DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py +++ b/DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py @@ -4,8 +4,10 @@ from DPGAnalysis.TrackNanoAOD.trackingParticles_cff import trackingParticleTable pfTruthParticles = cms.EDProducer("PFTruthParticleProducer", - simClusters = cms.InputTag("mix:MergedCaloTruth"), trackingParticles= cms.InputTag("mix:MergedTrackTruth"), + caloParticles= cms.InputTag("mix:MergedCaloTruth"), + simVertices= cms.InputTag("SimVertices"), + simTracks= cms.InputTag("SimTracks"), ) pfTruthTable = cms.EDProducer("SimplePFTruthParticleFlatTableProducer", diff --git a/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc b/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc index 75c8634c7069c..0b5177a0604a4 100644 --- a/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc +++ b/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc @@ -94,7 +94,7 @@ class PFTruthParticleProducer : public edm::global::EDProducer<> { PFTruthParticleProducer::PFTruthParticleProducer(const edm::ParameterSet &pset) : tpCollectionToken_(consumes(pset.getParameter("trackingParticles"))), - cpCollectionToken_(consumes(pset.getParameter("caloParticles"))), + cpCollectionToken_(consumes(pset.getParameter("caloParticles"))), svCollectionToken_(consumes >(pset.getParameter("simVertices"))), stCollectionToken_(consumes >(pset.getParameter("simTracks"))) { @@ -114,14 +114,14 @@ const SimTrack* PFTruthParticleProducer::getRoot( const std::vector & simvertices, const std::map& trackIdToTrackIdxAsso ) const{ - SimTrack* out=st; + const SimTrack* out=st; int vidx = out->vertIndex();//starting point while(true){ if(vidx<0) break; //no vertex const SimVertex& vertex = simvertices.at(vidx); int stid = vertex.parentIndex();//this is Geant track ID, not vector index - int stidx = trackIdToTrackIdxAsso[stid]; //get vector index + int stidx = trackIdToTrackIdxAsso.at(stid); //get vector index if(stidx<0) break; const SimTrack & simtrack = simtracks.at(stidx); @@ -162,7 +162,6 @@ void PFTruthParticleProducer::produce(edm::StreamID, edm::Event &iEvent, const e TrackingParticleRefVector tprefs; const SimClusterRefVector& screfs = cp.simClusters(); - bool hascharged=false; //match the tracking particle(s) for(size_t i=0; i< tpCollection->size(); i++){ if(std::find(matchedtptocp.begin(),matchedtptocp.end(), i) != matchedtptocp.end()) @@ -174,14 +173,11 @@ void PFTruthParticleProducer::produce(edm::StreamID, edm::Event &iEvent, const e auto stp = getRoot(& tpref->g4Tracks().at(0), *stCollection,*svCollection, trackIdToTrackIdxAsso); - //match if(stp->trackId() == cp.g4Tracks().at(0).trackId() && stp->eventId() == cp.g4Tracks().at(0).eventId()){ matchedtptocp.push_back(i); tprefs.push_back(tpref); - if(tpref->charge()) - hascharged=true; } } PFTruthParticle pftp(tprefs,screfs); @@ -240,7 +236,7 @@ void PFTruthParticleProducer::produce(edm::StreamID, edm::Event &iEvent, const e auto trimmed_pfp = pftp; SimClusterRefVector trimmersc; for(auto & sc: trimmed_pfp.simClusters()){ - if(sc->impactMomentum().E() > trimmed_pfp.p4().E()){ + if(sc->impactMomentum().E() > trimmed_pfp.p4().E() * softkill_relthreshold){ trimmersc.push_back(sc); } } From a69d30329784eed3c51a74ee291974c7052b7ed2 Mon Sep 17 00:00:00 2001 From: Kenneth Long Date: Fri, 27 Aug 2021 11:20:24 +0200 Subject: [PATCH 12/17] Add particle guns --- IOMC/ParticleGuns/BuildFile.xml | 1 + .../interface/CloseByFlatDeltaRGunProducer.h | 76 +++++++ .../interface/FlatEtaRangeGunProducer.h | 67 ++++++ .../FlatEtaRangeNoTrackerGunProducer.h | 82 +++++++ .../src/CloseByFlatDeltaRGunProducer.cc | 197 ++++++++++++++++ .../src/FlatEtaRangeGunProducer.cc | 150 +++++++++++++ .../src/FlatEtaRangeNoTrackerGunProducer.cc | 212 ++++++++++++++++++ .../src/FlatRandomPtAndDxyGunProducer.cc | 6 +- IOMC/ParticleGuns/src/SealModule.cc | 13 +- 9 files changed, 799 insertions(+), 5 deletions(-) create mode 100644 IOMC/ParticleGuns/interface/CloseByFlatDeltaRGunProducer.h create mode 100644 IOMC/ParticleGuns/interface/FlatEtaRangeGunProducer.h create mode 100644 IOMC/ParticleGuns/interface/FlatEtaRangeNoTrackerGunProducer.h create mode 100644 IOMC/ParticleGuns/src/CloseByFlatDeltaRGunProducer.cc create mode 100644 IOMC/ParticleGuns/src/FlatEtaRangeGunProducer.cc create mode 100644 IOMC/ParticleGuns/src/FlatEtaRangeNoTrackerGunProducer.cc diff --git a/IOMC/ParticleGuns/BuildFile.xml b/IOMC/ParticleGuns/BuildFile.xml index f061134749833..71b685b210fa9 100644 --- a/IOMC/ParticleGuns/BuildFile.xml +++ b/IOMC/ParticleGuns/BuildFile.xml @@ -5,4 +5,5 @@ + diff --git a/IOMC/ParticleGuns/interface/CloseByFlatDeltaRGunProducer.h b/IOMC/ParticleGuns/interface/CloseByFlatDeltaRGunProducer.h new file mode 100644 index 0000000000000..812a66219b295 --- /dev/null +++ b/IOMC/ParticleGuns/interface/CloseByFlatDeltaRGunProducer.h @@ -0,0 +1,76 @@ +/* + * Particle gun that can be positioned in space given ranges in rho, z and phi. + */ + +#ifndef IOMC_PARTICLEGUN_CLOSEBYFLATDELTARGUNPRODUCER_H +#define IOMC_PARTICLEGUN_CLOSEBYFLATDELTARGUNPRODUCER_H + +#include "FWCore/Framework/interface/one/EDProducer.h" +#include "FWCore/Framework/interface/ESHandle.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Framework/interface/Run.h" + +#include "HepMC/GenEvent.h" +#include "HepPDT/ParticleDataTable.hh" + +namespace edm { + + class CloseByFlatDeltaRGunProducer : public one::EDProducer { + public: + static void fillDescriptions(edm::ConfigurationDescriptions&); + + explicit CloseByFlatDeltaRGunProducer(const ParameterSet&); + ~CloseByFlatDeltaRGunProducer() override; + void beginRun(const edm::Run&, const edm::EventSetup&) override; + void endRun(const edm::Run&, const edm::EventSetup&) override; + void endRunProduce(edm::Run&, const edm::EventSetup&) override; + + private: + void produce(Event&, const EventSetup&) override; + + protected: + // ids of particles to shoot + std::vector particleIDs_; + + // the number of particles to shoot + int nParticles_; + + // flag that denotes that exactly the particles defined by fPartIds should be shot, with that order and quantity + bool exactShoot_; + + // flag that denotes whether a random number of particles in the range [1, fNParticles] is shot + bool randomShoot_; + + // energy range + double eMin_; + double eMax_; + + // eta range + double etaMin_; + double etaMax_; + + // phi range + double phiMin_; + double phiMax_; + + // range of longitudinal gun position + double zMin_; + double zMax_; + + // deltaR parameters + double deltaRMin_; + double deltaRMax_; + + // debug flag + bool debug_; + + // pointer to the current event + HepMC::GenEvent* genEvent_; + + // pdg table + ESHandle pdgTable_; + }; + +} // namespace edm + +#endif // IOMC_PARTICLEGUN_CLOSEBYFLATDELTARGUNPRODUCER_H diff --git a/IOMC/ParticleGuns/interface/FlatEtaRangeGunProducer.h b/IOMC/ParticleGuns/interface/FlatEtaRangeGunProducer.h new file mode 100644 index 0000000000000..2eeeb8cb26d75 --- /dev/null +++ b/IOMC/ParticleGuns/interface/FlatEtaRangeGunProducer.h @@ -0,0 +1,67 @@ +/* + * Particle gun that can be positioned in space given ranges in rho, z and phi. + */ + +#ifndef IOMC_PARTICLEGUN_FlatEtaRangeGunProducer_H +#define IOMC_PARTICLEGUN_FlatEtaRangeGunProducer_H + +#include "FWCore/Framework/interface/one/EDProducer.h" +#include "FWCore/Framework/interface/ESHandle.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Framework/interface/Run.h" + +#include "HepMC/GenEvent.h" +#include "HepPDT/ParticleDataTable.hh" + +namespace edm { + + class FlatEtaRangeGunProducer : public one::EDProducer { + public: + static void fillDescriptions(edm::ConfigurationDescriptions&); + + explicit FlatEtaRangeGunProducer(const ParameterSet&); + ~FlatEtaRangeGunProducer() override; + void beginRun(const edm::Run&, const edm::EventSetup&) override; + void endRun(const edm::Run&, const edm::EventSetup&) override; + void endRunProduce(edm::Run&, const edm::EventSetup&) override; + + private: + void produce(Event&, const EventSetup&) override; + + protected: + // ids of particles to shoot + std::vector particleIDs_; + + // the number of particles to shoot + int nParticles_; + + // flag that denotes that exactly the particles defined by fPartIds should be shot, with that order and quantity + bool exactShoot_; + + // flag that denotes whether a random number of particles in the range [1, fNParticles] is shot + bool randomShoot_; + + // energy range + double eMin_; + double eMax_; + + // eta range + double etaMin_; + double etaMax_; + + // phi range + double phiMin_; + double phiMax_; + + // debug flag + bool debug_; + + // pointer to the current event + + // pdg table + ESHandle pdgTable_; + }; + +} // namespace edm + +#endif // IOMC_PARTICLEGUN_FlatEtaRangeGunProducer_H diff --git a/IOMC/ParticleGuns/interface/FlatEtaRangeNoTrackerGunProducer.h b/IOMC/ParticleGuns/interface/FlatEtaRangeNoTrackerGunProducer.h new file mode 100644 index 0000000000000..aa3f44cf765b1 --- /dev/null +++ b/IOMC/ParticleGuns/interface/FlatEtaRangeNoTrackerGunProducer.h @@ -0,0 +1,82 @@ +/* + * Particle gun that can be positioned in space given ranges in rho, z and phi. + */ + +#ifndef IOMC_PARTICLEGUN_FlatEtaRangeNoTrackerGunProducer_H +#define IOMC_PARTICLEGUN_FlatEtaRangeNoTrackerGunProducer_H + +#include "FWCore/Framework/interface/one/EDProducer.h" +#include "FWCore/Framework/interface/ESHandle.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Framework/interface/Run.h" + +#include "HepMC/GenEvent.h" +#include "HepPDT/ParticleDataTable.hh" + +#include "RecoHGCal/GraphReco/interface/HGCalParticlePropagator.h" + + +namespace edm { + + class FlatEtaRangeNoTrackerGunProducer : public one::EDProducer { + public: + static void fillDescriptions(edm::ConfigurationDescriptions&); + + explicit FlatEtaRangeNoTrackerGunProducer(const ParameterSet&); + ~FlatEtaRangeNoTrackerGunProducer() override; + void beginRun(const edm::Run&, const edm::EventSetup&) override; + void endRun(const edm::Run&, const edm::EventSetup&) override; + void endRunProduce(edm::Run&, const edm::EventSetup&) override; + + private: + void produce(Event&, const EventSetup&) override; + + protected: + // ids of particles to shoot + std::vector particleIDs_; + + // the number of particles to shoot + int nParticles_; + + // flag that denotes that exactly the particles defined by fPartIds should be shot, with that order and quantity + bool exactShoot_; + + // flag that denotes whether a random number of particles in the range [1, fNParticles] is shot + bool randomShoot_; + + // energy range + double eMin_; + double eMax_; + + // eta range + double etaMin_; + double etaMax_; + + // phi range + double phiMin_; + double phiMax_; + + // debug flag + bool debug_; + + // pointer to the current event + HepMC::GenEvent* genEvent_; + + // pdg table + ESHandle pdgTable_; + + //propagator + HGCalParticlePropagator prop_; + + //smear vertex + double timeSmear_; + + //smear momentum direction a bit, to have a less stringent BS constraint + double momSmear_; + double minDistDR_; + + }; + +} // namespace edm + +#endif // IOMC_PARTICLEGUN_FlatEtaRangeNoTrackerGunProducer_H diff --git a/IOMC/ParticleGuns/src/CloseByFlatDeltaRGunProducer.cc b/IOMC/ParticleGuns/src/CloseByFlatDeltaRGunProducer.cc new file mode 100644 index 0000000000000..72dbb96339bc8 --- /dev/null +++ b/IOMC/ParticleGuns/src/CloseByFlatDeltaRGunProducer.cc @@ -0,0 +1,197 @@ +#include + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "FWCore/ServiceRegistry/interface/Service.h" +#include "FWCore/Utilities/interface/RandomNumberGenerator.h" + +#include "SimDataFormats/GeneratorProducts/interface/GenEventInfoProduct.h" +#include "SimDataFormats/GeneratorProducts/interface/GenRunInfoProduct.h" +#include "SimDataFormats/GeneratorProducts/interface/HepMCProduct.h" + +#include "SimGeneral/HepPDTRecord/interface/ParticleDataTable.h" + +#include "DataFormats/Math/interface/Vector3D.h" + +#include "IOMC/ParticleGuns/interface/CloseByFlatDeltaRGunProducer.h" + +#include "CLHEP/Random/RandFlat.h" +#include "CLHEP/Units/GlobalPhysicalConstants.h" +#include "CLHEP/Units/GlobalSystemOfUnits.h" + +void edm::CloseByFlatDeltaRGunProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + + desc.add>("particleIDs"); + desc.add("nParticles", 1); + desc.add("exactShoot", true); + desc.add("randomShoot", false); + desc.add("eMin", 1.); + desc.add("eMax", 100.); + desc.add("etaMin", 0.); + desc.add("etaMax", 0.); + desc.add("phiMin", 0.); + desc.add("phiMax", 2 * pi); + desc.add("zMin", 0.); + desc.add("zMax", 0.); + desc.add("deltaRMin", 0.); + desc.add("deltaRMax", 0.5); + desc.addUntracked("debug", false); + + descriptions.add("closeByFlatDeltaRGunProducer", desc); +} + +edm::CloseByFlatDeltaRGunProducer::CloseByFlatDeltaRGunProducer(const edm::ParameterSet& params) + : particleIDs_(params.getParameter>("particleIDs")), + nParticles_(params.getParameter("nParticles")), + exactShoot_(params.getParameter("exactShoot")), + randomShoot_(params.getParameter("randomShoot")), + eMin_(params.getParameter("eMin")), + eMax_(params.getParameter("eMax")), + etaMin_(params.getParameter("etaMin")), + etaMax_(params.getParameter("etaMax")), + phiMin_(params.getParameter("phiMin")), + phiMax_(params.getParameter("phiMax")), + zMin_(params.getParameter("zMin")), + zMax_(params.getParameter("zMax")), + deltaRMin_(params.getParameter("deltaRMin")), + deltaRMax_(params.getParameter("deltaRMax")), + debug_(params.getUntrackedParameter("debug")), + genEvent_(nullptr) { + produces("unsmeared"); + produces(); + produces(); +} + +edm::CloseByFlatDeltaRGunProducer::~CloseByFlatDeltaRGunProducer() {} + +void edm::CloseByFlatDeltaRGunProducer::beginRun(const edm::Run& run, const edm::EventSetup& setup) { + setup.getData(pdgTable_); +} + +void edm::CloseByFlatDeltaRGunProducer::endRun(const edm::Run& run, const edm::EventSetup& setup) {} + +void edm::CloseByFlatDeltaRGunProducer::produce(edm::Event& event, const edm::EventSetup& setup) { + edm::Service rng; + CLHEP::HepRandomEngine* engine = &(rng->getEngine(event.streamID())); + + if (debug_) { + LogDebug("CloseByFlatDeltaRGunProducer") << " : Begin New Event Generation" << std::endl; + } + + // create a new event to fill + genEvent_ = new HepMC::GenEvent(); + + // determine gun parameters for first particle to shoot (postfixed with "0") + double phi0 = CLHEP::RandFlat::shoot(engine, phiMin_, phiMax_); + double thetaMin = 2 * atan(exp(-etaMax_)); + double thetaMax = 2 * atan(exp(-etaMin_)); + double theta0 = CLHEP::RandFlat::shoot(engine, thetaMin, thetaMax); + double eta0 = -log(tan(0.5 * theta0)); + + // longitudinal gun position along the generated trajectory + double z0 = CLHEP::RandFlat::shoot(engine, zMin_, zMax_); + double rho0 = tan(theta0) * z0; + + // define variables that are changed per shot particle + double phi = phi0; + double eta = eta0; + double rho = rho0; + + // determine the number of particles to shoot + int n = 0; + if (exactShoot_) { + n = (int)particleIDs_.size(); + } else if (randomShoot_) { + n = CLHEP::RandFlat::shoot(engine, 1, nParticles_ + 1); + } else { + n = nParticles_; + } + + // shoot particles + for (int i = 0; i < n; i++) { + // find a new position relative to the first particle, obviously for all but the first one + if (i > 0) { + // create a random deltaR + double deltaR = CLHEP::RandFlat::shoot(engine, deltaRMin_, deltaRMax_); + + // split delta R randomly in phi and eta directions + double alpha = CLHEP::RandFlat::shoot(engine, 0., 2. * pi); + double deltaPhi = sin(alpha) * deltaR; + double deltaEta = cos(alpha) * deltaR; + + // update phi + phi = phi0 + deltaPhi; + + // update rho + // the approach is to transorm a difference in eta to a difference in rho using: + // 1. tan(theta) = rho / z <=> rho = z * tan(theta) + // 2. eta = -log(tan(theta / 2)) <=> theta = 2 * atan(exp(-eta)) + // 2. in 1. => rho = z * tan(2 * atan(exp(-eta))) + // using tan(atan(2 * x)) = -2 * x (x^2 - 1) leads to + // => rho = -2 * z * x / (x^2 - 1), with x = exp(-eta) + // for eta = eta0 + deltaEta, this allows for defining x = exp(-(eta0 + deltaEta)) + eta = eta0 + deltaEta; + double x = exp(-eta); + rho = -2 * z0 * x / (x * x - 1); + } + + // compute the gun / vertex position + // the time offset is given in c*t and is used later on in the digitization + double x = rho * cos(phi); + double y = rho * sin(phi); + double timeOffset = sqrt(x * x + y * y + z0 * z0) * cm / c_light; + HepMC::GenVertex* vtx = new HepMC::GenVertex(HepMC::FourVector(x * cm, y * cm, z0 * cm, timeOffset * c_light)); + + // obtain kinematics + int id = particleIDs_[exactShoot_ ? i : CLHEP::RandFlat::shoot(engine, 0, particleIDs_.size())]; + const HepPDT::ParticleData* pData = pdgTable_->particle(HepPDT::ParticleID(abs(id))); + double e = CLHEP::RandFlat::shoot(engine, eMin_, eMax_); + double m = pData->mass().value(); + double p = sqrt(e * e - m * m); + + // determine the momentum vector + math::XYZVector pVec = p * math::XYZVector(cos(phi), sin(phi), sinh(eta)).unit(); + + // create the GenParticle + HepMC::FourVector fVec(pVec.x(), pVec.y(), pVec.z(), e); + HepMC::GenParticle* particle = new HepMC::GenParticle(fVec, id, 1); + particle->suggest_barcode(i + 1); + + // add the particle to the vertex and the vertex to the event + vtx->add_particle_out(particle); + genEvent_->add_vertex(vtx); + + if (debug_) { + vtx->print(); + particle->print(); + } + } + + // fill event attributes + genEvent_->set_event_number(event.id().event()); + genEvent_->set_signal_process_id(20); + + if (debug_) { + genEvent_->print(); + } + + // store outputs + std::unique_ptr BProduct(new HepMCProduct()); + BProduct->addHepMCData(genEvent_); + event.put(std::move(BProduct), "unsmeared"); + std::unique_ptr genEventInfo(new GenEventInfoProduct(genEvent_)); + event.put(std::move(genEventInfo)); + + if (debug_) { + LogDebug("CloseByFlatDeltaRGunProducer") << " : Event Generation Done " << std::endl; + } +} + +void edm::CloseByFlatDeltaRGunProducer::endRunProduce(edm::Run& run, const edm::EventSetup& setup) { + std::unique_ptr genRunInfo(new GenRunInfoProduct()); + run.put(std::move(genRunInfo)); +} diff --git a/IOMC/ParticleGuns/src/FlatEtaRangeGunProducer.cc b/IOMC/ParticleGuns/src/FlatEtaRangeGunProducer.cc new file mode 100644 index 0000000000000..92c69b0c26b9a --- /dev/null +++ b/IOMC/ParticleGuns/src/FlatEtaRangeGunProducer.cc @@ -0,0 +1,150 @@ +#include + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "FWCore/ServiceRegistry/interface/Service.h" +#include "FWCore/Utilities/interface/RandomNumberGenerator.h" + +#include "SimDataFormats/GeneratorProducts/interface/GenEventInfoProduct.h" +#include "SimDataFormats/GeneratorProducts/interface/GenRunInfoProduct.h" +#include "SimDataFormats/GeneratorProducts/interface/HepMCProduct.h" + +#include "SimGeneral/HepPDTRecord/interface/ParticleDataTable.h" + +#include "DataFormats/Math/interface/Vector3D.h" + +#include "IOMC/ParticleGuns/interface/FlatEtaRangeGunProducer.h" + +#include "CLHEP/Random/RandFlat.h" +#include "CLHEP/Units/GlobalPhysicalConstants.h" +#include "CLHEP/Units/GlobalSystemOfUnits.h" + +void edm::FlatEtaRangeGunProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + + desc.add>("particleIDs"); + desc.add("nParticles", 1); + desc.add("exactShoot", true); + desc.add("randomShoot", false); + desc.add("eMin", 1.); + desc.add("eMax", 100.); + desc.add("etaMin", 1.5); + desc.add("etaMax", 3.0); + desc.add("phiMin", 0.); + desc.add("phiMax", 2 * pi); + desc.addUntracked("debug", false); + + descriptions.add("FlatEtaRangeGunProducer", desc); +} + +edm::FlatEtaRangeGunProducer::FlatEtaRangeGunProducer(const edm::ParameterSet& params) + : particleIDs_(params.getParameter>("particleIDs")), + nParticles_(params.getParameter("nParticles")), + exactShoot_(params.getParameter("exactShoot")), + randomShoot_(params.getParameter("randomShoot")), + eMin_(params.getParameter("eMin")), + eMax_(params.getParameter("eMax")), + etaMin_(params.getParameter("etaMin")), + etaMax_(params.getParameter("etaMax")), + phiMin_(params.getParameter("phiMin")), + phiMax_(params.getParameter("phiMax")), + debug_(params.getUntrackedParameter("debug")) { + produces("unsmeared"); + produces(); + produces(); +} + +edm::FlatEtaRangeGunProducer::~FlatEtaRangeGunProducer() {} + +void edm::FlatEtaRangeGunProducer::beginRun(const edm::Run& run, const edm::EventSetup& setup) { + setup.getData(pdgTable_); +} + +void edm::FlatEtaRangeGunProducer::endRun(const edm::Run& run, const edm::EventSetup& setup) {} + +void edm::FlatEtaRangeGunProducer::produce(edm::Event& event, const edm::EventSetup& setup) { + edm::Service rng; + CLHEP::HepRandomEngine* engine = &(rng->getEngine(event.streamID())); + + if (debug_) { + LogDebug("FlatEtaRangeGunProducer") << " : Begin New Event Generation" << std::endl; + } + + // create a new event to fill + auto* genEvent = new HepMC::GenEvent(); + + // determine the number of particles to shoot + int n = 0; + if (exactShoot_) { + n = (int)particleIDs_.size(); + } else if (randomShoot_) { + n = CLHEP::RandFlat::shoot(engine, 1, nParticles_ + 1); + } else { + n = nParticles_; + } + + int particle_counter = 0; + // shoot particles + for (int i = 0; i < 2 * n; i++) { //n for positive and n for negative eta + // create a random deltaR + + // obtain kinematics + int id = particleIDs_[exactShoot_ ? particle_counter : CLHEP::RandFlat::shoot(engine, 0, particleIDs_.size())]; + particle_counter++; + if (particle_counter >= n) + particle_counter = 0; + + const HepPDT::ParticleData* pData = pdgTable_->particle(HepPDT::ParticleID(abs(id))); + double eta = CLHEP::RandFlat::shoot(engine, etaMin_, etaMax_); + if (i < n) + eta *= -1; + double phi = CLHEP::RandFlat::shoot(engine, phiMin_, phiMax_); + double e = CLHEP::RandFlat::shoot(engine, eMin_, eMax_); + double m = pData->mass().value(); + double p = sqrt(e * e - m * m); + math::XYZVector pVec = p * math::XYZVector(cos(phi), sin(phi), sinh(eta)).unit(); + + HepMC::GenVertex* vtx = new HepMC::GenVertex(HepMC::FourVector(0, 0, 0, 0)); + + // create the GenParticle + HepMC::FourVector fVec(pVec.x(), pVec.y(), pVec.z(), e); + HepMC::GenParticle* particle = new HepMC::GenParticle(fVec, id, 1); + particle->suggest_barcode(i + 1); + + // add the particle to the vertex and the vertex to the event + vtx->add_particle_out(particle); + genEvent->add_vertex(vtx); + + if (debug_) { + vtx->print(); + particle->print(); + } + } + + // fill event attributes + genEvent->set_event_number(event.id().event()); + genEvent->set_signal_process_id(20); + + if (debug_) { + genEvent->print(); + } + + // store outputs + std::unique_ptr BProduct(new HepMCProduct()); + BProduct->addHepMCData(genEvent); + event.put(std::move(BProduct), "unsmeared"); + auto genEventInfo = std::make_unique(genEvent); + event.put(std::move(genEventInfo)); + + if (debug_) { + LogDebug("FlatEtaRangeGunProducer") << " : Event Generation Done " << std::endl; + } +} + +void edm::FlatEtaRangeGunProducer::endRunProduce(edm::Run& run, const edm::EventSetup& setup) { + std::unique_ptr genRunInfo(new GenRunInfoProduct()); + run.put(std::move(genRunInfo)); +} diff --git a/IOMC/ParticleGuns/src/FlatEtaRangeNoTrackerGunProducer.cc b/IOMC/ParticleGuns/src/FlatEtaRangeNoTrackerGunProducer.cc new file mode 100644 index 0000000000000..518deb26b52d6 --- /dev/null +++ b/IOMC/ParticleGuns/src/FlatEtaRangeNoTrackerGunProducer.cc @@ -0,0 +1,212 @@ +#include + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "FWCore/ServiceRegistry/interface/Service.h" +#include "FWCore/Utilities/interface/RandomNumberGenerator.h" + +#include "SimDataFormats/GeneratorProducts/interface/GenEventInfoProduct.h" +#include "SimDataFormats/GeneratorProducts/interface/GenRunInfoProduct.h" +#include "SimDataFormats/GeneratorProducts/interface/HepMCProduct.h" + +#include "SimGeneral/HepPDTRecord/interface/ParticleDataTable.h" + +#include "DataFormats/Math/interface/Vector3D.h" +#include "DataFormats/Math/interface/deltaR.h" + +#include "IOMC/ParticleGuns/interface/FlatEtaRangeNoTrackerGunProducer.h" + +#include "CLHEP/Units/GlobalSystemOfUnits.h" +#include "CLHEP/Units/GlobalPhysicalConstants.h" + +#include "CLHEP/Random/RandFlat.h" +#include "CLHEP/Units/GlobalPhysicalConstants.h" +#include "CLHEP/Units/GlobalSystemOfUnits.h" + +void edm::FlatEtaRangeNoTrackerGunProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + + desc.add>("particleIDs"); + desc.add("nParticles", 1); + desc.add("exactShoot", true); + desc.add("randomShoot", false); + desc.add("eMin", 1.); + desc.add("eMax", 100.); + desc.add("etaMin", 1.5); + desc.add("etaMax", 3.0); + desc.add("phiMin", 0.); + desc.add("phiMax", 2 * pi); + desc.addUntracked("debug", false); + desc.add("timeSmearInPs",0.); + desc.add("momSmear",0.); + desc.add("minDistDR",0.01); + + descriptions.add("FlatEtaRangeNoTrackerGunProducer", desc); +} + +edm::FlatEtaRangeNoTrackerGunProducer::FlatEtaRangeNoTrackerGunProducer(const edm::ParameterSet& params) + : particleIDs_(params.getParameter>("particleIDs")), + nParticles_(params.getParameter("nParticles")), + exactShoot_(params.getParameter("exactShoot")), + randomShoot_(params.getParameter("randomShoot")), + eMin_(params.getParameter("eMin")), + eMax_(params.getParameter("eMax")), + etaMin_(params.getParameter("etaMin")), + etaMax_(params.getParameter("etaMax")), + phiMin_(params.getParameter("phiMin")), + phiMax_(params.getParameter("phiMax")), + debug_(params.getUntrackedParameter("debug")), + genEvent_(nullptr), + timeSmear_(params.getParameter("timeSmearInPs")*1e-12), + momSmear_(params.getParameter("momSmear")), + minDistDR_(params.getParameter("minDistDR")){ + produces("unsmeared"); + produces(); + produces(); +} + +edm::FlatEtaRangeNoTrackerGunProducer::~FlatEtaRangeNoTrackerGunProducer() {} + +void edm::FlatEtaRangeNoTrackerGunProducer::beginRun(const edm::Run& run, const edm::EventSetup& setup) { + setup.getData(pdgTable_); + prop_.setEventSetup(setup); +} + +void edm::FlatEtaRangeNoTrackerGunProducer::endRun(const edm::Run& run, const edm::EventSetup& setup) {} + +void edm::FlatEtaRangeNoTrackerGunProducer::produce(edm::Event& event, const edm::EventSetup& setup) { + edm::Service rng; + CLHEP::HepRandomEngine* engine = &(rng->getEngine(event.streamID())); + + if (debug_) { + LogDebug("FlatEtaRangeNoTrackerGunProducer") << " : Begin New Event Generation" << std::endl; + } + + // create a new event to fill + genEvent_ = new HepMC::GenEvent(); + + + // determine the number of particles to shoot + int n = 0; + if (exactShoot_) { + n = (int)particleIDs_.size(); + } else if (randomShoot_) { + n = CLHEP::RandFlat::shoot(engine, 1, nParticles_ + 1); + } else { + n = nParticles_; + } + + int particle_counter=0; + std::vector previous_impacts; + + // shoot particles + for (int i = 0; i < 2 * n; i++) { //n for positive and n for negative eta + // create a random deltaR + + // obtain kinematics + int id = particleIDs_[exactShoot_ ? particle_counter : CLHEP::RandFlat::shoot(engine, 0, particleIDs_.size())]; + particle_counter++; + if(particle_counter>n) + particle_counter=0; + + //generate initial momentum + const HepPDT::ParticleData* pData = pdgTable_->particle(HepPDT::ParticleID(abs(id))); + double eta = CLHEP::RandFlat::shoot(engine, etaMin_, etaMax_); + if (i < n) + eta *= -1; + double phi = CLHEP::RandFlat::shoot(engine, phiMin_, phiMax_); + double e = CLHEP::RandFlat::shoot(engine, eMin_, eMax_); + double m = pData->mass().value(); + double p = sqrt(e * e - m * m); + math::XYZVector pVec = p + * math::XYZVector(cos(phi), sin(phi), sinh(eta)).unit(); + math::XYZTLorentzVectorF momentum(pVec.x(), pVec.y(), pVec.z(), e); + + //initialize original vertex + math::XYZTLorentzVectorF vertexPos(0,0,0,0); + if(timeSmear_>0){ + double t = CLHEP::RandFlat::shoot(engine, -timeSmear_, timeSmear_); + vertexPos.SetE(t); + } + + if(debug_) + LogDebug("FlatEtaRangeNoTrackerGunProducer") << " : Initial vertex position " << vertexPos << std::endl; + //propagate + prop_.propagate(vertexPos,momentum,(pData->charge() > 0) ? 1 : ((pData->charge() < 0) ? -1 : 0)); + + //just move a tad (1mm) towards beamspot + if(vertexPos.z()>0) + vertexPos.SetXYZT(vertexPos.x(),vertexPos.y(),vertexPos.z()-0.1,vertexPos.t()); + else + vertexPos.SetXYZT(vertexPos.x(),vertexPos.y(),vertexPos.z()+0.1,vertexPos.t()); + + if(minDistDR_>0){ + bool next=false; + for(const auto& previ: previous_impacts){ + math::XYZPoint this_im; + if(reco::deltaR(previ.eta(),previ.phi(),vertexPos.eta(),vertexPos.phi()) < minDistDR_){ + next=true; + break; + } + } + if(next){ + i--; + if(debug_) + LogDebug("FlatEtaRangeNoTrackerGunProducer") << " : skipping too close particle" << std::endl; + continue; + } + previous_impacts.push_back(math::XYZPoint(vertexPos.x(),vertexPos.y(),vertexPos.z())); + } + + if(momSmear_>0){ + //TBI + } + //convert all to HEPMC + + HepMC::GenVertex* vtx = new HepMC::GenVertex(HepMC::FourVector( + vertexPos.x()*cm,vertexPos.y()*cm, vertexPos.z()*cm,vertexPos.t()*s*c_light + )); + + HepMC::GenParticle* particle = new HepMC::GenParticle( + HepMC::FourVector(momentum.x(), momentum.y(), + momentum.z(), momentum.E()), + id, 1); + particle->suggest_barcode(i + 1); + + // add the particle to the vertex and the vertex to the event + vtx->add_particle_out(particle); + genEvent_->add_vertex(vtx); + + if (debug_) { + vtx->print(); + particle->print(); + } + } + + // fill event attributes + genEvent_->set_event_number(event.id().event()); + genEvent_->set_signal_process_id(20); + + if (debug_) { + genEvent_->print(); + } + + // store outputs + std::unique_ptr BProduct(new HepMCProduct()); + BProduct->addHepMCData(genEvent_); + event.put(std::move(BProduct), "unsmeared"); + std::unique_ptr genEventInfo(new GenEventInfoProduct(genEvent_)); + event.put(std::move(genEventInfo)); + + if (debug_) { + LogDebug("FlatEtaRangeNoTrackerGunProducer") << " : Event Generation Done " << std::endl; + } +} + +void edm::FlatEtaRangeNoTrackerGunProducer::endRunProduce(edm::Run& run, const edm::EventSetup& setup) { + std::unique_ptr genRunInfo(new GenRunInfoProduct()); + run.put(std::move(genRunInfo)); +} diff --git a/IOMC/ParticleGuns/src/FlatRandomPtAndDxyGunProducer.cc b/IOMC/ParticleGuns/src/FlatRandomPtAndDxyGunProducer.cc index 685185d8b5155..ea55ab190aa90 100644 --- a/IOMC/ParticleGuns/src/FlatRandomPtAndDxyGunProducer.cc +++ b/IOMC/ParticleGuns/src/FlatRandomPtAndDxyGunProducer.cc @@ -109,9 +109,7 @@ void FlatRandomPtAndDxyGunProducer::produce(Event& e, const EventSetup& es) { break; } - float time = sqrt(vx * vx + vy * vy + vz * vz); - - HepMC::GenVertex* Vtx1 = new HepMC::GenVertex(HepMC::FourVector(vx, vy, vz, time)); + HepMC::GenVertex* Vtx1 = new HepMC::GenVertex(HepMC::FourVector(vx, vy, vz)); int PartID = fPartIDs[ip]; const HepPDT::ParticleData* PData = fPDGTable->particle(HepPDT::ParticleID(abs(PartID))); @@ -126,7 +124,7 @@ void FlatRandomPtAndDxyGunProducer::produce(Event& e, const EventSetup& es) { fEvt->add_vertex(Vtx1); if (fAddAntiParticle) { - HepMC::GenVertex* Vtx2 = new HepMC::GenVertex(HepMC::FourVector(-vx, -vy, -vz, time)); + HepMC::GenVertex* Vtx2 = new HepMC::GenVertex(HepMC::FourVector(-vx, -vy, -vz)); HepMC::FourVector ap(-px, -py, -pz, energy); int APartID = -PartID; if (PartID == 22 || PartID == 23) { diff --git a/IOMC/ParticleGuns/src/SealModule.cc b/IOMC/ParticleGuns/src/SealModule.cc index d21e3d2b1f01f..55dc8c2336d29 100644 --- a/IOMC/ParticleGuns/src/SealModule.cc +++ b/IOMC/ParticleGuns/src/SealModule.cc @@ -13,15 +13,18 @@ #include "IOMC/ParticleGuns/interface/FlatRandomEThetaGunProducer.h" #include "IOMC/ParticleGuns/interface/FileRandomKEThetaGunProducer.h" #include "IOMC/ParticleGuns/interface/FileRandomMultiParticlePGunProducer.h" -#include "IOMC/ParticleGuns/interface/FlatRandomMultiParticlePGunProducer.h" +#include "IOMC/ParticleGuns/interface/FlatEtaRangeGunProducer.h" +#include "IOMC/ParticleGuns/interface/FlatEtaRangeNoTrackerGunProducer.h" #include "IOMC/ParticleGuns/interface/FlatRandomOneOverPtGunProducer.h" #include "IOMC/ParticleGuns/interface/FlatRandomPtAndDxyGunProducer.h" #include "IOMC/ParticleGuns/interface/FlatRandomPtGunProducer.h" #include "IOMC/ParticleGuns/interface/FlatRandomPtThetaGunProducer.h" +#include "IOMC/ParticleGuns/interface/FlatRandomMultiParticlePGunProducer.h" #include "IOMC/ParticleGuns/interface/GaussRandomPThetaGunProducer.h" #include "IOMC/ParticleGuns/interface/MultiParticleInConeGunProducer.h" #include "IOMC/ParticleGuns/interface/RandomtXiGunProducer.h" #include "IOMC/ParticleGuns/interface/RandomMultiParticlePGunProducer.h" +#include "IOMC/ParticleGuns/interface/CloseByFlatDeltaRGunProducer.h" #include "IOMC/ParticleGuns/interface/RandomXiThetaGunProducer.h" // particle gun prototypes // @@ -51,6 +54,12 @@ using edm::FlatRandomEThetaGunProducer; DEFINE_FWK_MODULE(FlatRandomEThetaGunProducer); using edm::FlatRandomMultiParticlePGunProducer; DEFINE_FWK_MODULE(FlatRandomMultiParticlePGunProducer); +using edm::FlatEtaRangeGunProducer; +DEFINE_FWK_MODULE(FlatEtaRangeGunProducer); +using edm::FlatEtaRangeNoTrackerGunProducer; +DEFINE_FWK_MODULE(FlatEtaRangeNoTrackerGunProducer); +using edm::FlatRandomPtThetaGunProducer; +DEFINE_FWK_MODULE(FlatRandomPtThetaGunProducer); using edm::FlatRandomOneOverPtGunProducer; DEFINE_FWK_MODULE(FlatRandomOneOverPtGunProducer); using edm::FlatRandomPtAndDxyGunProducer; @@ -65,5 +74,7 @@ using edm::RandomtXiGunProducer; DEFINE_FWK_MODULE(RandomtXiGunProducer); using edm::RandomMultiParticlePGunProducer; DEFINE_FWK_MODULE(RandomMultiParticlePGunProducer); +using edm::CloseByFlatDeltaRGunProducer; +DEFINE_FWK_MODULE(CloseByFlatDeltaRGunProducer); using edm::RandomXiThetaGunProducer; DEFINE_FWK_MODULE(RandomXiThetaGunProducer); From 83da06964fcc5325b62ea323e56195ddae278412 Mon Sep 17 00:00:00 2001 From: Kenneth Long Date: Fri, 27 Aug 2021 13:40:18 +0200 Subject: [PATCH 13/17] Turn off TP and SC associations in PFTruth --- DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py | 2 +- .../PFTruthProducer/plugins/PFTruthParticleProducer.cc | 10 ++++++++-- SimDataFormats/PFAnalysis/interface/PFTruthParticle.h | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py b/DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py index e0bf7a206dc9b..aabdb7471e385 100644 --- a/DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py +++ b/DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py @@ -41,5 +41,5 @@ docString = cms.string("PFTruth particle to which the TrackingPart is associated") ) -pfTruth = cms.Sequence(pfTruthParticles+pfTruthTable+simClusterToPFTruthTable+trackingPartToPFTruthTable) +pfTruth = cms.Sequence(pfTruthParticles+pfTruthTable)#+simClusterToPFTruthTable+trackingPartToPFTruthTable) diff --git a/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc b/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc index 0b5177a0604a4..87ec3b77278fc 100644 --- a/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc +++ b/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc @@ -157,6 +157,12 @@ void PFTruthParticleProducer::produce(edm::StreamID, edm::Event &iEvent, const e std::vector matchedtptocp; PFTruthParticleCollection idealPFTruth; + // Used to fill the associations in the ntuples + //auto tpAssoc = std::make_unique>(pfTruthHand); + //auto scAssoc = std::make_unique>(pfTruthHand); + + //edm::Association::Filler tpFiller(*tpAssoc); + for(const auto& cp: *cpCollection){ TrackingParticleRefVector tprefs; @@ -215,8 +221,8 @@ void PFTruthParticleProducer::produce(edm::StreamID, edm::Event &iEvent, const e //create PF particle per SimCluster //vertex position will remain the initial CP one (timing) auto npftp = pftp; - npftp.trackingParticles().clear(); - npftp.simClusters().clear(); + npftp.clearTrackingParticles(); + npftp.clearSimClusters(); npftp.addSimCluster(sc); //this is now defined to be a neutral PF Particle. Even if the SC happens to be charged npftp.setCharge(0); diff --git a/SimDataFormats/PFAnalysis/interface/PFTruthParticle.h b/SimDataFormats/PFAnalysis/interface/PFTruthParticle.h index 01198ca496664..6a0e7a736b4b5 100644 --- a/SimDataFormats/PFAnalysis/interface/PFTruthParticle.h +++ b/SimDataFormats/PFAnalysis/interface/PFTruthParticle.h @@ -47,8 +47,8 @@ class PFTruthParticle { void addSimCluster(const SimClusterRef sc); void addTrackingParticle(const TrackingParticleRef tp); - SimClusterRefVector& simClusters() { return simClusters_; } - TrackingParticleRefVector& trackingParticles() { return trackingParticles_; } + void clearSimClusters() { simClusters_.clear(); } + void clearTrackingParticles() { trackingParticles_.clear(); } const SimClusterRefVector& simClusters() const { return simClusters_; } const TrackingParticleRefVector& trackingParticles() const { return trackingParticles_; } size_t nSimCluster() const { return simClusters_.size(); } From a0f03e30df1af675fb5d3a15078e71c09961dc8c Mon Sep 17 00:00:00 2001 From: Kenneth Long Date: Fri, 27 Aug 2021 13:51:41 +0200 Subject: [PATCH 14/17] Fix input collection for SimHits and SimTracks --- DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py b/DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py index aabdb7471e385..0d5a923a0b1a9 100644 --- a/DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py +++ b/DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py @@ -6,8 +6,8 @@ pfTruthParticles = cms.EDProducer("PFTruthParticleProducer", trackingParticles= cms.InputTag("mix:MergedTrackTruth"), caloParticles= cms.InputTag("mix:MergedCaloTruth"), - simVertices= cms.InputTag("SimVertices"), - simTracks= cms.InputTag("SimTracks"), + simVertices= cms.InputTag("g4SimHits"), + simTracks= cms.InputTag("g4SimHits"), ) pfTruthTable = cms.EDProducer("SimplePFTruthParticleFlatTableProducer", From 24ccaddcafeb430a4e3f3c7d9cf81cec029c1ac6 Mon Sep 17 00:00:00 2001 From: Jan Kieseler Date: Fri, 27 Aug 2021 16:22:32 +0200 Subject: [PATCH 15/17] running version of pf truth --- .../PFTruthProducer/plugins/BuildFile.xml | 2 ++ .../plugins/PFTruthParticleProducer.cc | 18 +++++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/RecoParticleFlow/PFTruthProducer/plugins/BuildFile.xml b/RecoParticleFlow/PFTruthProducer/plugins/BuildFile.xml index 1d1e94bd4f9e3..17364514e6adf 100644 --- a/RecoParticleFlow/PFTruthProducer/plugins/BuildFile.xml +++ b/RecoParticleFlow/PFTruthProducer/plugins/BuildFile.xml @@ -26,3 +26,5 @@ + + diff --git a/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc b/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc index 87ec3b77278fc..444f602bdac44 100644 --- a/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc +++ b/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc @@ -121,8 +121,10 @@ const SimTrack* PFTruthParticleProducer::getRoot( break; //no vertex const SimVertex& vertex = simvertices.at(vidx); int stid = vertex.parentIndex();//this is Geant track ID, not vector index + if(stid < 0) + break; int stidx = trackIdToTrackIdxAsso.at(stid); //get vector index - if(stidx<0) + if(stidx < 0) break; const SimTrack & simtrack = simtracks.at(stidx); vidx = simtrack.vertIndex(); @@ -174,7 +176,8 @@ void PFTruthParticleProducer::produce(edm::StreamID, edm::Event &iEvent, const e continue; //already matched TrackingParticleRef tpref(tpCollection, i); - + if(tpref->g4Tracks().size()<1) + continue; //go through whole history auto stp = getRoot(& tpref->g4Tracks().at(0), *stCollection,*svCollection, trackIdToTrackIdxAsso); @@ -199,15 +202,17 @@ void PFTruthParticleProducer::produce(edm::StreamID, edm::Event &iEvent, const e idealPFTruth.push_back(pftp); } + std::cout << "ideal PF truth built, splitting" << std::endl; + // --- now we have the ideal PF truth, far from realistic. // --- this is where the actual "meat" of the implementation starts double softkill_relthreshold = 0.001;//just to avoid ambiguities. - double hardsplit_deltaR = 0.3; + //not used currently double hardsplit_deltaR = 0.3; - std::unique_ptr PFtruth; + auto PFtruth = std::make_unique() ; //apply splitting particle by particle //this is where the physics happens @@ -252,10 +257,9 @@ void PFTruthParticleProducer::produce(edm::StreamID, edm::Event &iEvent, const e } + std::cout << "putting PFTruthParticles" << std::endl; - - iEvent.put(std::move(PFtruth), "PFTruthParticles"); - + iEvent.put(std::move(PFtruth)); } From 4c02f367db80ca06701ad101f9bfc91108f72de5 Mon Sep 17 00:00:00 2001 From: Jan Kieseler Date: Fri, 27 Aug 2021 17:17:12 +0200 Subject: [PATCH 16/17] another snapshot --- .../plugins/PFTruthParticleProducer.cc | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc b/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc index 444f602bdac44..1857d21d0978d 100644 --- a/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc +++ b/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc @@ -170,6 +170,7 @@ void PFTruthParticleProducer::produce(edm::StreamID, edm::Event &iEvent, const e TrackingParticleRefVector tprefs; const SimClusterRefVector& screfs = cp.simClusters(); + bool hasfulltrack=false; //match the tracking particle(s) for(size_t i=0; i< tpCollection->size(); i++){ if(std::find(matchedtptocp.begin(),matchedtptocp.end(), i) != matchedtptocp.end()) @@ -178,21 +179,48 @@ void PFTruthParticleProducer::produce(edm::StreamID, edm::Event &iEvent, const e TrackingParticleRef tpref(tpCollection, i); if(tpref->g4Tracks().size()<1) continue; + + if(!tpref->charge()) + continue; //only charged ones + + if(tpref->numberOfTrackerLayers() < 5) + continue; //not reconstrucable: simple approx for now needs to be refined with tracking POG selection on input level + + if(tpref->pt() < 0.5)//throw out very low energy: simple approx... + continue; + //go through whole history auto stp = getRoot(& tpref->g4Tracks().at(0), *stCollection,*svCollection, trackIdToTrackIdxAsso); + //match + //this needs some more logic if(stp->trackId() == cp.g4Tracks().at(0).trackId() && stp->eventId() == cp.g4Tracks().at(0).eventId()){ matchedtptocp.push_back(i); tprefs.push_back(tpref); + + std::cout << "added track " << tpref->pdgId() << " "<< tpref->momentum() << ", pt " << tpref->pt()<< std::endl;//DEBUG } + + for(const auto g4t: tpref->g4Tracks()){ + if(g4t.trackId() == cp.g4Tracks().at(0).trackId() + && g4t.eventId() == cp.g4Tracks().at(0).eventId()){ + hasfulltrack=true; + } + } + } + + std::cout << "PF particle with "<< tprefs.size() << " attached tracking particles " <at(vidx).position(); @@ -202,7 +230,7 @@ void PFTruthParticleProducer::produce(edm::StreamID, edm::Event &iEvent, const e idealPFTruth.push_back(pftp); } - std::cout << "ideal PF truth built, splitting" << std::endl; + std::cout << "ideal PF truth built, splitting" << std::endl;//DEBUG // --- now we have the ideal PF truth, far from realistic. @@ -221,7 +249,10 @@ void PFTruthParticleProducer::produce(edm::StreamID, edm::Event &iEvent, const e //consider the ones without tracking particles // this is not the same as the ones without charge, // because e.g. a very early converting photon would have charge 0, but two tracking particles associated - if(! pftp.trackingParticles().size()) { + if(! pftp.charge()) { + + size_t pre = PFtruth->size(); + for(const auto& sc: pftp.simClusters()){ //create PF particle per SimCluster //vertex position will remain the initial CP one (timing) @@ -235,6 +266,7 @@ void PFTruthParticleProducer::produce(edm::StreamID, edm::Event &iEvent, const e npftp.setPdgId(sc->pdgId()); //to be discussed PFtruth->push_back(npftp); } + std::cout << "Split PF Particle to "<< PFtruth->size()-pre << " neutrals " < Date: Tue, 21 Sep 2021 00:27:24 +0200 Subject: [PATCH 17/17] PFTruth particle (with unmerged SCs) --- .../ObjectIndexFromAssociationProducer.cc | 6 + .../SimpleHGCFlatTableProducerPlugins.cc | 1 + .../HGCalNanoAOD/python/nanoHGCML_cff.py | 6 +- DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py | 19 +++- .../plugins/PFTruthParticleProducer.cc | 103 ++++++++++++++---- SimDataFormats/Associations/src/classes.h | 3 +- .../Associations/src/classes_def.xml | 3 + SimDataFormats/PFAnalysis/src/classes_def.xml | 2 - 8 files changed, 114 insertions(+), 29 deletions(-) diff --git a/DPGAnalysis/HGCalNanoAOD/plugins/ObjectIndexFromAssociationProducer.cc b/DPGAnalysis/HGCalNanoAOD/plugins/ObjectIndexFromAssociationProducer.cc index 49c1e6d5236e8..636dc103d127a 100644 --- a/DPGAnalysis/HGCalNanoAOD/plugins/ObjectIndexFromAssociationProducer.cc +++ b/DPGAnalysis/HGCalNanoAOD/plugins/ObjectIndexFromAssociationProducer.cc @@ -3,6 +3,8 @@ #include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" #include "SimDataFormats/CaloAnalysis/interface/CaloParticle.h" #include "SimDataFormats/CaloAnalysis/interface/CaloParticleFwd.h" +#include "SimDataFormats/PFAnalysis/interface/PFTruthParticle.h" +#include "SimDataFormats/PFAnalysis/interface/PFTruthParticleFwd.h" #include "SimDataFormats/Track/interface/SimTrack.h" #include "SimDataFormats/Track/interface/SimTrackContainer.h" #include "SimDataFormats/CaloHit/interface/PCaloHitContainer.h" @@ -25,9 +27,13 @@ typedef ObjectIndexFromAssociationTableProducer SimClusterToSimClusterIndexTableProducer; +typedef ObjectIndexFromAssociationTableProducer, PFTruthParticleCollection> + CaloRecHitToPFTruthParticleIndexTableProducer; + DEFINE_FWK_MODULE(SimTrackToSimClusterIndexTableProducer); DEFINE_FWK_MODULE(CaloHitToSimClusterIndexTableProducer); DEFINE_FWK_MODULE(SimClusterToCaloParticleIndexTableProducer); DEFINE_FWK_MODULE(SimClusterToSimClusterIndexTableProducer); DEFINE_FWK_MODULE(CaloRecHitToPFCandIndexTableProducer); DEFINE_FWK_MODULE(CaloRecHitToBestSimClusterIndexTableProducer); +DEFINE_FWK_MODULE(CaloRecHitToPFTruthParticleIndexTableProducer); diff --git a/DPGAnalysis/HGCalNanoAOD/plugins/SimpleHGCFlatTableProducerPlugins.cc b/DPGAnalysis/HGCalNanoAOD/plugins/SimpleHGCFlatTableProducerPlugins.cc index e968d485c64ff..206dc856b374a 100644 --- a/DPGAnalysis/HGCalNanoAOD/plugins/SimpleHGCFlatTableProducerPlugins.cc +++ b/DPGAnalysis/HGCalNanoAOD/plugins/SimpleHGCFlatTableProducerPlugins.cc @@ -13,6 +13,7 @@ typedef SimpleFlatTableProducer SimpleCaloParticleFlatTableProduce #include "DataFormats/CaloRecHit/interface/CaloCluster.h" typedef SimpleFlatTableProducer SimpleCaloClusterFlatTableProducer; + #include "FWCore/Framework/interface/MakerMacros.h" DEFINE_FWK_MODULE(SimplePCaloHitFlatTableProducer); DEFINE_FWK_MODULE(SimpleCaloRecHitFlatTableProducer); diff --git a/DPGAnalysis/HGCalNanoAOD/python/nanoHGCML_cff.py b/DPGAnalysis/HGCalNanoAOD/python/nanoHGCML_cff.py index d250ac0d67c8c..1320a72f05d38 100644 --- a/DPGAnalysis/HGCalNanoAOD/python/nanoHGCML_cff.py +++ b/DPGAnalysis/HGCalNanoAOD/python/nanoHGCML_cff.py @@ -33,8 +33,10 @@ simClusterTables ) -nanoHGCMLRecoSequence = cms.Sequence(hgcRecHitsSequence+hgcRecHitSimAssociationSequence+ - pfCandTable+pfTruth+pfTICLCandTable+trackTables) +nanoHGCMLRecoSequence = cms.Sequence(hgcRecHitsSequence+ + hgcRecHitSimAssociationSequence+ + pfCandTable+pfTruth+ + pfTICLCandTable+trackTables) def customizeReco(process): process.nanoHGCMLSequence.insert(-1, nanoHGCMLRecoSequence) diff --git a/DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py b/DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py index 0d5a923a0b1a9..f94c5a72eba58 100644 --- a/DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py +++ b/DPGAnalysis/PFNanoAOD/python/pfTruth_cff.py @@ -1,13 +1,17 @@ import FWCore.ParameterSet.Config as cms from PhysicsTools.NanoAOD.common_cff import CandVars,Var from DPGAnalysis.HGCalNanoAOD.simClusters_cff import simClusterTable +from DPGAnalysis.HGCalNanoAOD.hgcRecHits_cff import hgcRecHitsTable from DPGAnalysis.TrackNanoAOD.trackingParticles_cff import trackingParticleTable pfTruthParticles = cms.EDProducer("PFTruthParticleProducer", trackingParticles= cms.InputTag("mix:MergedTrackTruth"), caloParticles= cms.InputTag("mix:MergedCaloTruth"), + simClusters = cms.InputTag("mix:MergedCaloTruth"), simVertices= cms.InputTag("g4SimHits"), simTracks= cms.InputTag("g4SimHits"), + caloRecHits = cms.InputTag("hgcRecHits"), + rechitToSimClusAssoc = cms.InputTag("hgcRecHitsToSimClusters:hgcRecHitsToBestSimClus"), ) pfTruthTable = cms.EDProducer("SimplePFTruthParticleFlatTableProducer", @@ -41,5 +45,18 @@ docString = cms.string("PFTruth particle to which the TrackingPart is associated") ) -pfTruth = cms.Sequence(pfTruthParticles+pfTruthTable)#+simClusterToPFTruthTable+trackingPartToPFTruthTable) +recHitToPFTruthTable = cms.EDProducer("CaloRecHitToPFTruthParticleIndexTableProducer", + cut = hgcRecHitsTable.cut, + src = hgcRecHitsTable.src, + objName = hgcRecHitsTable.name, + branchName = cms.string("BestPFTruthPart"), + objMap = cms.InputTag("pfTruthParticles:caloRecHitToPFTruth"), + docString = cms.string("PFTruthParticle to which the RecHit is matched (via the sim cluster)") +) + +pfTruth = cms.Sequence(pfTruthParticles+pfTruthTable + +simClusterToPFTruthTable + +trackingPartToPFTruthTable + +recHitToPFTruthTable + ) diff --git a/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc b/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc index 1857d21d0978d..78ab62c939c5b 100644 --- a/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc +++ b/RecoParticleFlow/PFTruthProducer/plugins/PFTruthParticleProducer.cc @@ -16,13 +16,17 @@ #include "FWCore/MessageLogger/interface/MessageLogger.h" #include "SimDataFormats/TrackingAnalysis/interface/TrackingParticle.h" +#include "SimDataFormats/TrackingAnalysis/interface/TrackingParticleFwd.h" #include "SimDataFormats/CaloAnalysis/interface/CaloParticle.h" #include "SimDataFormats/CaloAnalysis/interface/CaloParticleFwd.h" #include "SimDataFormats/CaloAnalysis/interface/SimClusterFwd.h" #include "SimDataFormats/CaloAnalysis/interface/SimCluster.h" #include "SimDataFormats/PFAnalysis/interface/PFTruthParticle.h" #include "SimDataFormats/PFAnalysis/interface/PFTruthParticleFwd.h" +#include "DataFormats/CaloRecHit/interface/CaloRecHit.h" +#include "DataFormats/HGCRecHit/interface/HGCRecHit.h" +#include "DataFormats/HGCRecHit/interface/HGCRecHitCollections.h" #include "FWCore/Utilities/interface/EDGetToken.h" #include @@ -86,19 +90,28 @@ class PFTruthParticleProducer : public edm::global::EDProducer<> { edm::EDGetTokenT tpCollectionToken_; edm::EDGetTokenT cpCollectionToken_; + edm::EDGetTokenT scCollectionToken_; edm::EDGetTokenT > svCollectionToken_; edm::EDGetTokenT > stCollectionToken_; - + //edm::EDGetTokenT> caloRecHitToken_; + edm::EDGetTokenT caloRecHitToken_; + edm::EDGetTokenT> recHitToSCToken_; }; PFTruthParticleProducer::PFTruthParticleProducer(const edm::ParameterSet &pset) : tpCollectionToken_(consumes(pset.getParameter("trackingParticles"))), cpCollectionToken_(consumes(pset.getParameter("caloParticles"))), + scCollectionToken_(consumes(pset.getParameter("simClusters"))), svCollectionToken_(consumes >(pset.getParameter("simVertices"))), - stCollectionToken_(consumes >(pset.getParameter("simTracks"))) + stCollectionToken_(consumes >(pset.getParameter("simTracks"))), + caloRecHitToken_(consumes(pset.getParameter("caloRecHits"))), + recHitToSCToken_(consumes >(pset.getParameter("rechitToSimClusAssoc"))) { produces(); + produces>("trackingPartToPFTruth"); + produces>("simClusToPFTruth"); + produces>("caloRecHitToPFTruth"); } PFTruthParticleProducer::~PFTruthParticleProducer() {} @@ -143,12 +156,21 @@ void PFTruthParticleProducer::produce(edm::StreamID, edm::Event &iEvent, const e edm::Handle cpCollection; iEvent.getByToken(cpCollectionToken_, cpCollection); + edm::Handle scCollection; + iEvent.getByToken(scCollectionToken_, scCollection); + edm::Handle > svCollection; iEvent.getByToken(svCollectionToken_, svCollection); edm::Handle > stCollection; iEvent.getByToken(stCollectionToken_, stCollection); + edm::Handle caloRecHitCollection; + iEvent.getByToken(caloRecHitToken_, caloRecHitCollection); + + edm::Handle> recHitToSC; + iEvent.getByToken(recHitToSCToken_, recHitToSC); + std::map trackIdToTrackIdxAsso; for(size_t i=0;isize();i++){ trackIdToTrackIdxAsso[stCollection->at(i).trackId()] = i; @@ -159,11 +181,9 @@ void PFTruthParticleProducer::produce(edm::StreamID, edm::Event &iEvent, const e std::vector matchedtptocp; PFTruthParticleCollection idealPFTruth; - // Used to fill the associations in the ntuples - //auto tpAssoc = std::make_unique>(pfTruthHand); - //auto scAssoc = std::make_unique>(pfTruthHand); - - //edm::Association::Filler tpFiller(*tpAssoc); + std::vector tpToPFpartIdx(tpCollection->size(), -1); + std::vector scToPFpartIdx(scCollection->size(), -1); + std::vector rhToPFpartIdx(caloRecHitCollection->size(), -1); for(const auto& cp: *cpCollection){ @@ -244,9 +264,9 @@ void PFTruthParticleProducer::produce(edm::StreamID, edm::Event &iEvent, const e //apply splitting particle by particle //this is where the physics happens + int pfidx = 0; for(const auto & pftp: idealPFTruth){ - //consider the ones without tracking particles // this is not the same as the ones without charge, // because e.g. a very early converting photon would have charge 0, but two tracking particles associated if(! pftp.charge()) { @@ -264,35 +284,72 @@ void PFTruthParticleProducer::produce(edm::StreamID, edm::Event &iEvent, const e npftp.setCharge(0); npftp.setP4(sc->impactMomentum());//that's all we measure npftp.setPdgId(sc->pdgId()); //to be discussed + scToPFpartIdx[sc.key()] = PFtruth->size(); PFtruth->push_back(npftp); } std::cout << "Split PF Particle to "<< PFtruth->size()-pre << " neutrals " <impactMomentum().E() > trimmed_pfp.p4().E() * softkill_relthreshold){ - trimmersc.push_back(sc); - } - } - trimmed_pfp.setSimClusters(trimmersc); - //no split - PFtruth->push_back(trimmed_pfp); + //trim + auto trimmed_pfp = pftp; + SimClusterRefVector trimmersc; + for(auto & sc: trimmed_pfp.simClusters()){ + if(sc->impactMomentum().E() > trimmed_pfp.p4().E() * softkill_relthreshold){ + trimmersc.push_back(sc); + scToPFpartIdx[sc.key()] = PFtruth->size(); + } + } + trimmed_pfp.setSimClusters(trimmersc); + //no split + PFtruth->push_back(trimmed_pfp); + for (auto& tp : trimmed_pfp.trackingParticles()) + tpToPFpartIdx[tp.key()] = pfidx; + + } + pfidx++; + } + + for (size_t i = 0; i < caloRecHitCollection->size(); i++) { + HGCRecHitRef rh(caloRecHitCollection, i); + auto scRef = (*recHitToSC)[rh]; + int scIdx = scRef.isNonnull() ? scRef.key() : -1; + int pfIdx = scIdx >= 0 ? scToPFpartIdx[scIdx] : -1; + if (scIdx >= 0) + std::cout << "SC Index is " << scIdx << " pfIdx is " << pfIdx << std::endl; + rhToPFpartIdx.at(i) = pfIdx; } std::cout << "putting PFTruthParticles" << std::endl;//DEBUG - iEvent.put(std::move(PFtruth)); + auto pfTruthHand = iEvent.put(std::move(PFtruth)); + + // Used to fill the associations in the ntuples + auto tpAssoc = std::make_unique>(pfTruthHand); + auto scAssoc = std::make_unique>(pfTruthHand); + auto rhAssoc = std::make_unique>(pfTruthHand); + + edm::Association::Filler tpFiller(*tpAssoc); + tpFiller.insert(tpCollection, tpToPFpartIdx.begin(), tpToPFpartIdx.end()); + tpFiller.fill(); + + edm::Association::Filler scFiller(*scAssoc); + scFiller.insert(scCollection, scToPFpartIdx.begin(), scToPFpartIdx.end()); + scFiller.fill(); + + edm::Association::Filler rhFiller(*rhAssoc); + rhFiller.insert(caloRecHitCollection, rhToPFpartIdx.begin(), rhToPFpartIdx.end()); + rhFiller.fill(); + iEvent.put(std::move(tpAssoc), "trackingPartToPFTruth"); + iEvent.put(std::move(scAssoc), "simClusToPFTruth"); + iEvent.put(std::move(rhAssoc), "caloRecHitToPFTruth"); } // define this as a plug-in diff --git a/SimDataFormats/Associations/src/classes.h b/SimDataFormats/Associations/src/classes.h index 7542e39cde423..4d2494f9ed895 100644 --- a/SimDataFormats/Associations/src/classes.h +++ b/SimDataFormats/Associations/src/classes.h @@ -8,12 +8,12 @@ #include "SimDataFormats/Associations/interface/VertexToTrackingVertexAssociator.h" #include "SimDataFormats/Associations/interface/LayerClusterToCaloParticleAssociator.h" #include "SimDataFormats/Associations/interface/LayerClusterToSimClusterAssociator.h" +#include "SimDataFormats/Associations/interface/LayerClusterToSimTracksterAssociator.h" #include "SimDataFormats/Associations/interface/TrackAssociation.h" #include "SimDataFormats/Associations/interface/TracksterToSimClusterAssociator.h" #include "SimDataFormats/Associations/interface/MultiClusterToCaloParticleAssociator.h" #include "SimDataFormats/Associations/interface/TracksterToSimTracksterAssociator.h" #include "SimDataFormats/Associations/interface/TTTrackTruthPair.h" -#include "SimDataFormats/Associations/interface/LayerClusterToSimTracksterAssociator.h" #include "DataFormats/Common/interface/AssociationMap.h" #include "DataFormats/Common/interface/AssociationMapHelpers.h" @@ -21,6 +21,7 @@ #include "DataFormats/HGCRecHit/interface/HGCRecHit.h" #include "DataFormats/HGCRecHit/interface/HGCRecHitCollections.h" #include "DataFormats/CaloRecHit/interface/CaloCluster.h" +#include "SimDataFormats/PFAnalysis/interface/PFTruthParticle.h" #include "DataFormats/Common/interface/Association.h" #include "DataFormats/Common/interface/AssociationMap.h" diff --git a/SimDataFormats/Associations/src/classes_def.xml b/SimDataFormats/Associations/src/classes_def.xml index c1275c52e6a73..e523e37073407 100644 --- a/SimDataFormats/Associations/src/classes_def.xml +++ b/SimDataFormats/Associations/src/classes_def.xml @@ -143,6 +143,9 @@ + + + diff --git a/SimDataFormats/PFAnalysis/src/classes_def.xml b/SimDataFormats/PFAnalysis/src/classes_def.xml index 9f1a9b8d6daf1..cafbb7376b82f 100644 --- a/SimDataFormats/PFAnalysis/src/classes_def.xml +++ b/SimDataFormats/PFAnalysis/src/classes_def.xml @@ -8,7 +8,5 @@ - -