Design Overview¶
The most important entities in the mp-units library are:
- quantity,
- quantity point,
- unit,
- dimension,
- quantity specification
- quantity reference,
- quantity representation.
The graph provided below presents how those and a few other entities depend on each other:
flowchart TD
Unit --- Reference
Dimension --- QuantitySpec["Quantity specification"]
quantity_character["Quantity character"] --- QuantitySpec
QuantitySpec --- Reference["Quantity reference"]
Reference --- Quantity
quantity_character -.- Representation
Representation --- Quantity
Quantity --- QuantityPoint["Quantity point"]
PointOrigin["Point origin"] --- QuantityPoint
click Dimension "#dimension"
click quantity_character "#quantity-character"
click QuantitySpec "#quantity-specification"
click Unit "#unit"
click Reference "#quantity-reference"
click Representation "#quantity-representation"
click Quantity "#quantity"
click PointOrigin "#point-origin"
click QuantityPoint "#quantity-point"
Dimension¶
Dimension specifies the dependence of a quantity on the base quantities of a particular system of quantities. It is represented as a product of powers of factors corresponding to the base quantities, omitting any numerical factor.
In the mp-units library, we use the terms:
- base dimension to refer to the dimension of a base quantity,
- derived dimension to refer to the dimension of a derived quantity.
For example:
- length (\(\mathsf{L}\)), mass (\(\mathsf{M}\)), time (\(\mathsf{T}\)), electric current (\(\mathsf{I}\)), thermodynamic temperature (\(\mathsf{Θ}\)), amount of substance (\(\mathsf{N}\)), and luminous intensity (\(\mathsf{J}\)) are the base dimensions of the ISQ.
- A derived dimension of force in the ISQ is denoted by \(\textsf{dim }F = \mathsf{LMT}^{–2}\).
- The implementation of IEC 80000 in this library provides
iec::dim_traffic_intensity
base dimension to extend ISQ with strong information technology quantities.
Base dimensions can be defined by the user in the following way:
inline constexpr struct dim_length final : base_dimension<"L"> {} dim_length;
inline constexpr struct dim_time final : base_dimension<"T"> {} dim_time;
Derived dimensions are implicitly created by the library's framework based on the quantity equation provided in the quantity specification:
inline constexpr struct length final : quantity_spec<length, dim_length> {} length;
inline constexpr struct time final : quantity_spec<time, dim_time> {} time;
inline constexpr struct speed final : quantity_spec<speed, length / time> {} speed;
static_assert(speed.dimension == dim_length / dim_time);
Important
Users should not explicitly define any derived dimensions. Those should always be implicitly created by the framework.
The multiplication/division on quantity specifications also multiplies/divides their dimensions:
The dimension equation of isq::dim_length / isq::dim_time
results in the derived_dimension<isq::dim_length, per<isq::dim_time>>
type.
Quantity character¶
ISO 80000 explicitly states that quantities (even of the same kind) may have different characters:
- scalar,
- vector,
- tensor.
The quantity character in the mp-units library is implemented with the quantity_character
enumeration:
Info
You can read more on quantity characters in the "Character of a Quantity" chapter.
Quantity specification¶
Dimension is not enough to describe a quantity. This is why the ISO 80000 provides hundreds of named quantity types. It turns out that there are many more quantity types in the ISQ than the named units in the SI.
This is why the mp-units library introduces a quantity specification entity that stores:
- dimension,
- quantity type/name,
- quantity character,
- the quantity equation being the recipe to create this quantity (only for derived quantities that specify such a recipe).
Note
We know that it might be sometimes confusing to talk about quantities, quantity types/names, and quantity specifications. However, it might be important to notice here that even the ISO 80000 admits that:
It is customary to use the same term, "quantity", to refer to both general quantities, such as length, mass, etc., and their instances, such as given lengths, given masses, etc. Accordingly, we are used to saying both that length is a quantity and that a given length is a quantity by maintaining the specification – "general quantity, \(Q\)" or "individual quantity, \(Q_\textsf{a}\)" – implicit and exploiting the linguistic context to remove the ambiguity.
In the mp-units library, we have a:
- quantity - implemented as a
quantity
class template, - quantity specification - implemented with a
quantity_spec
class template that among others identifies a specific quantity type/name.
For example:
isq::length
,isq::mass
,isq::time
,isq::electric_current
,isq::thermodynamic_temperature
,isq::amount_of_substance
, andisq::luminous_intensity
are the specifications of base quantities in the ISQ.isq::width
,isq::height
,isq::radius
, andisq::position_vector
are only a few of many quantities of a kind length specified in the ISQ.isq::area
,isq::speed
,isq::moment_of_force
are only a few of many derived quantities provided in the ISQ.
Quantity specification can be defined by the user in one of the following ways:
The quantity equation of isq::length / isq::time
results
in the derived_quantity_spec<isq::length, per<isq::time>>
type.
Unit¶
A unit is a concrete amount of a quantity that allows us to measure the values of quantities of the same kind and represent the result as a number being the ratio of the two quantities.
For example:
si::second
,si::metre
,si::kilogram
,si::ampere
,si::kelvin
,si::mole
, andsi::candela
are the base units of the SI.si::kilo<si::metre>
is a prefixed unit of length.si::radian
,si::newton
, andsi::watt
are examples of named derived units within the SI.non_si::minute
is an example of a scaled unit of time.si::si2019::speed_of_light_in_vacuum
is a physical constant standardized by the SI in 2019.
Note
In the mp-units library, physical constants are also implemented as units.
A unit can be defined by the user in one of the following ways:
template<PrefixableUnit U> struct kilo_ : prefixed_unit<"k", mag_power<10, 3>, U{}> {};
template<PrefixableUnit auto U> constexpr kilo_<decltype(U)> kilo;
inline constexpr struct second final : named_unit<"s", kind_of<isq::time>> {} second;
inline constexpr struct minute final : named_unit<"min", mag<60> * second> {} minute;
inline constexpr struct gram final : named_unit<"g", kind_of<isq::mass>> {} gram;
inline constexpr auto kilogram = kilo<gram>;
inline constexpr struct newton final : named_unit<"N", kilogram * metre / square(second)> {} newton;
inline constexpr struct speed_of_light_in_vacuum final : named_unit<"c", mag<299'792'458> * metre / second> {} speed_of_light_in_vacuum;
The unit equation of si::metre / si::second
results
in the derived_unit<si::metre, per<si::second>>
type.
Quantity reference¶
ISO defines a quantity as:
Quote
property of a phenomenon, body, or substance, where the property has a magnitude that can be expressed as a number and a reference
After that, it says:
Quote
A reference can be a measurement unit, a measurement procedure, a reference material, or a combination of such.
In the mp-units library, a quantity reference provides all the domain-specific metadata for the quantity besides its numerical value:
- all the data stored in the quantity specification,
- unit.
Together with the value of a representation type, it forms a quantity.
In the library, we have two different ways to provide a reference:
- every unit with the associated quantity kind is a valid reference,
- providing a unit to an indexing operator of a quantity specification explicitly instantiates
a
reference
class template with this quantity spec and a unit passed as arguments.
Note
All the units of the SI have associated quantity kinds and may serve as a reference.
For example:
si::metre
is defined in the SI as a unit ofisq::length
and thus can be used as a reference to instantiate a quantity of length (e.g.,42 * m
).- The expression
isq::height[m]
results withreference<isq::height, si::metre>
, which can be used to instantiate a quantity ofisq::height
with a unit ofsi::metre
(e.g.,42 * isq::height[m]
).
Quantity representation¶
Quantity representation defines the type used to store the numerical value of a quantity. Such a type should be of a specific quantity character provided in the quantity specification.
Note
By default, all floating-point and integral (besides bool
) types are treated as scalars.
Quantity¶
ISO defines a quantity as:
Quote
property of a phenomenon, body, or substance, where the property has a magnitude that can be expressed as a number and a reference
This is why a quantity
class template is defined in the library as:
Its value can be easily created by multiplying/dividing the numerical value and a reference.
For example:
- All of
42 * m
,42 * si::metre
,42 * isq::height[m]
, andisq::height(42 * m)
create a quantity. - A quantity type can also be specified explicitly (e.g.,
quantity<si::metre, int>
,quantity<isq::height[m]>
).
Point origin¶
In the affine space theory, the point origin specifies where the "zero" of our measurement's scale is.
In the mp-units library, we have two types of point origins:
- absolute - defines an absolute "zero" for our point,
- relative - defines an origin that has some "offset" relative to an absolute point.
For example:
- the absolute point origin can be defined in the following way:
inline constexpr struct absolute_zero final : absolute_point_origin<isq::thermodynamic_temperature> {} absolute_zero;
- the relative point origin can be defined in the following way:
inline constexpr struct ice_point final : relative_point_origin<absolute_zero + 273'150 * milli<kelvin>> {} ice_point;
Quantity point¶
Quantity point implements a point in the affine space theory.
In the mp-units library, the quantity point is implemented as:
template<Reference auto R,
PointOriginFor<get_quantity_spec(R)> auto PO,
RepresentationOf<get_quantity_spec(R)> Rep = double>
class quantity_point;
Its value can be easily created by adding/subtracting the quantity with a point origin.
For example:
- The following specifies a quantity point defined in terms of an
ice_point
provided in the previous example: