diff --git a/Configuration/ProcessModifiers/python/ecal_deepsc_cff.py b/Configuration/ProcessModifiers/python/ecal_deepsc_cff.py
new file mode 100644
index 0000000000000..997decae5b524
--- /dev/null
+++ b/Configuration/ProcessModifiers/python/ecal_deepsc_cff.py
@@ -0,0 +1,6 @@
+import FWCore.ParameterSet.Config as cms
+
+# This modifier is for ECAL SuperCluster with ML studies
+
+ecal_deepsc = cms.Modifier()
+
diff --git a/Configuration/PyReleaseValidation/README.md b/Configuration/PyReleaseValidation/README.md
index 4098491d9779c..e448bf053fd42 100644
--- a/Configuration/PyReleaseValidation/README.md
+++ b/Configuration/PyReleaseValidation/README.md
@@ -57,6 +57,7 @@ The offsets currently in use are:
* 0.13: MLPF algorithm
* 0.15: JME NanoAOD
* 0.17: Run-3 deep core seeding for JetCore iteration
+* 0.19: ECAL SuperClustering with DeepSC algorithm
* 0.21: Production-like sequence
* 0.24: 0 Tesla (Run-2, Run-3)
* 0.31: Photon energy corrections with DRN architecture
diff --git a/Configuration/PyReleaseValidation/python/relval_2017.py b/Configuration/PyReleaseValidation/python/relval_2017.py
index cfb95356acc48..6fa76deeb654a 100644
--- a/Configuration/PyReleaseValidation/python/relval_2017.py
+++ b/Configuration/PyReleaseValidation/python/relval_2017.py
@@ -39,7 +39,8 @@
# (Patatrack HCAL-only: TTbar - on CPU)
# (TTbar 0T, TTbar PU 0T)
# (TTbar FastSim)
-# (TTbar PU MLPF)
+# (TTbar PU MLPF ecal_deepsc)
+# (ZEE ecal_deesc)
# (TTbar PU prod-like)
# (QCD 1.8TeV DeepCore)
# (TTbar DigiNoHLT)
@@ -71,7 +72,8 @@
11634.521,
11634.24,11834.24,
11634.301,
- 11834.13,
+ 11834.13, 11834.19,
+ 11846.19,
11834.21,
11723.17,
11634.601,
diff --git a/Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py b/Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py
index 3a1138c372193..7be1e7b0d1816 100644
--- a/Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py
+++ b/Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py
@@ -517,6 +517,35 @@ def condition(self, fragment, stepList, key, hasHarvest):
'--procModifiers': 'mlpf'
}
+
+# ECAL DeepSC clustering studies workflow
+class UpgradeWorkflow_ecalclustering(UpgradeWorkflow):
+ def setup_(self, step, stepName, stepDict, k, properties):
+ if 'Reco' in step:
+ stepDict[stepName][k] = merge([self.step3, stepDict[step][k]])
+ def condition(self, fragment, stepList, key, hasHarvest):
+ return (fragment=="ZEE_14" or fragment=="TTbar_14TeV" or fragment=="WprimeTolNu_M3000_13TeV_pythia8"
+ or fragment=="DisplacedSUSY_stopToBottom_M_300_1000mm_13" or fragment=="RunEGamma2018D" )
+
+upgradeWFs['ecalDeepSC'] = UpgradeWorkflow_ecalclustering(
+ steps = [
+ 'Reco',
+ 'RecoNano',
+ ],
+ PU = [
+ 'Reco',
+ 'RecoNano',
+ ],
+ suffix = '_ecalDeepSC',
+ offset = 0.19,
+)
+upgradeWFs['ecalDeepSC'].step3 = {
+ '--datatier': 'RECOSIM,MINIAODSIM,NANOAODSIM,DQMIO',
+ '--eventcontent': 'RECOSIM,MINIAODSIM,NANOEDMAODSIM,DQM',
+ '--procModifiers': 'ecal_deepsc'
+}
+
+
# photonDRN workflows
class UpgradeWorkflow_photonDRN(UpgradeWorkflow):
def setup_(self, step, stepName, stepDict, k, properties):
@@ -543,6 +572,7 @@ def condition(self, fragment, stepList, key, hasHarvest):
'--procModifiers': 'enableSonicTriton,photonDRN'
}
+
# Patatrack workflows:
# - 2018 conditions, TTbar
# - 2018 conditions, Z->mumu,
diff --git a/RecoEcal/EgammaClusterAlgos/BuildFile.xml b/RecoEcal/EgammaClusterAlgos/BuildFile.xml
index 6334a637b8a2f..685870289393a 100644
--- a/RecoEcal/EgammaClusterAlgos/BuildFile.xml
+++ b/RecoEcal/EgammaClusterAlgos/BuildFile.xml
@@ -1,18 +1,24 @@
+
+
+
+
-
+
+
+
diff --git a/RecoEcal/EgammaClusterAlgos/interface/PFECALSuperClusterAlgo.h b/RecoEcal/EgammaClusterAlgos/interface/PFECALSuperClusterAlgo.h
index 4e3558e89fe90..b311b99333ad8 100644
--- a/RecoEcal/EgammaClusterAlgos/interface/PFECALSuperClusterAlgo.h
+++ b/RecoEcal/EgammaClusterAlgos/interface/PFECALSuperClusterAlgo.h
@@ -13,11 +13,22 @@
#include "DataFormats/EgammaReco/interface/BasicCluster.h"
#include "DataFormats/EgammaReco/interface/BasicClusterFwd.h"
+#include "DataFormats/EcalDetId/interface/EBDetId.h"
+#include "DataFormats/EcalDetId/interface/EEDetId.h"
+#include "DataFormats/CaloRecHit/interface/CaloCluster.h"
#include "DataFormats/EcalRecHit/interface/EcalRecHitCollections.h"
+#include "Geometry/CaloTopology/interface/CaloTopology.h"
+#include "Geometry/CaloTopology/interface/CaloSubdetectorTopology.h"
+#include "Geometry/Records/interface/CaloTopologyRecord.h"
+#include "Geometry/CaloGeometry/interface/CaloGeometry.h"
+#include "Geometry/CaloGeometry/interface/CaloSubdetectorGeometry.h"
+
#include "RecoParticleFlow/PFClusterTools/interface/PFEnergyCalibration.h"
#include "RecoEcal/EgammaClusterAlgos/interface/SCEnergyCorrectorSemiParm.h"
+#include "RecoEcal/EgammaCoreTools/interface/EcalClustersGraph.h"
+#include "RecoEcal/EgammaCoreTools/interface/CalibratedPFCluster.h"
#include "FWCore/Framework/interface/Event.h"
#include "FWCore/Framework/interface/ESHandle.h"
@@ -37,6 +48,8 @@
#include "CondFormats/EcalObjects/interface/EcalSCDynamicDPhiParameters.h"
#include "CondFormats/DataRecord/interface/EcalSCDynamicDPhiParametersRcd.h"
+#include "RecoEcal/EgammaCoreTools/interface/SCProducerCache.h"
+
#include
#include
@@ -48,31 +61,16 @@
\date July 2012
*/
+typedef std::shared_ptr CalibratedClusterPtr;
+typedef std::vector CalibratedClusterPtrVector;
+
class PFECALSuperClusterAlgo {
public:
- enum clustering_type { kBOX = 1, kMustache = 2 };
+ enum clustering_type { kBOX = 1, kMustache = 2, kDeepSC = 3 };
enum energy_weight { kRaw, kCalibratedNoPS, kCalibratedTotal };
- // simple class for associating calibrated energies
- class CalibratedPFCluster {
- public:
- CalibratedPFCluster(const edm::Ptr& p) : cluptr(p) {}
-
- double energy() const { return cluptr->correctedEnergy(); }
- double energy_nocalib() const { return cluptr->energy(); }
- double eta() const { return cluptr->positionREP().eta(); }
- double phi() const { return cluptr->positionREP().phi(); }
-
- edm::Ptr the_ptr() const { return cluptr; }
-
- private:
- edm::Ptr cluptr;
- };
- typedef std::shared_ptr CalibratedClusterPtr;
- typedef std::vector CalibratedClusterPtrVector;
-
/// constructor
- PFECALSuperClusterAlgo();
+ PFECALSuperClusterAlgo(const reco::SCProducerCache* cache);
void setVerbosityLevel(bool verbose) { verbose_ = verbose; }
@@ -110,6 +108,7 @@ class PFECALSuperClusterAlgo {
void setCrackCorrections(bool applyCrackCorrections) { applyCrackCorrections_ = applyCrackCorrections; }
void setTokens(const edm::ParameterSet&, edm::ConsumesCollector&&);
+
void update(const edm::EventSetup&);
void updateSCParams(const edm::EventSetup&);
@@ -129,9 +128,17 @@ class PFECALSuperClusterAlgo {
edm::ESGetToken esChannelStatusToken_;
edm::ESGetToken ecalMustacheSCParametersToken_;
edm::ESGetToken ecalSCDynamicDPhiParametersToken_;
+ edm::ESGetToken caloTopologyToken_;
+ edm::ESGetToken caloGeometryToken_;
const reco::BeamSpot* beamSpot_;
const ESChannelStatus* channelStatus_;
+ const CaloGeometry* geometry_;
+ const CaloSubdetectorGeometry* ebGeom_;
+ const CaloSubdetectorGeometry* eeGeom_;
+ const CaloSubdetectorGeometry* esGeom_;
+ const CaloTopology* topology_;
+
const EcalMustacheSCParameters* mustacheSCParams_;
const EcalSCDynamicDPhiParameters* scDynamicDPhiParams_;
@@ -144,7 +151,10 @@ class PFECALSuperClusterAlgo {
clustering_type _clustype;
energy_weight _eweight;
void buildAllSuperClusters(CalibratedClusterPtrVector&, double seedthresh);
- void buildSuperCluster(CalibratedClusterPtr&, CalibratedClusterPtrVector&);
+ void buildAllSuperClustersMustacheOrBox(CalibratedClusterPtrVector&, double seedthresh);
+ void buildAllSuperClustersDeepSC(CalibratedClusterPtrVector&, double seedthresh);
+ void buildSuperClusterMustacheOrBox(CalibratedClusterPtr&, CalibratedClusterPtrVector&);
+ void finalizeSuperCluster(CalibratedClusterPtr& seed, CalibratedClusterPtrVector& clustered, bool isEE);
bool verbose_;
@@ -173,6 +183,8 @@ class PFECALSuperClusterAlgo {
bool applyCrackCorrections_;
bool threshIsET_;
+ const reco::SCProducerCache* SCProducerCache_;
+
// OOT photons
bool isOOTCollection_;
edm::EDGetTokenT inputTagBarrelRecHits_;
diff --git a/RecoEcal/EgammaClusterAlgos/src/PFECALSuperClusterAlgo.cc b/RecoEcal/EgammaClusterAlgos/src/PFECALSuperClusterAlgo.cc
index 92b0ee63e7f6d..15c7a82c9325f 100644
--- a/RecoEcal/EgammaClusterAlgos/src/PFECALSuperClusterAlgo.cc
+++ b/RecoEcal/EgammaClusterAlgos/src/PFECALSuperClusterAlgo.cc
@@ -1,8 +1,11 @@
#include "RecoEcal/EgammaClusterAlgos/interface/PFECALSuperClusterAlgo.h"
+#include "RecoEcal/EgammaCoreTools/interface/EcalClustersGraph.h"
#include "CommonTools/ParticleFlow/interface/PFClusterWidthAlgo.h"
#include "RecoParticleFlow/PFClusterTools/interface/LinkByRecHit.h"
#include "DataFormats/ParticleFlowReco/interface/PFLayer.h"
#include "DataFormats/ParticleFlowReco/interface/PFRecHit.h"
+#include "DataFormats/EcalDetId/interface/EBDetId.h"
+#include "DataFormats/EcalDetId/interface/EEDetId.h"
#include "DataFormats/EcalDetId/interface/ESDetId.h"
#include "DataFormats/HcalDetId/interface/HcalDetId.h"
#include "RecoEcal/EgammaCoreTools/interface/Mustache.h"
@@ -26,8 +29,6 @@ namespace {
typedef edm::View PFClusterView;
typedef edm::Ptr PFClusterPtr;
typedef edm::PtrVector PFClusterPtrVector;
- typedef PFECALSuperClusterAlgo::CalibratedClusterPtr CalibClusterPtr;
- typedef PFECALSuperClusterAlgo::CalibratedClusterPtrVector CalibClusterPtrVector;
typedef std::pair EEPSPair;
bool sortByKey(const EEPSPair& a, const EEPSPair& b) { return a.first < b.first; }
@@ -37,23 +38,23 @@ namespace {
return energy * std::sqrt(v.perp2() / v.mag2());
}
- bool greaterByEt(const CalibClusterPtr& x, const CalibClusterPtr& y) {
+ bool greaterByEt(const CalibratedClusterPtr& x, const CalibratedClusterPtr& y) {
const math::XYZPoint zero(0, 0, 0);
- const double xpt = ptFast(x->energy(), x->the_ptr()->position(), zero);
- const double ypt = ptFast(y->energy(), y->the_ptr()->position(), zero);
+ const double xpt = ptFast(x->energy(), x->ptr()->position(), zero);
+ const double ypt = ptFast(y->energy(), y->ptr()->position(), zero);
return xpt > ypt;
}
- bool isSeed(const CalibClusterPtr& x, double threshold, bool useETcut) {
+ bool isSeed(const CalibratedClusterPtr& x, double threshold, bool useETcut) {
const math::XYZPoint zero(0, 0, 0);
double e_or_et = x->energy();
if (useETcut)
- e_or_et = ptFast(e_or_et, x->the_ptr()->position(), zero);
+ e_or_et = ptFast(e_or_et, x->ptr()->position(), zero);
return e_or_et > threshold;
}
- bool isLinkedByRecHit(const CalibClusterPtr& x,
- const CalibClusterPtr& seed,
+ bool isLinkedByRecHit(const CalibratedClusterPtr& x,
+ const CalibratedClusterPtr& seed,
const double threshold,
const double majority,
const double maxDEta,
@@ -67,8 +68,8 @@ namespace {
return false;
}
// now see if the clusters overlap in rechits
- const auto& seedHitsAndFractions = seed->the_ptr()->hitsAndFractions();
- const auto& xHitsAndFractions = x->the_ptr()->hitsAndFractions();
+ const auto& seedHitsAndFractions = seed->ptr()->hitsAndFractions();
+ const auto& xHitsAndFractions = x->ptr()->hitsAndFractions();
double x_rechits_tot = xHitsAndFractions.size();
double x_rechits_match = 0.0;
for (const std::pair& seedHit : seedHitsAndFractions) {
@@ -81,8 +82,8 @@ namespace {
return x_rechits_match / x_rechits_tot > majority;
}
- bool isClustered(const CalibClusterPtr& x,
- const CalibClusterPtr seed,
+ bool isClustered(const CalibratedClusterPtr& x,
+ const CalibratedClusterPtr seed,
const PFECALSuperClusterAlgo::clustering_type type,
const EcalMustacheSCParameters* mustache_params,
const EcalSCDynamicDPhiParameters* dynamic_dphi_params,
@@ -107,14 +108,15 @@ namespace {
} // namespace
-PFECALSuperClusterAlgo::PFECALSuperClusterAlgo() : beamSpot_(nullptr) {}
+PFECALSuperClusterAlgo::PFECALSuperClusterAlgo(const reco::SCProducerCache* cache)
+ : beamSpot_(nullptr), SCProducerCache_(cache) {}
void PFECALSuperClusterAlgo::setPFClusterCalibration(const std::shared_ptr& calib) {
_pfEnergyCalibration = calib;
}
void PFECALSuperClusterAlgo::setTokens(const edm::ParameterSet& iConfig, edm::ConsumesCollector&& cc) {
- inputTagPFClusters_ = cc.consumes >(iConfig.getParameter("PFClusters"));
+ inputTagPFClusters_ = cc.consumes>(iConfig.getParameter("PFClusters"));
inputTagPFClustersES_ =
cc.consumes(iConfig.getParameter("ESAssociation"));
inputTagBeamSpot_ = cc.consumes(iConfig.getParameter("BeamSpot"));
@@ -137,10 +139,14 @@ void PFECALSuperClusterAlgo::setTokens(const edm::ParameterSet& iConfig, edm::Co
regr_->setTokens(regconf, cc);
}
- if (isOOTCollection_) { // OOT photons only
+ if (isOOTCollection_ || _clustype == PFECALSuperClusterAlgo::kDeepSC) { // OOT photons and DeepSC uses rechits
inputTagBarrelRecHits_ = cc.consumes(iConfig.getParameter("barrelRecHits"));
inputTagEndcapRecHits_ = cc.consumes(iConfig.getParameter("endcapRecHits"));
}
+ if (_clustype == PFECALSuperClusterAlgo::kDeepSC) { // DeepSC uses geometry also
+ caloTopologyToken_ = cc.esConsumes();
+ caloGeometryToken_ = cc.esConsumes();
+ }
}
void PFECALSuperClusterAlgo::update(const edm::EventSetup& setup) {
@@ -153,6 +159,17 @@ void PFECALSuperClusterAlgo::update(const edm::EventSetup& setup) {
edm::ESHandle esChannelStatusHandle_ = setup.getHandle(esChannelStatusToken_);
channelStatus_ = esChannelStatusHandle_.product();
+
+ if (_clustype == PFECALSuperClusterAlgo::kDeepSC) { // DeepSC uses geometry
+ edm::ESHandle caloGeometryHandle_ = setup.getHandle(caloGeometryToken_);
+ geometry_ = caloGeometryHandle_.product();
+ ebGeom_ = caloGeometryHandle_->getSubdetectorGeometry(DetId::Ecal, EcalBarrel);
+ eeGeom_ = caloGeometryHandle_->getSubdetectorGeometry(DetId::Ecal, EcalEndcap);
+ esGeom_ = caloGeometryHandle_->getSubdetectorGeometry(DetId::Ecal, EcalPreshower);
+
+ edm::ESHandle caloTopologyHandle_ = setup.getHandle(caloTopologyToken_);
+ topology_ = caloTopologyHandle_.product();
+ }
}
void PFECALSuperClusterAlgo::updateSCParams(const edm::EventSetup& setup) {
@@ -167,7 +184,7 @@ void PFECALSuperClusterAlgo::updateSCParams(const edm::EventSetup& setup) {
void PFECALSuperClusterAlgo::loadAndSortPFClusters(const edm::Event& iEvent) {
//load input collections
//Load the pfcluster collections
- edm::Handle > pfclustersHandle;
+ edm::Handle> pfclustersHandle;
iEvent.getByToken(inputTagPFClusters_, pfclustersHandle);
edm::Handle psAssociationHandle;
@@ -196,7 +213,7 @@ void PFECALSuperClusterAlgo::loadAndSortPFClusters(const edm::Event& iEvent) {
//Select PF clusters available for the clustering
for (size_t i = 0; i < clusters.size(); ++i) {
auto cluster = clusters.ptrAt(i);
- LogDebug("PFClustering") << "Loading PFCluster i=" << cluster.key() << " energy=" << cluster->energy() << std::endl;
+ LogDebug("PFClustering") << "Loading PFCluster i=" << cluster.key() << " energy=" << cluster->energy();
// protection for sim clusters
if (cluster->caloID().detectors() == 0 && cluster->hitsAndFractions().empty())
@@ -224,13 +241,13 @@ void PFECALSuperClusterAlgo::loadAndSortPFClusters(const edm::Event& iEvent) {
std::sort(_clustersEB.begin(), _clustersEB.end(), greaterByEt);
std::sort(_clustersEE.begin(), _clustersEE.end(), greaterByEt);
- // set recHit collections for OOT photons
- if (isOOTCollection_) {
+ // set recHit collections for OOT photons and DeepSC
+ if (isOOTCollection_ || _clustype == PFECALSuperClusterAlgo::kDeepSC) {
edm::Handle barrelRecHitsHandle;
iEvent.getByToken(inputTagBarrelRecHits_, barrelRecHitsHandle);
if (!barrelRecHitsHandle.isValid()) {
throw cms::Exception("PFECALSuperClusterAlgo")
- << "If you use OOT photons, need to specify proper barrel rec hit collection";
+ << "If you use OOT photons or DeepSC, need to specify proper barrel rec hit collection";
}
barrelRecHits_ = barrelRecHitsHandle.product();
@@ -238,7 +255,7 @@ void PFECALSuperClusterAlgo::loadAndSortPFClusters(const edm::Event& iEvent) {
iEvent.getByToken(inputTagEndcapRecHits_, endcapRecHitsHandle);
if (!endcapRecHitsHandle.isValid()) {
throw cms::Exception("PFECALSuperClusterAlgo")
- << "If you use OOT photons, need to specify proper endcap rec hit collection";
+ << "If you use OOT photons or DeepSC, need to specify proper endcap rec hit collection";
}
endcapRecHits_ = endcapRecHitsHandle.product();
}
@@ -251,24 +268,70 @@ void PFECALSuperClusterAlgo::run() {
buildAllSuperClusters(_clustersEE, threshPFClusterSeedEndcap_);
}
-void PFECALSuperClusterAlgo::buildAllSuperClusters(CalibClusterPtrVector& clusters, double seedthresh) {
+void PFECALSuperClusterAlgo::buildAllSuperClusters(CalibratedClusterPtrVector& clusters, double seedthresh) {
+ if (_clustype == PFECALSuperClusterAlgo::kMustache || _clustype == PFECALSuperClusterAlgo::kBOX)
+ buildAllSuperClustersMustacheOrBox(clusters, seedthresh);
+ else if (_clustype == PFECALSuperClusterAlgo::kDeepSC)
+ buildAllSuperClustersDeepSC(clusters, seedthresh);
+}
+
+void PFECALSuperClusterAlgo::buildAllSuperClustersMustacheOrBox(CalibratedClusterPtrVector& clusters,
+ double seedthresh) {
auto seedable = std::bind(isSeed, _1, seedthresh, threshIsET_);
+
// make sure only seeds appear at the front of the list of clusters
std::stable_partition(clusters.begin(), clusters.end(), seedable);
+
// in each iteration we are working on a list that is already sorted
// in the cluster energy and remains so through each iteration
// NB: since clusters is sorted in loadClusters any_of has O(1)
// timing until you run out of seeds!
while (std::any_of(clusters.cbegin(), clusters.cend(), seedable)) {
- buildSuperCluster(clusters.front(), clusters);
+ buildSuperClusterMustacheOrBox(clusters.front(), clusters);
}
}
-void PFECALSuperClusterAlgo::buildSuperCluster(CalibClusterPtr& seed, CalibClusterPtrVector& clusters) {
+void PFECALSuperClusterAlgo::buildAllSuperClustersDeepSC(CalibratedClusterPtrVector& clusters, double seedthresh) {
+ auto seedable = std::bind(isSeed, _1, seedthresh, threshIsET_);
+ // EcalClustersGraph utility class for DeepSC algorithm application
+ // make sure only seeds appear at the front of the list of clusters
+ auto last_seed = std::stable_partition(clusters.begin(), clusters.end(), seedable);
+
+ reco::EcalClustersGraph ecalClusterGraph_{clusters,
+ static_cast(std::distance(clusters.begin(), last_seed)),
+ topology_,
+ ebGeom_,
+ eeGeom_,
+ barrelRecHits_,
+ endcapRecHits_,
+ SCProducerCache_};
+ // Build sub-regions of the detector where the DeepSC algo will be run
+ ecalClusterGraph_.initWindows();
+ // For each sub-region, prepare the DeepSC input tensors
+ ecalClusterGraph_.fillVariables();
+ // Evaluate the DeepSC algorithm and save the scores
+ ecalClusterGraph_.evaluateScores();
+ // Select the final SuperCluster using the CollectionStrategy defined in the cfi
+ ecalClusterGraph_.setThresholds();
+ ecalClusterGraph_.selectClusters();
+ // Extract the final SuperCluster collection
+ reco::EcalClustersGraph::EcalGraphOutput windows = ecalClusterGraph_.getGraphOutput();
+ for (auto& [seed, clustered] : windows) {
+ bool isEE = false;
+ if (seed->ptr()->layer() == PFLayer::ECAL_ENDCAP)
+ isEE = true;
+ finalizeSuperCluster(seed, clustered, isEE);
+ }
+}
+
+void PFECALSuperClusterAlgo::buildSuperClusterMustacheOrBox(CalibratedClusterPtr& seed,
+ CalibratedClusterPtrVector& clusters) {
+ CalibratedClusterPtrVector clustered;
+
double etawidthSuperCluster = 0.0;
double phiwidthSuperCluster = 0.0;
bool isEE = false;
- switch (seed->the_ptr()->layer()) {
+ switch (seed->ptr()->layer()) {
case PFLayer::ECAL_BARREL:
phiwidthSuperCluster = phiwidthSuperClusterBarrel_;
etawidthSuperCluster = etawidthSuperClusterBarrel_;
@@ -286,6 +349,7 @@ void PFECALSuperClusterAlgo::buildSuperCluster(CalibClusterPtr& seed, CalibClust
default:
break;
}
+
auto isClusteredWithSeed = std::bind(isClustered,
_1,
seed,
@@ -295,6 +359,7 @@ void PFECALSuperClusterAlgo::buildSuperCluster(CalibClusterPtr& seed, CalibClust
useDynamicDPhi_,
etawidthSuperCluster,
phiwidthSuperCluster);
+
auto matchesSeedByRecHit = std::bind(isLinkedByRecHit, _1, seed, satelliteThreshold_, fractionForMajority_, 0.1, 0.2);
// this function shuffles the list of clusters into a list
@@ -337,28 +402,37 @@ void PFECALSuperClusterAlgo::buildSuperCluster(CalibClusterPtr& seed, CalibClust
// move the clustered clusters out of available cluster list
// and into a temporary vector for building the SC
- CalibratedClusterPtrVector clustered(clusters.begin(), not_clustered);
+ CalibratedClusterPtrVector clustered_tmp(clusters.begin(), not_clustered);
+ clustered = clustered_tmp;
clusters.erase(clusters.begin(), not_clustered);
+
+ // Finalize the SuperCluster passing the list of clustered clusters
+ finalizeSuperCluster(seed, clustered, isEE);
+}
+
+void PFECALSuperClusterAlgo::finalizeSuperCluster(CalibratedClusterPtr& seed,
+ CalibratedClusterPtrVector& clustered,
+ bool isEE) {
// need the vector of raw pointers for a PF width class
std::vector bare_ptrs;
// calculate necessary parameters and build the SC
double posX(0), posY(0), posZ(0), corrSCEnergy(0), corrPS1Energy(0), corrPS2Energy(0), energyweight(0),
energyweighttot(0);
- for (auto& clus : clustered) {
+ for (const auto& clus : clustered) {
double ePS1 = 0.0;
double ePS2 = 0.0;
energyweight = clus->energy_nocalib();
- bare_ptrs.push_back(clus->the_ptr().get());
+ bare_ptrs.push_back(clus->ptr().get());
// update EE calibrated super cluster energies
if (isEE) {
- auto ee_key_val = std::make_pair(clus->the_ptr().key(), edm::Ptr());
+ auto ee_key_val = std::make_pair(clus->ptr().key(), edm::Ptr());
const auto clustops = std::equal_range(EEtoPS_->begin(), EEtoPS_->end(), ee_key_val, sortByKey);
std::vector psClusterPointers;
for (auto i_ps = clustops.first; i_ps != clustops.second; ++i_ps) {
psClusterPointers.push_back(i_ps->second.get());
}
auto calibratedEnergies = _pfEnergyCalibration->calibrateEndcapClusterEnergies(
- *(clus->the_ptr()), psClusterPointers, *channelStatus_, applyCrackCorrections_);
+ *(clus->ptr()), psClusterPointers, *channelStatus_, applyCrackCorrections_);
ePS1 = calibratedEnergies.ps1Energy;
ePS2 = calibratedEnergies.ps2Energy;
}
@@ -380,7 +454,7 @@ void PFECALSuperClusterAlgo::buildSuperCluster(CalibClusterPtr& seed, CalibClust
default:
break;
}
- const math::XYZPoint& cluspos = clus->the_ptr()->position();
+ const math::XYZPoint& cluspos = clus->ptr()->position();
posX += energyweight * cluspos.X();
posY += energyweight * cluspos.Y();
posZ += energyweight * cluspos.Z();
@@ -397,19 +471,19 @@ void PFECALSuperClusterAlgo::buildSuperCluster(CalibClusterPtr& seed, CalibClust
// now build the supercluster
reco::SuperCluster new_sc(corrSCEnergy, math::XYZPoint(posX, posY, posZ));
new_sc.setCorrectedEnergy(corrSCEnergy);
- new_sc.setSeed(clustered.front()->the_ptr());
+ new_sc.setSeed(clustered.front()->ptr());
new_sc.setPreshowerEnergy(corrPS1Energy + corrPS2Energy);
new_sc.setPreshowerEnergyPlane1(corrPS1Energy);
new_sc.setPreshowerEnergyPlane2(corrPS2Energy);
for (const auto& clus : clustered) {
- new_sc.addCluster(clus->the_ptr());
+ new_sc.addCluster(clus->ptr());
- auto& hits_and_fractions = clus->the_ptr()->hitsAndFractions();
+ auto& hits_and_fractions = clus->ptr()->hitsAndFractions();
for (auto& hit_and_fraction : hits_and_fractions) {
new_sc.addHitAndFraction(hit_and_fraction.first, hit_and_fraction.second);
}
if (isEE) {
- auto ee_key_val = std::make_pair(clus->the_ptr().key(), edm::Ptr());
+ auto ee_key_val = std::make_pair(clus->ptr().key(), edm::Ptr());
const auto clustops = std::equal_range(EEtoPS_->begin(), EEtoPS_->end(), ee_key_val, sortByKey);
// EE rechits should be uniquely matched to sets of pre-shower
// clusters at this point, so we throw an exception if otherwise
@@ -456,7 +530,7 @@ void PFECALSuperClusterAlgo::buildSuperCluster(CalibClusterPtr& seed, CalibClust
double scEtBS = ptFast(new_sc.energy(), new_sc.position(), beamSpot_->position());
if (scEtBS > threshSuperClusterEt_) {
- switch (seed->the_ptr()->layer()) {
+ switch (seed->ptr()->layer()) {
case PFLayer::ECAL_BARREL:
if (isOOTCollection_) {
DetId seedId = new_sc.seed()->seed();
diff --git a/RecoEcal/EgammaClusterProducers/python/particleFlowSuperClusterECAL_cfi.py b/RecoEcal/EgammaClusterProducers/python/particleFlowSuperClusterECAL_cfi.py
index 2c81cf48e0e4f..e15dda00ca50a 100644
--- a/RecoEcal/EgammaClusterProducers/python/particleFlowSuperClusterECAL_cfi.py
+++ b/RecoEcal/EgammaClusterProducers/python/particleFlowSuperClusterECAL_cfi.py
@@ -1,10 +1,22 @@
import FWCore.ParameterSet.Config as cms
from RecoEcal.EgammaClusterProducers.particleFlowSuperClusterECALMustache_cfi import particleFlowSuperClusterECALMustache as _particleFlowSuperClusterECALMustache
-
-# define the default ECAL clustering (Mustache or Box)
+# define the default ECAL clustering (Mustache or Box or DeepSC)
particleFlowSuperClusterECAL = _particleFlowSuperClusterECALMustache.clone()
+from Configuration.ProcessModifiers.ecal_deepsc_cff import ecal_deepsc
+_particleFlowSuperClusterECALDeepSC = _particleFlowSuperClusterECALMustache.clone(
+ ClusteringType = "DeepSC",
+ deepSuperClusterConfig = cms.PSet(
+ modelFile = cms.string("RecoEcal/EgammaClusterProducers/data/DeepSCModels/EOY_2018/model.pb"),
+ configFileClusterFeatures = cms.string("RecoEcal/EgammaClusterProducers/data/DeepSCModels/EOY_2018/config_clusters_inputs.txt"),
+ configFileWindowFeatures = cms.string("RecoEcal/EgammaClusterProducers/data/DeepSCModels/EOY_2018/config_window_inputs.txt"),
+ configFileHitsFeatures = cms.string("RecoEcal/EgammaClusterProducers/data/DeepSCModels/EOY_2018/config_hits_inputs.txt"),
+ collectionStrategy = cms.string("Cascade")
+ )
+)
+ecal_deepsc.toReplaceWith(particleFlowSuperClusterECAL, _particleFlowSuperClusterECALDeepSC)
+
from Configuration.ProcessModifiers.pp_on_AA_cff import pp_on_AA
pp_on_AA.toModify(particleFlowSuperClusterECAL, useDynamicDPhiWindow = False,
phiwidth_SuperClusterBarrel = 0.20,
@@ -15,3 +27,4 @@
thresh_SCEt = 1.0,
thresh_PFClusterSeedBarrel = 0.5,
thresh_PFClusterSeedEndcap = 0.5)
+
diff --git a/RecoEcal/EgammaClusterProducers/python/particleFlowSuperClusteringSequence_cff.py b/RecoEcal/EgammaClusterProducers/python/particleFlowSuperClusteringSequence_cff.py
index cc9c95c3780ac..53ddabd9cdf1e 100644
--- a/RecoEcal/EgammaClusterProducers/python/particleFlowSuperClusteringSequence_cff.py
+++ b/RecoEcal/EgammaClusterProducers/python/particleFlowSuperClusteringSequence_cff.py
@@ -35,4 +35,3 @@
_phase2_hgcal_particleFlowSuperClusteringTask.add(particleFlowSuperClusterHGCal)
phase2_hgcal.toReplaceWith( particleFlowSuperClusteringTask, _phase2_hgcal_particleFlowSuperClusteringTask )
-
diff --git a/RecoEcal/EgammaClusterProducers/src/PFECALSuperClusterProducer.cc b/RecoEcal/EgammaClusterProducers/src/PFECALSuperClusterProducer.cc
index 83f8440cd3b7e..92a7e7bc435b4 100644
--- a/RecoEcal/EgammaClusterProducers/src/PFECALSuperClusterProducer.cc
+++ b/RecoEcal/EgammaClusterProducers/src/PFECALSuperClusterProducer.cc
@@ -1,9 +1,3 @@
-/**\class PFECALSuperClusterProducer
-
-\author Nicolas Chanon
-Additional authors for Mustache: Y. Gershtein, R. Patel, L. Gray
-\date July 2012
-*/
#include "CondFormats/DataRecord/interface/GBRWrapperRcd.h"
#include "CondFormats/GBRForest/interface/GBRForest.h"
@@ -30,25 +24,41 @@ Additional authors for Mustache: Y. Gershtein, R. Patel, L. Gray
#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
#include "FWCore/ParameterSet/interface/ParameterSet.h"
#include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
+#include "FWCore/ParameterSet/interface/EmptyGroupDescription.h"
#include "Geometry/CaloTopology/interface/CaloTopology.h"
#include "Geometry/Records/interface/CaloTopologyRecord.h"
#include "RecoEcal/EgammaClusterAlgos/interface/PFECALSuperClusterAlgo.h"
#include "RecoEcal/EgammaClusterAlgos/interface/SCEnergyCorrectorSemiParm.h"
#include "RecoEcal/EgammaCoreTools/interface/EcalClusterTools.h"
-
+#include "RecoEcal/EgammaCoreTools/interface/SCProducerCache.h"
#include "TVector2.h"
#include
#include
-class PFECALSuperClusterProducer : public edm::stream::EDProducer<> {
+/*
+ * class PFECALSuperClusterProducer
+ * author Nicolas Chanon
+ * Additional authors for Mustache: Y. Gershtein, R. Patel, L. Gray
+ * Additional authors for DeepSC: D.Valsecchi, B.Marzocchi
+ * date July 2012
+ * updates Feb 2022
+ */
+
+class PFECALSuperClusterProducer : public edm::stream::EDProducer> {
public:
- explicit PFECALSuperClusterProducer(const edm::ParameterSet&);
+ explicit PFECALSuperClusterProducer(const edm::ParameterSet&, const reco::SCProducerCache* gcache);
~PFECALSuperClusterProducer() override;
void beginLuminosityBlock(const edm::LuminosityBlock&, const edm::EventSetup&) override;
void produce(edm::Event&, const edm::EventSetup&) override;
+ static std::unique_ptr initializeGlobalCache(const edm::ParameterSet& config) {
+ return std::make_unique(config);
+ }
+
+ static void globalEndJob(const reco::SCProducerCache*){};
+
static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
private:
@@ -81,18 +91,22 @@ class PFECALSuperClusterProducer : public edm::stream::EDProducer<> {
DEFINE_FWK_MODULE(PFECALSuperClusterProducer);
using namespace std;
+
using namespace edm;
namespace {
const std::string ClusterType__BOX("Box");
const std::string ClusterType__Mustache("Mustache");
+ const std::string ClusterType__DeepSC("DeepSC");
const std::string EnergyWeight__Raw("Raw");
const std::string EnergyWeight__CalibratedNoPS("CalibratedNoPS");
const std::string EnergyWeight__CalibratedTotal("CalibratedTotal");
} // namespace
-PFECALSuperClusterProducer::PFECALSuperClusterProducer(const edm::ParameterSet& iConfig) {
+PFECALSuperClusterProducer::PFECALSuperClusterProducer(const edm::ParameterSet& iConfig,
+ const reco::SCProducerCache* gcache)
+ : superClusterAlgo_(gcache) {
verbose_ = iConfig.getUntrackedParameter("verbose", false);
superClusterAlgo_.setUseRegression(iConfig.getParameter("useRegression"));
@@ -105,14 +119,12 @@ PFECALSuperClusterProducer::PFECALSuperClusterProducer(const edm::ParameterSet&
_theclusteringtype = PFECALSuperClusterAlgo::kBOX;
} else if (_typename == ClusterType__Mustache) {
_theclusteringtype = PFECALSuperClusterAlgo::kMustache;
+ } else if (_typename == ClusterType__DeepSC) {
+ _theclusteringtype = PFECALSuperClusterAlgo::kDeepSC;
} else {
throw cms::Exception("InvalidClusteringType") << "You have not chosen a valid clustering type,"
- << " please choose from \"Box\" or \"Mustache\"!";
+ << " please choose from \"Box\" or \"Mustache\" or \"DeepSC\"!";
}
- superClusterAlgo_.setClusteringType(_theclusteringtype);
- superClusterAlgo_.setUseDynamicDPhi(iConfig.getParameter("useDynamicDPhiWindow"));
- // clusteringType and useDynamicDPhi need to be defined before setting the tokens in order to esConsume only the necessary records
- superClusterAlgo_.setTokens(iConfig, consumesCollector());
std::string _weightname = iConfig.getParameter("EnergyWeight");
if (_weightname == EnergyWeight__Raw) {
@@ -130,6 +142,8 @@ PFECALSuperClusterProducer::PFECALSuperClusterProducer(const edm::ParameterSet&
// parameters for clustering
bool seedThresholdIsET = iConfig.getParameter("seedThresholdIsET");
+ bool useDynamicDPhi = iConfig.getParameter("useDynamicDPhiWindow");
+
double threshPFClusterSeedBarrel = iConfig.getParameter("thresh_PFClusterSeedBarrel");
double threshPFClusterBarrel = iConfig.getParameter("thresh_PFClusterBarrel");
@@ -147,6 +161,11 @@ PFECALSuperClusterProducer::PFECALSuperClusterProducer(const edm::ParameterSet&
double satelliteMajorityFraction = iConfig.getParameter("satelliteMajorityFraction");
bool dropUnseedable = iConfig.getParameter("dropUnseedable");
+ superClusterAlgo_.setClusteringType(_theclusteringtype);
+ superClusterAlgo_.setUseDynamicDPhi(useDynamicDPhi);
+ // clusteringType and useDynamicDPhi need to be defined before setting the tokens in order to esConsume only the necessary records
+ superClusterAlgo_.setTokens(iConfig, consumesCollector());
+
superClusterAlgo_.setVerbosityLevel(verbose_);
superClusterAlgo_.setEnergyWeighting(_theenergyweight);
superClusterAlgo_.setUseETForSeeding(seedThresholdIsET);
@@ -354,7 +373,6 @@ void PFECALSuperClusterProducer::fillDescriptions(edm::ConfigurationDescriptions
desc.add("PFBasicClusterCollectionEndcap", "particleFlowBasicClusterECALEndcap");
desc.add("PFClusters", edm::InputTag("particleFlowClusterECAL"));
desc.add("thresh_PFClusterSeedBarrel", 1.0);
- desc.add("ClusteringType", "Mustache");
desc.add("EnergyWeight", "Raw");
desc.add("BeamSpot", edm::InputTag("offlineBeamSpot"));
desc.add("thresh_PFClusterSeedEndcap", 1.0);
@@ -367,5 +385,29 @@ void PFECALSuperClusterProducer::fillDescriptions(edm::ConfigurationDescriptions
desc.add("PFSuperClusterCollectionEndcapWithPreshower",
"particleFlowSuperClusterECALEndcapWithPreshower");
desc.add("dropUnseedable", false);
+
+ edm::ParameterSetDescription deepSCParams;
+ deepSCParams.add("modelFile", "");
+ deepSCParams.add("configFileClusterFeatures", "");
+ deepSCParams.add("configFileWindowFeatures", "");
+ deepSCParams.add("configFileHitsFeatures", "");
+ deepSCParams.add("nClusterFeatures", 12);
+ deepSCParams.add("nWindowFeatures", 18);
+ deepSCParams.add("nHitsFeatures", 4);
+ deepSCParams.add("maxNClusters", 40);
+ deepSCParams.add("maxNRechits", 40);
+ deepSCParams.add("batchSize", 64);
+ deepSCParams.add("collectionStrategy", "Cascade");
+
+ EmptyGroupDescription emptyGroup;
+
+ // Add DeepSC parameters only to the specific ClusteringType
+ edm::ParameterSwitch switchNode(
+ edm::ParameterDescription("ClusteringType", ClusterType__Mustache, true),
+ ClusterType__Mustache >> emptyGroup or ClusterType__BOX >> emptyGroup or
+ ClusterType__DeepSC >>
+ edm::ParameterDescription("deepSuperClusterConfig", deepSCParams, true));
+ desc.addNode(switchNode);
+
descriptions.add("particleFlowSuperClusterECALMustache", desc);
}
diff --git a/RecoEcal/EgammaCoreTools/BuildFile.xml b/RecoEcal/EgammaCoreTools/BuildFile.xml
index 82cb929f52e52..3287680adf306 100644
--- a/RecoEcal/EgammaCoreTools/BuildFile.xml
+++ b/RecoEcal/EgammaCoreTools/BuildFile.xml
@@ -1,15 +1,21 @@
+
+
+
+
+
-
+
+
diff --git a/RecoEcal/EgammaCoreTools/interface/CalibratedPFCluster.h b/RecoEcal/EgammaCoreTools/interface/CalibratedPFCluster.h
new file mode 100644
index 0000000000000..ed38058688237
--- /dev/null
+++ b/RecoEcal/EgammaCoreTools/interface/CalibratedPFCluster.h
@@ -0,0 +1,24 @@
+#ifndef RecoEcal_EgammaCoreTools_CalibratedPFCluster_h
+#define RecoEcal_EgammaCoreTools_CalibratedPFCluster_h
+
+#include "DataFormats/ParticleFlowReco/interface/PFCluster.h"
+#include "DataFormats/ParticleFlowReco/interface/PFClusterFwd.h"
+#include "DataFormats/CaloRecHit/interface/CaloCluster.h"
+
+// simple class for associating calibrated energies
+class CalibratedPFCluster {
+public:
+ CalibratedPFCluster(const edm::Ptr& p) : ptr_(p) {}
+
+ double energy() const { return ptr_->correctedEnergy(); }
+ double energy_nocalib() const { return ptr_->energy(); }
+ double eta() const { return ptr_->positionREP().eta(); }
+ double phi() const { return ptr_->positionREP().phi(); }
+
+ edm::Ptr ptr() const { return ptr_; }
+
+private:
+ edm::Ptr ptr_;
+};
+
+#endif
diff --git a/RecoEcal/EgammaCoreTools/interface/DeepSCGraphEvaluation.h b/RecoEcal/EgammaCoreTools/interface/DeepSCGraphEvaluation.h
new file mode 100644
index 0000000000000..e93b3b70e5972
--- /dev/null
+++ b/RecoEcal/EgammaCoreTools/interface/DeepSCGraphEvaluation.h
@@ -0,0 +1,98 @@
+#ifndef RecoEcal_EgammaCoreTools_DeepSCGraphEvaluation_h
+#define RecoEcal_EgammaCoreTools_DeepSCGraphEvaluation_h
+
+#include "PhysicsTools/TensorFlow/interface/TensorFlow.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+//author: Davide Valsecchi
+//description:
+// Handles Tensorflow DNN graphs and variables scaler configuration.
+// To be used for DeepSC.
+
+namespace reco {
+
+ struct DeepSCConfiguration {
+ std::string modelFile;
+ std::string configFileClusterFeatures;
+ std::string configFileWindowFeatures;
+ std::string configFileHitsFeatures;
+ uint nClusterFeatures;
+ uint nWindowFeatures;
+ uint nHitsFeatures;
+ uint maxNClusters;
+ uint maxNRechits;
+ uint batchSize;
+ std::string collectionStrategy;
+ };
+
+ /*
+ * Structure representing the detector windows of a single events, to be evaluated with the DeepSC model.
+ * The index structure is described in the following
+ */
+
+ namespace DeepSCInputs {
+ enum ScalerType {
+ MeanRms, // scale as (var - mean)/rms
+ MinMax, // scale as (var - min) (max-min)
+ None // do nothing
+ };
+ struct InputConfig {
+ // Each input variable is represented by the tuple
+ std::string varName;
+ ScalerType type;
+ float par1;
+ float par2;
+ };
+ typedef std::vector InputConfigs;
+ typedef std::map FeaturesMap;
+
+ struct Inputs {
+ std::vector>> clustersX;
+ std::vector>>> hitsX;
+ std::vector> windowX;
+ std::vector> isSeed;
+ };
+
+ }; // namespace DeepSCInputs
+
+ class DeepSCGraphEvaluation {
+ public:
+ DeepSCGraphEvaluation(const DeepSCConfiguration&);
+ ~DeepSCGraphEvaluation();
+
+ std::vector getScaledInputs(const DeepSCInputs::FeaturesMap& variables,
+ const DeepSCInputs::InputConfigs& config) const;
+
+ std::vector> evaluate(const DeepSCInputs::Inputs& inputs) const;
+
+ // List of input variables names used to check the variables request as
+ // inputs in a dynamic way from configuration file.
+ // If an input variables is not found at construction time an expection is thrown.
+ static const std::vector availableClusterInputs;
+ static const std::vector availableWindowInputs;
+ static const std::vector availableHitsInputs;
+
+ // Configuration of the input variables including the scaling parameters.
+ // The list is used to define the vector of input features passed to the tensorflow model.
+ DeepSCInputs::InputConfigs inputFeaturesClusters;
+ DeepSCInputs::InputConfigs inputFeaturesWindows;
+ DeepSCInputs::InputConfigs inputFeaturesHits;
+
+ private:
+ void initTensorFlowGraphAndSession();
+ DeepSCInputs::InputConfigs readInputFeaturesConfig(std::string file,
+ const std::vector& availableInputs) const;
+
+ const DeepSCConfiguration cfg_;
+ std::unique_ptr graphDef_;
+ tensorflow::Session* session_;
+ };
+
+}; // namespace reco
+
+#endif
diff --git a/RecoEcal/EgammaCoreTools/interface/EcalClustersGraph.h b/RecoEcal/EgammaCoreTools/interface/EcalClustersGraph.h
new file mode 100644
index 0000000000000..5a22442fd4721
--- /dev/null
+++ b/RecoEcal/EgammaCoreTools/interface/EcalClustersGraph.h
@@ -0,0 +1,123 @@
+#ifndef RecoEcal_EgammaCoreTools_EcalClustersGraph_h
+#define RecoEcal_EgammaCoreTools_EcalClustersGraph_h
+
+/**
+ \file
+ Tools for manipulating ECAL Clusters as graphs
+ \author Davide Valsecchi, Badder Marzocchi
+ \date 05 October 2020
+*/
+
+#include
+#include
+#include
+
+#include "PhysicsTools/TensorFlow/interface/TensorFlow.h"
+#include "FWCore/Utilities/interface/isFinite.h"
+
+#include "DataFormats/CaloRecHit/interface/CaloCluster.h"
+#include "DataFormats/CaloRecHit/interface/CaloClusterFwd.h"
+#include "DataFormats/EgammaReco/interface/SuperCluster.h"
+#include "DataFormats/ParticleFlowReco/interface/PFCluster.h"
+#include "DataFormats/ParticleFlowReco/interface/PFLayer.h"
+#include "DataFormats/Math/interface/deltaPhi.h"
+
+#include "RecoEcal/EgammaCoreTools/interface/EcalClusterTools.h"
+#include "DataFormats/EcalDetId/interface/EBDetId.h"
+#include "DataFormats/EcalDetId/interface/EEDetId.h"
+
+#include "Geometry/CaloTopology/interface/CaloTopology.h"
+#include "Geometry/CaloGeometry/interface/CaloGeometry.h"
+#include "Geometry/CaloGeometry/interface/CaloSubdetectorGeometry.h"
+#include "Geometry/Records/interface/CaloTopologyRecord.h"
+#include "Geometry/CaloTopology/interface/CaloSubdetectorTopology.h"
+#include "DataFormats/GeometryVector/interface/GlobalPoint.h"
+#include "Geometry/EcalAlgo/interface/EcalBarrelGeometry.h"
+#include "Geometry/EcalAlgo/interface/EcalEndcapGeometry.h"
+
+#include "RecoEcal/EgammaCoreTools/interface/CalibratedPFCluster.h"
+#include "RecoEcal/EgammaCoreTools/interface/GraphMap.h"
+#include "RecoEcal/EgammaCoreTools/interface/SCProducerCache.h"
+
+/*
+ * class: EcalClustersGraph
+ * Authors: D.Valsecchi, B.Marzocchi
+ * Date: January 2022
+ *
+ * Utility class to handle all the PFClusters in ECAL as a graph.
+ * The DeepSC algorithm is applied on sub-graphs of clusters to form SuperCluster.
+ */
+
+namespace reco {
+
+ class EcalClustersGraph {
+ public:
+ typedef std::shared_ptr CalibratedClusterPtr;
+ typedef std::vector CalibratedClusterPtrVector;
+ typedef std::vector> EcalGraphOutput;
+
+ EcalClustersGraph(CalibratedClusterPtrVector clusters,
+ int nSeeds,
+ const CaloTopology* topology,
+ const CaloSubdetectorGeometry* ebGeom,
+ const CaloSubdetectorGeometry* eeGeom,
+ const EcalRecHitCollection* recHitsEB,
+ const EcalRecHitCollection* recHitsEE,
+ const reco::SCProducerCache* cache);
+
+ void fillVariables();
+
+ double scoreThreshold(const CaloCluster* cluster);
+ void initWindows();
+
+ void setThresholds();
+ void evaluateScores();
+ void selectClusters();
+
+ EcalGraphOutput getGraphOutput();
+
+ private:
+ std::array clusterPosition(const CaloCluster* cluster) const;
+
+ // Sign flip deltaEta as in the Mustache
+ double deltaEta(double seed_eta, double cluster_eta) const {
+ return (1 - 2 * (seed_eta < 0)) * (cluster_eta - seed_eta);
+ }
+
+ // The dEta-dPhi detector window dimension is chosen to that the algorithm is always larger than
+ // the Mustache dimension
+ std::array dynamicWindow(double seedEta) const;
+
+ DeepSCInputs::FeaturesMap computeVariables(const CaloCluster* seed, const CaloCluster* cluster) const;
+ std::vector> fillHits(const CaloCluster* cluster) const;
+ DeepSCInputs::FeaturesMap computeWindowVariables(const std::vector& clusters) const;
+
+ std::pair computeCovariances(const CaloCluster* cluster);
+ std::vector computeShowerShapes(const CaloCluster* cluster, bool full5x5);
+
+ CalibratedClusterPtrVector clusters_;
+ uint nSeeds_;
+ uint nCls_;
+
+ std::array locCov_;
+ std::pair widths_;
+
+ //To compute the input variables
+ const CaloTopology* topology_;
+ const CaloSubdetectorGeometry* ebGeom_;
+ const CaloSubdetectorGeometry* eeGeom_;
+ const EcalRecHitCollection* recHitsEB_;
+ const EcalRecHitCollection* recHitsEE_;
+ const reco::SCProducerCache* scProducerCache_;
+
+ // GraphMap for handling all the windows and scores
+ reco::GraphMap graphMap_;
+ reco::GraphMap::CollectionStrategy strategy_;
+
+ // Raw input for the tensorflow DeepSCGraphEvaluation object
+ reco::DeepSCInputs::Inputs inputs_;
+ float threshold_;
+ };
+
+} // namespace reco
+#endif
diff --git a/RecoEcal/EgammaCoreTools/interface/GraphMap.h b/RecoEcal/EgammaCoreTools/interface/GraphMap.h
new file mode 100644
index 0000000000000..9d5914ea6664b
--- /dev/null
+++ b/RecoEcal/EgammaCoreTools/interface/GraphMap.h
@@ -0,0 +1,92 @@
+#ifndef RecoEcal_EgammaCoreTools_GraphMap_h
+#define RecoEcal_EgammaCoreTools_GraphMap_h
+
+#include
+#include
+#include