yoda is hosted by Hepforge, IPPP Durham
YODA - Yet more Objects for Data Analysis 2.0.2
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-2024 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 Annotations::const_iterator v = _annotations.find(name);
157 if (v != _annotations.end()) return Utils::lexical_cast<T>(v->second);
158 return defaultreturn;
159 }
160
161
165 template <typename T>
166 void setAnnotation(const std::string& name, const T& value) {
167 if constexpr( std::is_floating_point<T>::value ) {
168 // Recipe from Boost docs
169 std::stringstream ss;
170 ss << std::setprecision(std::numeric_limits<double>::max_digits10) << std::scientific << value;
171 setAnnotation(name, ss.str());
172 }
173 else if constexpr( std::is_same<T, std::string>::value ) {
174 _annotations[name] = value;
175 }
176 else {
177 _annotations[name] = Utils::lexical_cast<std::string>(value);
178 }
179 }
180
181
183 void setAnnotations(const Annotations& anns) {
184 _annotations = anns;
185 }
186
187
191 template <typename T>
192 void addAnnotation(const std::string& name, const T& value) {
193 setAnnotation(name, value);
194 }
195
196
198 void rmAnnotation(const std::string& name) {
199 _annotations.erase(name);
200 }
201
202
205 _annotations.clear();
206 }
207
209
210
213
217 const std::string title() const {
218 return annotation("Title", "");
219 }
220
222 void setTitle(const std::string& title) {
223 setAnnotation("Title", title);
224 }
225
230 const std::string path() const {
231 const std::string p = annotation("Path", "");
232 // If not set at all, return an empty string
233 if (p.empty()) return p;
234 // If missing a leading slash, one will be prepended
235 return p.find("/") == 0 ? p : ("/"+p);
236 }
237
241 void setPath(const std::string& path) {
242 const std::string p = (path.find("/") == 0) ? path : "/"+path;
243 // if (path.length() > 0 && path.find("/") != 0) {
244 // throw AnnotationError("Histo paths must start with a slash (/) character.");
245 // }
246 setAnnotation("Path", p);
247 }
248
249
252 const std::string name() const {
253 const std::string p = path();
254 const size_t lastslash = p.rfind("/");
255 if (lastslash == std::string::npos) return p;
256 return p.substr(lastslash+1);
257 }
258
260
261
262 public:
263
266
268 virtual std::string type() const {
269 return annotation("Type");
270 }
271
276 virtual size_t dim() const noexcept = 0;
277
279 virtual AnalysisObject* mkInert(const std::string& path = "",
280 const std::string& source = "") const noexcept {
281 (void)source;
282 AnalysisObject* rtn = this->newclone();
283 rtn->setPath(path);
284 return rtn;
285 }
286
288
291
293 virtual size_t lengthContent(bool fixed_length = false) const noexcept = 0;
294
296 virtual std::vector<double> serializeContent(bool fixed_length = false) const noexcept = 0;
297
299 virtual void deserializeContent(const std::vector<double>& data) = 0;
300
302 size_t lengthMeta(const bool skipPath = true,
303 const bool skipTitle = true) const noexcept {
304 return 2*(_annotations.size() - skipPath - skipTitle);
305 }
306
308 std::vector<std::string> serializeMeta(const bool skipPath = true,
309 const bool skipTitle = true) const noexcept {
310
311 // Assemble annotations
312 std::vector<std::string> rtn;
313 rtn.reserve(2*(_annotations.size() - skipPath - skipTitle));
314 for (const auto& item : _annotations) {
315 if (item.first == "Type") continue;
316 if (skipPath && item.first == "Path") continue;
317 if (skipTitle && item.first == "Title") continue;
318 rtn.push_back(item.first);
319 rtn.push_back(item.second);
320 }
321 return rtn;
322 }
323
325 virtual void deserializeMeta(const std::vector<std::string>& data,
326 const bool resetPath = false, const bool resetTitle = false) {
327
328 if (data.empty()) return;
329 if (data.size() % 2)
330 throw UserError("Expected even number of annotation elements (key-value pairs)!");
331
332 const std::string path = annotation("Path");
333 const std::string type = annotation("Type");
334 const std::string title = annotation("Title");
335 _annotations.clear();
336 _annotations["Type"] = type;
337 if (!resetPath) _annotations["Path"] = path;
338 if (!resetTitle) _annotations["Title"] = title;
339
340 auto itr = data.cbegin();
341 const auto itrEnd = data.cend();
342 while (itr != itrEnd) {
343 const std::string key = *itr; ++itr;
344 const std::string val = *itr; ++itr;
345 _annotations[key] = val;
346 }
347 }
348
350
351 private:
352
354 std::map<std::string,std::string> _annotations;
355
356 };
357
358
361
362
363}
364
365#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.