Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:01:52

0001 #ifndef CondCore_Utilities_PayloadInspector_h
0002 #define CondCore_Utilities_PayloadInspector_h
0003 
0004 #include "CondCore/CondDB/interface/Utils.h"
0005 #include "CondCore/CondDB/interface/Session.h"
0006 #include "CondCore/CondDB/interface/Exception.h"
0007 #include <iostream>
0008 
0009 #include <string>
0010 #include <tuple>
0011 #include <vector>
0012 #include <set>
0013 #include <type_traits>
0014 
0015 #include "FWCore/Utilities/interface/GlobalIdentifier.h"
0016 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0017 
0018 #include <pybind11/pybind11.h>
0019 #include <pybind11/stl.h>
0020 namespace py = pybind11;
0021 
0022 namespace PI {
0023   __attribute__((visibility("default"))) inline py::list mk_input(const std::string& tagName,
0024                                                                   cond::Time_t start,
0025                                                                   cond::Time_t end) {
0026     py::list ret;
0027     ret.append(py::make_tuple(tagName, std::to_string(start), std::to_string(end)));
0028     return ret;
0029   }
0030   __attribute__((visibility("default"))) inline py::list mk_input(const std::string& tagName0,
0031                                                                   cond::Time_t start0,
0032                                                                   cond::Time_t end0,
0033                                                                   const std::string& tagName1,
0034                                                                   cond::Time_t start1,
0035                                                                   cond::Time_t end1) {
0036     py::list ret;
0037     ret.append(py::make_tuple(tagName0, std::to_string(start0), std::to_string(end0)));
0038     ret.append(py::make_tuple(tagName1, std::to_string(start1), std::to_string(end1)));
0039     return ret;
0040   }
0041 }  // namespace PI
0042 
0043 namespace cond {
0044 
0045   namespace payloadInspector {
0046 
0047     // Metadata dictionary
0048     struct PlotAnnotations {
0049       static constexpr const char* const PLOT_TYPE_K = "type";
0050       static constexpr const char* const TITLE_K = "title";
0051       static constexpr const char* const PAYLOAD_TYPE_K = "payload_type";
0052       static constexpr const char* const INFO_K = "info";
0053       static constexpr const char* const XAXIS_K = "x_label";
0054       static constexpr const char* const YAXIS_K = "y_label";
0055       static constexpr const char* const ZAXIS_K = "z_label";
0056       PlotAnnotations();
0057       std::string get(const std::string& key) const;
0058       std::map<std::string, std::string> m;
0059       int ntags = 1;
0060       bool twoTags = false;
0061       bool singleIov = false;
0062     };
0063 
0064     static const char* const JSON_FORMAT_VERSION = "1.0";
0065 
0066     // Serialize functions
0067     template <typename V>
0068     std::string serializeValue(const std::string& entryLabel, const V& value) {
0069       std::stringstream ss;
0070 
0071       // N.B.:
0072       //  This hack is to output a line to stringstream only in case the
0073       //  return type of getFromPayload is a std::pair<bool, float>
0074       //  and the bool is true. This allows to control which points should
0075       //  enter the trend and which should not.
0076 
0077       if constexpr (std::is_same_v<V, std::pair<bool, float>>) {
0078         if (value.first) {
0079           ss << "\"" << entryLabel << "\":" << value.second;
0080         }
0081       } else if constexpr (std::is_same_v<V, double>) {
0082         if ((value - int(value)) == 0) {
0083           ss.precision(0);
0084         }
0085         ss << "\"" << entryLabel << "\":" << std::fixed << value;
0086       } else {
0087         ss << "\"" << entryLabel << "\":" << value;
0088       }
0089       return ss.str();
0090     }
0091 
0092     template <>
0093     inline std::string serializeValue(const std::string& entryLabel, const std::string& value) {
0094       std::stringstream ss;
0095       ss << "\"" << entryLabel << "\":\"" << value << "\"";
0096       return ss.str();
0097     }
0098 
0099     // Specialization for the multi-values coordinates ( to support the combined time+runlumi abscissa )
0100     template <typename V>
0101     std::string serializeValue(const std::string& entryLabel, const std::tuple<V, std::string>& value) {
0102       std::stringstream ss;
0103       ss << serializeValue(entryLabel, std::get<0>(value));
0104       ss << ", ";
0105       ss << serializeValue(entryLabel + "_label", std::get<1>(value));
0106       return ss.str();
0107     }
0108 
0109     // Specialization for the error bars
0110     template <typename V>
0111     std::string serializeValue(const std::string& entryLabel, const std::pair<V, V>& value) {
0112       std::stringstream ss;
0113       ss << serializeValue(entryLabel, value.first);
0114       ss << ", ";
0115       ss << serializeValue(entryLabel + "_err", value.second);
0116       return ss.str();
0117     }
0118 
0119     inline std::string serializeAnnotations(const PlotAnnotations& annotations) {
0120       std::stringstream ss;
0121       ss << "\"version\": \"" << JSON_FORMAT_VERSION << "\",";
0122       ss << "\"annotations\": {";
0123       bool first = true;
0124       for (const auto& a : annotations.m) {
0125         if (!first)
0126           ss << ",";
0127         ss << "\"" << a.first << "\":\"" << a.second << "\"";
0128         first = false;
0129       }
0130       ss << "}";
0131       return ss.str();
0132     }
0133 
0134     template <typename X, typename Y>
0135     std::string serialize(const PlotAnnotations& annotations, const std::vector<std::tuple<X, Y>>& data) {
0136       // prototype implementation...
0137       std::stringstream ss;
0138       ss << "{";
0139       ss << serializeAnnotations(annotations);
0140       ss << ",";
0141       ss << "\"data\": [";
0142       bool first = true;
0143       for (auto d : data) {
0144         auto serializedX = serializeValue("x", std::get<0>(d));
0145         auto serializedY = serializeValue("y", std::get<1>(d));
0146 
0147         // N.B.:
0148         //  we output to JSON only if the stringstream
0149         //  from serializeValue is not empty
0150 
0151         if (!serializedY.empty()) {
0152           if (!first) {
0153             ss << ",";
0154           }
0155           ss << " { " << serializedX << ", " << serializedY << " }";
0156           first = false;
0157         }
0158       }
0159       ss << "]";
0160       ss << "}";
0161       return ss.str();
0162     }
0163 
0164     template <typename X, typename Y, typename Z>
0165     std::string serialize(const PlotAnnotations& annotations, const std::vector<std::tuple<X, Y, Z>>& data) {
0166       // prototype implementation...
0167       std::stringstream ss;
0168       ss << "{";
0169       ss << serializeAnnotations(annotations);
0170       ss << ",";
0171       ss << "\"data\": [";
0172       bool first = true;
0173       for (auto d : data) {
0174         if (!first)
0175           ss << ",";
0176         ss << " { " << serializeValue("x", std::get<0>(d)) << ", " << serializeValue("y", std::get<1>(d)) << ", "
0177            << serializeValue("z", std::get<2>(d)) << " }";
0178         first = false;
0179       }
0180       ss << "]";
0181       ss << "}";
0182       return ss.str();
0183     }
0184 
0185     inline std::string serialize(const PlotAnnotations& annotations, const std::string& imageFileName) {
0186       std::stringstream ss;
0187       ss << "{";
0188       ss << serializeAnnotations(annotations);
0189       ss << ",";
0190       ss << "\"file\": \"" << imageFileName << "\"";
0191       ss << "}";
0192       return ss.str();
0193     }
0194 
0195     struct ModuleVersion {
0196       static constexpr const char* const label = "2.0";
0197     };
0198 
0199     struct TagReference {
0200       TagReference(const std::string& n,
0201                    const std::pair<cond::Time_t, cond::Time_t>& b,
0202                    const std::vector<std::tuple<cond::Time_t, cond::Hash>>& i)
0203           : name(n), boundary(b), iovs(i) {}
0204       TagReference(const TagReference& rhs) : name(rhs.name), boundary(rhs.boundary), iovs(rhs.iovs) {}
0205       const std::string& name;
0206       const std::pair<cond::Time_t, cond::Time_t>& boundary;
0207       const std::vector<std::tuple<cond::Time_t, cond::Hash>>& iovs;
0208     };
0209 
0210     // Base class, factorizing the functions exposed in the python interface
0211     class PlotBase {
0212     public:
0213       PlotBase();
0214       virtual ~PlotBase() = default;
0215       // required in the browser to find corresponding tags
0216       std::string payloadType() const;
0217 
0218       // required in the browser
0219       std::string title() const;
0220 
0221       // required in the browser
0222       std::string type() const;
0223 
0224       // required in the browser
0225       unsigned int ntags() const;
0226 
0227       //TBRemoved
0228       bool isTwoTags() const;
0229 
0230       // required in the browser
0231       bool isSingleIov() const;
0232 
0233       // required in the browser
0234       __attribute__((visibility("default"))) py::list inputParams() const;
0235 
0236       // required in the browser
0237       __attribute__((visibility("default"))) void setInputParamValues(const py::dict& values);
0238 
0239       // returns the json file with the plot data
0240       std::string data() const;
0241 
0242       // triggers the processing producing the plot
0243       __attribute__((visibility("default"))) bool process(const std::string& connectionString,
0244                                                           const py::list& tagsWithTimeBoundaries);
0245 
0246       // called by the above method - to be used in C++ unit tests...
0247       bool exec_process(const std::string& connectionString,
0248                         const std::vector<std::tuple<std::string, cond::Time_t, cond::Time_t>>& tagsWithTimeBoundaries);
0249 
0250       // not exposed in python:
0251       // called internally in process()
0252       virtual void init();
0253 
0254       // not exposed in python:
0255       // called internally in process()
0256       //virtual std::string processData(const std::vector<std::tuple<cond::Time_t, cond::Hash> >& iovs);
0257       virtual std::string processData();
0258 
0259       //
0260       void addInputParam(const std::string& paramName);
0261 
0262       // access to the fetch function of the configured reader, to be used in the processData implementations
0263       template <typename PayloadType>
0264       std::shared_ptr<PayloadType> fetchPayload(const cond::Hash& payloadHash) {
0265         return m_dbSession.fetchPayload<PayloadType>(payloadHash);
0266       }
0267 
0268       cond::Tag_t getTagInfo(const std::string& tag);
0269 
0270       template <int index>
0271       TagReference getTag() {
0272         size_t sz = m_tagNames.size();
0273         if (sz == 0 || index >= sz) {
0274           cond::throwException("Index out of range", "PlotBase::getTag()");
0275         }
0276         return TagReference(m_tagNames[index], m_tagBoundaries[index], m_tagIovs[index]);
0277       }
0278 
0279       const std::map<std::string, std::string>& inputParamValues() const;
0280 
0281       // access to the underlying db session
0282       cond::persistency::Session dbSession();
0283 
0284     protected:
0285       // possibly shared with the derived classes
0286       PlotAnnotations m_plotAnnotations;
0287       std::set<std::string> m_inputParams;
0288       std::vector<std::string> m_tagNames;
0289       std::vector<std::pair<cond::Time_t, cond::Time_t>> m_tagBoundaries;
0290       std::vector<std::vector<std::tuple<cond::Time_t, cond::Hash>>> m_tagIovs;
0291       std::map<std::string, std::string> m_inputParamValues;
0292 
0293     private:
0294       // this stuff should not be modified...
0295       cond::persistency::Session m_dbSession;
0296       std::string m_data = "";
0297     };
0298 
0299     enum IOVMultiplicity { UNSPECIFIED_IOV = 0, MULTI_IOV = 1, SINGLE_IOV = 2 };
0300 
0301     inline void setAnnotations(
0302         const std::string& type, const std::string& title, IOVMultiplicity IOV_M, int NTAGS, PlotAnnotations& target) {
0303       target.m[PlotAnnotations::PLOT_TYPE_K] = type;
0304       target.m[PlotAnnotations::TITLE_K] = title;
0305       target.ntags = NTAGS;
0306       target.singleIov = (IOV_M == SINGLE_IOV);
0307     }
0308 
0309     template <IOVMultiplicity IOV_M, int NTAGS>
0310     class PlotImpl : public PlotBase {
0311     public:
0312       PlotImpl(const std::string& type, const std::string& title) : PlotBase() {
0313         setAnnotations(type, title, IOV_M, NTAGS, m_plotAnnotations);
0314       }
0315       ~PlotImpl() override = default;
0316 
0317       virtual std::string serializeData() = 0;
0318 
0319       std::string processData() override {
0320         fill();
0321         return serializeData();
0322       }
0323 
0324       virtual bool fill() = 0;
0325     };
0326 
0327     // specialisations
0328     template <int NTAGS>
0329     class PlotImpl<UNSPECIFIED_IOV, NTAGS> : public PlotBase {
0330     public:
0331       PlotImpl(const std::string& type, const std::string& title) : PlotBase() {
0332         setAnnotations(type, title, MULTI_IOV, NTAGS, m_plotAnnotations);
0333       }
0334       ~PlotImpl() override = default;
0335 
0336       virtual std::string serializeData() = 0;
0337 
0338       std::string processData() override {
0339         fill();
0340         return serializeData();
0341       }
0342 
0343       virtual bool fill() = 0;
0344 
0345       void setSingleIov(bool flag) { m_plotAnnotations.singleIov = flag; }
0346     };
0347 
0348     template <>
0349     class PlotImpl<MULTI_IOV, 0> : public PlotBase {
0350     public:
0351       PlotImpl(const std::string& type, const std::string& title) : PlotBase() {
0352         setAnnotations(type, title, MULTI_IOV, 1, m_plotAnnotations);
0353       }
0354       ~PlotImpl() override = default;
0355 
0356       virtual std::string serializeData() = 0;
0357 
0358       std::string processData() override {
0359         fill();
0360         return serializeData();
0361       }
0362 
0363       virtual bool fill() = 0;
0364 
0365       void setTwoTags(bool flag) {
0366         if (flag)
0367           m_plotAnnotations.ntags = 2;
0368         else
0369           m_plotAnnotations.ntags = 1;
0370       }
0371     };
0372 
0373     template <>
0374     class PlotImpl<SINGLE_IOV, 0> : public PlotBase {
0375     public:
0376       PlotImpl(const std::string& type, const std::string& title) : PlotBase() {
0377         setAnnotations(type, title, SINGLE_IOV, 1, m_plotAnnotations);
0378       }
0379       ~PlotImpl() override = default;
0380 
0381       virtual std::string serializeData() = 0;
0382 
0383       std::string processData() override {
0384         fill();
0385         return serializeData();
0386       }
0387 
0388       virtual bool fill() = 0;
0389 
0390       void setTwoTags(bool flag) {
0391         if (flag)
0392           m_plotAnnotations.ntags = 2;
0393         else
0394           m_plotAnnotations.ntags = 1;
0395       }
0396     };
0397 
0398     template <>
0399     class PlotImpl<UNSPECIFIED_IOV, 0> : public PlotBase {
0400     public:
0401       PlotImpl(const std::string& type, const std::string& title) : PlotBase() {
0402         setAnnotations(type, title, MULTI_IOV, 1, m_plotAnnotations);
0403       }
0404       ~PlotImpl() override = default;
0405 
0406       virtual std::string serializeData() = 0;
0407 
0408       std::string processData() override {
0409         fill();
0410         return serializeData();
0411       }
0412 
0413       virtual bool fill() {
0414         std::vector<std::tuple<cond::Time_t, cond::Hash>> theIovs = PlotBase::getTag<0>().iovs;
0415         if (m_plotAnnotations.ntags == 2) {
0416           auto tag2iovs = PlotBase::getTag<1>().iovs;
0417           size_t oldSize = theIovs.size();
0418           size_t newSize = oldSize + tag2iovs.size();
0419           theIovs.resize(newSize);
0420           for (size_t i = 0; i < tag2iovs.size(); i++) {
0421             theIovs[i + oldSize] = tag2iovs[i];
0422           }
0423         }
0424         return fill(theIovs);
0425       }
0426 
0427       virtual bool fill(const std::vector<std::tuple<cond::Time_t, cond::Hash>>& iovs) { return false; }
0428 
0429       void setSingleIov(bool flag) {
0430         m_plotAnnotations.singleIov = flag;
0431         m_singleIovSet = true;
0432       }
0433 
0434       void setTwoTags(bool flag) {
0435         if (flag) {
0436           m_plotAnnotations.ntags = 2;
0437           if (!m_singleIovSet)
0438             m_plotAnnotations.singleIov = true;
0439         } else
0440           m_plotAnnotations.ntags = 1;
0441       }
0442 
0443       bool m_singleIovSet = false;
0444     };
0445 
0446     template <>
0447     class PlotImpl<UNSPECIFIED_IOV, 1> : public PlotBase {
0448     public:
0449       PlotImpl(const std::string& type, const std::string& title) : PlotBase() {
0450         setAnnotations(type, title, MULTI_IOV, 1, m_plotAnnotations);
0451       }
0452       ~PlotImpl() override = default;
0453 
0454       virtual std::string serializeData() = 0;
0455 
0456       std::string processData() override {
0457         fill();
0458         return serializeData();
0459       }
0460 
0461       virtual bool fill() {
0462         std::vector<std::tuple<cond::Time_t, cond::Hash>> theIovs = PlotBase::getTag<0>().iovs;
0463         if (m_plotAnnotations.ntags == 2) {
0464           auto tag2iovs = PlotBase::getTag<1>().iovs;
0465           size_t oldSize = theIovs.size();
0466           size_t newSize = oldSize + tag2iovs.size();
0467           theIovs.resize(newSize);
0468           for (size_t i = 0; i < tag2iovs.size(); i++) {
0469             theIovs[i + oldSize] = tag2iovs[i];
0470           }
0471         }
0472         return fill(theIovs);
0473       }
0474 
0475       virtual bool fill(const std::vector<std::tuple<cond::Time_t, cond::Hash>>& iovs) { return false; }
0476 
0477       void setSingleIov(bool flag) { m_plotAnnotations.singleIov = flag; }
0478     };
0479 
0480     // Concrete plot-types implementations
0481     template <typename PayloadType, typename X, typename Y, IOVMultiplicity IOV_M = UNSPECIFIED_IOV, int NTAGS = 0>
0482     class Plot2D : public PlotImpl<IOV_M, NTAGS> {
0483     public:
0484       typedef PlotImpl<IOV_M, NTAGS> Base;
0485       Plot2D(const std::string& type, const std::string& title, const std::string xLabel, const std::string& yLabel)
0486           : Base(type, title), m_plotData() {
0487         Base::m_plotAnnotations.m[PlotAnnotations::XAXIS_K] = xLabel;
0488         Base::m_plotAnnotations.m[PlotAnnotations::YAXIS_K] = yLabel;
0489         Base::m_plotAnnotations.m[PlotAnnotations::PAYLOAD_TYPE_K] = cond::demangledName(typeid(PayloadType));
0490       }
0491       ~Plot2D() override = default;
0492       std::string serializeData() override { return serialize(Base::m_plotAnnotations, m_plotData); }
0493 
0494       std::shared_ptr<PayloadType> fetchPayload(const cond::Hash& payloadHash) {
0495         return PlotBase::fetchPayload<PayloadType>(payloadHash);
0496       }
0497 
0498     protected:
0499       std::vector<std::tuple<X, Y>> m_plotData;
0500     };
0501 
0502     template <typename PayloadType,
0503               typename X,
0504               typename Y,
0505               typename Z,
0506               IOVMultiplicity IOV_M = UNSPECIFIED_IOV,
0507               int NTAGS = 0>
0508     class Plot3D : public PlotImpl<IOV_M, NTAGS> {
0509     public:
0510       typedef PlotImpl<IOV_M, NTAGS> Base;
0511       Plot3D(const std::string& type,
0512              const std::string& title,
0513              const std::string xLabel,
0514              const std::string& yLabel,
0515              const std::string& zLabel)
0516           : Base(type, title), m_plotData() {
0517         Base::m_plotAnnotations.m[PlotAnnotations::XAXIS_K] = xLabel;
0518         Base::m_plotAnnotations.m[PlotAnnotations::YAXIS_K] = yLabel;
0519         Base::m_plotAnnotations.m[PlotAnnotations::ZAXIS_K] = zLabel;
0520         Base::m_plotAnnotations.m[PlotAnnotations::PAYLOAD_TYPE_K] = cond::demangledName(typeid(PayloadType));
0521       }
0522       ~Plot3D() override = default;
0523       std::string serializeData() override { return serialize(Base::m_plotAnnotations, m_plotData); }
0524 
0525       std::shared_ptr<PayloadType> fetchPayload(const cond::Hash& payloadHash) {
0526         return PlotBase::fetchPayload<PayloadType>(payloadHash);
0527       }
0528 
0529     protected:
0530       std::vector<std::tuple<X, Y, Z>> m_plotData;
0531     };
0532 
0533     template <typename PayloadType, typename Y>
0534     class HistoryPlot : public Plot2D<PayloadType, unsigned long long, Y, MULTI_IOV, 1> {
0535     public:
0536       typedef Plot2D<PayloadType, unsigned long long, Y, MULTI_IOV, 1> Base;
0537 
0538       HistoryPlot(const std::string& title, const std::string& yLabel) : Base("History", title, "iov_since", yLabel) {}
0539 
0540       ~HistoryPlot() override = default;
0541 
0542       bool fill() override {
0543         auto tag = PlotBase::getTag<0>();
0544         for (auto iov : tag.iovs) {
0545           std::shared_ptr<PayloadType> payload = Base::fetchPayload(std::get<1>(iov));
0546           if (payload.get()) {
0547             Y value = getFromPayload(*payload);
0548             Base::m_plotData.push_back(std::make_tuple(std::get<0>(iov), value));
0549           }
0550         }
0551         return true;
0552       }
0553       virtual Y getFromPayload(PayloadType& payload) = 0;
0554     };
0555 
0556     template <typename PayloadType, typename Y>
0557     class RunHistoryPlot : public Plot2D<PayloadType, std::tuple<float, std::string>, Y, MULTI_IOV, 1> {
0558     public:
0559       typedef Plot2D<PayloadType, std::tuple<float, std::string>, Y, MULTI_IOV, 1> Base;
0560 
0561       RunHistoryPlot(const std::string& title, const std::string& yLabel)
0562           : Base("RunHistory", title, "iov_since", yLabel) {}
0563 
0564       ~RunHistoryPlot() override = default;
0565 
0566       bool fill() override {
0567         auto tag = PlotBase::getTag<0>();
0568         // for the lumi iovs we need to count the number of lumisections in every runs
0569         std::map<cond::Time_t, unsigned int> runs;
0570 
0571         cond::Tag_t tagInfo = Base::getTagInfo(tag.name);
0572         if (tagInfo.timeType == cond::lumiid) {
0573           for (auto iov : tag.iovs) {
0574             unsigned int run = std::get<0>(iov) >> 32;
0575             auto it = runs.find(run);
0576             if (it == runs.end())
0577               it = runs.insert(std::make_pair(run, 0)).first;
0578             it->second++;
0579           }
0580         }
0581         unsigned int currentRun = 0;
0582         float lumiIndex = 0;
0583         unsigned int lumiSize = 0;
0584         unsigned int rind = 0;
0585         float ind = 0;
0586         std::string label("");
0587         for (auto iov : tag.iovs) {
0588           unsigned long long since = std::get<0>(iov);
0589           // for the lumi iovs we squeeze the lumi section available in the constant run 'slot' of witdth=1
0590           if (tagInfo.timeType == cond::lumiid) {
0591             unsigned int run = since >> 32;
0592             unsigned int lumi = since & 0xFFFFFFFF;
0593             if (run != currentRun) {
0594               rind++;
0595               lumiIndex = 0;
0596               auto it = runs.find(run);
0597               if (it == runs.end()) {
0598                 // it should never happen
0599                 return false;
0600               }
0601               lumiSize = it->second;
0602             } else {
0603               lumiIndex++;
0604             }
0605             ind = rind + (lumiIndex / lumiSize);
0606             label = std::to_string(run) + " : " + std::to_string(lumi);
0607             currentRun = run;
0608           } else {
0609             ind++;
0610             // for the timestamp based iovs, it does not really make much sense to use this plot...
0611             if (tagInfo.timeType == cond::timestamp) {
0612               boost::posix_time::ptime t = cond::time::to_boost(since);
0613               label = boost::posix_time::to_simple_string(t);
0614             } else {
0615               label = std::to_string(since);
0616             }
0617           }
0618           std::shared_ptr<PayloadType> payload = Base::fetchPayload(std::get<1>(iov));
0619           if (payload.get()) {
0620             Y value = getFromPayload(*payload);
0621             Base::m_plotData.push_back(std::make_tuple(std::make_tuple(ind, label), value));
0622           }
0623         }
0624         return true;
0625       }
0626 
0627       virtual Y getFromPayload(PayloadType& payload) = 0;
0628     };
0629 
0630     template <typename PayloadType, typename Y>
0631     class TimeHistoryPlot : public Plot2D<PayloadType, std::tuple<unsigned long long, std::string>, Y, MULTI_IOV, 1> {
0632     public:
0633       typedef Plot2D<PayloadType, std::tuple<unsigned long long, std::string>, Y, MULTI_IOV, 1> Base;
0634 
0635       TimeHistoryPlot(const std::string& title, const std::string& yLabel)
0636           : Base("TimeHistory", title, "iov_since", yLabel) {}
0637       ~TimeHistoryPlot() override = default;
0638 
0639       bool fill() override {
0640         auto tag = PlotBase::getTag<0>();
0641         cond::persistency::RunInfoProxy runInfo;
0642 
0643         cond::Tag_t tagInfo = Base::getTagInfo(tag.name);
0644         if (tagInfo.timeType == cond::lumiid || tagInfo.timeType == cond::runnumber) {
0645           cond::Time_t min = std::get<0>(tag.iovs.front());
0646           cond::Time_t max = std::get<0>(tag.iovs.back());
0647           if (tagInfo.timeType == cond::lumiid) {
0648             min = min >> 32;
0649             max = max >> 32;
0650           }
0651           runInfo = Base::dbSession().getRunInfo(min, max);
0652         }
0653         for (auto iov : tag.iovs) {
0654           cond::Time_t since = std::get<0>(iov);
0655           boost::posix_time::ptime time;
0656           std::string label("");
0657           if (tagInfo.timeType == cond::lumiid || tagInfo.timeType == cond::runnumber) {
0658             unsigned int nlumi = since & 0xFFFFFFFF;
0659             if (tagInfo.timeType == cond::lumiid)
0660               since = since >> 32;
0661             label = std::to_string(since);
0662             auto it = runInfo.find(since);
0663             if (it == runInfo.end()) {
0664               // this should never happen...
0665               return false;
0666             }
0667             time = (*it).start;
0668             // add the lumi sections...
0669             if (tagInfo.timeType == cond::lumiid) {
0670               time += boost::posix_time::seconds(cond::time::SECONDS_PER_LUMI * nlumi);
0671               label += (" : " + std::to_string(nlumi));
0672             }
0673           } else if (tagInfo.timeType == cond::timestamp) {
0674             time = cond::time::to_boost(since);
0675             label = boost::posix_time::to_simple_string(time);
0676           }
0677           std::shared_ptr<PayloadType> payload = Base::fetchPayload(std::get<1>(iov));
0678           if (payload.get()) {
0679             Y value = getFromPayload(*payload);
0680             Base::m_plotData.push_back(std::make_tuple(std::make_tuple(cond::time::from_boost(time), label), value));
0681           }
0682         }
0683         return true;
0684       }
0685 
0686       virtual Y getFromPayload(PayloadType& payload) = 0;
0687     };
0688 
0689     template <typename PayloadType, typename X, typename Y>
0690     class ScatterPlot : public Plot2D<PayloadType, X, Y, MULTI_IOV, 1> {
0691     public:
0692       typedef Plot2D<PayloadType, X, Y, MULTI_IOV, 1> Base;
0693       // the x axis label will be overwritten by the plot rendering application
0694       ScatterPlot(const std::string& title, const std::string& xLabel, const std::string& yLabel)
0695           : Base("Scatter", title, xLabel, yLabel) {}
0696       ~ScatterPlot() override = default;
0697 
0698       bool fill() override {
0699         auto tag = PlotBase::getTag<0>();
0700         for (auto iov : tag.iovs) {
0701           std::shared_ptr<PayloadType> payload = Base::fetchPayload(std::get<1>(iov));
0702           if (payload.get()) {
0703             std::tuple<X, Y> value = getFromPayload(*payload);
0704             Base::m_plotData.push_back(value);
0705           }
0706         }
0707         return true;
0708       }
0709 
0710       virtual std::tuple<X, Y> getFromPayload(PayloadType& payload) = 0;
0711     };
0712 
0713     //
0714     template <typename AxisType, typename PayloadType, IOVMultiplicity IOV_M = UNSPECIFIED_IOV>
0715     class Histogram1 : public Plot2D<PayloadType, AxisType, AxisType, IOV_M, 1> {
0716     public:
0717       typedef Plot2D<PayloadType, AxisType, AxisType, IOV_M, 1> Base;
0718       // naive implementation, essentially provided as an example...
0719       Histogram1(const std::string& title,
0720                  const std::string& xLabel,
0721                  size_t nbins,
0722                  float min,
0723                  float max,
0724                  const std::string& yLabel = "entries")
0725           : Base("Histo1D", title, xLabel, yLabel), m_nbins(nbins), m_min(min), m_max(max) {}
0726 
0727       //
0728       void init() override {
0729         if (m_nbins < 1) {
0730           edm::LogError("payloadInspector::Histogram1D()")
0731               << " trying to book an histogram with less then 1 bin!" << std::endl;
0732         }
0733 
0734         if (m_min > m_max) {
0735           edm::LogError("payloadInspector::Histogram1D()")
0736               << " trying to book an histogram with minimum " << m_min << "> maximum" << m_max << " !" << std::endl;
0737         }
0738 
0739         Base::m_plotData.clear();
0740         float binSize = (m_max - m_min) / m_nbins;
0741         if (binSize > 0) {
0742           m_binSize = binSize;
0743           Base::m_plotData.resize(m_nbins);
0744           for (size_t i = 0; i < m_nbins; i++) {
0745             Base::m_plotData[i] = std::make_tuple(m_min + i * m_binSize, 0);
0746           }
0747         }
0748       }
0749 
0750       // to be used to fill the histogram!
0751       void fillWithValue(AxisType value, AxisType weight = 1) {
0752         // ignoring underflow/overflows ( they can be easily added - the total entries as well  )
0753         if (!Base::m_plotData.empty() && (value < m_max) && (value >= m_min)) {
0754           size_t ibin = (value - m_min) / m_binSize;
0755           std::get<1>(Base::m_plotData[ibin]) += weight;
0756         }
0757       }
0758 
0759       // to be used to fill the histogram!
0760       void fillWithBinAndValue(size_t bin, AxisType weight = 1) {
0761         if (bin < Base::m_plotData.size()) {
0762           std::get<1>(Base::m_plotData[bin]) = weight;
0763         }
0764       }
0765 
0766       // this one can ( and in general should ) be overridden - the implementation should use fillWithValue
0767       bool fill() override {
0768         auto tag = PlotBase::getTag<0>();
0769         for (auto iov : tag.iovs) {
0770           std::shared_ptr<PayloadType> payload = Base::fetchPayload(std::get<1>(iov));
0771           if (payload.get()) {
0772             AxisType value = getFromPayload(*payload);
0773             fillWithValue(value);
0774           }
0775         }
0776         return true;
0777       }
0778 
0779       // implement this one if you use the default fill implementation, otherwise ignore it...
0780       virtual AxisType getFromPayload(PayloadType& payload) { return 0; }
0781 
0782     private:
0783       float m_binSize = 0;
0784       size_t m_nbins;
0785       float m_min;
0786       float m_max;
0787     };
0788 
0789     // clever way to reduce the number of templated arguments
0790     // see https://stackoverflow.com/questions/3881633/reducing-number-of-template-arguments-for-class
0791     // for reference
0792 
0793     template <typename PayloadType, IOVMultiplicity IOV_M = UNSPECIFIED_IOV>
0794     using Histogram1D = Histogram1<float, PayloadType, UNSPECIFIED_IOV>;
0795 
0796     template <typename PayloadType, IOVMultiplicity IOV_M = UNSPECIFIED_IOV>
0797     using Histogram1DD = Histogram1<double, PayloadType, UNSPECIFIED_IOV>;
0798 
0799     //
0800     template <typename PayloadType, IOVMultiplicity IOV_M = UNSPECIFIED_IOV>
0801     class Histogram2D : public Plot3D<PayloadType, float, float, float, IOV_M, 1> {
0802     public:
0803       typedef Plot3D<PayloadType, float, float, float, IOV_M, 1> Base;
0804       // naive implementation, essentially provided as an example...
0805       Histogram2D(const std::string& title,
0806                   const std::string& xLabel,
0807                   size_t nxbins,
0808                   float xmin,
0809                   float xmax,
0810                   const std::string& yLabel,
0811                   size_t nybins,
0812                   float ymin,
0813                   float ymax)
0814           : Base("Histo2D", title, xLabel, yLabel, "entries"),
0815             m_nxbins(nxbins),
0816             m_xmin(xmin),
0817             m_xmax(xmax),
0818             m_nybins(nybins),
0819             m_ymin(ymin),
0820             m_ymax(ymax) {}
0821 
0822       //
0823       void init() override {
0824         // some protections
0825         if ((m_nxbins < 1) || (m_nybins < 1)) {
0826           edm::LogError("payloadInspector::Histogram2D()")
0827               << " trying to book an histogram with less then 1 bin!" << std::endl;
0828         }
0829 
0830         if (m_xmin > m_xmax) {
0831           edm::LogError("payloadInspector::Histogram2D()") << " trying to book an histogram with x-minimum " << m_xmin
0832                                                            << "> x-maximum" << m_xmax << " !" << std::endl;
0833         }
0834 
0835         if (m_ymin > m_ymax) {
0836           edm::LogError("payloadInspector::Histogram2D()") << " trying to book an histogram with y-minimum " << m_ymin
0837                                                            << "> y-maximum" << m_ymax << " !" << std::endl;
0838         }
0839 
0840         Base::m_plotData.clear();
0841         float xbinSize = (m_xmax - m_xmin) / m_nxbins;
0842         float ybinSize = (m_ymax - m_ymin) / m_nybins;
0843         if (xbinSize > 0 && ybinSize > 0) {
0844           m_xbinSize = xbinSize;
0845           m_ybinSize = ybinSize;
0846           Base::m_plotData.resize(m_nxbins * m_nybins);
0847           for (size_t i = 0; i < m_nybins; i++) {
0848             for (size_t j = 0; j < m_nxbins; j++) {
0849               Base::m_plotData[i * m_nxbins + j] = std::make_tuple(m_xmin + j * m_xbinSize, m_ymin + i * m_ybinSize, 0);
0850             }
0851           }
0852         }
0853       }
0854 
0855       // to be used to fill the histogram!
0856       void fillWithValue(float xvalue, float yvalue, float weight = 1) {
0857         // ignoring underflow/overflows ( they can be easily added - the total entries as well )
0858         if (!Base::m_plotData.empty() && xvalue < m_xmax && xvalue >= m_xmin && yvalue < m_ymax && yvalue >= m_ymin) {
0859           size_t ixbin = (xvalue - m_xmin) / m_xbinSize;
0860           size_t iybin = (yvalue - m_ymin) / m_ybinSize;
0861           std::get<2>(Base::m_plotData[iybin * m_nxbins + ixbin]) += weight;
0862         }
0863       }
0864 
0865       // this one can ( and in general should ) be overridden - the implementation should use fillWithValue
0866       bool fill() override {
0867         auto tag = PlotBase::getTag<0>();
0868         for (auto iov : tag.iovs) {
0869           std::shared_ptr<PayloadType> payload = Base::fetchPayload(std::get<1>(iov));
0870           if (payload.get()) {
0871             std::tuple<float, float> value = getFromPayload(*payload);
0872             fillWithValue(std::get<0>(value), std::get<1>(value));
0873           }
0874         }
0875         return true;
0876       }
0877 
0878       // implement this one if you use the default fill implementation, otherwise ignore it...
0879       virtual std::tuple<float, float> getFromPayload(PayloadType& payload) {
0880         float x = 0;
0881         float y = 0;
0882         return std::make_tuple(x, y);
0883       }
0884 
0885     private:
0886       size_t m_nxbins;
0887       float m_xbinSize = 0;
0888       float m_xmin;
0889       float m_xmax;
0890       float m_ybinSize = 0;
0891       size_t m_nybins;
0892       float m_ymin;
0893       float m_ymax;
0894     };
0895 
0896     //
0897     template <typename PayloadType, IOVMultiplicity IOV_M = UNSPECIFIED_IOV, int NTAGS = 0>
0898     class PlotImage : public PlotImpl<IOV_M, NTAGS> {
0899     public:
0900       typedef PlotImpl<IOV_M, NTAGS> Base;
0901       explicit PlotImage(const std::string& title) : Base("Image", title) {
0902         std::string payloadTypeName = cond::demangledName(typeid(PayloadType));
0903         Base::m_plotAnnotations.m[PlotAnnotations::PAYLOAD_TYPE_K] = payloadTypeName;
0904         m_imageFileName = edm::createGlobalIdentifier() + ".png";
0905       }
0906 
0907       std::string serializeData() override { return serialize(Base::m_plotAnnotations, m_imageFileName); }
0908 
0909       std::shared_ptr<PayloadType> fetchPayload(const cond::Hash& payloadHash) {
0910         return PlotBase::fetchPayload<PayloadType>(payloadHash);
0911       }
0912 
0913     protected:
0914       std::string m_imageFileName;
0915     };
0916 
0917   }  // namespace payloadInspector
0918 
0919 }  // namespace cond
0920 
0921 #endif