feat(example): spectroscopy_units example added

This commit is contained in:
Mateusz Pusz
2023-07-08 12:59:38 +02:00
parent b67fc48250
commit 3a94ca89fd
5 changed files with 264 additions and 1 deletions

View File

@ -0,0 +1,158 @@
# Character of a Quantity
!!! warning
Features described in this chapter are experimental and are subject to change or removal. Please
share your feedback if something doesn't seem right or could be improved.
## Scalars, vectors, and tensors
!!! quote "ISO 80000-2"
Scalars, vectors and tensors are mathematical objects that can be used to denote certain physical
quantities and their values. They are as such independent of the particular choice of a coordinate system,
whereas each scalar component of a vector or a tensor and each component vector and component
tensor depend on that choice.
While defining quantities ISO 80000 explicitly mentions when a specific quantity has a vector or tensor
character. Such distinction is important because each quantity character represent different properties
and allows different operations to be done on their quantities.
For example, imagine a physical units library that allows to create a `speed` quantity from both
`length / time` and `length * time`. It wouldn't be too safe to use such a product, right?
Now we have to realize that both of the above operations (multiplication and division) are even not
mathematically defined for linear algebra types such as vector or tensors. On the other hand, two vectors
can be passed as arguments to dot (`⋅`) and cross (`×`) product operations. The result of the first one is
a scalar. The second one results with a vector that is perpendicular to both vectors passed as arguments.
Again, it wouldn't be safe to allow replacing those two operations with each other or expect the same
results from both cases. This simply can't work.
## Examples from the ISQ
To provide some examples for further discussion let's pick a few quantities defined in the ISO 80000:
| Quantity | Character | Quantity Equation |
|------------------------|:------------:|:-------------------------------------------------:|
| `duration` | scalar | _{base quantity}_ |
| `mass` | scalar | _{base quantity}_ |
| `length` | scalar | _{base quantity}_ |
| `path_length` | scalar | _{base quantity}_ |
| `radius` | scalar | _{base quantity}_ |
| `position_vector` | **vector** | _{base quantity}_ |
| `velocity` | **vector** | `position_vector / duration` |
| `acceleration` | **vector** | `velocity / duration` |
| `force` | **vector** | `mass * acceleration` |
| `power` | scalar | `force ⋅ velocity` |
| `moment_of_force` | **vector** | `position_vector × force` |
| `torque` | scalar | `moment_of_force ⋅ {unit-vector}` |
| `surface_tension` | scalar | `|force| / length` |
| `angular_displacement` | scalar | `path_length / radius` |
| `angular_velocity` | **vector** | `angular_displacement / duration * {unit-vector}` |
| `momentum` | **vector** | `mass * velocity` |
| `angular_momentum` | **vector** | `position_vector × momentum` |
| `moment_of_inertia` | **_tensor_** | `angular_momentum ⊗ angular_velocity` |
!!! note
As of now, all of the C++ physical units libraries on the market besides **mp-units** do not
support above-mentioned operations. They expose only multiplication and division operators which
do not work for proper linear-algebra-based representation types. In case one would like to
construct the quantities provided in the above table with those libraries, this would result with
a compile-time error stating that multiplication and division of two linear-algebra vectors is not
possible.
## Characters apply to quantities but not dimensions or units
ISO 80000 explicitly states that dimensions are orthogonal to quantity characters:
!!! quote "ISO 80000-1:2009"
In deriving the dimension of a quantity, no account is taken of its scalar, vector, or tensor character.
Also, it explicitly states that:
!!! quote "ISO 80000-2"
All units are scalars.
## Defining vector and tensor quantities
To specify that a specific quantity has a vector or tensor character a value of `quantity_character`
enumeration can be appended to the `quantity_spec` describing such a quantity type:
```cpp
inline constexpr struct position_vector : quantity_spec<length, quantity_character::vector> {} position_vector;
inline constexpr struct displacement : quantity_spec<length, quantity_character::vector> {} displacement;
```
From now on all the quantities derived from `position_vector` or `displacement` will have a correct
character consistent with the operations performed in the [quantity equation](../../../appendix/glossary/#quantity-equation)
on their arguments.
## Representation types for vector and tensor quantities
!!! note
The current version of the C++ Standard Library does not provide any types that could be used as
a representation type for vector and tensor quantities. This is why users are on their own here
:worried:.
To provide examples and implement unit tests our library uses the types proposed in the [P1385](https://wg21.link/p1385)
and available as [a Conan package in the Conan Center](https://conan.io/center/wg21-linear_algebra).
In order to enable the usage of a user-defined type as a representation type for vector or tensor
quantities you need to provide a partial specialization of `is_vector` or `is_tensor` customization
points.
For example, here is how it can be done for the [P1385](https://wg21.link/p1385) types:
```cpp
#include <matrix>
using la_vector = STD_LA::fixed_size_column_vector<double, 3>;
template<>
inline constexpr bool mp_units::is_vector<la_vector> = true;
```
## Hacking the character
Sometimes you want to use a vector quantity but you do not care about its direction. For example,
the standard gravity acceleration constant is always pointing down and you might not care about this
in a particular case. In such a case you may want to "hack" the library to allow scalar types
to be used as a representation type for scalar quantities.
For example, you can do something like this:
```cpp
template<class T>
requires mp_units::is_scalar<T>
inline constexpr bool mp_units::is_vector<T> = true;
```
which says that every type that can be used a scalar representation is also allowed for vector
quantities.
Doing the above is actually not such a big "hack" as the ISO 80000 explicitly allows it:
!!! quote "ISO 80000-2"
A vector is a tensor of the first order and a scalar is a tensor of order zero.
However, for type-safety reasons, we do not want to allow of such a behavior by default.
## Different shades of vector and tensor quantities
Instead of treating each coordinate of a vector as a physical quantity value (i.e. a number multiplied by
a unit), the vector could be written as a numerical vector multiplied by a unit.
The same considerations apply to tensors of second and higher orders.

View File

@ -53,6 +53,7 @@ add_example(glide_computer mp-units::core-fmt mp-units::international mp-units::
add_example(hello_units mp-units::core-fmt mp-units::core-io mp-units::si mp-units::usc)
add_example(measurement mp-units::core-io mp-units::si)
add_example(si_constants mp-units::core-fmt mp-units::si)
add_example(spectroscopy_units mp-units::core-fmt mp-units::si)
add_example(storage_tank mp-units::core-fmt mp-units::si mp-units::utility)
add_example(
strong_angular_quantities mp-units::core-fmt mp-units::core-io mp-units::si mp-units::isq_angle mp-units::utility

View File

@ -0,0 +1,104 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Mateusz Pusz
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <mp-units/format.h>
#include <mp-units/systems/isq/isq.h>
#include <mp-units/systems/si/si.h>
#include <iostream>
#include <tuple>
// This example implements a table of units provided in the following article
// http://cds.cern.ch/record/1481609/files/978-3-642-18018-7_BookBackMatter.pdf
using namespace mp_units;
// import selected unit symbols only
using mp_units::si::unit_symbols::cm;
using mp_units::si::unit_symbols::eV;
using mp_units::si::unit_symbols::K;
using mp_units::si::unit_symbols::kJ;
using mp_units::si::unit_symbols::mol;
using mp_units::si::unit_symbols::THz;
using mp_units::si::unit_symbols::um;
// physical constants
constexpr auto c = 1 * si::si2019::speed_of_light_in_vacuum;
constexpr auto h = 1 * si::si2019::planck_constant;
constexpr auto kb = 1 * si::si2019::boltzmann_constant;
// prints quantities in the resulting unit
template<QuantityOf<isq::energy> T1, QuantityOf<isq::wavenumber> T2, QuantityOf<isq::frequency> T3,
QuantityOf<isq::thermodynamic_temperature> T4, QuantityOf<isq::wavelength> T5>
void print_line(const std::tuple<T1, T2, T3, T4, T5>& t)
{
MP_UNITS_STD_FMT::println("| {:<15} | {:<15} | {:<15} | {:<15} | {:<15} |", std::get<0>(t), std::get<1>(t),
std::get<2>(t), std::get<3>(t), std::get<4>(t));
}
// prints quantities in semi-SI units
// (eV is not an official SI unit)
template<QuantityOf<isq::energy> T1, QuantityOf<isq::wavenumber> T2, QuantityOf<isq::frequency> T3,
QuantityOf<isq::thermodynamic_temperature> T4, QuantityOf<isq::wavelength> T5>
void print_line_si(const std::tuple<T1, T2, T3, T4, T5>& t)
{
MP_UNITS_STD_FMT::println("| {:<15} | {:<15} | {:<15} | {:<15} | {:<15} |", std::get<0>(t)[eV],
std::get<1>(t)[1 / cm], std::get<2>(t)[THz], std::get<3>(t)[K], std::get<4>(t)[um]);
}
int main()
{
const auto q1 = isq::energy(1. * eV);
const auto t1 = std::make_tuple(q1, isq::wavenumber(q1 / (h * c)), isq::frequency(q1 / h),
isq::thermodynamic_temperature(q1 / kb), isq::wavelength(h * c / q1));
const auto q2 = 1. * isq::wavenumber[1 / cm];
const auto t2 = std::make_tuple(isq::energy(q2 * h * c), q2, isq::frequency(q2 * c),
isq::thermodynamic_temperature(q2 * h * c / kb), isq::wavelength(1 / q2));
const auto q3 = isq::frequency(1. * THz);
const auto t3 = std::make_tuple(isq::energy(q3 * h), isq::wavenumber(q3 / c), q3,
isq::thermodynamic_temperature(q3 * h / kb), isq::wavelength(c / q3));
const auto q4 = isq::thermodynamic_temperature(1. * K);
const auto t4 = std::make_tuple(isq::energy(q4 * kb), isq::wavenumber(q4 * kb / (h * c)), isq::frequency(q4 * kb / h),
q4, isq::wavelength(h * c / (q4 * kb)));
const auto q5 = isq::wavelength(1. * um);
const auto t5 = std::make_tuple(isq::energy(h * c / q5), isq::wavenumber(1 / q5), isq::frequency(c / q5),
isq::thermodynamic_temperature(h * c / (q5 * kb)), q5);
MP_UNITS_STD_FMT::println("| {:<15} | {:<15} | {:<15} | {:<15} | {:<15} |", "Energy", "Wavenumber", "Frequency",
"Temperature", "Wavelength");
MP_UNITS_STD_FMT::println("| {0:-^15} | {0:-^15} | {0:-^15} | {0:-^15} | {0:-^15} |", "");
print_line(t1);
print_line(t2);
print_line(t3);
print_line(t4);
print_line(t5);
MP_UNITS_STD_FMT::println("| {0:-^15} | {0:-^15} | {0:-^15} | {0:-^15} | {0:-^15} |", "");
print_line_si(t1);
print_line_si(t2);
print_line_si(t3);
print_line_si(t4);
print_line_si(t5);
}

View File

@ -111,8 +111,8 @@ nav:
- Systems of Units: users_guide/framework_basics/systems_of_units.md
- Simple and Typed Quantities: users_guide/framework_basics/simple_and_typed_quantities.md
- Value Conversions: users_guide/framework_basics/value_conversions.md
- Character of a Quantity: users_guide/framework_basics/character_of_a_quantity.md
- Quantity Arithmetics: users_guide/framework_basics/quantity_arithmetics.md
- Quantities of Different Characters: users_guide/framework_basics/quantities_of_different_characters.md
- Faster-than-lightspeed Constants: users_guide/framework_basics/faster_than_lightspeed_constants.md
- Dimensionless Quantities: users_guide/framework_basics/dimensionless_quantities.md
- The Affine Space: users_guide/framework_basics/the_affine_space.md