diff --git a/Configuration/PyReleaseValidation/python/relval_steps.py b/Configuration/PyReleaseValidation/python/relval_steps.py index 3bdcb7d657d7c..299e5d3b8e18b 100644 --- a/Configuration/PyReleaseValidation/python/relval_steps.py +++ b/Configuration/PyReleaseValidation/python/relval_steps.py @@ -478,7 +478,7 @@ def identitySim(wf): #input for a NANOAOD from MINIAOD workflow steps['ZEE_13_80XNanoAODINPUT']={'INPUT':InputInfo(dataSet='/RelValZEE_13/CMSSW_8_0_21-PU25ns_80X_mcRun2_asymptotic_2016_TrancheIV_v6_Tr4GT_v6-v1/MINIAODSIM',label='nanoaod80X',location='STD')} steps['TTbar_13_92XNanoAODINPUT']={'INPUT':InputInfo(dataSet='/RelValTTbar_13/CMSSW_9_2_12-PU25ns_92X_upgrade2017_realistic_v11-v1/MINIAODSIM',label='nanoaod92X',location='STD')} -steps['TTbar_13_94XNanoAODINPUT']={'INPUT':InputInfo(dataSet='/RelValTTbar_13/CMSSW_9_4_0_pre1-PU25ns_93X_mc2017_realistic_v3-v1/MINIAODSIM',label='nanoaod94X',location='STD')} +steps['TTbar_13_94XNanoAODINPUT']={'INPUT':InputInfo(dataSet='/RelValTTbar_13/CMSSW_9_4_0_pre3-PU25ns_94X_mc2017_realistic_v4-v1/MINIAODSIM',label='nanoaod94X',location='STD')} # 13 TeV recycle GEN-SIM input steps['MinBias_13INPUT']={'INPUT':InputInfo(dataSet='/RelValMinBias_13/%s/GEN-SIM'%(baseDataSetRelease[3],),location='STD')} @@ -1978,12 +1978,12 @@ def gen2018HiMix(fragment,howMuch): '--datatier' : 'MINIAODSIM', '--eventcontent':'MINIAOD',},stepMiniAODMC]) +stepNanoAODDefaults = { '-s': 'NANO,DQM:@nanoAODDQM', '-n': 1000 } +stepNanoAODData = merge([{ '--data':'', '--eventcontent' : 'NANOAOD,DQM' ,'--datatier': 'NANOAOD,DQMIO' }, stepNanoAODDefaults ]) +stepNanoAODMC = merge([{ '--mc':'' , '--eventcontent' : 'NANOAODSIM,DQM','--datatier': 'NANOAODSIM,DQMIO' }, stepNanoAODDefaults ]) +stepNanoEDMData = merge([{ '--data':'', '--eventcontent' : 'NANOAOD,DQM' ,'--datatier': 'NANOEDMAOD,DQMIO' }, stepNanoAODDefaults ]) +stepNanoEDMMC = merge([{ '--mc':'' , '--eventcontent' : 'NANOAODSIM,DQM','--datatier': 'NANOEDMAODSIM,DQMIO' }, stepNanoAODDefaults ]) -stepNanoAODDefaults = { '-s': 'NANO', '-n': 1000 } -stepNanoAODData = merge([{ '--data':'', '--eventcontent' : 'NANOAOD' ,'--datatier': 'NANOAOD' }, stepNanoAODDefaults ]) -stepNanoAODMC = merge([{ '--mc':'' , '--eventcontent' : 'NANOAODSIM','--datatier': 'NANOAODSIM' }, stepNanoAODDefaults ]) -stepNanoEDMData = merge([{ '--data':'', '--eventcontent' : 'NANOAOD' ,'--datatier': 'NANOEDMAOD' }, stepNanoAODDefaults ]) -stepNanoEDMMC = merge([{ '--mc':'' , '--eventcontent' : 'NANOAODSIM','--datatier': 'NANOEDMAODSIM' }, stepNanoAODDefaults ]) steps['NANOAOD2016'] = merge([{'--conditions': 'auto:run2_data_relval', '--era': 'Run2_2016'}, stepNanoAODData ]) steps['NANOAOD2017'] = merge([{'--conditions': 'auto:run2_data_relval', '--era': 'Run2_2017'}, stepNanoAODData ]) diff --git a/DQMOffline/Configuration/python/DQMOfflineMC_cff.py b/DQMOffline/Configuration/python/DQMOfflineMC_cff.py index 0c9c292168945..cfcda94f61ba3 100644 --- a/DQMOffline/Configuration/python/DQMOfflineMC_cff.py +++ b/DQMOffline/Configuration/python/DQMOfflineMC_cff.py @@ -28,3 +28,6 @@ label = 'TrackerCollisionSelectedTrackMonMB' + str(tracks) locals()[label].doEffFromHitPatternVsBX = False +from PhysicsTools.NanoAOD.nanoDQM_cff import nanoDQMMC +DQMOfflineNanoAOD.replace(nanoDQM, nanoDQMMC) +#PostDQMOfflineNanoAOD.replace(nanoDQM, nanoDQMMC) diff --git a/DQMOffline/Configuration/python/DQMOffline_SecondStep_cff.py b/DQMOffline/Configuration/python/DQMOffline_SecondStep_cff.py index 770c542d4e969..efab604e344a8 100644 --- a/DQMOffline/Configuration/python/DQMOffline_SecondStep_cff.py +++ b/DQMOffline/Configuration/python/DQMOffline_SecondStep_cff.py @@ -18,6 +18,7 @@ from DQMOffline.Hcal.HcalDQMOfflinePostProcessor_cff import * from DQMOffline.L1Trigger.L1TriggerDqmOffline_cff import * from DQM.HcalTasks.OfflineHarvestingSequence_pp import * +from PhysicsTools.NanoAOD.nanoDQM_cff import * DQMOffline_SecondStep_PreDPG = cms.Sequence( dqmDcsInfoClient * ecal_dqm_client_offline * @@ -140,3 +141,5 @@ DQMHarvestBTag = cms.Sequence( bTagCollectorSequenceDATA ) DQMHarvestMiniAOD = cms.Sequence( dataCertificationJetMETSequence * muonQualityTests_miniAOD) +DQMHarvestNanoAOD = cms.Sequence( nanoHarvest ) + diff --git a/DQMOffline/Configuration/python/DQMOffline_cff.py b/DQMOffline/Configuration/python/DQMOffline_cff.py index dcb602bacbef5..7ded0831f4603 100644 --- a/DQMOffline/Configuration/python/DQMOffline_cff.py +++ b/DQMOffline/Configuration/python/DQMOffline_cff.py @@ -176,3 +176,9 @@ phase2_hcal.toReplaceWith( PostDQMOfflineMiniAOD, PostDQMOfflineMiniAOD.copyAndExclude([ pfMetDQMAnalyzerMiniAOD, pfPuppiMetDQMAnalyzerMiniAOD # No hcalnoise yet ])) + + +from PhysicsTools.NanoAOD.nanoDQM_cff import nanoDQM +DQMOfflineNanoAOD = cms.Sequence(nanoDQM) +#PostDQMOfflineNanoAOD = cms.Sequence(nanoDQM) + diff --git a/DQMOffline/Configuration/python/autoDQM.py b/DQMOffline/Configuration/python/autoDQM.py index 245d186c9a67a..b22f46220ee93 100644 --- a/DQMOffline/Configuration/python/autoDQM.py +++ b/DQMOffline/Configuration/python/autoDQM.py @@ -47,6 +47,9 @@ 'miniAODDQM': ['DQMOfflineMiniAOD', 'PostDQMOfflineMiniAOD', 'DQMHarvestMiniAOD'], + 'nanoAODDQM': ['DQMOfflineNanoAOD', + 'PostDQMOffline', + 'DQMHarvestNanoAOD'], 'standardDQM': ['DQMOffline', 'PostDQMOffline', 'dqmHarvesting'], diff --git a/DataFormats/NanoAOD/interface/FlatTable.h b/DataFormats/NanoAOD/interface/FlatTable.h index 8a1a5909dc13b..d15b26df9b34d 100644 --- a/DataFormats/NanoAOD/interface/FlatTable.h +++ b/DataFormats/NanoAOD/interface/FlatTable.h @@ -69,6 +69,22 @@ class FlatTable { return * beginData(column); } + double getAnyValue(unsigned int row, unsigned int column) const ; + + class RowView { + public: + RowView() {} + RowView(const FlatTable & table, unsigned int row) : table_(&table), row_(row) {} + double getAnyValue(unsigned int column) const { return table_->getAnyValue(row_, column); } + double getAnyValue(const std::string & column) const { return table_->getAnyValue(row_, table_->columnIndex(column)); } + const FlatTable & table() const { return *table_; } + unsigned int row() const { return row_; } + private: + const FlatTable * table_; + unsigned int row_; + }; + RowView row(unsigned int row) const { return RowView(*this, row); } + template> void addColumn(const std::string & name, const C & values, const std::string & docString, ColumnType type = defaultColumnType(),int mantissaBits=-1) { if (columnIndex(name) != -1) throw cms::Exception("LogicError", "Duplicated column: "+name); @@ -94,7 +110,9 @@ class FlatTable { vec.push_back( value ); } } - + + void addExtension(const FlatTable & extension) ; + template static ColumnType defaultColumnType() { throw cms::Exception("unsupported type"); } // this below needs to be public for ROOT, but it is to be considered private otherwise diff --git a/DataFormats/NanoAOD/src/FlatTable.cc b/DataFormats/NanoAOD/src/FlatTable.cc index bffa199ed8f95..4a7560338a3ad 100644 --- a/DataFormats/NanoAOD/src/FlatTable.cc +++ b/DataFormats/NanoAOD/src/FlatTable.cc @@ -6,3 +6,32 @@ int nanoaod::FlatTable::columnIndex(const std::string & name) const { } return -1; } + +void nanoaod::FlatTable::addExtension(const nanoaod::FlatTable & other) { + if (extension() || !other.extension() || name() != other.name() || size() != other.size()) throw cms::Exception("LogicError", "Mismatch in adding extension"); + for (unsigned int i = 0, n = other.nColumns(); i < n; ++i) { + switch(other.columnType(i)) { + case FloatColumn: + addColumn(other.columnName(i), other.columnData(i), other.columnDoc(i), other.columnType(i)); + break; + case IntColumn: + addColumn(other.columnName(i), other.columnData(i), other.columnDoc(i), other.columnType(i)); + break; + case BoolColumn: // as UInt8 + case UInt8Column: + addColumn(other.columnName(i), other.columnData(i), other.columnDoc(i), other.columnType(i)); + break; + } + } +} + +double nanoaod::FlatTable::getAnyValue(unsigned int row, unsigned int column) const { + if (column >= nColumns()) throw cms::Exception("LogicError","Invalid column"); + switch(columnType(column)) { + case FloatColumn: return *(beginData(column)+row); + case IntColumn: return *(beginData(column)+row); + case BoolColumn: return *(beginData(column)+row); + case UInt8Column: return *(beginData(column)+row); + } + throw cms::Exception("LogicError", "Unsupported type"); +} diff --git a/DataFormats/NanoAOD/src/classes.h b/DataFormats/NanoAOD/src/classes.h index cd21de1d1e072..64a80ccb78fc5 100644 --- a/DataFormats/NanoAOD/src/classes.h +++ b/DataFormats/NanoAOD/src/classes.h @@ -9,6 +9,7 @@ namespace DataFormats_NanoAOD { struct dictionary { nanoaod::FlatTable table; edm::Wrapper w_table; + nanoaod::FlatTable::RowView table_cursor; edm::Wrapper w_mtable; edm::Wrapper w_ustr; }; diff --git a/DataFormats/NanoAOD/src/classes_def.xml b/DataFormats/NanoAOD/src/classes_def.xml index 7c85fe046b919..32c077349ff95 100644 --- a/DataFormats/NanoAOD/src/classes_def.xml +++ b/DataFormats/NanoAOD/src/classes_def.xml @@ -6,6 +6,7 @@ + diff --git a/PhysicsTools/NanoAOD/plugins/BuildFile.xml b/PhysicsTools/NanoAOD/plugins/BuildFile.xml index 1125b15bc0007..d2edc6cd4fd43 100644 --- a/PhysicsTools/NanoAOD/plugins/BuildFile.xml +++ b/PhysicsTools/NanoAOD/plugins/BuildFile.xml @@ -13,7 +13,7 @@ - + diff --git a/PhysicsTools/NanoAOD/plugins/GenWeightsTableProducer.cc b/PhysicsTools/NanoAOD/plugins/GenWeightsTableProducer.cc index 08e812ee4447b..5994871edfdfe 100644 --- a/PhysicsTools/NanoAOD/plugins/GenWeightsTableProducer.cc +++ b/PhysicsTools/NanoAOD/plugins/GenWeightsTableProducer.cc @@ -227,10 +227,11 @@ class GenWeightsTableProducer : public edm::global::EDProducer scaleVariationIDs; std::vector pdfSetWeightIDs; - std::regex weightgroup(""); + std::regex weightgroup(""); std::regex endweightgroup(""); - std::regex scalew("\\s*(muR=(\\S+)\\s+muF=(\\S+)(\\s+.*)?)"); + std::regex scalew("\\s*(mu[rR]=(\\S+)\\s+mu[Ff]=(\\S+)(\\s+.*)?)"); std::regex pdfw("\\s*PDF set\\s*=\\s*(\\d+)\\s*"); + std::regex pdfwOld("\\s*Member \\s*(\\d+)\\s*"); std::smatch groups; for (auto iter=lheInfo->headers_begin(), end = lheInfo->headers_end(); iter != end; ++iter) { if (iter->tag() != "initrwgt") { @@ -243,7 +244,7 @@ class GenWeightsTableProducer : public edm::global::EDProducer>> Looks like the beginning of a weight group for " << groups.str(2) << std::endl; - if (groups.str(2) == "scale_variation") { + if (groups.str(2) == "scale_variation" || groups.str(2) == "Central scale variation") { for ( ++iLine; iLine < nLines; ++iLine) { if (lheDebug) std::cout << " " << lines[iLine]; if (std::regex_search(lines[iLine], groups, scalew)) { @@ -276,6 +277,26 @@ class GenWeightsTableProducer : public edm::global::EDProducer>> PDF weight " << groups.str(1) << " for " << groups.str(2) << " = " << lhaID << std::endl; + if (lhaID == 262000) continue; // skip the central value weight as we have it already as nominal weight, only record the uncertainty weights + if (pdfSetWeightIDs.empty() || ! pdfSetWeightIDs.back().maybe_add(groups.str(1),lhaID)) { + pdfSetWeightIDs.emplace_back(groups.str(1),lhaID); + } + } else if (std::regex_search(lines[iLine], endweightgroup)) { + if (lheDebug) std::cout << ">>> Looks like the end of a weight group" << std::endl; + break; + } else if (std::regex_search(lines[iLine], weightgroup)) { + if (lheDebug) std::cout << ">>> Looks like the beginning of a new weight group, I will assume I missed the end of the group." << std::endl; + --iLine; // rewind by one, and go back to the outer loop + break; + } + } } else { for ( ++iLine; iLine < nLines; ++iLine) { if (lheDebug) std::cout << " " << lines[iLine]; diff --git a/PhysicsTools/NanoAOD/plugins/NanoAODDQM.cc b/PhysicsTools/NanoAOD/plugins/NanoAODDQM.cc new file mode 100644 index 0000000000000..e612f50cde4d3 --- /dev/null +++ b/PhysicsTools/NanoAOD/plugins/NanoAODDQM.cc @@ -0,0 +1,240 @@ +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/Utilities/interface/InputTag.h" +#include "DQMServices/Core/interface/DQMStore.h" +#include "DQMServices/Core/interface/DQMEDAnalyzer.h" +#include "DQMServices/Core/interface/MonitorElement.h" +#include "FWCore/Framework/interface/Event.h" +#include "DataFormats/NanoAOD/interface/FlatTable.h" +#include "CommonTools/Utils/interface/StringCutObjectSelector.h" + +#include +#include +#include + +namespace { + std::string replaceStringsToColumGets(const std::string & expr, const nanoaod::FlatTable & table) { + std::regex token("\\w+"); + std::sregex_iterator tbegin(expr.begin(), expr.end(), token), tend; + if (tbegin == tend) return expr; + std::stringstream out; + std::sregex_iterator last; + for (std::sregex_iterator i = tbegin; i != tend; last = i, ++i) { + std::smatch match = *i; + out << match.prefix().str(); + if (table.columnIndex(match.str()) != -1) { + out << "getAnyValue(\"" << match.str() << "\")"; + } else { + out << match.str(); + } + } + out << last->suffix().str(); + return out.str(); + }; +} + +class NanoAODDQM : public DQMEDAnalyzer { + public: + typedef nanoaod::FlatTable FlatTable; + + NanoAODDQM(const edm::ParameterSet&); + void analyze(const edm::Event&, const edm::EventSetup&) override; + + protected: + //Book histograms + void bookHistograms(DQMStore::IBooker &, edm::Run const &, edm::EventSetup const &) override; + void dqmBeginRun(const edm::Run&, const edm::EventSetup&) override {} + void endRun(const edm::Run&, const edm::EventSetup&) override {} + + private: + class Plot { + public: + Plot(MonitorElement * me) : plot_(me) {} + virtual ~Plot() {} + virtual void fill(const FlatTable & table, const std::vector & rowsel) = 0; + const std::string & name() const { return plot_->getName(); } + protected: + MonitorElement * plot_; + }; + class Count1D : public Plot { + public: + Count1D(DQMStore::IBooker & booker, const edm::ParameterSet & cfg) : + Plot(booker.book1D(cfg.getParameter("name"), cfg.getParameter("title"), cfg.getParameter("nbins"), cfg.getParameter("min"), cfg.getParameter("max"))) + { + } + ~Count1D() override {} + void fill(const FlatTable & table, const std::vector & rowsel) override { + plot_->Fill(std::accumulate(rowsel.begin(), rowsel.end(), 0u)); + } + }; + + class Plot1D : public Plot { + public: + Plot1D(DQMStore::IBooker & booker, const edm::ParameterSet & cfg) : + Plot(booker.book1D(cfg.getParameter("name"), cfg.getParameter("title"), cfg.getParameter("nbins"), cfg.getParameter("min"), cfg.getParameter("max"))), + col_(cfg.getParameter("column")) + { + } + ~Plot1D() override {} + void fill(const FlatTable & table, const std::vector & rowsel) override { + int icol = table.columnIndex(col_); + if (icol == -1) return; // columns may be missing (e.g. mc-only) + switch(table.columnType(icol)) { + case FlatTable::FloatColumn: vfill(table,icol,rowsel); break; + case FlatTable::IntColumn: vfill(table,icol,rowsel); break; + case FlatTable::UInt8Column: vfill(table,icol,rowsel); break; + case FlatTable::BoolColumn: vfill(table,icol,rowsel); break; + } + } + protected: + std::string col_; + template + void vfill(const FlatTable & table, int icol, const std::vector & rowsel) { + const auto & data = table.columnData(icol); + for (unsigned int i = 0, n = data.size(); i < n; ++i) { + if (rowsel[i]) plot_->Fill(data[i]); + } + } + }; + class Profile1D : public Plot { + public: + Profile1D(DQMStore::IBooker & booker, const edm::ParameterSet & cfg) : + Plot(booker.bookProfile(cfg.getParameter("name"), cfg.getParameter("title"), + cfg.getParameter("nbins"), cfg.getParameter("min"), cfg.getParameter("max"), + 0., 0., "")), + ycol_(cfg.getParameter("ycolumn")), xcol_(cfg.getParameter("xcolumn")) + { + } + ~Profile1D() override {} + void fill(const FlatTable & table, const std::vector & rowsel) override { + int icolx = table.columnIndex(xcol_); + int icoly = table.columnIndex(ycol_); + if (icolx == -1) throw cms::Exception("LogicError", "Missing "+xcol_); + if (icoly == -1) throw cms::Exception("LogicError", "Missing "+ycol_); + for (unsigned int irow = 0, n = table.size(); irow < n; ++irow) { + if (rowsel[irow]) plot_->Fill(table.getAnyValue(irow,icolx), table.getAnyValue(irow,icoly)); + } + } + protected: + std::string ycol_, xcol_; + }; + + + + static std::unique_ptr makePlot(DQMStore::IBooker & booker, const edm::ParameterSet & cfg) { + const std::string & kind = cfg.getParameter("kind"); + if (kind == "none") return nullptr; + if (kind == "count1d") return std::make_unique(booker,cfg); + if (kind == "hist1d") return std::make_unique(booker,cfg); + if (kind == "prof1d") return std::make_unique(booker,cfg); + throw cms::Exception("Configuration", "Unsupported plot kind '"+kind+"'"); + } + + struct SelGroupConfig { + typedef StringCutObjectSelector Selector; + std::string name; + std::string cutstr; + std::unique_ptr> cutptr; + std::vector> plots; + SelGroupConfig() : name(), cutstr(), cutptr(), plots() {} + SelGroupConfig(const std::string & nam, const std::string & cut) : name(nam), cutstr(cut), cutptr(), plots() {} + bool nullCut() const { return cutstr.empty(); } + void fillSel(const FlatTable & table, std::vector & out) { + out.resize(table.size()); + if (nullCut()) { + std::fill(out.begin(), out.end(), true); + } else { + if (!cutptr) { + cutptr.reset(new Selector(replaceStringsToColumGets(cutstr, table))); + } + for (unsigned int i = 0, n = table.size(); i < n; ++i) { + out[i] = (*cutptr)(table.row(i)); + } + } + } + }; + struct GroupConfig { + std::vector plotPSets; + std::vector selGroups; + }; + std::map groups_; + }; + +NanoAODDQM::NanoAODDQM(const edm::ParameterSet & iConfig) +{ + const edm::ParameterSet & vplots = iConfig.getParameter("vplots"); + for (const std::string & name : vplots.getParameterNamesForType()) { + auto & group = groups_[name]; + const auto & pset = vplots.getParameter(name); + group.plotPSets = pset.getParameter>("plots"); + group.selGroups.emplace_back(); // no selection (all entries) + const auto & cuts = pset.getParameter("sels"); + for (const std::string & cname : cuts.getParameterNamesForType()) { + group.selGroups.emplace_back(cname, cuts.getParameter(cname)); + } + } + consumesMany(); +} + +void NanoAODDQM::bookHistograms(DQMStore::IBooker & booker, edm::Run const &, edm::EventSetup const &) { + booker.setCurrentFolder("Physics/NanoAODDQM"); + + for (auto & pair : groups_) { + booker.setCurrentFolder("Physics/NanoAODDQM/"+pair.first); + for (auto & sels : pair.second.selGroups) { + std::string dir("Physics/NanoAODDQM/"+pair.first); + if (!sels.nullCut()) dir += "/" + sels.name; + booker.setCurrentFolder(dir); + auto & plots = sels.plots; + plots.clear(); + plots.reserve(pair.second.plotPSets.size()); + for (const auto & cfg : pair.second.plotPSets) { + auto plot = makePlot(booker, cfg); + if (plot) plots.push_back(std::move(plot)); + } + } + } +} + +void NanoAODDQM::analyze(const edm::Event &iEvent, const edm::EventSetup &) { + std::vector> alltables; + iEvent.getManyByType(alltables); + std::map>> maintables; + + for (const auto & htab : alltables) { + if (htab->extension()) continue; + maintables[htab->name()] = std::make_pair(htab.product(), std::vector()); + } + for (const auto & htab : alltables) { + if (htab->extension()) { + if (maintables.find(htab->name()) == maintables.end()) throw cms::Exception("LogicError","Missing main table for "+htab->name()); + maintables[htab->name()].second.push_back(htab.product()); + } + } + + FlatTable merged; + for (auto & pair : groups_) { + const std::string & name = pair.first; + if (maintables.find(name) == maintables.end()) continue; // may happen for missing collections + auto & tables = maintables[name]; + const FlatTable * table = tables.first; + if (!tables.second.empty()) { + merged = *tables.first; + for (auto * other : tables.second) { + merged.addExtension(*other); + } + table = & merged; + } + std::vector selbits; + for (auto & sel : pair.second.selGroups) { + sel.fillSel(*table, selbits); + + for (auto & plot : sel.plots) { + plot->fill(*table, selbits); + } + } + } +} + +#include "FWCore/Framework/interface/MakerMacros.h" +DEFINE_FWK_MODULE(NanoAODDQM); diff --git a/PhysicsTools/NanoAOD/plugins/SimpleFlatTableProducer.cc b/PhysicsTools/NanoAOD/plugins/SimpleFlatTableProducer.cc index 68a96105d6b3f..381d797ceaee4 100644 --- a/PhysicsTools/NanoAOD/plugins/SimpleFlatTableProducer.cc +++ b/PhysicsTools/NanoAOD/plugins/SimpleFlatTableProducer.cc @@ -195,11 +195,11 @@ class EventSingletonSimpleFlatTableProducer : public SimpleFlatTableProducerBase EventSingletonSimpleFlatTableProducer( edm::ParameterSet const & params ): SimpleFlatTableProducerBase(params) {} - virtual ~EventSingletonSimpleFlatTableProducer() {} + ~EventSingletonSimpleFlatTableProducer() override {} std::unique_ptr fillTable(const edm::Event &, const edm::Handle & prod) const override { auto out = std::make_unique(1, this->name_, true, this->extension_); - std::vector selobjs(1, prod->product()); + std::vector selobjs(1, prod.product()); for (const auto & var : this->vars_) var.fill(selobjs, *out); return out; } @@ -227,7 +227,11 @@ typedef SimpleFlatTableProducer SimpleCandidateFlatTableProduce #include "SimDataFormats/PileupSummaryInfo/interface/PileupSummaryInfo.h" typedef FirstObjectSimpleFlatTableProducer SimplePileupFlatTableProducer; +#include "SimDataFormats/GeneratorProducts/interface/GenEventInfoProduct.h" +typedef EventSingletonSimpleFlatTableProducer SimpleGenEventFlatTableProducer; + #include "FWCore/Framework/interface/MakerMacros.h" DEFINE_FWK_MODULE(SimpleCandidateFlatTableProducer); DEFINE_FWK_MODULE(SimplePileupFlatTableProducer); +DEFINE_FWK_MODULE(SimpleGenEventFlatTableProducer); diff --git a/PhysicsTools/NanoAOD/python/electrons_cff.py b/PhysicsTools/NanoAOD/python/electrons_cff.py index b6fa318b42a5d..7bfb09417419b 100644 --- a/PhysicsTools/NanoAOD/python/electrons_cff.py +++ b/PhysicsTools/NanoAOD/python/electrons_cff.py @@ -2,13 +2,32 @@ from Configuration.Eras.Modifier_run2_miniAOD_80XLegacy_cff import run2_miniAOD_80XLegacy from Configuration.Eras.Modifier_run2_nanoAOD_92X_cff import run2_nanoAOD_92X from PhysicsTools.NanoAOD.common_cff import * +import PhysicsTools.PatAlgos.producersLayer1.electronProducer_cfi from math import ceil,log +# this below is used only in some eras +slimmedElectronsUpdated = cms.EDProducer("PATElectronUpdater", + src = cms.InputTag("slimmedElectrons"), + vertices = cms.InputTag("offlineSlimmedPrimaryVertices"), + computeMiniIso = cms.bool(False), + pfCandsForMiniIso = cms.InputTag("packedPFCandidates"), + miniIsoParamsB = PhysicsTools.PatAlgos.producersLayer1.electronProducer_cfi.patElectrons.miniIsoParamsB, # so they're in sync + miniIsoParamsE = PhysicsTools.PatAlgos.producersLayer1.electronProducer_cfi.patElectrons.miniIsoParamsE, # so they're in sync +) +run2_miniAOD_80XLegacy.toModify( slimmedElectronsUpdated, computeMiniIso = True ) + from PhysicsTools.SelectorUtils.tools.vid_id_tools import setupVIDSelection from RecoEgamma.ElectronIdentification.egmGsfElectronIDs_cff import * + electronMVAValueMapProducer.srcMiniAOD = cms.InputTag("slimmedElectrons") +run2_miniAOD_80XLegacy.toModify(electronMVAValueMapProducer, srcMiniAOD = "slimmedElectronsUpdated") +run2_nanoAOD_92X.toModify(electronMVAValueMapProducer, srcMiniAOD = "slimmedElectronsUpdated") + egmGsfElectronIDs.physicsObjectIDs = cms.VPSet() egmGsfElectronIDs.physicsObjectSrc = cms.InputTag('slimmedElectrons') +run2_miniAOD_80XLegacy.toModify(egmGsfElectronIDs, physicsObjectSrc = "slimmedElectronsUpdated") +run2_nanoAOD_92X.toModify(egmGsfElectronIDs, physicsObjectSrc = "slimmedElectronsUpdated") + _electron_id_vid_modules=[ 'RecoEgamma.ElectronIdentification.Identification.cutBasedElectronID_Summer16_80X_V1_cff', 'RecoEgamma.ElectronIdentification.Identification.cutBasedElectronHLTPreselecition_Summer16_V1_cff', @@ -36,29 +55,40 @@ src = cms.InputTag("slimmedElectrons"), WorkingPoints = _bitmapVIDForEle_WorkingPoints, ) +run2_miniAOD_80XLegacy.toModify(bitmapVIDForEle, src = "slimmedElectronsUpdated") +run2_nanoAOD_92X.toModify(bitmapVIDForEle, src = "slimmedElectronsUpdated") isoForEle = cms.EDProducer("EleIsoValueMapProducer", src = cms.InputTag("slimmedElectrons"), relative = cms.bool(False), - rho_MiniIso = cms.InputTag("fixedGridRhoFastjetCentralNeutral"), + rho_MiniIso = cms.InputTag("fixedGridRhoFastjetAll"), rho_PFIso = cms.InputTag("fixedGridRhoFastjetAll"), EAFile_MiniIso = cms.FileInPath("RecoEgamma/ElectronIdentification/data/Spring15/effAreaElectrons_cone03_pfNeuHadronsAndPhotons_25ns.txt"), EAFile_PFIso = cms.FileInPath("RecoEgamma/ElectronIdentification/data/Summer16/effAreaElectrons_cone03_pfNeuHadronsAndPhotons_80X.txt"), ) +run2_miniAOD_80XLegacy.toModify(isoForEle, src = "slimmedElectronsUpdated") +run2_nanoAOD_92X.toModify(isoForEle, src = "slimmedElectronsUpdated") ptRatioRelForEle = cms.EDProducer("ElectronJetVarProducer", srcJet = cms.InputTag("slimmedJets"), srcLep = cms.InputTag("slimmedElectrons"), srcVtx = cms.InputTag("offlineSlimmedPrimaryVertices"), ) +run2_miniAOD_80XLegacy.toModify(ptRatioRelForEle, srcLep = "slimmedElectronsUpdated") +run2_nanoAOD_92X.toModify(ptRatioRelForEle, srcLep = "slimmedElectronsUpdated") from EgammaAnalysis.ElectronTools.calibratedElectronsRun2_cfi import calibratedPatElectrons calibratedPatElectrons.correctionFile = cms.string("PhysicsTools/NanoAOD/data/80X_ichepV1_2016_ele") # hack, should go somewhere in EgammaAnalysis +calibratedPatElectrons.semiDeterministic = cms.bool(True) +run2_miniAOD_80XLegacy.toModify(calibratedPatElectrons, electrons = "slimmedElectronsUpdated") +run2_nanoAOD_92X.toModify(calibratedPatElectrons, electrons = "slimmedElectronsUpdated") energyCorrForEle = cms.EDProducer("ElectronEnergyVarProducer", srcRaw = cms.InputTag("slimmedElectrons"), srcCorr = cms.InputTag("calibratedPatElectrons"), ) +run2_miniAOD_80XLegacy.toModify(energyCorrForEle, srcRaw = "slimmedElectronsUpdated") +run2_nanoAOD_92X.toModify(energyCorrForEle, srcRaw = "slimmedElectronsUpdated") slimmedElectronsWithUserData = cms.EDProducer("PATElectronUserDataEmbedder", @@ -92,19 +122,13 @@ jetForLepJetVar = cms.InputTag("ptRatioRelForEle:jetForLepJetVar") # warning: Ptr is null if no match is found ), ) - -# this below is used only in some eras -slimmedElectronsWithDZ = cms.EDProducer("PATElectronUpdater", - src = cms.InputTag("slimmedElectronsWithUserData"), - vertices = cms.InputTag("offlineSlimmedPrimaryVertices") -) +run2_miniAOD_80XLegacy.toModify(slimmedElectronsWithUserData, src = "slimmedElectronsUpdated") +run2_nanoAOD_92X.toModify(slimmedElectronsWithUserData, src = "slimmedElectronsUpdated") finalElectrons = cms.EDFilter("PATElectronRefSelector", src = cms.InputTag("slimmedElectronsWithUserData"), cut = cms.string("pt > 5 ") ) -run2_miniAOD_80XLegacy.toModify(finalElectrons, src = "slimmedElectronsWithDZ") -run2_nanoAOD_92X.toModify(finalElectrons, src = "slimmedElectronsWithDZ") electronMVATTH= cms.EDProducer("EleBaseMVAValueMapProducer", src = cms.InputTag("linkedObjects","electrons"), @@ -138,7 +162,6 @@ variables = cms.PSet(CandVars, jetIdx = Var("?hasUserCand('jet')?userCand('jet').key():-1", int, doc="index of the associated jet (-1 if none)"), photonIdx = Var("?overlaps('photons').size()>0?overlaps('photons')[0].key():-1", int, doc="index of the associated photon (-1 if none)"), - #ptErr = Var("gsfTrack().ptError()",float,doc="pt error of the GSF track",precision=6), energyErr = Var("p4Error('P4_COMBINATION')*userFloat('eCorr')",float,doc="energy error of the cluster-track combination",precision=6), eCorr = Var("userFloat('eCorr')",float,doc="ratio of the calibrated energy/miniaod energy"), dz = Var("dB('PVDZ')",float,doc="dz (with sign) wrt first PV, in cm",precision=10), @@ -162,16 +185,20 @@ miniPFRelIso_all = Var("userFloat('miniIsoAll')/pt",float,doc="mini PF relative isolation, total (with scaled rho*EA PU corrections)"), pfRelIso03_chg = Var("userFloat('PFIsoChg')/pt",float,doc="PF relative isolation dR=0.3, charged component"), pfRelIso03_all = Var("userFloat('PFIsoAll')/pt",float,doc="PF relative isolation dR=0.3, total (with rho*EA PU corrections)"), + dr03TkSumPt = Var("?pt>35?dr03TkSumPt():0",float,doc="Non-PF track isolation within a delta R cone of 0.3 with electron pt > 35 GeV",precision=8), + dr03EcalRecHitSumEt = Var("?pt>35?dr03EcalRecHitSumEt():0",float,doc="Non-PF Ecal isolation within a delta R cone of 0.3 with electron pt > 35 GeV",precision=8), + dr03HcalDepth1TowerSumEt = Var("?pt>35?dr03HcalDepth1TowerSumEt():0",float,doc="Non-PF Hcal isolation within a delta R cone of 0.3 with electron pt > 35 GeV",precision=8), hoe = Var("hadronicOverEm()",float,doc="H over E",precision=8), tightCharge = Var("isGsfCtfScPixChargeConsistent() + isGsfScPixChargeConsistent()",int,doc="Tight charge criteria (0:none, 1:isGsfScPixChargeConsistent, 2:isGsfCtfScPixChargeConsistent)"), convVeto = Var("passConversionVeto()",bool,doc="pass conversion veto"), lostHits = Var("gsfTrack.hitPattern.numberOfLostHits('MISSING_INNER_HITS')","uint8",doc="number of missing inner hits"), + isPFcand = Var("pfCandidateRef().isNonnull()",bool,doc="electron is PF candidate"), ), externalVariables = cms.PSet( mvaTTH = ExtVar(cms.InputTag("electronMVATTH"),float, doc="TTH MVA lepton ID score",precision=14), ), ) -electronTable.variables.pt = Var("pt*userFloat('eCorr')", float, precision=-1) +electronTable.variables.pt = Var("pt*userFloat('eCorr')", float, precision=-1, doc="p_{T} after energy correction & smearing") electronsMCMatchForTable = cms.EDProducer("MCMatcher", # cut on deltaR, deltaPt/Pt; pick best by deltaR src = electronTable.src, # final reco collection @@ -198,7 +225,6 @@ electronTables = cms.Sequence (electronMVATTH + electronTable) electronMC = cms.Sequence(electronsMCMatchForTable + electronMCTable) -_withDZ_sequence = electronSequence.copy() -_withDZ_sequence.replace(finalElectrons, slimmedElectronsWithDZ+finalElectrons) -run2_nanoAOD_92X.toReplaceWith(electronSequence, _withDZ_sequence) -run2_miniAOD_80XLegacy.toReplaceWith(electronSequence, _withDZ_sequence) +_withUpdate_sequence = cms.Sequence(slimmedElectronsUpdated + electronSequence.copy()) +run2_nanoAOD_92X.toReplaceWith(electronSequence, _withUpdate_sequence) +run2_miniAOD_80XLegacy.toReplaceWith(electronSequence, _withUpdate_sequence) diff --git a/PhysicsTools/NanoAOD/python/genparticles_cff.py b/PhysicsTools/NanoAOD/python/genparticles_cff.py index 8d5dddafab239..226cfc6bb9cd5 100644 --- a/PhysicsTools/NanoAOD/python/genparticles_cff.py +++ b/PhysicsTools/NanoAOD/python/genparticles_cff.py @@ -41,6 +41,7 @@ pt = Var("pt", float,precision=8), phi = Var("phi", float,precision=8), eta = Var("eta", float,precision=8), + mass = Var("?mass>10 || (pdgId==22 && mass > 1)?mass:0", float,precision=8,doc="Mass stored for all particles with mass > 10 GeV and photons with mass > 1 GeV. For other particles you can lookup from PDGID"), pdgId = Var("pdgId", int, doc="PDG id"), status = Var("status", int, doc="Particle status. 1=stable"), genPartIdxMother = Var("?numberOfMothers>0?motherRef(0).key():-1", int, doc="index of the mother particle"), diff --git a/PhysicsTools/NanoAOD/python/globals_cff.py b/PhysicsTools/NanoAOD/python/globals_cff.py index 471b44dec9807..c887121f04b82 100644 --- a/PhysicsTools/NanoAOD/python/globals_cff.py +++ b/PhysicsTools/NanoAOD/python/globals_cff.py @@ -21,6 +21,21 @@ nPU = Var( "getPU_NumInteractions()", int, doc="the number of pileup interactions that have been added to the event in the current bunch crossing" ), ), ) +genTable = cms.EDProducer("SimpleGenEventFlatTableProducer", + src = cms.InputTag("generator"), + cut = cms.string(""), + name= cms.string("Generator"), + doc = cms.string("Generator information"), + singleton = cms.bool(True), + extension = cms.bool(False), + variables = cms.PSet( + x1 = Var( "?hasPDF?pdf().x.first:-1", float, doc="x1 fraction of proton momentum carried by the first parton",precision=14 ), + x2 = Var( "?hasPDF?pdf().x.second:-1", float, doc="x2 fraction of proton momentum carried by the second parton",precision=14 ), + #AR: not sure what "xPDF" is wrt to just "x" + #x1PDF = Var( "?hasPDF?pdf().xPDF.first:-1", float, doc="x1 fraction of proton momentum carried by the first parton" ), + #x2PDF = Var( "?hasPDF?pdf().xPDF.second:-1", float, doc="x2 fraction of proton momentum carried by the second parton" ), + ), +) globalTables = cms.Sequence(rhoTable) -globalTablesMC = cms.Sequence(puTable) +globalTablesMC = cms.Sequence(puTable+genTable) diff --git a/PhysicsTools/NanoAOD/python/isotracks_cff.py b/PhysicsTools/NanoAOD/python/isotracks_cff.py index 98194503e9b7a..aaab62a15c6c2 100644 --- a/PhysicsTools/NanoAOD/python/isotracks_cff.py +++ b/PhysicsTools/NanoAOD/python/isotracks_cff.py @@ -3,18 +3,17 @@ finalIsolatedTracks = cms.EDProducer("IsolatedTrackCleaner", tracks = cms.InputTag("isolatedTracks"), - cut = cms.string("pt > 10 && abs(dxy) < 0.02 && abs(dz) < 0.1 && isHighPurityTrack && miniPFIsolation.chargedHadronIso/pt < 0.2"), + cut = cms.string("((pt>5 && (abs(pdgId) == 11 || abs(pdgId) == 13)) || pt > 10) && (abs(pdgId) < 15 || abs(eta) < 2.5) && abs(dxy) < 0.2 && abs(dz) < 0.1 && ((pfIsolationDR03().chargedHadronIso < 5 && pt < 25) || pfIsolationDR03().chargedHadronIso/pt < 0.2)"), finalLeptons = cms.VInputTag( cms.InputTag("finalElectrons"), cms.InputTag("finalMuons"), - cms.InputTag("finalTaus"), ), ) isoForIsoTk = cms.EDProducer("IsoTrackIsoValueMapProducer", src = cms.InputTag("finalIsolatedTracks"), relative = cms.bool(True), - rho_MiniIso = cms.InputTag("fixedGridRhoFastjetCentralNeutral"), + rho_MiniIso = cms.InputTag("fixedGridRhoFastjetAll"), EAFile_MiniIso = cms.FileInPath("PhysicsTools/NanoAOD/data/effAreaMuons_cone03_pfNeuHadronsAndPhotons_80X.txt"), ) @@ -30,6 +29,9 @@ dxy = Var("dxy",float,doc="dxy (with sign) wrt first PV, in cm",precision=10), pfRelIso03_chg = Var("pfIsolationDR03().chargedHadronIso/pt",float,doc="PF relative isolation dR=0.3, charged component",precision=10), pfRelIso03_all = Var("(pfIsolationDR03().chargedHadronIso + max(pfIsolationDR03().neutralHadronIso + pfIsolationDR03().photonIso - pfIsolationDR03().puChargedHadronIso/2,0.0))/pt",float,doc="PF relative isolation dR=0.3, total (deltaBeta corrections)",precision=10), + isPFcand = Var("packedCandRef().isNonnull()",bool,doc="if isolated track is a PF candidate"), + pdgId = Var("pdgId",int,doc="PDG id of PF cand"), + isHighPurityTrack = Var("isHighPurityTrack",bool,doc="track is high purity"), ), externalVariables = cms.PSet( miniPFRelIso_chg = ExtVar("isoForIsoTk:miniIsoChg",float,doc="mini PF relative isolation, charged component",precision=10), diff --git a/PhysicsTools/NanoAOD/python/jets_cff.py b/PhysicsTools/NanoAOD/python/jets_cff.py index 6dbd6868eadd0..86d54ae063bb1 100644 --- a/PhysicsTools/NanoAOD/python/jets_cff.py +++ b/PhysicsTools/NanoAOD/python/jets_cff.py @@ -1,5 +1,6 @@ import FWCore.ParameterSet.Config as cms from Configuration.Eras.Modifier_run2_miniAOD_80XLegacy_cff import run2_miniAOD_80XLegacy +from Configuration.Eras.Modifier_run2_nanoAOD_92X_cff import run2_nanoAOD_92X from PhysicsTools.NanoAOD.common_cff import * @@ -32,6 +33,7 @@ slimmedJetsWithUserData = cms.EDProducer("PATJetUserDataEmbedder", src = cms.InputTag("slimmedJets"), + userFloats = cms.PSet(), userInts = cms.PSet( tightId = cms.InputTag("tightJetId"), looseId = cms.InputTag("looseJetId"), @@ -105,7 +107,8 @@ jetTable.variables.pt.precision=10 ### Era dependent customization -run2_miniAOD_80XLegacy.toModify( jetTable.variables.qgl, expr="-1" ) +run2_miniAOD_80XLegacy.toModify( slimmedJetsWithUserData, userFloats=cms.PSet(qgl=cms.InputTag('qgtagger80x:qgLikelihood'))) +run2_miniAOD_80XLegacy.toModify( jetTable.variables.qgl, expr="userFloat('qgl')" ) bjetMVA= cms.EDProducer("BJetEnergyRegressionMVA", src = cms.InputTag("linkedObjects","jets"), @@ -171,12 +174,14 @@ extension = cms.bool(False), # this is the main table for the jets variables = cms.PSet(P4Vars, area = Var("jetArea()", float, doc="jet catchment area, for JECs",precision=10), - tau1 = Var("userFloat('ak8PFJetsCHSValueMap:NjettinessAK8CHSTau1')",float, doc="Nsubjettiness (1 axis)",precision=10), - tau2 = Var("userFloat('ak8PFJetsCHSValueMap:NjettinessAK8CHSTau2')",float, doc="Nsubjettiness (2 axis)",precision=10), - tau3 = Var("userFloat('ak8PFJetsCHSValueMap:NjettinessAK8CHSTau3')",float, doc="Nsubjettiness (3 axis)",precision=10), - msoftdrop = Var("userFloat('ak8PFJetsCHSValueMap:ak8PFJetsCHSSoftDropMass')",float, doc="Soft drop mass",precision=10), - mpruned = Var("userFloat('ak8PFJetsCHSValueMap:ak8PFJetsCHSPrunedMass')", float, doc="Pruned mass",precision=10), - + tau1 = Var("userFloat('NjettinessAK8Puppi:tau1')",float, doc="Nsubjettiness (1 axis)",precision=10), + tau2 = Var("userFloat('NjettinessAK8Puppi:tau2')",float, doc="Nsubjettiness (2 axis)",precision=10), + tau3 = Var("userFloat('NjettinessAK8Puppi:tau3')",float, doc="Nsubjettiness (3 axis)",precision=10), + tau4 = Var("userFloat('NjettinessAK8Puppi:tau4')",float, doc="Nsubjettiness (4 axis)",precision=10), + n2b1 = Var("userFloat('ak8PFJetsPuppiSoftDropValueMap:nb1AK8PuppiSoftDropN2')", float, doc="N2 with beta=1", precision=10), + n3b1 = Var("userFloat('ak8PFJetsPuppiSoftDropValueMap:nb1AK8PuppiSoftDropN3')", float, doc="N3 with beta=1", precision=10), + msoftdrop = Var("userFloat('ak8PFJetsPuppiSoftDropMass')",float, doc="Soft drop mass",precision=10), + btagCMVA = Var("bDiscriminator('pfCombinedMVAV2BJetTags')",float,doc="CMVA V2 btag discriminator",precision=10), btagDeepB = Var("bDiscriminator('pfDeepCSVJetTags:probb')",float,doc="DeepCSV B btag discriminator",precision=10), btagDeepBB = Var("bDiscriminator('pfDeepCSVJetTags:probbb')",float,doc="DeepCSV BB btag discriminator",precision=10), @@ -186,8 +191,6 @@ doc="index of first subjet"), subJetIdx2 = Var("?numberOfSourceCandidatePtrs()>1 && sourceCandidatePtr(1).numberOfSourceCandidatePtrs()>0?sourceCandidatePtr(1).key():-1", int, doc="index of second subjet"), - subJetIdx3 = Var("?numberOfSourceCandidatePtrs()>2 && sourceCandidatePtr(2).numberOfSourceCandidatePtrs()>0?sourceCandidatePtr(2).key():-1", int, - doc="index of third subjet"), # btagDeepC = Var("bDiscriminator('pfDeepCSVJetTags:probc')",float,doc="CMVA V2 btag discriminator",precision=10), #puIdDisc = Var("userFloat('pileupJetId:fullDiscriminant')",float,doc="Pilup ID discriminant",precision=10), @@ -196,11 +199,17 @@ ) ) ### Era dependent customization -run2_miniAOD_80XLegacy.toModify( fatJetTable.variables.mpruned, expr = cms.string("userFloat(\'ak8PFJetsCHSPrunedMass\')"),) run2_miniAOD_80XLegacy.toModify( fatJetTable.variables.msoftdrop, expr = cms.string("userFloat(\'ak8PFJetsCHSSoftDropMass\')"),) -run2_miniAOD_80XLegacy.toModify( fatJetTable.variables.tau1, expr = cms.string("userFloat(\'NjettinessAK8:tau1\')"),) -run2_miniAOD_80XLegacy.toModify( fatJetTable.variables.tau2, expr = cms.string("userFloat(\'NjettinessAK8:tau2\')"),) -run2_miniAOD_80XLegacy.toModify( fatJetTable.variables.tau3, expr = cms.string("userFloat(\'NjettinessAK8:tau3\')"),) +run2_miniAOD_80XLegacy.toModify( fatJetTable.variables.tau1, expr = cms.string("userFloat(\'ak8PFJetsPuppiValueMap:NjettinessAK8PuppiTau1\')"),) +run2_miniAOD_80XLegacy.toModify( fatJetTable.variables.tau2, expr = cms.string("userFloat(\'ak8PFJetsPuppiValueMap:NjettinessAK8PuppiTau2\')"),) +run2_miniAOD_80XLegacy.toModify( fatJetTable.variables.tau3, expr = cms.string("userFloat(\'ak8PFJetsPuppiValueMap:NjettinessAK8PuppiTau3\')"),) +run2_miniAOD_80XLegacy.toModify( fatJetTable.variables.tau4, expr = cms.string("-1"),) +run2_miniAOD_80XLegacy.toModify( fatJetTable.variables.n2b1, expr = cms.string("-1"),) +run2_miniAOD_80XLegacy.toModify( fatJetTable.variables.n3b1, expr = cms.string("-1"),) + +run2_nanoAOD_92X.toModify( fatJetTable.variables.tau4, expr = cms.string("-1"),) +run2_nanoAOD_92X.toModify( fatJetTable.variables.n2b1, expr = cms.string("-1"),) +run2_nanoAOD_92X.toModify( fatJetTable.variables.n3b1, expr = cms.string("-1"),) subJetTable = cms.EDProducer("SimpleCandidateFlatTableProducer", src = cms.InputTag("slimmedJetsAK8PFPuppiSoftDropPacked","SubJets"), @@ -250,7 +259,28 @@ ) ) - +genJetAK8Table = cms.EDProducer("SimpleCandidateFlatTableProducer", + src = cms.InputTag("slimmedGenJetsAK8"), + cut = cms.string("pt > 100."), + name = cms.string("GenJetAK8"), + doc = cms.string("slimmedGenJetsAK8SoftDropSubJets, i.e. subjets of ak8 Jets made with visible genparticles"), + singleton = cms.bool(False), # the number of entries is variable + extension = cms.bool(False), # this is the main table for the genjets + variables = cms.PSet(P4Vars, + #anything else? + ) +) +genSubJetAK8Table = cms.EDProducer("SimpleCandidateFlatTableProducer", + src = cms.InputTag("slimmedGenJetsAK8SoftDropSubJets"), + cut = cms.string(""), ## These don't get a pt cut, but in miniAOD only subjets from fat jets with pt > 100 are kept + name = cms.string("SubGenJetAK8"), + doc = cms.string("slimmedGenJetsAK8SoftDropSubJets, i.e. subjets of ak8 Jets made with visible genparticles"), + singleton = cms.bool(False), # the number of entries is variable + extension = cms.bool(False), # this is the main table for the genjets + variables = cms.PSet(P4Vars, + #anything else? + ) +) #before cross linking jetSequence = cms.Sequence(looseJetId+tightJetId+slimmedJetsWithUserData+jetCorrFactors+updatedJets+chsForSATkJets+softActivityJets+softActivityJets2+softActivityJets5+softActivityJets10+finalJets) @@ -258,5 +288,6 @@ jetTables = cms.Sequence(bjetMVA+ jetTable+fatJetTable+subJetTable+saJetTable+saTable) #MC only producers and tables -jetMC = cms.Sequence(jetMCTable+genJetTable) +jetMC = cms.Sequence(jetMCTable+genJetTable+genJetAK8Table+genSubJetAK8Table) + diff --git a/PhysicsTools/NanoAOD/python/met_cff.py b/PhysicsTools/NanoAOD/python/met_cff.py index df33266b41b8e..afbf94d8c7ab8 100644 --- a/PhysicsTools/NanoAOD/python/met_cff.py +++ b/PhysicsTools/NanoAOD/python/met_cff.py @@ -28,6 +28,8 @@ covXY = Var("getSignificanceMatrix().At(0,1)",float,doc="xy element of met covariance matrix", precision=8), covYY = Var("getSignificanceMatrix().At(1,1)",float,doc="yy element of met covariance matrix", precision=8), significance = Var("metSignificance()", float, doc="MET significance",precision=10), + MetUnclustEnUpDeltaX = Var("shiftedPx('UnclusteredEnUp')-px()", float, doc="Delta (METx_mod-METx) Unclustered Energy Up",precision=10), + MetUnclustEnUpDeltaY = Var("shiftedPy('UnclusteredEnUp')-py()", float, doc="Delta (METy_mod-METy) Unclustered Energy Up",precision=10), ), ) diff --git a/PhysicsTools/NanoAOD/python/muons_cff.py b/PhysicsTools/NanoAOD/python/muons_cff.py index 633c8ed5f7f12..0dd84fa702794 100644 --- a/PhysicsTools/NanoAOD/python/muons_cff.py +++ b/PhysicsTools/NanoAOD/python/muons_cff.py @@ -2,19 +2,34 @@ from Configuration.Eras.Modifier_run2_miniAOD_80XLegacy_cff import run2_miniAOD_80XLegacy from Configuration.Eras.Modifier_run2_nanoAOD_92X_cff import run2_nanoAOD_92X from PhysicsTools.NanoAOD.common_cff import * +import PhysicsTools.PatAlgos.producersLayer1.muonProducer_cfi + +# this below is used only in some eras +slimmedMuonsUpdated = cms.EDProducer("PATMuonUpdater", + src = cms.InputTag("slimmedMuons"), + vertices = cms.InputTag("offlineSlimmedPrimaryVertices"), + computeMiniIso = cms.bool(False), + pfCandsForMiniIso = cms.InputTag("packedPFCandidates"), + miniIsoParams = PhysicsTools.PatAlgos.producersLayer1.muonProducer_cfi.patMuons.miniIsoParams, # so they're in sync +) +run2_miniAOD_80XLegacy.toModify( slimmedMuonsUpdated, computeMiniIso = True ) isoForMu = cms.EDProducer("MuonIsoValueMapProducer", src = cms.InputTag("slimmedMuons"), relative = cms.bool(False), - rho_MiniIso = cms.InputTag("fixedGridRhoFastjetCentralNeutral"), + rho_MiniIso = cms.InputTag("fixedGridRhoFastjetAll"), EAFile_MiniIso = cms.FileInPath("PhysicsTools/NanoAOD/data/effAreaMuons_cone03_pfNeuHadronsAndPhotons_80X.txt"), ) +run2_miniAOD_80XLegacy.toModify(isoForMu, src = "slimmedMuonsUpdated") +run2_nanoAOD_92X.toModify(isoForMu, src = "slimmedMuonsUpdated") ptRatioRelForMu = cms.EDProducer("MuonJetVarProducer", srcJet = cms.InputTag("slimmedJets"), srcLep = cms.InputTag("slimmedMuons"), srcVtx = cms.InputTag("offlineSlimmedPrimaryVertices"), ) +run2_miniAOD_80XLegacy.toModify(ptRatioRelForMu, srcLep = "slimmedMuonsUpdated") +run2_nanoAOD_92X.toModify(ptRatioRelForMu, srcLep = "slimmedMuonsUpdated") slimmedMuonsWithUserData = cms.EDProducer("PATMuonUserDataEmbedder", src = cms.InputTag("slimmedMuons"), @@ -29,18 +44,13 @@ jetForLepJetVar = cms.InputTag("ptRatioRelForMu:jetForLepJetVar") # warning: Ptr is null if no match is found ), ) -# this below is used only in some eras -slimmedMuonsWithDZ = cms.EDProducer("PATMuonUpdater", - src = cms.InputTag("slimmedMuonsWithUserData"), - vertices = cms.InputTag("offlineSlimmedPrimaryVertices") -) +run2_miniAOD_80XLegacy.toModify(slimmedMuonsWithUserData, src = "slimmedMuonsUpdated") +run2_nanoAOD_92X.toModify(slimmedMuonsWithUserData, src = "slimmedMuonsUpdated") finalMuons = cms.EDFilter("PATMuonRefSelector", src = cms.InputTag("slimmedMuonsWithUserData"), cut = cms.string("pt > 3 && track.isNonnull && isLooseMuon") ) -run2_miniAOD_80XLegacy.toModify(finalMuons, src = "slimmedMuonsWithDZ") -run2_nanoAOD_92X.toModify(finalMuons, src = "slimmedMuonsWithDZ") muonMVATTH= cms.EDProducer("MuonBaseMVAValueMapProducer", src = cms.InputTag("linkedObjects","muons"), @@ -81,6 +91,7 @@ sip3d = Var("abs(dB('PV3D')/edB('PV3D'))",float,doc="3D impact parameter significance wrt first PV",precision=10), segmentComp = Var("segmentCompatibility()", float, doc = "muon segment compatibility", precision=14), # keep higher precision since people have cuts with 3 digits on this nStations = Var("numberOfMatchedStations", int, doc = "number of matched stations with default arbitration (segment & track)"), + nTrackerLayers = Var("innerTrack().hitPattern().trackerLayersWithMeasurement()", int, doc = "number of layers in the tracker"), jetIdx = Var("?hasUserCand('jet')?userCand('jet').key():-1", int, doc="index of the associated jet (-1 if none)"), miniPFRelIso_chg = Var("userFloat('miniIsoChg')/pt",float,doc="mini PF relative isolation, charged component"), miniPFRelIso_all = Var("userFloat('miniIsoAll')/pt",float,doc="mini PF relative isolation, total (with scaled rho*EA PU corrections)"), @@ -88,6 +99,7 @@ pfRelIso03_all = Var("(pfIsolationR03().sumChargedHadronPt + max(pfIsolationR03().sumNeutralHadronEt + pfIsolationR03().sumPhotonEt - pfIsolationR03().sumPUPt/2,0.0))/pt",float,doc="PF relative isolation dR=0.3, total (deltaBeta corrections)"), pfRelIso04_all = Var("(pfIsolationR04().sumChargedHadronPt + max(pfIsolationR04().sumNeutralHadronEt + pfIsolationR04().sumPhotonEt - pfIsolationR04().sumPUPt/2,0.0))/pt",float,doc="PF relative isolation dR=0.4, total (deltaBeta corrections)"), tightCharge = Var("?(muonBestTrack().ptError()/muonBestTrack().pt() < 0.2)?2:0",int,doc="Tight charge criterion using pterr/pt of muonBestTrack (0:fail, 2:pass)"), + isPFcand = Var("isPFMuon",bool,doc="muon is PF candidate"), ), externalVariables = cms.PSet( mvaTTH = ExtVar(cms.InputTag("muonMVATTH"),float, doc="TTH MVA lepton ID score",precision=14), @@ -126,7 +138,7 @@ muonMC = cms.Sequence(muonsMCMatchForTable + muonMCTable) muonTables = cms.Sequence(muonMVATTH + muonTable + muonIDTable) -_withDZ_sequence = muonSequence.copy() -_withDZ_sequence.replace(finalMuons, slimmedMuonsWithDZ+finalMuons) -run2_nanoAOD_92X.toReplaceWith(muonSequence, _withDZ_sequence) -run2_miniAOD_80XLegacy.toReplaceWith(muonSequence, _withDZ_sequence) +_withUpdate_sequence = muonSequence.copy() +_withUpdate_sequence.replace(isoForMu, slimmedMuonsUpdated+isoForMu) +run2_nanoAOD_92X.toReplaceWith(muonSequence, _withUpdate_sequence) +run2_miniAOD_80XLegacy.toReplaceWith(muonSequence, _withUpdate_sequence) diff --git a/PhysicsTools/NanoAOD/python/nanoDQM_cff.py b/PhysicsTools/NanoAOD/python/nanoDQM_cff.py new file mode 100644 index 0000000000000..42e6dc4d0212f --- /dev/null +++ b/PhysicsTools/NanoAOD/python/nanoDQM_cff.py @@ -0,0 +1,21 @@ +import FWCore.ParameterSet.Config as cms + +from PhysicsTools.NanoAOD.nanoDQM_cfi import nanoDQM + +nanoDQMMC = nanoDQM.clone() +nanoDQMMC.vplots.Electron.sels.Prompt = cms.string("genPartFlav == 1") +nanoDQMMC.vplots.Muon.sels.Prompt = cms.string("genPartFlav == 1") +nanoDQMMC.vplots.Photon.sels.Prompt = cms.string("genPartFlav == 1") +nanoDQMMC.vplots.Tau.sels.Prompt = cms.string("genPartFlav == 5") +nanoDQMMC.vplots.Jet.sels.Prompt = cms.string("genJetIdx != 1") +nanoDQMMC.vplots.Jet.sels.PromptB = cms.string("genJetIdx != 1 && hadronFlavour == 5") + +nanoDQMQTester = cms.EDAnalyzer("QualityTester", + qtList = cms.untracked.FileInPath('PhysicsTools/NanoAOD/test/dqmQualityTests.xml'), + prescaleFactor = cms.untracked.int32(1), + testInEventloop = cms.untracked.bool(False), + qtestOnEndLumi = cms.untracked.bool(False), + verboseQT = cms.untracked.bool(True) +) + +nanoHarvest = cms.Sequence( nanoDQMQTester ) diff --git a/PhysicsTools/NanoAOD/python/nanoDQM_cfi.py b/PhysicsTools/NanoAOD/python/nanoDQM_cfi.py new file mode 100644 index 0000000000000..99dc4997d1acf --- /dev/null +++ b/PhysicsTools/NanoAOD/python/nanoDQM_cfi.py @@ -0,0 +1,455 @@ +# automatically generated by prepareDQM.py +import FWCore.ParameterSet.Config as cms +from PhysicsTools.NanoAOD.nanoDQM_tools_cff import * + +nanoDQM = cms.EDAnalyzer("NanoAODDQM", + vplots = cms.PSet( + CaloMET = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'), + Plot1D('pt', 'pt', 20, 0, 400, 'pt'), + Plot1D('sumEt', 'sumEt', 20, 200, 3000, 'scalar sum of Et'), + ) + ), + Electron = cms.PSet( + sels = cms.PSet( + Good = cms.string('pt > 15 && abs(dxy) < 0.2 && abs(dz) < 0.5 && cutBased >= 3 && miniPFRelIso_all < 0.4') + ), + plots = cms.VPSet( + Count1D('_size', 8, -0.5, 7.5, 'slimmedElectrons after basic selection (pt > 5 )'), + Plot1D('charge', 'charge', 3, -1.5, 1.5, 'electric charge'), + Plot1D('cleanmask', 'cleanmask', 1, 0.5, 1.5, 'simple cleaning mask with priority to leptons'), + Plot1D('convVeto', 'convVeto', 2, -0.5, 1.5, 'pass conversion veto'), + Plot1D('cutBased', 'cutBased', 5, -0.5, 4.5, 'cut-based ID (0:fail, 1:veto, 2:loose, 3:medium, 4:tight)'), + Plot1D('cutBased_HLTPreSel', 'cutBased_HLTPreSel', 2, -0.5, 1.5, 'cut-based HLT pre-selection ID'), + Plot1D('deltaEtaSC', 'deltaEtaSC', 20, -0.2, 0.2, 'delta eta (SC,ele) with sign'), + Plot1D('dr03EcalRecHitSumEt', 'dr03EcalRecHitSumEt', 20, 0, 30, 'Non-PF Ecal isolation within a delta R cone of 0.3 with electron pt > 35 GeV'), + Plot1D('dr03HcalDepth1TowerSumEt', 'dr03HcalDepth1TowerSumEt', 20, 0, 20, 'Non-PF Hcal isolation within a delta R cone of 0.3 with electron pt > 35 GeV'), + Plot1D('dr03TkSumPt', 'dr03TkSumPt', 20, 0, 40, 'Non-PF track isolation within a delta R cone of 0.3 with electron pt > 35 GeV'), + Plot1D('dxy', 'dxy', 20, -0.1, 0.1, 'dxy (with sign) wrt first PV, in cm'), + Plot1D('dxyErr', 'dxyErr', 20, 0, 0.2, 'dxy uncertainty, in cm'), + Plot1D('dz', 'dz', 20, -0.3, 0.3, 'dz (with sign) wrt first PV, in cm'), + Plot1D('dzErr', 'dzErr', 20, 0, 0.2, 'dz uncertainty, in cm'), + Plot1D('eCorr', 'eCorr', 20, 0.6, 1.6, 'ratio of the calibrated energy/miniaod energy'), + Plot1D('energyErr', 'energyErr', 20, 0, 90, 'energy error of the cluster-track combination'), + Plot1D('eta', 'eta', 20, -3, 3, 'eta'), + Plot1D('genPartFlav', 'genPartFlav', 20, 0, 30, 'Flavour of genParticle for MC matching to status==1 electrons or photons: 1 = prompt electron (including gamma*->mu mu), 15 = electron from prompt tau, 22 = prompt photon (likely conversion), 5 = electron from b, 4 = electron from c, 3 = electron from light or unknown, 0 = unmatched'), + NoPlot('genPartIdx'), + Plot1D('hoe', 'hoe', 20, 0, 1, 'H over E'), + Plot1D('ip3d', 'ip3d', 20, 0, 0.2, '3D impact parameter wrt first PV, in cm'), + Plot1D('isPFcand', 'isPFcand', 2, -0.5, 1.5, 'electron is PF candidate'), + NoPlot('jetIdx'), + Plot1D('lostHits', 'lostHits', 2, -0.5, 1.5, 'number of missing inner hits'), + NoPlot('mass'), + Plot1D('miniPFRelIso_all', 'miniPFRelIso_all', 20, 0, 1, 'mini PF relative isolation, total (with scaled rho*EA PU corrections)'), + Plot1D('miniPFRelIso_chg', 'miniPFRelIso_chg', 20, 0, 1, 'mini PF relative isolation, charged component'), + Plot1D('mvaSpring16GP', 'mvaSpring16GP', 20, -1, 1, 'MVA general-purpose ID score'), + Plot1D('mvaSpring16GP_WP80', 'mvaSpring16GP_WP80', 2, -0.5, 1.5, 'MVA general-purpose ID WP80'), + Plot1D('mvaSpring16GP_WP90', 'mvaSpring16GP_WP90', 2, -0.5, 1.5, 'MVA general-purpose ID WP90'), + Plot1D('mvaSpring16HZZ', 'mvaSpring16HZZ', 20, -1, 1, 'MVA HZZ ID score'), + Plot1D('mvaSpring16HZZ_WPL', 'mvaSpring16HZZ_WPL', 2, -0.5, 1.5, 'MVA HZZ ID loose WP'), + Plot1D('mvaTTH', 'mvaTTH', 20, -1, 1, 'TTH MVA lepton ID score'), + Plot1D('pdgId', 'pdgId', 27, -13.5, 13.5, 'PDG code assigned by the event reconstruction (not by MC truth)'), + Plot1D('pfRelIso03_all', 'pfRelIso03_all', 20, 0, 2, 'PF relative isolation dR=0.3, total (with rho*EA PU corrections)'), + Plot1D('pfRelIso03_chg', 'pfRelIso03_chg', 20, 0, 2, 'PF relative isolation dR=0.3, charged component'), + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'), + NoPlot('photonIdx'), + Plot1D('pt', 'pt', 20, 0, 200, 'pt (corrected)'), + Plot1D('r9', 'r9', 20, 0, 1.1, 'R9 of the supercluster, calculated with full 5x5 region'), + Plot1D('sieie', 'sieie', 20, 0, 0.05, 'sigma_IetaIeta of the supercluster, calculated with full 5x5 region'), + Plot1D('sip3d', 'sip3d', 20, 0, 20, '3D impact parameter significance wrt first PV, in cm'), + Plot1D('tightCharge', 'tightCharge', 3, -0.5, 2.5, 'Tight charge criteria (0:none, 1:isGsfScPixChargeConsistent, 2:isGsfCtfScPixChargeConsistent)'), + NoPlot('vidNestedWPBitmap'), + ) + ), + FatJet = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Count1D('_size', 6, -0.5, 5.5, 'slimmedJetsAK8, i.e. ak8 fat jets for boosted analysis'), + Plot1D('area', 'area', 20, 2, 4, 'jet catchment area, for JECs'), + Plot1D('btagCMVA', 'btagCMVA', 20, -1, 1, 'CMVA V2 btag discriminator'), + Plot1D('btagDeepB', 'btagDeepB', 20, -1, 1, 'CMVA V2 btag discriminator'), + Plot1D('btagDeepBB', 'btagDeepBB', 20, -1, 1, 'CMVA V2 btag discriminator'), + Plot1D('btagHbb', 'btagHbb', 20, -1, 1, 'Higgs to BB tagger discriminator'), + Plot1D('eta', 'eta', 20, -4, 4, 'eta'), + Plot1D('mass', 'mass', 20, 0, 300, 'mass'), + Plot1D('msoftdrop', 'msoftdrop', 20, -300, 300, 'Soft drop mass'), + Plot1D('n2b1', 'n2b1', 20, 0, 1, 'N2 (beta=1)'), + Plot1D('n3b1', 'n3b1', 20, 0, 5, 'N3 (beta=1)'), + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'), + Plot1D('pt', 'pt', 20, 0, 800, 'pt'), + NoPlot('subJetIdx1'), + NoPlot('subJetIdx2'), + Plot1D('tau1', 'tau1', 20, 0, 1, 'Nsubjettiness (1 axis)'), + Plot1D('tau2', 'tau2', 20, 0, 1, 'Nsubjettiness (2 axis)'), + Plot1D('tau3', 'tau3', 20, 0, 1, 'Nsubjettiness (3 axis)'), + Plot1D('tau4', 'tau4', 20, 0, 1, 'Nsubjettiness (4 axis)'), + ) + ), + Flag = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Plot1D('BadChargedCandidateFilter', 'BadChargedCandidateFilter', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('BadChargedCandidateSummer16Filter', 'BadChargedCandidateSummer16Filter', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('BadPFMuonFilter', 'BadPFMuonFilter', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('BadPFMuonSummer16Filter', 'BadPFMuonSummer16Filter', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('CSCTightHalo2015Filter', 'CSCTightHalo2015Filter', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('CSCTightHaloFilter', 'CSCTightHaloFilter', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('CSCTightHaloTrkMuUnvetoFilter', 'CSCTightHaloTrkMuUnvetoFilter', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('EcalDeadCellBoundaryEnergyFilter', 'EcalDeadCellBoundaryEnergyFilter', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('EcalDeadCellTriggerPrimitiveFilter', 'EcalDeadCellTriggerPrimitiveFilter', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('HBHENoiseFilter', 'HBHENoiseFilter', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('HBHENoiseIsoFilter', 'HBHENoiseIsoFilter', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('HcalStripHaloFilter', 'HcalStripHaloFilter', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('METFilters', 'METFilters', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('chargedHadronTrackResolutionFilter', 'chargedHadronTrackResolutionFilter', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('ecalLaserCorrFilter', 'ecalLaserCorrFilter', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('eeBadScFilter', 'eeBadScFilter', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('globalSuperTightHalo2016Filter', 'globalSuperTightHalo2016Filter', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('globalTightHalo2016Filter', 'globalTightHalo2016Filter', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('goodVertices', 'goodVertices', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('hcalLaserEventFilter', 'hcalLaserEventFilter', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('muonBadTrackFilter', 'muonBadTrackFilter', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('trkPOGFilters', 'trkPOGFilters', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('trkPOG_logErrorTooManyClusters', 'trkPOG_logErrorTooManyClusters', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('trkPOG_manystripclus53X', 'trkPOG_manystripclus53X', 2, -0.5, 1.5, 'Trigger/flag bit'), + Plot1D('trkPOG_toomanystripclus53X', 'trkPOG_toomanystripclus53X', 2, -0.5, 1.5, 'Trigger/flag bit'), + ) + ), + GenJet = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Count1D('_size', 25, -0.5, 24.5, 'slimmedGenJets, i.e. ak4 Jets made with visible genparticles'), + Plot1D('eta', 'eta', 20, -7, 7, 'eta'), + Plot1D('mass', 'mass', 20, 0, 200, 'mass'), + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'), + Plot1D('pt', 'pt', 20, 0, 200, 'pt'), + ) + ), + GenMET = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'), + Plot1D('pt', 'pt', 20, 0, 400, 'pt'), + ) + ), + GenPart = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Count1D('_size', 40, -0.5, 124.5, 'interesting gen particles '), + Plot1D('eta', 'eta', 20, -30000, 30000, 'eta'), + NoPlot('genPartIdxMother'), + Plot1D('mass', 'mass', 20, 0, 300, 'Mass stored for all particles with mass > 10 GeV and photons with mass > 1 GeV. For other particles you can lookup from PDGID'), + Plot1D('pdgId', 'pdgId', 20, -6000, 6000, 'PDG id'), + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'), + Plot1D('pt', 'pt', 20, 0, 200, 'pt'), + Plot1D('status', 'status', 20, 0, 100, 'Particle status. 1=stable'), + ) + ), + GenVisTau = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Count1D('_size', 4, -0.5, 3.5, 'gen hadronic taus '), + Plot1D('charge', 'charge', 3, -1.5, 1.5, 'charge'), + Plot1D('eta', 'eta', 20, -5, 5, 'eta'), + NoPlot('genPartIdxMother'), + Plot1D('mass', 'mass', 20, 0, 2, 'mass'), + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'), + Plot1D('pt', 'pt', 20, 0, 200, 'pt'), + Plot1D('status', 'status', 16, -0.5, 15.5, 'Hadronic tau decay mode. 0=OneProng0PiZero, 1=OneProng1PiZero, 2=OneProng2PiZero, 10=ThreeProng0PiZero, 11=ThreeProng1PiZero, 15=Other'), + ) + ), + IsoTrack = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Count1D('_size', 5, -0.5, 4.5, 'isolated tracks after basic selection (pt > 10 && abs(dxy) < 0.02 && abs(dz) < 0.1 && isHighPurityTrack && miniPFIsolation.chargedHadronIso/pt < 0.2) and lepton veto'), + Plot1D('dxy', 'dxy', 20, -0.02, 0.02, 'dxy (with sign) wrt first PV, in cm'), + Plot1D('dz', 'dz', 20, -0.09, 0.09, 'dz (with sign) wrt first PV, in cm'), + Plot1D('eta', 'eta', 20, -3, 3, 'eta'), + Plot1D('isHighPurityTrack', 'isHighPurityTrack', 2, -0.5, 1.5, 'track is high purity'), + Plot1D('isPFcand', 'isPFcand', 2, -0.5, 1.5, 'if isolated track is a PF candidate'), + Plot1D('miniPFRelIso_all', 'miniPFRelIso_all', 20, 0, 2, 'mini PF relative isolation, total (with scaled rho*EA PU corrections)'), + Plot1D('miniPFRelIso_chg', 'miniPFRelIso_chg', 20, 0, 2, 'mini PF relative isolation, charged component'), + Plot1D('pdgId', 'pdgId', 20, -300, 300, 'PDG id of PF cand'), + Plot1D('pfRelIso03_all', 'pfRelIso03_all', 20, 0, 2, 'PF relative isolation dR=0.3, total (deltaBeta corrections)'), + Plot1D('pfRelIso03_chg', 'pfRelIso03_chg', 20, 0, 2, 'PF relative isolation dR=0.3, charged component'), + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'), + Plot1D('pt', 'pt', 20, 0, 200, 'pt'), + ) + ), + Jet = cms.PSet( + sels = cms.PSet( + CentralPt30 = cms.string('abs(eta) < 2.4 && pt > 30'), + ForwardPt30 = cms.string('abs(eta) > 2.4 && pt > 30') + ), + plots = cms.VPSet( + Count1D('_size', 20, -0.5, 19.5, 'slimmedJets, i.e. ak4 PFJets CHS with JECs applied, after basic selection (pt > 15)'), + Plot1D('area', 'area', 20, 0.2, 0.8, 'jet catchment area, for JECs'), + Plot1D('bReg', 'bReg', 20, 30, 500, 'pt corrected with b-jet regression'), + Plot1D('btagCMVA', 'btagCMVA', 20, -1, 1, 'CMVA V2 btag discriminator'), + Plot1D('btagDeepB', 'btagDeepB', 20, 0, 1, 'DeepCSV b tag discriminator'), + Plot1D('btagDeepBB', 'btagDeepBB', 20, 0, 1, 'DeepCSV bb tag discriminator'), + Plot1D('btagDeepC', 'btagDeepC', 20, 0, 1, 'DeepCSV charm btag discriminator'), + Plot1D('chEmEF', 'chEmEF', 20, 0, 1, 'charged Electromagnetic Energy Fraction'), + Plot1D('chHEF', 'chHEF', 20, 0, 2, 'charged Hadron Energy Fraction'), + Plot1D('cleanmask', 'cleanmask', 2, -0.5, 1.5, 'simple cleaning mask with priority to leptons'), + NoPlot('electronIdx1'), + NoPlot('electronIdx2'), + Plot1D('eta', 'eta', 20, -6, 6, 'eta'), + NoPlot('genJetIdx'), + Plot1D('hadronFlavour', 'hadronFlavour', 6, -0.5, 5.5, 'flavour from hadron ghost clustering'), + Plot1D('jetId', 'jetId', 4, -0.5, 3.5, 'Jet ID flags bit1 is loose, bit2 is tight'), + Plot1D('mass', 'mass', 20, 0, 200, 'mass'), + NoPlot('muonIdx1'), + NoPlot('muonIdx2'), + Plot1D('nConstituents', 'nConstituents', 20, 0, 80, 'Number of particles in the jet'), + Plot1D('nElectrons', 'nElectrons', 5, -0.5, 4.5, 'number of electrons in the jet'), + Plot1D('nMuons', 'nMuons', 4, -0.5, 3.5, 'number of muons in the jet'), + Plot1D('neEmEF', 'neEmEF', 20, 0, 1, 'charged Electromagnetic EnergyFraction'), + Plot1D('neHEF', 'neHEF', 20, 0, 1, 'neutral Hadron Energy Fraction'), + Plot1D('partonFlavour', 'partonFlavour', 40, -9.5, 30.5, 'flavour from parton matching'), + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'), + Plot1D('pt', 'pt', 20, 0, 400, 'pt'), + Plot1D('puId', 'puId', 8, -0.5, 7.5, 'Pilup ID flags'), + Plot1D('qgl', 'qgl', 20, 0, 1, 'Quark vs Gluon likelihood discriminator'), + Plot1D('rawFactor', 'rawFactor', 20, 0.5, 1.5, '1 - Factor to get back to raw pT'), + ) + ), + MET = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Plot1D('MetUnclustEnUpDeltaX', 'MetUnclustEnUpDeltaX', 20, -20, 20, 'Delta (METx_mod-METx) Unclustered Energy Up'), + Plot1D('MetUnclustEnUpDeltaY', 'MetUnclustEnUpDeltaY', 20, -10, 10, 'Delta (METy_mod-METy) Unclustered Energy Up'), + Plot1D('covXX', 'covXX', 20, 0, 40000, 'xx element of met covariance matrix'), + Plot1D('covXY', 'covXY', 20, -8000, 8000, 'xy element of met covariance matrix'), + Plot1D('covYY', 'covYY', 20, 0, 50000, 'yy element of met covariance matrix'), + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'), + Plot1D('pt', 'pt', 20, 0, 400, 'pt'), + Plot1D('significance', 'significance', 20, 0, 200, 'MET significance'), + Plot1D('sumEt', 'sumEt', 20, 600, 5000, 'scalar sum of Et'), + ) + ), + Muon = cms.PSet( + sels = cms.PSet( + Good = cms.string('pt > 15 && abs(dxy) < 0.2 && abs(dz) < 0.5 && mediumId && miniPFRelIso_all < 0.4') + ), + plots = cms.VPSet( + Count1D('_size', 5, -0.5, 4.5, 'slimmedMuons after basic selection (pt > 3 && track.isNonnull && isLooseMuon)'), + Plot1D('charge', 'charge', 3, -1.5, 1.5, 'electric charge'), + Plot1D('cleanmask', 'cleanmask', 2, -0.5, 1.5, 'simple cleaning mask with priority to leptons'), + Plot1D('dxy', 'dxy', 20, -0.1, 0.1, 'dxy (with sign) wrt first PV, in cm'), + Plot1D('dxyErr', 'dxyErr', 20, 0, 0.1, 'dxy uncertainty, in cm'), + Plot1D('dz', 'dz', 20, -0.3, 0.3, 'dz (with sign) wrt first PV, in cm'), + Plot1D('dzErr', 'dzErr', 20, 0, 0.2, 'dz uncertainty, in cm'), + Plot1D('eta', 'eta', 20, -2.5, 2.5, 'eta'), + Plot1D('genPartFlav', 'genPartFlav', 16, -0.5, 15.5, 'Flavour of genParticle for MC matching to status==1 muons: 1 = prompt muon (including gamma*->mu mu), 15 = muon from prompt tau, 5 = muon from b, 4 = muon from c, 3 = muon from light or unknown, 0 = unmatched'), + NoPlot('genPartIdx'), + Plot1D('highPtId', 'highPtId', 3, -0.5, 2.5, 'POG highPt muon ID (1 = tracker high pT, 2 = global high pT, which includes tracker high pT)'), + Plot1D('ip3d', 'ip3d', 20, 0, 0.2, '3D impact parameter wrt first PV, in cm'), + Plot1D('isPFcand', 'isPFcand', 2, -0.5, 1.5, 'muon is PF candidate'), + NoPlot('jetIdx'), + NoPlot('mass'), + Profile1D('mediumId', 'mediumId', 'pt', 16, 0, 80, 'POG Medium muon ID (using the relaxed cuts in the data Run 2016 B-F periods, and standard cuts elsewhere)'), + Plot1D('miniPFRelIso_all', 'miniPFRelIso_all', 20, 0, 1, 'mini PF relative isolation, total (with scaled rho*EA PU corrections)'), + Plot1D('miniPFRelIso_chg', 'miniPFRelIso_chg', 20, 0, 1, 'mini PF relative isolation, charged component'), + Plot1D('mvaTTH', 'mvaTTH', 20, -1, 1, 'TTH MVA lepton ID score'), + Plot1D('nStations', 'nStations', 5, -0.5, 4.5, 'number of matched stations with default arbitration (segment & track)'), + Plot1D('nTrackerLayers', 'nTrackerLayers', 15, 2.5, 17.5, 'number of layers in the tracker'), + Plot1D('pdgId', 'pdgId', 27, -13.5, 13.5, 'PDG code assigned by the event reconstruction (not by MC truth)'), + Plot1D('pfRelIso03_all', 'pfRelIso03_all', 20, 0, 2, 'PF relative isolation dR=0.3, total (deltaBeta corrections)'), + Plot1D('pfRelIso03_chg', 'pfRelIso03_chg', 20, 0, 2, 'PF relative isolation dR=0.3, charged component'), + Plot1D('pfRelIso04_all', 'pfRelIso04_all', 20, 0, 2, 'PF relative isolation dR=0.4, total (deltaBeta corrections)'), + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'), + Plot1D('pt', 'pt', 20, 0, 200, 'pt'), + Plot1D('ptErr', 'ptErr', 20, 0, 20, 'ptError of the muon track'), + Plot1D('segmentComp', 'segmentComp', 20, 0, 1, 'muon segment compatibility'), + Plot1D('sip3d', 'sip3d', 20, 0, 20, '3D impact parameter significance wrt first PV'), + Profile1D('softId', 'softId', 'pt', 20, 0, 40, 'POG Soft muon ID (using the relaxed cuts in the data Run 2016 B-F periods, and standard cuts elsewhere)'), + Plot1D('tightCharge', 'tightCharge', 1, 1.5, 2.5, 'Tight charge criterion using pterr/pt of muonBestTrack (0:fail, 2:pass)'), + Profile1D('tightId', 'tightId', 'pt', 16, 0, 80, 'POG Tight muon ID'), + ) + ), + OtherPV = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + NoPlot('_size'), + Plot1D('z', 'z', 20, -20, 20, 'Z position of other primary vertices, excluding the main PV'), + ) + ), + PV = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Plot1D('chi2', 'chi2', 20, 0.5, 3, 'main primary vertex reduced chi2'), + Plot1D('ndof', 'ndof', 20, 0, 500, 'main primary vertex number of degree of freedom'), + Plot1D('npvs', 'npvs', 20, 0, 60, 'total number of reconstructed primary vertices'), + Plot1D('score', 'score', 20, 0, 300000, 'main primary vertex score, i.e. sum pt2 of clustered objects'), + Plot1D('x', 'x', 20, -0.3, 0.3, 'main primary vertex position x coordinate'), + Plot1D('y', 'y', 20, -0.3, 0.3, 'main primary vertex position y coordinate'), + Plot1D('z', 'z', 20, -20, 20, 'main primary vertex position z coordinate'), + ) + ), + Photon = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Count1D('_size', 9, -0.5, 8.5, 'slimmedPhotons after basic selection (pt > 5 )'), + Plot1D('charge', 'charge', 1, -0.5, 0.5, 'electric charge'), + Plot1D('cleanmask', 'cleanmask', 1, 0.5, 1.5, 'simple cleaning mask with priority to leptons'), + Plot1D('cutBased', 'cutBased', 4, -0.5, 3.5, 'cut-based ID (0:fail, 1::loose, 2:medium, 3:tight)'), + Plot1D('eCorr', 'eCorr', 20, 0.6, 1.6, 'ratio of the calibrated energy/miniaod energy'), + NoPlot('electronIdx'), + Plot1D('electronVeto', 'electronVeto', 2, -0.5, 1.5, 'pass electron veto'), + Plot1D('energyErr', 'energyErr', 20, 0, 300, 'energy error of the cluster from regression'), + Plot1D('eta', 'eta', 20, -3, 3, 'eta'), + Plot1D('genPartFlav', 'genPartFlav', 14, -0.5, 13.5, 'Flavour of genParticle for MC matching to status==1 photons or electrons: 1 = prompt photon, 13 = prompt electron, 0 = unknown or unmatched'), + NoPlot('genPartIdx'), + Plot1D('hoe', 'hoe', 20, 0, 0.6, 'H over E'), + NoPlot('jetIdx'), + NoPlot('mass'), + Plot1D('mvaID', 'mvaID', 20, -1, 1, 'MVA ID score'), + Plot1D('mvaID_WP80', 'mvaID_WP80', 2, -0.5, 1.5, 'MVA ID WP80'), + Plot1D('mvaID_WP90', 'mvaID_WP90', 2, -0.5, 1.5, 'MVA ID WP90'), + Plot1D('pdgId', 'pdgId', 1, 21.5, 22.5, 'PDG code assigned by the event reconstruction (not by MC truth)'), + Plot1D('pfRelIso03_all', 'pfRelIso03_all', 20, 0, 2, 'PF relative isolation dR=0.3, total (with rho*EA PU corrections)'), + Plot1D('pfRelIso03_chg', 'pfRelIso03_chg', 20, 0, 2, 'PF relative isolation dR=0.3, charged component (with rho*EA PU corrections)'), + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'), + Plot1D('pixelSeed', 'pixelSeed', 2, -0.5, 1.5, 'has pixel seed'), + Plot1D('pt', 'pt', 20, 0, 200, 'pt (corrected)'), + Plot1D('r9', 'r9', 20, 0, 1.1, 'R9 of the supercluster, calculated with full 5x5 region'), + Plot1D('sieie', 'sieie', 20, 0, 0.05, 'sigma_IetaIeta of the supercluster, calculated with full 5x5 region'), + NoPlot('vidNestedWPBitmap'), + ) + ), + Pileup = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Plot1D('nPU', 'nPU', 20, 0, 60, 'the number of pileup interactions that have been added to the event in the current bunch crossing'), + Plot1D('nTrueInt', 'nTrueInt', 20, 0, 60, 'the true mean number of the poisson distribution for this event from which the number of interactions each bunch crossing has been sampled'), + ) + ), + PuppiMET = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'), + Plot1D('pt', 'pt', 20, 0, 400, 'pt'), + Plot1D('sumEt', 'sumEt', 20, 200, 3000, 'scalar sum of Et'), + ) + ), + RawMET = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'), + Plot1D('pt', 'pt', 20, 0, 400, 'pt'), + Plot1D('sumEt', 'sumEt', 20, 400, 4000, 'scalar sum of Et'), + ) + ), + SV = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Count1D('_size', 14, -0.5, 13.5), + Plot1D('chi2', 'chi2', 20, -2000, 2000, 'reduced chi2, i.e. chi/ndof'), + Plot1D('dlen', 'dlen', 20, 0, 4, 'decay length in cm'), + Plot1D('dlenSig', 'dlenSig', 20, 0, 50, 'decay length significance'), + Plot1D('eta', 'eta', 20, -3, 3, 'eta'), + Plot1D('mass', 'mass', 20, 0, 8, 'mass'), + Plot1D('ndof', 'ndof', 20, -1, 19, 'number of degrees of freedom'), + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'), + Plot1D('pt', 'pt', 20, 0, 200, 'pt'), + Plot1D('x', 'x', 20, -0.5, 0.5, 'secondary vertex X position, in cm'), + Plot1D('y', 'y', 20, -0.5, 0.5, 'secondary vertex Y position, in cm'), + Plot1D('z', 'z', 20, -10, 10, 'secondary vertex Z position, in cm'), + ) + ), + SoftActivityJet = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Count1D('_size', 7, -0.5, 6.5, 'jets clustered from charged candidates compatible with primary vertex (charge()!=0 && pvAssociationQuality()>=5 && vertexRef().key()==0)'), + Plot1D('eta', 'eta', 20, -3, 3, 'eta'), + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'), + Plot1D('pt', 'pt', 20, 0, 200, 'pt'), + ) + ), + SubJet = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Count1D('_size', 9, -0.5, 8.5, 'slimmedJetsAK8, i.e. ak8 fat jets for boosted analysis'), + Plot1D('btagCMVA', 'btagCMVA', 20, -1, 1, 'CMVA V2 btag discriminator'), + Plot1D('btagDeepB', 'btagDeepB', 20, -1, 1, 'CMVA V2 btag discriminator'), + Plot1D('btagDeepBB', 'btagDeepBB', 20, -1, 1, 'CMVA V2 btag discriminator'), + Plot1D('eta', 'eta', 20, -4, 4, 'eta'), + Plot1D('mass', 'mass', 20, -200, 200, 'mass'), + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'), + Plot1D('pt', 'pt', 20, 0, 200, 'pt'), + ) + ), + Tau = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Count1D('_size', 7, -0.5, 6.5, "slimmedTaus after basic selection (pt > 18 && tauID('decayModeFindingNewDMs') && (tauID('byLooseCombinedIsolationDeltaBetaCorr3Hits') || tauID('byVLooseIsolationMVArun2v1DBoldDMwLT') || tauID('byVLooseIsolationMVArun2v1DBnewDMwLT') || tauID('byVLooseIsolationMVArun2v1DBdR03oldDMwLT')))"), + Plot1D('charge', 'charge', 3, -1.5, 1.5, 'electric charge'), + Plot1D('chargedIso', 'chargedIso', 20, 0, 200, 'charged isolation'), + Plot1D('cleanmask', 'cleanmask', 1, 0.5, 1.5, 'simple cleaning mask with priority to leptons'), + Plot1D('decayMode', 'decayMode', 12, -0.5, 11.5, 'decayMode()'), + Plot1D('dxy', 'dxy', 20, -1000, 1000, 'd_{xy} of lead track with respect to PV, in cm (with sign)'), + Plot1D('dz', 'dz', 20, -20, 20, 'd_{z} of lead track with respect to PV, in cm (with sign)'), + Plot1D('eta', 'eta', 20, -3, 3, 'eta'), + Plot1D('footprintCorr', 'footprintCorr', 20, 0, 30, 'footprint correction'), + Plot1D('genPartFlav', 'genPartFlav', 6, -0.5, 5.5, 'Flavour of genParticle for MC matching to status==2 taus: 1 = prompt electron, 2 = prompt muon, 3 = tau->e decay, 4 = tau->mu decay, 5 = hadronic tau decay, 0 = unknown or unmatched'), + NoPlot('genPartIdx'), + Plot1D('idAntiEle', 'idAntiEle', 2, -0.5, 1.5, 'Anti-electron MVA discriminator V6: bitmask 1 = VLoose, 2 = Loose, 4 = Medium, 8 = Tight, 16 = VTight'), + Plot1D('idAntiMu', 'idAntiMu', 2, -0.5, 1.5, 'Anti-muon discriminator V3: : bitmask 1 = Loose, 2 = Tight'), + Plot1D('idDecayMode', 'idDecayMode', 2, -0.5, 1.5, "tauID('decayModeFinding')"), + Plot1D('idDecayModeNewDMs', 'idDecayModeNewDMs', 2, -0.5, 1.5, "tauID('decayModeFindingNewDMs')"), + Plot1D('idMVAnewDM', 'idMVAnewDM', 2, -0.5, 1.5, 'IsolationMVArun2v1DBnewDMwLT ID working point: bitmask 1 = VLoose, 2 = Loose, 4 = Medium, 8 = Tight, 16 = VTight, 32 = VVTight'), + Plot1D('idMVAoldDM', 'idMVAoldDM', 2, -0.5, 1.5, 'IsolationMVArun2v1DBoldDMwLT ID working point: bitmask 1 = VLoose, 2 = Loose, 4 = Medium, 8 = Tight, 16 = VTight, 32 = VVTight'), + Plot1D('idMVAoldDMdR03', 'idMVAoldDMdR03', 2, -0.5, 1.5, 'IsolationMVArun2v1DBdR03oldDMwLT ID working point: bitmask 1 = VLoose, 2 = Loose, 4 = Medium, 8 = Tight, 16 = VTight, 32 = VVTight'), + NoPlot('jetIdx'), + Plot1D('leadTkDeltaEta', 'leadTkDeltaEta', 20, -0.1, 0.1, 'eta of the leading track, minus tau eta'), + Plot1D('leadTkDeltaPhi', 'leadTkDeltaPhi', 20, -0.1, 0.1, 'phi of the leading track, minus tau phi'), + Plot1D('leadTkPtOverTauPt', 'leadTkPtOverTauPt', 20, 0, 2, 'pt of the leading track divided by tau pt'), + Plot1D('mass', 'mass', 20, 0, 5, 'mass'), + Plot1D('neutralIso', 'neutralIso', 20, 0, 200, 'neutral (photon) isolation'), + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'), + Plot1D('photonsOutsideSignalCone', 'photonsOutsideSignalCone', 20, 0, 30, 'sum of photons outside signal cone'), + Plot1D('pt', 'pt', 20, 0, 200, 'pt'), + Plot1D('puCorr', 'puCorr', 20, 0, 90, 'pileup correction'), + Plot1D('rawAntiEle', 'rawAntiEle', 20, -100, 100, 'Anti-electron MVA discriminator V6 raw output discriminator'), + Plot1D('rawAntiEleCat', 'rawAntiEleCat', 17, -1.5, 15.5, 'Anti-electron MVA discriminator V6 category'), + Plot1D('rawIso', 'rawIso', 20, 0, 200, 'combined isolation (deltaBeta corrections)'), + Plot1D('rawMVAnewDM', 'rawMVAnewDM', 20, -1, 1, 'byIsolationMVArun2v1DBnewDMwLT raw output discriminator'), + Plot1D('rawMVAoldDM', 'rawMVAoldDM', 20, -1, 1, 'byIsolationMVArun2v1DBoldDMwLT raw output discriminator'), + Plot1D('rawMVAoldDMdR03', 'rawMVAoldDMdR03', 20, -1, 1, 'byIsolationMVArun2v1DBdR03oldDMwLT raw output discriminator'), + ) + ), + TkMET = cms.PSet( + sels = cms.PSet(), + plots = cms.VPSet( + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'), + Plot1D('pt', 'pt', 20, 0, 400, 'pt'), + Plot1D('sumEt', 'sumEt', 20, 0, 2000, 'scalar sum of Et'), + ) + ), + TrigObj = cms.PSet( + sels = cms.PSet( + Electron = cms.string('id == 11'), + HT = cms.string('id == 3'), + Jet = cms.string('id == 1'), + MET = cms.string('id == 2'), + MHT = cms.string('id == 4'), + Muon = cms.string('id == 13'), + Photon = cms.string('id == 22'), + Tau = cms.string('id == 15') + ), + plots = cms.VPSet( + Count1D('_size', 28, -0.5, 27.5), + Plot1D('eta', 'eta', 20, -5, 5, 'eta'), + Plot1D('filterBits', 'filterBits', 16, -0.5, 15.5, 'extra bits of associated information: 1 = CaloIdL_TrackIdL_IsoVL, 2 = WPLoose, 4 = WPTight for Electron (PixelMatched e/gamma); 1 = TrkIsoVVL, 2 = Iso for Muon; '), + Plot1D('id', 'id', 20, 0, 30, 'ID of the object: 11 = Electron (PixelMatched e/gamma), 22 = Photon (PixelMatch-vetoed e/gamma), 13 = Muon, 14 = Tau, 1 = Jet, 2 = MET, 3 = HT, 4 = MHT'), + Plot1D('l1pt', 'l1pt', 20, 0, 200, 'pt of associated L1 seed'), + Plot1D('l2pt', 'l2pt', 20, 0, 200, "pt of associated 'L2' seed (i.e. HLT before tracking/PF)"), + Plot1D('phi', 'phi', 20, -3.14159, 3.14159, 'phi'), + Plot1D('pt', 'pt', 40, 0, 400, 'pt'), + ) + ), + ) +) diff --git a/PhysicsTools/NanoAOD/python/nanoDQM_tools_cff.py b/PhysicsTools/NanoAOD/python/nanoDQM_tools_cff.py new file mode 100644 index 0000000000000..bdd48e1593559 --- /dev/null +++ b/PhysicsTools/NanoAOD/python/nanoDQM_tools_cff.py @@ -0,0 +1,26 @@ +import FWCore.ParameterSet.Config as cms + +def NoPlot(name): + return cms.PSet( name = cms.string(name), kind = cms.string("none")) + +def Count1D(name, nbins, xmin, xmax, title=""): + return cms.PSet( name = cms.string(name), kind = cms.string("count1d"), nbins = cms.uint32(nbins), min = cms.double(xmin), max = cms.double(xmax), title = cms.string(title) ) + +def Plot1D(name, column, nbins, xmin, xmax, title=""): + return cms.PSet( name = cms.string(name), kind = cms.string("hist1d"), column = cms.string(column), nbins = cms.uint32(nbins), min = cms.double(xmin), max = cms.double(xmax), title = cms.string(title) ) + +def Profile1D(name, ycolumn, xcolumn, nbins, xmin, xmax, title=""): + return cms.PSet( name = cms.string(name), kind = cms.string("prof1d"), ycolumn = cms.string(ycolumn), xcolumn = cms.string(xcolumn), nbins = cms.uint32(nbins), min = cms.double(xmin), max = cms.double(xmax), title = cms.string(title) ) + +def shortDump(pset): + kind = pset.kind.value() + if kind == "none": + return "NoPlot(%r)" % (pset.name.value()) + elif kind == "count1d": + return ("Count1D(%r, %d, %g, %g%s)" % (pset.name.value(), pset.nbins.value(), pset.min.value(), pset.max.value(), ", %r" % pset.title.value() if pset.title.value() else "")) + elif kind == "hist1d": + return ("Plot1D(%r, %r, %d, %g, %g%s)" % (pset.name.value(), pset.column.value(), pset.nbins.value(), pset.min.value(), pset.max.value(), ", %r" % pset.title.value() if pset.title.value() else "")) + elif kind == "prof1d": + return ("Profile1D(%r, %r, %r, %d, %g, %g%s)" % (pset.name.value(), pset.ycolumn.value(), pset.xcolumn.value(), pset.nbins.value(), pset.min.value(), pset.max.value(), ", %r" % pset.title.value() if pset.title.value() else "")) + + diff --git a/PhysicsTools/NanoAOD/python/nano_cff.py b/PhysicsTools/NanoAOD/python/nano_cff.py index e8d7d8ee216d8..5c65920f2fee2 100644 --- a/PhysicsTools/NanoAOD/python/nano_cff.py +++ b/PhysicsTools/NanoAOD/python/nano_cff.py @@ -48,7 +48,7 @@ genWeightsTable = cms.EDProducer("GenWeightsTableProducer", genEvent = cms.InputTag("generator"), lheInfo = cms.InputTag("externalLHEProducer"), - preferredPDFs = cms.vuint32(91400,260001), + preferredPDFs = cms.vuint32(91400,260001,262001), namedWeightIDs = cms.vstring(), namedWeightLabels = cms.vstring(), lheWeightPrecision = cms.int32(14), @@ -82,24 +82,33 @@ def nanoAOD_customizeData(process): def nanoAOD_customizeMC(process): process = nanoAOD_customizeCommon(process) - ## FIXME: WILL NO LONGER NEED RANDOM SEEDS WHEN DETERMINISTIC SMEARING WILL BE IMPLEMENTED - if not hasattr(process,'RandomNumberGeneratorService'): - process.RandomNumberGeneratorService = cms.Service("RandomNumberGeneratorService") - for X in 'calibratedPatElectrons','calibratedPatPhotons': - if not hasattr(process.RandomNumberGeneratorService,X): - setattr(process.RandomNumberGeneratorService, X, - cms.PSet(initialSeed = cms.untracked.uint32(81), engineName = cms.untracked.string('TRandom3'))) process.calibratedPatElectrons.isMC = cms.bool(True) process.calibratedPatPhotons.isMC = cms.bool(True) return process ### Era dependent customization from Configuration.Eras.Modifier_run2_miniAOD_80XLegacy_cff import run2_miniAOD_80XLegacy -#remove stuff +from RecoJets.JetProducers.QGTagger_cfi import QGTagger +qgtagger80x=QGTagger.clone(srcJets="slimmedJets",srcVertexCollection="offlineSlimmedPrimaryVertices") _80x_sequence = nanoSequence.copy() +#remove stuff _80x_sequence.remove(isoTrackTable) _80x_sequence.remove(isoTrackSequence) +#add qgl +_80x_sequence.insert(1,qgtagger80x) + +_80x_sequenceMC = nanoSequenceMC.copy() +_80x_sequenceMC.remove(genSubJetAK8Table) run2_miniAOD_80XLegacy.toReplaceWith( nanoSequence, _80x_sequence) +run2_miniAOD_80XLegacy.toReplaceWith( nanoSequenceMC, _80x_sequenceMC) +from Configuration.Eras.Modifier_run2_nanoAOD_92X_cff import run2_nanoAOD_92X +#remove stuff + +_92x_sequence = nanoSequence.copy() +_92x_sequenceMC = nanoSequenceMC.copy() +_92x_sequenceMC.remove(genSubJetAK8Table) +run2_nanoAOD_92X.toReplaceWith( nanoSequence, _92x_sequence) +run2_nanoAOD_92X.toReplaceWith( nanoSequenceMC, _92x_sequenceMC) diff --git a/PhysicsTools/NanoAOD/python/photons_cff.py b/PhysicsTools/NanoAOD/python/photons_cff.py index b367b65b87e32..9be60175e51d3 100644 --- a/PhysicsTools/NanoAOD/python/photons_cff.py +++ b/PhysicsTools/NanoAOD/python/photons_cff.py @@ -49,6 +49,7 @@ from EgammaAnalysis.ElectronTools.calibratedPhotonsRun2_cfi import calibratedPatPhotons calibratedPatPhotons.correctionFile = cms.string("PhysicsTools/NanoAOD/data/80X_ichepV2_2016_pho") # hack, should go somewhere in EgammaAnalysis +calibratedPatPhotons.semiDeterministic = cms.bool(True) energyCorrForPhoton = cms.EDProducer("PhotonEnergyVarProducer", srcRaw = cms.InputTag("slimmedPhotons"), diff --git a/PhysicsTools/NanoAOD/python/taus_cff.py b/PhysicsTools/NanoAOD/python/taus_cff.py index 9e6de49a2c0b3..0f6020319e133 100644 --- a/PhysicsTools/NanoAOD/python/taus_cff.py +++ b/PhysicsTools/NanoAOD/python/taus_cff.py @@ -84,16 +84,17 @@ def _tauId6WPMask(pattern,doc): genVisTauTable = cms.EDProducer("SimpleCandidateFlatTableProducer", src = cms.InputTag("genVisTaus"), cut = cms.string("pt > 10."), - name= cms.string("GenVisTau"), + name = cms.string("GenVisTau"), doc = cms.string("gen hadronic taus "), singleton = cms.bool(False), # the number of entries is variable extension = cms.bool(False), # this is the main table for generator level hadronic tau decays variables = cms.PSet( - pt = Var("pt", float,precision=8), + pt = Var("pt", float,precision=8), phi = Var("phi", float,precision=8), - eta = Var("eta", float,precision=8), - pdgId = Var("pdgId", int, doc="PDG id"), - status = Var("status", int, doc="Hadronic tau decay mode. 0=OneProng0PiZero, 1=OneProng1PiZero, 2=OneProng2PiZero, 10=ThreeProng0PiZero, 11=ThreeProng1PiZero, 15=Other"), + eta = Var("eta", float,precision=8), + mass = Var("mass", float,precision=8), + charge = Var("charge", int), + status = Var("status", int, doc="Hadronic tau decay mode. 0=OneProng0PiZero, 1=OneProng1PiZero, 2=OneProng2PiZero, 10=ThreeProng0PiZero, 11=ThreeProng1PiZero, 15=Other"), genPartIdxMother = Var("?numberOfMothers>0?motherRef(0).key():-1", int, doc="index of the mother particle"), ) ) diff --git a/PhysicsTools/NanoAOD/python/triggerObjects_cff.py b/PhysicsTools/NanoAOD/python/triggerObjects_cff.py index d1e75d9cd67da..2d30df7c6e512 100644 --- a/PhysicsTools/NanoAOD/python/triggerObjects_cff.py +++ b/PhysicsTools/NanoAOD/python/triggerObjects_cff.py @@ -44,7 +44,7 @@ ), cms.PSet( name = cms.string("Tau"), - id = cms.int32(14), + id = cms.int32(15), sel = cms.string("type(84) && pt > 5 && coll('hltPFTaus')"), l1seed = cms.string("type(-100) && coll('hltGtStage2Digis:Tau')"), l1deltaR = cms.double(0.3), l2seed = cms.string("type(84) && coll('hltL2TauJetsL1IsoTauSeeded')"), l2deltaR = cms.double(0.3), diff --git a/PhysicsTools/NanoAOD/test/dqmQualityTests.xml b/PhysicsTools/NanoAOD/test/dqmQualityTests.xml new file mode 100644 index 0000000000000..969bc6796567b --- /dev/null +++ b/PhysicsTools/NanoAOD/test/dqmQualityTests.xml @@ -0,0 +1,17 @@ + + + + Comp2RefEqualH + 0 + 0.30 + 0.70 + + + + equalToRef + + + equalToRef + + + diff --git a/PhysicsTools/NanoAOD/test/inspectNanoFile.py b/PhysicsTools/NanoAOD/test/inspectNanoFile.py new file mode 100755 index 0000000000000..a985f6d63afc7 --- /dev/null +++ b/PhysicsTools/NanoAOD/test/inspectNanoFile.py @@ -0,0 +1,332 @@ +#!/usr/bin/env python + +import sys, os.path, json +from collections import defaultdict +import ROOT +ROOT.PyConfig.IgnoreCommandLineOptions = True +ROOT.gROOT.SetBatch(True) + + +class FileData: + def __init__(self,data): + self._json = data + for k,v in data.iteritems(): + setattr(self,k,v) + self.Events = self.trees["Events"] + self.nevents = self.Events["entries"] + +class Branch: + def __init__(self, tree, branch): + self.tree = tree + self.branch = branch + self.name = branch.GetName() + self.doc = branch.GetTitle() + self.tot = branch.GetZipBytes()/1024.0 + self.entries = None; + self.single = True + self.kind = "Unknown" + if branch.GetNleaves() != 1: + sys.stderr.write("Cannot parse branch '%s' in tree %s (%d leaves)\n", tree.GetName(), branch.GetName(), branch.GetNleaves()) + return + self.leaf = branch.FindLeaf(branch.GetName()) + if not self.leaf: + sys.stderr.write("Cannot parse branch '%s' in tree %s (no leaf)\n", tree.GetName(), branch.GetName()) + return + self.kind = self.leaf.GetTypeName() + if "Idx" in self.name: + self.kind+="(index to %s)"%((self.name[self.name.find("_")+1:self.name.find("Idx")]).title()) + if self.leaf.GetLen() == 0 and self.leaf.GetLeafCount() != None: + self.single = False + self.counter = self.leaf.GetLeafCount().GetName() + def toJSON(self): + return ( self.name, dict(name = self.name, doc = self.doc, tot=self.tot, entries=self.entries, single=self.single, kind=self.kind, counter = getattr(self,'counter','')) ) + +class BranchGroup: + def __init__(self, name): + self.name = name + self.tot = 0 + self.entries = None; + self.subs = [] + self.kind = None + self.doc = '' + def append(self, sub): + self.subs.append(sub) + self.tot += sub.tot + if not self.doc: self.doc = sub.doc + def getKind(self): + if self.kind: return self.kind + if len(self.subs) == 1: + if self.subs[0].single: self.kind = "Variable" + else: + self.kind = "Vector" + self.counter = self.subs[0].counter + else: + allsingles, commonCounter = True, True + counter = None + for s in self.subs: + if not s.single: + allsingles = False + if counter == None: counter = s.counter + elif counter != s.counter: + commonCounter = False + if allsingles: + self.kind = "Singleton" + elif commonCounter: + self.kind = "Collection" + self.counter = counter + else: + self.kind = "ItsComplicated" + return self.kind + def toJSON(self): + return (self.name, dict(name = self.name, doc = self.doc, kind = self.kind, tot = self.tot, entries = self.entries, subs = [s.name for s in self.subs])) + + +def inspectRootFile(infile): + if not os.path.isfile(infile): raise RuntimeError + filesize = os.path.getsize(infile)/1024.0 + tfile = ROOT.TFile.Open(infile) + trees = {} + for treeName in "Events", "Runs", "Lumis": + toplevelDoc={} + tree = tfile.Get(treeName) + entries = tree.GetEntries() + trees[treeName] = tree + branchList = tree.GetListOfBranches() + allbranches = [ Branch(tree,branchList.At(i)) for i in xrange(branchList.GetSize()) ] + branchmap = dict((b.name,b) for b in allbranches) + branchgroups = {} + # make list of counters and countees + counters = defaultdict(list) + for b in allbranches: + if not b.single: + counters[b.counter].append(b.name) + else: + b.entries = entries + c1 = ROOT.TCanvas("c1","c1") + for counter,countees in counters.iteritems(): + n = tree.Draw(counter+">>htemp") + if n != 0: + htemp = ROOT.gROOT.FindObject("htemp") + n = htemp.GetEntries() * htemp.GetMean() + htemp.Delete() + branchmap[counter].entries = entries + for c in countees: + br = branchmap[c] + br.entries = n + # now we start to create branch groups + for b in allbranches: + if b.name in counters: + if len(b.doc) > 0: + toplevelDoc[b.name[1:]]=b.doc + continue # skip counters + if "_" in b.name: + head, tail = b.name.split("_",1) + else: + head = b.name + toplevelDoc[b.name]=b.doc + if head not in branchgroups: + branchgroups[head] = BranchGroup(head) + branchgroups[head].append(b) + for bg in branchgroups.itervalues(): + if bg.name in toplevelDoc: + bg.doc = toplevelDoc[bg.name] + kind = bg.getKind() + bg.entries = bg.subs[0].entries + if kind == "Vector" or kind == "Collection": + bg.append(branchmap[bg.counter]) + elif kind == "ItsComplicated": + for counter in set(s.counter for s in bg.subs if not s.single): + bg.append(branchmap[counter]) + allsize_c = sum(b.tot for b in allbranches) + allsize = sum(b.tot for b in branchgroups.itervalues()) + if abs(allsize_c - allsize) > 1e-6*(allsize_c+allsize): + sys.stderr.write("Total size mismatch for tree %s: %10.4f kb vs %10.4f kb\n" % (treeName, allsize, allsize_c)) + trees[treeName] = dict( + entries = entries, + allsize = allsize, + branches = dict(b.toJSON() for b in allbranches), + branchgroups = dict(bg.toJSON() for bg in branchgroups.itervalues()), + ) + c1.Close() + break # only Event tree for now + tfile.Close() + return dict(filename = os.path.basename(infile), filesize = filesize, trees = trees) + +def makeSurvey(treeName, treeData): + allsize = treeData['allsize'] + entries = treeData['entries'] + survey = list(treeData['branchgroups'].itervalues()) + survey.sort(key = lambda bg : - bg['tot']) + scriptdata = [] + runningtotal = 0 + unit = treeName[:-1].lower() + for s in survey: + if s['tot'] < 0.01*allsize: + tag = "Others
Size: %.0f b/%s (%.1f%%)" % ((allsize - runningtotal)/entries*1024, unit, (allsize-runningtotal)/allsize*100) + scriptdata.append( "{ 'label':'others', 'tag':'top', 'size':%s, 'tip':'%s' }" % ((allsize-runningtotal)/entries, tag) ) + break + else: + tag = "%s
" % (s['name'],s['name']); + tag += "Size: %.0f b/%s (%.1f%%)" % (s['tot']/entries*1024, unit, s['tot']/allsize*100); + if (s['kind'] in ("Vector","Collection")) and s['entries'] > 0: + tag += "
Items/%s: %.1f, %.0f b/item" %(unit, float(s['entries'])/entries, s['tot']/s['entries']*1024); + scriptdata.append( "{ 'label':'%s', 'tag':'%s', 'size':%s, 'tip':'%s' }" % ( s['name'], s['name'], s['tot']/entries, tag) ) + runningtotal += s['tot'] + return (survey, "\n,\t".join(scriptdata)) + +def writeSizeReport(fileData, stream): + filename = fileData.filename + filesize = fileData.filesize + events = fileData.nevents + survey, scriptdata = makeSurvey("Events", filedata.Events) + title = "%s (%.3f Mb, %d events, %.2f kb/event)" % (filename, filesize/1024.0, events, filesize/events) + stream.write(""" + + + {title} + + + + + + + + +

{title}

+ [No canvas support] + +

Event data

+ + """); + stream.write("\n"); + grandtotal = filedata.Events['allsize']; runningtotal = 0 + for s in survey: + stream.write("" % (s['doc'],s['name'],s['name'],s['kind'].lower(),len(s['subs']))) + stream.write("" % (s['entries']/events, s['tot']/events, s['tot']/s['entries']*1024 if s['entries'] else 0)) + stream.write("" % (s['tot']/grandtotal*200,10)) + stream.write("" % ( s['tot']/grandtotal * 100.0)) + stream.write("" % ( (runningtotal+s['tot'])/grandtotal * 100.0)) + stream.write("" % ( (grandtotal-runningtotal)/grandtotal * 100.0)) + stream.write("\n") + runningtotal += s['tot']; + + # all known data + stream.write("") + stream.write("" % (grandtotal/events)) + stream.write("" % (grandtotal/filesize*100.0)) + stream.write("\n") + + # other, unknown overhead + stream.write("") + stream.write("" % ( (filesize-grandtotal)/events)) + stream.write("" % ( (filesize-grandtotal)/filesize * 100, 10 )) + stream.write("" % ( (filesize-grandtotal)/filesize * 100.0 )) + stream.write("\n") + + # all file + stream.write("") + stream.write("" % (filesize/events)) + stream.write("\n") + + stream.write(""" +
" + "".join([ "collection", "kind", "vars", "items/evt", "kb/evt", "b/item", "plot", "%" ]) + "cumulative %
%s%s%d%.2f%.3f%.1f%.1f%%%.1f%%%.1f%%
All Event data   %.2f " % ( grandtotal/filesize*100.0)) + stream.write("%.1f%%a
Non per-event data or overhead   %.2f %.1f%%a
File size   %.2f   
+ Note: size percentages of individual event products are relative to the total size of Event data only.
+ Percentages with a are instead relative to the full file size. +

Events detail

+ """) + for s in sorted(survey, key = lambda s : s['name']): + stream.write("

%s (%.1f items/evt, %.3f kb/evt) [back to top]

" % (s['name'], s['name'], s['name'], s['entries']/events, s['tot']/events)) + stream.write("\n") + stream.write("\n") + subs = [ fileData.Events['branches'][b] for b in s['subs'] ] + for b in sorted(subs, key = lambda s : - s['tot']): + stream.write("" % (b['doc'],b['name'], b['kind'], b['tot']/events*1024, b['tot']/s['entries']*1024 if s['entries'] else 0)) + stream.write("" % ( b['tot']/s['tot']*200, 10 )) + stream.write("" % (b['tot']/s['tot'] * 100.0)) + stream.write("\n") + stream.write("
" + "".join( [ "branch", "kind", "b/event", "b/item", "plot", "%" ]) + "
%s%s%.1f%.1f%.1f%%
\n") + stream.write(""" + + """) + +def writeDocReport(fileData, stream): + stream.write( """ + + + Documentation for {filename} + + + +

Content

+ + """.format(filename=fileData.filename)) + stream.write( "\n" ) + groups = fileData.Events['branchgroups'].values() + groups.sort(key = lambda s : s['name']) + for s in groups: + stream.write( "\n" % (s['name'],s['name'],s['doc']) ) + stream.write( "
CollectionDescription
%s%s
\n\n

Events detail

\n" ) + for s in groups: + stream.write( "

%s [back to top]

\n" % (s['name'], s['name'], s['name']) ) + stream.write( "\n" ) + stream.write( "\n" ) + subs = [ fileData.Events['branches'][b] for b in s['subs'] ] + for b in sorted(subs, key = lambda s : s['name']): + stream.write( "" % (b['name'], b['kind'], b['doc']) ) + stream.write( "\n" ) + stream.write( "
Object propertyTypeDescription
%s%s%s
\n" ) + stream.write( """ + + """ ) + +def _maybeOpen(filename): + return open(filename, 'w') if filename != "-" else sys.stdout + +if __name__ == '__main__': + from optparse import OptionParser + parser = OptionParser(usage="%prog [options] inputFile") + parser.add_option("-j", "--json", dest="json", type="string", default=None, help="Write out json file") + parser.add_option("-d", "--doc", dest="doc", type="string", default=None, help="Write out html doc") + parser.add_option("-s", "--size", dest="size", type="string", default=None, help="Write out html size report") + (options, args) = parser.parse_args() + if len(args) != 1: raise RuntimeError("Please specify one input file") + + if args[0].endswith(".root"): + filedata = FileData(inspectRootFile(args[0])) + elif args[0].endswith(".json"): + filedata = FileData(json.load(open(args[0],'r'))) + else: raise RuntimeError("Input file %s is not a root or json file" % args[0]) + + if options.json: + json.dump(filedata._json, _maybeOpen(options.json), indent=4) + sys.stderr.write("JSON output saved to %s\n" % options.json) + if options.doc: + writeDocReport(filedata, _maybeOpen(options.doc)) + sys.stderr.write("HTML documentation saved to %s\n" % options.doc) + if options.size: + writeSizeReport(filedata, _maybeOpen(options.size)) + sys.stderr.write("HTML size report saved to %s\n" % options.size) diff --git a/PhysicsTools/NanoAOD/test/prepareDQM.py b/PhysicsTools/NanoAOD/test/prepareDQM.py new file mode 100644 index 0000000000000..13064ee5e38ab --- /dev/null +++ b/PhysicsTools/NanoAOD/test/prepareDQM.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python + +import sys, os +from collections import defaultdict +from math import ceil, pi, log +import ROOT +ROOT.PyConfig.IgnoreCommandLineOptions = True +ROOT.gROOT.SetBatch(True) + +from PhysicsTools.NanoAOD.nanoDQM_cfi import nanoDQM, NoPlot, Plot1D, Count1D, shortDump + +from optparse import OptionParser +parser = OptionParser(usage="%prog [options] inputFile") +parser.add_option("-u", dest="update", action="store_true", default=False, help="Update nanoDQM_cfi.py directly") +parser.add_option("-d", dest="delete", action="store_true", default=False, help="Delete lines corresponding to missing plots, instead of commenting them out") +parser.add_option("-q", dest="verbose", action="store_false", default=True, help="Quiet mode") +parser.add_option("-o", dest="out", type="string", default="newDQM.py", help="Output file (unless -u is used)") +(options, args) = parser.parse_args() +if options.update: options.out = "%s/src/PhysicsTools/NanoAOD/python/nanoDQM_cfi.py" % os.environ["CMSSW_BASE"] + +infile = args[0] +if not os.path.isfile(infile): raise RuntimeError + +class Branch: + def __init__(self, branch): + self.name = branch.GetName() + self.title = branch.GetTitle() + self.counter = None + self.good = True + if branch.GetNleaves() != 1: + sys.stderr.write("Cannot parse branch '%s' in tree %s (%d leaves)\n", tree.GetName(), branch.GetName(), branch.GetNleaves()) + self.good = False + return + self.leaf = branch.FindLeaf(branch.GetName()) + if not self.leaf: + sys.stderr.write("Cannot parse branch '%s' in tree %s (no leaf)\n", tree.GetName(), branch.GetName()) + self.good = False + return + self.kind = self.leaf.GetTypeName() + if self.leaf.GetLen() == 0 and self.leaf.GetLeafCount() != None: + self.counter = self.leaf.GetLeafCount().GetName() + +class BranchGroup: + def __init__(self, name): + self.name = name + self.subs = [] + def append(self, sub): + self.subs.append(sub) + +tfile = ROOT.TFile.Open(infile) +tree = tfile.Get("Events") +allbranches = [ Branch(b) for b in tree.GetListOfBranches() ] +allbranches = [ b for b in allbranches if b.good ] +branchmap = dict((b.name,b) for b in allbranches ) +branchgroups = defaultdict(dict) +iscounter = {} +for b in allbranches: + if b.counter: iscounter[b.counter] = True +for b in allbranches: + if b.name in iscounter: continue + if "_" in b.name: + head, tail = b.name.split("_",1) + if head == "HLT": continue # no monitoring for these + else: + head, tail = b.name, '' + branchgroups[head][tail] = b + if b.counter and ('@size' not in branchgroups[head]): + branchgroups[head]['@size'] = branchmap[b.counter] + +pyout = open(options.out, "w") +pyout.write("""# automatically generated by prepareDQM.py +import FWCore.ParameterSet.Config as cms +from PhysicsTools.NanoAOD.nanoDQM_tools_cff import * + +nanoDQM = cms.EDAnalyzer("NanoAODDQM", + vplots = cms.PSet( +"""); + +c1 = ROOT.TCanvas("c1","c1") +def smartRound(x): + if abs(x) < 1e-7: return 0 + if x < 0: return -smartRound(-x) + shift = pow(10,ceil(log(x,10))-1) + xu = x/shift; + if (xu > 30): xu = 5*ceil(xu/5) + else: xu = ceil(xu) + return xu*shift; +def autoPlot1D(name, col, branch): + if branch.kind == "Bool_t": + return Plot1D(name, col, 2, -0.5, 1.5) + xmin, xmax = tree.GetMinimum(branch.name), tree.GetMaximum(branch.name) + if col == "@size": + return Count1D(name, int(xmax+1 if xmax < 40 else 40), -0.5, xmax+0.5) + if branch.kind == "Int_t" and "Idx" in name: + return NoPlot(name) + if branch.kind != "Float_t": + xmin, xmax = map(int, (xmin,xmax)) + if xmax-xmin < 20: + return Plot1D(name, col, xmax-xmin+1, xmin-0.5, xmax+0.5) + elif name == "phi": + return Plot1D(name, col, 20, -pi, pi) + if xmin < 0 and xmax > 0: + xmin, xmax = min(xmin, -xmax), max(xmax, -xmin) # symmetrize + elif xmax > 0 and xmin/xmax < 0.03: + xmin = 0 + xmin, xmax = map(smartRound, (xmin,xmax)) + return Plot1D(name, col, 20, xmin, xmax) + +for head in sorted(branchgroups.iterkeys()): + pset = getattr(nanoDQM.vplots, head, None) + if not pset: + if options.verbose: print "%s " % head + continue + if options.verbose: print "%s" % head + vpset = pset.plots + allplots = [ (x.name.value(),x) for x in vpset ] + existing = set(x[0] for x in allplots) + found = set() + title = dict( (n,x.title.value()) for (n,x) in allplots if x.kind.value() != "none" and x.title.value() ) + for (t,branch) in sorted(branchgroups[head].iteritems()): + t_noat = t.replace("@","_") + found.add(t_noat) + if t_noat not in title: title[t_noat] = branch.title + if t_noat not in existing: allplots.append( (t_noat,autoPlot1D(t_noat,t,branch)) ) + # update titles + for k,v in allplots: + if k in title and title[k] and v.kind.value() != "none": v.title = title[k] + allplots.sort() + pyout.write(" %s = cms.PSet(\n" % head) + seldump = pset.sels.dumpPython().replace("\n","\n ") if len(pset.sels.parameterNames_()) else "cms.PSet()" + pyout.write(" sels = %s,\n" % seldump) + pyout.write(" plots = cms.VPSet(\n") + for k,v in allplots: + if k not in found and options.delete: continue + pyout.write(" %s %s,\n" % (" " if k in found else "#", shortDump(v))); + pyout.write(" )\n") + pyout.write(" ),\n") +pyout.write(" )\n)\n"); + diff --git a/PhysicsTools/NanoAOD/test/runtests.sh b/PhysicsTools/NanoAOD/test/runtests.sh index ba91908cf92af..8086690ee755b 100755 --- a/PhysicsTools/NanoAOD/test/runtests.sh +++ b/PhysicsTools/NanoAOD/test/runtests.sh @@ -6,6 +6,6 @@ function die { echo $1: status $2 ; exit $2; } #cmsDriver.py test80X -s NANO --mc --eventcontent NANOAODSIM --datatier NANO --filein /store/relval/CMSSW_8_0_0/RelValTTbar_13/MINIAODSIM/PU25ns_80X_mcRun2_asymptotic_v4-v1/10000/A65CD249-BFDA-E511-813A-0025905A6066.root --conditions auto:run2_mc -n 100 --era Run2_2016,run2_miniAOD_80XLegacy || die 'Failure using cmsdriver 80X' $? cmsDriver.py test92X -s NANO --mc --eventcontent NANOAODSIM --datatier NANOAODSIM --filein /store/relval/CMSSW_9_2_12/RelValTTbar_13/MINIAODSIM/PU25ns_92X_upgrade2017_realistic_v11-v1/00000/080E2624-F59D-E711-ACEE-0CC47A7C35A4.root --conditions auto:phase1_2017_realistic -n 100 --era Run2_2017,run2_nanoAOD_92X || die 'Failure using cmsdriver 92X' $? -cmsDriver.py test94X -s NANO --mc --eventcontent NANOAODSIM --datatier NANOAODSIM --filein /store/relval/CMSSW_9_4_0_pre1/RelValTTbar_13/MINIAODSIM/PU25ns_93X_mc2017_realistic_v3-v1/00000/92FD5642-509D-E711-ADAB-0025905B85C6.root --conditions auto:phase1_2017_realistic -n 100 --era Run2_2017 || die 'Failure using cmsdriver 94X' $? +cmsDriver.py test94X -s NANO --mc --eventcontent NANOAODSIM --datatier NANOAODSIM --filein /store/relval/CMSSW_9_4_0_pre3/RelValTTbar_13/MINIAODSIM/PU25ns_94X_mc2017_realistic_v4-v1/10000/52B94CC0-6FBB-E711-B577-0CC47A7C35F8.root --conditions auto:phase1_2017_realistic -n 100 --era Run2_2017 || die 'Failure using cmsdriver 94X' $? diff --git a/PhysicsTools/NanoAOD/test/treeSize.py b/PhysicsTools/NanoAOD/test/treeSize.py deleted file mode 100644 index f23982861bb5e..0000000000000 --- a/PhysicsTools/NanoAOD/test/treeSize.py +++ /dev/null @@ -1,293 +0,0 @@ -#!/usr/bin/env python - -import sys, os.path -from collections import defaultdict -import ROOT -ROOT.PyConfig.IgnoreCommandLineOptions = True -ROOT.gROOT.SetBatch(True) - -## Tool to dig out information about the event size in NanoAOD -## -## Please run this giving as argument the root file, and redirecting the output on an HTML file -## Notes: -## - you must have a correctly initialized environment, and FWLite auto-loading with ROOT -## - you must put in the same folder of the html also these three files: -## http://cern.ch/gpetrucc/patsize.css -## http://cern.ch/gpetrucc/blue-dot.gif -## http://cern.ch/gpetrucc/red-dot.gif -## otherwise you will get an unreadable output file - -infile = sys.argv[1] -docMode= (sys.argv[2] == "doc") if len(sys.argv) >2 else False - -if not os.path.isfile(infile): raise RuntimeError -filesize = os.path.getsize(infile)/1024.0 -class Branch: - def __init__(self, tree, branch): - self.tree = tree - self.branch = branch - self.name = branch.GetName() - self.doc = branch.GetTitle() - self.tot = branch.GetZipBytes()/1024.0 - self.entries = None; - self.single = True - self.kind = "Unknown" - if branch.GetNleaves() != 1: - sys.stderr.write("Cannot parse branch '%s' in tree %s (%d leaves)\n", tree.GetName(), branch.GetName(), branch.GetNleaves()) - return - self.leaf = branch.FindLeaf(branch.GetName()) - if not self.leaf: - sys.stderr.write("Cannot parse branch '%s' in tree %s (no leaf)\n", tree.GetName(), branch.GetName()) - return - self.kind = self.leaf.GetTypeName() - if docMode and "Idx" in self.name: - self.kind+="(index to %s)"%((self.name[self.name.find("_")+1:self.name.find("Idx")]).title()) - if self.leaf.GetLen() == 0 and self.leaf.GetLeafCount() != None: - self.single = False - self.counter = self.leaf.GetLeafCount().GetName() - -class BranchGroup: - def __init__(self, name): - self.name = name - self.tot = 0 - self.entries = None; - self.subs = [] - self.kind = None - def append(self, sub): - self.subs.append(sub) - self.tot += sub.tot - def getKind(self): - if self.kind: return self.kind - if len(self.subs) == 1: - if self.subs[0].single: self.kind = "Variable" - else: - self.kind = "Vector" - self.counter = self.subs[0].counter - else: - allsingles, commonCounter = True, True - counter = None - for s in self.subs: - if not s.single: - allsingles = False - if counter == None: counter = s.counter - elif counter != s.counter: - commonCounter = False - if allsingles: - self.kind = "Singleton" - elif commonCounter: - self.kind = "Collection" - self.counter = counter - else: - self.kind = "ItsComplicated" - return self.kind -tfile = ROOT.TFile.Open(infile) -trees = {} -branches = {} -toplevelDoc={} -for treeName in "Events", "Runs", "Lumis": - tree = tfile.Get(treeName) - entries = tree.GetEntries() - trees[treeName] = tree - branchList = tree.GetListOfBranches() - allbranches = [ Branch(tree,branchList.At(i)) for i in xrange(branchList.GetSize()) ] - branchmap = dict((b.name,b) for b in allbranches) - branchgroups = {} - # make list of counters and countees - counters = defaultdict(list) - for b in allbranches: - if not b.single: - counters[b.counter].append(b.name) - else: - b.entries = entries - c1 = ROOT.TCanvas("c1","c1") - for counter,countees in counters.iteritems(): - n = tree.Draw(counter+">>htemp") - if n != 0: - htemp = ROOT.gROOT.FindObject("htemp") - n = htemp.GetEntries() * htemp.GetMean() - htemp.Delete() - branchmap[counter]._entries = entries - for c in countees: - br = branchmap[c] - br.entries = n - # now we start to create branch groups - for b in allbranches: - if b.name in counters: - if len(b.doc) > 0: - toplevelDoc[b.name[1:]]=b.doc - continue # skip counters - if "_" in b.name: - head, tail = b.name.split("_",1) - else: - head = b.name - toplevelDoc[b.name]=b.doc - - if head not in branchgroups: - branchgroups[head] = BranchGroup(head) - branchgroups[head].append(b) - for bg in branchgroups.itervalues(): - kind = bg.getKind() - bg.entries = bg.subs[0].entries - if kind == "Vector" or kind == "Collection": - bg.append(branchmap[bg.counter]) - elif kind == "ItsComplicated": - for counter in set(s.counter for s in bg.subs if not s.single): - bg.append(branchmap[counter]) - allsize_c = sum(b.tot for b in allbranches) - allsize = sum(b.tot for b in branchgroups.itervalues()) - if abs(allsize_c - allsize) > 1e-6*(allsize_c+allsize): - sys.stderr.write("Total size mismatch for tree %s: %10.4f kb vs %10.4f kb\n" % (treeName, allsize, allsize_c)) - tree.allsize = allsize - tree.entries = entries - tree.survey = list(branchgroups.itervalues()) - tree.survey.sort(key = lambda bg : - bg.tot) - scriptdata = [] - runningtotal = 0 - unit = treeName[:-1].lower() - for s in tree.survey: - if s.tot < 0.01*allsize: - tag = "Others
Size: %.0f b/%s (%.1f%%)" % ((allsize - runningtotal)/entries*1024, unit, (allsize-runningtotal)/allsize*100) - scriptdata.append( "{ 'label':'others', 'tag':'top', 'size':%s, 'tip':'%s' }" % ((allsize-runningtotal)/entries, tag) ) - break - else: - tag = "%s
" % (s.name, s.name); - tag += "Size: %.0f b/%s (%.1f%%)" % (s.tot/entries*1024, unit, s.tot/allsize*100); - if (s.getKind() in ("Vector","Collection")): - tag += "
Items/%s: %.1f, %.0f b/item" %(unit, float(s.entries)/entries, s.tot/s.entries*1024); - scriptdata.append( "{ 'label':'%s', 'tag':'%s', 'size':%s, 'tip':'%s' }" % ( s.name, s.name, s.tot/entries, tag) ) - runningtotal += s.tot - tree.scriptdata = "\n,\t".join(scriptdata) - break # let's do only Events for now - -events = trees["Events"].entries -sizeline = "%.3f Mb, %d events, %.2f kb/event" % ( filesize/1024.0, events, filesize/events) -if not docMode: - print """ - - - {filename} : size ({allsize}) - - - - - - - - -

Summary ({allsize})

- [No canvas support] - -

Event data

- - """ - print ""; - grandtotal = trees["Events"].allsize; runningtotal = 0 - for s in trees["Events"].survey: - print "" % ((toplevelDoc[s.name] if s.name in toplevelDoc else ""),s.name,s.name,s.getKind().lower(),len(s.subs)), - print "" % (s.entries/events, s.tot/events, s.tot/s.entries*1024 if s.entries else 0), - print "" % (s.tot/grandtotal*200,10), - print "" % ( s.tot/grandtotal * 100.0), - print "" % ( (runningtotal+s.tot)/grandtotal * 100.0), - print "" % ( (grandtotal-runningtotal)/grandtotal * 100.0), - print ""; - runningtotal += s.tot; - - # all known data - print "", - print "" % (grandtotal/events), - print "" % (grandtotal/filesize*100.0), - print ""; - - # other, unknown overhead - print "", - print "" % ( (filesize-grandtotal)/events), - print "" % ( (filesize-grandtotal)/filesize * 100, 10 ), - print "" % ( (filesize-grandtotal)/filesize * 100.0 ), - print "" - - # all file - print "", - print "" % (filesize/events), - print "\n"; - - print """ -
" + "".join([ "collection", "kind", "vars", "items/evt", "kb/evt", "b/item", "plot", "%" ]) + "cumulative %
%s%s%d%.2f%.3f%.1f%.1f%%%.1f%%%.1f%%
All Event data   %.2f " % ( grandtotal/filesize*100.0), - print "%.1f%%a
Non per-event data or overhead   %.2f %.1f%%a
File size   %.2f   
- Note: size percentages of individual event products are relative to the total size of Event data only.
- Percentages with a are instead relative to the full file size. -

Events detail

- """ - for s in sorted(trees["Events"].survey, key = lambda s : s.name): - print "

%s (%.1f items/evt, %.3f kb/evt)

" % (s.name, s.name, s.name, s.entries/events, s.tot/events) - print "" - print "" - for b in sorted(s.subs, key = lambda s : - s.tot): - print "" % (b.doc,b.name, b.kind, b.tot/events*1024, b.tot/s.entries*1024), - print "" % ( b.tot/s.tot*200, 10 ), - print "" % (b.tot/s.tot * 100.0), - print "" - print "
" + "".join( [ "branch", "kind", "b/event", "b/item", "plot", "%" ]) + "
%s%s%.1f%.1f%.1f%%
" - print """ - - """ -else: - print """ - - - Documentation for {filename} - - - - - - - - -

Content

- - """ - print "" - grandtotal = trees["Events"].allsize; runningtotal = 0 - for s in trees["Events"].survey: - print "" % (s.name,s.name,(toplevelDoc[s.name] if s.name in toplevelDoc else "no documentation available")) - print "" - runningtotal += s.tot; - - print """ -
CollectionDescription
%s%s
-

Events detail

- """ - for s in sorted(trees["Events"].survey, key = lambda s : s.name): - print "

%s (%.1f items/evt, %.3f kb/evt)

" % (s.name, s.name, s.name, s.entries/events, s.tot/events) - print "" - print "" - for b in sorted(s.subs, key = lambda s : - s.tot): - print "" % (b.name, b.kind, b.doc), - print "" - print "
Object propertyTypeDescription
%s%s%s
" - print """ - - """ diff --git a/PhysicsTools/PatAlgos/plugins/LeptonUpdater.cc b/PhysicsTools/PatAlgos/plugins/LeptonUpdater.cc index 14a65009304b7..ba8a8c7f5825c 100644 --- a/PhysicsTools/PatAlgos/plugins/LeptonUpdater.cc +++ b/PhysicsTools/PatAlgos/plugins/LeptonUpdater.cc @@ -4,10 +4,12 @@ #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" #include "FWCore/ParameterSet/interface/ParameterSetDescription.h" #include "FWCore/Utilities/interface/InputTag.h" +#include "PhysicsTools/PatUtils/interface/MiniIsolation.h" #include "DataFormats/Common/interface/View.h" #include "DataFormats/PatCandidates/interface/Muon.h" #include "DataFormats/PatCandidates/interface/Electron.h" +#include "DataFormats/PatCandidates/interface/PackedCandidate.h" namespace pat { @@ -19,8 +21,14 @@ namespace pat { explicit LeptonUpdater(const edm::ParameterSet & iConfig) : src_(consumes>(iConfig.getParameter("src"))), - vertices_(consumes>(iConfig.getParameter("vertices"))) + vertices_(consumes>(iConfig.getParameter("vertices"))), + computeMiniIso_(iConfig.getParameter("computeMiniIso")) { + //for mini-isolation calculation + if (computeMiniIso_) { + readMiniIsoParams(iConfig); + pcToken_ = consumes(iConfig.getParameter("pfCandsForMiniIso")); + } produces>(); } @@ -32,16 +40,33 @@ namespace pat { edm::ParameterSetDescription desc; desc.add("src")->setComment("Lepton collection"); desc.add("vertices")->setComment("Vertex collection"); - if (typeid(T) == typeid(pat::Muon)) descriptions.add("muonsUpdated", desc); - else if (typeid(T) == typeid(pat::Electron)) descriptions.add("electronsUpdated", desc); + desc.add("computeMiniIso", false)->setComment("Recompute miniIsolation"); + desc.addOptional("pfCandsForMiniIso", edm::InputTag("packedPFCandidates"))->setComment("PackedCandidate collection used for miniIso"); + if (typeid(T) == typeid(pat::Muon)) { + desc.addOptional>("miniIsoParams")->setComment("Parameters used for miniIso (as in PATMuonProducer)"); + descriptions.add("muonsUpdated", desc); + } else if (typeid(T) == typeid(pat::Electron)) { + desc.addOptional>("miniIsoParamsB")->setComment("Parameters used for miniIso in the barrel (as in PATElectronProducer)"); + desc.addOptional>("miniIsoParamsE")->setComment("Parameters used for miniIso in the endcap (as in PATElectronProducer)"); + descriptions.add("electronsUpdated", desc); + } } void setDZ(T & lep, const reco::Vertex & pv) const {} + + void readMiniIsoParams(const edm::ParameterSet & iConfig) { + miniIsoParams_[0] = iConfig.getParameter >("miniIsoParams"); + if(miniIsoParams_[0].size() != 9) throw cms::Exception("ParameterError", "miniIsoParams must have exactly 9 elements.\n"); + } + const std::vector & miniIsoParams(const T &lep) const { return miniIsoParams_[0]; } private: // configurables edm::EDGetTokenT> src_; edm::EDGetTokenT> vertices_; + bool computeMiniIso_; + std::vector miniIsoParams_[2]; + edm::EDGetTokenT pcToken_; }; // must do the specialization within the namespace otherwise gcc complains @@ -58,6 +83,18 @@ namespace pat { aMuon.setDB( track->dz(pv.position()), std::hypot(track->dzError(), pv.zError()), pat::Muon::PVDZ ); } + template<> + void LeptonUpdater::readMiniIsoParams(const edm::ParameterSet & iConfig) { + miniIsoParams_[0] = iConfig.getParameter >("miniIsoParamsB"); + miniIsoParams_[1] = iConfig.getParameter >("miniIsoParamsE"); + if(miniIsoParams_[0].size() != 9) throw cms::Exception("ParameterError", "miniIsoParamsB must have exactly 9 elements.\n"); + if(miniIsoParams_[1].size() != 9) throw cms::Exception("ParameterError", "miniIsoParamsE must have exactly 9 elements.\n"); + } + template<> + const std::vector & LeptonUpdater::miniIsoParams(const pat::Electron &lep) const { + return miniIsoParams_[lep.isEE()]; + } + } // namespace template @@ -69,11 +106,22 @@ void pat::LeptonUpdater::produce(edm::StreamID, edm::Event& iEvent, edm::Even iEvent.getByToken(vertices_, vertices); const reco::Vertex & pv = vertices->front(); + edm::Handle pc; + if(computeMiniIso_) iEvent.getByToken(pcToken_, pc); + std::unique_ptr> out(new std::vector(*src)); for (unsigned int i = 0, n = src->size(); i < n; ++i) { T & lep = (*out)[i]; setDZ(lep, pv); + if (computeMiniIso_) { + const auto & params = miniIsoParams(lep); + pat::PFIsolation miniiso = pat::getMiniPFIsolation(pc.product(), lep.p4(), + params[0], params[1], params[2], + params[3], params[4], params[5], + params[6], params[7], params[8]); + lep.setMiniPFIsolation(miniiso); + } } iEvent.put(std::move(out));