Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-03-10 23:53:31

0001 #ifndef DQMSERVICES_CORE_MONITOR_ELEMENT_H
0002 #define DQMSERVICES_CORE_MONITOR_ELEMENT_H
0003 
0004 #if __GNUC__ && !defined DQM_DEPRECATED
0005 //#define DQM_DEPRECATED __attribute__((deprecated))
0006 #define DQM_DEPRECATED
0007 #endif
0008 
0009 #include "DQMServices/Core/interface/DQMNet.h"
0010 
0011 #include "DataFormats/Histograms/interface/MonitorElementCollection.h"
0012 
0013 #include "FWCore/Utilities/interface/Exception.h"
0014 
0015 #include "TF1.h"
0016 #include "TH1F.h"
0017 #include "TH1S.h"
0018 #include "TH1D.h"
0019 #include "TH1I.h"
0020 #include "TH2F.h"
0021 #include "TH2S.h"
0022 #include "TH2I.h"
0023 #include "TH2D.h"
0024 #include "TH2Poly.h"
0025 #include "TH3F.h"
0026 #include "TProfile.h"
0027 #include "TProfile2D.h"
0028 #include "TObjString.h"
0029 #include "TAxis.h"
0030 #include "TGraph.h"
0031 
0032 #include <mutex>
0033 #include <memory>
0034 #include <string>
0035 #include <atomic>
0036 #include <sstream>
0037 #include <iomanip>
0038 #include <cassert>
0039 #include <cstdint>
0040 #include <sys/time.h>
0041 #include <oneapi/tbb/spin_mutex.h>
0042 
0043 // TODO: cleaup the usages and remove.
0044 using QReport = MonitorElementData::QReport;
0045 using DQMChannel = MonitorElementData::QReport::DQMChannel;
0046 
0047 // TODO: move to a better location (changing all usages)
0048 namespace dqm {
0049   /** Numeric constants for quality test results.  The smaller the
0050       number, the less severe the message.  */
0051   namespace qstatus {
0052     static const int OTHER = 30;        //< Anything but 'ok','warning' or 'error'.
0053     static const int DISABLED = 50;     //< Test has been disabled.
0054     static const int INVALID = 60;      //< Problem preventing test from running.
0055     static const int INSUF_STAT = 70;   //< Insufficient statistics.
0056     static const int DID_NOT_RUN = 90;  //< Algorithm did not run.
0057     static const int STATUS_OK = 100;   //< Test was succesful.
0058     static const int WARNING = 200;     //< Test had some problems.
0059     static const int ERROR = 300;       //< Test has failed.
0060   }  // namespace qstatus
0061 
0062   namespace me_util {
0063     using Channel = DQMChannel;
0064   }
0065 }  // namespace dqm
0066 
0067 // forward declarations for all our friends
0068 namespace dqm::implementation {
0069   class DQMStore;
0070   class IBooker;
0071 }  // namespace dqm::implementation
0072 struct DQMTTreeIO;
0073 namespace dqm {
0074   class DQMFileSaverPB;
0075 }
0076 class DQMService;
0077 class QualityTester;
0078 
0079 namespace dqm::impl {
0080 
0081   using dqmmutex = tbb::spin_mutex;
0082 
0083   struct Access {
0084     std::unique_lock<dqmmutex> guard_;
0085     MonitorElementData::Key const &key;
0086     MonitorElementData::Value const &value;
0087   };
0088   // TODO: can this be the same type, just const?
0089   struct AccessMut {
0090     std::unique_lock<dqmmutex> guard_;
0091     MonitorElementData::Key const &key;
0092     MonitorElementData::Value &value;
0093   };
0094 
0095   struct MutableMonitorElementData {
0096     MonitorElementData data_;
0097     dqmmutex lock_;
0098     Access access() { return Access{std::unique_lock<dqmmutex>(lock_), data_.key_, data_.value_}; }
0099     AccessMut accessMut() { return AccessMut{std::unique_lock<dqmmutex>(lock_), data_.key_, data_.value_}; }
0100   };
0101 
0102   /** The base class for all MonitorElements (ME) */
0103   class MonitorElement {
0104     // these need to create and destroy MEs.
0105     friend dqm::implementation::DQMStore;
0106     friend dqm::implementation::IBooker;
0107     // these need to access some of the IO related methods.
0108     friend ::DQMTTreeIO;  // declared in DQMRootSource
0109     friend ::dqm::DQMFileSaverPB;
0110     friend ::DQMService;
0111     // this one only needs syncCoreObject.
0112     friend ::QualityTester;
0113 
0114   public:
0115     using Scalar = MonitorElementData::Scalar;
0116     using Kind = MonitorElementData::Kind;
0117 
0118     // Comparison helper used in DQMStore to insert into sets. This needs deep
0119     // private access to the MEData, that is why it lives here.
0120     struct MEComparison {
0121       using is_transparent = int;  // magic marker to allow C++14 heterogeneous set lookup.
0122 
0123       auto make_tuple(MonitorElement *me) const {
0124         return std::make_tuple(std::reference_wrapper(me->getPathname()), std::reference_wrapper(me->getName()));
0125       }
0126       auto make_tuple(MonitorElementData::Path const &path) const {
0127         return std::make_tuple(std::reference_wrapper(path.getDirname()), std::reference_wrapper(path.getObjectname()));
0128       }
0129       bool operator()(MonitorElement *left, MonitorElement *right) const {
0130         return make_tuple(left) < make_tuple(right);
0131       }
0132       bool operator()(MonitorElement *left, MonitorElementData::Path const &right) const {
0133         return make_tuple(left) < make_tuple(right);
0134       }
0135       bool operator()(MonitorElementData::Path const &left, MonitorElement *right) const {
0136         return make_tuple(left) < make_tuple(right);
0137       }
0138       bool operator()(MonitorElementData::Path const &left, MonitorElementData::Path const &right) const {
0139         return make_tuple(left) < make_tuple(right);
0140       }
0141     };
0142 
0143   private:
0144     std::shared_ptr<MutableMonitorElementData> mutable_;  // only set if this is a mutable copy of this ME
0145     // there are no immutable MEs at this time, but we might need them in the future.
0146     /** 
0147      * To do anything to the MEs data, one needs to obtain an access object.
0148      * This object will contain the lock guard if one is needed. We differentiate
0149      * access for reading and access for mutation (denoted by `Access` or
0150      * `AccessMut`, however, also read-only access may need to take a lock
0151      * if it is to a mutable object. 
0152      * We want all of this inlined and redundant operations any copies/refs
0153      * optimized away.
0154      */
0155     const Access access() const {
0156       // First, check if there is a mutable object
0157       if (mutable_) {
0158         // if there is a mutable object, that is the truth, and we take a lock.
0159         return mutable_->access();
0160       }  // else
0161       throw cms::Exception("LogicError") << "MonitorElement " << getName() << " not backed by any data!";
0162     }
0163 
0164     AccessMut accessMut() {
0165       // For completeness, set the legacy `updated` marker.
0166       this->update();
0167 
0168       // First, check if there is a mutable object
0169       if (mutable_) {
0170         // if there is a mutable object, that is the truth, and we take a lock.
0171         return mutable_->accessMut();
0172       }  // else
0173       throw cms::Exception("LogicError") << "MonitorElement " << getName() << " not backed by any data!";
0174     }
0175 
0176   private:
0177     // but internal -- only for DQMStore etc.
0178 
0179     // Create ME using this data. A ROOT object pointer may be moved into the
0180     // new ME. The new ME will own this data.
0181     MonitorElement(MonitorElementData &&data);
0182     // Create new ME and take ownership of this data.
0183     MonitorElement(std::shared_ptr<MutableMonitorElementData> data);
0184     // Create a new ME sharing data with this existing ME.
0185     MonitorElement(MonitorElement *me);
0186 
0187     // return a new clone of the data of this ME. Calls ->Clone(), new object
0188     // is owned by the returned value.
0189     MonitorElementData cloneMEData();
0190 
0191     // Remove access to the data.
0192     std::shared_ptr<MutableMonitorElementData> release();
0193 
0194     // re-initialize this ME as a shared copy of the other.
0195     void switchData(MonitorElement *other);
0196     // re-initialize taking ownership of this data.
0197     void switchData(std::shared_ptr<MutableMonitorElementData> data);
0198 
0199     // Replace the ROOT object in this ME's data with the new object, taking
0200     // ownership. The old object is deleted.
0201     void switchObject(std::unique_ptr<TH1> &&newobject);
0202 
0203     // copy applicable fileds into the DQMNet core object for compatibility.
0204     // In a few places these flags are also still used by the ME.
0205     void syncCoreObject();
0206     void syncCoreObject(AccessMut &access);
0207 
0208     // check if the ME is currently backed by MEData; if false (almost) any
0209     // access will throw.
0210     bool isValid() const { return mutable_ != nullptr; }
0211 
0212     // used to implement getQErrors et. al.
0213     template <typename FILTER>
0214     std::vector<MonitorElementData::QReport *> filterQReports(FILTER filter) const;
0215 
0216     // legacy interfaces, there are no alternatives but they should not be used
0217 
0218     /// Compare monitor elements, for ordering in sets.
0219     bool operator<(const MonitorElement &x) const { return DQMNet::setOrder(data_, x.data_); }
0220     /// Check the consistency of the axis labels
0221     static bool CheckBinLabels(const TAxis *a1, const TAxis *a2);
0222     /// Get the object flags.
0223     uint32_t flags() const { return data_.flags; }
0224     /// Mark the object updated.
0225     void update() { data_.flags |= DQMNet::DQM_PROP_NEW; }
0226 
0227     // mostly used for IO, should be private.
0228     std::string valueString() const;
0229     std::string tagString() const;
0230     std::string tagLabelString() const;
0231     std::string effLabelString() const;
0232     std::string qualityTagString(const DQMNet::QValue &qv) const;
0233 
0234     // kept for DQMService. data_ is also used for MEComparison, without it
0235     // we'd need to keep a copy od the name somewhere else.
0236     /// true if ME was updated in last monitoring cycle
0237     bool wasUpdated() const { return data_.flags & DQMNet::DQM_PROP_NEW; }
0238     void packScalarData(std::string &into, const char *prefix) const;
0239     void packQualityData(std::string &into) const;
0240     DQMNet::CoreObject data_;  //< Core object information.
0241 
0242   public:
0243     MonitorElement &operator=(const MonitorElement &) = delete;
0244     MonitorElement &operator=(MonitorElement &&) = delete;
0245     virtual ~MonitorElement();
0246 
0247   public:
0248     // good to be used in subsystem code
0249 
0250     /// Get the type of the monitor element.
0251     Kind kind() const { return Kind(data_.flags & DQMNet::DQM_PROP_TYPE_MASK); }
0252 
0253     /// get name of ME
0254     const std::string &getName() const { return this->data_.objname; }
0255 
0256     /// get pathname of parent folder
0257     const std::string &getPathname() const { return this->data_.dirname; }
0258 
0259     /// get full name of ME including Pathname
0260     std::string getFullname() const { return access().key.path_.getFullname(); }
0261 
0262     edm::LuminosityBlockID getRunLumi() { return access().key.id_; }
0263 
0264     MonitorElementData::Scope getScope() { return access().key.scope_; }
0265 
0266     /// true if ME is meant to be stored for each luminosity section
0267     bool getLumiFlag() const { return access().key.scope_ == MonitorElementData::Scope::LUMI; }
0268 
0269     /// this ME is meant to be an efficiency plot that must not be
0270     /// normalized when drawn in the DQM GUI.
0271     void setEfficiencyFlag() {
0272       auto access = this->accessMut();
0273       if (access.value.object_)
0274         access.value.object_->SetBit(TH1::kIsAverage);
0275     }
0276     bool getEfficiencyFlag() {
0277       auto access = this->access();
0278       return access.value.object_ && access.value.object_->TestBit(TH1::kIsAverage);
0279     }
0280 
0281   private:
0282     // A static assert to check that T actually fits in
0283     // int64_t.
0284     template <typename T>
0285     struct fits_in_int64_t {
0286       int checkArray[sizeof(int64_t) - sizeof(T) + 1];
0287     };
0288 
0289     void doFill(int64_t x);
0290 
0291   public:
0292     // filling API.
0293 
0294     void Fill(long long x) {
0295       fits_in_int64_t<long long>();
0296       doFill(static_cast<int64_t>(x));
0297     }
0298     void Fill(unsigned long long x) {
0299       fits_in_int64_t<unsigned long long>();
0300       doFill(static_cast<int64_t>(x));
0301     }
0302     void Fill(unsigned long x) {
0303       fits_in_int64_t<unsigned long>();
0304       doFill(static_cast<int64_t>(x));
0305     }
0306     void Fill(long x) {
0307       fits_in_int64_t<long>();
0308       doFill(static_cast<int64_t>(x));
0309     }
0310     void Fill(unsigned int x) {
0311       fits_in_int64_t<unsigned int>();
0312       doFill(static_cast<int64_t>(x));
0313     }
0314     void Fill(int x) {
0315       fits_in_int64_t<int>();
0316       doFill(static_cast<int64_t>(x));
0317     }
0318     void Fill(short x) {
0319       fits_in_int64_t<short>();
0320       doFill(static_cast<int64_t>(x));
0321     }
0322     void Fill(unsigned short x) {
0323       fits_in_int64_t<unsigned short>();
0324       doFill(static_cast<int64_t>(x));
0325     }
0326     void Fill(char x) {
0327       fits_in_int64_t<char>();
0328       doFill(static_cast<int64_t>(x));
0329     }
0330     void Fill(unsigned char x) {
0331       fits_in_int64_t<unsigned char>();
0332       doFill(static_cast<int64_t>(x));
0333     }
0334 
0335     void Fill(float x) { Fill(static_cast<double>(x)); }
0336     void Fill(double x);
0337     void Fill(std::string &value);
0338 
0339     void Fill(double x, double yw);
0340     void Fill(double x, double y, double zw);
0341     void Fill(double x, double y, double z, double w);
0342     DQM_DEPRECATED
0343     void ShiftFillLast(double y, double ye = 0., int32_t xscale = 1);
0344 
0345   public:
0346     // additional APIs, mainly for harvesting.
0347 
0348     /// Remove all data from the ME, keept the empty histogram with all its settings.
0349     virtual void Reset();
0350 
0351     /// true if at least of one of the quality tests returned an error
0352     bool hasError() const { return data_.flags & DQMNet::DQM_PROP_REPORT_ERROR; }
0353 
0354     /// true if at least of one of the quality tests returned a warning
0355     bool hasWarning() const { return data_.flags & DQMNet::DQM_PROP_REPORT_WARN; }
0356 
0357     /// true if at least of one of the tests returned some other (non-ok) status
0358     bool hasOtherReport() const { return data_.flags & DQMNet::DQM_PROP_REPORT_OTHER; }
0359 
0360     /// get QReport corresponding to <qtname> (null pointer if QReport does not exist)
0361     const MonitorElementData::QReport *getQReport(const std::string &qtname) const;
0362     /// get map of QReports
0363     std::vector<MonitorElementData::QReport *> getQReports() const;
0364     /// access QReport, potentially adding it.
0365     void getQReport(bool create, const std::string &qtname, MonitorElementData::QReport *&qr, DQMNet::QValue *&qv);
0366 
0367     /// get warnings from last set of quality tests
0368     std::vector<MonitorElementData::QReport *> getQWarnings() const;
0369     /// get errors from last set of quality tests
0370     std::vector<MonitorElementData::QReport *> getQErrors() const;
0371     /// from last set of quality tests
0372     std::vector<MonitorElementData::QReport *> getQOthers() const;
0373 
0374     // const and data-independent -- safe
0375     virtual int getNbinsX() const;
0376     virtual int getNbinsY() const;
0377     virtual int getNbinsZ() const;
0378     virtual int getBin(int binx, int biny) const;
0379     virtual int getNcells() const;
0380     virtual std::string getAxisTitle(int axis = 1) const;
0381     virtual std::string getTitle() const;
0382 
0383     // const but data-dependent -- semantically unsafe in RECO
0384     virtual double getMean(int axis = 1) const;
0385     virtual double getMeanError(int axis = 1) const;
0386     virtual double getRMS(int axis = 1) const;
0387     virtual double getRMSError(int axis = 1) const;
0388     virtual double getBinContent(int binx) const;
0389     virtual double getBinContent(int binx, int biny) const;
0390     virtual double getBinContent(int binx, int biny, int binz) const;
0391     virtual double getBinError(int binx) const;
0392     virtual double getBinError(int binx, int biny) const;
0393     virtual double getBinError(int binx, int biny, int binz) const;
0394     virtual double getEntries() const;
0395     virtual double getBinEntries(int bin) const;
0396     virtual double getBinEntries(int binx, int biny) const;
0397     virtual double integral() const;
0398 
0399     virtual int64_t getIntValue() const;
0400     virtual double getFloatValue() const;
0401     virtual const std::string &getStringValue() const;
0402 
0403     // non-const -- thread safety and semantical issues
0404     virtual void addBin(TGraph *graph);
0405     virtual void addBin(int n, const double *x, const double *y);
0406     virtual void addBin(double x1, double y1, double x2, double y2);
0407     virtual void setBinContent(int binx, double content);
0408     virtual void setBinContent(int binx, int biny, double content);
0409     virtual void setBinContent(int binx, int biny, int binz, double content);
0410     virtual void setBinError(int binx, double error);
0411     virtual void setBinError(int binx, int biny, double error);
0412     virtual void setBinError(int binx, int biny, int binz, double error);
0413     virtual void setBinEntries(int bin, double nentries);
0414     virtual void setEntries(double nentries);
0415     virtual void divide(const MonitorElement *, const MonitorElement *, double, double, const char *);
0416     virtual void setBinLabel(int bin, const std::string &label, int axis = 1);
0417     virtual void setAxisRange(double xmin, double xmax, int axis = 1);
0418     virtual void setAxisTitle(const std::string &title, int axis = 1);
0419     virtual void setAxisTimeDisplay(int value, int axis = 1);
0420     virtual void setAxisTimeFormat(const char *format = "", int axis = 1);
0421     virtual void setTitle(const std::string &title);
0422 
0423     // additional operations mainly for booking
0424     virtual void setXTitle(std::string const &title);
0425     virtual void setYTitle(std::string const &title);
0426     virtual void enableSumw2();
0427     virtual void disableAlphanumeric();
0428     virtual void setOption(const char *option);
0429     virtual double getAxisMin(int axis = 1) const;
0430     virtual double getAxisMax(int axis = 1) const;
0431     // We should avoid extending histograms in general, and if the behaviour
0432     // is actually needed, provide a more specific interface rather than
0433     // relying on the ROOT behaviour.
0434     DQM_DEPRECATED
0435     virtual void setCanExtend(unsigned int value);
0436     // We should decide if we support this (or make it default)
0437     DQM_DEPRECATED
0438     virtual void setStatOverflows(bool value);
0439     virtual bool getStatOverflows();
0440 
0441     // these should be non-const, since they are potentially not thread-safe
0442     virtual TObject const *getRootObject() const;
0443     virtual TH1 *getTH1();
0444     virtual TH1F *getTH1F();
0445     virtual TH1S *getTH1S();
0446     virtual TH1D *getTH1D();
0447     virtual TH1I *getTH1I();
0448     virtual TH2F *getTH2F();
0449     virtual TH2S *getTH2S();
0450     virtual TH2I *getTH2I();
0451     virtual TH2D *getTH2D();
0452     virtual TH2Poly *getTH2Poly();
0453     virtual TH3F *getTH3F();
0454     virtual TProfile *getTProfile();
0455     virtual TProfile2D *getTProfile2D();
0456 
0457   private:
0458     void incompatible(const char *func) const;
0459     TH1 const *accessRootObject(Access const &access, const char *func, int reqdim) const;
0460     TH1 *accessRootObject(AccessMut const &, const char *func, int reqdim) const;
0461 
0462     TAxis const *getAxis(Access const &access, const char *func, int axis) const;
0463     TAxis *getAxis(AccessMut const &access, const char *func, int axis) const;
0464   };
0465 
0466 }  // namespace dqm::impl
0467 
0468 // These may become distinct classes in the future.
0469 namespace dqm::reco {
0470   using MonitorElement = dqm::impl::MonitorElement;
0471 }
0472 namespace dqm::legacy {
0473   class MonitorElement : public dqm::reco::MonitorElement {
0474   public:
0475     // import constructors
0476     using dqm::reco::MonitorElement::MonitorElement;
0477 
0478     // Add ROOT object accessors without cost here so that harvesting code can
0479     // still freely use getTH1() and friends.
0480     using dqm::reco::MonitorElement::getRootObject;
0481     TObject *getRootObject() const override {
0482       return const_cast<TObject *>(
0483           const_cast<dqm::legacy::MonitorElement *>(this)->dqm::reco::MonitorElement::getRootObject());
0484     };
0485     using dqm::reco::MonitorElement::getTH1;
0486     virtual TH1 *getTH1() const {
0487       return const_cast<dqm::legacy::MonitorElement *>(this)->dqm::reco::MonitorElement::getTH1();
0488     };
0489     using dqm::reco::MonitorElement::getTH1F;
0490     virtual TH1F *getTH1F() const {
0491       return const_cast<dqm::legacy::MonitorElement *>(this)->dqm::reco::MonitorElement::getTH1F();
0492     };
0493     using dqm::reco::MonitorElement::getTH1S;
0494     virtual TH1S *getTH1S() const {
0495       return const_cast<dqm::legacy::MonitorElement *>(this)->dqm::reco::MonitorElement::getTH1S();
0496     };
0497     using dqm::reco::MonitorElement::getTH1D;
0498     virtual TH1D *getTH1D() const {
0499       return const_cast<dqm::legacy::MonitorElement *>(this)->dqm::reco::MonitorElement::getTH1D();
0500     };
0501     using dqm::reco::MonitorElement::getTH1I;
0502     virtual TH1I *getTH1I() const {
0503       return const_cast<dqm::legacy::MonitorElement *>(this)->dqm::reco::MonitorElement::getTH1I();
0504     };
0505     using dqm::reco::MonitorElement::getTH2F;
0506     virtual TH2F *getTH2F() const {
0507       return const_cast<dqm::legacy::MonitorElement *>(this)->dqm::reco::MonitorElement::getTH2F();
0508     };
0509     using dqm::reco::MonitorElement::getTH2S;
0510     virtual TH2S *getTH2S() const {
0511       return const_cast<dqm::legacy::MonitorElement *>(this)->dqm::reco::MonitorElement::getTH2S();
0512     };
0513     using dqm::reco::MonitorElement::getTH2I;
0514     virtual TH2I *getTH2I() const {
0515       return const_cast<dqm::legacy::MonitorElement *>(this)->dqm::reco::MonitorElement::getTH2I();
0516     };
0517     using dqm::reco::MonitorElement::getTH2D;
0518     virtual TH2D *getTH2D() const {
0519       return const_cast<dqm::legacy::MonitorElement *>(this)->dqm::reco::MonitorElement::getTH2D();
0520     };
0521     using dqm::reco::MonitorElement::getTH2Poly;
0522     virtual TH2Poly *getTH2Poly() const {
0523       return const_cast<dqm::legacy::MonitorElement *>(this)->dqm::reco::MonitorElement::getTH2Poly();
0524     };
0525     using dqm::reco::MonitorElement::getTH3F;
0526     virtual TH3F *getTH3F() const {
0527       return const_cast<dqm::legacy::MonitorElement *>(this)->dqm::reco::MonitorElement::getTH3F();
0528     };
0529     using dqm::reco::MonitorElement::getTProfile;
0530     virtual TProfile *getTProfile() const {
0531       return const_cast<dqm::legacy::MonitorElement *>(this)->dqm::reco::MonitorElement::getTProfile();
0532     };
0533     using dqm::reco::MonitorElement::getTProfile2D;
0534     virtual TProfile2D *getTProfile2D() const {
0535       return const_cast<dqm::legacy::MonitorElement *>(this)->dqm::reco::MonitorElement::getTProfile2D();
0536     };
0537   };
0538 }  // namespace dqm::legacy
0539 namespace dqm::harvesting {
0540   using MonitorElement = dqm::legacy::MonitorElement;
0541 }
0542 
0543 #endif  // DQMSERVICES_CORE_MONITOR_ELEMENT_H