CMS 3D CMS Logo

HLTGenValSource.cc
Go to the documentation of this file.
1 //********************************************************************************
2 //
3 // Description:
4 // Producing and filling histograms for generator-level HLT path efficiency histograms. Harvested by a HLTGenValClient.
5 //
6 // Implementation:
7 // Histograms for objects of a certain type are created for multiple paths chosen by the user: for all objects,
8 // and for objects passing filters in the path, determined by deltaR matching.
9 // Each HLTGenValSource can handle a single object type and any number of paths (and filters in them)
10 //
11 // Author: Finn Labe, UHH, Jul. 2022
12 //
13 //********************************************************************************
14 
15 // system include files
16 #include <memory>
17 #include <chrono>
18 #include <ctime>
19 
20 // user include files
23 
26 
27 // including GenParticles
29 
30 // icnluding GenMET
33 
34 // includes needed for histogram creation
37 
38 // FunctionDefs
40 
41 // includes of histogram collection class
43 
44 // DQMStore
47 
48 // trigger Event
51 
52 // object that can be a GenJet, GenParticle or energy sum
54 
56 public:
57  explicit HLTGenValSource(const edm::ParameterSet&);
58  ~HLTGenValSource() override = default;
59  HLTGenValSource(const HLTGenValSource&) = delete;
60  HLTGenValSource& operator=(const HLTGenValSource&) = delete;
61 
62  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
63 
64 private:
65  void analyze(const edm::Event&, const edm::EventSetup&) override;
66  void bookHistograms(DQMStore::IBooker&, edm::Run const& run, edm::EventSetup const& c) override;
67  void dqmBeginRun(const edm::Run&, const edm::EventSetup&) override;
68 
69  // functions to get correct object collection for chosen object type
70  std::vector<HLTGenValObject> getObjectCollection(const edm::Event&);
71  std::vector<HLTGenValObject> getGenParticles(const edm::Event&);
74 
75  // ----------member data ---------------------------
76 
77  // tokens to get collections
83 
84  // config strings/Psets
87  std::vector<edm::ParameterSet> histConfigs_;
88  std::vector<edm::ParameterSet> histConfigs2D_;
89  std::vector<edm::ParameterSet> binnings_;
91 
92  // constructing the info string, which will be written to the output file for display of information in the GUI
93  // the string will have a JSON formating, thus starting here with the opening bracket, which will be close directly before saving to the root file
95 
96  // histogram collection per path
97  std::vector<HLTGenValHistCollPath> collectionPath_;
98 
99  // HLT config provider/getter
101 
102  // some miscellaneous member variables
103  std::vector<std::string> hltPathsToCheck_;
104  std::vector<std::string> hltPaths;
105  std::vector<std::string> hltPathSpecificCuts;
106  double dR2limit_;
108 };
109 
111  : genParticleToken_(consumes<reco::GenParticleCollection>(
112  iConfig.getParameterSet("inputCollections").getParameter<edm::InputTag>("genParticles"))),
113  genMETToken_(consumes<reco::GenMETCollection>(
114  iConfig.getParameterSet("inputCollections").getParameter<edm::InputTag>("genMET"))),
115  ak4genJetToken_(consumes<reco::GenJetCollection>(
116  iConfig.getParameterSet("inputCollections").getParameter<edm::InputTag>("ak4GenJets"))),
117  ak8genJetToken_(consumes<reco::GenJetCollection>(
118  iConfig.getParameterSet("inputCollections").getParameter<edm::InputTag>("ak8GenJets"))),
119  trigEventToken_(consumes<trigger::TriggerEvent>(
120  iConfig.getParameterSet("inputCollections").getParameter<edm::InputTag>("TrigEvent"))) {
121  // getting the histogram configurations
122  histConfigs_ = iConfig.getParameterSetVector("histConfigs");
123  histConfigs2D_ = iConfig.getParameterSetVector("histConfigs2D");
124  binnings_ = iConfig.getParameterSetVector("binnings");
125 
126  // getting all other configurations
127  dirName_ = iConfig.getParameter<std::string>("dqmDirName");
128  objType_ = iConfig.getParameter<std::string>("objType");
129  dR2limit_ = iConfig.getParameter<double>("dR2limit");
130  doOnlyLastFilter_ = iConfig.getParameter<bool>("doOnlyLastFilter");
131  hltProcessName_ = iConfig.getParameter<std::string>("hltProcessName");
132  hltPathsToCheck_ = iConfig.getParameter<std::vector<std::string>>("hltPathsToCheck");
133 }
134 
135 void HLTGenValSource::dqmBeginRun(const edm::Run& iRun, const edm::EventSetup& iSetup) {
136  // writing general information to info JSON
137  auto t = std::time(nullptr);
138  auto tm = *std::localtime(&t);
139 
140  // date and time of running this
141  std::ostringstream timeStringStream;
142  timeStringStream << std::put_time(&tm, "%d-%m-%Y %H-%M-%S");
143  auto timeString = timeStringStream.str();
144  infoString_ += "\"date & time\":\"" + timeString + "\",";
145 
146  // CMSSW version
147  [[clang::suppress]]
148  std::string cmsswVersion = std::getenv("CMSSW_VERSION");
149  infoString_ += std::string("\"CMSSW release\":\"") + cmsswVersion + "\",";
150 
151  // Initialize hltConfig, for cross-checking whether chosen paths exist
152  bool changedConfig;
153  if (!hltConfig_.init(iRun, iSetup, hltProcessName_, changedConfig)) {
154  edm::LogError("HLTGenValSource") << "Initialization of HLTConfigProvider failed!";
155  return;
156  }
157 
158  // global tag
159  infoString_ += std::string("\"global tag\":\"") + hltConfig_.globalTag() + "\",";
160 
161  // confDB table name
162  infoString_ += std::string("\"HLT ConfDB table\":\"") + hltConfig_.tableName() + "\",";
163 
164  // Get the set of trigger paths we want to make plots for
165  std::vector<std::string> notFoundPaths;
166  for (auto const& pathToCheck : hltPathsToCheck_) {
167  // It is possible to add additional requirements to each path, seperated by a colon from the path name
168  // these additional requirements are split from the path name here
169  std::string cleanedPathToCheck;
170  std::string pathSpecificCuts = "";
171  if (pathToCheck.find(':') != std::string::npos) {
172  // splitting the string
173  std::stringstream hltPathToCheckInputStream(pathToCheck);
174  std::string hltPathToCheckInputSegment;
175  std::vector<std::string> hltPathToCheckInputSeglist;
176  while (std::getline(hltPathToCheckInputStream, hltPathToCheckInputSegment, ':')) {
177  hltPathToCheckInputSeglist.push_back(hltPathToCheckInputSegment);
178  }
179 
180  // here, exactly two parts are expected
181  if (hltPathToCheckInputSeglist.size() != 2)
182  throw cms::Exception("InputError")
183  << "Path string can not be properly split into path and cuts: please use exactly one colon!.\n";
184 
185  // the first part is the name of the path
186  cleanedPathToCheck = hltPathToCheckInputSeglist.at(0);
187 
188  // second part are the cuts, to be parsed later
189  pathSpecificCuts = hltPathToCheckInputSeglist.at(1);
190 
191  } else {
192  cleanedPathToCheck = pathToCheck;
193  }
194 
195  bool pathfound = false;
196  for (auto const& pathFromConfig : hltConfig_.triggerNames()) {
197  if (pathFromConfig.find(cleanedPathToCheck) != std::string::npos) {
198  hltPaths.push_back(pathFromConfig);
199 
200  // in case the path was added twice, we'll add a tag automatically
201  int count = std::count(hltPaths.begin(), hltPaths.end(), pathFromConfig);
202  if (count > 1) {
203  pathSpecificCuts += std::string(",autotag=v") + std::to_string(count);
204  }
205  hltPathSpecificCuts.push_back(pathSpecificCuts);
206  pathfound = true;
207  }
208  }
209  if (!pathfound)
210  notFoundPaths.push_back(cleanedPathToCheck);
211  }
212  if (!notFoundPaths.empty()) {
213  // error handling in case some paths do not exist
214  std::string notFoundPathsMessage = "";
215  for (const auto& path : notFoundPaths)
216  notFoundPathsMessage += "- " + path + "\n";
217  edm::LogError("HLTGenValSource") << "The following paths could not be found and will not be used: \n"
218  << notFoundPathsMessage << std::endl;
219  }
220 
221  // before creating the collections for each path, we'll store the needed configurations in a pset
222  // we'll copy this base multiple times and add the respective path
223  // most of these options are not needed in the pathColl, but in the filterColls created in the pathColl
224  edm::ParameterSet pathCollConfig;
225  pathCollConfig.addParameter<std::string>("objType", objType_);
226  pathCollConfig.addParameter<double>("dR2limit", dR2limit_);
227  pathCollConfig.addParameter<bool>("doOnlyLastFilter", doOnlyLastFilter_);
228  pathCollConfig.addParameter<std::string>("hltProcessName", hltProcessName_);
229 
230  // creating a histogram collection for each path
231  for (const auto& path : hltPaths) {
232  edm::ParameterSet pathCollConfigStep = pathCollConfig;
233  pathCollConfigStep.addParameter<std::string>("triggerPath", path);
234  collectionPath_.emplace_back(HLTGenValHistCollPath(pathCollConfigStep, hltConfig_));
235  }
236 }
237 
238 // ------------ method called for each event ------------
240  // creating the collection of HLTGenValObjects
241  const std::vector<HLTGenValObject> objects = getObjectCollection(iEvent);
242 
243  // init triggerEvent, which is always needed
245  iEvent.getByToken(trigEventToken_, triggerEvent);
246 
247  // loop over all objects and fill hists
248  for (const auto& object : objects) {
249  for (auto& collection_path : collectionPath_) {
250  collection_path.fillHists(object, triggerEvent);
251  }
252  }
253 }
254 
255 // ------------ method called once each job just before starting event loop ------------
257  iBooker.setCurrentFolder(dirName_);
258 
259  if (infoString_.back() == ',')
260  infoString_.pop_back();
261  infoString_ += "}"; // adding the closing bracked to the JSON string
262  iBooker.bookString("HLTGenValInfo", infoString_);
263 
264  // booking all histograms
265  for (long unsigned int i = 0; i < collectionPath_.size(); i++) {
266  std::vector<edm::ParameterSet> histConfigs = histConfigs_;
267  for (auto& histConfig : histConfigs) {
268  histConfig.addParameter<std::string>("pathSpecificCuts", hltPathSpecificCuts.at(i));
269  histConfig.addParameter<std::vector<edm::ParameterSet>>("binnings",
270  binnings_); // passing along the user-defined binnings
271  }
272 
273  collectionPath_.at(i).bookHists(iBooker, histConfigs, histConfigs2D_);
274  }
275 }
276 
277 // ------------ method fills 'descriptions' with the allowed parameters for the module ------------
280 
281  // basic parameter strings
282  desc.add<std::string>(
283  "objType"); // this deliberately has no default, as this is the main thing the user needs to chose
284  desc.add<std::vector<std::string>>(
285  "hltPathsToCheck"); // this for the moment also has no default: maybe there can be some way to handle this later?
286  desc.add<std::string>("dqmDirName", "HLTGenVal");
287  desc.add<std::string>("hltProcessName", "HLT");
288  desc.add<double>("dR2limit", 0.1);
289  desc.add<bool>("doOnlyLastFilter", false);
290 
291  // input collections, a PSet
292  edm::ParameterSetDescription inputCollections;
293  inputCollections.add<edm::InputTag>("genParticles", edm::InputTag("genParticles"));
294  inputCollections.add<edm::InputTag>("genMET", edm::InputTag("genMetTrue"));
295  inputCollections.add<edm::InputTag>("ak4GenJets", edm::InputTag("ak4GenJets"));
296  inputCollections.add<edm::InputTag>("ak8GenJets", edm::InputTag("ak8GenJets"));
297  inputCollections.add<edm::InputTag>("TrigEvent", edm::InputTag("hltTriggerSummaryAOD"));
298  desc.add<edm::ParameterSetDescription>("inputCollections", inputCollections);
299 
300  // hist descriptors, which are a vector of PSets
301 
302  // defining single histConfig
303  // this is generally without default, but a default set of histConfigs is specified below
304  edm::ParameterSetDescription histConfig;
305  histConfig.add<std::string>("vsVar");
306  histConfig.add<std::vector<double>>("binLowEdges");
307  histConfig.addVPSet(
308  "rangeCuts", VarRangeCut<HLTGenValObject>::makePSetDescription(), std::vector<edm::ParameterSet>());
309 
310  // default set of histConfigs
311  std::vector<edm::ParameterSet> histConfigDefaults;
312 
313  edm::ParameterSet histConfigDefault0;
314  histConfigDefault0.addParameter<std::string>("vsVar", "pt");
315  std::vector<double> defaultPtBinning{0, 5, 10, 12.5, 15, 17.5, 20, 22.5, 25, 30, 35, 40,
316  45, 50, 60, 80, 100, 150, 200, 250, 300, 350, 400};
317  histConfigDefault0.addParameter<std::vector<double>>("binLowEdges", defaultPtBinning);
318  histConfigDefaults.push_back(histConfigDefault0);
319 
320  edm::ParameterSet histConfigDefault1;
321  histConfigDefault1.addParameter<std::string>("vsVar", "eta");
322  std::vector<double> defaultetaBinning{-10, -8, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 8, 10};
323  histConfigDefault1.addParameter<std::vector<double>>("binLowEdges", defaultetaBinning);
324  histConfigDefaults.push_back(histConfigDefault1);
325 
326  desc.addVPSet("histConfigs", histConfig, histConfigDefaults);
327 
328  // defining single histConfig2D
329  edm::ParameterSetDescription histConfig2D;
330  histConfig2D.add<std::string>("vsVarX");
331  histConfig2D.add<std::string>("vsVarY");
332  histConfig2D.add<std::vector<double>>("binLowEdgesX");
333  histConfig2D.add<std::vector<double>>("binLowEdgesY");
334 
335  // default set of histConfigs
336  std::vector<edm::ParameterSet> histConfigDefaults2D;
337 
338  edm::ParameterSet histConfigDefault2D0;
339  histConfigDefault2D0.addParameter<std::string>("vsVarX", "pt");
340  histConfigDefault2D0.addParameter<std::string>("vsVarY", "eta");
341  histConfigDefault2D0.addParameter<std::vector<double>>("binLowEdgesX", defaultPtBinning);
342  histConfigDefault2D0.addParameter<std::vector<double>>("binLowEdgesY", defaultetaBinning);
343  histConfigDefaults2D.push_back(histConfigDefault2D0);
344 
345  desc.addVPSet("histConfigs2D", histConfig2D, histConfigDefaults2D);
346 
347  // binnings, which are vectors of PSets
348  // there are no default for this
349  edm::ParameterSetDescription binningConfig;
350  binningConfig.add<std::string>("name");
351  binningConfig.add<std::string>("vsVar");
352  binningConfig.add<std::vector<double>>("binLowEdges");
353 
354  // this by default is empty
355  std::vector<edm::ParameterSet> binningConfigDefaults;
356 
357  desc.addVPSet("binnings", binningConfig, binningConfigDefaults);
358 
359  descriptions.addDefault(desc);
360 }
361 
362 // this method handles the different object types and collections that can be used for efficiency calculation
363 std::vector<HLTGenValObject> HLTGenValSource::getObjectCollection(const edm::Event& iEvent) {
364  std::vector<HLTGenValObject> objects; // the vector of objects to be filled
365 
366  // handle object type
367  std::vector<std::string> implementedGenParticles = {"ele", "pho", "mu", "tau"};
368  if (std::find(implementedGenParticles.begin(), implementedGenParticles.end(), objType_) !=
369  implementedGenParticles.end()) {
371  } else if (objType_ == "AK4jet") { // ak4 jets, using the ak4GenJets collection
372  const auto& genJets = iEvent.getHandle(ak4genJetToken_);
373  for (size_t i = 0; i < genJets->size(); i++) {
374  const reco::GenJet p = (*genJets)[i];
375  objects.emplace_back(p);
376  }
377  } else if (objType_ == "AK8jet") { // ak8 jets, using the ak8GenJets collection
378  const auto& genJets = iEvent.getHandle(ak8genJetToken_);
379  for (size_t i = 0; i < genJets->size(); i++) {
380  const reco::GenJet p = (*genJets)[i];
381  objects.emplace_back(p);
382  }
383  } else if (objType_ == "AK4HT") { // ak4-based HT, using the ak4GenJets collection
384  const auto& genJets = iEvent.getHandle(ak4genJetToken_);
385  if (!genJets->empty()) {
386  double HTsum = 0.;
387  for (const auto& genJet : *genJets) {
388  if (genJet.pt() > 30 && std::abs(genJet.eta()) < 2.5)
389  HTsum += genJet.pt();
390  }
391  if (HTsum > 0)
392  objects.emplace_back(reco::Candidate::PolarLorentzVector(HTsum, 0, 0, 0));
393  }
394  } else if (objType_ == "AK8HT") { // ak8-based HT, using the ak8GenJets collection
395  const auto& genJets = iEvent.getHandle(ak8genJetToken_);
396  if (!genJets->empty()) {
397  double HTsum = 0.;
398  for (const auto& genJet : *genJets) {
399  if (genJet.pt() > 200 && std::abs(genJet.eta()) < 2.5)
400  HTsum += genJet.pt();
401  }
402  if (HTsum > 0)
403  objects.emplace_back(reco::Candidate::PolarLorentzVector(HTsum, 0, 0, 0));
404  }
405  } else if (objType_ == "MET") { // MET, using genMET
406  const auto& genMET = iEvent.getHandle(genMETToken_);
407  if (!genMET->empty()) {
408  auto genMETpt = (*genMET)[0].pt();
409  objects.emplace_back(reco::Candidate::PolarLorentzVector(genMETpt, 0, 0, 0));
410  }
411  } else
412  throw cms::Exception("InputError") << "Generator-level validation is not available for type " << objType_ << ".\n"
413  << "Please check for a potential spelling error.\n";
414 
415  return objects;
416 }
417 
418 // in case of GenParticles, a subset of the entire collection needs to be chosen
419 std::vector<HLTGenValObject> HLTGenValSource::getGenParticles(const edm::Event& iEvent) {
420  std::vector<HLTGenValObject> objects; // vector to be filled
421 
422  const auto& genParticles = iEvent.getHandle(genParticleToken_); // getting all GenParticles
423 
424  // we need to ge the ID corresponding to the desired GenParticle type
425  int pdgID = -1; // setting to -1 should not be needed, but prevents the compiler warning :)
426  if (objType_ == "ele")
427  pdgID = 11;
428  else if (objType_ == "pho")
429  pdgID = 22;
430  else if (objType_ == "mu")
431  pdgID = 13;
432  else if (objType_ == "tau")
433  pdgID = 15;
434 
435  // main loop over GenParticles
436  for (size_t i = 0; i < genParticles->size(); ++i) {
437  const reco::GenParticle p = (*genParticles)[i];
438 
439  // only GenParticles with correct ID
440  if (std::abs(p.pdgId()) != pdgID)
441  continue;
442 
443  // checking if particle comes from "hard process"
444  if (p.isHardProcess()) {
445  // depending on the particle type, last particle before or after FSR is chosen
446  if ((objType_ == "ele") || (objType_ == "pho"))
447  objects.emplace_back(getLastCopyPreFSR(p));
448  else if ((objType_ == "mu") || (objType_ == "tau"))
449  objects.emplace_back(getLastCopy(p));
450  }
451  }
452 
453  return objects;
454 }
455 
456 // function returning the last GenParticle in a decay chain before FSR
458  const auto& daughters = part.daughterRefVector();
459  if (daughters.size() == 1 && daughters.at(0)->pdgId() == part.pdgId())
460  return getLastCopyPreFSR(*daughters.at(0).get()); // recursion, whooo
461  else
462  return part;
463 }
464 
465 // function returning the last GenParticle in a decay chain
467  for (const auto& daughter : part.daughterRefVector()) {
468  if (daughter->pdgId() == part.pdgId())
469  return getLastCopy(*daughter.get());
470  }
471  return part;
472 }
473 
474 //define this as a framework plug-in
std::vector< GenParticle > GenParticleCollection
collection of GenParticles
std::string objType_
T getParameter(std::string const &) const
Definition: ParameterSet.h:307
Collection of Gen MET.
std::string hltProcessName_
virtual void setCurrentFolder(std::string const &fullpath)
Definition: DQMStore.cc:36
reco::GenParticle getLastCopy(reco::GenParticle part)
const std::string & globalTag() const
global tag
std::vector< GenJet > GenJetCollection
collection of GenJet objects
std::vector< std::string > hltPaths
Log< level::Error, false > LogError
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:19
void dqmBeginRun(const edm::Run &, const edm::EventSetup &) override
static std::string to_string(const XMLCh *ch)
std::vector< edm::ParameterSet > binnings_
MonitorElement * bookString(TString const &name, TString const &value, FUNC onbooking=NOOP())
Definition: DQMStore.h:87
const edm::EDGetTokenT< reco::GenParticleCollection > genParticleToken_
int iEvent
Definition: GenABIO.cc:224
void addDefault(ParameterSetDescription const &psetDescription)
std::vector< HLTGenValObject > getObjectCollection(const edm::Event &)
void addParameter(std::string const &name, T const &value)
Definition: ParameterSet.h:136
std::string infoString_
HLTGenValSource(const edm::ParameterSet &)
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
Jets made from MC generator particles.
Definition: GenJet.h:23
const edm::EDGetTokenT< reco::GenJetCollection > ak8genJetToken_
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
std::vector< std::string > hltPathsToCheck_
ParameterDescriptionBase * add(U const &iLabel, T const &value)
const edm::EDGetTokenT< trigger::TriggerEvent > trigEventToken_
const edm::EDGetTokenT< reco::GenJetCollection > ak4genJetToken_
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
std::vector< edm::ParameterSet > histConfigs_
std::vector< HLTGenValObject > getGenParticles(const edm::Event &)
HLTConfigProvider hltConfig_
part
Definition: HCALResponse.h:20
std::string dirName_
bool init(const edm::Run &iRun, const edm::EventSetup &iSetup, const std::string &processName, bool &changed)
d&#39;tor
std::vector< edm::ParameterSet > histConfigs2D_
std::vector< std::string > hltPathSpecificCuts
const std::vector< std::string > & triggerNames() const
names of trigger paths
ParameterSet const & getParameterSet(ParameterSetID const &id)
fixed size matrix
const std::string & tableName() const
HLT ConfDB table name.
HLT enums.
VParameterSet const & getParameterSetVector(std::string const &name) const
~HLTGenValSource() override=default
const edm::EDGetTokenT< reco::GenMETCollection > genMETToken_
void bookHistograms(DQMStore::IBooker &, edm::Run const &run, edm::EventSetup const &c) override
void analyze(const edm::Event &, const edm::EventSetup &) override
HLTGenValSource & operator=(const HLTGenValSource &)=delete
reco::GenParticle getLastCopyPreFSR(reco::GenParticle part)
std::vector< HLTGenValHistCollPath > collectionPath_
Definition: Run.h:45
math::PtEtaPhiMLorentzVector PolarLorentzVector
Lorentz vector.
Definition: Candidate.h:38