File indexing completed on 2024-04-06 12:23:42
0001 #include "FWCore/Framework/interface/Frameworkfwd.h"
0002 #include "FWCore/Framework/interface/MakerMacros.h"
0003 #include "FWCore/Utilities/interface/InputTag.h"
0004 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0005 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0006
0007 #include "FWCore/ParameterSet/interface/allowedValues.h"
0008 #include "DQMServices/Core/interface/DQMStore.h"
0009 #include "DQMServices/Core/interface/DQMEDAnalyzer.h"
0010 #include "FWCore/Framework/interface/Event.h"
0011 #include "DataFormats/NanoAOD/interface/FlatTable.h"
0012 #include "CommonTools/Utils/interface/StringCutObjectSelector.h"
0013
0014 #include "FWCore/Framework/interface/GetterOfProducts.h"
0015 #include "FWCore/Framework/interface/ProcessMatch.h"
0016
0017 #include <memory>
0018 #include <limits>
0019 #include <numeric>
0020 #include <regex>
0021 #include <sstream>
0022 #include <type_traits>
0023
0024 namespace {
0025 bool notANumber(std::string const &iValue) {
0026 auto find = iValue.find_first_not_of("0123456789");
0027 return find != std::string::npos;
0028 }
0029 bool notRowMethod(std::string const &iValue) { return iValue != "row" and iValue != "table"; }
0030
0031 bool notAFunction(std::string const &iSuffix) { return (iSuffix.empty() or iSuffix[0] != '('); }
0032 std::string replaceStringsToColumGets(const std::string &expr) {
0033 std::regex token("\\w+");
0034 std::sregex_iterator tbegin(expr.begin(), expr.end(), token), tend;
0035 if (tbegin == tend)
0036 return expr;
0037 std::stringstream out;
0038 std::sregex_iterator last;
0039 for (std::sregex_iterator i = tbegin; i != tend; last = i, ++i) {
0040 const std::smatch &match = *i;
0041 out << match.prefix().str();
0042 if (notAFunction(i->suffix().str()) and notANumber(match.str()) and notRowMethod(match.str())) {
0043 out << "getAnyValue(\"" << match.str() << "\")";
0044 } else {
0045 out << match.str();
0046 }
0047 }
0048 out << last->suffix().str();
0049 return out.str();
0050 };
0051 }
0052
0053 class NanoAODDQM : public DQMEDAnalyzer {
0054 public:
0055 typedef nanoaod::FlatTable FlatTable;
0056
0057 NanoAODDQM(const edm::ParameterSet &);
0058 void analyze(const edm::Event &, const edm::EventSetup &) override;
0059
0060 static void fillDescriptions(edm::ConfigurationDescriptions &descriptions);
0061
0062 protected:
0063
0064 void bookHistograms(DQMStore::IBooker &, edm::Run const &, edm::EventSetup const &) override;
0065
0066 private:
0067 class Plot {
0068 public:
0069 Plot(MonitorElement *me) : plot_(me) {}
0070 virtual ~Plot() {}
0071 virtual void fill(const FlatTable &table, const std::vector<bool> &rowsel) = 0;
0072 const std::string &name() const { return plot_->getName(); }
0073
0074 protected:
0075 MonitorElement *plot_;
0076 };
0077 class Count1D : public Plot {
0078 public:
0079 Count1D(DQMStore::IBooker &booker, const edm::ParameterSet &cfg)
0080 : Plot(booker.book1D(cfg.getParameter<std::string>("name"),
0081 cfg.getParameter<std::string>("title"),
0082 cfg.getParameter<uint32_t>("nbins"),
0083 cfg.getParameter<double>("min"),
0084 cfg.getParameter<double>("max"))) {}
0085 ~Count1D() override {}
0086 void fill(const FlatTable &table, const std::vector<bool> &rowsel) override {
0087 plot_->Fill(std::accumulate(rowsel.begin(), rowsel.end(), 0u));
0088 }
0089 };
0090
0091 class Plot1D : public Plot {
0092 public:
0093 Plot1D(DQMStore::IBooker &booker, const edm::ParameterSet &cfg)
0094 : Plot(booker.book1D(cfg.getParameter<std::string>("name"),
0095 cfg.getParameter<std::string>("title"),
0096 cfg.getParameter<uint32_t>("nbins"),
0097 cfg.getParameter<double>("min"),
0098 cfg.getParameter<double>("max"))),
0099 col_(cfg.getParameter<std::string>("column")),
0100 bitset_(cfg.getParameter<bool>("bitset")) {}
0101 ~Plot1D() override {}
0102 void fill(const FlatTable &table, const std::vector<bool> &rowsel) override {
0103 int icol = table.columnIndex(col_);
0104 if (icol == -1)
0105 return;
0106 switch (table.columnType(icol)) {
0107 case FlatTable::ColumnType::UInt8:
0108 vfill<uint8_t>(table, icol, rowsel);
0109 break;
0110 case FlatTable::ColumnType::Int16:
0111 vfill<int16_t>(table, icol, rowsel);
0112 break;
0113 case FlatTable::ColumnType::UInt16:
0114 vfill<uint16_t>(table, icol, rowsel);
0115 break;
0116 case FlatTable::ColumnType::Int32:
0117 vfill<int32_t>(table, icol, rowsel);
0118 break;
0119 case FlatTable::ColumnType::UInt32:
0120 vfill<uint32_t>(table, icol, rowsel);
0121 break;
0122 case FlatTable::ColumnType::Bool:
0123 vfill<bool>(table, icol, rowsel);
0124 break;
0125 case FlatTable::ColumnType::Float:
0126 vfill<float>(table, icol, rowsel);
0127 break;
0128 case FlatTable::ColumnType::Double:
0129 vfill<double>(table, icol, rowsel);
0130 break;
0131 default:
0132 throw cms::Exception("LogicError", "Unsupported type");
0133 }
0134 }
0135
0136 protected:
0137 std::string col_;
0138 bool bitset_;
0139 template <typename T>
0140 void vfill(const FlatTable &table, int icol, const std::vector<bool> &rowsel) {
0141 const auto &data = table.columnData<T>(icol);
0142 for (unsigned int i = 0, n = data.size(); i < n; ++i) {
0143 if (rowsel[i]) {
0144 const T val = data[i];
0145 if constexpr (std::is_integral<T>::value) {
0146 if (bitset_) {
0147 for (unsigned int b = 0; b < std::numeric_limits<T>::digits; b++) {
0148 if ((val >> b) & 0b1)
0149 plot_->Fill(b);
0150 }
0151 } else {
0152 plot_->Fill(val);
0153 }
0154 } else {
0155 plot_->Fill(val);
0156 }
0157 }
0158 }
0159 }
0160 };
0161
0162 class Profile1D : public Plot {
0163 public:
0164 Profile1D(DQMStore::IBooker &booker, const edm::ParameterSet &cfg)
0165 : Plot(booker.bookProfile(cfg.getParameter<std::string>("name"),
0166 cfg.getParameter<std::string>("title"),
0167 cfg.getParameter<uint32_t>("nbins"),
0168 cfg.getParameter<double>("min"),
0169 cfg.getParameter<double>("max"),
0170 0.,
0171 0.,
0172 "")),
0173 ycol_(cfg.getParameter<std::string>("ycolumn")),
0174 xcol_(cfg.getParameter<std::string>("xcolumn")) {}
0175 ~Profile1D() override {}
0176 void fill(const FlatTable &table, const std::vector<bool> &rowsel) override {
0177 int icolx = table.columnIndex(xcol_);
0178 int icoly = table.columnIndex(ycol_);
0179 if (icolx == -1)
0180 throw cms::Exception("LogicError", "Missing " + xcol_);
0181 if (icoly == -1)
0182 throw cms::Exception("LogicError", "Missing " + ycol_);
0183 for (unsigned int irow = 0, n = table.size(); irow < n; ++irow) {
0184 if (rowsel[irow])
0185 plot_->Fill(table.getAnyValue(irow, icolx), table.getAnyValue(irow, icoly));
0186 }
0187 }
0188
0189 protected:
0190 std::string ycol_, xcol_;
0191 };
0192
0193 static std::unique_ptr<Plot> makePlot(DQMStore::IBooker &booker, const edm::ParameterSet &cfg) {
0194 const std::string &kind = cfg.getParameter<std::string>("kind");
0195 if (kind == "none")
0196 return nullptr;
0197 if (kind == "count1d")
0198 return std::make_unique<Count1D>(booker, cfg);
0199 if (kind == "hist1d")
0200 return std::make_unique<Plot1D>(booker, cfg);
0201 if (kind == "prof1d")
0202 return std::make_unique<Profile1D>(booker, cfg);
0203 throw cms::Exception("Configuration", "Unsupported plot kind '" + kind + "'");
0204 }
0205
0206 struct SelGroupConfig {
0207 typedef StringCutObjectSelector<FlatTable::RowView> Selector;
0208 std::string name;
0209 std::string cutstr;
0210 std::unique_ptr<StringCutObjectSelector<FlatTable::RowView>> cutptr;
0211 std::vector<std::unique_ptr<Plot>> plots;
0212 SelGroupConfig() : name(), cutstr(), cutptr(), plots() {}
0213 SelGroupConfig(const std::string &nam, const std::string &cut) : name(nam), cutstr(cut), cutptr(), plots() {
0214 if (not nullCut()) {
0215 cutptr = std::make_unique<Selector>(replaceStringsToColumGets(cutstr));
0216 }
0217 }
0218 bool nullCut() const { return cutstr.empty(); }
0219 void fillSel(const FlatTable &table, std::vector<bool> &out) {
0220 out.resize(table.size());
0221 if (nullCut()) {
0222 std::fill(out.begin(), out.end(), true);
0223 } else {
0224 for (unsigned int i = 0, n = table.size(); i < n; ++i) {
0225 out[i] = (*cutptr)(table.row(i));
0226 }
0227 }
0228 }
0229 };
0230 struct GroupConfig {
0231 std::vector<edm::ParameterSet> plotPSets;
0232 std::vector<SelGroupConfig> selGroups;
0233 };
0234 std::map<std::string, GroupConfig> groups_;
0235 edm::GetterOfProducts<FlatTable> getterOfProducts_;
0236 };
0237
0238 NanoAODDQM::NanoAODDQM(const edm::ParameterSet &iConfig) : getterOfProducts_(edm::ProcessMatch("*"), this) {
0239 const edm::ParameterSet &vplots = iConfig.getParameter<edm::ParameterSet>("vplots");
0240 for (const std::string &name : vplots.getParameterNamesForType<edm::ParameterSet>()) {
0241 auto &group = groups_[name];
0242 const auto &pset = vplots.getParameter<edm::ParameterSet>(name);
0243 group.plotPSets = pset.getParameter<std::vector<edm::ParameterSet>>("plots");
0244 group.selGroups.emplace_back();
0245 const auto &cuts = pset.getParameter<edm::ParameterSet>("sels");
0246 for (const std::string &cname : cuts.getParameterNamesForType<std::string>()) {
0247 group.selGroups.emplace_back(cname, cuts.getParameter<std::string>(cname));
0248 }
0249 }
0250 callWhenNewProductsRegistered(getterOfProducts_);
0251 }
0252
0253 void NanoAODDQM::fillDescriptions(edm::ConfigurationDescriptions &descriptions) {
0254 edm::ParameterSetDescription desc;
0255
0256 edm::ParameterSetDescription sels;
0257 sels.setComment("a paramerter set to define the selections to be made from the table row");
0258 sels.addNode(edm::ParameterWildcard<std::string>("*", edm::RequireZeroOrMore, true));
0259
0260 edm::ParameterDescription<std::string> name("name", true, edm::Comment(""));
0261 edm::ParameterDescription<std::string> title("title", true, edm::Comment("title of the plot"));
0262 edm::ParameterDescription<uint32_t> nbins("nbins", true, edm::Comment("number of bins of the plot"));
0263 edm::ParameterDescription<double> min("min", true, edm::Comment("starting value of the x axis"));
0264 edm::ParameterDescription<double> max("max", true, edm::Comment("ending value of the x axis"));
0265 edm::ParameterDescription<bool> bitset("bitset", false, true, edm::Comment("plot individual bits of values"));
0266 edm::ParameterDescription<std::string> column(
0267 "column", true, edm::Comment("name of the raw to fill the content of the plot"));
0268 edm::ParameterDescription<std::string> xcolumn(
0269 "xcolumn", true, edm::Comment("name of the raw to fill the x content of the plot"));
0270 edm::ParameterDescription<std::string> ycolumn(
0271 "ycolumn", true, edm::Comment("name of the raw to fill the y content of the plot"));
0272
0273 edm::ParameterSetDescription plot;
0274 plot.setComment("a parameter set that defines a DQM histogram");
0275 plot.ifValue(
0276 edm::ParameterDescription<std::string>("kind", "none", true, edm::Comment("the type of histogram")),
0277 "none" >> (name) or
0278 "count1d" >> (name and title and nbins and min and max) or
0279 "hist1d" >> (name and title and nbins and min and max and column and bitset) or
0280 "prof1d" >> (name and title and nbins and min and max and xcolumn and ycolumn));
0281
0282 edm::ParameterSetDescription vplot;
0283 vplot.setComment(
0284 "a parameter set to define all the plots to be made from a table row selected from the name of the PSet");
0285 vplot.add<edm::ParameterSetDescription>("sels", sels);
0286 vplot.addVPSet("plots", plot);
0287
0288 edm::ParameterSetDescription vplots;
0289 vplots.setComment("a parameter set to define all the set of plots to be made from the tables");
0290 vplots.addNode(edm::ParameterWildcard<edm::ParameterSetDescription>("*", edm::RequireZeroOrMore, true, vplot));
0291 desc.add<edm::ParameterSetDescription>("vplots", vplots);
0292
0293 descriptions.addWithDefaultLabel(desc);
0294 }
0295
0296 void NanoAODDQM::bookHistograms(DQMStore::IBooker &booker, edm::Run const &, edm::EventSetup const &) {
0297 booker.setCurrentFolder("Physics/NanoAODDQM");
0298
0299 for (auto &pair : groups_) {
0300 booker.setCurrentFolder("Physics/NanoAODDQM/" + pair.first);
0301 for (auto &sels : pair.second.selGroups) {
0302 std::string dir("Physics/NanoAODDQM/" + pair.first);
0303 if (!sels.nullCut())
0304 dir += "/" + sels.name;
0305 booker.setCurrentFolder(dir);
0306 auto &plots = sels.plots;
0307 plots.clear();
0308 plots.reserve(pair.second.plotPSets.size());
0309 for (const auto &cfg : pair.second.plotPSets) {
0310 auto plot = makePlot(booker, cfg);
0311 if (plot)
0312 plots.push_back(std::move(plot));
0313 }
0314 }
0315 }
0316 }
0317
0318 void NanoAODDQM::analyze(const edm::Event &iEvent, const edm::EventSetup &) {
0319 std::vector<edm::Handle<FlatTable>> alltables;
0320 getterOfProducts_.fillHandles(iEvent, alltables);
0321 std::map<std::string, std::pair<const FlatTable *, std::vector<const FlatTable *>>> maintables;
0322
0323 for (const auto &htab : alltables) {
0324 if (htab->extension())
0325 continue;
0326 maintables[htab->name()] = std::make_pair(htab.product(), std::vector<const FlatTable *>());
0327 }
0328 for (const auto &htab : alltables) {
0329 if (htab->extension()) {
0330 if (maintables.find(htab->name()) == maintables.end())
0331 throw cms::Exception("LogicError", "Missing main table for " + htab->name());
0332 maintables[htab->name()].second.push_back(htab.product());
0333 }
0334 }
0335
0336 FlatTable merged;
0337 for (auto &pair : groups_) {
0338 const std::string &name = pair.first;
0339 if (maintables.find(name) == maintables.end())
0340 continue;
0341 auto &tables = maintables[name];
0342 const FlatTable *table = tables.first;
0343 if (!tables.second.empty()) {
0344 merged = *tables.first;
0345 for (auto *other : tables.second) {
0346 merged.addExtension(*other);
0347 }
0348 table = &merged;
0349 }
0350 std::vector<bool> selbits;
0351 for (auto &sel : pair.second.selGroups) {
0352 sel.fillSel(*table, selbits);
0353
0354 for (auto &plot : sel.plots) {
0355 plot->fill(*table, selbits);
0356 }
0357 }
0358 }
0359 }
0360
0361 #include "FWCore/Framework/interface/MakerMacros.h"
0362 DEFINE_FWK_MODULE(NanoAODDQM);