SST  14.1.0
StructuralSimulationToolkit
unitAlgebra.h
1 // -*- c++ -*-
2 
3 // Copyright 2009-2024 NTESS. Under the terms
4 // of Contract DE-NA0003525 with NTESS, the U.S.
5 // Government retains certain rights in this software.
6 //
7 // Copyright (c) 2009-2024, NTESS
8 // All rights reserved.
9 //
10 // This file is part of the SST software package. For license
11 // information, see the LICENSE file in the top level directory of the
12 // distribution.
13 
14 #ifndef SST_CORE_UNITALGEBRA_H
15 #define SST_CORE_UNITALGEBRA_H
16 
17 #include "sst/core/decimal_fixedpoint.h"
18 #include "sst/core/serialization/objectMap.h"
19 #include "sst/core/serialization/serialize.h"
20 #include "sst/core/serialization/serializer.h"
21 #include "sst/core/sst_types.h"
22 #include "sst/core/warnmacros.h"
23 
24 #include <map>
25 #include <mutex>
26 #include <string>
27 #include <vector>
28 
29 namespace SST {
30 
31 typedef decimal_fixedpoint<3, 3> sst_big_num;
32 
33 /**
34  * Helper class internal to UnitAlgebra.
35  *
36  * Contains information on valid units
37  */
38 class Units
39 {
40 
41  typedef uint8_t unit_id_t;
42 
43 private:
44  friend class UnitAlgebra;
45 
46  // Static data members and functions
47  static std::recursive_mutex unit_lock;
48  static std::map<std::string, unit_id_t> valid_base_units;
49  static std::map<std::string, std::pair<Units, sst_big_num>> valid_compound_units;
50  static std::map<unit_id_t, std::string> unit_strings;
51  static unit_id_t count;
52  static bool initialized;
53 
54  static bool initialize();
55 
56  // Non-static data members and functions
57  std::vector<unit_id_t> numerator;
58  std::vector<unit_id_t> denominator;
59 
60  void reduce();
61  // Used in constructor to incrementally build up unit from string
62  void addUnit(const std::string&, sst_big_num& multiplier, bool invert);
63 
64 public:
65  // Static data members and functions
66  /** Create a new Base Unit type */
67  static void registerBaseUnit(const std::string& u);
68  /** Create a new Compound Unit type */
69  static void registerCompoundUnit(const std::string& u, const std::string& v);
70 
71  // Non-static data members and functions
72  /** Create a new instantiation of a Units with a base unit string, and multiplier
73  * @param units String representing the new unit
74  * @param multiplier Value by which to multiply to get to this unit
75  */
76  Units(const std::string& units, sst_big_num& multiplier);
77  Units() {}
78  virtual ~Units() {}
79 
80  /** Copy constructor */
81  Units(const Units&) = default;
82 
83  /** Assignment operator */
84  Units& operator=(const Units& v);
85  /** Self-multiplication operator */
86  Units& operator*=(const Units& v);
87  /** Self-division operator */
88  Units& operator/=(const Units& v);
89  /** Equality Operator */
90  bool operator==(const Units& lhs) const;
91  /** Inequality Operator */
92  bool operator!=(const Units& lhs) const { return !(*this == lhs); }
93  /** Perform a reciprocal operation. Numerator and Denominator swap. */
94  Units& invert();
95 
96  /** Return a String representation if this Unit */
97  std::string toString() const;
98 };
99 
100 /**
101  * Performs Unit math in full precision
102  *
103  * Allows operations such as multiplying a frequency by 2.
104  *
105  */
107 {
108 private:
109  Units unit;
110  sst_big_num value;
111 
112  static std::string trim(const std::string& str);
113 
114 public:
115  void init(const std::string& val);
116 
117  UnitAlgebra() {}
118  /**
119  Create a new UnitAlgebra instance, and pre-populate with a parsed value.
120 
121  @param val Value to parse. It is of the following format:
122  @code
123  val := NUMBER( )?UNITS
124  NUMBER := (-)?[0-9]+(.[0-9]+)?
125  UNITS := UNITGROUP(/UNITGROUP)
126  UNITGROUP := UNIT(-UNIT)*
127  UNIT := (SIPREFIX)?(BASEUNIT|COMPUNIT)
128  SIPREFIX := {a,f,p,n,u,m,[kKMGTPE]i?}
129  BASEUNIT := {s,B,b,events}
130  COMPUNIT := {Hz,hz,Bps,bps,event}
131  @endcode
132  */
133  UnitAlgebra(const std::string& val);
134  virtual ~UnitAlgebra();
135 
136  /** Copy constructor */
137  UnitAlgebra(const UnitAlgebra&) = default;
138 
139  /** Print to an ostream the value
140  * @param stream Output stream
141  * @param precision Number of digits to print. Default is 6. <= 0 is full precision.
142  */
143  void print(std::ostream& stream, int32_t precision = 6);
144  /** Print to an ostream the value
145  * Formats the number using SI-prefixes
146  * @param stream Output stream
147  * @param precision Number of digits to print. Default is 6. <= 0 is full precision.
148  */
149  void printWithBestSI(std::ostream& stream, int32_t precision = 6);
150  /** Return a string representation of this value
151  * @param precision Number of digits to print. Default is 6. <= 0 is full precision.
152  */
153  std::string toString(int32_t precision = 6) const;
154  /** Return a string representation of this value
155  * Formats the number using SI-prefixes
156  * @param precision Number of digits to print. Default is 6. <= 0 is full precision.
157  */
158  std::string toStringBestSI(int32_t precision = 6) const;
159 
160  UnitAlgebra& operator=(const std::string& v);
161 
162  /** Multiply by an argument; */
164  /** Multiply by an argument; */
165  template <typename T>
166  UnitAlgebra& operator*=(const T& v)
167  {
168  value *= v;
169  return *this;
170  }
171 
172  /** Divide by an argument; */
174  /** Divide by an argument; */
175  template <typename T>
176  UnitAlgebra& operator/=(const T& v)
177  {
178  value /= v;
179  return *this;
180  }
181 
182  /** Add an argument; */
184  /** Multiply by an argument; */
185  template <typename T>
186  UnitAlgebra& operator+=(const T& v)
187  {
188  value += v;
189  return *this;
190  }
191 
192  /** Subtract an argument; */
194  /** Divide by an argument; */
195  template <typename T>
196  UnitAlgebra& operator-=(const T& v)
197  {
198  value -= v;
199  return *this;
200  }
201 
202  /** Compare if this object is greater than the argument */
203  bool operator>(const UnitAlgebra& v) const;
204  /** Compare if this object is greater than, or equal to, the argument */
205  bool operator>=(const UnitAlgebra& v) const;
206  /** Compare if this object is less than the argument */
207  bool operator<(const UnitAlgebra& v) const;
208  /** Compare if this object is less than, or equal to, the argument */
209  bool operator<=(const UnitAlgebra& v) const;
210  /** Compare if this object is equal to, the argument */
211  bool operator==(const UnitAlgebra& v) const;
212  /** Compare if this object is not equal to, the argument */
213  bool operator!=(const UnitAlgebra& v) const;
214  /** Apply a reciprocal operation to the object */
215  UnitAlgebra& invert();
216 
217  /** Returns true if the units in the parameter string are found
218  * in this object.
219  */
220  bool hasUnits(const std::string& u) const;
221  /** Return the raw value */
222  sst_big_num getValue() const { return value; }
223  /** @return Rounded value as a 64bit integer */
224  int64_t getRoundedValue() const;
225  double getDoubleValue() const;
226  bool isValueZero() const;
227 
228  void serialize_order(SST::Core::Serialization::serializer& ser) /* override */
229  {
230  // Do the unit
231  ser& unit.numerator;
232  ser& unit.denominator;
233 
234  // For value, need to convert cpp_dec_float to string and
235  // reinit from string
236  switch ( ser.mode() ) {
237  case SST::Core::Serialization::serializer::SIZER:
238  case SST::Core::Serialization::serializer::PACK:
239  {
240  // std::string s = value.str(40, std::ios_base::fixed);
241  std::string s = value.toString(0);
242  ser& s;
243  break;
244  }
245  case SST::Core::Serialization::serializer::UNPACK:
246  {
247  std::string s;
248  ser& s;
249  value = sst_big_num(s);
250  break;
251  }
252  case SST::Core::Serialization::serializer::MAP:
253  // Add your code here
254  break;
255  }
256  }
257 
258 public:
259  /** Base exception for all exception classes in UnitAlgebra
260  *
261  * This exception inherits from std::logic_error, as all exceptions
262  * thrown in UnitAlgebra are considered configuration errors occurring
263  * prior to simulation start, rather than runtime errors.
264  */
265  class UnitAlgebraException : public std::logic_error
266  {
267  public:
268  /**
269  * @param msg exception message displayed as-is without modification
270  */
271  UnitAlgebraException(const std::string& msg);
272  };
273 
274  /** Exception for when units are not recognized or are invalid
275  */
277  {
278  public:
279  /**
280  * @param type string containing invalid type
281  */
282  InvalidUnitType(const std::string& type);
283  };
284 
285  /** Exception for when number couldn't be parsed
286  */
288  {
289  public:
290  /**
291  * @param number string containing invalid number
292  */
293  InvalidNumberString(const std::string& number);
294  };
295 
296  /** Exception for when attempting operations between objects that do not have matching base units
297  */
299  {
300  public:
301  /**
302  * @param lhs units for UnitAlgebra on left-hand side of operation
303  * @param rhs units for UnitAlgebra on right-hand side of operation
304  * @param operation representation of operation attempted between units
305  */
306  NonMatchingUnits(const std::string& lhs, const std::string& rhs, const std::string& operation);
307  };
308 };
309 
310 // template <typename T>
311 // UnitAlgebra operator* (UnitAlgebra lhs, const T& rhs);
312 
313 // template <typename T>
314 // UnitAlgebra operator* (const T& lhs, UnitAlgebra rhs);
315 
316 // UnitAlgebra operator* (UnitAlgebra& lhs, const UnitAlgebra rhs);
317 
318 // template <typename T>
319 // UnitAlgebra operator/ (UnitAlgebra lhs, const T& rhs);
320 
321 // std::ostream& operator<< (std::ostream& os, const UnitAlgebra& r);
322 
323 // std::ostream& operator<< (std::ostream& os, const Units& r);
324 
325 template <typename T>
327 operator*(UnitAlgebra lhs, const T& rhs)
328 {
329  lhs *= rhs;
330  return lhs;
331 }
332 
333 // template <typename T>
334 // UnitAlgebra operator* (const T& lhs, UnitAlgebra rhs)
335 // {
336 // rhs *= lhs;
337 // return rhs;
338 // }
339 
340 inline UnitAlgebra
341 operator*(UnitAlgebra lhs, const UnitAlgebra& rhs)
342 {
343  lhs *= rhs;
344  return lhs;
345 }
346 
347 template <typename T>
348 UnitAlgebra
349 operator/(UnitAlgebra lhs, const T& rhs)
350 {
351  lhs /= rhs;
352  return lhs;
353 }
354 
355 inline UnitAlgebra
356 operator/(UnitAlgebra lhs, const UnitAlgebra& rhs)
357 {
358  lhs /= rhs;
359  return lhs;
360 }
361 
362 template <typename T>
363 UnitAlgebra
364 operator+(UnitAlgebra lhs, const T& rhs)
365 {
366  lhs += rhs;
367  return lhs;
368 }
369 
370 inline UnitAlgebra
371 operator+(UnitAlgebra lhs, const UnitAlgebra& rhs)
372 {
373  lhs += rhs;
374  return lhs;
375 }
376 
377 template <typename T>
378 UnitAlgebra
379 operator-(UnitAlgebra lhs, const T& rhs)
380 {
381  lhs -= rhs;
382  return lhs;
383 }
384 
385 inline UnitAlgebra
386 operator-(UnitAlgebra lhs, const UnitAlgebra& rhs)
387 {
388  lhs -= rhs;
389  return lhs;
390 }
391 
392 inline std::ostream&
393 operator<<(std::ostream& os, const UnitAlgebra& r)
394 {
395  os << r.toString();
396  return os;
397 }
398 
399 inline std::ostream&
400 operator<<(std::ostream& os, const Units& r)
401 {
402  os << r.toString();
403  return os;
404 }
405 
406 
407 namespace Core {
408 namespace Serialization {
409 
410 template <>
412 {
413 protected:
414  /**
415  Address of the variable for reading and writing
416  */
417  UnitAlgebra* addr_ = nullptr;
418 
419 public:
420  std::string get() override { return addr_->toStringBestSI(); }
421  void set_impl(const std::string& value) override { addr_->init(value); }
422 
423  // We'll act like we're a fundamental type
424  bool isFundamental() override { return true; }
425 
426  /**
427  Get the address of the variable represented by the ObjectMap
428 
429  @return Address of varaible
430  */
431  void* getAddr() override { return addr_; }
432 
433 
434  /**
435  Get the list of child variables contained in this ObjectMap,
436  which in this case will be empty.
437 
438  @return Refernce to vector containing ObjectMaps for this
439  ObjectMap's child variables. This vector will be empty because
440  fundamentals have no children
441  */
442  const std::vector<std::pair<std::string, ObjectMap*>>& getVariables() override { return emptyVars; }
443 
444  ObjectMapFundamental(UnitAlgebra* addr) : ObjectMap(), addr_(addr) {}
445 
446  std::string getType() override { return demangle_name(typeid(UnitAlgebra).name()); }
447 };
448 
449 template <>
451 {
452  template <class A>
453  friend class serialize;
454 
455  void operator()(UnitAlgebra& ua, serializer& ser)
456  {
457  switch ( ser.mode() ) {
458  case serializer::SIZER:
459  case serializer::PACK:
460  case serializer::UNPACK:
461  ua.serialize_order(ser);
462  break;
463  case serializer::MAP:
464  // Add your code here
465  break;
466  }
467  }
468 
469  void operator()(UnitAlgebra& ua, serializer& ser, const char* name)
470  {
471  ObjectMap* obj_map = new ObjectMapFundamental<UnitAlgebra>(&ua);
472  ser.mapper().map_primitive(name, obj_map);
473  }
474 };
475 
476 
477 } // namespace Serialization
478 } // namespace Core
479 
480 
481 } // namespace SST
482 
483 #endif // SST_CORE_UNITALGEBRA_H
Units & operator*=(const Units &v)
Self-multiplication operator.
Definition: unitAlgebra.cc:244
void * getAddr() override
Get the address of the variable represented by the ObjectMap.
Definition: unitAlgebra.h:431
UnitAlgebra & operator/=(const UnitAlgebra &v)
Divide by an argument;.
Definition: unitAlgebra.cc:432
This class is basically a wrapper for objects to declare the order in which their members should be s...
Definition: serializer.h:43
bool operator<=(const UnitAlgebra &v) const
Compare if this object is less than, or equal to, the argument.
Definition: unitAlgebra.cc:480
bool operator>=(const UnitAlgebra &v) const
Compare if this object is greater than, or equal to, the argument.
Definition: unitAlgebra.cc:463
std::string toString(int32_t precision=6) const
Create a string representation of this decimal_fixedpoint.
Definition: decimal_fixedpoint.h:440
static std::vector< std::pair< std::string, ObjectMap * > > emptyVars
Static empty variable vector for use by versions that don&#39;t have variables (i.e.
Definition: objectMap.h:70
ObjectMap object fundamental types, and classes treated as fundamental types.
Definition: objectMap.h:501
T * addr_
Address of the variable for reading and writing.
Definition: objectMap.h:507
bool isFundamental() override
Check to see if this ObjectMap represents a fundamental or a class treated as a fundamental.
Definition: unitAlgebra.h:424
bool operator>(const UnitAlgebra &v) const
Compare if this object is greater than the argument.
Definition: unitAlgebra.cc:456
Base serialize class.
Definition: serialize.h:45
Definition: action.cc:18
UnitAlgebra & operator+=(const T &v)
Multiply by an argument;.
Definition: unitAlgebra.h:186
Units & operator=(const Units &v)
Assignment operator.
Definition: unitAlgebra.cc:236
static void registerBaseUnit(const std::string &u)
Create a new Base Unit type.
Definition: unitAlgebra.cc:183
sst_big_num getValue() const
Return the raw value.
Definition: unitAlgebra.h:222
const std::vector< std::pair< std::string, ObjectMap * > > & getVariables() override
Get the list of child variables contained in this ObjectMap, which in this case will be empty...
Definition: unitAlgebra.h:442
Class created by the serializer mapping mode used to map the variables for objects.
Definition: objectMap.h:61
Exception for when number couldn&#39;t be parsed.
Definition: unitAlgebra.h:287
Units & invert()
Perform a reciprocal operation.
Definition: unitAlgebra.cc:278
bool operator<(const UnitAlgebra &v) const
Compare if this object is less than the argument.
Definition: unitAlgebra.cc:473
Serialization "gateway" object.
Definition: serialize.h:133
UnitAlgebra & operator*=(const T &v)
Multiply by an argument;.
Definition: unitAlgebra.h:166
void print(std::ostream &stream, int32_t precision=6)
Print to an ostream the value.
Definition: unitAlgebra.cc:375
bool operator==(const UnitAlgebra &v) const
Compare if this object is equal to, the argument.
Definition: unitAlgebra.cc:487
Base exception for all exception classes in UnitAlgebra.
Definition: unitAlgebra.h:265
bool operator!=(const Units &lhs) const
Inequality Operator.
Definition: unitAlgebra.h:92
NonMatchingUnits(const std::string &lhs, const std::string &rhs, const std::string &operation)
Definition: unitAlgebra.cc:554
InvalidUnitType(const std::string &type)
Definition: unitAlgebra.cc:546
Exception for when attempting operations between objects that do not have matching base units...
Definition: unitAlgebra.h:298
UnitAlgebra & operator-=(const T &v)
Divide by an argument;.
Definition: unitAlgebra.h:196
InvalidNumberString(const std::string &number)
Definition: unitAlgebra.cc:550
UnitAlgebraException(const std::string &msg)
Definition: unitAlgebra.cc:544
bool operator==(const Units &lhs) const
Equality Operator.
Definition: unitAlgebra.cc:264
Exception for when units are not recognized or are invalid.
Definition: unitAlgebra.h:276
UnitAlgebra & invert()
Apply a reciprocal operation to the object.
Definition: unitAlgebra.cc:501
std::string getType() override
Get the type of the variable represented by the ObjectMap.
Definition: unitAlgebra.h:446
bool operator!=(const UnitAlgebra &v) const
Compare if this object is not equal to, the argument.
Definition: unitAlgebra.cc:494
static std::string demangle_name(const char *name)
Static function to demangle type names returned from typeid<T>.name()
Definition: objectMap.cc:139
UnitAlgebra & operator/=(const T &v)
Divide by an argument;.
Definition: unitAlgebra.h:176
UnitAlgebra & operator*=(const UnitAlgebra &v)
Multiply by an argument;.
Definition: unitAlgebra.cc:424
UnitAlgebra & operator+=(const UnitAlgebra &v)
Add an argument;.
Definition: unitAlgebra.cc:440
std::string toString() const
Return a String representation if this Unit.
Definition: unitAlgebra.cc:287
static void registerCompoundUnit(const std::string &u, const std::string &v)
Create a new Compound Unit type.
Definition: unitAlgebra.cc:194
UnitAlgebra & operator-=(const UnitAlgebra &v)
Subtract an argument;.
Definition: unitAlgebra.cc:448
std::string toStringBestSI(int32_t precision=6) const
Return a string representation of this value Formats the number using SI-prefixes.
Definition: unitAlgebra.cc:395
bool hasUnits(const std::string &u) const
Returns true if the units in the parameter string are found in this object.
Definition: unitAlgebra.cc:510
Performs Unit math in full precision.
Definition: unitAlgebra.h:106
void printWithBestSI(std::ostream &stream, int32_t precision=6)
Print to an ostream the value Formats the number using SI-prefixes.
Definition: unitAlgebra.cc:381
Units & operator/=(const Units &v)
Self-division operator.
Definition: unitAlgebra.cc:255
int64_t getRoundedValue() const
Definition: unitAlgebra.cc:520
std::string toString(int32_t precision=6) const
Return a string representation of this value.
Definition: unitAlgebra.cc:387
Helper class internal to UnitAlgebra.
Definition: unitAlgebra.h:38