Physical Quantities  v1.0.0
C++ library of physical quantities, physical models, and units of measure for scientific computing. https://github.com/acodcha/phq
Loading...
Searching...
No Matches
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
39namespace PhQ {
40
41/// \brief Namespace that contains units of measure.
42namespace 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.
46template <typename Unit>
48
49namespace 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.
54template <typename Unit, Unit UnitValue>
55class Conversion {
56public:
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.
73template <typename Unit, Unit UnitValue>
74class Conversions {
75public:
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.
111template <typename Unit, typename NumericType>
112inline 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.
119template <typename Unit, typename NumericType>
120inline 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.
127template <typename Unit, typename NumericType>
128inline 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.
142template <typename Unit, std::size_t Size, typename NumericType>
143inline 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.
159template <typename Unit, typename NumericType>
160inline 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.
176template <typename Unit, typename NumericType>
177inline 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.
184template <typename Unit, typename NumericType>
185inline 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.
192template <typename Unit, typename NumericType>
193inline 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.
201template <typename Unit, typename NumericType>
202inline 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.
209template <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.
219template <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.
229template <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.
240template <typename Unit, typename NumericType>
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.
248template <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.
257template <typename Unit, typename NumericType>
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.
267template <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.
277template <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.
291template <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.
306template <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.
316template <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.
325template <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.
335template <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...
Three-dimensional Euclidean dyadic tensor. Contains nine components in Cartesian coordinates: xx,...
Definition Dyad.hpp:51
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
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
Two-dimensional Euclidean vector in the XY plane. Contains two components in Cartesian coordinates: x...
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.
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.
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