Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-03-23 16:00:20

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   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 }  // namespace
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   //Book histograms
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;  // columns may be missing (e.g. mc-only)
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::Int64:
0123           vfill<int64_t>(table, icol, rowsel);
0124           break;
0125         case FlatTable::ColumnType::UInt64:
0126           vfill<uint64_t>(table, icol, rowsel);
0127           break;
0128         case FlatTable::ColumnType::Bool:
0129           vfill<bool>(table, icol, rowsel);
0130           break;
0131         case FlatTable::ColumnType::Float:
0132           vfill<float>(table, icol, rowsel);
0133           break;
0134         case FlatTable::ColumnType::Double:
0135           vfill<double>(table, icol, rowsel);
0136           break;
0137         default:
0138           throw cms::Exception("LogicError", "Unsupported type");
0139       }
0140     }
0141 
0142   protected:
0143     std::string col_;
0144     bool bitset_;
0145     template <typename T>
0146     void vfill(const FlatTable &table, int icol, const std::vector<bool> &rowsel) {
0147       const auto &data = table.columnData<T>(icol);
0148       for (unsigned int i = 0, n = data.size(); i < n; ++i) {
0149         if (rowsel[i]) {
0150           const T val = data[i];
0151           if constexpr (std::is_integral<T>::value) {
0152             if (bitset_) {
0153               for (unsigned int b = 0; b < std::numeric_limits<T>::digits; b++) {
0154                 if ((val >> b) & 0b1)
0155                   plot_->Fill(b);
0156               }
0157             } else {
0158               plot_->Fill(val);
0159             }
0160           } else {
0161             plot_->Fill(val);
0162           }
0163         }
0164       }
0165     }
0166   };
0167 
0168   class Profile1D : public Plot {
0169   public:
0170     Profile1D(DQMStore::IBooker &booker, const edm::ParameterSet &cfg)
0171         : Plot(booker.bookProfile(cfg.getParameter<std::string>("name"),
0172                                   cfg.getParameter<std::string>("title"),
0173                                   cfg.getParameter<uint32_t>("nbins"),
0174                                   cfg.getParameter<double>("min"),
0175                                   cfg.getParameter<double>("max"),
0176                                   0.,
0177                                   0.,
0178                                   "")),
0179           ycol_(cfg.getParameter<std::string>("ycolumn")),
0180           xcol_(cfg.getParameter<std::string>("xcolumn")) {}
0181     ~Profile1D() override {}
0182     void fill(const FlatTable &table, const std::vector<bool> &rowsel) override {
0183       int icolx = table.columnIndex(xcol_);
0184       int icoly = table.columnIndex(ycol_);
0185       if (icolx == -1)
0186         throw cms::Exception("LogicError", "Missing " + xcol_);
0187       if (icoly == -1)
0188         throw cms::Exception("LogicError", "Missing " + ycol_);
0189       for (unsigned int irow = 0, n = table.size(); irow < n; ++irow) {
0190         if (rowsel[irow])
0191           plot_->Fill(table.getAnyValue(irow, icolx), table.getAnyValue(irow, icoly));
0192       }
0193     }
0194 
0195   protected:
0196     std::string ycol_, xcol_;
0197   };
0198 
0199   static std::unique_ptr<Plot> makePlot(DQMStore::IBooker &booker, const edm::ParameterSet &cfg) {
0200     const std::string &kind = cfg.getParameter<std::string>("kind");
0201     if (kind == "none")
0202       return nullptr;
0203     if (kind == "count1d")
0204       return std::make_unique<Count1D>(booker, cfg);
0205     if (kind == "hist1d")
0206       return std::make_unique<Plot1D>(booker, cfg);
0207     if (kind == "prof1d")
0208       return std::make_unique<Profile1D>(booker, cfg);
0209     throw cms::Exception("Configuration", "Unsupported plot kind '" + kind + "'");
0210   }
0211 
0212   struct SelGroupConfig {
0213     typedef StringCutObjectSelector<FlatTable::RowView> Selector;
0214     std::string name;
0215     std::string cutstr;
0216     std::unique_ptr<StringCutObjectSelector<FlatTable::RowView>> cutptr;
0217     std::vector<std::unique_ptr<Plot>> plots;
0218     SelGroupConfig() : name(), cutstr(), cutptr(), plots() {}
0219     SelGroupConfig(const std::string &nam, const std::string &cut) : name(nam), cutstr(cut), cutptr(), plots() {
0220       if (not nullCut()) {
0221         cutptr = std::make_unique<Selector>(replaceStringsToColumGets(cutstr));
0222       }
0223     }
0224     bool nullCut() const { return cutstr.empty(); }
0225     void fillSel(const FlatTable &table, std::vector<bool> &out) {
0226       out.resize(table.size());
0227       if (nullCut()) {
0228         std::fill(out.begin(), out.end(), true);
0229       } else {
0230         for (unsigned int i = 0, n = table.size(); i < n; ++i) {
0231           out[i] = (*cutptr)(table.row(i));
0232         }
0233       }
0234     }
0235   };
0236   struct GroupConfig {
0237     std::vector<edm::ParameterSet> plotPSets;
0238     std::vector<SelGroupConfig> selGroups;
0239   };
0240   std::map<std::string, GroupConfig> groups_;
0241   edm::GetterOfProducts<FlatTable> getterOfProducts_;
0242 };
0243 
0244 NanoAODDQM::NanoAODDQM(const edm::ParameterSet &iConfig) : getterOfProducts_(edm::ProcessMatch("*"), this) {
0245   const edm::ParameterSet &vplots = iConfig.getParameter<edm::ParameterSet>("vplots");
0246   for (const std::string &name : vplots.getParameterNamesForType<edm::ParameterSet>()) {
0247     auto &group = groups_[name];
0248     const auto &pset = vplots.getParameter<edm::ParameterSet>(name);
0249     group.plotPSets = pset.getParameter<std::vector<edm::ParameterSet>>("plots");
0250     group.selGroups.emplace_back();  // no selection (all entries)
0251     const auto &cuts = pset.getParameter<edm::ParameterSet>("sels");
0252     for (const std::string &cname : cuts.getParameterNamesForType<std::string>()) {
0253       group.selGroups.emplace_back(cname, cuts.getParameter<std::string>(cname));
0254     }
0255   }
0256   callWhenNewProductsRegistered(getterOfProducts_);
0257 }
0258 
0259 void NanoAODDQM::fillDescriptions(edm::ConfigurationDescriptions &descriptions) {
0260   edm::ParameterSetDescription desc;
0261 
0262   edm::ParameterSetDescription sels;
0263   sels.setComment("a paramerter set to define the selections to be made from the table row");
0264   sels.addNode(edm::ParameterWildcard<std::string>("*", edm::RequireZeroOrMore, true));
0265 
0266   edm::ParameterDescription<std::string> name("name", true, edm::Comment(""));
0267   edm::ParameterDescription<std::string> title("title", true, edm::Comment("title of the plot"));
0268   edm::ParameterDescription<uint32_t> nbins("nbins", true, edm::Comment("number of bins of the plot"));
0269   edm::ParameterDescription<double> min("min", true, edm::Comment("starting value of the x axis"));
0270   edm::ParameterDescription<double> max("max", true, edm::Comment("ending value of the x axis"));
0271   edm::ParameterDescription<bool> bitset("bitset", false, true, edm::Comment("plot individual bits of values"));
0272   edm::ParameterDescription<std::string> column(
0273       "column", true, edm::Comment("name of the raw to fill the content of the plot"));
0274   edm::ParameterDescription<std::string> xcolumn(
0275       "xcolumn", true, edm::Comment("name of the raw to fill the x content of the plot"));
0276   edm::ParameterDescription<std::string> ycolumn(
0277       "ycolumn", true, edm::Comment("name of the raw to fill the y content of the plot"));
0278 
0279   edm::ParameterSetDescription plot;
0280   plot.setComment("a parameter set that defines a DQM histogram");
0281   plot.ifValue(
0282       edm::ParameterDescription<std::string>("kind", "none", true, edm::Comment("the type of histogram")),
0283       "none" >> (name) or  //it should really be edm::EmptyGroupDescription(), but name is used in python by modifiers
0284           "count1d" >> (name and title and nbins and min and max) or
0285           "hist1d" >> (name and title and nbins and min and max and column and bitset) or
0286           "prof1d" >> (name and title and nbins and min and max and xcolumn and ycolumn));
0287 
0288   edm::ParameterSetDescription vplot;
0289   vplot.setComment(
0290       "a parameter set to define all the plots to be made from a table row selected from the name of the PSet");
0291   vplot.add<edm::ParameterSetDescription>("sels", sels);
0292   vplot.addVPSet("plots", plot);
0293 
0294   edm::ParameterSetDescription vplots;
0295   vplots.setComment("a parameter set to define all the set of plots to be made from the tables");
0296   vplots.addNode(edm::ParameterWildcard<edm::ParameterSetDescription>("*", edm::RequireZeroOrMore, true, vplot));
0297   desc.add<edm::ParameterSetDescription>("vplots", vplots);
0298 
0299   descriptions.addWithDefaultLabel(desc);
0300 }
0301 
0302 void NanoAODDQM::bookHistograms(DQMStore::IBooker &booker, edm::Run const &, edm::EventSetup const &) {
0303   booker.setCurrentFolder("Physics/NanoAODDQM");
0304 
0305   for (auto &pair : groups_) {
0306     booker.setCurrentFolder("Physics/NanoAODDQM/" + pair.first);
0307     for (auto &sels : pair.second.selGroups) {
0308       std::string dir("Physics/NanoAODDQM/" + pair.first);
0309       if (!sels.nullCut())
0310         dir += "/" + sels.name;
0311       booker.setCurrentFolder(dir);
0312       auto &plots = sels.plots;
0313       plots.clear();
0314       plots.reserve(pair.second.plotPSets.size());
0315       for (const auto &cfg : pair.second.plotPSets) {
0316         auto plot = makePlot(booker, cfg);
0317         if (plot)
0318           plots.push_back(std::move(plot));
0319       }
0320     }
0321   }
0322 }
0323 
0324 void NanoAODDQM::analyze(const edm::Event &iEvent, const edm::EventSetup &) {
0325   std::vector<edm::Handle<FlatTable>> alltables;
0326   getterOfProducts_.fillHandles(iEvent, alltables);
0327   std::map<std::string, std::pair<const FlatTable *, std::vector<const FlatTable *>>> maintables;
0328 
0329   for (const auto &htab : alltables) {
0330     if (htab->extension())
0331       continue;
0332     maintables[htab->name()] = std::make_pair(htab.product(), std::vector<const FlatTable *>());
0333   }
0334   for (const auto &htab : alltables) {
0335     if (htab->extension()) {
0336       if (maintables.find(htab->name()) == maintables.end())
0337         throw cms::Exception("LogicError", "Missing main table for " + htab->name());
0338       maintables[htab->name()].second.push_back(htab.product());
0339     }
0340   }
0341 
0342   FlatTable merged;
0343   for (auto &pair : groups_) {
0344     const std::string &name = pair.first;
0345     if (maintables.find(name) == maintables.end())
0346       continue;  // may happen for missing collections
0347     auto &tables = maintables[name];
0348     const FlatTable *table = tables.first;
0349     if (!tables.second.empty()) {
0350       merged = *tables.first;
0351       for (auto *other : tables.second) {
0352         merged.addExtension(*other);
0353       }
0354       table = &merged;
0355     }
0356     std::vector<bool> selbits;
0357     for (auto &sel : pair.second.selGroups) {
0358       sel.fillSel(*table, selbits);
0359 
0360       for (auto &plot : sel.plots) {
0361         plot->fill(*table, selbits);
0362       }
0363     }
0364   }
0365 }
0366 
0367 #include "FWCore/Framework/interface/MakerMacros.h"
0368 DEFINE_FWK_MODULE(NanoAODDQM);