2020-03-09 18:55:41 +01:00
|
|
|
.. namespace:: units
|
|
|
|
|
|
|
|
|
|
Dimensions
|
|
|
|
|
==========
|
|
|
|
|
|
|
|
|
|
In the previous chapter we briefly introduced the notion of a physical
|
|
|
|
|
:term:`dimension`. Now it is time to learn much more about this subject.
|
2020-05-10 17:31:47 +02:00
|
|
|
Length, time, speed, area, energy are only a few examples of physical
|
2020-03-09 18:55:41 +01:00
|
|
|
dimensions.
|
|
|
|
|
|
2021-02-16 16:19:57 +01:00
|
|
|
Arithmetics
|
|
|
|
|
-----------
|
|
|
|
|
|
|
|
|
|
Quantities
|
|
|
|
|
++++++++++
|
2020-03-09 18:55:41 +01:00
|
|
|
|
|
|
|
|
Quantities of the same dimension can be easily added or subtracted with
|
|
|
|
|
each other and the result will always be a quantity of the same dimension:
|
|
|
|
|
|
|
|
|
|
.. code-block::
|
|
|
|
|
:emphasize-lines: 3-4
|
|
|
|
|
|
2021-04-02 13:11:20 +02:00
|
|
|
Length auto dist1 = 2 * m;
|
|
|
|
|
Length auto dist2 = 1 * m;
|
2020-03-09 18:55:41 +01:00
|
|
|
Length auto res1 = dist1 + dist2;
|
|
|
|
|
Length auto res2 = dist1 - dist2;
|
|
|
|
|
|
|
|
|
|
Additionally, we can always multiply or divide a quantity by a
|
2020-09-08 21:17:09 +02:00
|
|
|
:term:`scalable number` and in such a case the quantity's dimension will also
|
2020-03-09 18:55:41 +01:00
|
|
|
not change:
|
|
|
|
|
|
|
|
|
|
.. code-block::
|
|
|
|
|
:emphasize-lines: 2-4
|
|
|
|
|
|
2021-04-02 13:11:20 +02:00
|
|
|
Length auto dist = 2 * m;
|
2020-03-09 18:55:41 +01:00
|
|
|
Length auto res1 = dist * 2; // 4 m
|
|
|
|
|
Length auto res2 = 3 * res1; // 12 m
|
|
|
|
|
Length auto res3 = res2 / 2; // 6 m
|
|
|
|
|
|
|
|
|
|
However, if we try to multiply or divide quantities of the same or
|
2020-09-08 21:17:09 +02:00
|
|
|
different dimensions, or we will divide a scalable number by a quantity, we most
|
2020-03-09 18:55:41 +01:00
|
|
|
probably will always end up in a quantity of a yet another dimension:
|
|
|
|
|
|
|
|
|
|
.. code-block::
|
|
|
|
|
:emphasize-lines: 4-6
|
|
|
|
|
|
2021-04-02 13:11:20 +02:00
|
|
|
Length auto dist1 = 2 * m;
|
|
|
|
|
Length auto dist2 = 3 * m;
|
|
|
|
|
Time auto dur1 = 2 * s;
|
2020-03-09 18:55:41 +01:00
|
|
|
Area auto res1 = dist1 * dist2; // 6 m²
|
2020-05-10 17:31:47 +02:00
|
|
|
Speed auto res2 = dist1 / dur1; // 1 m/s
|
2020-03-09 18:55:41 +01:00
|
|
|
Frequency auto res3 = 10 / dur1; // 5 Hz
|
|
|
|
|
|
|
|
|
|
However, please note that there is an exception from the above rule.
|
|
|
|
|
In case we divide the same dimensions, or multiply by the inverted
|
2021-01-04 18:36:26 -04:00
|
|
|
dimension, than we will end up with just a dimensionless quantity:
|
2020-03-09 18:55:41 +01:00
|
|
|
|
|
|
|
|
.. code-block::
|
|
|
|
|
:emphasize-lines: 4-5
|
|
|
|
|
|
2021-04-02 13:11:20 +02:00
|
|
|
Time auto dur1 = 10 * s;
|
|
|
|
|
Time auto dur2 = 2 * s;
|
|
|
|
|
Frequency auto fr1 = 5 * Hz;
|
2021-01-04 18:36:26 -04:00
|
|
|
Dimensionless auto v1 = dur1 / dur2; // quantity(5)
|
|
|
|
|
Dimensionless auto v2 = dur1 * fr1; // quantity(50)
|
|
|
|
|
|
2021-02-16 16:19:57 +01:00
|
|
|
Quantity Kinds
|
|
|
|
|
++++++++++++++
|
|
|
|
|
|
2021-02-16 18:40:03 -04:00
|
|
|
Quantity kinds behave the same as quantities for all operations,
|
|
|
|
|
except that the quantity types in the operators' declarations
|
|
|
|
|
are quantity kind types instead.
|
|
|
|
|
Additionally, for the dimensional analysis operators,
|
|
|
|
|
you can use a quantity argument instead of a quantity kind.
|
2021-02-16 16:19:57 +01:00
|
|
|
|
2021-02-16 18:40:03 -04:00
|
|
|
.. code-block::
|
|
|
|
|
:emphasize-lines: 8-9
|
|
|
|
|
|
|
|
|
|
struct height_kind : kind<height_kind, dim_length> {};
|
|
|
|
|
struct rate_of_climb_kind : derived_kind<rate_of_climb_kind, height_kind, dim_speed> {};
|
|
|
|
|
|
2021-03-19 07:53:18 +01:00
|
|
|
template <Unit U, Representation Rep = double> using height = quantity_kind<height_kind, U, Rep>;
|
|
|
|
|
template <Unit U, Representation Rep = double> using rate_of_climb = quantity_kind<rate_of_climb_kind, U, Rep>;
|
2021-02-16 18:40:03 -04:00
|
|
|
|
|
|
|
|
height h{100 * m};
|
|
|
|
|
rate_of_climb rate = h / (25 * s);
|
|
|
|
|
// quantity_kind<rate_of_climb_kind, si::metre_per_second, int>(4 * m / s)
|
2021-01-04 18:36:26 -04:00
|
|
|
|
2021-02-16 16:19:57 +01:00
|
|
|
.. code-block::
|
2021-02-16 18:40:03 -04:00
|
|
|
:emphasize-lines: 8-12
|
|
|
|
|
|
|
|
|
|
struct width_kind : kind<width_kind, dim_length> {};
|
|
|
|
|
struct horizontal_area_kind : derived_kind<horizontal_area_kind, width_kind, dim_area> {};
|
2021-01-04 18:36:26 -04:00
|
|
|
|
2021-03-19 07:53:18 +01:00
|
|
|
template <Unit U, Representation Rep = double> using width = quantity_kind<width_kind, U, Rep>;
|
|
|
|
|
template <Unit U, Representation Rep = double> using horizontal_area = quantity_kind<horizontal_area_kind, U, Rep>;
|
2021-01-04 18:36:26 -04:00
|
|
|
|
2021-02-16 18:40:03 -04:00
|
|
|
width w{5 * m};
|
|
|
|
|
horizontal_area area1 = w * w;
|
|
|
|
|
// quantity_kind<horizontal_area_kind, si::metre_per_second, int>(25 * m * m)
|
|
|
|
|
width w2 = area1 / w; // quantity_kind<width_kind, si::metre, int>(5 * m)
|
|
|
|
|
auto q1 = w / w; // Dimensionless quantity kinds related to width
|
|
|
|
|
auto q2 = w / (5 * m); // with .common() equal to quantity{1}
|
2021-02-16 16:19:57 +01:00
|
|
|
|
|
|
|
|
Quantity Points
|
|
|
|
|
+++++++++++++++
|
2020-03-09 18:55:41 +01:00
|
|
|
|
2020-08-17 22:23:11 -04:00
|
|
|
Quantity points have a more restricted set of operations.
|
2021-02-16 16:19:57 +01:00
|
|
|
Quantity can be added to or subtracted from a quantity point.
|
2020-08-17 22:23:11 -04:00
|
|
|
The result will always be a quantity point of the same dimension:
|
|
|
|
|
|
|
|
|
|
.. code-block::
|
2020-08-18 02:56:01 -04:00
|
|
|
:emphasize-lines: 3-5
|
2020-08-17 22:23:11 -04:00
|
|
|
|
2021-04-02 13:11:20 +02:00
|
|
|
Length auto dist1 = 2 * m;
|
|
|
|
|
Length auto dist2 = 1 * m;
|
2020-08-17 22:23:11 -04:00
|
|
|
QuantityPoint auto res1 = quantity_point{dist1} + dist2;
|
|
|
|
|
QuantityPoint auto res2 = dist1 + quantity_point{dist2};
|
|
|
|
|
QuantityPoint auto res3 = quantity_point{dist1} - dist2;
|
|
|
|
|
|
2020-09-07 12:44:00 +02:00
|
|
|
We can also subtract two quantity points.
|
2020-08-17 22:23:11 -04:00
|
|
|
The result is a relative quantity of the same dimension:
|
|
|
|
|
|
2020-08-18 02:56:01 -04:00
|
|
|
.. code-block::
|
|
|
|
|
:emphasize-lines: 3
|
2020-09-07 12:44:00 +02:00
|
|
|
|
2021-04-02 13:11:20 +02:00
|
|
|
Length auto dist1 = 2 * m;
|
|
|
|
|
Length auto dist2 = 1 * m;
|
2020-08-17 22:23:11 -04:00
|
|
|
Length auto res1 = quantity_point{dist1} - quantity_point{dist2};
|
|
|
|
|
|
2021-02-16 16:19:57 +01:00
|
|
|
.. note::
|
|
|
|
|
|
|
|
|
|
It is not allowed to:
|
|
|
|
|
|
|
|
|
|
- add quantity points
|
|
|
|
|
- subtract a quantity point from a quantity:
|
|
|
|
|
- multiply nor divide quantity points with anything else.
|
|
|
|
|
|
|
|
|
|
.. code-block::
|
|
|
|
|
:emphasize-lines: 3-5
|
|
|
|
|
|
2021-04-02 13:11:20 +02:00
|
|
|
Length auto dist1 = 2 * m;
|
|
|
|
|
Length auto dist2 = 1 * m;
|
2021-02-16 16:19:57 +01:00
|
|
|
auto res1 = quantity_point{dist1} + quantity_point{dist2}; // ERROR
|
|
|
|
|
auto res2 = dist1 - quantity_point{dist2}; // ERROR
|
2021-04-02 13:11:20 +02:00
|
|
|
auto res3 = quantity_point{dist1} / (2 * s); // ERROR
|
2021-02-16 16:19:57 +01:00
|
|
|
|
|
|
|
|
Quantity Point Kinds
|
|
|
|
|
++++++++++++++++++++
|
2020-03-09 18:55:41 +01:00
|
|
|
|
2021-01-04 18:36:26 -04:00
|
|
|
The same restrictions of a quantity point with respect to its quantity
|
|
|
|
|
apply to a quantity point kind with respect to its quantity kind.
|
|
|
|
|
|
2020-09-07 12:44:00 +02:00
|
|
|
|
2020-03-26 17:09:26 +01:00
|
|
|
Base Dimensions
|
2020-03-09 18:55:41 +01:00
|
|
|
---------------
|
|
|
|
|
|
|
|
|
|
The quantities of base dimensions are called
|
|
|
|
|
:term:`base quantities <base quantity>` which are the atomic building blocks
|
|
|
|
|
of a :term:`system of quantities`. For example the The International System
|
|
|
|
|
of Units (:term:`SI`) defines 7 of them: length, mass, time, electric
|
|
|
|
|
current, thermodynamic temperature, substance, and luminous intensity.
|
|
|
|
|
|
|
|
|
|
To define a new base dimension the `base_dimension` class template is
|
|
|
|
|
provided. For example the SI base dimension of length can be defined as::
|
|
|
|
|
|
|
|
|
|
namespace si {
|
|
|
|
|
|
|
|
|
|
struct dim_length : base_dimension<"L", metre> {};
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
In the above code sample ``"L"`` is an base dimension's unique identifier
|
2021-03-16 12:03:25 +01:00
|
|
|
and `isq::si::metre` is a :term:`base unit` of this base dimension. We can
|
2020-03-09 18:55:41 +01:00
|
|
|
obtain those back easily with::
|
|
|
|
|
|
|
|
|
|
static_assert(si::dim_length::symbol == "L");
|
2020-06-29 20:30:59 +02:00
|
|
|
static_assert(is_same_v<si::dim_length::base_unit, si::metre>);
|
2020-03-09 18:55:41 +01:00
|
|
|
|
|
|
|
|
|
2020-03-26 17:09:26 +01:00
|
|
|
Derived Dimensions
|
2020-03-09 18:55:41 +01:00
|
|
|
------------------
|
|
|
|
|
|
|
|
|
|
The quantities of derived dimensions are called
|
|
|
|
|
:term:`derived quantities <derived quantity>` and are derived from base
|
|
|
|
|
quantities. This means that they are created by multiplying or dividing
|
|
|
|
|
quantities of other dimensions.
|
|
|
|
|
|
2020-05-10 17:31:47 +02:00
|
|
|
Looking at the previous code snippets the area, speed, or frequency are
|
2020-03-09 18:55:41 +01:00
|
|
|
the examples of such quantities. Each derived quantity can be represented
|
|
|
|
|
as a unique list of exponents of base quantities. For example:
|
|
|
|
|
|
|
|
|
|
- an area is a length base quantity raised to the exponent ``2``
|
2020-05-10 17:31:47 +02:00
|
|
|
- a speed is formed from the length base quantity with exponent ``1``
|
2020-03-09 18:55:41 +01:00
|
|
|
and time base quantity with exponent ``-1``.
|
|
|
|
|
|
|
|
|
|
The above dimensions can be defined in the library with the
|
|
|
|
|
`derived_dimension` class template as follows::
|
|
|
|
|
|
|
|
|
|
namespace si {
|
|
|
|
|
|
2020-05-14 16:00:38 +02:00
|
|
|
struct dim_area : derived_dimension<dim_area, square_metre,
|
2020-09-08 11:02:16 +02:00
|
|
|
exponent<dim_length, 2>> {};
|
2020-05-14 16:00:38 +02:00
|
|
|
struct dim_speed : derived_dimension<dim_speed, metre_per_second,
|
2020-09-08 11:02:16 +02:00
|
|
|
exponent<dim_length, 1>, exponent<dim_time, -1>> {};
|
2020-03-09 18:55:41 +01:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 12:03:25 +01:00
|
|
|
In the above code sample `isq::si::square_metre` and
|
|
|
|
|
`isq::si::metre_per_second` are the
|
2020-09-08 20:05:30 +02:00
|
|
|
:term:`coherent derived units <coherent derived unit>` of those derived dimensions.
|
2020-03-09 18:55:41 +01:00
|
|
|
|
|
|
|
|
Coherent unit argument is followed by the list of exponents that form this
|
|
|
|
|
derived dimension. This list is called a :term:`recipe` of this derived
|
|
|
|
|
dimension and may contain both base and derived dimensions. In the latter
|
|
|
|
|
case the dimension is being extracted to base dimensions by the framework
|
|
|
|
|
itself. The order and types of dimensions used in the recipe determine how
|
|
|
|
|
an dimension's unnamed unit symbol is being printed in the text output.
|
|
|
|
|
|
|
|
|
|
.. seealso::
|
|
|
|
|
|
|
|
|
|
More information on how the :term:`recipe` affect the printed symbol
|
2021-02-16 16:19:57 +01:00
|
|
|
of unnamed unit can be found in the :ref:`framework/units:Derived Unnamed Units`
|
|
|
|
|
chapter.
|
2020-03-09 18:55:41 +01:00
|
|
|
|
|
|
|
|
It is important to mention here that beside text output the order and
|
|
|
|
|
the number of elements in the `derived_dimension` definition does not
|
|
|
|
|
matter. Even if we define the above as:
|
|
|
|
|
|
|
|
|
|
.. code-block::
|
|
|
|
|
:emphasize-lines: 4, 6
|
|
|
|
|
|
|
|
|
|
namespace si {
|
|
|
|
|
|
2020-05-14 16:00:38 +02:00
|
|
|
struct dim_area : derived_dimension<dim_area, square_metre,
|
2020-09-08 11:02:16 +02:00
|
|
|
exponent<dim_length, 1>, exponent<dim_length, 1>> {};
|
2020-05-14 16:00:38 +02:00
|
|
|
struct dim_speed : derived_dimension<dim_speed, metre_per_second,
|
2020-09-08 11:02:16 +02:00
|
|
|
exponent<dim_time, -1>, exponent<dim_length, 1>> {};
|
2020-03-09 18:55:41 +01:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
the library will do its magic and will end up with the same
|
|
|
|
|
:term:`normalized derived dimension` which will allow the dimensional
|
|
|
|
|
analysis in the library to work as expected.
|
|
|
|
|
|
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
|
|
The first template argument of `derived_dimension` is the type of the
|
|
|
|
|
child class inherited from the instantiation of this `derived_dimension`
|
|
|
|
|
class template. This is called a
|
|
|
|
|
:abbr:`CRTP (Curiously Recurring Template Parameter)` Idiom and is used
|
2021-02-16 16:19:57 +01:00
|
|
|
in many places in this library to provide
|
|
|
|
|
:ref:`design/downcasting:The Downcasting Facility`.
|
2020-03-09 18:55:41 +01:00
|
|
|
Hopefully if [P0847]_ will land in C++23 the additional CRTP-related
|
|
|
|
|
template parameter will be removed from this definition.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Obtaining a Unit of the Dimension
|
|
|
|
|
---------------------------------
|
|
|
|
|
|
|
|
|
|
In order to obtain the base/coherent unit of any dimension type a
|
|
|
|
|
`dimension_unit` helper was introduced::
|
|
|
|
|
|
2020-06-29 20:30:59 +02:00
|
|
|
static_assert(is_same_v<dimension_unit<si::dim_length>, si::metre>);
|
|
|
|
|
static_assert(is_same_v<dimension_unit<si::dim_speed>, si::metre_per_second>);
|