mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-30 18:37:15 +02:00
feat(example): spectroscopy_units
example added
This commit is contained in:
158
docs/users_guide/framework_basics/character_of_a_quantity.md
Normal file
158
docs/users_guide/framework_basics/character_of_a_quantity.md
Normal 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.
|
@ -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(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(measurement mp-units::core-io mp-units::si)
|
||||||
add_example(si_constants mp-units::core-fmt 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(storage_tank mp-units::core-fmt mp-units::si mp-units::utility)
|
||||||
add_example(
|
add_example(
|
||||||
strong_angular_quantities mp-units::core-fmt mp-units::core-io mp-units::si mp-units::isq_angle mp-units::utility
|
strong_angular_quantities mp-units::core-fmt mp-units::core-io mp-units::si mp-units::isq_angle mp-units::utility
|
||||||
|
104
example/spectroscopy_units.cpp
Normal file
104
example/spectroscopy_units.cpp
Normal 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);
|
||||||
|
}
|
@ -111,8 +111,8 @@ nav:
|
|||||||
- Systems of Units: users_guide/framework_basics/systems_of_units.md
|
- Systems of Units: users_guide/framework_basics/systems_of_units.md
|
||||||
- Simple and Typed Quantities: users_guide/framework_basics/simple_and_typed_quantities.md
|
- Simple and Typed Quantities: users_guide/framework_basics/simple_and_typed_quantities.md
|
||||||
- Value Conversions: users_guide/framework_basics/value_conversions.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
|
- 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
|
- Faster-than-lightspeed Constants: users_guide/framework_basics/faster_than_lightspeed_constants.md
|
||||||
- Dimensionless Quantities: users_guide/framework_basics/dimensionless_quantities.md
|
- Dimensionless Quantities: users_guide/framework_basics/dimensionless_quantities.md
|
||||||
- The Affine Space: users_guide/framework_basics/the_affine_space.md
|
- The Affine Space: users_guide/framework_basics/the_affine_space.md
|
||||||
|
Reference in New Issue
Block a user