From adae59871a6ed1fff4e93a9a81042d9dca6ffd75 Mon Sep 17 00:00:00 2001 From: Marco Rovere Date: Mon, 13 Dec 2021 15:04:16 +0100 Subject: [PATCH 1/5] Add Matrix workflows for CLUE3D and FastJet in TICL --- .../python/upgradeWorkflowComponents.py | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py b/Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py index 15a16ec5a3b54..7f19a94d83e75 100644 --- a/Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py +++ b/Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py @@ -381,6 +381,52 @@ def condition(self, fragment, stepList, key, hasHarvest): offset = 0.9, ) +# Special TICL Pattern recognition Workflows +class UpgradeWorkflow_ticl_clue3D(UpgradeWorkflow): + def setup_(self, step, stepName, stepDict, k, properties): + if 'RecoGlobal' in step: + stepDict[stepName][k] = merge([self.step3, stepDict[step][k]]) + if 'HARVESTGlobal' in step: + stepDict[stepName][k] = merge([self.step4, stepDict[step][k]]) + def condition(self, fragment, stepList, key, hasHarvest): + return (fragment=="TTbar_14TeV" or 'CloseByPGun_CE' in fragment) and '2026' in key +upgradeWFs['ticl_clue3D'] = UpgradeWorkflow_ticl_clue3D( + steps = [ + 'RecoGlobal', + 'HARVESTGlobal' + ], + PU = [ + 'RecoGlobal', + 'HARVESTGlobal' + ], + suffix = '_ticl_clue3D', + offset = 0.201, +) +upgradeWFs['ticl_clue3D'].step3 = {'--procModifiers': 'clue3D'} +upgradeWFs['ticl_clue3D'].step4 = {'--procModifiers': 'clue3D'} + +class UpgradeWorkflow_ticl_FastJet(UpgradeWorkflow): + def setup_(self, step, stepName, stepDict, k, properties): + if 'RecoGlobal' in step: + stepDict[stepName][k] = merge([self.step3, stepDict[step][k]]) + if 'HARVESTGlobal' in step: + stepDict[stepName][k] = merge([self.step4, stepDict[step][k]]) + def condition(self, fragment, stepList, key, hasHarvest): + return (fragment=="TTbar_14TeV" or 'CloseByPGun_CE' in fragment) and '2026' in key +upgradeWFs['ticl_FastJet'] = UpgradeWorkflow_ticl_FastJet( + steps = [ + 'RecoGlobal', + 'HARVESTGlobal' + ], + PU = [ + 'RecoGlobal', + 'HARVESTGlobal' + ], + suffix = '_ticl_FastJet', + offset = 0.202, +) +upgradeWFs['ticl_FastJet'].step3 = {'--procModifiers': 'fastJetTICL'} +upgradeWFs['ticl_FastJet'].step4 = {'--procModifiers': 'fastJetTICL'} # Track DNN workflows class UpgradeWorkflow_trackdnn(UpgradeWorkflow): From cf7f72087aaa3d044c69b17bf0f59b33fab07a27 Mon Sep 17 00:00:00 2001 From: Marco Rovere Date: Thu, 14 Oct 2021 10:14:26 +0200 Subject: [PATCH 2/5] Add FastJet as TICL Pattern Recognition plugin --- .../python/fastJetTICL_cff.py | 5 + RecoHGCal/TICL/plugins/BuildFile.xml | 1 + .../PatternRecognitionPluginFactory.cc | 2 + .../plugins/PatternRecognitionbyFastJet.cc | 329 ++++++++++++++++++ .../plugins/PatternRecognitionbyFastJet.h | 43 +++ RecoHGCal/TICL/plugins/TrackstersProducer.cc | 9 +- RecoHGCal/TICL/python/FastJetStep_cff.py | 32 ++ RecoHGCal/TICL/python/iterativeTICL_cff.py | 4 + 8 files changed, 423 insertions(+), 2 deletions(-) create mode 100644 Configuration/ProcessModifiers/python/fastJetTICL_cff.py create mode 100644 RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.cc create mode 100644 RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.h create mode 100644 RecoHGCal/TICL/python/FastJetStep_cff.py diff --git a/Configuration/ProcessModifiers/python/fastJetTICL_cff.py b/Configuration/ProcessModifiers/python/fastJetTICL_cff.py new file mode 100644 index 0000000000000..977b584061ae1 --- /dev/null +++ b/Configuration/ProcessModifiers/python/fastJetTICL_cff.py @@ -0,0 +1,5 @@ +import FWCore.ParameterSet.Config as cms + +# This modifier is for injecting CLUE3D-based iterations in TICL. + +fastJetTICL = cms.Modifier() diff --git a/RecoHGCal/TICL/plugins/BuildFile.xml b/RecoHGCal/TICL/plugins/BuildFile.xml index e23f331607ef8..8c631381e21b4 100644 --- a/RecoHGCal/TICL/plugins/BuildFile.xml +++ b/RecoHGCal/TICL/plugins/BuildFile.xml @@ -29,6 +29,7 @@ + diff --git a/RecoHGCal/TICL/plugins/PatternRecognitionPluginFactory.cc b/RecoHGCal/TICL/plugins/PatternRecognitionPluginFactory.cc index e35a6d24c91a0..ac6296db5bf3b 100644 --- a/RecoHGCal/TICL/plugins/PatternRecognitionPluginFactory.cc +++ b/RecoHGCal/TICL/plugins/PatternRecognitionPluginFactory.cc @@ -1,6 +1,7 @@ #include "RecoHGCal/TICL/plugins/PatternRecognitionPluginFactory.h" #include "PatternRecognitionbyCA.h" #include "PatternRecognitionbyCLUE3D.h" +#include "PatternRecognitionbyFastJet.h" #include "FWCore/ParameterSet/interface/ValidatedPluginFactoryMacros.h" #include "FWCore/ParameterSet/interface/ValidatedPluginMacros.h" @@ -8,4 +9,5 @@ EDM_REGISTER_VALIDATED_PLUGINFACTORY(PatternRecognitionFactory, "PatternRecognit EDM_REGISTER_VALIDATED_PLUGINFACTORY(PatternRecognitionHFNoseFactory, "PatternRecognitionHFNoseFactory"); DEFINE_EDM_VALIDATED_PLUGIN(PatternRecognitionFactory, ticl::PatternRecognitionbyCA, "CA"); DEFINE_EDM_VALIDATED_PLUGIN(PatternRecognitionFactory, ticl::PatternRecognitionbyCLUE3D, "CLUE3D"); +DEFINE_EDM_VALIDATED_PLUGIN(PatternRecognitionFactory, ticl::PatternRecognitionbyFastJet, "FastJet"); DEFINE_EDM_VALIDATED_PLUGIN(PatternRecognitionHFNoseFactory, ticl::PatternRecognitionbyCA, "CA"); diff --git a/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.cc b/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.cc new file mode 100644 index 0000000000000..00f4516416a0f --- /dev/null +++ b/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.cc @@ -0,0 +1,329 @@ +// Author: Marco Rovere - marco.rovere@cern.ch +// Date: 04/2021 +#include +#include +#include + +#include "tbb/task_arena.h" +#include "tbb/tbb.h" + +#include "DataFormats/Math/interface/deltaR.h" +#include "DataFormats/Math/interface/LorentzVector.h" +#include "DataFormats/Candidate/interface/Candidate.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "FWCore/Utilities/interface/Exception.h" +#include "PatternRecognitionbyFastJet.h" + +#include "TrackstersPCA.h" +#include "Geometry/CaloGeometry/interface/CaloGeometry.h" +#include "Geometry/Records/interface/CaloGeometryRecord.h" +#include "FWCore/Framework/interface/EventSetup.h" + +#include "fastjet/ClusterSequence.hh" + + +using namespace ticl; +using namespace fastjet; + + template +PatternRecognitionbyFastJet::PatternRecognitionbyFastJet(const edm::ParameterSet &conf, + const CacheBase *cache, + edm::ConsumesCollector iC) + : PatternRecognitionAlgoBaseT(conf, cache, iC), + caloGeomToken_(iC.esConsumes()), + minNumLayerCluster_(conf.getParameter("minNumLayerCluster")), + eidInputName_(conf.getParameter("eid_input_name")), + eidOutputNameEnergy_(conf.getParameter("eid_output_name_energy")), + eidOutputNameId_(conf.getParameter("eid_output_name_id")), + eidMinClusterEnergy_(conf.getParameter("eid_min_cluster_energy")), + eidNLayers_(conf.getParameter("eid_n_layers")), + eidNClusters_(conf.getParameter("eid_n_clusters")), + eidSession_(nullptr) { + // mount the tensorflow graph onto the session when set + const TrackstersCache *trackstersCache = dynamic_cast(cache); + if (trackstersCache == nullptr || trackstersCache->eidGraphDef == nullptr) { + throw cms::Exception("MissingGraphDef") + << "PatternRecognitionbyFastJet received an empty graph definition from the global cache"; + } + eidSession_ = tensorflow::createSession(trackstersCache->eidGraphDef); + } + +template +void PatternRecognitionbyFastJet::makeTracksters( + const typename PatternRecognitionAlgoBaseT::Inputs &input, + std::vector &result, + std::unordered_map> &seedToTracksterAssociation) { + // Protect from events with no seeding regions + if (input.regions.empty()) + return; + + edm::EventSetup const &es = input.es; + const CaloGeometry &geom = es.getData(caloGeomToken_); + rhtools_.setGeometry(geom); + + int type = input.tiles[0].typeT(); + int nEtaBin = (type == 1) ? ticl::TileConstantsHFNose::nEtaBins : ticl::TileConstants::nEtaBins; + int nPhiBin = (type == 1) ? ticl::TileConstantsHFNose::nPhiBins : ticl::TileConstants::nPhiBins; + + // We need to partition the two sides of the HGCAL detector + auto lastLayerPerSide = static_cast(rhtools_.lastLayer(false)) - 1; + unsigned int maxLayer = 2 * lastLayerPerSide - 1; + std::vector fjInputs; + fjInputs.clear(); + for (unsigned int currentLayer = 0; currentLayer <= maxLayer ; ++currentLayer) { + if (currentLayer == lastLayerPerSide) { + if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Basic) { + edm::LogVerbatim("PatternRecogntionbyFastJet") << "Creating FastJet at later " + << currentLayer + << " with " << fjInputs.size() << " LayerClusters in input"; + } + fastjet::ClusterSequence sequence(fjInputs, JetDefinition(antikt_algorithm, 0.1)); + auto jets = fastjet::sorted_by_pt(sequence.inclusive_jets(0)); + if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Basic) { + edm::LogVerbatim("PatternRecogntionbyFastJet") << "FastJet produced " + << jets.size() << " jets/trackster"; + } + + auto trackster_idx = result.size(); + result.resize(trackster_idx + jets.size()); + for (const auto &pj : jets) { + for (const auto &component : pj.constituents()) { + result[trackster_idx].vertices().push_back(component.user_index()); + result[trackster_idx].vertex_multiplicity().push_back(1); + if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Basic) { + edm::LogVerbatim("PatternRecogntionbyFastJet") << "Jet has " + << pj.constituents().size() << " components that are stored in trackster " << trackster_idx; + } + } + trackster_idx++; + } + fjInputs.clear(); + } + const auto &tileOnLayer = input.tiles[currentLayer]; + for (int ieta = 0; ieta <= nEtaBin; ++ieta) { + auto offset = ieta * nPhiBin; + if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Advanced) { + edm::LogVerbatim("PatternRecogntionbyFastJet") << "offset: " << offset; + } + for (int iphi = 0; iphi <= nPhiBin; ++iphi) { + if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Advanced) { + edm::LogVerbatim("PatternRecogntionbyFastJet") << "iphi: " << iphi; + edm::LogVerbatim("PatternRecogntionbyFastJet") + << "Entries in tileBin: " << tileOnLayer[offset + iphi].size(); + } + for (auto clusterIdx : tileOnLayer[offset + iphi]) { + // Skip masked layer clusters + if (input.mask[clusterIdx] == 0.) { + if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Advanced) { + edm::LogVerbatim("PatternRecogntionbyFastJet") << "Skipping masked layerIdx " << clusterIdx; + } + continue; + } + // Should we correct for the position of the PV? + auto const & cl = input.layerClusters[clusterIdx]; + math::XYZVector direction(cl.x(), cl.y(), cl.z()); + direction = direction.Unit(); + direction *= cl.energy(); + auto fpj = fastjet::PseudoJet(direction.X(), direction.Y(), direction.Z(), cl.energy()); + fpj.set_user_index(clusterIdx); + fjInputs.push_back(fpj); + } // End of loop on the clusters on currentLayer + } // End of loop over phi-bin region + } // End of loop over eta-bin region + } // End of loop over layers + if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Basic) { + edm::LogVerbatim("PatternRecogntionbyFastJet") << "Creating FastJet for the opposite side with " << fjInputs.size() << " LayerClusters in input"; + } + fastjet::ClusterSequence sequence(fjInputs, JetDefinition(antikt_algorithm, 0.1)); + auto jets = fastjet::sorted_by_pt(sequence.inclusive_jets(0)); + if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Basic) { + edm::LogVerbatim("PatternRecogntionbyFastJet") << "FastJet produced " + << jets.size() << " jets/trackster"; + } + + auto trackster_idx = result.size(); + result.resize(trackster_idx + jets.size()); + for (const auto &pj : jets) { + for (const auto &component : pj.constituents()) { + result[trackster_idx].vertices().push_back(component.user_index()); + result[trackster_idx].vertex_multiplicity().push_back(1); + if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Basic) { + edm::LogVerbatim("PatternRecogntionbyFastJet") << "Jet has " + << pj.constituents().size() << " components that are stored in trackster " << trackster_idx; + } + } + trackster_idx++; + } + fjInputs.clear(); + + ticl::assignPCAtoTracksters(result, + input.layerClusters, + input.layerClustersTime, + rhtools_.getPositionLayer(rhtools_.lastLayerEE(false), false).z()); + + // run energy regression and ID + energyRegressionAndID(input.layerClusters, result); + if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Basic) { + for (auto const &t : result) { + edm::LogVerbatim("PatternRecogntionbyFastJet") << "Barycenter: " << t.barycenter(); + edm::LogVerbatim("PatternRecogntionbyFastJet") << "LCs: " << t.vertices().size(); + edm::LogVerbatim("PatternRecogntionbyFastJet") << "Energy: " << t.raw_energy(); + edm::LogVerbatim("PatternRecogntionbyFastJet") << "Regressed: " << t.regressed_energy(); + } + } + +} + +template +void PatternRecognitionbyFastJet::energyRegressionAndID(const std::vector &layerClusters, + std::vector &tracksters) { + // Energy regression and particle identification strategy: + // + // 1. Set default values for regressed energy and particle id for each trackster. + // 2. Store indices of tracksters whose total sum of cluster energies is above the + // eidMinClusterEnergy_ (GeV) treshold. Inference is not applied for soft tracksters. + // 3. When no trackster passes the selection, return. + // 4. Create input and output tensors. The batch dimension is determined by the number of + // selected tracksters. + // 5. Fill input tensors with layer cluster features. Per layer, clusters are ordered descending + // by energy. Given that tensor data is contiguous in memory, we can use pointer arithmetic to + // fill values, even with batching. + // 6. Zero-fill features for empty clusters in each layer. + // 7. Batched inference. + // 8. Assign the regressed energy and id probabilities to each trackster. + // + // Indices used throughout this method: + // i -> batch element / trackster + // j -> layer + // k -> cluster + // l -> feature + + // set default values per trackster, determine if the cluster energy threshold is passed, + // and store indices of hard tracksters + std::vector tracksterIndices; + for (int i = 0; i < static_cast(tracksters.size()); i++) { + // calculate the cluster energy sum (2) + // note: after the loop, sumClusterEnergy might be just above the threshold which is enough to + // decide whether to run inference for the trackster or not + float sumClusterEnergy = 0.; + for (const unsigned int &vertex : tracksters[i].vertices()) { + sumClusterEnergy += static_cast(layerClusters[vertex].energy()); + // there might be many clusters, so try to stop early + if (sumClusterEnergy >= eidMinClusterEnergy_) { + // set default values (1) + tracksters[i].setRegressedEnergy(0.f); + tracksters[i].zeroProbabilities(); + tracksterIndices.push_back(i); + break; + } + } + } + + // do nothing when no trackster passes the selection (3) + int batchSize = static_cast(tracksterIndices.size()); + if (batchSize == 0) { + return; + } + + // create input and output tensors (4) + tensorflow::TensorShape shape({batchSize, eidNLayers_, eidNClusters_, eidNFeatures_}); + tensorflow::Tensor input(tensorflow::DT_FLOAT, shape); + tensorflow::NamedTensorList inputList = {{eidInputName_, input}}; + + std::vector outputs; + std::vector outputNames; + if (!eidOutputNameEnergy_.empty()) { + outputNames.push_back(eidOutputNameEnergy_); + } + if (!eidOutputNameId_.empty()) { + outputNames.push_back(eidOutputNameId_); + } + + // fill input tensor (5) + for (int i = 0; i < batchSize; i++) { + const Trackster &trackster = tracksters[tracksterIndices[i]]; + + // per layer, we only consider the first eidNClusters_ clusters in terms of energy, so in order + // to avoid creating large / nested structures to do the sorting for an unknown number of total + // clusters, create a sorted list of layer cluster indices to keep track of the filled clusters + std::vector clusterIndices(trackster.vertices().size()); + for (int k = 0; k < (int)trackster.vertices().size(); k++) { + clusterIndices[k] = k; + } + sort(clusterIndices.begin(), clusterIndices.end(), [&layerClusters, &trackster](const int &a, const int &b) { + return layerClusters[trackster.vertices(a)].energy() > layerClusters[trackster.vertices(b)].energy(); + }); + + // keep track of the number of seen clusters per layer + std::vector seenClusters(eidNLayers_); + + // loop through clusters by descending energy + for (const int &k : clusterIndices) { + // get features per layer and cluster and store the values directly in the input tensor + const reco::CaloCluster &cluster = layerClusters[trackster.vertices(k)]; + int j = rhtools_.getLayerWithOffset(cluster.hitsAndFractions()[0].first) - 1; + if (j < eidNLayers_ && seenClusters[j] < eidNClusters_) { + // get the pointer to the first feature value for the current batch, layer and cluster + float *features = &input.tensor()(i, j, seenClusters[j], 0); + + // fill features + *(features++) = float(cluster.energy() / float(trackster.vertex_multiplicity(k))); + *(features++) = float(std::abs(cluster.eta())); + *(features) = float(cluster.phi()); + + // increment seen clusters + seenClusters[j]++; + } + } + + // zero-fill features of empty clusters in each layer (6) + for (int j = 0; j < eidNLayers_; j++) { + for (int k = seenClusters[j]; k < eidNClusters_; k++) { + float *features = &input.tensor()(i, j, k, 0); + for (int l = 0; l < eidNFeatures_; l++) { + *(features++) = 0.f; + } + } + } + } + + // run the inference (7) + tensorflow::run(eidSession_, inputList, outputNames, &outputs); + + // store regressed energy per trackster (8) + if (!eidOutputNameEnergy_.empty()) { + // get the pointer to the energy tensor, dimension is batch x 1 + float *energy = outputs[0].flat().data(); + + for (const int &i : tracksterIndices) { + tracksters[i].setRegressedEnergy(*(energy++)); + } + } + + // store id probabilities per trackster (8) + if (!eidOutputNameId_.empty()) { + // get the pointer to the id probability tensor, dimension is batch x id_probabilities.size() + int probsIdx = eidOutputNameEnergy_.empty() ? 0 : 1; + float *probs = outputs[probsIdx].flat().data(); + + for (const int &i : tracksterIndices) { + tracksters[i].setProbabilities(probs); + probs += tracksters[i].id_probabilities().size(); + } + } +} + +template +void PatternRecognitionbyFastJet::fillPSetDescription(edm::ParameterSetDescription &iDesc) { + iDesc.add("algo_verbosity", 0); + iDesc.add("minNumLayerCluster", 5)->setComment("Not Inclusive"); + iDesc.add("eid_input_name", "input"); + iDesc.add("eid_output_name_energy", "output/regressed_energy"); + iDesc.add("eid_output_name_id", "output/id_probabilities"); + iDesc.add("eid_min_cluster_energy", 1.); + iDesc.add("eid_n_layers", 50); + iDesc.add("eid_n_clusters", 10); +} + +template class ticl::PatternRecognitionbyFastJet; diff --git a/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.h b/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.h new file mode 100644 index 0000000000000..a9785558b843f --- /dev/null +++ b/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.h @@ -0,0 +1,43 @@ +// Author: Marco Rovere - marco.rovere@cern.ch +// Date: 04/2021 + +#ifndef __RecoHGCal_TICL_PRbyFASTJET_H__ +#define __RecoHGCal_TICL_PRbyFASTJET_H__ +#include // unique_ptr +#include "RecoHGCal/TICL/interface/PatternRecognitionAlgoBase.h" +#include "RecoLocalCalo/HGCalRecAlgos/interface/RecHitTools.h" + +namespace ticl { + template + class PatternRecognitionbyFastJet final : public PatternRecognitionAlgoBaseT { + public: + PatternRecognitionbyFastJet(const edm::ParameterSet& conf, const CacheBase* cache, edm::ConsumesCollector); + ~PatternRecognitionbyFastJet() override = default; + + void makeTracksters(const typename PatternRecognitionAlgoBaseT::Inputs& input, + std::vector& result, + std::unordered_map>& seedToTracksterAssociation) override; + + void energyRegressionAndID(const std::vector& layerClusters, std::vector& result); + + static void fillPSetDescription(edm::ParameterSetDescription& iDesc); + + private: + + edm::ESGetToken caloGeomToken_; + const int minNumLayerCluster_; + const std::string eidInputName_; + const std::string eidOutputNameEnergy_; + const std::string eidOutputNameId_; + const float eidMinClusterEnergy_; + const int eidNLayers_; + const int eidNClusters_; + + hgcal::RecHitTools rhtools_; + tensorflow::Session* eidSession_; + + static const int eidNFeatures_ = 3; + }; + +} // namespace ticl +#endif diff --git a/RecoHGCal/TICL/plugins/TrackstersProducer.cc b/RecoHGCal/TICL/plugins/TrackstersProducer.cc index 955af3572dc95..3b126143f91f4 100644 --- a/RecoHGCal/TICL/plugins/TrackstersProducer.cc +++ b/RecoHGCal/TICL/plugins/TrackstersProducer.cc @@ -135,13 +135,18 @@ void TrackstersProducer::fillDescriptions(edm::ConfigurationDescriptions& descri // CA Plugin edm::ParameterSetDescription pluginDesc; pluginDesc.addNode(edm::PluginDescription("type", "CA", true)); - - // CLUE3D Plugin desc.add("pluginPatternRecognitionByCA", pluginDesc); + // + // CLUE3D Plugin edm::ParameterSetDescription pluginDescClue3D; pluginDescClue3D.addNode(edm::PluginDescription("type", "CLUE3D", true)); desc.add("pluginPatternRecognitionByCLUE3D", pluginDescClue3D); + // FastJet Plugin + edm::ParameterSetDescription pluginDescFastJet; + pluginDescFastJet.addNode(edm::PluginDescription("type", "FastJet", true)); + desc.add("pluginPatternRecognitionByFastJet", pluginDescFastJet); + descriptions.add("trackstersProducer", desc); } diff --git a/RecoHGCal/TICL/python/FastJetStep_cff.py b/RecoHGCal/TICL/python/FastJetStep_cff.py new file mode 100644 index 0000000000000..55a6745ddd1ee --- /dev/null +++ b/RecoHGCal/TICL/python/FastJetStep_cff.py @@ -0,0 +1,32 @@ +import FWCore.ParameterSet.Config as cms + +from RecoHGCal.TICL.TICLSeedingRegions_cff import ticlSeedingGlobal, ticlSeedingGlobalHFNose +from RecoHGCal.TICL.trackstersProducer_cfi import trackstersProducer as _trackstersProducer +from RecoHGCal.TICL.filteredLayerClustersProducer_cfi import filteredLayerClustersProducer as _filteredLayerClustersProducer +from RecoHGCal.TICL.multiClustersFromTrackstersProducer_cfi import multiClustersFromTrackstersProducer as _multiClustersFromTrackstersProducer + +# CLUSTER FILTERING/MASKING + +filteredLayerClustersFastJet = _filteredLayerClustersProducer.clone( + clusterFilter = "ClusterFilterByAlgoAndSize", + min_cluster_size = 3, # inclusive + algo_number = 8, + iteration_label = "FastJet" +) + +# PATTERN RECOGNITION + +ticlTrackstersFastJet = _trackstersProducer.clone( + filtered_mask = "filteredLayerClustersFastJet:FastJet", + seeding_regions = "ticlSeedingGlobal", + itername = "FastJet", + patternRecognitionBy = "FastJet", + pluginPatternRecognitionByFastJet = dict ( + algo_verbosity = 2 + ) +) + +ticlFastJetStepTask = cms.Task(ticlSeedingGlobal + ,filteredLayerClustersFastJet + ,ticlTrackstersFastJet) + diff --git a/RecoHGCal/TICL/python/iterativeTICL_cff.py b/RecoHGCal/TICL/python/iterativeTICL_cff.py index 1cfe7e953896c..80d660cfdbfb5 100644 --- a/RecoHGCal/TICL/python/iterativeTICL_cff.py +++ b/RecoHGCal/TICL/python/iterativeTICL_cff.py @@ -1,5 +1,6 @@ import FWCore.ParameterSet.Config as cms +from RecoHGCal.TICL.FastJetStep_cff import * from RecoHGCal.TICL.CLUE3DHighStep_cff import * from RecoHGCal.TICL.CLUE3DLowStep_cff import * from RecoHGCal.TICL.MIPStep_cff import * @@ -31,6 +32,9 @@ from Configuration.ProcessModifiers.clue3D_cff import clue3D clue3D.toModify(ticlIterationsTask, func=lambda x : x.add(ticlCLUE3DHighStepTask,ticlCLUE3DLowStepTask)) +from Configuration.ProcessModifiers.fastJetTICL_cff import fastJetTICL +fastJetTICL.toModify(ticlIterationsTask, func=lambda x : x.add(ticlFastJetStepTask)) + ticlIterLabels = [_step.itername.value() for _iteration in ticlIterationsTask for _step in _iteration if (_step._TypedParameterizable__type == "TrackstersProducer")] iterTICLTask = cms.Task(ticlLayerTileTask From ec312f7a9bd9eff548602b06cd737cfd1613f303 Mon Sep 17 00:00:00 2001 From: Marco Rovere Date: Thu, 14 Oct 2021 11:27:02 +0200 Subject: [PATCH 3/5] Factorize code and parametrize AntiKt radius via config --- .../plugins/PatternRecognitionbyFastJet.cc | 91 +++++++++---------- .../plugins/PatternRecognitionbyFastJet.h | 7 ++ 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.cc b/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.cc index 00f4516416a0f..1596d9f4c963e 100644 --- a/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.cc +++ b/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.cc @@ -32,6 +32,7 @@ PatternRecognitionbyFastJet::PatternRecognitionbyFastJet(const edm::Param edm::ConsumesCollector iC) : PatternRecognitionAlgoBaseT(conf, cache, iC), caloGeomToken_(iC.esConsumes()), + antikt_radius_(conf.getParameter("antikt_radius")), minNumLayerCluster_(conf.getParameter("minNumLayerCluster")), eidInputName_(conf.getParameter("eid_input_name")), eidOutputNameEnergy_(conf.getParameter("eid_output_name_energy")), @@ -49,6 +50,43 @@ PatternRecognitionbyFastJet::PatternRecognitionbyFastJet(const edm::Param eidSession_ = tensorflow::createSession(trackstersCache->eidGraphDef); } +template +void PatternRecognitionbyFastJet::buildJetAndTracksters(std::vector & fjInputs, + std::vector & result) { + if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Basic) { + edm::LogVerbatim("PatternRecogntionbyFastJet") << "Creating FastJet with " + << fjInputs.size() << " LayerClusters in input"; + } + fastjet::ClusterSequence sequence(fjInputs, JetDefinition(antikt_algorithm, antikt_radius_)); + auto jets = fastjet::sorted_by_pt(sequence.inclusive_jets(0)); + if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Basic) { + edm::LogVerbatim("PatternRecogntionbyFastJet") << "FastJet produced " + << jets.size() << " jets/trackster"; + } + + auto trackster_idx = result.size(); + result.resize(trackster_idx + jets.size()); + for (const auto &pj : jets) { + if (pj.constituents().size() > static_cast(minNumLayerCluster_)) { + for (const auto &component : pj.constituents()) { + result[trackster_idx].vertices().push_back(component.user_index()); + result[trackster_idx].vertex_multiplicity().push_back(1); + if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Basic) { + edm::LogVerbatim("PatternRecogntionbyFastJet") << "Jet has " + << pj.constituents().size() << " components that are stored in trackster " << trackster_idx; + } + } + trackster_idx++; + } else { + if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Advanced) { + edm::LogVerbatim("PatternRecogntionbyFastJet") << "Jet with " << pj.constituents().size() + << " constituents discarded since too small wrt " << minNumLayerCluster_; + } + } + } + fjInputs.clear(); +} + template void PatternRecognitionbyFastJet::makeTracksters( const typename PatternRecognitionAlgoBaseT::Inputs &input, @@ -73,32 +111,7 @@ void PatternRecognitionbyFastJet::makeTracksters( fjInputs.clear(); for (unsigned int currentLayer = 0; currentLayer <= maxLayer ; ++currentLayer) { if (currentLayer == lastLayerPerSide) { - if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Basic) { - edm::LogVerbatim("PatternRecogntionbyFastJet") << "Creating FastJet at later " - << currentLayer - << " with " << fjInputs.size() << " LayerClusters in input"; - } - fastjet::ClusterSequence sequence(fjInputs, JetDefinition(antikt_algorithm, 0.1)); - auto jets = fastjet::sorted_by_pt(sequence.inclusive_jets(0)); - if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Basic) { - edm::LogVerbatim("PatternRecogntionbyFastJet") << "FastJet produced " - << jets.size() << " jets/trackster"; - } - - auto trackster_idx = result.size(); - result.resize(trackster_idx + jets.size()); - for (const auto &pj : jets) { - for (const auto &component : pj.constituents()) { - result[trackster_idx].vertices().push_back(component.user_index()); - result[trackster_idx].vertex_multiplicity().push_back(1); - if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Basic) { - edm::LogVerbatim("PatternRecogntionbyFastJet") << "Jet has " - << pj.constituents().size() << " components that are stored in trackster " << trackster_idx; - } - } - trackster_idx++; - } - fjInputs.clear(); + buildJetAndTracksters(fjInputs, result); } const auto &tileOnLayer = input.tiles[currentLayer]; for (int ieta = 0; ieta <= nEtaBin; ++ieta) { @@ -132,30 +145,9 @@ void PatternRecognitionbyFastJet::makeTracksters( } // End of loop over phi-bin region } // End of loop over eta-bin region } // End of loop over layers - if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Basic) { - edm::LogVerbatim("PatternRecogntionbyFastJet") << "Creating FastJet for the opposite side with " << fjInputs.size() << " LayerClusters in input"; - } - fastjet::ClusterSequence sequence(fjInputs, JetDefinition(antikt_algorithm, 0.1)); - auto jets = fastjet::sorted_by_pt(sequence.inclusive_jets(0)); - if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Basic) { - edm::LogVerbatim("PatternRecogntionbyFastJet") << "FastJet produced " - << jets.size() << " jets/trackster"; - } - auto trackster_idx = result.size(); - result.resize(trackster_idx + jets.size()); - for (const auto &pj : jets) { - for (const auto &component : pj.constituents()) { - result[trackster_idx].vertices().push_back(component.user_index()); - result[trackster_idx].vertex_multiplicity().push_back(1); - if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Basic) { - edm::LogVerbatim("PatternRecogntionbyFastJet") << "Jet has " - << pj.constituents().size() << " components that are stored in trackster " << trackster_idx; - } - } - trackster_idx++; - } - fjInputs.clear(); + // Collect the jet from the other side wrt to the one taken care of inside the main loop above. + buildJetAndTracksters(fjInputs, result); ticl::assignPCAtoTracksters(result, input.layerClusters, @@ -317,6 +309,7 @@ void PatternRecognitionbyFastJet::energyRegressionAndID(const std::vector template void PatternRecognitionbyFastJet::fillPSetDescription(edm::ParameterSetDescription &iDesc) { iDesc.add("algo_verbosity", 0); + iDesc.add("antikt_radius", 0.09)->setComment("Radius to be used while running the Anti-kt clustering"); iDesc.add("minNumLayerCluster", 5)->setComment("Not Inclusive"); iDesc.add("eid_input_name", "input"); iDesc.add("eid_output_name_energy", "output/regressed_energy"); diff --git a/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.h b/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.h index a9785558b843f..4ad39a2060c17 100644 --- a/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.h +++ b/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.h @@ -7,6 +7,10 @@ #include "RecoHGCal/TICL/interface/PatternRecognitionAlgoBase.h" #include "RecoLocalCalo/HGCalRecAlgos/interface/RecHitTools.h" +// fwd declaration + +namespace fastjet { class PseudoJet;}; + namespace ticl { template class PatternRecognitionbyFastJet final : public PatternRecognitionAlgoBaseT { @@ -25,6 +29,7 @@ namespace ticl { private: edm::ESGetToken caloGeomToken_; + const double antikt_radius_; const int minNumLayerCluster_; const std::string eidInputName_; const std::string eidOutputNameEnergy_; @@ -37,6 +42,8 @@ namespace ticl { tensorflow::Session* eidSession_; static const int eidNFeatures_ = 3; + + void buildJetAndTracksters(std::vector &, std::vector &); }; } // namespace ticl From f2015ce72d625976f598321fcc0445af59b3dba1 Mon Sep 17 00:00:00 2001 From: Marco Rovere Date: Wed, 20 Oct 2021 12:22:07 +0200 Subject: [PATCH 4/5] Code format --- .../plugins/PatternRecognitionbyFastJet.cc | 79 +++++++++---------- .../plugins/PatternRecognitionbyFastJet.h | 7 +- 2 files changed, 42 insertions(+), 44 deletions(-) diff --git a/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.cc b/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.cc index 1596d9f4c963e..2ceda18cc9cc8 100644 --- a/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.cc +++ b/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.cc @@ -22,46 +22,44 @@ #include "fastjet/ClusterSequence.hh" - using namespace ticl; using namespace fastjet; - template +template PatternRecognitionbyFastJet::PatternRecognitionbyFastJet(const edm::ParameterSet &conf, - const CacheBase *cache, - edm::ConsumesCollector iC) - : PatternRecognitionAlgoBaseT(conf, cache, iC), - caloGeomToken_(iC.esConsumes()), - antikt_radius_(conf.getParameter("antikt_radius")), - minNumLayerCluster_(conf.getParameter("minNumLayerCluster")), - eidInputName_(conf.getParameter("eid_input_name")), - eidOutputNameEnergy_(conf.getParameter("eid_output_name_energy")), - eidOutputNameId_(conf.getParameter("eid_output_name_id")), - eidMinClusterEnergy_(conf.getParameter("eid_min_cluster_energy")), - eidNLayers_(conf.getParameter("eid_n_layers")), - eidNClusters_(conf.getParameter("eid_n_clusters")), - eidSession_(nullptr) { - // mount the tensorflow graph onto the session when set - const TrackstersCache *trackstersCache = dynamic_cast(cache); - if (trackstersCache == nullptr || trackstersCache->eidGraphDef == nullptr) { - throw cms::Exception("MissingGraphDef") + const CacheBase *cache, + edm::ConsumesCollector iC) + : PatternRecognitionAlgoBaseT(conf, cache, iC), + caloGeomToken_(iC.esConsumes()), + antikt_radius_(conf.getParameter("antikt_radius")), + minNumLayerCluster_(conf.getParameter("minNumLayerCluster")), + eidInputName_(conf.getParameter("eid_input_name")), + eidOutputNameEnergy_(conf.getParameter("eid_output_name_energy")), + eidOutputNameId_(conf.getParameter("eid_output_name_id")), + eidMinClusterEnergy_(conf.getParameter("eid_min_cluster_energy")), + eidNLayers_(conf.getParameter("eid_n_layers")), + eidNClusters_(conf.getParameter("eid_n_clusters")), + eidSession_(nullptr) { + // mount the tensorflow graph onto the session when set + const TrackstersCache *trackstersCache = dynamic_cast(cache); + if (trackstersCache == nullptr || trackstersCache->eidGraphDef == nullptr) { + throw cms::Exception("MissingGraphDef") << "PatternRecognitionbyFastJet received an empty graph definition from the global cache"; - } - eidSession_ = tensorflow::createSession(trackstersCache->eidGraphDef); } + eidSession_ = tensorflow::createSession(trackstersCache->eidGraphDef); +} -template -void PatternRecognitionbyFastJet::buildJetAndTracksters(std::vector & fjInputs, - std::vector & result) { +template +void PatternRecognitionbyFastJet::buildJetAndTracksters(std::vector &fjInputs, + std::vector &result) { if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Basic) { - edm::LogVerbatim("PatternRecogntionbyFastJet") << "Creating FastJet with " - << fjInputs.size() << " LayerClusters in input"; + edm::LogVerbatim("PatternRecogntionbyFastJet") + << "Creating FastJet with " << fjInputs.size() << " LayerClusters in input"; } fastjet::ClusterSequence sequence(fjInputs, JetDefinition(antikt_algorithm, antikt_radius_)); auto jets = fastjet::sorted_by_pt(sequence.inclusive_jets(0)); if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Basic) { - edm::LogVerbatim("PatternRecogntionbyFastJet") << "FastJet produced " - << jets.size() << " jets/trackster"; + edm::LogVerbatim("PatternRecogntionbyFastJet") << "FastJet produced " << jets.size() << " jets/trackster"; } auto trackster_idx = result.size(); @@ -72,15 +70,16 @@ void PatternRecognitionbyFastJet::buildJetAndTracksters(std::vector::algo_verbosity_ > PatternRecognitionAlgoBaseT::Basic) { - edm::LogVerbatim("PatternRecogntionbyFastJet") << "Jet has " - << pj.constituents().size() << " components that are stored in trackster " << trackster_idx; + edm::LogVerbatim("PatternRecogntionbyFastJet") + << "Jet has " << pj.constituents().size() << " components that are stored in trackster " << trackster_idx; } } trackster_idx++; } else { if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Advanced) { - edm::LogVerbatim("PatternRecogntionbyFastJet") << "Jet with " << pj.constituents().size() - << " constituents discarded since too small wrt " << minNumLayerCluster_; + edm::LogVerbatim("PatternRecogntionbyFastJet") + << "Jet with " << pj.constituents().size() << " constituents discarded since too small wrt " + << minNumLayerCluster_; } } } @@ -109,7 +108,7 @@ void PatternRecognitionbyFastJet::makeTracksters( unsigned int maxLayer = 2 * lastLayerPerSide - 1; std::vector fjInputs; fjInputs.clear(); - for (unsigned int currentLayer = 0; currentLayer <= maxLayer ; ++currentLayer) { + for (unsigned int currentLayer = 0; currentLayer <= maxLayer; ++currentLayer) { if (currentLayer == lastLayerPerSide) { buildJetAndTracksters(fjInputs, result); } @@ -122,8 +121,7 @@ void PatternRecognitionbyFastJet::makeTracksters( for (int iphi = 0; iphi <= nPhiBin; ++iphi) { if (PatternRecognitionAlgoBaseT::algo_verbosity_ > PatternRecognitionAlgoBaseT::Advanced) { edm::LogVerbatim("PatternRecogntionbyFastJet") << "iphi: " << iphi; - edm::LogVerbatim("PatternRecogntionbyFastJet") - << "Entries in tileBin: " << tileOnLayer[offset + iphi].size(); + edm::LogVerbatim("PatternRecogntionbyFastJet") << "Entries in tileBin: " << tileOnLayer[offset + iphi].size(); } for (auto clusterIdx : tileOnLayer[offset + iphi]) { // Skip masked layer clusters @@ -134,7 +132,7 @@ void PatternRecognitionbyFastJet::makeTracksters( continue; } // Should we correct for the position of the PV? - auto const & cl = input.layerClusters[clusterIdx]; + auto const &cl = input.layerClusters[clusterIdx]; math::XYZVector direction(cl.x(), cl.y(), cl.z()); direction = direction.Unit(); direction *= cl.energy(); @@ -142,9 +140,9 @@ void PatternRecognitionbyFastJet::makeTracksters( fpj.set_user_index(clusterIdx); fjInputs.push_back(fpj); } // End of loop on the clusters on currentLayer - } // End of loop over phi-bin region - } // End of loop over eta-bin region - } // End of loop over layers + } // End of loop over phi-bin region + } // End of loop over eta-bin region + } // End of loop over layers // Collect the jet from the other side wrt to the one taken care of inside the main loop above. buildJetAndTracksters(fjInputs, result); @@ -164,12 +162,11 @@ void PatternRecognitionbyFastJet::makeTracksters( edm::LogVerbatim("PatternRecogntionbyFastJet") << "Regressed: " << t.regressed_energy(); } } - } template void PatternRecognitionbyFastJet::energyRegressionAndID(const std::vector &layerClusters, - std::vector &tracksters) { + std::vector &tracksters) { // Energy regression and particle identification strategy: // // 1. Set default values for regressed energy and particle id for each trackster. diff --git a/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.h b/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.h index 4ad39a2060c17..d515b18ff63af 100644 --- a/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.h +++ b/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.h @@ -9,7 +9,9 @@ // fwd declaration -namespace fastjet { class PseudoJet;}; +namespace fastjet { + class PseudoJet; +}; namespace ticl { template @@ -27,7 +29,6 @@ namespace ticl { static void fillPSetDescription(edm::ParameterSetDescription& iDesc); private: - edm::ESGetToken caloGeomToken_; const double antikt_radius_; const int minNumLayerCluster_; @@ -43,7 +44,7 @@ namespace ticl { static const int eidNFeatures_ = 3; - void buildJetAndTracksters(std::vector &, std::vector &); + void buildJetAndTracksters(std::vector&, std::vector&); }; } // namespace ticl From 3a0c1b3d6ac0597905509ddc45db3467195f9c7d Mon Sep 17 00:00:00 2001 From: Marco Rovere Date: Thu, 18 Nov 2021 15:58:18 +0100 Subject: [PATCH 5/5] Adapt FastJet plugin to LayerTiles type traits --- .../TICL/plugins/PatternRecognitionbyFastJet.cc | 12 ++++++------ RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.cc b/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.cc index 2ceda18cc9cc8..47e19e499cc92 100644 --- a/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.cc +++ b/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.cc @@ -1,5 +1,5 @@ // Author: Marco Rovere - marco.rovere@cern.ch -// Date: 04/2021 +// Date: 10/2021 #include #include #include @@ -99,12 +99,12 @@ void PatternRecognitionbyFastJet::makeTracksters( const CaloGeometry &geom = es.getData(caloGeomToken_); rhtools_.setGeometry(geom); - int type = input.tiles[0].typeT(); - int nEtaBin = (type == 1) ? ticl::TileConstantsHFNose::nEtaBins : ticl::TileConstants::nEtaBins; - int nPhiBin = (type == 1) ? ticl::TileConstantsHFNose::nPhiBins : ticl::TileConstants::nPhiBins; + constexpr auto isHFnose = std::is_same::value; + constexpr int nEtaBin = TILES::constants_type_t::nEtaBins; + constexpr int nPhiBin = TILES::constants_type_t::nPhiBins; // We need to partition the two sides of the HGCAL detector - auto lastLayerPerSide = static_cast(rhtools_.lastLayer(false)) - 1; + auto lastLayerPerSide = static_cast(rhtools_.lastLayer(isHFnose)) - 1; unsigned int maxLayer = 2 * lastLayerPerSide - 1; std::vector fjInputs; fjInputs.clear(); @@ -150,7 +150,7 @@ void PatternRecognitionbyFastJet::makeTracksters( ticl::assignPCAtoTracksters(result, input.layerClusters, input.layerClustersTime, - rhtools_.getPositionLayer(rhtools_.lastLayerEE(false), false).z()); + rhtools_.getPositionLayer(rhtools_.lastLayerEE(isHFnose), isHFnose).z()); // run energy regression and ID energyRegressionAndID(input.layerClusters, result); diff --git a/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.h b/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.h index d515b18ff63af..53c9279a31dec 100644 --- a/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.h +++ b/RecoHGCal/TICL/plugins/PatternRecognitionbyFastJet.h @@ -1,5 +1,5 @@ // Author: Marco Rovere - marco.rovere@cern.ch -// Date: 04/2021 +// Date: 10/2021 #ifndef __RecoHGCal_TICL_PRbyFASTJET_H__ #define __RecoHGCal_TICL_PRbyFASTJET_H__