mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-30 02:17:16 +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(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
|
||||
|
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
|
||||
- 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
|
||||
|
Reference in New Issue
Block a user