Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Seed TICL by L1 e/gamma + other timing considerations for e/gamma HLT #32978

Merged
merged 10 commits into from
Mar 4, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -331,3 +331,16 @@ DEFINE_FWK_MODULE(HLTEcalRecHitsInRegionsProducer);
#include "DataFormats/EcalRecHit/interface/EcalUncalibratedRecHit.h"
using HLTEcalUnCalibRecHitsInRegionsProducer = HLTCaloObjInRegionsProducer<EcalUncalibratedRecHit>;
DEFINE_FWK_MODULE(HLTEcalUnCalibRecHitsInRegionsProducer);

// HGCAL Digis
#include "DataFormats/HGCDigi/interface/HGCDigiCollections.h"
using HLTHGCalDigisInRegionsProducer = HLTCaloObjInRegionsProducer<HGCalDataFrame, HGCalDigiCollection>;
DEFINE_FWK_MODULE(HLTHGCalDigisInRegionsProducer);

// HGCAL RecHits
#include "DataFormats/HGCRecHit/interface/HGCRecHit.h"
using HLTHGCalRecHitsInRegionsProducer = HLTCaloObjInRegionsProducer<HGCRecHit>;
DEFINE_FWK_MODULE(HLTHGCalRecHitsInRegionsProducer);
#include "DataFormats/HGCRecHit/interface/HGCUncalibratedRecHit.h"
using HLTHGCalUncalibratedRecHitsInRegionsProducer = HLTCaloObjInRegionsProducer<HGCUncalibratedRecHit>;
DEFINE_FWK_MODULE(HLTHGCalUncalibratedRecHitsInRegionsProducer);
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
Author: Swagata Mukherjee
Date: Feb 2021
At the time of writing this new module, it is intended to be used mainly for
phase-2. Before feeding in the L1 e/g collection to
HLTEcalRecHitInAllL1RegionsProducer, it can pass through this module which
will filter the collection based on hardware quality and pT.
The most generic L1 e/g phase-2 collections are:
TkEm, which is std::vector<l1t::TkEm>
&
StaEG, which is BXVector<l1t::EGamma>
Despite this technical difference, the objects are almost identical, for all
practical purposes. So any of these two collections could have been used.
Currently, BXVector<l1t::EGamma> is recognised by the next step
HLTEcalRecHitInAllL1RegionsProducer, while std::vector<l1t::TkEm> is not. So
using BXVector<l1t::EGamma> is straightforward. If for some reason one need to
use std::vector<l1t::TkEm>, changes in HLTEcalRecHitInAllL1RegionsProducer
would also be necesary.
*/

#include "DataFormats/L1TCorrelator/interface/TkEm.h"
#include "FWCore/Framework/interface/ESHandle.h"
#include "FWCore/Framework/interface/Event.h"
#include "FWCore/Framework/interface/EventSetup.h"
#include "FWCore/Framework/interface/EventSetupRecord.h"
#include "FWCore/Framework/interface/Frameworkfwd.h"
#include "FWCore/Framework/interface/MakerMacros.h"
#include "FWCore/Framework/interface/global/EDProducer.h"
#include "FWCore/MessageLogger/interface/MessageLogger.h"
#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
#include "FWCore/ParameterSet/interface/ParameterSet.h"
#include "FWCore/ParameterSet/interface/ParameterSetDescription.h"

class L1TEGammaFilteredCollectionProducer : public edm::global::EDProducer<> {
public:
explicit L1TEGammaFilteredCollectionProducer(const edm::ParameterSet&);
~L1TEGammaFilteredCollectionProducer() override;
static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
void produce(edm::StreamID sid, edm::Event& iEvent, const edm::EventSetup& iSetup) const override;

private:
edm::InputTag l1EgTag_;
edm::EDGetTokenT<BXVector<l1t::EGamma>> l1EgToken_;
int quality_;
bool qualIsMask_;
bool applyQual_;
int minBX_;
int maxBX_;
double minPt_;
std::vector<double> scalings_; // pT scaling factors
double getOfflineEt(double et) const;
};

L1TEGammaFilteredCollectionProducer::L1TEGammaFilteredCollectionProducer(const edm::ParameterSet& iConfig)
: l1EgTag_(iConfig.getParameter<edm::InputTag>("inputTag")), l1EgToken_(consumes<BXVector<l1t::EGamma>>(l1EgTag_)) {
quality_ = iConfig.getParameter<int>("quality");
qualIsMask_ = iConfig.getParameter<bool>("qualIsMask");
applyQual_ = iConfig.getParameter<bool>("applyQual");
minBX_ = iConfig.getParameter<int>("minBX");
maxBX_ = iConfig.getParameter<int>("maxBX");
minPt_ = iConfig.getParameter<double>("minPt");
scalings_ = iConfig.getParameter<std::vector<double>>("scalings");

produces<BXVector<l1t::EGamma>>();
}

L1TEGammaFilteredCollectionProducer::~L1TEGammaFilteredCollectionProducer() = default;

void L1TEGammaFilteredCollectionProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
edm::ParameterSetDescription desc;
desc.add<edm::InputTag>("inputTag", edm::InputTag("L1EGammaClusterEmuProducer"));
desc.add<int>("quality", 0x2);
desc.add<bool>("qualIsMask", true);
desc.add<bool>("applyQual", true);
desc.add<int>("minBX", -1);
desc.add<int>("maxBX", 1);
desc.add<double>("minPt", 5.0);
desc.add<std::vector<double>>("scalings", {2.6604, 1.06077, 0.0});
descriptions.add("L1TEGammaFilteredCollectionProducer", desc);
}

void L1TEGammaFilteredCollectionProducer::produce(edm::StreamID sid,
edm::Event& iEvent,
const edm::EventSetup& iSetup) const {
auto outEgs = std::make_unique<BXVector<l1t::EGamma>>();
auto l1Egs = iEvent.getHandle(l1EgToken_);

int startBX = std::max((*l1Egs).getFirstBX(), minBX_);
int endBX = std::min((*l1Egs).getLastBX(), maxBX_);

for (int bx = startBX; bx <= endBX; bx++) {
// Loop over all L1 e/gamma objects
for (BXVector<l1t::EGamma>::const_iterator iEg = (*l1Egs).begin(bx); iEg != (*l1Egs).end(bx); iEg++) {
double offlineEt = this->getOfflineEt((*iEg).pt());
bool passQuality(false);
if (applyQual_) {
if (qualIsMask_)
passQuality = ((*iEg).hwQual() & quality_);
else
passQuality = ((*iEg).hwQual() == quality_);
} else
passQuality = true;

// if quality is passed, put the object in filtered collection
if (passQuality && (offlineEt > minPt_)) {
outEgs->push_back(bx, *iEg);
}
} // l1EG loop ends
} // BX loop ends
iEvent.put(std::move(outEgs));
}

double L1TEGammaFilteredCollectionProducer::getOfflineEt(double et) const {
return (scalings_.at(0) + et * scalings_.at(1) + et * et * scalings_.at(2));
}

DEFINE_FWK_MODULE(L1TEGammaFilteredCollectionProducer);
2 changes: 2 additions & 0 deletions RecoHGCal/TICL/plugins/BuildFile.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
<use name="FWCore/ParameterSet"/>
<use name="FWCore/PluginManager"/>
<use name="DataFormats/CaloRecHit"/>
<use name="DataFormats/L1Trigger"/>
<use name="DataFormats/Candidate"/>
<use name="DataFormats/ParticleFlowCandidate"/>
<use name="DataFormats/HGCalReco"/>
<use name="FWCore/MessageLogger"/>
Expand Down
74 changes: 74 additions & 0 deletions RecoHGCal/TICL/plugins/SeedingRegionByL1.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
Author: Swagata Mukherjee

Date: Feb 2021

TICL is currently seeded by tracks, or just globally.
Here, adding option to seed TICL by L1 e/gamma objects (L1 TkEm).
This is expected to be useful for CPU timing at the HLT.
*/

#include "SeedingRegionByL1.h"

#include <algorithm>
#include <set>
#include <vector>

#include "FWCore/MessageLogger/interface/MessageLogger.h"

ticl::SeedingRegionByL1::SeedingRegionByL1(const edm::ParameterSet &conf, edm::ConsumesCollector &sumes)
: SeedingRegionAlgoBase(conf, sumes),
l1TkEmsToken_(sumes.consumes<std::vector<l1t::TkEm>>(conf.getParameter<edm::InputTag>("l1TkEmColl"))),
algoVerbosity_(conf.getParameter<int>("algo_verbosity")),
minPt_(conf.getParameter<double>("minPt")),
minAbsEta_(conf.getParameter<double>("minAbsEta")),
maxAbsEta_(conf.getParameter<double>("maxAbsEta")),
endcapScalings_(conf.getParameter<std::vector<double>>("endcapScalings")),
quality_(conf.getParameter<int>("quality")) {}

void ticl::SeedingRegionByL1::makeRegions(const edm::Event &ev,
const edm::EventSetup &es,
std::vector<TICLSeedingRegion> &result) {
auto l1TrkEms = ev.getHandle(l1TkEmsToken_);
edm::ProductID l1tkemsId = l1TrkEms.id();

for (size_t indx = 0; indx < (*l1TrkEms).size(); indx++) {
const auto &l1TrkEm = (*l1TrkEms)[indx];
double offlinePt = this->TkEmOfflineEt(l1TrkEm.pt());
if ((offlinePt < minPt_) || (std::abs(l1TrkEm.eta()) < minAbsEta_) || (std::abs(l1TrkEm.eta()) > maxAbsEta_) ||
(l1TrkEm.EGRef()->hwQual() != quality_)) {
continue;
}

int iSide = int(l1TrkEm.eta() > 0);
result.emplace_back(GlobalPoint(l1TrkEm.p4().X(), l1TrkEm.p4().Y(), l1TrkEm.p4().Z()),
GlobalVector(l1TrkEm.px(), l1TrkEm.py(), l1TrkEm.pz()),
iSide,
indx,
l1tkemsId);
}

std::sort(result.begin(), result.end(), [](const TICLSeedingRegion &a, const TICLSeedingRegion &b) {
return a.directionAtOrigin.perp2() > b.directionAtOrigin.perp2();
});
}

double ticl::SeedingRegionByL1::TkEmOfflineEt(double Et) const {
return (endcapScalings_.at(0) + Et * endcapScalings_.at(1) + Et * Et * endcapScalings_.at(2));
}

void ticl::SeedingRegionByL1::fillPSetDescription(edm::ParameterSetDescription &desc) {
desc.add<edm::InputTag>("l1TkEmColl", edm::InputTag("L1TkPhotonsHGC", "EG"));
desc.add<int>("algo_verbosity", 0);
desc.add<double>("minPt", 10);
desc.add<double>("minAbsEta", 1.479);
desc.add<double>("maxAbsEta", 4.0);
desc.add<std::vector<double>>("endcapScalings", {3.17445, 1.13219, 0.0});
desc.add<int>("quality", 5);
}

edm::ParameterSetDescription ticl::SeedingRegionByL1::makePSetDescription() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method and its declaration should not be necessary and can be removed, IMHO.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm yes, it was useful in the original design but in the current design I agree its not necessary and introduces a difference to the other SeedingRegions which violates principle of least surprise. @swagata87 , can you remove it please?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makePSetDescription is now removed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you Swagata

edm::ParameterSetDescription desc;
fillPSetDescription(desc);
return desc;
}
43 changes: 43 additions & 0 deletions RecoHGCal/TICL/plugins/SeedingRegionByL1.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Author: Swagata Mukherjee

#ifndef RecoHGCal_TICL_SeedingRegionByL1_h
#define RecoHGCal_TICL_SeedingRegionByL1_h
#include <memory>
#include <string>

#include "DataFormats/L1TCorrelator/interface/TkEm.h"
#include "DataFormats/L1TCorrelator/interface/TkEmFwd.h"
#include "FWCore/Framework/interface/ConsumesCollector.h"
#include "FWCore/Framework/interface/ESHandle.h"
#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/ConfigurationDescriptions.h"
#include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
#include "FWCore/Utilities/interface/ESGetToken.h"
#include "RecoHGCal/TICL/plugins/SeedingRegionAlgoBase.h"

namespace ticl {
class SeedingRegionByL1 final : public SeedingRegionAlgoBase {
public:
SeedingRegionByL1(const edm::ParameterSet& conf, edm::ConsumesCollector& sumes);

void initialize(const edm::EventSetup& es) override{};
void makeRegions(const edm::Event& ev, const edm::EventSetup& es, std::vector<TICLSeedingRegion>& result) override;
static void fillPSetDescription(edm::ParameterSetDescription& desc);
static edm::ParameterSetDescription makePSetDescription();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, see my comments here.

Copy link
Contributor Author

@swagata87 swagata87 Mar 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @rovere,
just trying to understand it better,
do you mean something like this ?

void TICLSeedingRegionProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
edm::ParameterSetDescription desc;
desc.add<int>("algo_verbosity", 0);
desc.add<edm::InputTag>("tracks", edm::InputTag("generalTracks"));
desc.add<std::string>("cutTk",
"1.48 < abs(eta) < 3.0 && pt > 1. && quality(\"highPurity\") && "
"hitPattern().numberOfLostHits(\"MISSING_OUTER_HITS\") < 5");
desc.add<std::string>("propagator", "PropagatorWithMaterial");
desc.add<int>("algoId", 1);
// following are needed for seeding TICL with L1 egamma objects (TkEm) //
desc.add<edm::InputTag>("l1tkems", edm::InputTag("L1TkPhotonsHGC","EG"));
desc.add<double>("minpt", 10);
desc.add<double>("minabseta", 1.479);
desc.add<double>("maxabseta", 4.0);
desc.add<std::vector<double>>("endcapScalings", {3.17445,1.13219,0.0});
desc.add<int>("quality", 5);
descriptions.add("ticlSeedingRegionProducer", desc);
}

i.e, the parameters needed by SeedingRegionByL1 class are included explicitly in the TICLSeedingRegionProducer::fillDescriptions ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ciao @swagata87 I meant following the example of what has been done, e.g, here:

  • base class for all algos link
  • derived plugins with proper implementation of fillPSetDescription here and here
  • Create a PluginFactory and properly register the plugins as having also a PSet available: here
  • Get the desired plugin from the PluginFactory by name: here

All that is described in more details here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, ultimately this is the way to go. But this puts us in a tricky situation, we would rather very much like to have this in a release built tomorrow. So the way I see it there are two ways

  1. we put it in as is.
  2. we make these changes but in this situation we do not want to have a long back and forth about any implementation decisions we make. This is specifically the PSet name for the tracking seeding algo. A subsequent PR can fix any of those issues.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ciao @Sam-Harper
if we assume you also would like to have a backport, I agree with your plan 1, provided there's a commitment to also implement 2 after 1 has been integrated. This will have interplay with #33001 that could be used, in principle, as the PR where this approach is first implemented (eventually integrating also the changes required in these files).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so we updated the config, there are few things to address:

the name of plugin pset, we chose "seedingPSet"

the name of the parameter which is the plugin name, "type" was the example but its not great to use a python reserved word (although in this case we dont shadow). They can be changed to anything people want.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rovere any comments on the parameter names ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name is fine.
Thanks @Sam-Harper @swagata87 for this additional effort!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no problem it ended up being easier than we thought it would be at first glance :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name is fine.
Thanks @Sam-Harper @swagata87 for this additional effort!

Thank you @rovere for your suggestion to use plugins, and also for the examples & twiki that you linked to before.
The additional effort is made by Sam, he implemented the plugin related changes to address your comment. I wasn't fully sure how to do it quickly enough :-)


private:
edm::EDGetTokenT<std::vector<l1t::TkEm>> l1TkEmsToken_;
int algoVerbosity_ = 0;
double minPt_; // minimum pT of L1 TkEm objects
double minAbsEta_; // minimum |eta| of L1 TkEm objects
double maxAbsEta_; // maximum |eta| of L1 TkEm objects
std::vector<double> endcapScalings_; // pT scaling factors for endcap
int quality_; // hwQual

double TkEmOfflineEt(double Et) const;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry to be picky

Suggested change
double TkEmOfflineEt(double Et) const;
double tkEmOfflineEt(double et) const;

to agree with 2.8 https://cms-sw.github.io/cms_coding_rules.html (and function parameters commonly start with lowercase too)

Start method names with lowercase, use upper case initials for following words, e.g. collisionPoint().
Allowed exception: Implementation of virtual methods inherited from external packages, e.g. ProcessHits() method required by Geant4.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, done

};
} // namespace ticl
#endif
5 changes: 5 additions & 0 deletions RecoHGCal/TICL/plugins/TICLSeedingRegionProducer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
#include "FWCore/Framework/interface/ConsumesCollector.h"
#include "RecoHGCal/TICL/plugins/SeedingRegionAlgoBase.h"
#include "SeedingRegionByL1.h"
#include "SeedingRegionByTracks.h"
#include "SeedingRegionGlobal.h"

Expand Down Expand Up @@ -47,6 +48,9 @@ TICLSeedingRegionProducer::TICLSeedingRegionProducer(const edm::ParameterSet& ps
case 2:
myAlgo_ = std::make_unique<SeedingRegionGlobal>(ps, sumes);
break;
case 3:
myAlgo_ = std::make_unique<SeedingRegionByL1>(ps.getParameterSet("seedTiclByL1Config"), sumes); // needed for HLT
break;
default:
break;
}
Expand All @@ -62,6 +66,7 @@ void TICLSeedingRegionProducer::fillDescriptions(edm::ConfigurationDescriptions&
"hitPattern().numberOfLostHits(\"MISSING_OUTER_HITS\") < 5");
desc.add<std::string>("propagator", "PropagatorWithMaterial");
desc.add<int>("algoId", 1);
desc.add<edm::ParameterSetDescription>("seedTiclByL1Config", SeedingRegionByL1::makePSetDescription());
descriptions.add("ticlSeedingRegionProducer", desc);
}

Expand Down