Units and quantities¶
Internally, wave_tracer uses a strongly-typed unit system for all physical quantities. This is very useful when writing physical simulation software, and helps catch errors early. Scene files also use units for quantities.
wave_tracer defines wt::f_t
as the floating-point representation type for real numbers.
wt::f_t
to the single-precision 32-bit float, but can be compile-time configured.
wave_tracer uses the mp-units library for strongly-typed units and dimensions.
Units are defined in namespace wt::u
.
The underlying numeric representation for all these quantities is wt::f_t
.
In addition, common types for quantities, like length, wavenumber and power, are defined (see below).
For example,
length_t len = 3 * u::mm;
area_t area = m::sqr(len);
auto p = irradiance_t(1.1f * u::W / area);
std::cout << std::format("{}", p) << std::endl;
defines a variable with a quantity concept of ISQ length with units of millimetre, squares it to produce area, and then constructs a quantity of radiometric irradiance.
length_t stores values in units of metres.
Dimensionless quantities can be cast to a unitless number wt::f_t
in two ways:
auto area_ratio = area / (.5f * u::m2);
std::cout << std::format("{}", (f_t)area_ratio) << std::endl;
std::cout << std::format("{}", u::to_num(area_ratio)) << std::endl;
The static cast guarantees a lossless conversion. At times a lossless conversion is not possible, and the static cast will fail to compile:
auto area_ratio = area / m::sqr(1 * u::mm);
std::cout << std::format("{}", (f_t)area_ratio) << std::endl; // fails to compile!
std::cout << std::format("{}", u::to_num(area_ratio)) << std::endl; // compiles: forces lossy conversion
The former is not a lossless conversion because the type area_t uses units of metre squared; therefore, even though the type of area_ratio is a dimensionless quantity, its units include a static scaling constant of \(\tfrac{\text{m}^2}{\text{mm}^2}\), and a conversion to a unitless number cannot be done losslessly.
The explicit cast via wt::u::to_num()
forces a lossy conversion.
Neither form will compile when attempting to convert from a non-dimensionless quantity. To cast units away, different functions of the form wt::u::to_X are provided. For example,
length_t len = 3 * u::mm;
std::cout << std::format("len = {} mm", u::to_mm(1 * u::m)) << std::endl;
std::cout << std::format("len = {} m", u::to_m(len)) << std::endl;
std::cout << std::format("{}", u::to_Hz(1 * u::m)) << std::endl; // fails to compile: cannot cast `mm` to `Hz`
The first cast is lossless, and simply discards the units to produce a number (of type wt::f_t
); the second cast is lossy, and first converts the representation of len to metres; the third cast does not compile as a conversion from millimetres to Hertz is not legal.
Quantities of same concept can be compared to each other and ordered:
static_assert(1 * u::mm < 1 * u::m);
Comparisons between quantities of different concepts will fail to compile.
Common math operations, like wt::m::sqrt()
, wt::m::abs()
, wt::m::inverse()
are defined for quantities and behave properly.
Likewise, trigonometric functions are defined for angle quantities.
c++ concepts for different quantity concepts are also defined.
For example, the following template function accepts any angle quantities, with no runtime conversions:
auto cone_solid_angle(const Angle auto& half_opening_angle) {
return m::four_pi * m::sqr(m::sin(half_opening_angle / 2.f));
}
std::cout << std::format("{}", cone_solid_angle(1 * u::ang::rad)) << std::endl;
std::cout << std::format("{}", cone_solid_angle(m::pi/180 * u::ang::deg)) << std::endl;
General quantities¶
The following general quantities are defined. The suffix “[unit]” indicates the units used for internal storage.
length |
|
area |
|
volume |
|
length density |
|
area density |
|
volume density |
|
angle |
|
solid angle |
|
angle density |
|
solid angle density |
|
wavenumber |
|
wavelength |
|
frequency |
|
wavenumber density |
|
wavelength density |
|
power |
|
temperature |
|
As long as the quantity concepts match, a quantity can be implicitly converted to another.
For example: f_t(1) / length_t(2 * u::m) can be implicitly captured by a wt::length_density_t
, and vice versa.
Some helper converters for quantities that quantify electrodynamic (EM) radiation frequency are defined:
wavelength to wavenumber |
|
wavenumber to wavelength |
|
EM frequency to wavelength (vacuum) |
|
EM frequency to wavenumber (vacuum) |
|
wavenumber (vacuum) to EM frequency |
Radiometric quantities¶
wave_tracer defines common power-derived radiometric quantities, including spectral variants. Note that wave_tracer defines spectral quantities per wavenumber, and not per wavelength.
radiated flux |
|
radiant intensity |
|
radiated irradiance |
|
radiance |
|
spectral radiated flux |
|
spectral radiant intensity |
|
spectral irradiance |
|
spectral radiance |
|
Importance-derived quantities are also defined:
importance flux |
|
importance flux per solid angle |
|
importance flux per area |
|
importance (Quantum efficiency) |
|
The importance-derived quantities have a similar geometric meaning to the power-derived quantities: for example, spectral radiated flux and importance flux are both quantities that integrate emitted power or importance, respectively, over solid angle and area; spectral irradiance and importance flux per area are both differential quantities that quantify flux (power or importance, respectively) per unit area.
Non-spectral variants of importance-derived quantities above are not defined, as these are not used in practice.
Facilities that are used for light transport, like Stokes parameters vectors and beams (the primary light transport primitive), have specializations for relevant radiometric quantities.
For example, wt::spectral_radiance_stokes_t
and wt::spectral_radiance_beam_t
.
Units in scene file¶
WIP