Skip to content

Implement TH2Poly in DQM Services for HGCal DQM #41932

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Mar 10, 2025
Merged
9 changes: 9 additions & 0 deletions DQMServices/Components/plugins/DQMStoreStats.cc
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,15 @@ int DQMStoreStats::calcstats(int mode = DQMStoreStats::considerAllME) {
getEmptyMetric(it->getTH2I()->GetArray(), it->getNbinsX() + 2, it->getNbinsY() + 2, 0),
it->getNbinsX() * it->getNbinsY() * sizeof(int));
break;
// TH2Poly does not have GetArray() method
//case MonitorElement::Kind::TH2Poly:
// currentSubfolder.AddBinsD(
// it->getNbinsX() * it->getNbinsY(),
// getEmptyMetric(it->getTH2Poly()->GetArray(), it->getNbinsX() + 2, it->getNbinsY() + 2, 0));
// curr->update(it->getNbinsX() * it->getNbinsY(),
// getEmptyMetric(it->getTH2Poly()->GetArray(), it->getNbinsX() + 2, it->getNbinsY() + 2, 0),
// it->getNbinsX() * it->getNbinsY() * sizeof(int));
// break;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about this code? Is something needed here? (I have no idea what exactly is being done in this function in general)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure all the details either. I referred to PR#37665-files, the implementation of DQM support of TH1I and TH2I.

@mmusich could you help evaluate the necessity of having TH2Poly::GetArray() functionality? Maybe we need help from ROOT experts.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the question on this commented out code is still open.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @makortel, I'm addressing the open question about the commented-out TH2Poly code. After examining the issue, I have found that while TH2Poly lacks a GetArray() method, we can create a simple workaround:

std::vector<double> GetTH2PolyArray(TH2Poly* poly) {
  int nBins = poly->GetNumberOfBins();
  std::vector<double> array(nBins + 1, 0.0); // Initialize with zeros

  for (int i = 1; i <= nBins; i++) {
    array[i] = poly->GetBinContent(i);
  }

  return array;
}

and the DQM code can be:

case MonitorElement::Kind::TH2Poly:
  std::vector<double> polyArray = GetTH2PolyArray(it->getTH2Poly());
  int nBins = polyArray.size() - 1;
  
  currentSubfolder.AddBinsD(
      nBins,
      getEmptyMetric(polyArray.data(), nBins + 1, 1, 0));
  
  curr->update(nBins,
               getEmptyMetric(polyArray.data(), nBins + 1, 1, 0),
               nBins * sizeof(double));
  
  break;

Since the system already correctly handles the lack of TH2Poly support through the case/default structure, the currently commented-out code doesn't affect system functionality.

Would you prefer I implement this in the current PR, or would it be better to address it in a separate, focused PR?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you prefer I implement this in the current PR, or would it be better to address it in a separate, focused PR?

This is up to @cms-sw/dqm-l2

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would advise removing the commented-out code and address the introduction of a GetArray method for TH2poly in a separate PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. I will follow the guidance.

case MonitorElement::Kind::TPROFILE2D:
currentSubfolder.AddBinsD(
it->getNbinsX() * it->getNbinsY(),
Expand Down
9 changes: 9 additions & 0 deletions DQMServices/Components/plugins/EDMtoMEConverter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ class EDMtoMEConverter : public edm::one::EDProducer<edm::one::WatchRuns,
Tokens<TH2S>,
Tokens<TH2D>,
Tokens<TH2I>,
Tokens<TH2Poly>,
Tokens<TH3F>,
Tokens<TProfile>,
Tokens<TProfile2D>,
Expand Down Expand Up @@ -235,6 +236,14 @@ namespace {
}
};
template <>
struct HistoTraits<TH2Poly> {
static TH2Poly *get(MonitorElement *me) { return me->getTH2Poly(); }
template <typename... Args>
static MonitorElement *book(DQMStore::IBooker &iBooker, Args &&...args) {
return iBooker.book2DPoly(std::forward<Args>(args)...);
}
};
template <>
struct HistoTraits<TH3F> {
static TH3F *get(MonitorElement *me) { return me->getTH3F(); }
template <typename... Args>
Expand Down
14 changes: 14 additions & 0 deletions DQMServices/Components/plugins/MEtoEDMConverter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#include "TH2S.h"
#include "TH2D.h"
#include "TH2I.h"
#include "TH2Poly.h"
#include "TH3F.h"
#include "TProfile.h"
#include "TProfile2D.h"
Expand Down Expand Up @@ -139,6 +140,7 @@ MEtoEDMConverter::MEtoEDMConverter(const edm::ParameterSet& iPSet) : fName(""),
produces<MEtoEDM<TH2S>, edm::Transition::EndRun>(sName);
produces<MEtoEDM<TH2D>, edm::Transition::EndRun>(sName);
produces<MEtoEDM<TH2I>, edm::Transition::EndRun>(sName);
produces<MEtoEDM<TH2Poly>, edm::Transition::EndRun>(sName);
produces<MEtoEDM<TH3F>, edm::Transition::EndRun>(sName);
produces<MEtoEDM<TProfile>, edm::Transition::EndRun>(sName);
produces<MEtoEDM<TProfile2D>, edm::Transition::EndRun>(sName);
Expand All @@ -155,6 +157,7 @@ MEtoEDMConverter::MEtoEDMConverter(const edm::ParameterSet& iPSet) : fName(""),
produces<MEtoEDM<TH2S>, edm::Transition::EndLuminosityBlock>(sName);
produces<MEtoEDM<TH2D>, edm::Transition::EndLuminosityBlock>(sName);
produces<MEtoEDM<TH2I>, edm::Transition::EndLuminosityBlock>(sName);
produces<MEtoEDM<TH2Poly>, edm::Transition::EndLuminosityBlock>(sName);
produces<MEtoEDM<TH3F>, edm::Transition::EndLuminosityBlock>(sName);
produces<MEtoEDM<TProfile>, edm::Transition::EndLuminosityBlock>(sName);
produces<MEtoEDM<TProfile2D>, edm::Transition::EndLuminosityBlock>(sName);
Expand Down Expand Up @@ -220,6 +223,7 @@ void MEtoEDMConverter::putData(DQMStore::IGetter& iGetter, T& iPutTo, bool iLumi
unsigned int n2S = 0;
unsigned int n2D = 0;
unsigned int n2I = 0;
unsigned int n2P = 0;
unsigned int n3F = 0;
unsigned int nProf = 0;
unsigned int nProf2 = 0;
Expand Down Expand Up @@ -282,6 +286,10 @@ void MEtoEDMConverter::putData(DQMStore::IGetter& iGetter, T& iPutTo, bool iLumi
++n2I;
break;

case MonitorElement::Kind::TH2Poly:
++n2P;
break;

case MonitorElement::Kind::TH3F:
++n3F;
break;
Expand Down Expand Up @@ -313,6 +321,7 @@ void MEtoEDMConverter::putData(DQMStore::IGetter& iGetter, T& iPutTo, bool iLumi
std::unique_ptr<MEtoEDM<TH2S> > pOut2s(new MEtoEDM<TH2S>(n2S));
std::unique_ptr<MEtoEDM<TH2D> > pOut2d(new MEtoEDM<TH2D>(n2D));
std::unique_ptr<MEtoEDM<TH2I> > pOut2i(new MEtoEDM<TH2I>(n2I));
std::unique_ptr<MEtoEDM<TH2Poly> > pOut2p(new MEtoEDM<TH2Poly>(n2P));
std::unique_ptr<MEtoEDM<TH3F> > pOut3(new MEtoEDM<TH3F>(n3F));
std::unique_ptr<MEtoEDM<TProfile> > pOutProf(new MEtoEDM<TProfile>(nProf));
std::unique_ptr<MEtoEDM<TProfile2D> > pOutProf2(new MEtoEDM<TProfile2D>(nProf2));
Expand Down Expand Up @@ -371,6 +380,10 @@ void MEtoEDMConverter::putData(DQMStore::IGetter& iGetter, T& iPutTo, bool iLumi
pOut2i->putMEtoEdmObject(me->getFullname(), *me->getTH2I());
break;

case MonitorElement::Kind::TH2Poly:
pOut2p->putMEtoEdmObject(me->getFullname(), *me->getTH2Poly());
break;

case MonitorElement::Kind::TH3F:
pOut3->putMEtoEdmObject(me->getFullname(), *me->getTH3F());
break;
Expand Down Expand Up @@ -411,6 +424,7 @@ void MEtoEDMConverter::putData(DQMStore::IGetter& iGetter, T& iPutTo, bool iLumi
iPutTo.put(std::move(pOut2s), sName);
iPutTo.put(std::move(pOut2d), sName);
iPutTo.put(std::move(pOut2i), sName);
iPutTo.put(std::move(pOut2p), sName);
iPutTo.put(std::move(pOut3), sName);
iPutTo.put(std::move(pOutProf), sName);
iPutTo.put(std::move(pOutProf2), sName);
Expand Down
1 change: 1 addition & 0 deletions DQMServices/Components/scripts/dqmiolistmes.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"TH2Fs",
"TH2Ss",
"TH2Ds",
"TH2Polys",
"TH3Fs",
"TProfiles",
"TProfile2Ds",
Expand Down
1 change: 1 addition & 0 deletions DQMServices/Core/interface/DQMNet.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class DQMNet {
static const uint32_t DQM_PROP_TYPE_TH2S = 0x00000021;
static const uint32_t DQM_PROP_TYPE_TH2D = 0x00000022;
static const uint32_t DQM_PROP_TYPE_TH2I = 0x00000023;
static const uint32_t DQM_PROP_TYPE_TH2Poly = 0x00000024;
static const uint32_t DQM_PROP_TYPE_TH3F = 0x00000030;
static const uint32_t DQM_PROP_TYPE_TH3S = 0x00000031;
static const uint32_t DQM_PROP_TYPE_TH3D = 0x00000032;
Expand Down
28 changes: 27 additions & 1 deletion DQMServices/Core/interface/DQMStore.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ namespace dqm {
virtual ~NavigatorBase() {}

protected:
NavigatorBase(){};
NavigatorBase() {};
std::string cwd_ = "";
};

Expand Down Expand Up @@ -260,6 +260,32 @@ namespace dqm {
/* forceReplace */ true);
}
template <typename FUNC = NOOP, std::enable_if_t<not std::is_arithmetic<FUNC>::value, int> = 0>
MonitorElement* book2DPoly(TString const& name,
TString const& title,
double lowX,
double highX,
double lowY,
double highY,
FUNC onbooking = NOOP()) {
return bookME(name, MonitorElementData::Kind::TH2Poly, [=]() {
auto th2poly = new TH2Poly(name, title, lowX, highX, lowY, highY);
onbooking(th2poly);
return th2poly;
});
}
template <typename FUNC = NOOP, std::enable_if_t<not std::is_arithmetic<FUNC>::value, int> = 0>
MonitorElement* book2DPoly(TString const& name, TH2Poly* object, FUNC onbooking = NOOP()) {
return bookME(
name,
MonitorElementData::Kind::TH2Poly,
[=]() {
auto th2 = static_cast<TH2Poly*>(object->Clone(name));
onbooking(th2);
return th2;
},
/* forceReplace */ true);
}
template <typename FUNC = NOOP, std::enable_if_t<not std::is_arithmetic<FUNC>::value, int> = 0>
MonitorElement* book2S(TString const& name,
TString const& title,
int nchX,
Expand Down
10 changes: 9 additions & 1 deletion DQMServices/Core/interface/MonitorElement.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@
#include "TH2S.h"
#include "TH2I.h"
#include "TH2D.h"
#include "TH2Poly.h"
#include "TH3F.h"
#include "TProfile.h"
#include "TProfile2D.h"
#include "TObjString.h"
#include "TAxis.h"
#include "TGraph.h"

#include <mutex>
#include <memory>
Expand Down Expand Up @@ -55,7 +57,7 @@ namespace dqm {
static const int STATUS_OK = 100; //< Test was succesful.
static const int WARNING = 200; //< Test had some problems.
static const int ERROR = 300; //< Test has failed.
} // namespace qstatus
} // namespace qstatus

namespace me_util {
using Channel = DQMChannel;
Expand Down Expand Up @@ -398,6 +400,7 @@ namespace dqm::impl {
virtual const std::string &getStringValue() const;

// non-const -- thread safety and semantical issues
virtual void addBin(TGraph *graph);
virtual void setBinContent(int binx, double content);
virtual void setBinContent(int binx, int biny, double content);
virtual void setBinContent(int binx, int biny, int binz, double content);
Expand Down Expand Up @@ -443,6 +446,7 @@ namespace dqm::impl {
virtual TH2S *getTH2S();
virtual TH2I *getTH2I();
virtual TH2D *getTH2D();
virtual TH2Poly *getTH2Poly();
virtual TH3F *getTH3F();
virtual TProfile *getTProfile();
virtual TProfile2D *getTProfile2D();
Expand Down Expand Up @@ -511,6 +515,10 @@ namespace dqm::legacy {
virtual TH2D *getTH2D() const {
return const_cast<dqm::legacy::MonitorElement *>(this)->dqm::reco::MonitorElement::getTH2D();
};
using dqm::reco::MonitorElement::getTH2Poly;
virtual TH2Poly *getTH2Poly() const {
return const_cast<dqm::legacy::MonitorElement *>(this)->dqm::reco::MonitorElement::getTH2Poly();
};
using dqm::reco::MonitorElement::getTH3F;
virtual TH3F *getTH3F() const {
return const_cast<dqm::legacy::MonitorElement *>(this)->dqm::reco::MonitorElement::getTH3F();
Expand Down
4 changes: 4 additions & 0 deletions DQMServices/Core/src/DQMNet.cc
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,10 @@ DQMNet::reinstateObject(DQMStore *store, Object &o)
obj = store->book2I(name, dynamic_cast<TH2I *>(o.object));
break;

case DQM_PROP_TYPE_TH2Poly:
obj = store->book2DPoly(name, dynamic_cast<TH2Poly *>(o.object));
break;

case DQM_PROP_TYPE_TH3F:
obj = store->book3D(name, dynamic_cast<TH3F *>(o.object));
break;
Expand Down
7 changes: 7 additions & 0 deletions DQMServices/Core/src/LegacyIOHelper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,13 @@ bool LegacyIOHelper::readdir(TDirectory *dir, const std::string &toppath) {
getMEName<TH2I>(h, toppath, meName);
data_.insert(dbe_->book2I(meName, h));
}
} else if (cl->InheritsFrom("TH2Poly")) {
TH2Poly *h = dynamic_cast<TH2Poly *>(key->ReadObject<TH2Poly>()->Clone());
h->SetDirectory(nullptr);
if (h) {
getMEName<TH2Poly>(h, toppath, meName);
data_.insert(dbe_->book2DPoly(meName, h));
}
} else if (cl->InheritsFrom("TH3F")) {
TH3F *h = dynamic_cast<TH3F *>(key->ReadObject<TH3F>()->Clone());
h->SetDirectory(nullptr);
Expand Down
20 changes: 20 additions & 0 deletions DQMServices/Core/src/MonitorElement.cc
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ namespace dqm::impl {
static_cast<TH2D *>(accessRootObject(access, __PRETTY_FUNCTION__, 2))->Fill(x, yw, 1);
else if (kind() == Kind::TH2I)
static_cast<TH2I *>(accessRootObject(access, __PRETTY_FUNCTION__, 2))->Fill(x, yw, 1);
else if (kind() == Kind::TH2Poly)
static_cast<TH2Poly *>(accessRootObject(access, __PRETTY_FUNCTION__, 2))->Fill(x, yw, 1);
else if (kind() == Kind::TPROFILE)
static_cast<TProfile *>(accessRootObject(access, __PRETTY_FUNCTION__, 1))->Fill(x, yw, 1);
else
Expand Down Expand Up @@ -329,6 +331,8 @@ namespace dqm::impl {
static_cast<TH2D *>(accessRootObject(access, __PRETTY_FUNCTION__, 2))->Fill(x, y, zw);
else if (kind() == Kind::TH2I)
static_cast<TH2I *>(accessRootObject(access, __PRETTY_FUNCTION__, 2))->Fill(x, y, zw);
else if (kind() == Kind::TH2Poly)
static_cast<TH2Poly *>(accessRootObject(access, __PRETTY_FUNCTION__, 2))->Fill(x, y, zw);
else if (kind() == Kind::TH3F)
static_cast<TH3F *>(accessRootObject(access, __PRETTY_FUNCTION__, 2))->Fill(x, y, zw, 1);
else if (kind() == Kind::TPROFILE)
Expand Down Expand Up @@ -688,6 +692,16 @@ namespace dqm::impl {

/*** setter methods (wrapper around ROOT methods) ****/
//
/// set polygon bin (TH2Poly)
void MonitorElement::addBin(TGraph *graph) {
auto access = this->accessMut();
if (kind() == Kind::TH2Poly) {
static_cast<TH2Poly *>(accessRootObject(access, __PRETTY_FUNCTION__, 2))->AddBin(graph);
} else {
incompatible(__PRETTY_FUNCTION__);
}
}

/// set content of bin (1-D)
void MonitorElement::setBinContent(int binx, double content) {
auto access = this->accessMut();
Expand Down Expand Up @@ -1032,6 +1046,12 @@ namespace dqm::impl {
return static_cast<TH2D *>(accessRootObject(access, __PRETTY_FUNCTION__, 2));
}

TH2Poly *MonitorElement::getTH2Poly() {
auto access = this->accessMut();
assert(kind() == Kind::TH2Poly);
return static_cast<TH2Poly *>(accessRootObject(access, __PRETTY_FUNCTION__, 2));
}

TH3F *MonitorElement::getTH3F() {
auto access = this->accessMut();
assert(kind() == Kind::TH3F);
Expand Down
4 changes: 4 additions & 0 deletions DQMServices/Demo/test/TestDQMEDAnalyzer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class BookerFiller {
mes_2D.push_back(ibooker.book2D("th2f" + num, "2D Float Histogram " + num, 101, -0.5, 100.5, 11, -0.5, 10.5));
mes_2D.push_back(ibooker.book2S("th2s" + num, "2D Short Histogram " + num, 101, -0.5, 100.5, 11, -0.5, 10.5));
mes_2D.push_back(ibooker.book2DD("th2d" + num, "2D Double Histogram " + num, 101, -0.5, 100.5, 11, -0.5, 10.5));
mes_2D.push_back(
ibooker.book2DPoly("th2poly" + num, "2D Polygonal Double Histogram " + num, -0.5, 100.5, -0.5, 10.5));
mes_2D.push_back(ibooker.book2I("th2i" + num, "2D Integer Histogram " + num, 101, -0.5, 100.5, 11, -0.5, 10.5));
mes_2D.push_back(
ibooker.bookProfile("tprofile" + num, "1D Profile Histogram " + num, 101, -0.5, 100.5, 11, -0.5, 10.5));
Expand All @@ -57,6 +59,8 @@ class BookerFiller {
mes_2D.push_back(ibooker.book2D("th2f" + num, "2D Float Histogram " + num, 101, -0.5, 100.5, 11, -0.5, 10.5));
mes_2D.push_back(ibooker.book2S("th2s" + num, "2D Short Histogram " + num, 101, -0.5, 100.5, 11, -0.5, 10.5));
mes_2D.push_back(ibooker.book2DD("th2d" + num, "2D Double Histogram " + num, 101, -0.5, 100.5, 11, -0.5, 10.5));
mes_2D.push_back(
ibooker.book2DPoly("th2poly" + num, "2D Polygonal Double Histogram " + num, -0.5, 100.5, -0.5, 10.5));
mes_2D.push_back(ibooker.book2I("th2i" + num, "2D Integer Histogram " + num, 101, -0.5, 100.5, 11, -0.5, 10.5));
mes_2D.push_back(
ibooker.bookProfile("tprofile" + num, "1D Profile Histogram " + num, 101, -0.5, 100.5, 11, -0.5, 10.5));
Expand Down
11 changes: 6 additions & 5 deletions DQMServices/Demo/test/dqmiodumpentries.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@
6: "TH2Fs",
7: "TH2Ss",
8: "TH2Ds",
9: "TH3Fs",
10: "TProfiles",
11: "TProfile2Ds",
12: "TH1Is",
13: "TH2Is"
9: "TH2Polys",
10: "TH3Fs",
11: "TProfiles",
12: "TProfile2Ds",
13: "TH1Is",
14: "TH2Is"
}

f = ROOT.TFile.Open(args.inputfile)
Expand Down
Loading