diff --git a/DQMOffline/Trigger/src/FunctionDefs.cc b/DQMOffline/Trigger/src/FunctionDefs.cc index 334052cc3c83c..6545fc1332cea 100644 --- a/DQMOffline/Trigger/src/FunctionDefs.cc +++ b/DQMOffline/Trigger/src/FunctionDefs.cc @@ -20,3 +20,12 @@ std::function hltdqm::getUnaryFuncExtraFloat float { return pho.hadTowOverEm(); }; return varFunc; } + +//hack to put the function definitions in the non-plugin libary +//so they can be used by other packages +#include "DataFormats/EgammaCandidates/interface/GsfElectron.h" +#include "DataFormats/EgammaCandidates/interface/Photon.h" +#include "DataFormats/MuonReco/interface/Muon.h" +auto testPho = hltdqm::getUnaryFuncFloat("et"); +auto testEle = hltdqm::getUnaryFuncFloat("et"); +auto testMu = hltdqm::getUnaryFuncFloat("et"); diff --git a/Validation/HLTrigger/BuildFile.xml b/Validation/HLTrigger/BuildFile.xml new file mode 100644 index 0000000000000..2daa1786b213f --- /dev/null +++ b/Validation/HLTrigger/BuildFile.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/Validation/HLTrigger/interface/HLTGenValHist.h b/Validation/HLTrigger/interface/HLTGenValHist.h new file mode 100644 index 0000000000000..1bbaf228cab81 --- /dev/null +++ b/Validation/HLTrigger/interface/HLTGenValHist.h @@ -0,0 +1,84 @@ +#ifndef Validation_HLTrigger_HLTGenValHist_h +#define Validation_HLTrigger_HLTGenValHist_h + +//******************************************************************************** +// +// Description: +// Histogram holder class for the GEN-level HLT validation +// Handling and filling of 1D and 2D histograms is done by this class. +// +// +// Author : Finn Labe, UHH, Jul. 2022 +// (Strongly inspired by Sam Harpers HLTDQMHist class) +// +//*********************************************************************************** + +#include "DQMOffline/Trigger/interface/FunctionDefs.h" + +#include "DQMOffline/Trigger/interface/VarRangeCutColl.h" + +#include "FWCore/Framework/interface/Event.h" + +#include "Validation/HLTrigger/interface/HLTGenValObject.h" + +#include +#include + +// base histogram class, with specific implementations following below +class HLTGenValHist { +public: + HLTGenValHist() = default; + virtual ~HLTGenValHist() = default; + virtual void fill(const HLTGenValObject& objType) = 0; +}; + +// specific implimentation of a HLTGenValHist for 1D histograms +// it takes the histogram which it will fill +// it takes the variable to plot (func) and its name (varName) +// also, it takes additional cuts (rangeCuts) applied before filling +// to fill the histogram, an object is passed in the Fill function +class HLTGenValHist1D : public HLTGenValHist { +public: + HLTGenValHist1D(TH1* hist, + std::string varName, + std::function func, + VarRangeCutColl rangeCuts) + : var_(std::move(func)), varName_(std::move(varName)), rangeCuts_(std::move(rangeCuts)), hist_(hist) {} + + void fill(const HLTGenValObject& obj) override { + if(rangeCuts_(obj)) hist_->Fill(var_(obj)); + } + +private: + std::function var_; + std::string varName_; + VarRangeCutColl rangeCuts_; + TH1* hist_; //we do not own this +}; + +// specific implimentation of a HLTGenValHist for 2D histograms +// it takes the histogram which it will fill +// it takes the two variable to plot (func) and their name (varName) +// to fill the histogram, two objects are passed in the Fill function +class HLTGenValHist2D : public HLTGenValHist { +public: + HLTGenValHist2D(TH2* hist, + std::string varNameX, + std::string varNameY, + std::function funcX, + std::function funcY) + : varX_(std::move(funcX)), varY_(std::move(funcY)), varNameX_(std::move(varNameX)), varNameY_(std::move(varNameY)), hist_(hist) {} + + void fill(const HLTGenValObject& obj) override { + hist_->Fill(varX_(obj), varY_(obj)); + } + +private: + std::function varX_; + std::function varY_; + std::string varNameX_; + std::string varNameY_; + TH2* hist_; //we do not own this +}; + +#endif diff --git a/Validation/HLTrigger/interface/HLTGenValHistCollFilter.h b/Validation/HLTrigger/interface/HLTGenValHistCollFilter.h new file mode 100644 index 0000000000000..0dfe064c1decf --- /dev/null +++ b/Validation/HLTrigger/interface/HLTGenValHistCollFilter.h @@ -0,0 +1,61 @@ +#ifndef Validation_HLTrigger_HLTGenValHistCollFilter_h +#define Validation_HLTrigger_HLTGenValHistCollFilter_h + +//******************************************************************************** +// +// Description: +// This class contains a collection of HLTGenvalHists used to measure the efficiency of a +// specified filter. It is resonsible for booking and filling the histograms of all vsVars +// histograms that are created for a specific filter. +// +// Author : Finn Labe, UHH, Jul. 2022 +// (Strongly inspired by Sam Harpers HLTDQMFilterEffHists class) +// +//*********************************************************************************** + +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" + +#include "DQMServices/Core/interface/DQMStore.h" + +#include "DataFormats/HLTReco/interface/TriggerEvent.h" + +#include "Validation/HLTrigger/interface/HLTGenValHist.h" +#include "DQMOffline/Trigger/interface/FunctionDefs.h" +#include "DQMOffline/Trigger/interface/UtilFuncs.h" + +#include "Validation/HLTrigger/interface/HLTGenValObject.h" +#include "Validation/HLTrigger/interface/HLTGenValPathSpecificSettingParser.h" + +#include "DataFormats/Math/interface/deltaR.h" + +#include + +// class containing a collection of HLTGenValHist for a specific filter +// functions for initial booking of hists, and filling of hists for a single object are available +class HLTGenValHistCollFilter { +public: + typedef dqm::legacy::MonitorElement MonitorElement; + typedef dqm::legacy::DQMStore DQMStore; + + explicit HLTGenValHistCollFilter(edm::ParameterSet filterCollConfig); + + static edm::ParameterSetDescription makePSetDescription(); + + void bookHists(DQMStore::IBooker& iBooker, const std::vector& histConfigs, const std::vector& histConfigs2D); + void fillHists(const HLTGenValObject& obj, edm::Handle& triggerEvent); + +private: + void book1D(DQMStore::IBooker& iBooker, const edm::ParameterSet& histConfig); + void book2D(DQMStore::IBooker& iBooker, const edm::ParameterSet& histConfig2D); + + std::vector> hists_; // the collection of histograms + std::string objType_; + std::string tag_; + std::string filter_; + std::string path_; + std::string hltProcessName_; + double dR2limit_; +}; + +#endif diff --git a/Validation/HLTrigger/interface/HLTGenValHistCollPath.h b/Validation/HLTrigger/interface/HLTGenValHistCollPath.h new file mode 100644 index 0000000000000..8bad30c793cea --- /dev/null +++ b/Validation/HLTrigger/interface/HLTGenValHistCollPath.h @@ -0,0 +1,59 @@ +#ifndef Validation_HLTrigger_HLTGenValHistCollPath_h +#define Validation_HLTrigger_HLTGenValHistCollPath_h + +//******************************************************************************** +// +// Description: +// This contains a collection of HLTGenValHistCollFilter used to measure the efficiencies of all +// filters in a specified path. The actual booking and filling happens in the respective HLTGenValHistCollFilters. +// +// Author : Finn Labe, UHH, Oct. 2021 +// (Heavily borrowed from Sam Harpers HLTDQMFilterEffHists) +// +//*********************************************************************************** + +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" + +#include "DQMServices/Core/interface/DQMStore.h" + +#include "DataFormats/HLTReco/interface/TriggerEvent.h" + +#include "DQMOffline/Trigger/interface/FunctionDefs.h" +#include "DQMOffline/Trigger/interface/UtilFuncs.h" + +#include "Validation/HLTrigger/interface/HLTGenValHistCollFilter.h" +#include "HLTrigger/HLTcore/interface/HLTConfigProvider.h" + +#include "Validation/HLTrigger/interface/HLTGenValObject.h" + +// class containing a collection of HLTGenValHistCollFilters for a specific path +// at object creation time, the object type (used for systematically naming the histogram), +// triggerPath, hltConfig and dR2limit (for deltaR matching) need to be specified +// functions for initial booking of hists, and filling of hists for a single object, are available +class HLTGenValHistCollPath { +public: + typedef dqm::legacy::MonitorElement MonitorElement; + typedef dqm::legacy::DQMStore DQMStore; + + explicit HLTGenValHistCollPath(edm::ParameterSet pathCollConfig, HLTConfigProvider& hltConfig); + + static edm::ParameterSetDescription makePSetDescription(); + + void bookHists(DQMStore::IBooker& iBooker, std::vector& histConfigs, std::vector& histConfigs2D); + void fillHists(const HLTGenValObject& obj, edm::Handle& triggerEvent); + +private: + std::string triggerPath_; + std::vector collectionFilter_; + std::vector filters_; + HLTConfigProvider hltConfig_; + bool doOnlyLastFilter_; + + // we will add a string to the root file that is named after the path + // it will contain the filters of that path divided by semicola + std::string pathStringName_; + std::string pathString_; +}; + +#endif diff --git a/Validation/HLTrigger/interface/HLTGenValObject.h b/Validation/HLTrigger/interface/HLTGenValObject.h new file mode 100644 index 0000000000000..7719bba7656a2 --- /dev/null +++ b/Validation/HLTrigger/interface/HLTGenValObject.h @@ -0,0 +1,51 @@ +#ifndef Validation_HLTrigger_HLTGenValObject_h +#define Validation_HLTrigger_HLTGenValObject_h + +//******************************************************************************** +// +// Description: +// This class is an object wrapper for the Generator level validation code. +// It handles the different type of objects the code needs to run on: GenParticles, GenJets and event-level energy sums +// +// Author : Finn Labe, UHH, Nov. 2021 +// +//******************************************************************************** + + +#include "DataFormats/HepMCCandidate/interface/GenParticle.h" +#include "DataFormats/JetReco/interface/GenJet.h" + +#include "DataFormats/Math/interface/LorentzVector.h" +#include + +class HLTGenValObject { +public: + + // empty constructor + HLTGenValObject() {} + + // constructor from GenParticle + HLTGenValObject(const reco::GenParticle &p) + : p4Polar_(p.p4()), p4Cartesian_(p.p4()) {} + + // constructor from GenJet + HLTGenValObject(const reco::GenJet &p) + : p4Polar_(p.p4()), p4Cartesian_(p.p4()) {} + + // constructor from LorentzVector (for energy sums) + HLTGenValObject(const reco::Candidate::PolarLorentzVector& p) + : p4Polar_(p), p4Cartesian_(p) {} + + // object functions, for usage of HLTGenValObjects by other modules + double pt() const { return p4Polar_.pt(); } + double eta() const { return p4Polar_.eta(); } + double phi() const { return p4Polar_.phi(); } + double et() const { return (pt() <= 0) ? 0 : p4Cartesian_.Et(); } + +private: + // containing information in two "shapes" + math::PtEtaPhiMLorentzVector p4Polar_; + math::XYZTLorentzVector p4Cartesian_; +}; + +#endif diff --git a/Validation/HLTrigger/interface/HLTGenValPathSpecificSettingParser.h b/Validation/HLTrigger/interface/HLTGenValPathSpecificSettingParser.h new file mode 100644 index 0000000000000..a3874a6068fe4 --- /dev/null +++ b/Validation/HLTrigger/interface/HLTGenValPathSpecificSettingParser.h @@ -0,0 +1,40 @@ +#ifndef Validation_HLTrigger_HLTGenValPathSpecificSettingParser_h +#define Validation_HLTrigger_HLTGenValSpecificCutParser_h + +//******************************************************************************** +// +// Description: +// This class handles parsing of additional settings that can be set for each path in the generator-level validation module +// Mainly, these are cuts in addition to the ones specified in the module. Passing a pre-defined region is also possible +// The binning of a certain variable can be changed through this class, as well as setting a tag for all histograms of a path. +// +// Author : Finn Labe, UHH, Jul. 2022 +// +//******************************************************************************** + +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" + +#include "DQMServices/Core/interface/DQMStore.h" + +#include + +class HLTGenValPathSpecificSettingParser { +public: + + // constructor + HLTGenValPathSpecificSettingParser(std::string pathSpecificSettings, std::vector binnings, std::string vsVar); + + std::vector getPathSpecificCuts() {return pathSpecificCutsVector_;} + std::vector getPathSpecificBins() {return pathSpecificBins_;} + bool havePathSpecificBins() { return (!pathSpecificBins_.empty()); } + std::string getTag() {return tag_;} + +private: + std::vector pathSpecificCutsVector_; + std::vector pathSpecificBins_; + std::string tag_ = ""; + +}; + +#endif diff --git a/Validation/HLTrigger/plugins/BuildFile.xml b/Validation/HLTrigger/plugins/BuildFile.xml new file mode 100644 index 0000000000000..3f6fcd3d7bf11 --- /dev/null +++ b/Validation/HLTrigger/plugins/BuildFile.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/Validation/HLTrigger/plugins/HLTGenValClient.cc b/Validation/HLTrigger/plugins/HLTGenValClient.cc new file mode 100644 index 0000000000000..359bb44ab1a3c --- /dev/null +++ b/Validation/HLTrigger/plugins/HLTGenValClient.cc @@ -0,0 +1,435 @@ +//******************************************************************************** +// +// Description: +// DQM histogram post processor for the HLT Gen validation source module +// Given a folder name, this module will find histograms before and after +// HLT filters and produce efficiency histograms from these. +// The structure of this model is strongly inspired by the DQMGenericClient, +// replacing most user input parameters by the automatic parsing of the given directory. +// +// Author: Finn Labe, UHH, Jul. 2022 +// Inspired by DQMGenericClient from Junghwan Goh - SungKyunKwan University +//******************************************************************************** + +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ServiceRegistry/interface/Service.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "DQMServices/Core/interface/DQMEDHarvester.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +class HLTGenValClient : public DQMEDHarvester { +public: + HLTGenValClient(const edm::ParameterSet& pset); + ~HLTGenValClient() override{}; + + void dqmEndLuminosityBlock(DQMStore::IBooker& ibooker, + DQMStore::IGetter& igetter, + const edm::LuminosityBlock& lumiSeg, + const edm::EventSetup& c) override; + void dqmEndRun(DQMStore::IBooker&, DQMStore::IGetter&, edm::Run const&, edm::EventSetup const&) override; + void dqmEndJob(DQMStore::IBooker&, DQMStore::IGetter&) override{}; + + struct EfficOption { + std::string name, title; + std::string numerator, denominator; + }; + + void computeEfficiency(DQMStore::IBooker& ibooker, + DQMStore::IGetter& igetter, + const std::string& dirName, + const std::string& efficMEName, + const std::string& efficMETitle, + const std::string& numeratorMEName, + const std::string& denominatorMEName + ); + +private: + TPRegexp metacharacters_; + TPRegexp nonPerlWildcard_; + unsigned int verbose_; + bool runOnEndLumi_; + bool runOnEndJob_; + bool makeGlobalEffPlot_; + bool isWildcardUsed_; + + DQMStore* theDQM; + std::vector subDirs_; + std::string outputFileName_; + + std::vector efficOptions_; + + void makeAllPlots(DQMStore::IBooker&, DQMStore::IGetter&); + + void findAllSubdirectories(DQMStore::IBooker& ibooker, + DQMStore::IGetter& igetter, + std::string dir, + std::set* myList, + const TString& pattern); + + void genericEff(TH1* denom, TH1* numer, MonitorElement* efficiencyHist); + + +}; + +HLTGenValClient::HLTGenValClient(const edm::ParameterSet& pset) + : metacharacters_("[\\^\\$\\.\\*\\+\\?\\|\\(\\)\\{\\}\\[\\]]"), nonPerlWildcard_("\\w\\*|^\\*") { + + boost::escaped_list_separator commonEscapes("\\", " \t", "\'"); + + verbose_ = pset.getUntrackedParameter("verbose", 0); + runOnEndLumi_ = pset.getUntrackedParameter("runOnEndLumi", false); + runOnEndJob_ = pset.getUntrackedParameter("runOnEndJob", true); + makeGlobalEffPlot_ = pset.getUntrackedParameter("makeGlobalEffienciesPlot", true); + + outputFileName_ = pset.getUntrackedParameter("outputFileName", ""); + subDirs_ = pset.getUntrackedParameter>("subDirs"); + + isWildcardUsed_ = false; +} + +void HLTGenValClient::dqmEndLuminosityBlock(DQMStore::IBooker& ibooker, + DQMStore::IGetter& igetter, + const edm::LuminosityBlock& lumiSeg, + const edm::EventSetup& c) { + if (runOnEndLumi_) { + makeAllPlots(ibooker, igetter); + } +} + +void HLTGenValClient::dqmEndRun(DQMStore::IBooker& ibooker, + DQMStore::IGetter& igetter, + edm::Run const&, + edm::EventSetup const&) { + + // Create new MEs in endRun, even though we are requested to do it in endJob. + // This gives the QTests a chance to run, before summaries are created in + // endJob. The negative side effect is that we cannot run the GenericClient + // for plots produced in Harvesting, but that seems rather rare. + // + // It is important that this is still save in the presence of multiple runs, + // first because in multi-run harvesting, we accumulate statistics over all + // runs and have full statistics at the endRun of the last run, and second, + // because we set the efficiencyFlag so any further aggregation should produce + // correct results. Also, all operations should be idempotent; running them + // more than once does no harm. + + theDQM = edm::Service().operator->(); + + if (runOnEndJob_) { + makeAllPlots(ibooker, igetter); + } + + if (!outputFileName_.empty()) + theDQM->save(outputFileName_); +} + +// the main method that creates the plots +void HLTGenValClient::makeAllPlots(DQMStore::IBooker& ibooker, DQMStore::IGetter& igetter) { + + // Process wildcard in the sub-directory + std::set subDirSet; + for (auto & subDir : subDirs_) { + + if (subDir[subDir.size() - 1] == '/') + subDir.erase(subDir.size() - 1); + + if (TString(subDir).Contains(metacharacters_)) { + isWildcardUsed_ = true; + + const std::string::size_type shiftPos = subDir.rfind('/'); + const std::string searchPath = subDir.substr(0, shiftPos); + const std::string pattern = subDir.substr(shiftPos + 1, subDir.length()); + + findAllSubdirectories(ibooker, igetter, searchPath, &subDirSet, pattern); + + } else { + subDirSet.insert(subDir); + } + } + + // loop through all sub-directories + // from the current implementation of the HLTGenValSource, we expect all histograms in a single directory + // however, this module is also capable of handling sub-directories, if needed + for (std::set::const_iterator iSubDir = subDirSet.begin(); iSubDir != subDirSet.end(); ++iSubDir) { + const std::string& dirName = *iSubDir; + + // construct efficiency options automatically from systematically names histograms^ + const auto contents = igetter.getAllContents(dirName); + for (const auto & content : contents) { + + // splitting the input string + std::stringstream namestream(content->getName()); + std::string namesegment; + std::vector seglist; + while(std::getline(namestream, namesegment, ':')) + { + seglist.push_back(namesegment); + } + + if(seglist.size() == 4 || seglist.size() == 5) { // this should be the only "proper" files we want to look at. 5 means that a custom tag was set! + if(seglist.at(2) == "GEN") continue; // this is the "before" hist, we won't create an effiency from this alone + + // if a fifth entry exists, it is expected to be the custom tag + std::string tag = ""; + if(seglist.size() == 5) tag = seglist.at(4); + + // first we determing whether we have the 1D or 2D case + if(seglist.at(3).rfind("2D", 0) == 0) { + + // 2D case + EfficOption opt; + opt.name = seglist.at(0) + ":" + seglist.at(1) + ":" + seglist.at(2) + ":" + seglist.at(3) + ":eff"; // efficiency histogram name + opt.title = seglist.at(0) + " " + seglist.at(1) + " " + seglist.at(2) + " " + seglist.at(3) + " efficiency"; // efficiency histogram title + opt.numerator = content->getName(); // numerator histogram (after a filter) + opt.denominator = seglist.at(0) + ":" + seglist.at(1) + ":GEN:" + seglist.at(3); // denominator histogram (before all filters) + + efficOptions_.push_back(opt); + + } else { + + // 1D case + EfficOption opt; + opt.name = seglist.at(0) + ":" + seglist.at(1) + ":" + seglist.at(2) + ":" + seglist.at(3) + ":eff"; // efficiency histogram name + opt.title = seglist.at(0) + " " + seglist.at(1) + " " + seglist.at(2) + " " + seglist.at(3) + " efficiency"; // efficiency histogram title + opt.numerator = content->getName(); // numerator histogram (after a filter) + opt.denominator = seglist.at(0) + ":" + seglist.at(1) + ":GEN:" + seglist.at(3); // denominator histogram (before all filters) + + // propagating the custom tag to the efficiency + if(!tag.empty()) { + opt.name += ":" + tag; + opt.title += " " + tag; + opt.denominator += ":" + tag; + } + + efficOptions_.push_back(opt); + + } + } + } + + // now that we have all EfficOptions, we create the histograms + for (const auto& efficOption : efficOptions_){ + computeEfficiency(ibooker, igetter, dirName, efficOption.name, efficOption.title, efficOption.numerator, efficOption.denominator); + } + + } +} + +// main method of efficiency computation, called once for each EfficOption +void HLTGenValClient::computeEfficiency(DQMStore::IBooker& ibooker, + DQMStore::IGetter& igetter, + const std::string& dirName, + const std::string& efficMEName, + const std::string& efficMETitle, + const std::string& numeratorMEName, + const std::string& denominatorMEName) { + + // checking if directory exists + if (!igetter.dirExists(dirName)) { + if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { + edm::LogError("HLTGenValClient") << "computeEfficiency() : " << "Cannot find sub-directory " << dirName << std::endl; + } + return; + } + + ibooker.cd(); + + // getting input MEs + HLTGenValClient::MonitorElement* denominatorME = igetter.get(dirName + "/" + denominatorMEName); + HLTGenValClient::MonitorElement* numeratorME = igetter.get(dirName + "/" + numeratorMEName); + + // checking of input MEs exist + if (!denominatorME) { + if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { + edm::LogError("HLTGenValClient") << "computeEfficiency() : " << "No denominator-ME '" << denominatorMEName << "' found\n"; + } + return; + } + if (!numeratorME) { + if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { + edm::LogError("HLTGenValClient") << "computeEfficiency() : " << "No numerator-ME '" << numeratorMEName << "' found\n"; + } + return; + } + + + // Treat everything as the base class, TH1 + TH1* hDenominator = denominatorME->getTH1(); + TH1* hNumerator = numeratorME->getTH1(); + + // check if TH1 extraction has succeeded + if (!hDenominator || !hNumerator) { + if (verbose_ >= 2 || (verbose_ == 1 && !isWildcardUsed_)) { + edm::LogError("HLTGenValClient") << "computeEfficiency() : " << "Cannot create TH1 from ME\n"; + } + return; + } + + // preparing efficiency output path and name + std::string efficDir = dirName; + std::string newEfficMEName = efficMEName; + std::string::size_type shiftPos; + if (std::string::npos != (shiftPos = efficMEName.rfind('/'))) { + efficDir += "/" + efficMEName.substr(0, shiftPos); + newEfficMEName.erase(0, shiftPos + 1); + } + ibooker.setCurrentFolder(efficDir); + + // creating the efficiency MonitorElement + HLTGenValClient::MonitorElement* efficME = nullptr; + + // We need to know what kind of TH1 we have + // That information is obtained from the class name of the hDenominator + // Then we use the appropriate booking function + TH1* efficHist = static_cast(hDenominator->Clone(newEfficMEName.c_str())); + efficHist->SetDirectory(nullptr); + efficHist->SetTitle(efficMETitle.c_str()); + TClass* myHistClass = efficHist->IsA(); + std::string histClassName = myHistClass->GetName(); + if (histClassName == "TH1F") { + efficME = ibooker.book1D(newEfficMEName, (TH1F*)efficHist); + } else if (histClassName == "TH2F") { + efficME = ibooker.book2D(newEfficMEName, (TH2F*)efficHist); + } else if (histClassName == "TH3F") { + efficME = ibooker.book3D(newEfficMEName, (TH3F*)efficHist); + } + delete efficHist; + + // checking whether efficME was succesfully created + if (!efficME) { + edm::LogError("HLTGenValClient") << "computeEfficiency() : " << "Cannot book effic-ME from the DQM\n"; + return; + } + + // actually calculating the efficiency and filling the ME + genericEff(hDenominator, hNumerator, efficME); + efficME->setEntries(denominatorME->getEntries()); + + // Putting total efficiency in "GLobal efficiencies" histogram + if (makeGlobalEffPlot_) { + + // getting global efficiency ME + HLTGenValClient::MonitorElement* globalEfficME = igetter.get(efficDir + "/globalEfficiencies"); + if (!globalEfficME) // in case it does not exist yet, we create it + globalEfficME = ibooker.book1D("globalEfficiencies", "Global efficiencies", 1, 0, 1); + if (!globalEfficME) { // error handling in case creation failed + edm::LogError("HLTGenValClient") << "computeEfficiency() : " << "Cannot book globalEffic-ME from the DQM\n"; + return; + } + globalEfficME->setEfficiencyFlag(); + + // extracting histogram + TH1F* hGlobalEffic = globalEfficME->getTH1F(); + if (!hGlobalEffic) { + edm::LogError("HLTGenValClient") << "computeEfficiency() : " << "Cannot create TH1F from ME, globalEfficME\n"; + return; + } + + // getting total counts + const float nDenominatorAll = hDenominator->GetEntries(); + const float nNumeratorAll = hNumerator->GetEntries(); + + // calculating total efficiency + float efficAll = 0; + float errorAll = 0; + efficAll = nDenominatorAll ? nNumeratorAll / nDenominatorAll : 0; + errorAll = nDenominatorAll && efficAll < 1 ? sqrt(efficAll * (1 - efficAll) / nDenominatorAll) : 0; + + // Filling the histogram bin + const int iBin = hGlobalEffic->Fill(newEfficMEName.c_str(), 0); + hGlobalEffic->SetBinContent(iBin, efficAll); + hGlobalEffic->SetBinError(iBin, errorAll); + } +} + +// method to find all subdirectories of the given directory +// goal is to fill myList with paths to all subdirectories +void HLTGenValClient::findAllSubdirectories(DQMStore::IBooker& ibooker, + DQMStore::IGetter& igetter, + std::string dir, + std::set* myList, + const TString& _pattern = TString("")) { + TString patternTmp = _pattern; + + // checking if directory exists + if (!igetter.dirExists(dir)) { + edm::LogError("HLTGenValClient") << " HLTGenValClient::findAllSubdirectories ==> Missing folder " << dir << " !!!"; + return; + } + + // replacing wildcards + if (patternTmp != "") { + if (patternTmp.Contains(nonPerlWildcard_)) patternTmp.ReplaceAll("*", ".*"); + TPRegexp regexp(patternTmp); + ibooker.cd(dir); + std::vector foundDirs = igetter.getSubdirs(); + for (const auto & iDir : foundDirs) { + TString dirName = iDir.substr(iDir.rfind('/') + 1, iDir.length()); + if (dirName.Contains(regexp)) findAllSubdirectories(ibooker, igetter, iDir, myList); + } + } + else if (igetter.dirExists(dir)) { + + // we have found a subdirectory - adding it to the list + myList->insert(dir); + + // moving into the found subdirectory and recursively continue + ibooker.cd(dir); + findAllSubdirectories(ibooker, igetter, dir, myList, "*"); + + } else { + + // error handling in case found directory does not exist + edm::LogError("HLTGenValClient") << "Trying to find sub-directories of " << dir << " failed because " << dir << " does not exist"; + } + return; +} + +// efficiency calculation from two histograms +void HLTGenValClient::genericEff(TH1* denom, TH1* numer, MonitorElement* efficiencyHist) { + + // looping over all bins. Up to three dimentions can be handled + // in case of less dimensions, the inner for loops are excecuted only once + for (int iBinX = 1; iBinX < denom->GetNbinsX() + 1; iBinX++) { + for (int iBinY = 1; iBinY < denom->GetNbinsY() + 1; iBinY++) { + for (int iBinZ = 1; iBinZ < denom->GetNbinsZ() + 1; iBinZ++) { + int globalBinNum = denom->GetBin(iBinX, iBinY, iBinZ); + + // getting numerator and denominator values + float numerVal = numer->GetBinContent(globalBinNum); + float denomVal = denom->GetBinContent(globalBinNum); + + // calculating effiency + float effVal = 0; + effVal = denomVal ? numerVal / denomVal : 0; + + // calculating error + float errVal = 0; + errVal = (denomVal && (effVal <= 1)) ? sqrt(effVal * (1 - effVal) / denomVal) : 0; + + // inserting value into the efficiency histogram + efficiencyHist->setBinContent(globalBinNum, effVal); + efficiencyHist->setBinError(globalBinNum, errVal); + efficiencyHist->setEfficiencyFlag(); + } + } + } +} + +DEFINE_FWK_MODULE(HLTGenValClient); diff --git a/Validation/HLTrigger/plugins/HLTGenValSource.cc b/Validation/HLTrigger/plugins/HLTGenValSource.cc new file mode 100644 index 0000000000000..2cb0edac55baa --- /dev/null +++ b/Validation/HLTrigger/plugins/HLTGenValSource.cc @@ -0,0 +1,479 @@ +//******************************************************************************** +// +// Description: +// Producing and filling histograms for generator-level HLT path efficiency histograms. Harvested by a HLTGenValClient. +// +// Implementation: +// Histograms for objects of a certain type are created for multiple paths chosen by the user: for all objects, +// and for objects passing filters in the path, determined by deltaR matching. +// Each HLTGenValSource can handle a single object type and any number of paths (and filters in them) +// +// Author: Finn Labe, UHH, Jul. 2022 +// +//******************************************************************************** + + +// system include files +#include +#include +#include + +// user include files +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/one/EDAnalyzer.h" + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/Utilities/interface/InputTag.h" + +// including GenParticles +#include "DataFormats/HepMCCandidate/interface/GenParticle.h" + +// icnluding GenMET +#include "DataFormats/METReco/interface/GenMETCollection.h" +#include "DataFormats/METReco/interface/GenMET.h" + +// includes needed for histogram creation +#include "FWCore/ServiceRegistry/interface/Service.h" +#include "CommonTools/UtilAlgos/interface/TFileService.h" + +// FunctionDefs +#include "DQMOffline/Trigger/interface/FunctionDefs.h" + +// includes of histogram collection class +#include "Validation/HLTrigger/interface/HLTGenValHistCollPath.h" + +// DQMStore +#include "DQMServices/Core/interface/DQMStore.h" +#include "DQMServices/Core/interface/DQMEDAnalyzer.h" + +// trigger Event +#include "HLTrigger/HLTcore/interface/HLTConfigProvider.h" +#include "DataFormats/HLTReco/interface/TriggerEvent.h" + +// object that can be a GenJet, GenParticle or energy sum +#include "Validation/HLTrigger/interface/HLTGenValObject.h" + +class HLTGenValSource : public DQMEDAnalyzer { +public: + + explicit HLTGenValSource(const edm::ParameterSet&); + ~HLTGenValSource() override = default; + HLTGenValSource(const HLTGenValSource&) = delete; + HLTGenValSource& operator=(const HLTGenValSource&) = delete; + + static void fillDescriptions(edm::ConfigurationDescriptions& descriptions); + +private: + void analyze(const edm::Event&, const edm::EventSetup&) override; + void bookHistograms(DQMStore::IBooker&, edm::Run const& run, edm::EventSetup const& c) override; + void dqmBeginRun(const edm::Run &, const edm::EventSetup &) override; + + // functions to get correct object collection for chosen object type + std::vector getObjectCollection(const edm::Event&); + std::vector getGenParticles(const edm::Event&); + reco::GenParticle getLastCopyPreFSR(reco::GenParticle part); + reco::GenParticle getLastCopy(reco::GenParticle part); + + // ----------member data --------------------------- + + // tokens to get collections + const edm::EDGetTokenT genParticleToken_; + const edm::EDGetTokenT genMETToken_; + const edm::EDGetTokenT AK4genJetToken_; + const edm::EDGetTokenT AK8genJetToken_; + const edm::EDGetTokenT trigEventToken_; + + // config strings/Psets + std::string objType_; + std::string dirName_; + std::vector histConfigs_; + std::vector histConfigs2D_; + std::vector binnings_; + std::string hltProcessName_; + + // constructing the info string, which will be written to the output file for display of information in the GUI + // 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 + std::string infoString_ = "{"; + + // histogram collection per path + std::vector collectionPath_; + + // HLT config provider/getter + HLTConfigProvider hltConfig_; + + // some miscellaneous member variables + std::vector hltPathsToCheck_; + std::vector hltPaths; + std::vector hltPathSpecificCuts; + double dR2limit_; + bool doOnlyLastFilter_; + +}; + +HLTGenValSource::HLTGenValSource(const edm::ParameterSet& iConfig) + : genParticleToken_( consumes( iConfig.getParameterSet("inputCollections").getParameter("genParticles") ) ), + genMETToken_( consumes( iConfig.getParameterSet("inputCollections").getParameter("genMET") ) ), + AK4genJetToken_(consumes( iConfig.getParameterSet("inputCollections").getParameter("ak4GenJets"))), + AK8genJetToken_(consumes( iConfig.getParameterSet("inputCollections").getParameter("ak8GenJets"))), + trigEventToken_(consumes( iConfig.getParameterSet("inputCollections").getParameter("TrigEvent") )) { + + // getting the histogram configurations + histConfigs_ = iConfig.getParameterSetVector("histConfigs"); + histConfigs2D_ = iConfig.getParameterSetVector("histConfigs2D"); + binnings_ = iConfig.getParameterSetVector("binnings"); + + // getting all other configurations + dirName_ = iConfig.getParameter("DQMDirName"); + objType_ = iConfig.getParameter("objType"); + dR2limit_ = iConfig.getParameter("dR2limit"); + doOnlyLastFilter_ = iConfig.getParameter("doOnlyLastFilter"); + hltProcessName_ = iConfig.getParameter("hltProcessName"); + hltPathsToCheck_ = iConfig.getParameter>("hltPathsToCheck"); + +} + +void HLTGenValSource::dqmBeginRun(const edm::Run &iRun, const edm::EventSetup &iSetup) { + + // writing general information to info JSON + auto t = std::time(nullptr); + auto tm = *std::localtime(&t); + + // date and time of running this + std::ostringstream timeStringStream; + timeStringStream << std::put_time(&tm, "%d-%m-%Y %H-%M-%S"); + auto timeString = timeStringStream.str(); + infoString_ += "\"date & time\":\""+timeString+"\","; + + // CMSSW version + std::stringstream CMSSWversionStream(std::getenv("CMSSW_BASE")); + std::string CMSSWversionSegment; + std::string CMSSWversion; + while(std::getline(CMSSWversionStream, CMSSWversionSegment, '/')) + { + CMSSWversion = CMSSWversionSegment; + } + infoString_ += std::string("\"CMSSW release\":\"")+CMSSWversion+"\","; + + // Initialize hltConfig, for cross-checking whether chosen paths exist + bool changedConfig; + if (!hltConfig_.init(iRun, iSetup, hltProcessName_, changedConfig)) { + edm::LogError("HLTGenValSource") << "Initialization of HLTConfigProvider failed!"; + return; + } + + // global tag + infoString_ += std::string("\"global tag\":\"")+hltConfig_.globalTag()+"\","; + + // confDB table name + infoString_ += std::string("\"HLT ConfDB table\":\"")+hltConfig_.tableName()+"\","; + + // Get the set of trigger paths we want to make plots for + std::vector notFoundPaths; + for (auto const &pathToCheck : hltPathsToCheck_) { + + // It is possible to add additional requirements to each path, seperated by a colon from the path name + // these additional requirements are split from the path name here + std::string cleanedPathToCheck; + std::string pathSpecificCuts = ""; + if (pathToCheck.find(":") != std::string::npos) { + + // splitting the string + std::stringstream hltPathToCheckInputStream(pathToCheck); + std::string hltPathToCheckInputSegment; + std::vector hltPathToCheckInputSeglist; + while(std::getline(hltPathToCheckInputStream, hltPathToCheckInputSegment, ':')) + { + hltPathToCheckInputSeglist.push_back(hltPathToCheckInputSegment); + } + + // here, exactly two parts are expected + if(hltPathToCheckInputSeglist.size() != 2) throw cms::Exception("InputError") << "Path string can not be properly split into path and cuts: please use exactly one colon!.\n"; + + // the first part is the name of the path + cleanedPathToCheck = hltPathToCheckInputSeglist.at(0); + + // second part are the cuts, to be parsed later + pathSpecificCuts = hltPathToCheckInputSeglist.at(1); + + } else { + cleanedPathToCheck = pathToCheck; + } + + bool pathfound = false; + for (auto const &pathFromConfig : hltConfig_.triggerNames()) { + if (pathFromConfig.find(cleanedPathToCheck) != std::string::npos) { + + hltPaths.push_back(pathFromConfig); + + // in case the path was added twice, we'll add a tag automatically + int count = std::count(hltPaths.begin(), hltPaths.end(), pathFromConfig); + if (count > 1) { + pathSpecificCuts += std::string(",autotag=v")+std::to_string( count ); + } + hltPathSpecificCuts.push_back(pathSpecificCuts); + pathfound = true; + } + } + if(!pathfound) notFoundPaths.push_back(cleanedPathToCheck); + } + if(!notFoundPaths.empty()) { + // error handling in case some paths do not exist + std::string notFoundPathsMessage = ""; + for (const auto & path : notFoundPaths) notFoundPathsMessage += "- " + path + "\n"; + edm::LogError("HLTGenValSource") << "The following paths could not be found and will not be used: \n" << notFoundPathsMessage << std::endl; + + } + + // before creating the collections for each path, we'll store the needed configurations in a pset + // we'll copy this base multiple times and add the respective path + // most of these options are not needed in the pathColl, but in the filterColls created in the pathColl + edm::ParameterSet pathCollConfig; + pathCollConfig.addParameter("objType", objType_); + pathCollConfig.addParameter("dR2limit", dR2limit_); + pathCollConfig.addParameter("doOnlyLastFilter", doOnlyLastFilter_); + pathCollConfig.addParameter("hltProcessName", hltProcessName_); + + // creating a histogram collection for each path + for (const auto & path : hltPaths) { + edm::ParameterSet pathCollConfigStep = pathCollConfig; + pathCollConfigStep.addParameter("triggerPath", path); + collectionPath_.emplace_back(HLTGenValHistCollPath(pathCollConfigStep, hltConfig_)); + } + +} + +// ------------ method called for each event ------------ +void HLTGenValSource::analyze(const edm::Event& iEvent, const edm::EventSetup& iSetup) { + + // creating the collection of HLTGenValObjects + const std::vector objects = getObjectCollection(iEvent); + + // init triggerEvent, which is always needed + edm::Handle triggerEvent; + iEvent.getByToken(trigEventToken_, triggerEvent); + + // loop over all objects and fill hists + for (const auto & object : objects) { + for (auto& collection_path : collectionPath_) { + collection_path.fillHists(object, triggerEvent); + } + } + +} + +// ------------ method called once each job just before starting event loop ------------ +void HLTGenValSource::bookHistograms(DQMStore::IBooker& iBooker, const edm::Run& run, const edm::EventSetup& setup) { + + iBooker.setCurrentFolder(dirName_); + + if(infoString_.back() == ',') infoString_.pop_back(); + infoString_ += "}"; // adding the closing bracked to the JSON string + iBooker.bookString("HLTGenValInfo", infoString_); + + // booking all histograms + for (long unsigned int i = 0; i < collectionPath_.size(); i++) { + std::vector histConfigs = histConfigs_; + for (auto & histConfig : histConfigs) { + histConfig.addParameter("pathSpecificCuts", hltPathSpecificCuts.at(i)); + histConfig.addParameter>("binnings", binnings_); // passing along the user-defined binnings + } + + collectionPath_.at(i).bookHists(iBooker, histConfigs, histConfigs2D_); + } + +} + + +// ------------ method fills 'descriptions' with the allowed parameters for the module ------------ +void HLTGenValSource::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + + // basic parameter strings + desc.add("objType"); // this deliberately has no default, as this is the main thing the user needs to chose + desc.add>("hltPathsToCheck"); // this for the moment also has no default: maybe there can be some way to handle this later? + desc.add("DQMDirName", "HLTGenVal"); + desc.add("hltProcessName", "HLT"); + desc.add("dR2limit", 0.1); + desc.add("doOnlyLastFilter", false); + + // input collections, a PSet + edm::ParameterSetDescription inputCollections; + inputCollections.add("genParticles", edm::InputTag("genParticles")); + inputCollections.add("genMET", edm::InputTag("genMetTrue")); + inputCollections.add("ak4GenJets", edm::InputTag("ak4GenJets")); + inputCollections.add("ak8GenJets", edm::InputTag("ak8GenJets")); + inputCollections.add("TrigEvent", edm::InputTag("hltTriggerSummaryAOD")); + desc.add("inputCollections", inputCollections); + + // hist descriptors, which are a vector of PSets + + // defining single histConfig + // this is generally without default, but a default set of histConfigs is specified below + edm::ParameterSetDescription histConfig; + histConfig.add("vsVar"); + histConfig.add>("binLowEdges"); + histConfig.addVPSet("rangeCuts", VarRangeCut::makePSetDescription(), std::vector()); + + // default set of histConfigs + std::vector histConfigDefaults; + + edm::ParameterSet histConfigDefault0; + histConfigDefault0.addParameter("vsVar", "pt"); + std::vector defaultPtBinning{ 0,5,10,12.5,15,17.5,20,22.5,25,30,35,40,45,50,60,80,100,150,200,250,300,350,400 }; + histConfigDefault0.addParameter>("binLowEdges", defaultPtBinning ); + histConfigDefaults.push_back(histConfigDefault0); + + edm::ParameterSet histConfigDefault1; + histConfigDefault1.addParameter("vsVar", "eta"); + std::vector defaultetaBinning{ -10, -8, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 8, 10 }; + histConfigDefault1.addParameter>("binLowEdges", defaultetaBinning ); + histConfigDefaults.push_back(histConfigDefault1); + + desc.addVPSet("histConfigs", histConfig, histConfigDefaults); + + // defining single histConfig2D + edm::ParameterSetDescription histConfig2D; + histConfig2D.add("vsVarX"); + histConfig2D.add("vsVarY"); + histConfig2D.add>("binLowEdgesX"); + histConfig2D.add>("binLowEdgesY"); + + // default set of histConfigs + std::vector histConfigDefaults2D; + + edm::ParameterSet histConfigDefault2D0; + histConfigDefault2D0.addParameter("vsVarX", "pt"); + histConfigDefault2D0.addParameter("vsVarY", "eta"); + histConfigDefault2D0.addParameter>("binLowEdgesX", defaultPtBinning); + histConfigDefault2D0.addParameter>("binLowEdgesY", defaultetaBinning); + histConfigDefaults2D.push_back(histConfigDefault2D0); + + desc.addVPSet("histConfigs2D", histConfig2D, histConfigDefaults2D); + + // binnings, which are vectors of PSets + // there are no default for this + edm::ParameterSetDescription binningConfig; + binningConfig.add("name"); + binningConfig.add("vsVar"); + binningConfig.add>("binLowEdges"); + + // this by default is empty + std::vector binningConfigDefaults; + + desc.addVPSet("binnings", binningConfig, binningConfigDefaults); + + descriptions.addDefault(desc); +} + +// this method handles the different object types and collections that can be used for efficiency calculation +std::vector HLTGenValSource::getObjectCollection(const edm::Event& iEvent) { + + std::vector objects; // the vector of objects to be filled + + // handle object type + std::vector implementedGenParticles = {"ele", "pho", "mu", "tau"}; + if(std::find(implementedGenParticles.begin(), implementedGenParticles.end(), objType_) != implementedGenParticles.end()) { + objects = getGenParticles(iEvent); + } + else if(objType_ == "AK4jet") { // ak4 jets, using the ak4GenJets collection + const auto& genJets = iEvent.getHandle(AK4genJetToken_); + for(size_t i = 0; i < genJets->size(); i++) { + const reco::GenJet p = (*genJets)[i]; + objects.emplace_back(p); + } + } + else if(objType_ == "AK8jet") { // ak8 jets, using the ak8GenJets collection + const auto& genJets = iEvent.getHandle(AK8genJetToken_); + for(size_t i = 0; i < genJets->size(); i++) { + const reco::GenJet p = (*genJets)[i]; + objects.emplace_back(p); + } + } + else if(objType_ == "AK4HT") { // ak4-based HT, using the ak4GenJets collection + const auto& genJets = iEvent.getHandle(AK4genJetToken_); + if(!genJets->empty()){ + auto HTsum = (*genJets)[0].pt(); + for(size_t i = 1; i < genJets->size(); i++) { + if(((*genJets)[i].pt() > 30) && (abs((*genJets)[i].eta()) < 2.5)) HTsum += (*genJets)[i].pt(); + } + objects.emplace_back(reco::Candidate::PolarLorentzVector(HTsum, 0, 0, 0)); + } + } + else if(objType_ == "AK8HT") { // ak8-based HT, using the ak8GenJets collection + const auto& genJets = iEvent.getHandle(AK8genJetToken_); + if(!genJets->empty()){ + auto HTsum = (*genJets)[0].pt(); + for(size_t i = 1; i < genJets->size(); i++) { + if(((*genJets)[i].pt() > 200) && (abs((*genJets)[i].eta()) < 2.5)) HTsum += (*genJets)[i].pt(); + } + objects.emplace_back(reco::Candidate::PolarLorentzVector(HTsum, 0, 0, 0)); + } + } + else if(objType_ == "MET") { // MET, using genMET + const auto& genMET = iEvent.getHandle(genMETToken_); + if(!genMET->empty()){ + auto genMETpt = (*genMET)[0].pt(); + objects.emplace_back(reco::Candidate::PolarLorentzVector(genMETpt, 0, 0, 0)); + } + } + else throw cms::Exception("InputError") << "Generator-level validation is not available for type " << objType_ << ".\n" << "Please check for a potential spelling error.\n"; + + return objects; +} + +// in case of GenParticles, a subset of the entire collection needs to be chosen +std::vector HLTGenValSource::getGenParticles(const edm::Event& iEvent) { + + std::vector objects; // vector to be filled + + const auto& genParticles = iEvent.getHandle(genParticleToken_); // getting all GenParticles + + // we need to ge the ID corresponding to the desired GenParticle type + int pdgID = -1; // setting to -1 should not be needed, but prevents the compiler warning :) + if(objType_ == "ele") pdgID = 11; + else if(objType_ == "pho") pdgID = 22; + else if(objType_ == "mu") pdgID = 13; + else if(objType_ == "tau") pdgID = 15; + + // main loop over GenParticles + for(size_t i = 0; i < genParticles->size(); ++ i) { + const reco::GenParticle p = (*genParticles)[i]; + + // only GenParticles with correct ID + if (abs(p.pdgId()) != pdgID) continue; + + // checking if particle comes from "hard process" + if(p.isHardProcess()) { + + // depending on the particle type, last particle before or after FSR is chosen + if( (objType_ == "ele") || (objType_ == "pho") ) objects.emplace_back( getLastCopyPreFSR(p) ); + else if( (objType_ == "mu") || (objType_ == "tau") ) objects.emplace_back( getLastCopy(p) ); + + } + + } + + return objects; + +} + +// function returning the last GenParticle in a decay chain before FSR +reco::GenParticle HLTGenValSource::getLastCopyPreFSR(reco::GenParticle part) { + const auto daughters = part.daughterRefVector(); + if (daughters.size() == 1 && daughters.at(0)->pdgId() == part.pdgId()) return getLastCopyPreFSR(*daughters.at(0).get()); // recursion, whooo + else return part; +} + +// function returning the last GenParticle in a decay chain +reco::GenParticle HLTGenValSource::getLastCopy(reco::GenParticle part) { + for (const auto & daughter : part.daughterRefVector()){ + if (daughter->pdgId() == part.pdgId()) return getLastCopy(*daughter.get()); + } + return part; +} + +//define this as a framework plug-in +DEFINE_FWK_MODULE(HLTGenValSource); diff --git a/Validation/HLTrigger/src/HLTGenValHistCollFilter.cc b/Validation/HLTrigger/src/HLTGenValHistCollFilter.cc new file mode 100644 index 0000000000000..d7926771fe2ab --- /dev/null +++ b/Validation/HLTrigger/src/HLTGenValHistCollFilter.cc @@ -0,0 +1,179 @@ +#include "Validation/HLTrigger/interface/HLTGenValHistCollFilter.h" + +// constructor +HLTGenValHistCollFilter::HLTGenValHistCollFilter(edm::ParameterSet filterCollConfig) { + objType_ = filterCollConfig.getParameter("objType"); + filter_ = filterCollConfig.getParameter("filterName"); + path_ = filterCollConfig.getParameter("pathName"); + hltProcessName_ = filterCollConfig.getParameter("hltProcessName"); + dR2limit_ = filterCollConfig.getParameter("dR2limit"); +} + +edm::ParameterSetDescription HLTGenValHistCollFilter::makePSetDescription() { + edm::ParameterSetDescription desc; + desc.add("objType", ""); + desc.add("hltProcessName", "HLT"); + desc.add("dR2limit", 0.1); + desc.add("filterName", ""); + desc.add("pathName", ""); + return desc; +} + +// general hist booking function, receiving configurations for 1D and 2D hists and calling the respective functions +void HLTGenValHistCollFilter::bookHists(DQMStore::IBooker& iBooker, const std::vector& histConfigs, const std::vector& histConfigs2D) { + for (const auto& histConfig : histConfigs) book1D(iBooker, histConfig); + for (const auto& histConfig : histConfigs2D) book2D(iBooker, histConfig); +} + +// histogram filling routine +void HLTGenValHistCollFilter::fillHists(const HLTGenValObject& obj, edm::Handle& triggerEvent) { + + // this handles the "before" step, denoted by a "dummy" filter called "beforeAnyFilter" + // the histogram is filled without any additional requirements for all objects + if(filter_ == "beforeAnyFilter") { + for (auto& hist : hists_) hist->fill(obj); + } else { + // main filling code + + // get filter object from filter name + edm::InputTag filterTag(filter_, "", hltProcessName_); + size_t filterIndex = triggerEvent->filterIndex(filterTag); + + // get trigger objects passing filter in question + trigger::TriggerObjectCollection allTriggerObjects = triggerEvent->getObjects(); // all objects + trigger::TriggerObjectCollection selectedObjects; // vector to fill with objects passing our filter + if (filterIndex < triggerEvent->sizeFilters()) { + const auto& keys = triggerEvent->filterKeys(filterIndex); + for (unsigned short key : keys) { + trigger::TriggerObject foundObject = allTriggerObjects[key]; + selectedObjects.push_back(foundObject); + } + } + + // differentiate between event level and particle level variables + std::vector eventLevelVariables = {"AK4HT", "AK8HT", "MET"}; + if(std::find(eventLevelVariables.begin(), eventLevelVariables.end(), objType_) != eventLevelVariables.end()) { + // for these event level variables we only require the existence of a trigger object, but no matching + if(!selectedObjects.empty()) for (auto& hist : hists_) hist->fill(obj); + } else { + // do a deltaR matching between trigger object and GEN object + double mindR2 = 99999; + for (const auto & filterobj : selectedObjects) { + double dR = deltaR2(obj, filterobj); + if(dR < mindR2) mindR2 = dR; + } + if(mindR2 < dR2limit_) for (auto& hist : hists_) hist->fill(obj); + } + + } +} + +// booker function for 1D hists +void HLTGenValHistCollFilter::book1D(DQMStore::IBooker& iBooker, const edm::ParameterSet& histConfig) { + // extracting parameters from configuration + auto vsVar = histConfig.getParameter("vsVar"); + auto vsVarFunc = hltdqm::getUnaryFuncFloat(vsVar); + + // this class parses any potential additional cuts, changes in binning or tags + HLTGenValPathSpecificSettingParser parser = HLTGenValPathSpecificSettingParser( histConfig.getParameter("pathSpecificCuts"), histConfig.getParameter>("binnings"), vsVar ); + + // getting the bin edges, path-specific overwrites general if present + auto binLowEdgesDouble = histConfig.getParameter >("binLowEdges"); + if(parser.havePathSpecificBins()) binLowEdgesDouble = parser.getPathSpecificBins(); + + // additional cuts applied to this histogram, combination of general ones and path-specific ones + std::vector allCutsVector = histConfig.getParameter >("rangeCuts"); + std::vector pathSpecificCutsVector = parser.getPathSpecificCuts(); + allCutsVector.insert(allCutsVector.end(), pathSpecificCutsVector.begin(), pathSpecificCutsVector.end()); + VarRangeCutColl rangeCuts(allCutsVector); + + // getting the custom tag + std::string tag = parser.getTag(); + + // checking validity of vsVar + if (!vsVarFunc) { throw cms::Exception("ConfigError") << " vsVar " << vsVar << " is giving null ptr (likely empty) in " << __FILE__ << "," << __LINE__ << std::endl;} + + // converting bin edges to float + std::vector binLowEdges; + binLowEdges.reserve(binLowEdgesDouble.size()); + for (double lowEdge : binLowEdgesDouble) binLowEdges.push_back(lowEdge); + + // name and title are systematically constructed + + // remove potential leading "-" (which denotes that that trigger is ignored) + std::string filterName = filter_; + if(filterName.rfind("-", 0) == 0) filterName.erase(0, 1); + + std::string histName, histTitle; + if(filter_ == "beforeAnyFilter") { // this handles the naming of the "before" hist + histName = objType_ + ":" + path_ + ":GEN:vs" + vsVar ; + histTitle = objType_ + ":" + path_ + " GEN vs " + vsVar; + if(!tag.empty()) { + histName += ":"+tag; + histTitle += " "+tag; + } + } else { // naming of all regular hists + histName = objType_ + ":" + path_ + ":" + filterName + ":vs" + vsVar; + histTitle = objType_ + ":" + path_ + ":" + filterName + ":vs" + vsVar; + + // appending the tag, in case it is filled + if(!tag.empty()) { + histName += ":"+tag; + histTitle += " "+tag; + } + } + + auto me = iBooker.book1D(histName.c_str(), histTitle.c_str(), binLowEdges.size() - 1, &binLowEdges[0] ); // booking MonitorElement + + std::unique_ptr hist; // creating the hist object + + hist = std::make_unique(me->getTH1(), vsVar, vsVarFunc, rangeCuts); + + hists_.emplace_back(std::move(hist)); +} + +// booker function for 2D hists +void HLTGenValHistCollFilter::book2D(DQMStore::IBooker& iBooker, const edm::ParameterSet& histConfig2D) { + // extracting parameters from configuration + auto vsVarX = histConfig2D.getParameter("vsVarX"); + auto vsVarY = histConfig2D.getParameter("vsVarY"); + auto vsVarFuncX = hltdqm::getUnaryFuncFloat(vsVarX); + auto vsVarFuncY = hltdqm::getUnaryFuncFloat(vsVarY); + auto binLowEdgesDoubleX = histConfig2D.getParameter >("binLowEdgesX"); + auto binLowEdgesDoubleY = histConfig2D.getParameter >("binLowEdgesY"); + + // checking validity of vsVar + if (!vsVarFuncX) {throw cms::Exception("ConfigError") << " vsVar " << vsVarX << " is giving null ptr (likely empty) in " << __FILE__ << "," << __LINE__ << std::endl;} + if (!vsVarFuncY) {throw cms::Exception("ConfigError") << " vsVar " << vsVarY << " is giving null ptr (likely empty) in " << __FILE__ << "," << __LINE__ << std::endl;} + + // converting bin edges to float + std::vector binLowEdgesX; + std::vector binLowEdgesY; + binLowEdgesX.reserve(binLowEdgesDoubleX.size()); + binLowEdgesY.reserve(binLowEdgesDoubleY.size()); + for (double lowEdge : binLowEdgesDoubleX) binLowEdgesX.push_back(lowEdge); + for (double lowEdge : binLowEdgesDoubleY) binLowEdgesY.push_back(lowEdge); + + // name and title are systematically constructed + + // remove potential leading "-" (which denotes that that trigger is ignored) + std::string filterName = filter_; + if(filterName.rfind("-", 0) == 0) filterName.erase(0, 1); + + std::string histName, histTitle; + if(filter_ == "beforeAnyFilter") { + histName = objType_ + ":" + path_ + ":GEN:2Dvs" + vsVarX + ":" + vsVarY; + histTitle = objType_ + ":" + path_ + " GEN 2D vs " + vsVarX + " " + vsVarY; + } else { + histName = objType_ + ":" + path_ + ":" + filterName + ":2Dvs" + vsVarX + vsVarY; + histTitle = objType_ + ":" + path_ + " " + filterName + " 2D vs" + vsVarX + " " + vsVarY; + } + + auto me = iBooker.book2D(histName.c_str(), histTitle.c_str(), binLowEdgesX.size() - 1, &binLowEdgesX[0], binLowEdgesY.size() - 1, &binLowEdgesY[0]); + + std::unique_ptr hist; + + hist = std::make_unique(me->getTH2F(), vsVarX, vsVarY, vsVarFuncX, vsVarFuncY); + + hists_.emplace_back(std::move(hist)); +} diff --git a/Validation/HLTrigger/src/HLTGenValHistCollPath.cc b/Validation/HLTrigger/src/HLTGenValHistCollPath.cc new file mode 100644 index 0000000000000..03f7dcc003854 --- /dev/null +++ b/Validation/HLTrigger/src/HLTGenValHistCollPath.cc @@ -0,0 +1,82 @@ +#include "Validation/HLTrigger/interface/HLTGenValHistCollPath.h" + +// constructor +HLTGenValHistCollPath::HLTGenValHistCollPath(edm::ParameterSet pathCollConfig, HLTConfigProvider& hltConfig) : + hltConfig_(hltConfig) { + + triggerPath_ = pathCollConfig.getParameter("triggerPath"); + doOnlyLastFilter_ = pathCollConfig.getParameter("doOnlyLastFilter"); + + // before creating the collections for each filter, we'll store the needed configurations in a pset + // we'll copy this basis multiple times and add the respective path later + edm::ParameterSet filterCollConfig; + filterCollConfig.addParameter("objType", pathCollConfig.getParameter("objType")); + filterCollConfig.addParameter("hltProcessName", pathCollConfig.getParameter("hltProcessName")); + filterCollConfig.addParameter("dR2limit", pathCollConfig.getParameter("dR2limit")); + filterCollConfig.addParameter("pathName", triggerPath_); + + pathStringName_ = triggerPath_ + "-" + pathCollConfig.getParameter("objType"); + + // this filter will be the denominator + edm::ParameterSet filterCollConfigStepBeforeAny = filterCollConfig; + filterCollConfigStepBeforeAny.addParameter("filterName", "beforeAnyFilter"); + collectionFilter_.emplace_back(HLTGenValHistCollFilter(filterCollConfigStepBeforeAny)); + + // we'll use this to construct the string to find which filters belong to which histogram later + pathString_ = ""; + + // getting all filters from path + filters_ = hltConfig_.saveTagsModules(triggerPath_); + if(doOnlyLastFilter_) { + edm::ParameterSet filterCollConfigOnlyLastFilter = filterCollConfig; + filterCollConfigOnlyLastFilter.addParameter("filterName", filters_.back()); + collectionFilter_.emplace_back(HLTGenValHistCollFilter(filterCollConfigOnlyLastFilter)); + + // remove potential leading "-" for printing + std::string filterName = filters_.back(); + if(filterName.rfind("-", 0) == 0) filterName.erase(0, 1); + + pathString_ += filterName; + } else { + + for (auto & filter : filters_) { + edm::ParameterSet filterCollConfigStep = filterCollConfig; + filterCollConfigStep.addParameter("filterName", filter); + collectionFilter_.emplace_back(HLTGenValHistCollFilter(filterCollConfigStep)); + + // remove potential leading "-" for printing + std::string filterName = filter; + if(filterName.rfind("-", 0) == 0) filterName.erase(0, 1); + + pathString_ += filterName; + if(filter != filters_.back()) pathString_ += ";"; + } + } + + +} + +edm::ParameterSetDescription HLTGenValHistCollPath::makePSetDescription() { + edm::ParameterSetDescription desc; + desc.add("objType", ""); + desc.add("dR2limit", 0.1); + desc.add("doOnlyLastFilter", false); + desc.add("hltProcessName", "HLT"); + desc.add("triggerPath", ""); + return desc; +} + +// hist booking function +// this just calls the booking for each object in the the filter collection +void HLTGenValHistCollPath::bookHists(DQMStore::IBooker& iBooker, std::vector& histConfigs, std::vector& histConfigs2D) { + + if(!pathString_.empty()) iBooker.bookString("path-"+pathStringName_, pathString_); + + for (auto& collection_filter : collectionFilter_) collection_filter.bookHists(iBooker, histConfigs, histConfigs2D); +} + +// hist filling function +// this just calls the filling for each object in the filter collection +void HLTGenValHistCollPath::fillHists(const HLTGenValObject& obj, edm::Handle& triggerEvent) { + for (auto& collection_filter : collectionFilter_) collection_filter.fillHists(obj, triggerEvent); +} diff --git a/Validation/HLTrigger/src/HLTGenValPathSpecificSettingParser.cc b/Validation/HLTrigger/src/HLTGenValPathSpecificSettingParser.cc new file mode 100644 index 0000000000000..dd83f7ae87eb9 --- /dev/null +++ b/Validation/HLTrigger/src/HLTGenValPathSpecificSettingParser.cc @@ -0,0 +1,101 @@ +#include "Validation/HLTrigger/interface/HLTGenValPathSpecificSettingParser.h" + +HLTGenValPathSpecificSettingParser::HLTGenValPathSpecificSettingParser(std::string pathSpecificSettings, std::vector binnings, std::string vsVar) { + + // splitting the cutstring + std::stringstream pathSpecificSettingsStream(pathSpecificSettings); + std::string pathSpecificSettingsSegment; + std::vector pathSpecificSettingsSeglist; + while(std::getline(pathSpecificSettingsStream, pathSpecificSettingsSegment, ',')) + { + pathSpecificSettingsSeglist.push_back(pathSpecificSettingsSegment); + } + + for (const auto pathSpecificSetting : pathSpecificSettingsSeglist) { + + // each of these strings is expected to contain exactly one equal sign + std::stringstream pathSpecificSettingStream(pathSpecificSetting); + std::string pathSpecificSettingSegment; + std::vector pathSpecificSettingSeglist; + while(std::getline(pathSpecificSettingStream, pathSpecificSettingSegment, '=')) + { + pathSpecificSettingSeglist.push_back(pathSpecificSettingSegment); + } + if(pathSpecificSettingSeglist.size() != 2) throw cms::Exception("InputError") << "Path-specific cuts could not be parsed. Make sure that each parameter contains exactly one equal sign!.\n"; + const std::string cutVariable = pathSpecificSettingSeglist.at(0); + const std::string cutParameter = pathSpecificSettingSeglist.at(1); + + edm::ParameterSet rangeCutConfig; + if (cutVariable == "absEtaMax" || cutVariable == "absEtaCut") { + rangeCutConfig.addParameter("rangeVar", "eta"); + rangeCutConfig.addParameter>("allowedRanges", {"-"+cutParameter+":"+cutParameter} ); + } else if (cutVariable == "absEtaMin") { + rangeCutConfig.addParameter("rangeVar", "eta"); + rangeCutConfig.addParameter>("allowedRanges", {"-999:"+cutParameter, cutParameter+":999"} ); + } else if (cutVariable == "ptMax") { + rangeCutConfig.addParameter("rangeVar", "pt"); + rangeCutConfig.addParameter>("allowedRanges", {"0:"+cutParameter} ); + } else if (cutVariable == "ptMin" || cutVariable == "ptCut") { + rangeCutConfig.addParameter("rangeVar", "pt"); + rangeCutConfig.addParameter>("allowedRanges", {cutParameter+":999999"} ); + } else if (cutVariable == "etMax") { + rangeCutConfig.addParameter("rangeVar", "et"); + rangeCutConfig.addParameter>("allowedRanges", {"0:"+cutParameter} ); + } else if (cutVariable == "etMin" || cutVariable == "etCut") { + rangeCutConfig.addParameter("rangeVar", "et"); + rangeCutConfig.addParameter>("allowedRanges", {cutParameter+":999999"} ); + } else if (cutVariable == "region") { + rangeCutConfig.addParameter("rangeVar", "eta"); + + // various predefined regions + // multiple regions might used, which are then split by a plus sign + std::stringstream cutParameterStream(cutParameter); + std::string cutParameterSegment; + std::vector cutParameterSeglist; + while(std::getline(cutParameterStream, cutParameterSegment, '+')) + { + cutParameterSeglist.push_back(cutParameterSegment); + } + + for (const auto region : cutParameterSeglist) { + if(region == "EB") { + rangeCutConfig.addParameter>("allowedRanges", {"-1.4442:1.4442"} ); + } else if (region == "EE") { + rangeCutConfig.addParameter>("allowedRanges", {"-999:-1.5660", "1.5660:999"} ); + } else { + throw cms::Exception("InputError") << "Region "+region+" not recognized.\n"; + } + } + + } else if (cutVariable == "bins") { + + // sets of binnings are read from the user-input ones passed in the "binnings" VPset + + bool binningFound = false; + bool binningUsed = false; + for (const auto binning : binnings) { + if (binning.getParameter("name") == cutParameter) { + if (binning.getParameter("vsVar") == vsVar) { + if (binningUsed) throw cms::Exception("InputError") << "Multiple different binnings set for a path, this does not make sense!.\n"; + pathSpecificBins_ = binning.getParameter>("binLowEdges"); + binningUsed = true; + } + binningFound = true; + } + } + if (!binningFound) throw cms::Exception("InputError") << "Binning " << cutParameter << " not recognized! Please pass the definition to the module.\n"; + + } else if (cutVariable == "tag") { + tag_ = cutParameter; + } else if (cutVariable == "autotag") { + // autotag is only used if no manual tag is set + if(tag_.empty()) tag_ = cutParameter; + } else { + throw cms::Exception("InputError") << "Path-specific cut "+cutVariable+" not recognized. The following options can be user: absEtaMax, absEtaCut, absEtaMin, ptMax, ptMin, ptCut, etMax, etMin, etCut, region, bins and tag.\n"; + } + + if(!rangeCutConfig.empty()) pathSpecificCutsVector_.push_back( rangeCutConfig ); + + } + +} diff --git a/Validation/HLTrigger/test/ConfFile_source_cfg.py b/Validation/HLTrigger/test/ConfFile_source_cfg.py new file mode 100644 index 0000000000000..b2359c4a55fea --- /dev/null +++ b/Validation/HLTrigger/test/ConfFile_source_cfg.py @@ -0,0 +1,215 @@ +import FWCore.ParameterSet.Config as cms + +process = cms.Process("HLTGenValSource") + +process.load("FWCore.MessageService.MessageLogger_cfi") +process.load("DQMServices.Core.DQM_cfg") +process.load("DQMServices.Core.DQMStore_cfg") +process.load("DQMServices.Components.DQMEnvironment_cfi") +process.load("DQMServices.Components.MEtoEDMConverter_cff") +from DQMServices.Core.DQMEDHarvester import DQMEDHarvester + +process.maxEvents = cms.untracked.PSet( input = cms.untracked.int32(-1) ) + +process.load("FWCore.MessageService.MessageLogger_cfi") +process.MessageLogger.cerr.FwkReport.reportEvery = 100 + + +# using: CMSSW_12_3_0_pre4__fullsim_noPU_2021_14TeV-TTbar_14TeV-00001 +process.source = cms.Source("PoolSource", + #fileNames = cms.untracked.vstring("root://cmsxrootd.fnal.gov//store/mc/RunIISummer20UL18RECO/TTToSemiLeptonic_TuneCP5_13TeV-powheg-pythia8/AODSIM/106X_upgrade2018_realistic_v11_L1v1-v2/00000/B4A06248-D09E-314A-ACD7-F157B86109E6.root") + fileNames = cms.untracked.vstring( + "root://cmsxrootd.fnal.gov//store/relval/CMSSW_12_3_0_pre4/RelValTTbar_14TeV/GEN-SIM-DIGI-RAW/123X_mcRun3_2021_realistic_v4-v1/2580000/07f08321-b24c-4397-b019-18c8ba54696c.root", + "root://cmsxrootd.fnal.gov//store/relval/CMSSW_12_3_0_pre4/RelValTTbar_14TeV/GEN-SIM-DIGI-RAW/123X_mcRun3_2021_realistic_v4-v1/2580000/22cc5971-134c-4a49-94b6-a3f96de01d94.root", + "root://cmsxrootd.fnal.gov//store/relval/CMSSW_12_3_0_pre4/RelValTTbar_14TeV/GEN-SIM-DIGI-RAW/123X_mcRun3_2021_realistic_v4-v1/2580000/2d20a2a4-b411-4124-bf1d-93db155b76e8.root", + "root://cmsxrootd.fnal.gov//store/relval/CMSSW_12_3_0_pre4/RelValTTbar_14TeV/GEN-SIM-DIGI-RAW/123X_mcRun3_2021_realistic_v4-v1/2580000/5f762599-4ddb-4c5f-8975-0229b54cae07.root", + "root://cmsxrootd.fnal.gov//store/relval/CMSSW_12_3_0_pre4/RelValTTbar_14TeV/GEN-SIM-DIGI-RAW/123X_mcRun3_2021_realistic_v4-v1/2580000/7964789d-c81b-4927-abaf-73acbd202abc.root", + "root://cmsxrootd.fnal.gov//store/relval/CMSSW_12_3_0_pre4/RelValTTbar_14TeV/GEN-SIM-DIGI-RAW/123X_mcRun3_2021_realistic_v4-v1/2580000/9cfca190-28f6-43af-b300-e3af7dbbfdd2.root", + "root://cmsxrootd.fnal.gov//store/relval/CMSSW_12_3_0_pre4/RelValTTbar_14TeV/GEN-SIM-DIGI-RAW/123X_mcRun3_2021_realistic_v4-v1/2580000/d22883fe-df35-48f3-ad2b-dbad44c8eaa4.root", + "root://cmsxrootd.fnal.gov//store/relval/CMSSW_12_3_0_pre4/RelValTTbar_14TeV/GEN-SIM-DIGI-RAW/123X_mcRun3_2021_realistic_v4-v1/2580000/f8ee9482-41e8-4126-ae00-bf07ef019d66.root", + "root://cmsxrootd.fnal.gov//store/relval/CMSSW_12_3_0_pre4/RelValTTbar_14TeV/GEN-SIM-DIGI-RAW/123X_mcRun3_2021_realistic_v4-v1/2580000/fe617389-a652-418d-b24e-55ea0ccacd7e.root", + ) +) + +ptBins=cms.vdouble(0, 10, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85,90,95 , 100,105,110,115 ,120,125, 130, 135,140,145, 150) +ptBinsHT=cms.vdouble(0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950, 1000, 1050, 1100, 1150, 1200, 1300) +ptBinsJet=cms.vdouble(0, 100, 200, 300, 350, 375, 400, 425, 450, 475, 500, 550, 600, 700, 800, 900, 1000) +etaBins=cms.vdouble(-4,-3, -2.5, -2, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2, 2.5, 3, 4) + +etaCut=cms.PSet( + rangeVar=cms.string("eta"), + allowedRanges=cms.vstring("-2.4:2.4") +) +ptCut=cms.PSet( + rangeVar=cms.string("pt"), + allowedRanges=cms.vstring("40:9999") +) + +process.HLTGenValSourceHT = cms.EDProducer('HLTGenValSource', + # these are the only one the user needs to specify + objType = cms.string("AK4HT"), + hltPathsToCheck = cms.vstring( + "HLT_PFHT1050_v", + ), + doOnlyLastFilter = cms.bool(False), + histConfigs = cms.VPSet( + cms.PSet( + vsVar = cms.string("pt"), + binLowEdges = ptBinsHT, + ), + cms.PSet( + vsVar = cms.string("eta"), + binLowEdges = etaBins, + ), + ), +) + +process.HLTGenValSourceHT = cms.EDProducer('HLTGenValSource', + # these are the only one the user needs to specify + objType = cms.string("AK8HT"), + hltPathsToCheck = cms.vstring( + "HLT_AK8PFHT800_TrimMass50" + ), + doOnlyLastFilter = cms.bool(False), + histConfigs = cms.VPSet( + cms.PSet( + vsVar = cms.string("pt"), + binLowEdges = ptBinsHT, + ), + cms.PSet( + vsVar = cms.string("eta"), + binLowEdges = etaBins, + ), + ), +) + + +process.HLTGenValSourceMU = cms.EDProducer('HLTGenValSource', + # these are the only one the user needs to specify + objType = cms.string("mu"), + hltPathsToCheck = cms.vstring( + "HLT_Mu50_v", + "HLT_IsoMu24_v" + ), + doOnlyLastFilter = cms.bool(False), + histConfigs = cms.VPSet( + cms.PSet( + vsVar = cms.string("pt"), + binLowEdges = ptBins, + rangeCuts = cms.VPSet(etaCut) + ), + cms.PSet( + vsVar = cms.string("eta"), + binLowEdges = etaBins, + ), + ), +) + +process.HLTGenValSourceELE = cms.EDProducer('HLTGenValSource', + # these are the only one the user needs to specify + objType = cms.string("ele"), + hltPathsToCheck = cms.vstring( + "HLT_Ele35_WPTight_Gsf_v", + "HLT_Ele35_WPTight_Gsf_v:bins=ptBinsJet", + "HLT_Ele115_CaloIdVT_GsfTrkIdT_v:region=EB", + "HLT_Ele115_CaloIdVT_GsfTrkIdT_v:region=EE", + "HLT_Photon200_v" + ), + binnings = cms.VPSet( + cms.PSet( + name = cms.string("ptBinsJet"), + vsVar = cms.string("pt"), + binLowEdges = ptBinsJet + ) + ), + doOnlyLastFilter = cms.bool(False), + histConfigs = cms.VPSet( + cms.PSet( + vsVar = cms.string("pt"), + binLowEdges = ptBins, + rangeCuts = cms.VPSet(etaCut) + ), + cms.PSet( + vsVar = cms.string("eta"), + binLowEdges = etaBins, + ), + ), +) + +process.HLTGenValSourceAK4 = cms.EDProducer('HLTGenValSource', + # these are the only one the user needs to specify + objType = cms.string("AK4jet"), + hltPathsToCheck = cms.vstring( + "HLT_PFJet500", + ), + doOnlyLastFilter = cms.bool(False), + histConfigs = cms.VPSet( + cms.PSet( + vsVar = cms.string("pt"), + binLowEdges = ptBinsJet, + rangeCuts = cms.VPSet(etaCut) + ), + cms.PSet( + vsVar = cms.string("eta"), + binLowEdges = etaBins, + ), + ), +) + +process.HLTGenValSourceAK8 = cms.EDProducer('HLTGenValSource', + # these are the only one the user needs to specify + objType = cms.string("AK8jet"), + hltPathsToCheck = cms.vstring( + "HLT_AK8PFJet500", + "HLT_AK8PFJet400_TrimMass30", + ), + doOnlyLastFilter = cms.bool(False), + histConfigs = cms.VPSet( + cms.PSet( + vsVar = cms.string("pt"), + binLowEdges = ptBinsJet, + rangeCuts = cms.VPSet(etaCut) + ), + cms.PSet( + vsVar = cms.string("eta"), + binLowEdges = etaBins, + ), + ), +) + +process.HLTGenValSourceMET = cms.EDProducer('HLTGenValSource', + # these are the only one the user needs to specify + objType = cms.string("MET"), + hltPathsToCheck = cms.vstring( + "HLT_PFMET120_PFMHT120_IDTight", + ), + doOnlyLastFilter = cms.bool(False), + histConfigs = cms.VPSet( + cms.PSet( + vsVar = cms.string("pt"), + binLowEdges = ptBins, + rangeCuts = cms.VPSet(etaCut) + ), + cms.PSet( + vsVar = cms.string("eta"), + binLowEdges = etaBins, + ), + ), +) + +process.p = cms.Path( + process.HLTGenValSourceMU * + process.HLTGenValSourceELE * + process.HLTGenValSourceHT * + process.HLTGenValSourceAK4 * + process.HLTGenValSourceAK8 + #process.HLTGenValSourceMET + ) + +# the harvester +process.harvester = DQMEDHarvester("HLTGenValClient", + outputFileName = cms.untracked.string('output.root'), + subDirs = cms.untracked.vstring("HLTGenVal"), +) + +process.outpath = cms.EndPath(process.harvester) diff --git a/Validation/HLTrigger/test/Run4test_cfg.py b/Validation/HLTrigger/test/Run4test_cfg.py new file mode 100644 index 0000000000000..c20405089c30b --- /dev/null +++ b/Validation/HLTrigger/test/Run4test_cfg.py @@ -0,0 +1,293 @@ +import FWCore.ParameterSet.Config as cms + +process = cms.Process("HLTGenValSource") + +process.load("FWCore.MessageService.MessageLogger_cfi") +process.load("DQMServices.Core.DQM_cfg") +process.load("DQMServices.Core.DQMStore_cfg") +process.load("DQMServices.Components.DQMEnvironment_cfi") +process.load("DQMServices.Components.MEtoEDMConverter_cff") +from DQMServices.Core.DQMEDHarvester import DQMEDHarvester + +process.maxEvents = cms.untracked.PSet( input = cms.untracked.int32(-1) ) + +process.load("FWCore.MessageService.MessageLogger_cfi") +process.MessageLogger.cerr.FwkReport.reportEvery = 100 + +process.source = cms.Source("PoolSource", + fileNames = cms.untracked.vstring( + 'file:input/RelValTTbar_14TeV_Phase2HLT.root' + ) +) + +ptBinsLow = cms.vdouble(0, 10, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 90, 100) +ptBinsMed = cms.vdouble(0, 25, 50, 75, 100, 125, 150, 175, 200, 225, 250, 275, 300, 325, 350, 375, 400, 425, 450, 475, 500) +ptBinsHigh = cms.vdouble(0, 50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500) +etaBins=cms.vdouble(-4,-3, -2.5, -2, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2, 2.5, 3, 4) + +etaCut=cms.PSet( + rangeVar=cms.string("eta"), + allowedRanges=cms.vstring("-2.4:2.4") +) + +# AK4 jets +process.HLTGenValSourceAK4 = cms.EDProducer('HLTGenValSource', + # these are the only one the user needs to specify + objType = cms.string("AK4jet"), + hltPathsToCheck = cms.vstring( + "l1tReconstructionPath", + "L1T_SinglePFPuppiJet230off", + "HLT_AK4PFPuppiJet520", + "L1T_PFHT400PT30_QuadPFPuppiJet_70_55_40_40_2p4", + "L1T_DoublePFPuppiJets112_2p4_DEta1p6", + "HLT_PFHT330PT30_QuadPFPuppiJet_75_60_45_40_TriplePFPuppiBTagDeepCSV_2p4", + "HLT_PFHT200PT30_QuadPFPuppiJet_70_40_30_30_TriplePFPuppiBTagDeepCSV_2p4", + "HLT_DoublePFPuppiJets128_DoublePFPuppiBTagDeepCSV_2p4", + "HLT_PFHT330PT30_QuadPFPuppiJet_75_60_45_40_TriplePFPuppiBTagDeepFlavour_2p4", + "HLT_PFHT200PT30_QuadPFPuppiJet_70_40_30_30_TriplePFPuppiBTagDeepFlavour_2p4", + "HLT_DoublePFPuppiJets128_DoublePFPuppiBTagDeepFlavour_2p4", + ), + hltProcessName = cms.string("HLTX"), + doOnlyLastFilter = cms.bool(False), + histConfigs = cms.VPSet( + cms.PSet( + vsVar = cms.string("pt"), + binLowEdges = ptBinsMed, + rangeCuts = cms.VPSet(etaCut) + ), + cms.PSet( + vsVar = cms.string("eta"), + binLowEdges = etaBins, + ), + ), +) + +process.HLTGenValSourceAK4HT = cms.EDProducer('HLTGenValSource', + # these are the only one the user needs to specify + objType = cms.string("AK4HT"), + hltPathsToCheck = cms.vstring( + "l1tReconstructionPath", + "L1T_PFPuppiHT450off", + "HLT_PFPuppiHT1070", + "HLT_PFPuppiMETTypeOne140_PFPuppiMHT140", + "L1T_PFHT400PT30_QuadPFPuppiJet_70_55_40_40_2p4", + "HLT_PFHT330PT30_QuadPFPuppiJet_75_60_45_40_TriplePFPuppiBTagDeepCSV_2p4", + "HLT_PFHT200PT30_QuadPFPuppiJet_70_40_30_30_TriplePFPuppiBTagDeepCSV_2p4", + "HLT_PFHT330PT30_QuadPFPuppiJet_75_60_45_40_TriplePFPuppiBTagDeepFlavour_2p4", + "HLT_PFHT200PT30_QuadPFPuppiJet_70_40_30_30_TriplePFPuppiBTagDeepFlavour_2p4", + ), + hltProcessName = cms.string("HLTX"), + doOnlyLastFilter = cms.bool(False), + histConfigs = cms.VPSet( + cms.PSet( + vsVar = cms.string("pt"), + binLowEdges = ptBinsHigh, + ), + cms.PSet( + vsVar = cms.string("eta"), + binLowEdges = etaBins, + ), + ), +) + +process.HLTGenValSourceMET = cms.EDProducer('HLTGenValSource', + # these are the only one the user needs to specify + objType = cms.string("MET"), + hltPathsToCheck = cms.vstring( + "l1tReconstructionPath", + "L1T_PFPuppiMET220off", + "HLT_PFPuppiMETTypeOne140_PFPuppiMHT140", + ), + hltProcessName = cms.string("HLTX"), + doOnlyLastFilter = cms.bool(False), + histConfigs = cms.VPSet( + cms.PSet( + vsVar = cms.string("pt"), + binLowEdges = ptBinsMed, + ), + cms.PSet( + vsVar = cms.string("eta"), + binLowEdges = etaBins, + ), + ), +) + +process.HLTGenValSourceMU = cms.EDProducer('HLTGenValSource', + # these are the only one the user needs to specify + objType = cms.string("mu"), + hltPathsToCheck = cms.vstring( + "L1T_SingleTkMuon_22", + "L1T_DoubleTkMuon_15_7", + "L1T_TripleTkMuon_5_3_3", + "HLT_Mu50_FromL1TkMuon", + "HLT_IsoMu24_FromL1TkMuon", + "HLT_Mu37_Mu27_FromL1TkMuon", + "HLT_Mu17_TrkIsoVVL_Mu8_TrkIsoVVL_DZ_FromL1TkMuon", + "HLT_TriMu_10_5_5_DZ_FromL1TkMuon", + ), + hltProcessName = cms.string("HLTX"), + doOnlyLastFilter = cms.bool(False), + histConfigs = cms.VPSet( + cms.PSet( + vsVar = cms.string("pt"), + binLowEdges = ptBinsLow, + ), + cms.PSet( + vsVar = cms.string("eta"), + binLowEdges = etaBins, + ), + ), +) + +process.HLTGenValSourceELE = cms.EDProducer('HLTGenValSource', + # these are the only one the user needs to specify + objType = cms.string("ele"), + hltPathsToCheck = cms.vstring( + "l1tReconstructionPath", + "L1T_TkEm51", + "L1T_TkEle36", + "L1T_TkIsoEm36", + "L1T_TkIsoEle28", + "L1T_TkEm37TkEm24", + "L1T_TkEle25TkEle12", + "L1T_TkIsoEm22TkIsoEm12", + "L1T_TkIsoEle22TkEm12", + "HLT_Ele32_WPTight_Unseeded", + "HLT_Ele26_WP70_Unseeded", + "HLT_Ele32_WPTight_L1Seeded", + "HLT_Ele26_WP70_L1Seeded", + "MC_Ele5_Open_Unseeded", + "MC_Ele5_WP70_Open_Unseeded", + "MC_Ele5_Open_L1Seeded", + "MC_Ele5_WP70_Open_L1Seeded", + ), + hltProcessName = cms.string("HLTX"), + doOnlyLastFilter = cms.bool(False), + histConfigs = cms.VPSet( + cms.PSet( + vsVar = cms.string("pt"), + binLowEdges = ptBinsLow, + ), + cms.PSet( + vsVar = cms.string("eta"), + binLowEdges = etaBins, + ), + ), +) + +process.HLTGenValSourcePHO = cms.EDProducer('HLTGenValSource', + # these are the only one the user needs to specify + objType = cms.string("pho"), + hltPathsToCheck = cms.vstring( + "l1tReconstructionPath", + "HLT_Photon108EB_TightID_TightIso_Unseeded", + "HLT_Photon187_Unseeded", + "HLT_DoubleEle25_CaloIdL_PMS2_Unseeded", + "HLT_Diphoton30_23_IsoCaloId_Unseeded", + "HLT_Photon108EB_TightID_TightIso_L1Seeded", + "HLT_Photon187_L1Seeded", + "HLT_DoubleEle23_12_Iso_L1Seeded", + "HLT_Diphoton30_23_IsoCaloId_L1Seeded", + "MC_Photon100_Open_Unseeded", + "MC_Photon100EB_TightID_TightIso_Open_Unseeded", + "MC_Photon100_Open_L1Seeded", + "MC_Photon100EB_TightID_TightIso_Open_L1Seeded" + ), + hltProcessName = cms.string("HLTX"), + doOnlyLastFilter = cms.bool(False), + histConfigs = cms.VPSet( + cms.PSet( + vsVar = cms.string("pt"), + binLowEdges = ptBinsLow, + ), + cms.PSet( + vsVar = cms.string("eta"), + binLowEdges = etaBins, + ), + ), +) + +process.HLTGenValSourceTEMPLATE = cms.EDProducer('HLTGenValSource', + # these are the only one the user needs to specify + objType = cms.string("TEMPLATE DONT USE"), + hltPathsToCheck = cms.vstring( + "l1tReconstructionPath", + "L1T_SinglePFPuppiJet230off", + "L1T_PFPuppiHT450off", + "L1T_PFPuppiMET220off", + "HLT_AK4PFPuppiJet520", + "HLT_PFPuppiHT1070", + "HLT_PFPuppiMETTypeOne140_PFPuppiMHT140", + "L1T_PFHT400PT30_QuadPFPuppiJet_70_55_40_40_2p4", + "L1T_DoublePFPuppiJets112_2p4_DEta1p6", + "HLT_PFHT330PT30_QuadPFPuppiJet_75_60_45_40_TriplePFPuppiBTagDeepCSV_2p4", + "HLT_PFHT200PT30_QuadPFPuppiJet_70_40_30_30_TriplePFPuppiBTagDeepCSV_2p4", + "HLT_DoublePFPuppiJets128_DoublePFPuppiBTagDeepCSV_2p4", + "HLT_PFHT330PT30_QuadPFPuppiJet_75_60_45_40_TriplePFPuppiBTagDeepFlavour_2p4", + "HLT_PFHT200PT30_QuadPFPuppiJet_70_40_30_30_TriplePFPuppiBTagDeepFlavour_2p4", + "HLT_DoublePFPuppiJets128_DoublePFPuppiBTagDeepFlavour_2p4", + "L1T_SingleTkMuon_22", + "L1T_DoubleTkMuon_15_7", + "L1T_TripleTkMuon_5_3_3", + "HLT_Mu50_FromL1TkMuon", + "HLT_IsoMu24_FromL1TkMuon", + "HLT_Mu37_Mu27_FromL1TkMuon", + "HLT_Mu17_TrkIsoVVL_Mu8_TrkIsoVVL_DZ_FromL1TkMuon", + "HLT_TriMu_10_5_5_DZ_FromL1TkMuon", + "L1T_TkEm51", + "L1T_TkEle36", + "L1T_TkIsoEm36", + "L1T_TkIsoEle28", + "L1T_TkEm37TkEm24", + "L1T_TkEle25TkEle12", + "L1T_TkIsoEm22TkIsoEm12", + "L1T_TkIsoEle22TkEm12", + "HLT_Ele32_WPTight_Unseeded", + "HLT_Ele26_WP70_Unseeded", + "HLT_Photon108EB_TightID_TightIso_Unseeded", + "HLT_Photon187_Unseeded", + "HLT_DoubleEle25_CaloIdL_PMS2_Unseeded", + "HLT_Diphoton30_23_IsoCaloId_Unseeded", + "HLT_Ele32_WPTight_L1Seeded", + "HLT_Ele26_WP70_L1Seeded", + "HLT_Photon108EB_TightID_TightIso_L1Seeded", + "HLT_Photon187_L1Seeded", + "HLT_DoubleEle25_CaloIdL_PMS2_L1Seeded", + "HLT_DoubleEle23_12_Iso_L1Seeded", + "HLT_Diphoton30_23_IsoCaloId_L1Seeded", + "L1T_DoubleNNTau52", + "L1T_SingleNNTau150", + "MC_JME", + "MC_BTV", + "MC_Ele5_Open_Unseeded", + "MC_Ele5_WP70_Open_Unseeded", + "MC_Ele5_Open_L1Seeded", + "MC_Ele5_WP70_Open_L1Seeded", + "MC_Photon100_Open_Unseeded", + "MC_Photon100EB_TightID_TightIso_Open_Unseeded", + "MC_Photon100_Open_L1Seeded", + "MC_Photon100EB_TightID_TightIso_Open_L1Seeded" + ), + hltProcessName = cms.string("HLTX"), + doOnlyLastFilter = cms.bool(False), + histConfigs = cms.VPSet( + cms.PSet( + vsVar = cms.string("pt"), + binLowEdges = ptBinsHigh, + ), + cms.PSet( + vsVar = cms.string("eta"), + binLowEdges = etaBins, + ), + ), +) + +process.p = cms.Path(process.HLTGenValSourceAK4*process.HLTGenValSourceAK4HT*process.HLTGenValSourceMU*process.HLTGenValSourceMET*process.HLTGenValSourceELE*process.HLTGenValSourcePHO) + +# the harvester +process.harvester = DQMEDHarvester("HLTGenValClient", + outputFileName = cms.untracked.string('upgrade_run4_test.root'), + subDirs = cms.untracked.vstring("HLTGenVal"), +) + +process.outpath = cms.EndPath(process.harvester)