feat: full-on dimensional analysis between related quantity kinds

This commit is contained in:
Johel Ernesto Guerrero Peña
2021-02-21 00:17:03 +01:00
committed by Mateusz Pusz
parent dad9b4f166
commit 017183653d
11 changed files with 295 additions and 49 deletions
+1
View File
@@ -49,6 +49,7 @@ set(unitsSphinxDocs
"${CMAKE_CURRENT_SOURCE_DIR}/design/directories.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/design/downcasting.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/design/quantity.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/design/quantity_kind.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/avg_speed.rst"
+52
View File
@@ -0,0 +1,52 @@
.. namespace:: units
quantity_kind
=============
The ``quantity_kind`` class template provides a similar interface to ``quantity``.
Kinds
-----
The first template parameter of ``quantity_kind`` is a ``Kind``.
``Kind``s, by themselves:
* Wrap a ``Dimension``, and
* opt into the downcasting facility.
If a dimensional analysis operator on a quantity of kind *A*
can result on a quantity of kind *B*,
*A* and *B* are *related*.
The library provides two ``Kind`` bases, ``kind`` and ``derived_kind``.
``kind`` is an entry point, and there's only one per set of related kinds.
``derived_kind`` is used to explicitly name other related kinds.
Unnamed, they look like ``detail::_kind_base<the-entry-kind, some_dimension>``.
Unnamed kinds, like unnamed units and dimensions,
allows (intermediate) results in formulas without having to name them.
Quantity kinds
--------------
``quantity_kind`` wraps a ``quantity`` and layers over its dimensional analysis.
While all properties of the ``quantity`` apply transparently,
results are always ``quantity_kind``s related to the kind(s) of the argument(s).
One of the arguments to the dimensional analysis operators can also be ``Quantity``.
The way back to ``quantity`` is through the ``.common()`` observer.
Intra-kind operations
---------------------
``quantity_kind`` takes care of operators between related quantity kinds.
Intra-kind operations can be opted into as follows::
struct width : kind<width, dim_length> {};
struct height : kind<height, dim_length> {};
size2d operator+(QuantityKindOf<width> auto, QuantityKindOf<height> auto);
+30 -13
View File
@@ -67,23 +67,40 @@ dimension, than we will end up with just a dimensionless quantity:
Quantity Kinds
++++++++++++++
Quantity kinds behave the same as quantities for addition and subtraction.
The same behavior is also provided for multiplication with, and division by
a :term:`scalable number`.
Multiplication and division with a quantity (but not a quantity kind) is allowed.
The result is a quantity kind with the appropriate dimension
and related to the original quantity kind:
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.
.. code-block::
:emphasize-lines: 5-6
:emphasize-lines: 8-9
struct height : kind<height, dim_length> {};
struct rate_of_climb : derived_kind<rate_of_climb, height, dim_speed> {};
struct height_kind : kind<height_kind, dim_length> {};
struct rate_of_climb_kind : derived_kind<rate_of_climb_kind, height_kind, dim_speed> {};
quantity_kind h(height{}, 100 * m);
quantity_point_kind rate = h / (25 * s);
// quantity_point_kind<rate_of_climb, si::metre_per_second, int>(4 * m / s)
template <Unit U, QuantityValue Rep = double> using height = quantity_kind<height_kind, U, Rep>;
template <Unit U, QuantityValue Rep = double> using rate_of_climb = quantity_kind<rate_of_climb_kind, U, Rep>;
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)
.. code-block::
: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> {};
template <Unit U, QuantityValue Rep = double> using width = quantity_kind<width_kind, U, Rep>;
template <Unit U, QuantityValue Rep = double> using horizontal_area = quantity_kind<horizontal_area_kind, U, Rep>;
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}
Quantity Points
+++++++++++++++
+2 -2
View File
@@ -41,7 +41,7 @@ the value to the `quantity_kind` class template constructor::
Differences To Quantity
-----------------------
Unlike `quantity`, the library provides:
The library provides:
- no kinds, such as ``radius`` or ``width``, therefore
@@ -49,7 +49,7 @@ Unlike `quantity`, the library provides:
* no kind-specific concepts, such as ``Radius``,
(there's the generic `QuantityKind` and kind-specifiable `QuantityKindOf`),
- a slightly different set of operations on quantity kinds
- a slightly larger set of operations on quantity kinds
(see the :ref:`framework/dimensions:Quantity Kinds` chapter).