CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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  TH2F = 0x20,
137  TH2S = 0x21,
138  TH2D = 0x22,
139  TH3F = 0x30,
140  TPROFILE = 0x40,
141  TPROFILE2D = 0x41
142  };
143 
144  // Which window of time the ME is supposed to cover.
145  // There is space for a granularity level between runs and lumisections,
146  // maybe blocks of 10LS or some fixed number of events or integrated
147  // luminosity. We also want to be able to change the granularity centrally
148  // depending on the use case. That is what the default is for, and it should
149  // be used unless some specific granularity is really required.
150  // We'll also need to switch the default to JOB for multi-run harvesting.
151  enum Scope { JOB = 1, RUN = 2, LUMI = 3 /*, BLOCK = 4 */ };
152 
153  // The main ME data. We don't keep references/QTest results, instead we use
154  // only the fields stored in DQMIO files.
155  struct Value {
158  std::vector<QReport> qreports_;
159  };
160 
161  struct Path {
162  private:
163  // We could use pointers to interned strings here to save some space.
166 
167  public:
168  enum class Type { DIR, DIR_AND_NAME };
169 
170  std::string const& getDirname() const { return dirname_; }
171  std::string const& getObjectname() const { return objname_; }
172  std::string getFullname() const { return dirname_ + objname_; }
173 
174  // Clean up the path and normalize it to preserve certain invariants.
175  // Instead of reasoning about whatever properties of paths, we just parse
176  // the thing and build a normalized instance with no slash in the beginning
177  // and a slash in the end.
178  // Type of string `path` could be just directory name, or
179  // directory name followed by the name of the monitor element
181  //rebuild 'path' to be in canonical form
182 
183  //remove any leading '/'
184  while (not path.empty() and path.front() == '/') {
185  path.erase(path.begin());
186  }
187 
188  //handle '..' and '//'
189  // the 'dir' tokens are separate by a single '/'
190  std::string::size_type tokenStartPos = 0;
191  while (tokenStartPos < path.size()) {
192  auto tokenEndPos = path.find('/', tokenStartPos);
193  if (tokenEndPos == std::string::npos) {
194  tokenEndPos = path.size();
195  }
196  if (0 == tokenEndPos - tokenStartPos) {
197  //we are sitting on a '/'
198  path.erase(path.begin() + tokenStartPos);
199  continue;
200  } else if (2 == tokenEndPos - tokenStartPos) {
201  if (path[tokenStartPos] == '.' and path[tokenStartPos + 1] == '.') {
202  //need to go backwards and remove previous directory
203  auto endOfLastToken = tokenStartPos;
204  if (tokenStartPos > 1) {
205  endOfLastToken -= 2;
206  }
207  auto startOfLastToken = path.rfind('/', endOfLastToken);
208  if (startOfLastToken == std::string::npos) {
209  //we are at the very beginning of 'path' since no '/' found
210  path.erase(path.begin(), path.begin() + tokenEndPos);
211  tokenStartPos = 0;
212  } else {
213  path.erase(path.begin() + startOfLastToken + 1, path.begin() + tokenEndPos);
214  tokenStartPos = startOfLastToken + 1;
215  }
216  continue;
217  }
218  }
219  tokenStartPos = tokenEndPos + 1;
220  }
221 
222  //separate into objname_ and dirname_;
223  objname_.clear();
224  if (type == Path::Type::DIR) {
225  if (not path.empty() and path.back() != '/') {
226  path.append(1, '/');
227  }
228  dirname_ = std::move(path);
229  } else {
230  auto lastSlash = path.rfind('/');
231  if (lastSlash == std::string::npos) {
232  objname_ = std::move(path);
233  dirname_.clear();
234  } else {
235  objname_ = path.substr(lastSlash + 1);
236  path.erase(path.begin() + lastSlash + 1, path.end());
237  dirname_ = std::move(path);
238  }
239  }
240  }
241 
242  bool operator==(Path const& other) const {
243  return this->dirname_ == other.dirname_ && this->objname_ == other.objname_;
244  }
245  };
246 
247  // Metadata about the ME. The range is included here in case we have e.g.
248  // multiple per-lumi histograms in one collection. For a logical comparison,
249  // one should look only at the name.
250  struct Key {
252 
253  // Run number (and optionally lumi number) that the ME belongs to.
257 
258  bool operator<(Key const& other) const {
259  auto makeKeyTuple = [](Key const& k) {
260  return std::make_tuple(
261  k.path_.getDirname(), k.path_.getObjectname(), k.scope_, k.id_.run(), k.id_.luminosityBlock());
262  };
263 
264  return makeKeyTuple(*this) < makeKeyTuple(other);
265  }
266  };
267 
268  bool operator<(MonitorElementData const& other) const { return this->key_ < other.key_; }
269 
270  // The only non class/struct members
273 };
274 
275 // For now, no additional (meta-)data is needed apart from the MEs themselves.
276 // The framework will take care of tracking the plugin and LS/run that the MEs
277 // belong to.
278 // Unused for now.
280  std::vector<std::unique_ptr<const MonitorElementData>> data_;
281 
282 public:
283  void push_back(std::unique_ptr<const MonitorElementData> value) {
284  // enforce ordering
285  assert(data_.empty() || data_[data_.size() - 1] <= value);
286  data_.push_back(std::move(value));
287  }
288 
289  void swap(MonitorElementCollection& other) { data_.swap(other.data_); }
290 
291  auto begin() const { return data_.begin(); }
292 
293  auto end() const { return data_.end(); }
294 
295  bool mergeProduct(MonitorElementCollection const& product) {
296  // discussion: https://twiki.cern.ch/twiki/bin/view/CMSPublic/SWGuidePerRunAndPerLumiBlockData#Merging_Run_and_Luminosity_Block
297  assert(!"Not implemented yet.");
298  return false;
299  // Things to decide:
300  // - Should we allow merging collections of different sets of MEs? (probably not.) [0]
301  // - Should we assume the MEs to be ordered? (probably yes.)
302  // - How to handle incompatible MEs (different binning)? (fail hard.) [1]
303  // - Can multiple MEs with same (dirname, objname) exist? (probably yes.) [2]
304  // - Shall we modify the (immutable?) ROOT objects? (probably yes.)
305  //
306  // [0] Merging should increase the statistics, but not change the number of
307  // MEs, at least with the current workflows. It might be convenient to
308  // allow it, but for the beginning, it would only mask errors.
309  // [1] The DQM framework should guarantee same booking parameters as long
310  // as we stay within the Scope of the MEs.
311  // [2] To implement e.g. MEs covering blocks of 10LS, we'd store them in a
312  // run product, but have as many MEs with same name but different range as
313  // needed to perserve the wanted granularity. Merging then can merge or
314  // concatenate as possible/needed.
315  // Problem: We need to keep copies in memory until the end of run, even
316  // though we could save them to the output file as soon as it is clear that
317  // the nexe LS will not fall into the same block. Instead, we could drop
318  // them into the next lumi block we see; the semantics would be weird (the
319  // MEs in the lumi block don't actually correspond to the lumi block they
320  // are in) but the DQMIO output should be able to handle that.
321  }
322 };
323 
324 #endif
QValue const & getValue() const
void swap(MonitorElementCollection &other)
edm::propagate_const< std::unique_ptr< TH1 > > object_
assert(be >=bs)
uint16_t size_type
std::vector< DQMChannel > badChannels_
int getStatus() const
get test status
const std::string & getAlgorithm() const
get quality test algorithm
const std::string & getMessage() const
get message attached to test
std::string const & getDirname() const
void set(std::string path, Path::Type type)
def move
Definition: eostools.py:511
std::vector< std::unique_ptr< const MonitorElementData > > data_
void push_back(std::unique_ptr< const MonitorElementData > value)
void setBadChannels(std::vector< DQMChannel > badChannels)
DQMChannel(int bx, int by, int bz, float data, float rms)
std::string const & getObjectname() const
bool operator<(Key const &other) const
float getQTresult() const
get test result i.e. prob value
const std::vector< DQMChannel > & getBadChannels() const
std::vector< QReport > qreports_
char data[epos_bytes_allocation]
Definition: EPOS_Wrapper.h:79
bool operator<(MonitorElementData const &other) const
QValue & getValue()
access underlying value
bool operator==(Path const &other) const
bool mergeProduct(MonitorElementCollection const &product)
const std::string & getQRName() const
get name of quality test