forked from mpusz/mp-units
207 lines
7.4 KiB
ReStructuredText
207 lines
7.4 KiB
ReStructuredText
.. 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.
|
|
Length, time, speed, area, energy are only a few examples of physical
|
|
dimensions.
|
|
|
|
.. raw:: html
|
|
|
|
<object data="../_images/dimensions.svg" type="image/svg+xml" class="align-center" style="max-width: 100%;"></object>
|
|
|
|
..
|
|
https://www.planttext.com
|
|
|
|
|
|
Base Dimensions
|
|
---------------
|
|
|
|
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
|
|
and `isq::si::metre` is a :term:`base unit` of this base dimension. We can
|
|
obtain those back easily with::
|
|
|
|
static_assert(si::dim_length::symbol == "L");
|
|
static_assert(is_same_v<si::dim_length::base_unit, si::metre>);
|
|
|
|
|
|
Derived Dimensions
|
|
------------------
|
|
|
|
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.
|
|
|
|
The [SIBrochure]_ states:
|
|
|
|
All other quantities, with the exception of counts, are derived quantities, which may be
|
|
written in terms of base quantities according to the equations of physics. The dimensions of
|
|
the derived quantities are written as products of powers of the dimensions of the base
|
|
quantities using the equations that relate the derived quantities to the base quantities.
|
|
In general the dimension of any quantity :math:`Q` is written in the form of a dimensional product,
|
|
|
|
:math:`dim Q = T^\alpha L^\beta M^\gamma I^\delta \Theta^\varepsilon N^\zeta J^\eta`
|
|
|
|
where the exponents :math:`\alpha`, :math:`\beta`, :math:`\gamma`, :math:`\delta`, :math:`\varepsilon`,
|
|
:math:`\zeta` and :math:`\eta`, which are generally small integers, which can be positive,
|
|
negative, or zero, are called the dimensional exponents.
|
|
|
|
Looking at the previous code snippets the area, speed, or frequency are
|
|
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``
|
|
- a speed is formed from the length base quantity with exponent ``1``
|
|
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 {
|
|
|
|
struct dim_area : derived_dimension<dim_area, square_metre,
|
|
exponent<dim_length, 2>> {};
|
|
struct dim_speed : derived_dimension<dim_speed, metre_per_second,
|
|
exponent<dim_length, 1>, exponent<dim_time, -1>> {};
|
|
|
|
}
|
|
|
|
In the above code sample `isq::si::square_metre` and
|
|
`isq::si::metre_per_second` are the
|
|
:term:`coherent derived units <coherent derived unit>` of those derived dimensions.
|
|
|
|
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
|
|
of unnamed unit can be found in the :ref:`framework/units:Derived Unnamed Units`
|
|
chapter.
|
|
|
|
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 {
|
|
|
|
struct dim_area : derived_dimension<dim_area, square_metre,
|
|
exponent<dim_length, 1>, exponent<dim_length, 1>> {};
|
|
struct dim_speed : derived_dimension<dim_speed, metre_per_second,
|
|
exponent<dim_time, -1>, exponent<dim_length, 1>> {};
|
|
|
|
}
|
|
|
|
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
|
|
in many places in this library to provide
|
|
:ref:`design/downcasting:The Downcasting Facility`.
|
|
|
|
|
|
Obtaining a Unit of the Dimension
|
|
---------------------------------
|
|
|
|
In order to obtain the base/coherent unit of any dimension type a
|
|
`dimension_unit` helper was introduced::
|
|
|
|
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>);
|
|
|
|
|
|
|
|
|
|
How do you feel about:
|
|
|
|
inline constexpr second second;
|
|
?
|
|
|
|
We could do the same to dimensions to not have to type dim_length{} all the time.
|
|
|
|
6 replies 2 new
|
|
@JohelEGP
|
|
JohelEGP
|
|
2 days ago
|
|
mp_units::units::second is a variable. The reference isq::si::second could stay a type and s continue to be a variable.
|
|
|
|
@mpusz
|
|
mpusz
|
|
2 days ago
|
|
Maintainer
|
|
Author
|
|
The problem is the following:
|
|
|
|
Variables are really needed for a new design. We can ask users to put {} after every dimension unit, and reference types but it would be really nasty and a lot of boilerplate.
|
|
Short names have to be opt-in as they collide with a lot of code (especially on MSVC).
|
|
@JohelEGP
|
|
JohelEGP
|
|
yesterday
|
|
As pointed out by #389 (reply in thread), I think it'd be OK suffix _t to the types.
|
|
|
|
@mpusz
|
|
mpusz
|
|
10 hours ago
|
|
Maintainer
|
|
Author
|
|
It will be visible in the compilation errors, which is inconvenient :-(
|
|
|
|
Instead of:
|
|
|
|
quantity<reference<derived_dimension<length_dim, per<time_dim>>, derived_unit<metre, per<second>>>
|
|
we will have something like:
|
|
|
|
quantity<reference<derived_dimension<length_dim_t, per<time_dim_t>>, derived_unit<metre_t, per<second_t>>>
|
|
Personally, I like the first output more.
|
|
|
|
Note that definition like:
|
|
|
|
inline constexpr second second;
|
|
besides, being really unconventional, is allowed by the language and will not impact our users at all. A user is about to always work with values in the code and observe types in the compilation errors. Using the same nicely blends those two domains together.
|
|
|
|
@mpusz
|
|
mpusz
|
|
10 hours ago
|
|
Maintainer
|
|
Author
|
|
I could use a list of values instead of types as template parameters in the dervied_dimension and derived_unit but in such case the error would look like:
|
|
|
|
quantity<reference<derived_dimension<length_dim{}, per<time_dim{}>{}>{}, derived_unit<metre{}, per<second{}>{}>{}>>
|
|
which also is not that nice.
|
|
|
|
@JohelEGP
|
|
JohelEGP
|
|
6 hours ago
|
|
That's convincing. This justification should definitely be part of the documentation.
|