yoda is hosted by Hepforge, IPPP Durham
YODA - Yet more Objects for Data Analysis 2.0.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-2023 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#include <iomanip>
13#include <string>
14#include <limits>
15#include <map>
16
17namespace YODA {
18
19
22
23 public:
24
26 typedef std::map<std::string, std::string> Annotations;
27
28
31
34
36 AnalysisObject(const std::string& type, const std::string& path, const std::string& title="") {
37 setAnnotation("Type", type);
40 }
41
43 AnalysisObject(const std::string& type, const std::string& path,
44 const AnalysisObject& ao, const std::string& title="") {
46 setAnnotation("Type", type); // might override the copied ones
49 }
50
51 // /// Default copy constructor
52 // AnalysisObject(const AnalysisObject& ao) {
53 // if (ao.path().length() > 0) setPath(ao.path());
54 // if (ao.title().length() > 0) setTitle(ao.title());
55 // }
56
58 virtual ~AnalysisObject() { }
59
61 virtual AnalysisObject& operator = (const AnalysisObject& ao) noexcept {
62 for (const std::string& a : ao.annotations()) {
63 if (a == "Type") continue;
64 if (a == "Path" && !ao.path().length()) continue;
65 if (a == "Title" && !ao.title().length()) continue;
66 setAnnotation(a, ao.annotation(a));
67 }
68 return *this;
69 }
70
72 virtual AnalysisObject* newclone() const = 0;
73
75
76
77
80
82 virtual void reset() = 0;
83
85
88
90 virtual void _renderYODA(std::ostream& os, const int width = 13) const noexcept = 0;
91
93 virtual void _renderFLAT(std::ostream& os, const int width = 13) const noexcept = 0;
94
96 virtual std::string _config() const noexcept { return ""; }
97
99
100
101
104
107 std::vector<std::string> annotations() const {
108 std::vector<std::string> rtn;
109 rtn.reserve(_annotations.size());
110 for (const Annotations::value_type& kv : _annotations) rtn.push_back(kv.first);
111 return rtn;
112 }
113
114
116 bool hasAnnotation(const std::string& name) const {
117 return _annotations.find(name) != _annotations.end();
118 }
119
120
122 const std::string& annotation(const std::string& name) const {
123 Annotations::const_iterator v = _annotations.find(name);
124 // If not found... written this way round on purpose
125 if (v == _annotations.end()) {
126 std::string missing = "YODA::AnalysisObject: No annotation named " + name;
127 throw AnnotationError(missing);
128 }
129 return v->second;
130 }
131
132
134 const std::string& annotation(const std::string& name, const std::string& defaultreturn) const {
135 Annotations::const_iterator v = _annotations.find(name);
136 if (v != _annotations.end()) return v->second;
137 return defaultreturn;
138 }
139
140
144 template <typename T>
145 const T annotation(const std::string& name) const {
146 std::string s = annotation(name);
147 return Utils::lexical_cast<T>(s);
148 }
149
150
154 template <typename T>
155 const T annotation(const std::string& name, const T& defaultreturn) const {
156 try {
157 std::string s = annotation(name);
158 return Utils::lexical_cast<T>(s);
159 } catch (const AnnotationError& ae) {
160 return defaultreturn;
161 }
162 }
163
164
168 template <typename T>
169 void setAnnotation(const std::string& name, const T& value) {
170 if constexpr( std::is_floating_point<T>::value ) {
171 // Recipe from Boost docs
172 std::stringstream ss;
173 ss << std::setprecision(std::numeric_limits<double>::max_digits10) << std::scientific << value;
174 setAnnotation(name, ss.str());
175 }
176 else if constexpr( std::is_same<T, std::string>::value ) {
177 _annotations[name] = value;
178 }
179 else {
180 _annotations[name] = Utils::lexical_cast<std::string>(value);
181 }
182 }
183
184
186 void setAnnotations(const Annotations& anns) {
187 _annotations = anns;
188 }
189
190
194 template <typename T>
195 void addAnnotation(const std::string& name, const T& value) {
196 setAnnotation(name, value);
197 }
198
199
201 void rmAnnotation(const std::string& name) {
202 _annotations.erase(name);
203 }
204
205
208 _annotations.clear();
209 }
210
212
213
216
220 const std::string title() const {
221 return annotation("Title", "");
222 }
223
225 void setTitle(const std::string& title) {
226 setAnnotation("Title", title);
227 }
228
233 const std::string path() const {
234 const std::string p = annotation("Path", "");
235 // If not set at all, return an empty string
236 if (p.empty()) return p;
237 // If missing a leading slash, one will be prepended
238 return p.find("/") == 0 ? p : ("/"+p);
239 }
240
244 void setPath(const std::string& path) {
245 const std::string p = (path.find("/") == 0) ? path : "/"+path;
246 // if (path.length() > 0 && path.find("/") != 0) {
247 // throw AnnotationError("Histo paths must start with a slash (/) character.");
248 // }
249 setAnnotation("Path", p);
250 }
251
252
255 const std::string name() const {
256 const std::string p = path();
257 const size_t lastslash = p.rfind("/");
258 if (lastslash == std::string::npos) return p;
259 return p.substr(lastslash+1);
260 }
261
263
264
265 public:
266
269
271 virtual std::string type() const {
272 return annotation("Type");
273 }
274
279 virtual size_t dim() const noexcept = 0;
280
282 virtual AnalysisObject* mkInert(const std::string& path = "",
283 const std::string& source = "") const noexcept {
284 (void)source;
285 AnalysisObject* rtn = this->newclone();
286 rtn->setPath(path);
287 return rtn;
288 }
289
291
294
296 virtual size_t lengthContent(bool fixed_length = false) const noexcept = 0;
297
299 virtual std::vector<double> serializeContent(bool fixed_length = false) const noexcept = 0;
300
302 virtual void deserializeContent(const std::vector<double>& data) = 0;
303
305 size_t lengthMeta(const bool skipPath = true,
306 const bool skipTitle = true) const noexcept {
307 return 2*(_annotations.size() - skipPath - skipTitle);
308 }
309
311 std::vector<std::string> serializeMeta(const bool skipPath = true,
312 const bool skipTitle = true) const noexcept {
313
314 // Assemble annotations
315 std::vector<std::string> rtn;
316 rtn.reserve(2*(_annotations.size() - skipPath - skipTitle));
317 for (const auto& item : _annotations) {
318 if (item.first == "Type") continue;
319 if (skipPath && item.first == "Path") continue;
320 if (skipTitle && item.first == "Title") continue;
321 rtn.push_back(item.first);
322 rtn.push_back(item.second);
323 }
324 return rtn;
325 }
326
328 virtual void deserializeMeta(const std::vector<std::string>& data,
329 const bool resetPath = false, const bool resetTitle = false) {
330
331 if (data.empty()) return;
332 if (data.size() % 2)
333 throw UserError("Expected even number of annotation elements (key-value pairs)!");
334
335 const std::string path = annotation("Path");
336 const std::string type = annotation("Type");
337 const std::string title = annotation("Title");
338 _annotations.clear();
339 _annotations["Type"] = type;
340 if (!resetPath) _annotations["Path"] = path;
341 if (!resetTitle) _annotations["Title"] = title;
342
343 auto itr = data.cbegin();
344 const auto itrEnd = data.cend();
345 while (itr != itrEnd) {
346 const std::string key = *itr; ++itr;
347 const std::string val = *itr; ++itr;
348 _annotations[key] = val;
349 }
350 }
351
353
354 private:
355
357 std::map<std::string,std::string> _annotations;
358
359 };
360
361
364
365
366}
367
368#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
Mate-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.
Error for unfound or broken AnalysisObject annotations.
Definition Exceptions.h:79
Error for problems introduced outside YODA, to put it nicely.
Definition Exceptions.h:100
Anonymous namespace to limit visibility.