From 70cdb973eb995bd020db9d8830f0ef53bb3fd043 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Thu, 19 Dec 2019 17:06:45 +0100 Subject: [PATCH] New LHEWeightsTableProducer --- PhysicsTools/NanoAOD/BuildFile.xml | 1 + .../plugins/GenWeightsTableProducer.cc | 45 +----- .../plugins/LHEWeightsTableProducer.cc | 138 ++++++++++++++++++ PhysicsTools/NanoAOD/python/nanogen_cff.py | 114 +++++++++++++++ 4 files changed, 254 insertions(+), 44 deletions(-) create mode 100644 PhysicsTools/NanoAOD/plugins/LHEWeightsTableProducer.cc create mode 100644 PhysicsTools/NanoAOD/python/nanogen_cff.py diff --git a/PhysicsTools/NanoAOD/BuildFile.xml b/PhysicsTools/NanoAOD/BuildFile.xml index c36ed4184624a..1d6f1f6d5dccb 100644 --- a/PhysicsTools/NanoAOD/BuildFile.xml +++ b/PhysicsTools/NanoAOD/BuildFile.xml @@ -5,6 +5,7 @@ + diff --git a/PhysicsTools/NanoAOD/plugins/GenWeightsTableProducer.cc b/PhysicsTools/NanoAOD/plugins/GenWeightsTableProducer.cc index 77c8989defef1..9a86e108bc1b8 100644 --- a/PhysicsTools/NanoAOD/plugins/GenWeightsTableProducer.cc +++ b/PhysicsTools/NanoAOD/plugins/GenWeightsTableProducer.cc @@ -233,10 +233,6 @@ class GenWeightsTableProducer : public edm::global::EDProducer(); produces("genModel"); - produces("LHEScale"); - produces("LHEPdf"); - produces("LHEReweighting"); - produces("LHENamed"); produces("PS"); produces(); if (namedWeightIDs_.size() != namedWeightLabels_.size()) { @@ -273,7 +269,6 @@ class GenWeightsTableProducer : public edm::global::EDProducer lheScaleTab, lhePdfTab, lheRwgtTab, lheNamedTab; std::unique_ptr genPSTab; edm::Handle lheInfo; @@ -287,25 +282,16 @@ class GenWeightsTableProducer : public edm::global::EDProducer& outScale, - std::unique_ptr& outPdf, - std::unique_ptr& outRwgt, - std::unique_ptr& outNamed, std::unique_ptr& outPS) const { bool lheDebug = debug_.exchange( false); // make sure only the first thread dumps out this (even if may still be mixed up with other output, but nevermind) @@ -367,31 +349,6 @@ class GenWeightsTableProducer : public edm::global::EDProduceraddColumn( - "", wScale, weightChoice->scaleWeightsDoc, nanoaod::FlatTable::FloatColumn, lheWeightPrecision_); - - outPdf.reset(new nanoaod::FlatTable(wPDF.size(), "LHEPdfWeight", false)); - outPdf->addColumn( - "", wPDF, weightChoice->pdfWeightsDoc, nanoaod::FlatTable::FloatColumn, lheWeightPrecision_); - - outRwgt.reset(new nanoaod::FlatTable(wRwgt.size(), "LHEReweightingWeight", false)); - outRwgt->addColumn( - "", wRwgt, weightChoice->rwgtWeightDoc, nanoaod::FlatTable::FloatColumn, lheWeightPrecision_); - - outNamed.reset(new nanoaod::FlatTable(1, "LHEWeight", true)); - outNamed->addColumnValue("originalXWGTUP", - lheProd.originalXWGTUP(), - "Nominal event weight in the LHE file", - nanoaod::FlatTable::FloatColumn); - for (unsigned int i = 0, n = wNamed.size(); i < n; ++i) { - outNamed->addColumnValue(namedWeightLabels_[i], - wNamed[i], - "LHE weight for id " + namedWeightIDs_[i] + ", relative to nominal", - nanoaod::FlatTable::FloatColumn, - lheWeightPrecision_); - } - counter->incLHE(genWeight, wScale, wPDF, wRwgt, wNamed, wPS); } diff --git a/PhysicsTools/NanoAOD/plugins/LHEWeightsTableProducer.cc b/PhysicsTools/NanoAOD/plugins/LHEWeightsTableProducer.cc new file mode 100644 index 0000000000000..f3584332186c9 --- /dev/null +++ b/PhysicsTools/NanoAOD/plugins/LHEWeightsTableProducer.cc @@ -0,0 +1,138 @@ +#include "FWCore/Framework/interface/global/EDProducer.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/Run.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "DataFormats/NanoAOD/interface/FlatTable.h" +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "SimDataFormats/GeneratorProducts/interface/LHEEventProduct.h" +#include "SimDataFormats/GeneratorProducts/interface/LHERunInfoProduct.h" +#include "FWCore/MessageLogger/interface/MessageLogger.h" + +#include +#include + +namespace { + + // join vector of strings to one string + std::string join(const std::vector& vec, const char* delim) { + std::stringstream res; + std::copy(vec.begin(), vec.end(), std::ostream_iterator(res, delim)); + return res.str(); + } + + struct LHEWeightInfo { + std::string id; + std::string text; + std::optional group = std::nullopt; + }; + + + std::vector getLHEWeightInfos(LHERunInfoProduct const& lheInfo) { + std::vector out; + + for (auto iter = lheInfo.headers_begin(), end = lheInfo.headers_end(); iter != end; ++iter) { + if (iter->tag() != "initrwgt") { + continue; + } + + tinyxml2::XMLDocument xmlDoc; + xmlDoc.Parse(("" + join(iter->lines(), "") + "").c_str()); + tinyxml2::XMLElement* root = xmlDoc.FirstChildElement("root"); + + for (auto* e = root->FirstChildElement(); e != nullptr; e = e->NextSiblingElement()) { + if (strcmp(e->Name(), "weight") == 0) { + // we are here if there is a weight that does not belong to any group + std::string text = ""; + if(e->GetText()) text = e->GetText(); + out.push_back({e->Attribute("id"), text}); + } + if (strcmp(e->Name(), "weightgroup") == 0) { + std::string groupName = e->Attribute("name"); + for (auto* inner = e->FirstChildElement("weight"); inner != nullptr; + inner = inner->NextSiblingElement("weight")) { + // we are here if there is a weight in a weightgroup + std::string text = ""; + if(inner->GetText()) text = inner->GetText(); + out.push_back({inner->Attribute("id"), text, groupName}); + } + } + } + } + + return out; + } + +} + +class LHEWeightsTableProducer : public edm::global::EDProducer>> { + public: + LHEWeightsTableProducer( edm::ParameterSet const & params ) : + lheInputTag_(params.getParameter("lheInfo")), + lheToken_(consumes(params.getParameter("lheInfo"))), + lheWeightPrecision_(params.getParameter("lheWeightPrecision")) + { + consumes(lheInputTag_); + produces(); + } + + void produce(edm::StreamID id, edm::Event& iEvent, const edm::EventSetup& iSetup) const override { + // tables for LHE weights, may not be filled + auto const& lheInfo = iEvent.get(lheToken_); + + auto lheWeightsTab = std::make_unique(1, "LHEWeight", true); + + auto const& weightInfos = *runCache(iEvent.getRun().index()); + + double w0 = lheInfo.originalXWGTUP(); + + int i = 0; + if(lheInfo.weights().size() != weightInfos.size()) { + throw cms::Exception("LogicError", "Weight labels don't have the same size as weights!\n"); + } + for(auto const& weight : lheInfo.weights()) { + if(!weightInfos[i].group) { + // for now we ignore the ungrouped weights + continue; + } + auto const& label = (*weightInfos[i].group) + "__" + weightInfos[i].id; + lheWeightsTab->addColumnValue(label, weight.wgt / w0, weightInfos[i].text + " (w_var / w_nominal)", nanoaod::FlatTable::FloatColumn, lheWeightPrecision_); + ++i; + } + + iEvent.put(std::move(lheWeightsTab)); + } + + std::shared_ptr> globalBeginRun(edm::Run const& iRun, edm::EventSetup const&) const override { + edm::Handle lheInfo; + + auto weightChoice = std::make_shared>(); + + // getByToken throws since we're not in the endRun (see https://github.com/cms-sw/cmssw/pull/18499) + iRun.getByLabel(lheInputTag_, lheInfo); + if (lheInfo.isValid()) { + getLHEWeightInfos(*lheInfo).swap(*weightChoice); + } + + return weightChoice; + } + + // nothing to do here + void globalEndRun(edm::Run const&, edm::EventSetup const&) const override {} + + static void fillDescriptions(edm::ConfigurationDescriptions & descriptions) { + edm::ParameterSetDescription desc; + desc.add("lheInfo", {"externalLHEProducer"})->setComment("tag(s) for the LHE information (LHEEventProduct and LHERunInfoProduct)"); + desc.add("lheWeightPrecision", -1)->setComment("Number of bits in the mantissa for LHE weights"); + descriptions.addDefault(desc); + } + + + protected: + const edm::InputTag lheInputTag_; + const edm::EDGetTokenT lheToken_; + int lheWeightPrecision_; +}; + +#include "FWCore/Framework/interface/MakerMacros.h" +DEFINE_FWK_MODULE(LHEWeightsTableProducer); diff --git a/PhysicsTools/NanoAOD/python/nanogen_cff.py b/PhysicsTools/NanoAOD/python/nanogen_cff.py new file mode 100644 index 0000000000000..d5efb1ced3282 --- /dev/null +++ b/PhysicsTools/NanoAOD/python/nanogen_cff.py @@ -0,0 +1,114 @@ +from PhysicsTools.NanoAOD.common_cff import * +from PhysicsTools.NanoAOD.taus_cff import * +from PhysicsTools.NanoAOD.jets_cff import * +from PhysicsTools.NanoAOD.globals_cff import * +from PhysicsTools.NanoAOD.genparticles_cff import * +from PhysicsTools.NanoAOD.particlelevel_cff import * +from PhysicsTools.NanoAOD.lheInfoTable_cfi import * + +# duplicate definition with nano_cff right now +genWeightsTable = cms.EDProducer( + "GenWeightsTableProducer", + genEvent = cms.InputTag("generator"), + genLumiInfoHeader = cms.InputTag("generator"), + lheInfo = cms.VInputTag(cms.InputTag("externalLHEProducer"), cms.InputTag("source")), + preferredPDFs = cms.VPSet( # see https://lhapdf.hepforge.org/pdfsets.html + cms.PSet(name = cms.string("PDF4LHC15_nnlo_30_pdfas"), lhaid = cms.uint32(91400)), + cms.PSet(name = cms.string("NNPDF31_nnlo_hessian_pdfas"), lhaid = cms.uint32(306000)), + # for some 92X samples. Note that the nominal weight, 260000, is not included in the LHE ... + cms.PSet(name = cms.string("NNPDF30_nlo_as_0118"), lhaid = cms.uint32(260000)), + # some MLM 80X samples have only this (e.g. /store/mc/RunIISummer16MiniAODv2/DYJetsToLL_M-50_TuneCUETP8M1_13TeV-madgraphMLM-pythia8/MINIAODSIM/PUMoriond17_80X_mcRun2_asymptotic_2016_TrancheIV_v6_ext1-v2/120000/02A210D6-F5C3-E611-B570-008CFA197BD4.root ) + cms.PSet(name = cms.string("NNPDF30_lo_as_0130"), lhaid = cms.uint32(262000)), + # some FXFX 80X samples have only this (e.g. WWTo1L1Nu2Q, WWTo4Q) + cms.PSet(name = cms.string("NNPDF30_nlo_nf_4_pdfas"), lhaid = cms.uint32(292000)), + # some FXFX 80X samples have only this (e.g. DYJetsToLL_Pt, WJetsToLNu_Pt, DYJetsToNuNu_Pt) + cms.PSet(name = cms.string("NNPDF30_nlo_nf_5_pdfas"), lhaid = cms.uint32(292200)), + ), + namedWeightIDs = cms.vstring(), + namedWeightLabels = cms.vstring(), + lheWeightPrecision = cms.int32(14), + maxPdfWeights = cms.uint32(150), + debug = cms.untracked.bool(False), +) + +lheWeightsTable = cms.EDProducer( + "LHEWeightsTableProducer", + lheInfo = cms.InputTag("externalLHEProducer"), + lheWeightPrecision = cms.int32(14), +) + +nanoMetadata = cms.EDProducer("UniqueStringProducer", + strings = cms.PSet( + tag = cms.string("untagged"), + ) +) + +metGenTable = cms.EDProducer("SimpleCandidateFlatTableProducer", + src = cms.InputTag("genMetTrue"), + name = cms.string("GenMET"), + doc = cms.string("Gen MET"), + singleton = cms.bool(True), + extension = cms.bool(False), + variables = cms.PSet( + pt = Var("pt", float, doc="pt", precision=10), + phi = Var("phi", float, doc="phi", precision=10), + ), +) + +nanogenSequence = cms.Sequence( + nanoMetadata+ + particleLevel+ + genJetTable+ + patJetPartons+ + genJetFlavourAssociation+ + genJetFlavourTable+ + genJetAK8Table+ + genJetAK8FlavourAssociation+ + genJetAK8FlavourTable+ + tauGenJets+ + tauGenJetsSelectorAllHadrons+ + genVisTaus+ + genVisTauTable+ + genTable+ + genWeightsTable+ + lheWeightsTable+ + genParticleTables+ + tautagger+ + rivetProducerHTXS+ + particleLevelTables+ + metGenTable+ + lheInfoTable +) + +NANOAODGENoutput = cms.OutputModule("NanoAODOutputModule", + compressionAlgorithm = cms.untracked.string('LZMA'), + compressionLevel = cms.untracked.int32(9), + dataset = cms.untracked.PSet( + dataTier = cms.untracked.string('NANOAODSIM'), + filterName = cms.untracked.string('') + ), + fileName = cms.untracked.string('nanogen.root'), + outputCommands = cms.untracked.vstring( + 'drop *', + "keep nanoaodFlatTable_*Table_*_*", # event data + "keep String_*_genModel_*", # generator model data + "keep nanoaodMergeableCounterTable_*Table_*_*", # accumulated per/run or per/lumi data + "keep nanoaodUniqueString_nanoMetadata_*_*", # basic metadata + ) +) + +def customizeNanoGEN(process): + process.genParticleTable.src = "genParticles" + process.patJetPartons.particles = "genParticles" + process.particleLevel.src = "generatorSmeared" + process.rivetProducerHTXS.HepMCCollection = "generatorSmeared" + + process.genJetTable.src = "ak4GenJetsNoNu" + process.genJetFlavourAssociation.jets = process.genJetTable.src + process.genJetFlavourTable.src = process.genJetTable.src + process.genJetFlavourTable.jetFlavourInfos = "genJetFlavourAssociation" + process.genJetAK8Table.src = "ak8GenJetsNoNu" + process.genJetAK8FlavourAssociation.jets = process.genJetAK8Table.src + process.genJetAK8FlavourTable.src = process.genJetAK8Table.src + process.tauGenJets.GenParticles = "genParticles" + process.genVisTaus.srcGenParticles = "genParticles"