Skip to main content

qtty_core/units/
dimensionless.rs

1// SPDX-License-Identifier: BSD-3-Clause
2// Copyright (C) 2026 Vallés Puig, Ramon
3
4//! Named dimensionless units for domain-specific ratios.
5//!
6//! These unit markers all have the [`Dimensionless`] dimension and a ratio of
7//! `1.0`, but their names preserve semantic intent in public APIs. They are
8//! useful when a raw scalar would otherwise hide whether a value is an optical
9//! depth, airmass, reflectance-like fraction, or refractivity.
10
11use crate::{Quantity, Unit};
12use qtty_derive::Unit;
13
14/// Re-export the dimensionless dimension from the dimension module.
15pub use crate::dimension::Dimensionless;
16
17/// Marker trait for any [`Unit`] whose dimension is [`Dimensionless`].
18pub trait DimensionlessUnit: Unit<Dim = Dimensionless> {}
19impl<T: Unit<Dim = Dimensionless>> DimensionlessUnit for T {}
20
21/// Atmospheric vertical or slant optical depth `tau`.
22#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
23#[unit(symbol = "", dimension = Dimensionless, ratio = 1.0)]
24pub struct OpticalDepth;
25
26/// A quantity measured as optical depth.
27pub type OpticalDepths = Quantity<OpticalDepth>;
28
29/// Airmass `X`, the path-length multiplier relative to zenith.
30#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
31#[unit(symbol = "", dimension = Dimensionless, ratio = 1.0)]
32pub struct Airmass;
33
34/// A quantity measured as airmass.
35pub type Airmasses = Quantity<Airmass>;
36
37/// Transmittance `T`, the surviving fraction of incident flux.
38#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
39#[unit(symbol = "", dimension = Dimensionless, ratio = 1.0)]
40pub struct Transmittance;
41
42/// A quantity measured as transmittance.
43pub type Transmittances = Quantity<Transmittance>;
44
45/// Bond or geometric albedo.
46#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
47#[unit(symbol = "", dimension = Dimensionless, ratio = 1.0)]
48pub struct Albedo;
49
50/// A quantity measured as albedo.
51pub type Albedos = Quantity<Albedo>;
52
53/// Illuminated fraction of a planetary or lunar disk.
54#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
55#[unit(symbol = "", dimension = Dimensionless, ratio = 1.0)]
56pub struct IlluminationFraction;
57
58/// A quantity measured as illuminated fraction.
59pub type IlluminationFractions = Quantity<IlluminationFraction>;
60
61/// Atmospheric refractivity `n - 1`.
62#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
63#[unit(symbol = "", dimension = Dimensionless, ratio = 1.0)]
64pub struct Refractivity;
65
66/// A quantity measured as refractivity.
67pub type Refractivities = Quantity<Refractivity>;
68
69/// A generic dimensionless ratio (e.g. `v/c`, efficiency, scale factor).
70///
71/// Use this when no more specific named dimensionless unit applies.
72#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Unit)]
73#[unit(symbol = "", dimension = Dimensionless, ratio = 1.0)]
74pub struct Ratio;
75
76/// A quantity measured as a dimensionless ratio.
77pub type Ratios = Quantity<Ratio>;
78
79/// Canonical list of named dimensionless units.
80#[macro_export]
81#[doc(hidden)]
82macro_rules! dimensionless_units {
83    ($cb:path) => {
84        $cb!(
85            OpticalDepth,
86            Airmass,
87            Transmittance,
88            Albedo,
89            IlluminationFraction,
90            Refractivity,
91            Ratio
92        );
93    };
94}
95
96#[cfg(all(test, feature = "std"))]
97mod tests {
98    use super::*;
99
100    #[test]
101    fn named_dimensionless_values_round_trip() {
102        assert_eq!(OpticalDepths::new(0.5).value(), 0.5);
103        assert_eq!(Airmasses::new(1.2).value(), 1.2);
104        assert_eq!(Transmittances::new(0.8).value(), 0.8);
105        assert_eq!(Albedos::new(0.3).value(), 0.3);
106        assert_eq!(IlluminationFractions::new(0.75).value(), 0.75);
107        assert_eq!(Refractivities::new(2.7e-4).value(), 2.7e-4);
108    }
109}