SST 15.0
Structural Simulation Toolkit
unitAlgebra.h
1// -*- c++ -*-
2
3// Copyright 2009-2025 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-2025, 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
29namespace SST {
30
31using sst_big_num = decimal_fixedpoint<3, 3>;
32
33/**
34 * Helper class internal to UnitAlgebra.
35 *
36 * Contains information on valid units
37 */
38class Units
39{
40
41 using unit_id_t = uint8_t;
42
43private:
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
64public:
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 */
106class UnitAlgebra
107{
108private:
109 Units unit;
110 sst_big_num value;
111
112 static std::string trim(const std::string& str);
113
114public:
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() = default;
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; */
163 UnitAlgebra& operator*=(const UnitAlgebra& v);
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 */
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 SST_SER(unit.numerator);
232 SST_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 SST_SER(s);
243 break;
244 }
245 case SST::Core::Serialization::serializer::UNPACK:
246 {
247 std::string s;
248 SST_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
258public:
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 explicit 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 explicit 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 explicit 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
325template <typename T>
327operator*(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
340inline UnitAlgebra
341operator*(UnitAlgebra lhs, const UnitAlgebra& rhs)
342{
343 lhs *= rhs;
344 return lhs;
345}
346
347template <typename T>
349operator/(UnitAlgebra lhs, const T& rhs)
350{
351 lhs /= rhs;
352 return lhs;
353}
354
355inline UnitAlgebra
356operator/(UnitAlgebra lhs, const UnitAlgebra& rhs)
357{
358 lhs /= rhs;
359 return lhs;
360}
361
362template <typename T>
364operator+(UnitAlgebra lhs, const T& rhs)
365{
366 lhs += rhs;
367 return lhs;
368}
369
370inline UnitAlgebra
371operator+(UnitAlgebra lhs, const UnitAlgebra& rhs)
372{
373 lhs += rhs;
374 return lhs;
375}
376
377template <typename T>
379operator-(UnitAlgebra lhs, const T& rhs)
380{
381 lhs -= rhs;
382 return lhs;
383}
384
385inline UnitAlgebra
386operator-(UnitAlgebra lhs, const UnitAlgebra& rhs)
387{
388 lhs -= rhs;
389 return lhs;
390}
391
392inline std::ostream&
393operator<<(std::ostream& os, const UnitAlgebra& r)
394{
395 os << r.toString();
396 return os;
397}
398
399inline std::ostream&
400operator<<(std::ostream& os, const Units& r)
401{
402 os << r.toString();
403 return os;
404}
405
406
407namespace Core::Serialization {
408
409template <>
410class ObjectMapFundamental<UnitAlgebra> : public ObjectMap
411{
412protected:
413 /**
414 Address of the variable for reading and writing
415 */
416 UnitAlgebra* addr_ = nullptr;
417
418public:
419 std::string get() override { return addr_->toStringBestSI(); }
420 void set_impl(const std::string& value) override { addr_->init(value); }
421
422 // We'll act like we're a fundamental type
423 bool isFundamental() override { return true; }
424
425 /**
426 Get the address of the variable represented by the ObjectMap
427
428 @return Address of varaible
429 */
430 void* getAddr() override { return addr_; }
431
432 explicit ObjectMapFundamental(UnitAlgebra* addr) :
433 ObjectMap(),
434 addr_(addr)
435 {}
436
437 std::string getType() override { return demangle_name(typeid(UnitAlgebra).name()); }
438};
439
440template <>
442{
443 void operator()(UnitAlgebra& ua, serializer& ser, ser_opt_t options)
444 {
445 switch ( ser.mode() ) {
446 case serializer::SIZER:
447 case serializer::PACK:
448 case serializer::UNPACK:
449 ua.serialize_order(ser);
450 break;
451 case serializer::MAP:
452 {
454 if ( options & SerOption::map_read_only ) {
455 ser.mapper().setNextObjectReadOnly();
456 }
457 ser.mapper().map_primitive(ser.getMapName(), obj_map);
458 break;
459 }
460 }
461 }
462
463 SST_FRIEND_SERIALIZE();
464};
465
466
467} // namespace Core::Serialization
468
469} // namespace SST
470
471#endif // SST_CORE_UNITALGEBRA_H
void * getAddr() override
Get the address of the variable represented by the ObjectMap.
Definition unitAlgebra.h:430
std::string get() override
Get the value of the variable as a string.
Definition unitAlgebra.h:419
bool isFundamental() override
Check to see if this ObjectMap represents a fundamental or a class treated as a fundamental.
Definition unitAlgebra.h:423
std::string getType() override
Get the type of the variable represented by the ObjectMap.
Definition unitAlgebra.h:437
UnitAlgebra * addr_
Address of the variable for reading and writing.
Definition unitAlgebra.h:416
ObjectMap representing fundamental types, and classes treated as fundamental types.
Definition objectMap.h:753
virtual void set_impl(const std::string &value) override
Set the value of the object represented as a string.
Definition objectMap.h:767
T * addr_
Address of the variable for reading and writing.
Definition objectMap.h:758
Base class for objects created by the serializer mapping mode used to map the variables for objects.
Definition objectMap.h:112
ObjectMap()=default
Default constructor primarily used for the "top" object in the hierarchy.
static std::string demangle_name(const char *name)
Static function to demangle type names returned from typeid(T).name()
Definition objectMap.cc:137
Base serialize class.
Definition serialize.h:110
This class is basically a wrapper for objects to declare the order in which their members should be s...
Definition serializer.h:45
InvalidNumberString(const std::string &number)
Definition unitAlgebra.cc:559
InvalidUnitType(const std::string &type)
Definition unitAlgebra.cc:555
NonMatchingUnits(const std::string &lhs, const std::string &rhs, const std::string &operation)
Definition unitAlgebra.cc:563
UnitAlgebraException(const std::string &msg)
Definition unitAlgebra.cc:551
Performs Unit math in full precision.
Definition unitAlgebra.h:107
void print(std::ostream &stream, int32_t precision=6)
Print to an ostream the value.
Definition unitAlgebra.cc:374
sst_big_num getValue() const
Return the raw value.
Definition unitAlgebra.h:222
bool operator==(const UnitAlgebra &v) const
Compare if this object is equal to, the argument.
Definition unitAlgebra.cc:496
UnitAlgebra & operator/=(const T &v)
Divide by an argument;.
Definition unitAlgebra.h:176
UnitAlgebra & operator+=(const UnitAlgebra &v)
Add an argument;.
Definition unitAlgebra.cc:439
bool operator>=(const UnitAlgebra &v) const
Compare if this object is greater than, or equal to, the argument.
Definition unitAlgebra.cc:468
UnitAlgebra & operator*=(const UnitAlgebra &v)
Multiply by an argument;.
Definition unitAlgebra.cc:423
UnitAlgebra & invert()
Apply a reciprocal operation to the object.
Definition unitAlgebra.cc:510
bool hasUnits(const std::string &u) const
Returns true if the units in the parameter string are found in this object.
Definition unitAlgebra.cc:519
bool operator!=(const UnitAlgebra &v) const
Compare if this object is not equal to, the argument.
Definition unitAlgebra.cc:503
bool operator<=(const UnitAlgebra &v) const
Compare if this object is less than, or equal to, the argument.
Definition unitAlgebra.cc:487
std::string toStringBestSI(int32_t precision=6) const
Return a string representation of this value Formats the number using SI-prefixes.
Definition unitAlgebra.cc:394
std::string toString(int32_t precision=6) const
Return a string representation of this value.
Definition unitAlgebra.cc:386
UnitAlgebra(const UnitAlgebra &)=default
Copy constructor.
UnitAlgebra & operator-=(const UnitAlgebra &v)
Subtract an argument;.
Definition unitAlgebra.cc:449
UnitAlgebra & operator*=(const T &v)
Multiply by an argument;.
Definition unitAlgebra.h:166
void printWithBestSI(std::ostream &stream, int32_t precision=6)
Print to an ostream the value Formats the number using SI-prefixes.
Definition unitAlgebra.cc:380
UnitAlgebra & operator/=(const UnitAlgebra &v)
Divide by an argument;.
Definition unitAlgebra.cc:431
int64_t getRoundedValue() const
Definition unitAlgebra.cc:527
bool operator>(const UnitAlgebra &v) const
Compare if this object is greater than the argument.
Definition unitAlgebra.cc:459
UnitAlgebra & operator+=(const T &v)
Multiply by an argument;.
Definition unitAlgebra.h:186
bool operator<(const UnitAlgebra &v) const
Compare if this object is less than the argument.
Definition unitAlgebra.cc:478
UnitAlgebra & operator-=(const T &v)
Divide by an argument;.
Definition unitAlgebra.h:196
Helper class internal to UnitAlgebra.
Definition unitAlgebra.h:39
Units(const Units &)=default
Copy constructor.
Units & operator=(const Units &v)
Assignment operator.
Definition unitAlgebra.cc:233
std::string toString() const
Return a String representation if this Unit.
Definition unitAlgebra.cc:284
Units & operator/=(const Units &v)
Self-division operator.
Definition unitAlgebra.cc:252
static void registerBaseUnit(const std::string &u)
Create a new Base Unit type.
Definition unitAlgebra.cc:180
static void registerCompoundUnit(const std::string &u, const std::string &v)
Create a new Compound Unit type.
Definition unitAlgebra.cc:191
Units & operator*=(const Units &v)
Self-multiplication operator.
Definition unitAlgebra.cc:241
bool operator==(const Units &lhs) const
Equality Operator.
Definition unitAlgebra.cc:261
bool operator!=(const Units &lhs) const
Inequality Operator.
Definition unitAlgebra.h:92
Units(const std::string &units, sst_big_num &multiplier)
Create a new instantiation of a Units with a base unit string, and multiplier.
Definition unitAlgebra.cc:201
Units & invert()
Perform a reciprocal operation.
Definition unitAlgebra.cc:275
Class that implements a decimal fixed-point number.
Definition decimal_fixedpoint.h:42
std::string toString(int32_t precision=6) const
Create a string representation of this decimal_fixedpoint.
Definition decimal_fixedpoint.h:443