diff --git a/PhysicsTools/NanoAOD/interface/SimpleFlatTableProducer.h b/PhysicsTools/NanoAOD/interface/SimpleFlatTableProducer.h index 087fa85bdb3b9..e72f9ebf7a7c0 100644 --- a/PhysicsTools/NanoAOD/interface/SimpleFlatTableProducer.h +++ b/PhysicsTools/NanoAOD/interface/SimpleFlatTableProducer.h @@ -1,4 +1,5 @@ #include "FWCore/Framework/interface/stream/EDProducer.h" +#include "FWCore/Framework/interface/one/EDProducer.h" #include "FWCore/ParameterSet/interface/ParameterSet.h" #include "FWCore/Framework/interface/ConsumesCollector.h" #include "DataFormats/Common/interface/View.h" @@ -271,3 +272,144 @@ class FirstObjectSimpleFlatTableProducer : public SimpleFlatTableProducerBase +class SimpleFlatTableProducerBaseLumi + : public edm::one::EDProducer> { +public: + SimpleFlatTableProducerBaseLumi(edm::ParameterSet const ¶ms) + : name_(params.getParameter("name")), + doc_(params.existsAs("doc") ? params.getParameter("doc") : ""), + extension_(params.existsAs("extension") ? params.getParameter("extension") : false), + skipNonExistingSrc_( + params.existsAs("skipNonExistingSrc") ? params.getParameter("skipNonExistingSrc") : false), + src_(skipNonExistingSrc_ ? mayConsume(params.getParameter("src")) + : consumes(params.getParameter("src"))) { + edm::ParameterSet const &varsPSet = params.getParameter("variables"); + for (const std::string &vname : varsPSet.getParameterNamesForType()) { + const auto &varPSet = varsPSet.getParameter(vname); + const std::string &type = varPSet.getParameter("type"); + if (type == "int") + vars_.push_back(std::make_unique(vname, varPSet)); + else if (type == "float") + vars_.push_back(std::make_unique(vname, varPSet)); + else if (type == "uint8") + vars_.push_back(std::make_unique(vname, varPSet)); + else if (type == "bool") + vars_.push_back(std::make_unique(vname, varPSet)); + else + throw cms::Exception("Configuration", "unsupported type " + type + " for variable " + vname); + } + + produces(); + } + + ~SimpleFlatTableProducerBaseLumi() override {} + + std::shared_ptr globalBeginLuminosityBlock(edm::LuminosityBlock const &, + edm::EventSetup const &) const override { + return nullptr; + } + + void globalEndLuminosityBlock(edm::LuminosityBlock const &, edm::EventSetup const &) override {} + + // this is to be overriden by the child class + virtual std::unique_ptr fillTable(const edm::LuminosityBlock &iLumi, + const edm::Handle &prod) const = 0; + + void produce(edm::Event &iEvent, const edm::EventSetup &iSetup) override { + // do nothing + } + + void endLuminosityBlockProduce(edm::LuminosityBlock &iLumi, const edm::EventSetup &iSetup) final { + edm::Handle src; + iLumi.getByToken(src_, src); + + std::unique_ptr out = fillTable(iLumi, src); + out->setDoc(doc_); + + iLumi.put(std::move(out)); + } + +protected: + const std::string name_; + const std::string doc_; + const bool extension_; + const bool skipNonExistingSrc_; + const edm::EDGetTokenT src_; + + class VariableBase { + public: + VariableBase(const std::string &aname, const edm::ParameterSet &cfg) + : name_(aname), + doc_(cfg.getParameter("doc")), + precision_(cfg.existsAs("precision") ? cfg.getParameter("precision") + : (cfg.existsAs("precision") ? -2 : -1)) {} + virtual ~VariableBase() {} + const std::string &name() const { return name_; } + + protected: + std::string name_, doc_; + int precision_; + }; + + class Variable : public VariableBase { + public: + Variable(const std::string &aname, const edm::ParameterSet &cfg) : VariableBase(aname, cfg) {} + virtual void fill(std::vector selobjs, nanoaod::FlatTable &out) const = 0; + }; + + template + class FuncVariable : public Variable { + public: + FuncVariable(const std::string &aname, const edm::ParameterSet &cfg) + : Variable(aname, cfg), + func_(cfg.getParameter("expr"), true), + precisionFunc_(cfg.existsAs("precision") ? cfg.getParameter("precision") : "23", + true) {} + ~FuncVariable() override {} + void fill(std::vector selobjs, nanoaod::FlatTable &out) const override { + std::vector vals(selobjs.size()); + for (unsigned int i = 0, n = vals.size(); i < n; ++i) { + if constexpr (std::is_same()) { + if (this->precision_ == -2) { + vals[i] = + MiniFloatConverter::reduceMantissaToNbitsRounding(func_(*selobjs[i]), precisionFunc_(*selobjs[i])); + } else { + vals[i] = func_(*selobjs[i]); + } + } else { + vals[i] = func_(*selobjs[i]); + } + } + out.template addColumn(this->name_, vals, this->doc_, this->precision_); + } + + protected: + StringFunctor func_; + StringFunctor precisionFunc_; + }; + typedef FuncVariable, int> IntVar; + typedef FuncVariable, float> FloatVar; + typedef FuncVariable, uint8_t> UInt8Var; + typedef FuncVariable, bool> BoolVar; + std::vector> vars_; +}; + +template +class LumiSingletonSimpleFlatTableProducer : public SimpleFlatTableProducerBaseLumi { +public: + LumiSingletonSimpleFlatTableProducer(edm::ParameterSet const ¶ms) + : SimpleFlatTableProducerBaseLumi(params) {} + + ~LumiSingletonSimpleFlatTableProducer() override {} + + std::unique_ptr fillTable(const edm::LuminosityBlock &, + const edm::Handle &prod) const override { + auto out = std::make_unique(1, this->name_, true, this->extension_); + std::vector selobjs(1, prod.product()); + for (const auto &var : this->vars_) + var->fill(selobjs, *out); + return out; + } +}; diff --git a/PhysicsTools/NanoAOD/plugins/LumiOutputBranches.cc b/PhysicsTools/NanoAOD/plugins/LumiOutputBranches.cc new file mode 100644 index 0000000000000..181eac081f4e1 --- /dev/null +++ b/PhysicsTools/NanoAOD/plugins/LumiOutputBranches.cc @@ -0,0 +1,94 @@ +#include "PhysicsTools/NanoAOD/plugins/LumiOutputBranches.h" + +#include + +namespace { + std::string makeBranchName(const std::string &baseName, const std::string &leafName) { + return baseName.empty() ? leafName : (leafName.empty() ? baseName : baseName + "_" + leafName); + } +} // namespace + +void LumiOutputBranches::defineBranchesFromFirstEvent(const nanoaod::FlatTable &tab) { + m_baseName = tab.name(); + for (size_t i = 0; i < tab.nColumns(); i++) { + const std::string &var = tab.columnName(i); + switch (tab.columnType(i)) { + case nanoaod::FlatTable::ColumnType::Float: + m_floatBranches.emplace_back(var, tab.columnDoc(i), "F"); + break; + case nanoaod::FlatTable::ColumnType::Int: + m_intBranches.emplace_back(var, tab.columnDoc(i), "I"); + break; + case nanoaod::FlatTable::ColumnType::UInt8: + m_uint8Branches.emplace_back(var, tab.columnDoc(i), "b"); + break; + case nanoaod::FlatTable::ColumnType::Bool: + m_uint8Branches.emplace_back(var, tab.columnDoc(i), "O"); + break; + default: + throw cms::Exception("LogicError", "Unsupported type"); + } + } +} + +void LumiOutputBranches::branch(TTree &tree) { + if (!m_singleton) { + if (m_extension == IsExtension) { + m_counterBranch = tree.FindBranch(("n" + m_baseName).c_str()); + if (!m_counterBranch) { + throw cms::Exception("LogicError", + "Trying to save an extension table for " + m_baseName + + " before having saved the corresponding main table\n"); + } + } else { + if (tree.FindBranch(("n" + m_baseName).c_str()) != nullptr) { + throw cms::Exception("LogicError", "Trying to save multiple main tables for " + m_baseName + "\n"); + } + m_counterBranch = tree.Branch(("n" + m_baseName).c_str(), &m_counter, ("n" + m_baseName + "/i").c_str()); + m_counterBranch->SetTitle(m_doc.c_str()); + } + } + std::string varsize = m_singleton ? "" : "[n" + m_baseName + "]"; + for (std::vector *branches : {&m_floatBranches, &m_intBranches, &m_uint8Branches}) { + for (auto &pair : *branches) { + std::string branchName = makeBranchName(m_baseName, pair.name); + pair.branch = + tree.Branch(branchName.c_str(), (void *)nullptr, (branchName + varsize + "/" + pair.rootTypeCode).c_str()); + pair.branch->SetTitle(pair.title.c_str()); + } + } +} + +void LumiOutputBranches::fill(const edm::LuminosityBlockForOutput &iLumi, TTree &tree, bool extensions) { + if (m_extension != DontKnowYetIfMainOrExtension) { + if (extensions != m_extension) + return; // do nothing, wait to be called with the proper flag + } + + edm::Handle handle; + iLumi.getByToken(m_token, handle); + const nanoaod::FlatTable &tab = *handle; + m_counter = tab.size(); + m_singleton = tab.singleton(); + if (!m_branchesBooked) { + m_extension = tab.extension() ? IsExtension : IsMain; + if (extensions != m_extension) + return; // do nothing, wait to be called with the proper flag + defineBranchesFromFirstEvent(tab); + m_doc = tab.doc(); + m_branchesBooked = true; + branch(tree); + } + if (!m_singleton && m_extension == IsExtension) { + if (m_counter != *reinterpret_cast(m_counterBranch->GetAddress())) { + throw cms::Exception("LogicError", + "Mismatch in number of entries between extension and main table for " + tab.name()); + } + } + for (auto &pair : m_floatBranches) + fillColumn(pair, tab); + for (auto &pair : m_intBranches) + fillColumn(pair, tab); + for (auto &pair : m_uint8Branches) + fillColumn(pair, tab); +} diff --git a/PhysicsTools/NanoAOD/plugins/LumiOutputBranches.h b/PhysicsTools/NanoAOD/plugins/LumiOutputBranches.h new file mode 100644 index 0000000000000..532fe7f6e2d94 --- /dev/null +++ b/PhysicsTools/NanoAOD/plugins/LumiOutputBranches.h @@ -0,0 +1,58 @@ +#ifndef PhysicsTools_NanoAOD_LumiOutputBranches_h +#define PhysicsTools_NanoAOD_LumiOutputBranches_h + +#include +#include +#include +#include "FWCore/Framework/interface/LuminosityBlockForOutput.h" +#include "DataFormats/NanoAOD/interface/FlatTable.h" +#include "DataFormats/Provenance/interface/BranchDescription.h" +#include "FWCore/Utilities/interface/EDGetToken.h" + +class LumiOutputBranches { +public: + LumiOutputBranches(const edm::BranchDescription *desc, const edm::EDGetToken &token) + : m_token(token), m_extension(DontKnowYetIfMainOrExtension), m_branchesBooked(false) { + if (desc->className() != "nanoaod::FlatTable") + throw cms::Exception("Configuration", "NanoAODOutputModule can only write out nanoaod::FlatTable objects"); + } + + void defineBranchesFromFirstEvent(const nanoaod::FlatTable &tab); + void branch(TTree &tree); + + /// Fill the current table, if extensions == table.extension(). + /// This parameter is used so that the fill is called first for non-extensions and then for extensions + void fill(const edm::LuminosityBlockForOutput &iLumi, TTree &tree, bool extensions); + +private: + edm::EDGetToken m_token; + std::string m_baseName; + bool m_singleton; + enum { IsMain = 0, IsExtension = 1, DontKnowYetIfMainOrExtension = 2 } m_extension; + std::string m_doc; + UInt_t m_counter; + struct NamedBranchPtr { + std::string name, title, rootTypeCode; + TBranch *branch; + NamedBranchPtr(const std::string &aname, + const std::string &atitle, + const std::string &rootType, + TBranch *branchptr = nullptr) + : name(aname), title(atitle), rootTypeCode(rootType), branch(branchptr) {} + }; + TBranch *m_counterBranch; + std::vector m_floatBranches; + std::vector m_intBranches; + std::vector m_uint8Branches; + bool m_branchesBooked; + + template + void fillColumn(NamedBranchPtr &pair, const nanoaod::FlatTable &tab) { + int idx = tab.columnIndex(pair.name); + if (idx == -1) + throw cms::Exception("LogicError", "Missing column in input for " + m_baseName + "_" + pair.name); + pair.branch->SetAddress(const_cast(&tab.columnData(idx).front())); // SetAddress should take a const * ! + } +}; + +#endif diff --git a/PhysicsTools/NanoAOD/plugins/NanoAODOutputModule.cc b/PhysicsTools/NanoAOD/plugins/NanoAODOutputModule.cc index 01744ed260e59..1b53a0fc0d1b5 100644 --- a/PhysicsTools/NanoAOD/plugins/NanoAODOutputModule.cc +++ b/PhysicsTools/NanoAOD/plugins/NanoAODOutputModule.cc @@ -39,6 +39,7 @@ #include "DataFormats/NanoAOD/interface/FlatTable.h" #include "DataFormats/NanoAOD/interface/UniqueString.h" #include "PhysicsTools/NanoAOD/plugins/TableOutputBranches.h" +#include "PhysicsTools/NanoAOD/plugins/LumiOutputBranches.h" #include "PhysicsTools/NanoAOD/plugins/TriggerOutputBranches.h" #include "PhysicsTools/NanoAOD/plugins/EventStringOutputBranches.h" #include "PhysicsTools/NanoAOD/plugins/SummaryTableOutputBranches.h" @@ -128,6 +129,7 @@ class NanoAODOutputModule : public edm::one::OutputModule<> { std::vector m_runTables; std::vector m_lumiTables; + std::vector m_lumiTables2; std::vector m_runFlatTables; std::vector> m_nanoMetadata; @@ -232,6 +234,11 @@ void NanoAODOutputModule::writeLuminosityBlock(edm::LuminosityBlockForOutput con for (auto& t : m_lumiTables) t.fill(iLumi, *m_lumiTree); + for (unsigned int extensions = 0; extensions <= 1; ++extensions) { + for (auto& t : m_lumiTables2) + t.fill(iLumi, *m_lumiTree, extensions); + } + tbb::this_task_arena::isolate([&] { m_lumiTree->Fill(); }); m_processHistoryRegistry.registerProcessHistory(iLumi.processHistory()); @@ -301,6 +308,7 @@ void NanoAODOutputModule::openFile(edm::FileBlock const&) { m_evstrings.clear(); m_runTables.clear(); m_lumiTables.clear(); + m_lumiTables2.clear(); m_runFlatTables.clear(); const auto& keeps = keptProducts(); for (const auto& keep : keeps[edm::InEvent]) { @@ -320,6 +328,8 @@ void NanoAODOutputModule::openFile(edm::FileBlock const&) { m_lumiTables.push_back(SummaryTableOutputBranches(keep.first, keep.second)); else if (keep.first->className() == "nanoaod::UniqueString" && keep.first->moduleLabel() == "nanoMetadata") m_nanoMetadata.emplace_back(keep.first->productInstanceName(), keep.second); + else if (keep.first->className() == "nanoaod::FlatTable") + m_lumiTables2.push_back(LumiOutputBranches(keep.first, keep.second)); else throw cms::Exception( "Configuration", diff --git a/PhysicsTools/NanoAOD/plugins/SimpleFlatTableProducerPlugins.cc b/PhysicsTools/NanoAOD/plugins/SimpleFlatTableProducerPlugins.cc index 1207a565c8a40..404b12c6f316c 100644 --- a/PhysicsTools/NanoAOD/plugins/SimpleFlatTableProducerPlugins.cc +++ b/PhysicsTools/NanoAOD/plugins/SimpleFlatTableProducerPlugins.cc @@ -6,6 +6,9 @@ typedef SimpleFlatTableProducer SimpleCandidateFlatTableProduce #include "SimDataFormats/GeneratorProducts/interface/GenEventInfoProduct.h" typedef EventSingletonSimpleFlatTableProducer SimpleGenEventFlatTableProducer; +#include "SimDataFormats/GeneratorProducts/interface/GenFilterInfo.h" +typedef LumiSingletonSimpleFlatTableProducer SimpleGenFilterFlatTableProducerLumi; + #include "SimDataFormats/HTXS/interface/HiggsTemplateCrossSections.h" typedef EventSingletonSimpleFlatTableProducer SimpleHTXSFlatTableProducer; @@ -21,7 +24,8 @@ typedef EventSingletonSimpleFlatTableProducer SimpleXYZPointFla #include "FWCore/Framework/interface/MakerMacros.h" DEFINE_FWK_MODULE(SimpleCandidateFlatTableProducer); DEFINE_FWK_MODULE(SimpleGenEventFlatTableProducer); +DEFINE_FWK_MODULE(SimpleGenFilterFlatTableProducerLumi); DEFINE_FWK_MODULE(SimpleHTXSFlatTableProducer); DEFINE_FWK_MODULE(SimpleProtonTrackFlatTableProducer); DEFINE_FWK_MODULE(SimpleLocalTrackFlatTableProducer); -DEFINE_FWK_MODULE(SimpleXYZPointFlatTableProducer); \ No newline at end of file +DEFINE_FWK_MODULE(SimpleXYZPointFlatTableProducer); diff --git a/PhysicsTools/NanoAOD/python/globals_cff.py b/PhysicsTools/NanoAOD/python/globals_cff.py index f7fd993677679..c544e11f90522 100644 --- a/PhysicsTools/NanoAOD/python/globals_cff.py +++ b/PhysicsTools/NanoAOD/python/globals_cff.py @@ -38,5 +38,20 @@ ), ) +genFilterTable = cms.EDProducer("SimpleGenFilterFlatTableProducerLumi", + src = cms.InputTag("genFilterEfficiencyProducer"), + cut = cms.string(""), + name= cms.string("GenFilter"), + doc = cms.string("Generator filter information"), + singleton = cms.bool(True), + extension = cms.bool(False), + variables = cms.PSet( + numEventsTotal = Var("numEventsTotal()", int, doc="generator filter: total number of events", precision=6), + numEventsPassed = Var("numEventsPassed()", int, doc="generator filter: passed number of events", precision=6), + filterEfficiency = Var("filterEfficiency()", float, doc="generator filter: efficiency", precision=14), + filterEfficiencyError = Var("filterEfficiencyError()", float, doc="generator filter: efficiency error", precision=14), + ), +) + globalTablesTask = cms.Task(rhoTable) -globalTablesMCTask = cms.Task(puTable,genTable) +globalTablesMCTask = cms.Task(puTable,genTable,genFilterTable) diff --git a/PhysicsTools/NanoAOD/python/nanogen_cff.py b/PhysicsTools/NanoAOD/python/nanogen_cff.py index 8308e00e484d7..3551f0442184a 100644 --- a/PhysicsTools/NanoAOD/python/nanogen_cff.py +++ b/PhysicsTools/NanoAOD/python/nanogen_cff.py @@ -1,6 +1,6 @@ from PhysicsTools.NanoAOD.taus_cff import * from PhysicsTools.NanoAOD.jets_cff import * -from PhysicsTools.NanoAOD.globals_cff import genTable +from PhysicsTools.NanoAOD.globals_cff import genTable,genFilterTable from PhysicsTools.NanoAOD.met_cff import metMCTable from PhysicsTools.NanoAOD.genparticles_cff import * from PhysicsTools.NanoAOD.particlelevel_cff import * @@ -26,6 +26,7 @@ genJetAK8FlavourTable+ cms.Sequence(genTauTask)+ genTable+ + genFilterTable+ cms.Sequence(genParticleTablesTask)+ cms.Sequence(genVertexTablesTask)+ tautagger+