Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-03-17 11:16:07

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