Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:10:09

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