/
githubmirror
/
cmssw
Обзор
Документация
Войти
/
githubmirror
/
cmssw
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
DQMServices/Core/src/MonitorElement.cc
1 198 строк
43 KB
Bruno Alves
Add debug message when DQM Monitor Element kind is wrong.
13 фев 2026, 16:03
13 фев 2026, 16:03
1e65c2e
Код
Авторство
О чём код?
#define __STDC_FORMAT_MACROS 1 #include "DQMServices/Core/interface/MonitorElement.h" #include "TClass.h" #include "TMath.h" #include "TList.h" #include "THashList.h" #include <iostream> #include <cassert> #include <cfloat> #include <cinttypes> #include "FWCore/MessageLogger/interface/MessageLogger.h" namespace dqm::impl { static TH1 *checkRootObject(const std::string &name, TObject *tobj, const char *func, int reqdim) { if (!tobj) throw cms::Exception("MonitorElementError") << "Method '" << func << "' cannot be invoked on monitor" " element '" << name << "' because it is not a ROOT object."; auto *h = static_cast<TH1 *>(tobj); int ndim = h->GetDimension(); if (reqdim < 0 || reqdim > ndim) throw cms::Exception("MonitorElementError") << "Method '" << func << "' cannot be invoked on monitor" " element '" << name << "' because it requires " << reqdim << " dimensions; this" " object of type '" << typeid(*h).name() << "' has " << ndim << " dimensions"; return h; } MonitorElement::MonitorElement(MonitorElementData &&data) { this->mutable_ = std::make_shared<MutableMonitorElementData>(); this->mutable_->data_ = std::move(data); syncCoreObject(); } MonitorElement::MonitorElement(std::shared_ptr<MutableMonitorElementData> data) { switchData(std::move(data)); } MonitorElement::MonitorElement(MonitorElement *me) { switchData(me); } MonitorElementData MonitorElement::cloneMEData() { MonitorElementData out; auto access = this->access(); out.key_ = access.key; out.value_.scalar_ = access.value.scalar_; if (access.value.object_) { out.value_.object_ = std::unique_ptr<TH1>(static_cast<TH1 *>(access.value.object_->Clone())); } return out; } std::shared_ptr<MutableMonitorElementData> MonitorElement::release() { auto data = this->mutable_; this->mutable_.reset(); return data; } void MonitorElement::switchData(MonitorElement *other) { assert(other); this->mutable_ = other->mutable_; syncCoreObject(); } void MonitorElement::switchData(std::shared_ptr<MutableMonitorElementData> data) { this->mutable_ = std::move(data); syncCoreObject(); } void MonitorElement::switchObject(std::unique_ptr<TH1> &&newobject) { auto access = this->accessMut(); // Assume kind etc. matches. // This should free the old object. access.value.object_ = std::move(newobject); } void MonitorElement::syncCoreObject() { auto access = this->accessMut(); syncCoreObject(access); } void MonitorElement::syncCoreObject(AccessMut &access) { data_.flags &= ~DQMNet::DQM_PROP_TYPE_MASK; data_.flags |= (int)access.key.kind_; // mark as updated. data_.flags |= DQMNet::DQM_PROP_NEW; // lumi flag is approximately equivalent to Scope::LUMI. data_.flags &= ~DQMNet::DQM_PROP_LUMI; if (access.key.scope_ == MonitorElementData::Scope::LUMI) { data_.flags |= DQMNet::DQM_PROP_LUMI; } // these are unsupported and always off. data_.flags &= ~DQMNet::DQM_PROP_HAS_REFERENCE; data_.flags &= ~DQMNet::DQM_PROP_TAGGED; data_.flags &= ~DQMNet::DQM_PROP_RESET; data_.flags &= ~DQMNet::DQM_PROP_ACCUMULATE; // we use ROOT's internal efficiency flag as the truth data_.flags &= ~DQMNet::DQM_PROP_EFFICIENCY_PLOT; if (access.value.object_ && access.value.object_->TestBit(TH1::kIsAverage)) { data_.flags |= DQMNet::DQM_PROP_EFFICIENCY_PLOT; } data_.tag = 0; // don't touch version (a timestamp). // we could set proper values here, but nobody should use them. data_.run = 0; data_.lumi = 0; // these are relics from the threaded migration and should not be used anywhere. data_.streamId = 0; data_.moduleId = 0; // leaking a pointer here, but that should be fine. data_.dirname = access.key.path_.getDirname(); data_.objname = access.key.path_.getObjectname(); data_.flags &= ~DQMNet::DQM_PROP_REPORT_ALARM; data_.qreports.clear(); for (QReport const &qr : access.value.qreports_) { data_.qreports.push_back(qr.getValue()); switch (qr.getStatus()) { case dqm::qstatus::STATUS_OK: break; case dqm::qstatus::WARNING: data_.flags |= DQMNet::DQM_PROP_REPORT_WARN; break; case dqm::qstatus::ERROR: data_.flags |= DQMNet::DQM_PROP_REPORT_ERROR; break; default: data_.flags |= DQMNet::DQM_PROP_REPORT_OTHER; break; } } } MonitorElement::~MonitorElement() {} //utility function to check the consistency of the axis labels //taken from TH1::CheckBinLabels which is not public bool MonitorElement::CheckBinLabels(const TAxis *a1, const TAxis *a2) { // check that axis have same labels THashList *l1 = (const_cast<TAxis *>(a1))->GetLabels(); THashList *l2 = (const_cast<TAxis *>(a2))->GetLabels(); if (!l1 && !l2) return true; if (!l1 || !l2) { return false; } // check now labels sizes are the same if (l1->GetSize() != l2->GetSize()) { return false; } for (int i = 1; i <= a1->GetNbins(); ++i) { TString label1 = a1->GetBinLabel(i); TString label2 = a2->GetBinLabel(i); if (label1 != label2) { return false; } } return true; } /// "Fill" ME methods for string void MonitorElement::Fill(std::string &value) { auto access = this->accessMut(); update(); if (kind() == Kind::STRING) { access.value.scalar_.str = value; } else { incompatible(__PRETTY_FUNCTION__); } } /// "Fill" ME methods for double void MonitorElement::Fill(double x) { auto access = this->accessMut(); update(); if (kind() == Kind::INT) access.value.scalar_.num = static_cast<int64_t>(x); else if (kind() == Kind::REAL) access.value.scalar_.real = x; else if (kind() == Kind::TH1F) accessRootObject(access, __PRETTY_FUNCTION__, 1)->Fill(x, 1); else if (kind() == Kind::TH1S) accessRootObject(access, __PRETTY_FUNCTION__, 1)->Fill(x, 1); else if (kind() == Kind::TH1I) accessRootObject(access, __PRETTY_FUNCTION__, 1)->Fill(x, 1); else if (kind() == Kind::TH1D) accessRootObject(access, __PRETTY_FUNCTION__, 1)->Fill(x, 1); else incompatible(__PRETTY_FUNCTION__); } /// "Fill" ME method for int64_t void MonitorElement::doFill(int64_t x) { auto access = this->accessMut(); update(); if (kind() == Kind::INT) access.value.scalar_.num = static_cast<int64_t>(x); else if (kind() == Kind::REAL) access.value.scalar_.real = static_cast<double>(x); else if (kind() == Kind::TH1F) accessRootObject(access, __PRETTY_FUNCTION__, 1)->Fill(static_cast<double>(x), 1); else if (kind() == Kind::TH1S) accessRootObject(access, __PRETTY_FUNCTION__, 1)->Fill(static_cast<double>(x), 1); else if (kind() == Kind::TH1I) accessRootObject(access, __PRETTY_FUNCTION__, 1)->Fill(static_cast<double>(x), 1); else if (kind() == Kind::TH1D) accessRootObject(access, __PRETTY_FUNCTION__, 1)->Fill(static_cast<double>(x), 1); else incompatible(__PRETTY_FUNCTION__); } /// can be used with 2D (x,y) or 1D (x, w) histograms void MonitorElement::Fill(double x, double yw) { auto access = this->accessMut(); update(); if (kind() == Kind::TH1F) accessRootObject(access, __PRETTY_FUNCTION__, 1)->Fill(x, yw); else if (kind() == Kind::TH1S) accessRootObject(access, __PRETTY_FUNCTION__, 1)->Fill(x, yw); else if (kind() == Kind::TH1D) accessRootObject(access, __PRETTY_FUNCTION__, 1)->Fill(x, yw); else if (kind() == Kind::TH1I) accessRootObject(access, __PRETTY_FUNCTION__, 1)->Fill(x, yw); else if (kind() == Kind::TH2F) static_cast<TH2F *>(accessRootObject(access, __PRETTY_FUNCTION__, 2))->Fill(x, yw, 1); else if (kind() == Kind::TH2S) static_cast<TH2S *>(accessRootObject(access, __PRETTY_FUNCTION__, 2))->Fill(x, yw, 1); else if (kind() == Kind::TH2D) 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 incompatible(__PRETTY_FUNCTION__); } /// shift bin to the left and fill last bin with new entry /// 1st argument is y value, 2nd argument is y error (default 0) /// can be used with 1D or profile histograms only void MonitorElement::ShiftFillLast(double y, double ye, int xscale) { // TODO: this should take the lock only once to be actually safe. // But since it is not const, we don't even claim it is thread-safe. update(); if (kind() == Kind::TH1F || kind() == Kind::TH1S || kind() == Kind::TH1D || kind() == Kind::TH1I) { int nbins = getNbinsX(); auto entries = (int)getEntries(); // first fill bins from left to right int index = entries + 1; int xlow = 2; int xup = nbins; // if more entries than bins then start shifting if (entries >= nbins) { index = nbins; xlow = entries - nbins + 3; xup = entries + 1; // average first bin double y1 = getBinContent(1); double y2 = getBinContent(2); double y1err = getBinError(1); double y2err = getBinError(2); double N = entries - nbins + 1.; if (ye == 0. || y1err == 0. || y2err == 0.) { // for errors zero calculate unweighted mean and its error double sum = N * y1 + y2; y1 = sum / (N + 1.); // FIXME check if correct double s = (N + 1.) * (N * y1 * y1 + y2 * y2) - sum * sum; if (s >= 0.) y1err = sqrt(s) / (N + 1.); else y1err = 0.; } else { // for errors non-zero calculate weighted mean and its error double denom = (1. / y1err + 1. / y2err); double mean = (y1 / y1err + y2 / y2err) / denom; // FIXME check if correct y1err = sqrt(((y1 - mean) * (y1 - mean) / y1err + (y2 - mean) * (y2 - mean) / y2err) / denom / 2.); y1 = mean; // set y1 to mean for filling below } setBinContent(1, y1); setBinError(1, y1err); // shift remaining bins to the left for (int i = 3; i <= nbins; i++) { setBinContent(i - 1, getBinContent(i)); setBinError(i - 1, getBinError(i)); } } // fill last bin with new values setBinContent(index, y); setBinError(index, ye); // set entries setEntries(entries + 1); // set axis labels and reset drawing option char buffer[10]; sprintf(buffer, "%d", xlow * xscale); std::string a(buffer); setBinLabel(2, a); sprintf(buffer, "%d", xup * xscale); std::string b(buffer); setBinLabel(nbins, b); setBinLabel(1, "av."); } else incompatible(__PRETTY_FUNCTION__); } /// can be used with 3D (x, y, z) or 2D (x, y, w) histograms void MonitorElement::Fill(double x, double y, double zw) { auto access = this->accessMut(); update(); if (kind() == Kind::TH2F) static_cast<TH2F *>(accessRootObject(access, __PRETTY_FUNCTION__, 2))->Fill(x, y, zw); else if (kind() == Kind::TH2S) static_cast<TH2S *>(accessRootObject(access, __PRETTY_FUNCTION__, 2))->Fill(x, y, zw); else if (kind() == Kind::TH2D) 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) static_cast<TProfile *>(accessRootObject(access, __PRETTY_FUNCTION__, 2))->Fill(x, y, zw); else if (kind() == Kind::TPROFILE2D) static_cast<TProfile2D *>(accessRootObject(access, __PRETTY_FUNCTION__, 2))->Fill(x, y, zw, 1); else incompatible(__PRETTY_FUNCTION__); } /// can be used with 3D (x, y, z, w) histograms void MonitorElement::Fill(double x, double y, double z, double w) { auto access = this->accessMut(); update(); if (kind() == Kind::TH3F) static_cast<TH3F *>(accessRootObject(access, __PRETTY_FUNCTION__, 2))->Fill(x, y, z, w); else if (kind() == Kind::TPROFILE2D) static_cast<TProfile2D *>(accessRootObject(access, __PRETTY_FUNCTION__, 2))->Fill(x, y, z, w); else incompatible(__PRETTY_FUNCTION__); } /// reset ME (ie. contents, errors, etc) void MonitorElement::Reset() { auto access = this->accessMut(); update(); if (kind() == Kind::INT) access.value.scalar_.num = 0; else if (kind() == Kind::REAL) access.value.scalar_.real = 0; else if (kind() == Kind::STRING) access.value.scalar_.str.clear(); else if (kind() == Kind::TH1F) return accessRootObject(access, __PRETTY_FUNCTION__, 1)->Reset(); else if (kind() == Kind::TH1S) return accessRootObject(access, __PRETTY_FUNCTION__, 1)->Reset(); else if (kind() == Kind::TH1D) return accessRootObject(access, __PRETTY_FUNCTION__, 1)->Reset(); else if (kind() == Kind::TH1I) return accessRootObject(access, __PRETTY_FUNCTION__, 1)->Reset(); else if (kind() == Kind::TPROFILE) return accessRootObject(access, __PRETTY_FUNCTION__, 1)->Reset(); else if (kind() == Kind::TH2F) return accessRootObject(access, __PRETTY_FUNCTION__, 2)->Reset(); else if (kind() == Kind::TH2S) return accessRootObject(access, __PRETTY_FUNCTION__, 2)->Reset(); else if (kind() == Kind::TH2D) return accessRootObject(access, __PRETTY_FUNCTION__, 2)->Reset(); else if (kind() == Kind::TH2I) return accessRootObject(access, __PRETTY_FUNCTION__, 2)->Reset(); else if (kind() == Kind::TH2Poly) return accessRootObject(access, __PRETTY_FUNCTION__, 2)->Reset(); else if (kind() == Kind::TPROFILE2D) return accessRootObject(access, __PRETTY_FUNCTION__, 2)->Reset(); else if (kind() == Kind::TH3F) return accessRootObject(access, __PRETTY_FUNCTION__, 3)->Reset(); else incompatible(__PRETTY_FUNCTION__); } std::string MonitorElement::kindHumanReadable() const { if (kind() == Kind::TH1F) return "TH1F"; else if (kind() == Kind::TH1S) return "TH1S"; else if (kind() == Kind::TH1D) return "TH1D"; else if (kind() == Kind::TH1I) return "TH1I"; else if (kind() == Kind::TPROFILE) return "TPROFILE"; else if (kind() == Kind::TH2F) return "TH2F"; else if (kind() == Kind::TH2S) return "TH2S"; else if (kind() == Kind::TH2D) return "TH2D"; else if (kind() == Kind::TH2I) return "TH2I"; else if (kind() == Kind::TH2Poly) return "TH2Poly"; else if (kind() == Kind::TPROFILE2D) return "TPROFILE2D"; else if (kind() == Kind::TH3F) return "TH3F"; else { incompatible(__PRETTY_FUNCTION__); return "incompatible"; } } /// convert scalar data into a string. void MonitorElement::packScalarData(std::string &into, const char *prefix) const { auto access = this->access(); char buf[64]; if (kind() == Kind::INT) { snprintf(buf, sizeof(buf), "%s%" PRId64, prefix, access.value.scalar_.num); into = buf; } else if (kind() == Kind::REAL) { snprintf(buf, sizeof(buf), "%s%.*g", prefix, DBL_DIG + 2, access.value.scalar_.real); into = buf; } else if (kind() == Kind::STRING) { into.reserve(strlen(prefix) + access.value.scalar_.str.size()); into += prefix; into += access.value.scalar_.str; } else incompatible(__PRETTY_FUNCTION__); } /// serialise quality report information into a string. void MonitorElement::packQualityData(std::string &into) const { DQMNet::packQualityData(into, data_.qreports); } /// returns value of ME in string format (eg. "f = 3.14151926" for double numbers); /// relevant only for scalar or string MEs std::string MonitorElement::valueString() const { std::string result; if (kind() == Kind::INT) packScalarData(result, "i="); else if (kind() == Kind::REAL) packScalarData(result, "f="); else if (kind() == Kind::STRING) packScalarData(result, "s="); else incompatible(__PRETTY_FUNCTION__); return result; } /// return tagged value of ME in string format /// (eg. <name>f=3.14151926</name> for double numbers); /// relevant only for sending scalar or string MEs over TSocket std::string MonitorElement::tagString() const { std::string result; std::string val(valueString()); result.reserve(6 + 2 * data_.objname.size() + val.size()); result += '<'; result += data_.objname; result += '>'; result += val; result += '<'; result += '/'; result += data_.objname; result += '>'; return result; } /// return label string for the monitor element tag (eg. <name>t=12345</name>) std::string MonitorElement::tagLabelString() const { char buf[32]; std::string result; size_t len = sprintf(buf, "t=%" PRIu32, data_.tag); result.reserve(6 + 2 * data_.objname.size() + len); result += '<'; result += data_.objname; result += '>'; result += buf; result += '<'; result += '/'; result += data_.objname; result += '>'; return result; } /// return label string for the monitor element tag (eg. <name>t=12345</name>) std::string MonitorElement::effLabelString() const { std::string result; result.reserve(6 + 2 * data_.objname.size() + 3); result += '<'; result += data_.objname; result += '>'; result += "e=1"; result += '<'; result += '/'; result += data_.objname; result += '>'; return result; } std::string MonitorElement::qualityTagString(const DQMNet::QValue &qv) const { char buf[64]; std::string result; size_t titlelen = data_.objname.size() + qv.qtname.size() + 1; size_t buflen = sprintf(buf, "qr=st:%d:%.*g:", qv.code, DBL_DIG + 2, qv.qtresult); result.reserve(7 + 2 * titlelen + buflen + qv.algorithm.size() + qv.message.size()); result += '<'; result += data_.objname; result += '.'; result += qv.qtname; result += '>'; result += buf; result += qv.algorithm; result += ':'; result += qv.message; result += '<'; result += '/'; result += data_.objname; result += '.'; result += qv.qtname; result += '>'; return result; } const MonitorElementData::QReport *MonitorElement::getQReport(const std::string &qtname) const { MonitorElementData::MonitorElementData::QReport *qr; DQMNet::QValue *qv; const_cast<MonitorElement *>(this)->getQReport(false, qtname, qr, qv); return qr; } template <typename FILTER> std::vector<MonitorElementData::QReport *> MonitorElement::filterQReports(FILTER filter) const { auto access = this->access(); std::vector<MonitorElementData::QReport *> result; for (MonitorElementData::QReport const &qr : access.value.qreports_) { if (filter(qr)) { // const_cast here because this API always violated cons'ness. Should // make the result type const and fix all usages. result.push_back(const_cast<MonitorElementData::QReport *>(&qr)); } } return result; } std::vector<MonitorElementData::QReport *> MonitorElement::getQReports() const { return filterQReports([](MonitorElementData::QReport const &qr) { return true; }); } std::vector<MonitorElementData::QReport *> MonitorElement::getQWarnings() const { return filterQReports( [](MonitorElementData::QReport const &qr) { return qr.getStatus() == dqm::qstatus::WARNING; }); } std::vector<MonitorElementData::QReport *> MonitorElement::getQErrors() const { return filterQReports([](MonitorElementData::QReport const &qr) { return qr.getStatus() == dqm::qstatus::ERROR; }); } std::vector<MonitorElementData::QReport *> MonitorElement::getQOthers() const { return filterQReports([](MonitorElementData::QReport const &qr) { return qr.getStatus() != dqm::qstatus::STATUS_OK && qr.getStatus() != dqm::qstatus::WARNING && qr.getStatus() != dqm::qstatus::ERROR; }); } void MonitorElement::incompatible(const char *func) const { throw cms::Exception("MonitorElementError") << "Method '" << func << "' cannot be invoked on monitor" " element '" << data_.objname << "'"; } void MonitorElement::wrongKind(const std::string rightKind) const { throw cms::Exception("MonitorElementError") << "Wrong kind of MonitorElement: " << kindHumanReadable() << " instead of " << rightKind << "."; } TH1 const *MonitorElement::accessRootObject(Access const &access, const char *func, int reqdim) const { if (kind() < Kind::TH1F) throw cms::Exception("MonitorElement") << "Method '" << func << "' cannot be invoked on monitor" " element '" << data_.objname << "' because it is not a root object"; return access.value.object_.get(); } TH1 *MonitorElement::accessRootObject(AccessMut const &access, const char *func, int reqdim) const { if (kind() < Kind::TH1F) throw cms::Exception("MonitorElement") << "Method '" << func << "' cannot be invoked on monitor" " element '" << data_.objname << "' because it is not a root object"; return checkRootObject(data_.objname, access.value.object_.get(), func, reqdim); } /*** getter methods (wrapper around ROOT methods) ****/ // /// get mean value of histogram along x, y or z axis (axis=1, 2, 3 respectively) double MonitorElement::getMean(int axis /* = 1 */) const { auto access = this->access(); return accessRootObject(access, __PRETTY_FUNCTION__, axis - 1)->GetMean(axis); } /// get mean value uncertainty of histogram along x, y or z axis /// (axis=1, 2, 3 respectively) double MonitorElement::getMeanError(int axis /* = 1 */) const { auto access = this->access(); return accessRootObject(access, __PRETTY_FUNCTION__, axis - 1)->GetMeanError(axis); } /// get RMS of histogram along x, y or z axis (axis=1, 2, 3 respectively) double MonitorElement::getRMS(int axis /* = 1 */) const { auto access = this->access(); return accessRootObject(access, __PRETTY_FUNCTION__, axis - 1)->GetRMS(axis); } /// get RMS uncertainty of histogram along x, y or z axis(axis=1,2,3 respectively) double MonitorElement::getRMSError(int axis /* = 1 */) const { auto access = this->access(); return accessRootObject(access, __PRETTY_FUNCTION__, axis - 1)->GetRMSError(axis); } /// get # of bins in X-axis int MonitorElement::getNbinsX() const { auto access = this->access(); return accessRootObject(access, __PRETTY_FUNCTION__, 1)->GetNbinsX(); } /// get # of bins in Y-axis int MonitorElement::getNbinsY() const { auto access = this->access(); return accessRootObject(access, __PRETTY_FUNCTION__, 2)->GetNbinsY(); } /// get # of bins in Z-axis int MonitorElement::getNbinsZ() const { auto access = this->access(); return accessRootObject(access, __PRETTY_FUNCTION__, 3)->GetNbinsZ(); } /// get content of bin (1-D) double MonitorElement::getBinContent(int binx) const { auto access = this->access(); return accessRootObject(access, __PRETTY_FUNCTION__, 1)->GetBinContent(binx); } /// get content of bin (2-D) double MonitorElement::getBinContent(int binx, int biny) const { auto access = this->access(); return accessRootObject(access, __PRETTY_FUNCTION__, 2)->GetBinContent(binx, biny); } /// get content of bin (3-D) double MonitorElement::getBinContent(int binx, int biny, int binz) const { auto access = this->access(); return accessRootObject(access, __PRETTY_FUNCTION__, 3)->GetBinContent(binx, biny, binz); } /// get uncertainty on content of bin (1-D) - See TH1::GetBinError for details double MonitorElement::getBinError(int binx) const { auto access = this->access(); return accessRootObject(access, __PRETTY_FUNCTION__, 1)->GetBinError(binx); } /// get uncertainty on content of bin (2-D) - See TH1::GetBinError for details double MonitorElement::getBinError(int binx, int biny) const { auto access = this->access(); return accessRootObject(access, __PRETTY_FUNCTION__, 2)->GetBinError(binx, biny); } /// get uncertainty on content of bin (3-D) - See TH1::GetBinError for details double MonitorElement::getBinError(int binx, int biny, int binz) const { auto access = this->access(); return accessRootObject(access, __PRETTY_FUNCTION__, 3)->GetBinError(binx, biny, binz); } /// get # of entries double MonitorElement::getEntries() const { auto access = this->access(); return accessRootObject(access, __PRETTY_FUNCTION__, 1)->GetEntries(); } /// get global bin number (for 2-D profiles) int MonitorElement::getBin(int binx, int biny) const { auto access = this->access(); if (kind() == Kind::TPROFILE2D) return static_cast<TProfile2D const *>(accessRootObject(access, __PRETTY_FUNCTION__, 1))->GetBin(binx, biny); else { incompatible(__PRETTY_FUNCTION__); return 0; } } // Returns number of cells (9 indicates empty TH2Poly without user-defined bins) int MonitorElement::getNcells() const { auto access = this->access(); if (kind() == Kind::TH1F) return accessRootObject(access, __PRETTY_FUNCTION__, 1)->GetNcells(); else if (kind() == Kind::TH1S) return accessRootObject(access, __PRETTY_FUNCTION__, 1)->GetNcells(); else if (kind() == Kind::TH1D) return accessRootObject(access, __PRETTY_FUNCTION__, 1)->GetNcells(); else if (kind() == Kind::TH1I) return accessRootObject(access, __PRETTY_FUNCTION__, 1)->GetNcells(); else if (kind() == Kind::TPROFILE) return accessRootObject(access, __PRETTY_FUNCTION__, 1)->GetNcells(); else if (kind() == Kind::TH2F) return accessRootObject(access, __PRETTY_FUNCTION__, 2)->GetNcells(); else if (kind() == Kind::TH2S) return accessRootObject(access, __PRETTY_FUNCTION__, 2)->GetNcells(); else if (kind() == Kind::TH2D) return accessRootObject(access, __PRETTY_FUNCTION__, 2)->GetNcells(); else if (kind() == Kind::TH2I) return accessRootObject(access, __PRETTY_FUNCTION__, 2)->GetNcells(); else if (kind() == Kind::TH2Poly) return accessRootObject(access, __PRETTY_FUNCTION__, 2)->GetNcells(); else if (kind() == Kind::TPROFILE2D) return accessRootObject(access, __PRETTY_FUNCTION__, 2)->GetNcells(); else if (kind() == Kind::TH3F) return accessRootObject(access, __PRETTY_FUNCTION__, 3)->GetNcells(); else { incompatible(__PRETTY_FUNCTION__); return 0; } } /// get # of bin entries (for profiles) double MonitorElement::getBinEntries(int bin) const { auto access = this->access(); if (kind() == Kind::TPROFILE) return static_cast<TProfile const *>(accessRootObject(access, __PRETTY_FUNCTION__, 1))->GetBinEntries(bin); else if (kind() == Kind::TPROFILE2D) return static_cast<TProfile2D const *>(accessRootObject(access, __PRETTY_FUNCTION__, 1))->GetBinEntries(bin); else { incompatible(__PRETTY_FUNCTION__); return 0; } } /// get # of bin entries (for 2-D profiles) double MonitorElement::getBinEntries(int binx, int biny) const { auto access = this->access(); if (kind() == Kind::TPROFILE2D) { int globBin = static_cast<TProfile2D const *>(accessRootObject(access, __PRETTY_FUNCTION__, 1))->GetBin(binx, biny); return static_cast<TProfile2D const *>(accessRootObject(access, __PRETTY_FUNCTION__, 1))->GetBinEntries(globBin); } else { incompatible(__PRETTY_FUNCTION__); return 0; } } /// get integral of bins double MonitorElement::integral() const { auto access = this->access(); return accessRootObject(access, __PRETTY_FUNCTION__, 1)->Integral(); } /// get x-, y- or z-axis title (axis=1, 2, 3 respectively) std::string MonitorElement::getAxisTitle(int axis /* = 1 */) const { auto access = this->access(); return getAxis(access, __PRETTY_FUNCTION__, axis)->GetTitle(); } /// get MonitorElement title std::string MonitorElement::getTitle() const { auto access = this->access(); return accessRootObject(access, __PRETTY_FUNCTION__, 1)->GetTitle(); } /*** setter methods (wrapper around ROOT methods) ****/ // Add a polygonal bin to a TH2Poly histogram through TGraph 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__); } } // Add a polygonal bin to a TH2Poly histogram through arrays void MonitorElement::addBin(int n, const double *x, const double *y) { auto access = this->accessMut(); if (kind() == Kind::TH2Poly) { static_cast<TH2Poly *>(accessRootObject(access, __PRETTY_FUNCTION__, 2))->AddBin(n, x, y); } else { incompatible(__PRETTY_FUNCTION__); } } // Add a rectangular bin to a TH2Poly histogram void MonitorElement::addBin(double x1, double y1, double x2, double y2) { auto access = this->accessMut(); if (kind() == Kind::TH2Poly) { static_cast<TH2Poly *>(accessRootObject(access, __PRETTY_FUNCTION__, 2))->AddBin(x1, y1, x2, y2); } else { incompatible(__PRETTY_FUNCTION__); } } /// set content of bin (1-D) void MonitorElement::setBinContent(int binx, double content) { auto access = this->accessMut(); accessRootObject(access, __PRETTY_FUNCTION__, 1)->SetBinContent(binx, content); } /// set content of bin (2-D) void MonitorElement::setBinContent(int binx, int biny, double content) { auto access = this->accessMut(); accessRootObject(access, __PRETTY_FUNCTION__, 2)->SetBinContent(binx, biny, content); } /// set content of bin (3-D) void MonitorElement::setBinContent(int binx, int biny, int binz, double content) { auto access = this->accessMut(); accessRootObject(access, __PRETTY_FUNCTION__, 3)->SetBinContent(binx, biny, binz, content); } /// set uncertainty on content of bin (1-D) void MonitorElement::setBinError(int binx, double error) { auto access = this->accessMut(); accessRootObject(access, __PRETTY_FUNCTION__, 1)->SetBinError(binx, error); } /// set uncertainty on content of bin (2-D) void MonitorElement::setBinError(int binx, int biny, double error) { auto access = this->accessMut(); accessRootObject(access, __PRETTY_FUNCTION__, 2)->SetBinError(binx, biny, error); } /// set uncertainty on content of bin (3-D) void MonitorElement::setBinError(int binx, int biny, int binz, double error) { auto access = this->accessMut(); accessRootObject(access, __PRETTY_FUNCTION__, 3)->SetBinError(binx, biny, binz, error); } /// set # of bin entries (to be used for profiles) void MonitorElement::setBinEntries(int bin, double nentries) { auto access = this->accessMut(); if (kind() == Kind::TPROFILE) static_cast<TProfile *>(accessRootObject(access, __PRETTY_FUNCTION__, 1))->SetBinEntries(bin, nentries); else if (kind() == Kind::TPROFILE2D) static_cast<TProfile2D *>(accessRootObject(access, __PRETTY_FUNCTION__, 1))->SetBinEntries(bin, nentries); else incompatible(__PRETTY_FUNCTION__); } /// set # of entries void MonitorElement::setEntries(double nentries) { auto access = this->accessMut(); accessRootObject(access, __PRETTY_FUNCTION__, 1)->SetEntries(nentries); } /// Replace entries with results of dividing num by denom void MonitorElement::divide( const MonitorElement *num, const MonitorElement *denom, double c1, double c2, const char *options) { if (num->kind() < Kind::TH1F) num->incompatible(__PRETTY_FUNCTION__); if (denom->kind() < Kind::TH1F) denom->incompatible(__PRETTY_FUNCTION__); TH1 const *numH = static_cast<TH1 const *>(num->getRootObject()); TH1 const *denomH = static_cast<TH1 const *>(denom->getRootObject()); TH1 *thisH = getTH1(); //Need to take locks in a consistent order to avoid deadlocks. Use pointer value order of underlying ROOT object.. //This is known as the monitor pattern. std::array<const MonitorElement *, 3> order{{this, num, denom}}; std::sort(order.begin(), order.end(), [](auto const *lhs, auto const *rhs) { return lhs->mutable_->data_.value_.object_.get() < rhs->mutable_->data_.value_.object_.get(); }); auto a0 = order[0]->access(); auto a1 = order[1]->access(); auto a2 = order[2]->access(); //Have ROOT do check that the types are compatible thisH->Divide(numH, denomH, c1, c2, options); } /// set bin label for x, y or z axis (axis=1, 2, 3 respectively) void MonitorElement::setBinLabel(int bin, const std::string &label, int axis /* = 1 */) { bool fail = false; { auto access = this->accessMut(); update(); if (getAxis(access, __PRETTY_FUNCTION__, axis)->GetNbins() >= bin) { getAxis(access, __PRETTY_FUNCTION__, axis)->SetBinLabel(bin, label.c_str()); } else { fail = true; } } // do this with the ME lock released to prevent a deadlock if (fail) { // this also takes the lock, make sure to release it before going to edm // (which might take more locks) auto name = getFullname(); edm::LogWarning("MonitorElement") << "*** MonitorElement: WARNING:" << "setBinLabel: attempting to set label of non-existent bin number for ME: " << name << " \n"; } } /// set x-, y- or z-axis range (axis=1, 2, 3 respectively) void MonitorElement::setAxisRange(double xmin, double xmax, int axis /* = 1 */) { auto access = this->accessMut(); getAxis(access, __PRETTY_FUNCTION__, axis)->SetRangeUser(xmin, xmax); } /// set x-, y- or z-axis title (axis=1, 2, 3 respectively) void MonitorElement::setAxisTitle(const std::string &title, int axis /* = 1 */) { auto access = this->accessMut(); getAxis(access, __PRETTY_FUNCTION__, axis)->SetTitle(title.c_str()); } /// set x-, y-, or z-axis to display time values void MonitorElement::setAxisTimeDisplay(int value, int axis /* = 1 */) { auto access = this->accessMut(); getAxis(access, __PRETTY_FUNCTION__, axis)->SetTimeDisplay(value); } /// set the format of the time values that are displayed on an axis void MonitorElement::setAxisTimeFormat(const char *format /* = "" */, int axis /* = 1 */) { auto access = this->accessMut(); getAxis(access, __PRETTY_FUNCTION__, axis)->SetTimeFormat(format); } /// set (ie. change) histogram/profile title void MonitorElement::setTitle(const std::string &title) { auto access = this->accessMut(); accessRootObject(access, __PRETTY_FUNCTION__, 1)->SetTitle(title.c_str()); } TAxis *MonitorElement::getAxis(AccessMut const &access, const char *func, int axis) const { TH1 *h = accessRootObject(access, func, axis - 1); TAxis *a = nullptr; if (axis == 1) a = h->GetXaxis(); else if (axis == 2) a = h->GetYaxis(); else if (axis == 3) a = h->GetZaxis(); if (!a) throw cms::Exception("MonitorElementError") << "No such axis " << axis << " in monitor element" " '" << data_.objname << "' of type '" << typeid(*h).name() << "'"; return a; } TAxis const *MonitorElement::getAxis(Access const &access, const char *func, int axis) const { TH1 const *h = accessRootObject(access, func, axis - 1); TAxis const *a = nullptr; if (axis == 1) a = h->GetXaxis(); else if (axis == 2) a = h->GetYaxis(); else if (axis == 3) a = h->GetZaxis(); if (!a) throw cms::Exception("MonitorElementError") << "No such axis " << axis << " in monitor element" " '" << data_.objname << "' of type '" << typeid(*h).name() << "'"; return a; } void MonitorElement::setXTitle(std::string const &title) { auto access = this->accessMut(); update(); access.value.object_->SetXTitle(title.c_str()); } void MonitorElement::setYTitle(std::string const &title) { auto access = this->accessMut(); update(); access.value.object_->SetYTitle(title.c_str()); } void MonitorElement::enableSumw2() { auto access = this->accessMut(); update(); if (access.value.object_->GetSumw2() == nullptr) { access.value.object_->Sumw2(); } } void MonitorElement::disableAlphanumeric() { auto access = this->accessMut(); update(); access.value.object_->GetXaxis()->SetNoAlphanumeric(false); access.value.object_->GetYaxis()->SetNoAlphanumeric(false); } void MonitorElement::setOption(const char *option) { auto access = this->accessMut(); update(); access.value.object_->SetOption(option); } double MonitorElement::getAxisMin(int axis) const { auto access = this->access(); return getAxis(access, __PRETTY_FUNCTION__, axis)->GetXmin(); } double MonitorElement::getAxisMax(int axis) const { auto access = this->access(); return getAxis(access, __PRETTY_FUNCTION__, axis)->GetXmax(); } void MonitorElement::setCanExtend(unsigned int value) { auto access = this->accessMut(); access.value.object_->SetCanExtend(value); } void MonitorElement::setStatOverflows(bool value) { auto access = this->accessMut(); if (value == kTRUE) access.value.object_->SetStatOverflows(TH1::kConsider); else access.value.object_->SetStatOverflows(TH1::kIgnore); } bool MonitorElement::getStatOverflows() { auto access = this->accessMut(); auto value = access.value.object_->GetStatOverflows(); if (value == TH1::kConsider) return true; else return false; } int64_t MonitorElement::getIntValue() const { assert(kind() == Kind::INT); auto access = this->access(); return access.value.scalar_.num; } double MonitorElement::getFloatValue() const { assert(kind() == Kind::REAL); auto access = this->access(); return access.value.scalar_.real; } const std::string &MonitorElement::getStringValue() const { assert(kind() == Kind::STRING); auto access = this->access(); return access.value.scalar_.str; } void MonitorElement::getQReport(bool create, const std::string &qtname, MonitorElementData::QReport *&qr, DQMNet::QValue *&qv) { auto access = this->accessMut(); syncCoreObject(access); assert(access.value.qreports_.size() == data_.qreports.size()); qr = nullptr; qv = nullptr; size_t pos = 0, end = access.value.qreports_.size(); while (pos < end && data_.qreports[pos].qtname != qtname) ++pos; if (pos == end && !create) return; else if (pos == end) { DQMNet::QValue q; q.code = dqm::qstatus::DID_NOT_RUN; q.qtresult = 0; q.qtname = qtname; q.message = "NO_MESSAGE_ASSIGNED"; q.algorithm = "UNKNOWN_ALGORITHM"; access.value.qreports_.push_back(MonitorElementData::QReport(q)); syncCoreObject(access); } qr = &access.value.qreports_[pos]; qv = &(qr->getValue()); } // ------------------------------------------------------------------- // TODO: all of these are UNSAFE and have to be NON-const. TObject const *MonitorElement::getRootObject() const { auto access = this->access(); return access.value.object_.get(); } TH1 *MonitorElement::getTH1() { auto access = this->accessMut(); return accessRootObject(access, __PRETTY_FUNCTION__, 0); } TH1F *MonitorElement::getTH1F() { auto access = this->accessMut(); if (kind() != Kind::TH1F) wrongKind("TH1F"); return static_cast<TH1F *>(accessRootObject(access, __PRETTY_FUNCTION__, 1)); } TH1S *MonitorElement::getTH1S() { auto access = this->accessMut(); if (kind() != Kind::TH1S) wrongKind("TH1S"); return static_cast<TH1S *>(accessRootObject(access, __PRETTY_FUNCTION__, 1)); } TH1I *MonitorElement::getTH1I() { auto access = this->accessMut(); if (kind() != Kind::TH1I) wrongKind("TH1I"); return static_cast<TH1I *>(accessRootObject(access, __PRETTY_FUNCTION__, 1)); } TH1D *MonitorElement::getTH1D() { auto access = this->accessMut(); if (kind() != Kind::TH1D) wrongKind("TH1D"); return static_cast<TH1D *>(accessRootObject(access, __PRETTY_FUNCTION__, 1)); } TH2F *MonitorElement::getTH2F() { auto access = this->accessMut(); if (kind() != Kind::TH2F) wrongKind("TH2F"); return static_cast<TH2F *>(accessRootObject(access, __PRETTY_FUNCTION__, 2)); } TH2S *MonitorElement::getTH2S() { auto access = this->accessMut(); if (kind() != Kind::TH2S) wrongKind("TH2S"); return static_cast<TH2S *>(accessRootObject(access, __PRETTY_FUNCTION__, 2)); } TH2I *MonitorElement::getTH2I() { auto access = this->accessMut(); if (kind() != Kind::TH2I) wrongKind("TH2I"); return static_cast<TH2I *>(accessRootObject(access, __PRETTY_FUNCTION__, 2)); } TH2D *MonitorElement::getTH2D() { auto access = this->accessMut(); if (kind() != Kind::TH2D) wrongKind("TH2D"); return static_cast<TH2D *>(accessRootObject(access, __PRETTY_FUNCTION__, 2)); } TH2Poly *MonitorElement::getTH2Poly() { auto access = this->accessMut(); if (kind() != Kind::TH2Poly) wrongKind("TH2Poly"); return static_cast<TH2Poly *>(accessRootObject(access, __PRETTY_FUNCTION__, 2)); } TH3F *MonitorElement::getTH3F() { auto access = this->accessMut(); if (kind() != Kind::TH3F) wrongKind("TH3F"); return static_cast<TH3F *>(accessRootObject(access, __PRETTY_FUNCTION__, 3)); } TProfile *MonitorElement::getTProfile() { auto access = this->accessMut(); if (kind() != Kind::TPROFILE) wrongKind("TPROFILE"); return static_cast<TProfile *>(accessRootObject(access, __PRETTY_FUNCTION__, 1)); } TProfile2D *MonitorElement::getTProfile2D() { auto access = this->accessMut(); if (kind() != Kind::TPROFILE2D) wrongKind("TPROFILE2D"); return static_cast<TProfile2D *>(accessRootObject(access, __PRETTY_FUNCTION__, 2)); } } // namespace dqm::impl