Physical Quantities  v1.0.0
C++ library of physical quantities, physical models, and units of measure for scientific computing. https://github.com/acodcha/phq
Unit.hpp
Go to the documentation of this file.
1 // Copyright © 2020-2024 Alexandre Coderre-Chabot
2 //
3 // This file is part of Physical Quantities (PhQ), a C++ library of physical quantities, physical
4 // models, and units of measure for scientific computing.
5 //
6 // Physical Quantities is hosted at:
7 // https://github.com/acodcha/phq
8 //
9 // Physical Quantities is licensed under the MIT License:
10 // https://mit-license.org
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
13 // associated documentation files (the "Software"), to deal in the Software without restriction,
14 // including without limitation the rights to use, copy, modify, merge, publish, distribute,
15 // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
17 // - The above copyright notice and this permission notice shall be included in all copies or
18 // substantial portions of the Software.
19 // - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
20 // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM
23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 
25 #ifndef PHQ_UNIT_HPP
26 #define PHQ_UNIT_HPP
27 
28 #include <functional>
29 #include <type_traits>
30 #include <vector>
31 
32 #include "Dimensions.hpp"
33 #include "Dyad.hpp"
34 #include "PlanarVector.hpp"
35 #include "SymmetricDyad.hpp"
36 #include "UnitSystem.hpp"
37 #include "Vector.hpp"
38 
39 namespace PhQ {
40 
41 /// \brief Namespace that contains units of measure.
42 namespace Unit {}
43 
44 /// \brief Physical dimension set of a given type of unit of measure. Units of measure are organized
45 /// into types that share the same physical dimension set.
46 template <typename Unit>
47 inline constexpr Dimensions RelatedDimensions;
48 
49 namespace Internal {
50 
51 /// \brief Abstract class for converting a value expressed in a unit of measure to or from the
52 /// standard unit of measure of that type. Internal implementation detail not intended to be used
53 /// outside of the PhQ::ConvertInPlace, PhQ::Convert, and PhQ::ConvertStatically functions.
54 template <typename Unit, Unit UnitValue>
55 class Conversion {
56 public:
57  /// \brief Converts a value expressed in the standard unit of measure of a given unit type to any
58  /// given unit of measure of that type. Internal implementation detail not intended to be used
59  /// outside of the PhQ::ConvertInPlace, PhQ::Convert, and PhQ::ConvertStatically functions.
60  template <typename NumericType>
61  static inline constexpr void FromStandard(NumericType& value) noexcept;
62 
63  /// \brief Converts a value expressed in any given unit of measure of a given unit type to the
64  /// standard unit of measure of that type. Internal implementation detail not intended to be used
65  /// outside of the PhQ::ConvertInPlace, PhQ::Convert, and PhQ::ConvertStatically functions.
66  template <typename NumericType>
67  static inline constexpr void ToStandard(NumericType& value) noexcept;
68 };
69 
70 /// \brief Abstract class for converting a sequence of values expressed in a unit of measure to or
71 /// from the standard unit of measure of that type. Internal implementation detail not intended to
72 /// be used outside of the PhQ::ConvertInPlace, PhQ::Convert, and PhQ::ConvertStatically functions.
73 template <typename Unit, Unit UnitValue>
74 class Conversions {
75 public:
76  /// \brief Converts a sequence of values expressed in the standard unit of measure of a given unit
77  /// type to any given unit of measure of that type. Internal implementation detail not intended to
78  /// be used outside of the PhQ::ConvertInPlace, PhQ::Convert, and PhQ::ConvertStatically
79  /// functions.
80  template <typename NumericType>
81  static inline constexpr void FromStandard(NumericType* values, const std::size_t size) noexcept {
82  static_assert(std::is_floating_point<NumericType>::value,
83  "The NumericType template parameter of PhQ::Conversions::FromStandard must be a "
84  "numeric floating-point type: float, double, or long double.");
85  const NumericType* const end{values + size};
86  for (; values < end; ++values) {
87  Conversion<Unit, UnitValue>::FromStandard(*values);
88  }
89  }
90 
91  /// \brief Converts a sequence of values expressed in any given unit of measure of a given unit
92  /// type to the standard unit of measure of that type. Internal implementation detail not intended
93  /// to be used outside of the PhQ::ConvertInPlace, PhQ::Convert, and PhQ::ConvertStatically
94  /// functions.
95  template <typename NumericType>
96  static inline constexpr void ToStandard(NumericType* values, const std::size_t size) noexcept {
97  static_assert(std::is_floating_point<NumericType>::value,
98  "The NumericType template parameter of PhQ::Conversions::ToStandard must be a "
99  "numeric floating-point type: float, double, or long double.");
100  const NumericType* const end{values + size};
101  for (; values < end; ++values) {
102  Conversion<Unit, UnitValue>::ToStandard(*values);
103  }
104  }
105 };
106 
107 /// \brief Abstract map of functions for converting a sequence of values expressed in the standard
108 /// unit of measure of a given type to any given unit of measure of that type. Internal
109 /// implementation detail not intended to be used outside of the PhQ::ConvertInPlace, PhQ::Convert,
110 /// and PhQ::ConvertStatically functions.
111 template <typename Unit, typename NumericType>
112 inline const std::map<Unit, std::function<void(NumericType* values, const std::size_t size)>>
113  MapOfConversionsFromStandard;
114 
115 /// \brief Abstract map of functions for converting a sequence of values expressed in any given unit
116 /// of measure of a given type to the standard unit of measure of that type. Internal implementation
117 /// detail not intended to be used outside of the PhQ::ConvertInPlace, PhQ::Convert, and
118 /// PhQ::ConvertStatically functions.
119 template <typename Unit, typename NumericType>
120 inline const std::map<Unit, std::function<void(NumericType* values, const std::size_t size)>>
121  MapOfConversionsToStandard;
122 
123 } // namespace Internal
124 
125 /// \brief Converts a value expressed in a given unit of measure to a new unit of measure. The
126 /// conversion is performed in-place.
127 template <typename Unit, typename NumericType>
128 inline void ConvertInPlace(NumericType& value, const Unit original_unit, const Unit new_unit) {
129  static_assert(std::is_floating_point<NumericType>::value,
130  "The NumericType template parameter of PhQ::ConvertInPlace must be a numeric "
131  "floating-point type: float, double, or long double.");
132  if (original_unit != Standard<Unit>) {
133  Internal::MapOfConversionsToStandard<Unit, NumericType>.find(original_unit)->second(&value, 1);
134  }
135  if (new_unit != Standard<Unit>) {
136  Internal::MapOfConversionsFromStandard<Unit, NumericType>.find(new_unit)->second(&value, 1);
137  }
138 }
139 
140 /// \brief Converts an array of values expressed in a given unit of measure to a new unit of
141 /// measure. The conversion is performed in-place.
142 template <typename Unit, std::size_t Size, typename NumericType>
143 inline void ConvertInPlace(
144  std::array<NumericType, Size>& values, const Unit original_unit, const Unit new_unit) {
145  static_assert(std::is_floating_point<NumericType>::value,
146  "The NumericType template parameter of PhQ::ConvertInPlace must be a numeric "
147  "floating-point type: float, double, or long double.");
148  if (original_unit != Standard<Unit>) {
149  Internal::MapOfConversionsToStandard<Unit, NumericType>.find(original_unit)->second(values.data(), Size);
150  }
151  if (new_unit != Standard<Unit>) {
152  Internal::MapOfConversionsFromStandard<Unit, NumericType>.find(new_unit)->second(
153  values.data(), Size);
154  }
155 }
156 
157 /// \brief Converts a vector of values expressed in a given unit of measure to a new unit of
158 /// measure. The conversion is performed in-place.
159 template <typename Unit, typename NumericType>
160 inline void ConvertInPlace(
161  std::vector<NumericType>& values, const Unit original_unit, const Unit new_unit) {
162  static_assert(std::is_floating_point<NumericType>::value,
163  "The NumericType template parameter of PhQ::ConvertInPlace must be a numeric "
164  "floating-point type: float, double, or long double.");
165  if (original_unit != Standard<Unit>) {
166  Internal::MapOfConversionsToStandard<Unit, NumericType>.find(original_unit)->second(values.data(), values.size());
167  }
168  if (new_unit != Standard<Unit>) {
169  Internal::MapOfConversionsFromStandard<Unit, NumericType>.find(new_unit)->second(
170  values.data(), values.size());
171  }
172 }
173 
174 /// \brief Converts a two-dimensional Euclidean planar vector in the XY plane expressed in a given
175 /// unit of measure to a new unit of measure. The conversion is performed in-place.
176 template <typename Unit, typename NumericType>
177 inline void ConvertInPlace(
178  PlanarVector<NumericType>& planar_vector, const Unit original_unit, const Unit new_unit) {
179  ConvertInPlace<Unit, 2, NumericType>(planar_vector.Mutable_x_y(), original_unit, new_unit);
180 }
181 
182 /// \brief Converts a three-dimensional Euclidean vector expressed in a given unit of measure to a
183 /// new unit of measure. The conversion is performed in-place.
184 template <typename Unit, typename NumericType>
185 inline void ConvertInPlace(
186  Vector<NumericType>& vector, const Unit original_unit, const Unit new_unit) {
187  ConvertInPlace<Unit, 3, NumericType>(vector.Mutable_x_y_z(), original_unit, new_unit);
188 }
189 
190 /// \brief Converts a three-dimensional Euclidean symmetric dyadic tensor expressed in a given unit
191 /// of measure to a new unit of measure. The conversion is performed in-place.
192 template <typename Unit, typename NumericType>
193 inline void ConvertInPlace(
194  SymmetricDyad<NumericType>& symmetric_dyad, const Unit original_unit, const Unit new_unit) {
195  ConvertInPlace<Unit, 6, NumericType>(
196  symmetric_dyad.Mutable_xx_xy_xz_yy_yz_zz(), original_unit, new_unit);
197 }
198 
199 /// \brief Converts a three-dimensional Euclidean dyadic tensor expressed in a given unit of measure
200 /// to a new unit of measure. The conversion is performed in-place.
201 template <typename Unit, typename NumericType>
202 inline void ConvertInPlace(Dyad<NumericType>& dyad, const Unit original_unit, const Unit new_unit) {
203  ConvertInPlace<Unit, 9, NumericType>(
204  dyad.Mutable_xx_xy_xz_yx_yy_yz_zx_zy_zz(), original_unit, new_unit);
205 }
206 
207 /// \brief Converts a value expressed in a given unit of measure to a new unit of measure. Returns
208 /// the converted value. The original value remains unchanged.
209 template <typename Unit, typename NumericType>
210 [[nodiscard]] inline NumericType Convert(
211  const NumericType value, const Unit original_unit, const Unit new_unit) {
212  NumericType result{value};
213  ConvertInPlace<Unit, NumericType>(result, original_unit, new_unit);
214  return result;
215 }
216 
217 /// \brief Converts an array of values expressed in a given unit of measure to a new unit of
218 /// measure. Returns the converted values. The original values remain unchanged.
219 template <typename Unit, std::size_t Size, typename NumericType>
220 [[nodiscard]] inline std::array<NumericType, Size> Convert(
221  const std::array<NumericType, Size>& values, const Unit original_unit, const Unit new_unit) {
222  std::array<NumericType, Size> result{values};
223  ConvertInPlace<Unit, Size, NumericType>(result, original_unit, new_unit);
224  return result;
225 }
226 
227 /// \brief Converts a vector of values expressed in a given unit of measure to a new unit of
228 /// measure. Returns the converted values. The original values remain unchanged.
229 template <typename Unit, typename NumericType>
230 [[nodiscard]] inline std::vector<NumericType> Convert(
231  const std::vector<NumericType>& values, const Unit original_unit, const Unit new_unit) {
232  std::vector<NumericType> result{values};
233  ConvertInPlace<Unit, NumericType>(result, original_unit, new_unit);
234  return result;
235 }
236 
237 /// \brief Converts a two-dimensional Euclidean planar vector in the XY plane expressed in a given
238 /// unit of measure to a new unit of measure. Returns the converted vector. The original vector
239 /// remains unchanged.
240 template <typename Unit, typename NumericType>
241 [[nodiscard]] inline PlanarVector<NumericType> Convert(
242  const PlanarVector<NumericType>& planar_vector, const Unit original_unit, const Unit new_unit) {
243  return PlanarVector{Convert<Unit, 2, NumericType>(planar_vector.x_y(), original_unit, new_unit)};
244 }
245 
246 /// \brief Converts a three-dimensional Euclidean vector expressed in a given unit of measure to a
247 /// new unit of measure. Returns the converted vector. The original vector remains unchanged.
248 template <typename Unit, typename NumericType>
249 [[nodiscard]] inline Vector<NumericType> Convert(
250  const Vector<NumericType>& vector, const Unit original_unit, const Unit new_unit) {
251  return Vector{Convert<Unit, 3, NumericType>(vector.x_y_z(), original_unit, new_unit)};
252 }
253 
254 /// \brief Converts a three-dimensional Euclidean symmetric dyadic tensor expressed in a given unit
255 /// of measure to a new unit of measure. Returns the converted tensor. The original tensor remains
256 /// unchanged.
257 template <typename Unit, typename NumericType>
258 [[nodiscard]] inline SymmetricDyad<NumericType> Convert(
259  const SymmetricDyad<NumericType>& symmetric_dyad, const Unit original_unit,
260  const Unit new_unit) {
261  return SymmetricDyad{
262  Convert<Unit, 6, NumericType>(symmetric_dyad.xx_xy_xz_yy_yz_zz(), original_unit, new_unit)};
263 }
264 
265 /// \brief Converts a three-dimensional Euclidean dyadic tensor expressed in a given unit of measure
266 /// to a new unit of measure. Returns the converted tensor. The original tensor remains unchanged.
267 template <typename Unit, typename NumericType>
268 [[nodiscard]] inline Dyad<NumericType> Convert(
269  const Dyad<NumericType>& dyad, const Unit original_unit, const Unit new_unit) {
270  return Dyad{
271  Convert<Unit, 9, NumericType>(dyad.xx_xy_xz_yx_yy_yz_zx_zy_zz(), original_unit, new_unit)};
272 }
273 
274 /// \brief Converts a value expressed in a given unit of measure to a new unit of measure. Returns
275 /// the converted value. The original value remains unchanged. This function can be evaluated at
276 /// compile time.
277 template <typename Unit, Unit OriginalUnit, Unit NewUnit, typename NumericType>
278 [[nodiscard]] inline constexpr NumericType ConvertStatically(const NumericType value) {
279  static_assert(std::is_floating_point<NumericType>::value,
280  "The NumericType template parameter of PhQ::ConvertStatically must be a numeric "
281  "floating-point type: float, double, or long double.");
282  NumericType result{value};
283  Internal::Conversion<Unit, OriginalUnit>::ToStandard(result);
284  Internal::Conversion<Unit, NewUnit>::FromStandard(result);
285  return result;
286 }
287 
288 /// \brief Converts an array of values expressed in a given unit of measure to a new unit of
289 /// measure. Returns the converted values. The original values remain unchanged. This function can
290 /// be evaluated at compile time.
291 template <typename Unit, Unit OriginalUnit, Unit NewUnit, std::size_t Size, typename NumericType>
292 [[nodiscard]] inline constexpr std::array<NumericType, Size> ConvertStatically(
293  const std::array<NumericType, Size>& values) {
294  static_assert(std::is_floating_point<NumericType>::value,
295  "The NumericType template parameter of PhQ::ConvertStatically must be a numeric "
296  "floating-point type: float, double, or long double.");
297  std::array<NumericType, Size> result{values};
298  Internal::Conversions<Unit, OriginalUnit>::ToStandard(result.data(), Size);
299  Internal::Conversions<Unit, NewUnit>::FromStandard(result.data(), Size);
300  return result;
301 }
302 
303 /// \brief Converts a two-dimensional Euclidean planar vector in the XY plane expressed in a given
304 /// unit of measure to a new unit of measure. Returns the converted vector. The original vector
305 /// remains unchanged. This function can be evaluated at compile time.
306 template <typename Unit, Unit OriginalUnit, Unit NewUnit, typename NumericType>
307 [[nodiscard]] inline constexpr PlanarVector<NumericType> ConvertStatically(
308  const PlanarVector<NumericType>& planar_vector) {
309  return PlanarVector{
310  ConvertStatically<Unit, OriginalUnit, NewUnit, 2, NumericType>(planar_vector.x_y())};
311 }
312 
313 /// \brief Converts a three-dimensional Euclidean vector expressed in a given unit of measure to a
314 /// new unit of measure. Returns the converted vector. The original vector remains unchanged. This
315 /// function can be evaluated at compile time.
316 template <typename Unit, Unit OriginalUnit, Unit NewUnit, typename NumericType>
317 [[nodiscard]] inline constexpr Vector<NumericType> ConvertStatically(
318  const Vector<NumericType>& vector) {
319  return Vector{ConvertStatically<Unit, OriginalUnit, NewUnit, 3, NumericType>(vector.x_y_z())};
320 }
321 
322 /// \brief Converts a three-dimensional Euclidean symmetric dyadic tensor expressed in a given unit
323 /// of measure to a new unit of measure. Returns the converted tensor. The original tensor remains
324 /// unchanged. This function can be evaluated at compile time.
325 template <typename Unit, Unit OriginalUnit, Unit NewUnit, typename NumericType>
326 [[nodiscard]] inline constexpr SymmetricDyad<NumericType> ConvertStatically(
327  const SymmetricDyad<NumericType>& symmetric_dyad) {
328  return SymmetricDyad{ConvertStatically<Unit, OriginalUnit, NewUnit, 6, NumericType>(
329  symmetric_dyad.xx_xy_xz_yy_yz_zz())};
330 }
331 
332 /// \brief Converts a three-dimensional Euclidean dyadic tensor expressed in a given unit of measure
333 /// to a new unit of measure. Returns the converted tensor. The original tensor remains unchanged.
334 /// This function can be evaluated at compile time.
335 template <typename Unit, Unit OriginalUnit, Unit NewUnit, typename NumericType>
336 [[nodiscard]] inline constexpr Dyad<NumericType> ConvertStatically(const Dyad<NumericType>& dyad) {
337  return Dyad{ConvertStatically<Unit, OriginalUnit, NewUnit, 9, NumericType>(
339 }
340 
341 } // namespace PhQ
342 
343 #endif // PHQ_UNIT_HPP
Physical dimension set of a unit of measure or physical quantity. Composed of the seven independent b...
Definition: Dimensions.hpp:49
Three-dimensional Euclidean dyadic tensor. Contains nine components in Cartesian coordinates: xx,...
Definition: Dyad.hpp:51
constexpr std::array< NumericType, 9 > & Mutable_xx_xy_xz_yx_yy_yz_zx_zy_zz() noexcept
Returns this three-dimensional symmetric dyadic tensor's xx, xy, xz, yx, yy, yz, zx,...
Definition: Dyad.hpp:213
constexpr const std::array< NumericType, 9 > & xx_xy_xz_yx_yy_yz_zx_zy_zz() const noexcept
Returns this three-dimensional symmetric dyadic tensor's xx, xy, xz, yx, yy, yz, zx,...
Definition: Dyad.hpp:161
Two-dimensional Euclidean vector in the XY plane. Contains two components in Cartesian coordinates: x...
constexpr const std::array< NumericType, 2 > & x_y() const noexcept
Returns this two-dimensional planar vector's x and y Cartesian components as an array.
constexpr std::array< NumericType, 2 > & Mutable_x_y() noexcept
Returns this two-dimensional planar vector's x and y Cartesian components as a mutable array.
Symmetric three-dimensional Euclidean dyadic tensor. Contains six components in Cartesian coordinates...
constexpr const std::array< NumericType, 6 > & xx_xy_xz_yy_yz_zz() const noexcept
Returns this three-dimensional symmetric dyadic tensor's xx, xy, xz, yy, yz, and zz Cartesian compone...
constexpr std::array< NumericType, 6 > & Mutable_xx_xy_xz_yy_yz_zz() noexcept
Returns this three-dimensional symmetric dyadic tensor's xx, xy, xz, yy, yz, and zz Cartesian compone...
Three-dimensional Euclidean vector. Contains three components in Cartesian coordinates: x,...
Definition: Vector.hpp:60
constexpr const std::array< NumericType, 3 > & x_y_z() const noexcept
Returns this three-dimensional vector's x, y, and z Cartesian components as an array.
Definition: Vector.hpp:134
constexpr std::array< NumericType, 3 > & Mutable_x_y_z() noexcept
Returns this three-dimensional vector's x, y, and z Cartesian components as a mutable array.
Definition: Vector.hpp:155
Namespace that encompasses all of the Physical Quantities library's content.
NumericType Convert(const NumericType value, const Unit original_unit, const Unit new_unit)
Converts a value expressed in a given unit of measure to a new unit of measure. Returns the converted...
Definition: Unit.hpp:210
constexpr NumericType ConvertStatically(const NumericType value)
Converts a value expressed in a given unit of measure to a new unit of measure. Returns the converted...
Definition: Unit.hpp:278
constexpr Dimensions RelatedDimensions
Physical dimension set of a given type of unit of measure. Units of measure are organized into types ...
Definition: Unit.hpp:47
void ConvertInPlace(NumericType &value, const Unit original_unit, const Unit new_unit)
Converts a value expressed in a given unit of measure to a new unit of measure. The conversion is per...
Definition: Unit.hpp:128