CMS 3D CMS Logo

MonitorElementCollection.h
Go to the documentation of this file.
1 #ifndef DataFormats_Histograms_MonitorElementCollection_h
2 #define DataFormats_Histograms_MonitorElementCollection_h
3 // -*- C++ -*-
4 //
5 // Package: DataFormats/Histograms
6 // Class : MonitorElementCollection
7 //
27 //
28 // Original Author: Marcel Schneider
29 // Created: 2018-05-02
30 //
31 //
34 
35 #include <cstdint>
36 #include <cassert>
37 #include <vector>
38 #include <string>
39 
40 #include "TH1.h"
41 
43  // This is technically a union, but the struct is safer.
44  struct Scalar {
45  int64_t num = 0;
46  double real = 0;
48  };
49 
50  // Quality test result types.
51  // These are inherited from DQMNet/old DQMStore, and left unchanged to avoid
52  // another layer of wrapping. The APIs are used in some places in subsystem
53  // code, and could be changed, but not removed.
54  class QReport {
55  public:
56  struct QValue {
57  int code;
58  float qtresult;
62  };
63  struct DQMChannel {
64  int binx; //< bin # in x-axis (or bin # for 1D histogram)
65  int biny; //< bin # in y-axis (for 2D or 3D histograms)
66  int binz; //< bin # in z-axis (for 3D histograms)
67  float content; //< bin content
68  float RMS; //< RMS of bin content
69 
70  int getBin() { return getBinX(); }
71  int getBinX() { return binx; }
72  int getBinY() { return biny; }
73  int getBinZ() { return binz; }
74  float getContents() { return content; }
75  float getRMS() { return RMS; }
76 
77  DQMChannel(int bx, int by, int bz, float data, float rms) {
78  binx = bx;
79  biny = by;
80  binz = bz;
81  content = data;
82  RMS = rms;
83  }
84 
86  binx = 0;
87  biny = 0;
88  binz = 0;
89  content = 0;
90  RMS = 0;
91  }
92  };
93 
95  QValue& getValue() { return qvalue_; };
96  QValue const& getValue() const { return qvalue_; };
97 
99  int getStatus() const { return qvalue_.code; }
100 
102  float getQTresult() const { return qvalue_.qtresult; }
103 
105  const std::string& getMessage() const { return qvalue_.message; }
106 
108  const std::string& getQRName() const { return qvalue_.qtname; }
109 
111  const std::string& getAlgorithm() const { return qvalue_.algorithm; }
112 
115  const std::vector<DQMChannel>& getBadChannels() const { return badChannels_; }
116 
117  void setBadChannels(std::vector<DQMChannel> badChannels) { badChannels_ = badChannels; }
118 
120 
121  private:
122  QValue qvalue_; //< Pointer to the actual data.
123  std::vector<DQMChannel> badChannels_; //< Bad channels from QCriterion.
124  };
125 
126  // These values are compatible to DQMNet, but DQMNet is not likely to exist
127  // in the future.
128  enum class Kind {
129  INVALID = 0x0,
130  INT = 0x1,
131  REAL = 0x2,
132  STRING = 0x3,
133  TH1F = 0x10,
134  TH1S = 0x11,
135  TH1D = 0x12,
136  TH1I = 0x13,
137  TH2F = 0x20,
138  TH2S = 0x21,
139  TH2D = 0x22,
140  TH2I = 0x23,
141  TH3F = 0x30,
142  TPROFILE = 0x40,
143  TPROFILE2D = 0x41
144  };
145 
146  // Which window of time the ME is supposed to cover.
147  // There is space for a granularity level between runs and lumisections,
148  // maybe blocks of 10LS or some fixed number of events or integrated
149  // luminosity. We also want to be able to change the granularity centrally
150  // depending on the use case. That is what the default is for, and it should
151  // be used unless some specific granularity is really required.
152  // We'll also need to switch the default to JOB for multi-run harvesting.
153  enum Scope { JOB = 1, RUN = 2, LUMI = 3 /*, BLOCK = 4 */ };
154 
155  // The main ME data. We don't keep references/QTest results, instead we use
156  // only the fields stored in DQMIO files.
157  struct Value {
160  std::vector<QReport> qreports_;
161  };
162 
163  struct Path {
164  private:
165  // We could use pointers to interned strings here to save some space.
168 
169  public:
170  enum class Type { DIR, DIR_AND_NAME };
171 
172  std::string const& getDirname() const { return dirname_; }
173  std::string const& getObjectname() const { return objname_; }
174  std::string getFullname() const { return dirname_ + objname_; }
175 
176  // Clean up the path and normalize it to preserve certain invariants.
177  // Instead of reasoning about whatever properties of paths, we just parse
178  // the thing and build a normalized instance with no slash in the beginning
179  // and a slash in the end.
180  // Type of string `path` could be just directory name, or
181  // directory name followed by the name of the monitor element
183  //rebuild 'path' to be in canonical form
184 
185  //remove any leading '/'
186  while (not path.empty() and path.front() == '/') {
187  path.erase(path.begin());
188  }
189 
190  //handle '..' and '//'
191  // the 'dir' tokens are separate by a single '/'
192  std::string::size_type tokenStartPos = 0;
193  while (tokenStartPos < path.size()) {
194  auto tokenEndPos = path.find('/', tokenStartPos);
195  if (tokenEndPos == std::string::npos) {
196  tokenEndPos = path.size();
197  }
198  if (0 == tokenEndPos - tokenStartPos) {
199  //we are sitting on a '/'
200  path.erase(path.begin() + tokenStartPos);
201  continue;
202  } else if (2 == tokenEndPos - tokenStartPos) {
203  if (path[tokenStartPos] == '.' and path[tokenStartPos + 1] == '.') {
204  //need to go backwards and remove previous directory
205  auto endOfLastToken = tokenStartPos;
206  if (tokenStartPos > 1) {
207  endOfLastToken -= 2;
208  }
209  auto startOfLastToken = path.rfind('/', endOfLastToken);
210  if (startOfLastToken == std::string::npos) {
211  //we are at the very beginning of 'path' since no '/' found
212  path.erase(path.begin(), path.begin() + tokenEndPos);
213  tokenStartPos = 0;
214  } else {
215  path.erase(path.begin() + startOfLastToken + 1, path.begin() + tokenEndPos);
216  tokenStartPos = startOfLastToken + 1;
217  }
218  continue;
219  }
220  }
221  tokenStartPos = tokenEndPos + 1;
222  }
223 
224  //separate into objname_ and dirname_;
225  objname_.clear();
226  if (type == Path::Type::DIR) {
227  if (not path.empty() and path.back() != '/') {
228  path.append(1, '/');
229  }
231  } else {
232  auto lastSlash = path.rfind('/');
233  if (lastSlash == std::string::npos) {
235  dirname_.clear();
236  } else {
237  objname_ = path.substr(lastSlash + 1);
238  path.erase(path.begin() + lastSlash + 1, path.end());
240  }
241  }
242  }
243 
244  bool operator==(Path const& other) const {
245  return this->dirname_ == other.dirname_ && this->objname_ == other.objname_;
246  }
247  };
248 
249  // Metadata about the ME. The range is included here in case we have e.g.
250  // multiple per-lumi histograms in one collection. For a logical comparison,
251  // one should look only at the name.
252  struct Key {
254 
255  // Run number (and optionally lumi number) that the ME belongs to.
259 
260  bool operator<(Key const& other) const {
261  auto makeKeyTuple = [](Key const& k) {
262  return std::make_tuple(
263  k.path_.getDirname(), k.path_.getObjectname(), k.scope_, k.id_.run(), k.id_.luminosityBlock());
264  };
265 
266  return makeKeyTuple(*this) < makeKeyTuple(other);
267  }
268  };
269 
270  bool operator<(MonitorElementData const& other) const { return this->key_ < other.key_; }
271 
272  // The only non class/struct members
275 };
276 
277 // For now, no additional (meta-)data is needed apart from the MEs themselves.
278 // The framework will take care of tracking the plugin and LS/run that the MEs
279 // belong to.
280 // Unused for now.
282  std::vector<std::unique_ptr<const MonitorElementData>> data_;
283 
284 public:
285  void push_back(std::unique_ptr<const MonitorElementData> value) {
286  // enforce ordering
287  assert(data_.empty() || data_[data_.size() - 1] <= value);
288  data_.push_back(std::move(value));
289  }
290 
292 
293  auto begin() const { return data_.begin(); }
294 
295  auto end() const { return data_.end(); }
296 
297  bool mergeProduct(MonitorElementCollection const& product) {
298  // discussion: https://twiki.cern.ch/twiki/bin/view/CMSPublic/SWGuidePerRunAndPerLumiBlockData#Merging_Run_and_Luminosity_Block
299  assert(!"Not implemented yet.");
300  return false;
301  // Things to decide:
302  // - Should we allow merging collections of different sets of MEs? (probably not.) [0]
303  // - Should we assume the MEs to be ordered? (probably yes.)
304  // - How to handle incompatible MEs (different binning)? (fail hard.) [1]
305  // - Can multiple MEs with same (dirname, objname) exist? (probably yes.) [2]
306  // - Shall we modify the (immutable?) ROOT objects? (probably yes.)
307  //
308  // [0] Merging should increase the statistics, but not change the number of
309  // MEs, at least with the current workflows. It might be convenient to
310  // allow it, but for the beginning, it would only mask errors.
311  // [1] The DQM framework should guarantee same booking parameters as long
312  // as we stay within the Scope of the MEs.
313  // [2] To implement e.g. MEs covering blocks of 10LS, we'd store them in a
314  // run product, but have as many MEs with same name but different range as
315  // needed to perserve the wanted granularity. Merging then can merge or
316  // concatenate as possible/needed.
317  // Problem: We need to keep copies in memory until the end of run, even
318  // though we could save them to the output file as soon as it is clear that
319  // the nexe LS will not fall into the same block. Instead, we could drop
320  // them into the next lumi block we see; the semantics would be weird (the
321  // MEs in the lumi block don't actually correspond to the lumi block they
322  // are in) but the DQMIO output should be able to handle that.
323  }
324 };
325 
326 #endif
void swap(MonitorElementCollection &other)
float getQTresult() const
get test result i.e. prob value
const std::vector< DQMChannel > & getBadChannels() const
edm::propagate_const< std::unique_ptr< TH1 > > object_
const std::string & getAlgorithm() const
get quality test algorithm
assert(be >=bs)
uint16_t size_type
std::vector< DQMChannel > badChannels_
std::string const & getDirname() const
std::vector< std::unique_ptr< const MonitorElementData > > data_
Definition: value.py:1
bool operator==(Path const &other) const
void push_back(std::unique_ptr< const MonitorElementData > value)
void setBadChannels(std::vector< DQMChannel > badChannels)
const std::string & getMessage() const
get message attached to test
DQMChannel(int bx, int by, int bz, float data, float rms)
const std::string & getQRName() const
get name of quality test
std::vector< QReport > qreports_
char data[epos_bytes_allocation]
Definition: EPOS_Wrapper.h:80
int getStatus() const
get test status
bool operator<(Key const &other) const
QValue & getValue()
access underlying value
bool operator<(MonitorElementData const &other) const
std::string const & getObjectname() const
bool mergeProduct(MonitorElementCollection const &product)
def move(src, dest)
Definition: eostools.py:511