yoda is hosted by Hepforge, IPPP Durham
YODA - Yet more Objects for Data Analysis 2.1.0
AnalysisObject.h
Go to the documentation of this file.
1// -*- C++ -*-
2//
3// This file is part of YODA -- Yet more Objects for Data Analysis
4// Copyright (C) 2008-2025 The YODA collaboration (see AUTHORS for details)
5//
6#ifndef YODA_AnalysisObject_h
7#define YODA_AnalysisObject_h
8
9#include "YODA/Exceptions.h"
12
13#ifdef HAVE_HDF5
14#include "YODA/Utils/H5Utils.h"
15#endif
16
17#include <iomanip>
18#include <string>
19#include <limits>
20#include <map>
21
22namespace YODA {
23
24
27
28 public:
29
31 typedef std::map<std::string, std::string> Annotations;
32
33
36
39
41 AnalysisObject(const std::string& type, const std::string& path, const std::string& title="") {
42 setAnnotation("Type", type);
45 }
46
48 AnalysisObject(const std::string& type, const std::string& path,
49 const AnalysisObject& ao, const std::string& title="") {
51 setAnnotation("Type", type); // might override the copied ones
54 }
55
56 // /// Default copy constructor
57 // AnalysisObject(const AnalysisObject& ao) {
58 // if (ao.path().length() > 0) setPath(ao.path());
59 // if (ao.title().length() > 0) setTitle(ao.title());
60 // }
61
63 virtual ~AnalysisObject() { }
64
66 virtual AnalysisObject& operator = (const AnalysisObject& ao) noexcept {
67 for (const std::string& a : ao.annotations()) {
68 if (a == "Type") continue;
69 if (a == "Path" && !ao.path().length()) continue;
70 if (a == "Title" && !ao.title().length()) continue;
71 setAnnotation(a, ao.annotation(a));
72 }
73 return *this;
74 }
75
77 virtual AnalysisObject* newclone() const = 0;
78
80
81
82
85
87 virtual void reset() = 0;
88
90
93
95 virtual void _renderYODA(std::ostream& os, const int width = 13) const noexcept = 0;
96
98 virtual void _renderFLAT(std::ostream& os, const int width = 13) const noexcept = 0;
99
100 #ifdef HAVE_HDF5
101
103 virtual void _extractLabels(std::vector<std::string>&, std::vector<size_t>&) const noexcept { };
104
106 virtual void _extractEdges(std::map<std::string, EdgeHandlerBasePtr>&,
107 const std::vector<std::string>&) const noexcept { };
108
109 #endif
110
112 virtual std::string _config() const noexcept { return ""; }
113
115
116
117
120
123 std::vector<std::string> annotations() const {
124 std::vector<std::string> rtn;
125 rtn.reserve(_annotations.size());
126 for (const Annotations::value_type& kv : _annotations) rtn.push_back(kv.first);
127 return rtn;
128 }
129
130
132 bool hasAnnotation(const std::string& name) const {
133 return _annotations.find(name) != _annotations.end();
134 }
135
136
138 const std::string& annotation(const std::string& name) const {
139 Annotations::const_iterator v = _annotations.find(name);
140 // If not found... written this way round on purpose
141 if (v == _annotations.end()) {
142 std::string missing = "YODA::AnalysisObject: No annotation named " + name;
143 throw AnnotationError(missing);
144 }
145 return v->second;
146 }
147
148
150 const std::string& annotation(const std::string& name, const std::string& defaultreturn) const {
151 Annotations::const_iterator v = _annotations.find(name);
152 if (v != _annotations.end()) return v->second;
153 return defaultreturn;
154 }
155
156
160 template <typename T>
161 const T annotation(const std::string& name) const {
162 std::string s = annotation(name);
163 return Utils::lexical_cast<T>(s);
164 }
165
166
170 template <typename T>
171 const T annotation(const std::string& name, const T& defaultreturn) const {
172 Annotations::const_iterator v = _annotations.find(name);
173 if (v != _annotations.end()) return Utils::lexical_cast<T>(v->second);
174 return defaultreturn;
175 }
176
177
181 template <typename T>
182 void setAnnotation(const std::string& name, const T& value) {
183 if constexpr( std::is_floating_point<T>::value ) {
184 // Recipe from Boost docs
185 std::stringstream ss;
186 ss << std::setprecision(std::numeric_limits<double>::max_digits10) << std::scientific << value;
187 setAnnotation(name, ss.str());
188 }
189 else if constexpr( std::is_same<T, std::string>::value ) {
190 _annotations[name] = value;
191 }
192 else {
193 _annotations[name] = Utils::lexical_cast<std::string>(value);
194 }
195 }
196
197
199 void setAnnotations(const Annotations& anns) {
200 _annotations = anns;
201 }
202
203
207 template <typename T>
208 void addAnnotation(const std::string& name, const T& value) {
209 setAnnotation(name, value);
210 }
211
212
214 void rmAnnotation(const std::string& name) {
215 _annotations.erase(name);
216 }
217
218
221 _annotations.clear();
222 }
223
225
226
229
233 const std::string title() const {
234 return annotation("Title", "");
235 }
236
238 void setTitle(const std::string& title) {
239 setAnnotation("Title", title);
240 }
241
246 const std::string path() const {
247 const std::string p = annotation("Path", "");
248 // If not set at all, return an empty string
249 if (p.empty()) return p;
250 // If missing a leading slash, one will be prepended
251 return p.find("/") == 0 ? p : ("/"+p);
252 }
253
257 void setPath(const std::string& path) {
258 const std::string p = (path.find("/") == 0) ? path : "/"+path;
259 // if (path.length() > 0 && path.find("/") != 0) {
260 // throw AnnotationError("Histo paths must start with a slash (/) character.");
261 // }
262 setAnnotation("Path", p);
263 }
264
265
268 const std::string name() const {
269 const std::string p = path();
270 const size_t lastslash = p.rfind("/");
271 if (lastslash == std::string::npos) return p;
272 return p.substr(lastslash+1);
273 }
274
276
277
278 public:
279
282
284 virtual std::string type() const {
285 return annotation("Type");
286 }
287
292 virtual size_t dim() const noexcept = 0;
293
295 virtual AnalysisObject* mkInert(const std::string& path = "",
296 const std::string& source = "") const noexcept {
297 (void)source;
298 AnalysisObject* rtn = this->newclone();
299 rtn->setPath(path);
300 return rtn;
301 }
302
304
307
309 virtual size_t lengthContent(bool fixed_length = false) const noexcept = 0;
310
312 virtual std::vector<double> serializeContent(bool fixed_length = false) const noexcept = 0;
313
315 virtual void deserializeContent(const std::vector<double>& data) = 0;
316
318 size_t lengthMeta(const bool skipPath = true,
319 const bool skipTitle = true) const noexcept {
320 return 2*(_annotations.size() - skipPath - skipTitle);
321 }
322
324 std::vector<std::string> serializeMeta(const bool skipPath = true,
325 const bool skipTitle = true) const noexcept {
326
327 // Assemble annotations
328 std::vector<std::string> rtn;
329 rtn.reserve(2*(_annotations.size() - skipPath - skipTitle));
330 for (const auto& item : _annotations) {
331 if (item.first == "Type") continue;
332 if (skipPath && item.first == "Path") continue;
333 if (skipTitle && item.first == "Title") continue;
334 rtn.push_back(item.first);
335 rtn.push_back(item.second);
336 }
337 return rtn;
338 }
339
341 virtual void deserializeMeta(const std::vector<std::string>& data,
342 const bool resetPath = false, const bool resetTitle = false) {
343
344 if (data.empty()) return;
345 if (data.size() % 2)
346 throw UserError("Expected even number of annotation elements (key-value pairs)!");
347
348 const std::string path = annotation("Path");
349 const std::string type = annotation("Type");
350 const std::string title = annotation("Title");
351 _annotations.clear();
352 _annotations["Type"] = type;
353 if (!resetPath) _annotations["Path"] = path;
354 if (!resetTitle) _annotations["Title"] = title;
355
356 auto itr = data.cbegin();
357 const auto itrEnd = data.cend();
358 while (itr != itrEnd) {
359 const std::string key = *itr; ++itr;
360 const std::string val = *itr; ++itr;
361 _annotations[key] = val;
362 }
363 }
364
366
367 private:
368
370 std::map<std::string,std::string> _annotations;
371
372 };
373
374
377
378
379}
380
381#endif // YODA_AnalysisObject_h
AnalysisObject is the base class for histograms and scatters.
size_t lengthMeta(const bool skipPath=true, const bool skipTitle=true) const noexcept
Length of serialized meta-data vector for MPI reduce operations.
virtual void deserializeContent(const std::vector< double > &data)=0
Content deserialisation for MPI reduce operations.
AnalysisObject(const std::string &type, const std::string &path, const AnalysisObject &ao, const std::string &title="")
Constructor giving a type, a path, another AO to copy annotation from, and an optional title.
void setAnnotations(const Annotations &anns)
Set all annotations at once.
virtual void reset()=0
Reset this analysis object.
virtual ~AnalysisObject()
Default destructor.
virtual AnalysisObject & operator=(const AnalysisObject &ao) noexcept
Default copy assignment operator.
virtual std::vector< double > serializeContent(bool fixed_length=false) const noexcept=0
Content serialisation for MPI reduce operations.
virtual size_t lengthContent(bool fixed_length=false) const noexcept=0
Length of serialized content vector for MPI reduce operations.
std::vector< std::string > serializeMeta(const bool skipPath=true, const bool skipTitle=true) const noexcept
Meta-data serialisation for MPI reduce operations.
virtual std::string type() const
Get name of the analysis object type.
void setAnnotation(const std::string &name, const T &value)
Add or set an annotation by name (templated for remaining types)
virtual void deserializeMeta(const std::vector< std::string > &data, const bool resetPath=false, const bool resetTitle=false)
Mate-data deserialisation for MPI reduce operations.
void setPath(const std::string &path)
const T annotation(const std::string &name, const T &defaultreturn) const
Get an annotation by name (copied to another type) with a default in case the annotation is not found...
const std::string title() const
Get the AO title.
AnalysisObject(const std::string &type, const std::string &path, const std::string &title="")
Constructor giving a type, a path and an optional title.
void addAnnotation(const std::string &name, const T &value)
Add or set an annotation by name.
virtual AnalysisObject * mkInert(const std::string &path="", const std::string &source="") const noexcept
Return an inert version of the analysis object (e.g. scatter, estimate)
std::vector< std::string > annotations() const
virtual size_t dim() const noexcept=0
Get the dimension of the analysis object type.
void clearAnnotations()
Delete an annotation by name.
const std::string name() const
void setTitle(const std::string &title)
Set the AO title.
const std::string path() const
Get the AO path.
void rmAnnotation(const std::string &name)
Delete an annotation by name.
const T annotation(const std::string &name) const
Get an annotation by name (copied to another type)
const std::string & annotation(const std::string &name) const
Get an annotation by name (as a string)
virtual AnalysisObject * newclone() const =0
Make a copy on the heap, via 'new'.
bool hasAnnotation(const std::string &name) const
Check if an annotation is defined.
std::map< std::string, std::string > Annotations
Collection type for annotations, as a string-string map.
AnalysisObject()
Default constructor.
const std::string & annotation(const std::string &name, const std::string &defaultreturn) const
Get an annotation by name (as a string) with a default in case the annotation is not found.
Errors relating to insufficient (effective) statistics.
Definition Exceptions.h:65
Error for problems introduced outside YODA, to put it nicely.
Definition Exceptions.h:86
Anonymous namespace to limit visibility.