Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add photometric units #313

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions src/si/illuminance.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//! Illuminance (base unit lux, lx, cd · sr / m²).

quantity! {
/// Illuminance (base unit lux, lx, cd · sr / m²).
quantity: Illuminance; "illuminance";
/// Dimension of illuminance, E (base unit lux, lx, cd · sr / m²).
Comment on lines +1 to +6
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
//! Illuminance (base unit lux, lx, cd · sr / m²).
quantity! {
/// Illuminance (base unit lux, lx, cd · sr / m²).
quantity: Illuminance; "illuminance";
/// Dimension of illuminance, E (base unit lux, lx, cd · sr / m²).
//! Illuminance (base unit lux, m⁻² · cd).
quantity! {
/// Illuminance (base unit lux, m⁻² · cd).
quantity: Illuminance; "illuminance";
/// Dimension of illuminance, L⁻²J (base unit lux, m⁻² · cd).

By convention just the base 7 units are included. I've excluded the steradian (sr) because it's not a base unit, but I'm not convinced this is the right choice.

For the dimension comment the base unit dimensions are used. There isn't a current place where a quantity's symbol is defined or used anywhere. I'll add an issue about this.

dimension: ISQ<
N2, // length
Z0, // mass
Z0, // time
Z0, // electric current
Z0, // thermodynamic temperature
Z0, // amount of substance
P1>; // luminous intensity
kind: dyn (crate::si::marker::IlluminanceKind);
units {
@yottalux: prefix!(yotta); "Ylm", "yottalux", "yottaluxs";
@zettalux: prefix!(zetta); "Zlm", "zettalux", "zettaluxs";
@exalux: prefix!(exa); "Elm", "exalux", "exaluxs";
@petalux: prefix!(peta); "Plm", "petalux", "petaluxs";
@teralux: prefix!(tera); "Tlm", "teralux", "teraluxs";
@gigalux: prefix!(giga); "Glm", "gigalux", "gigaluxs";
@megalux: prefix!(mega); "Mlm", "megalux", "megaluxs";
@kilolux: prefix!(kilo); "klm", "kilolux", "kiloluxs";
@hectolux: prefix!(hecto); "hlm", "hectolux", "hectoluxs";
@decalux: prefix!(deca); "dalm", "decalux", "decaluxs";
/// The lux is defined to be 1 lumen per square meter,
/// or 1 candela steradian per square meter.
Comment on lines +27 to +28
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// The lux is defined to be 1 lumen per square meter,
/// or 1 candela steradian per square meter.
/// Dervied unit of illuminance. The lux is defined to be 1 lumen per square meter, or 1
/// candela steradian per square meter.

@lux: prefix!(none); "lm", "lux", "luxs";
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@lux: prefix!(none); "lm", "lux", "luxs";
@lux: prefix!(none); "lx", "lux", "lux";

Copy/paste error from luminous flux? It also seems the plural and singular are the same.

@decilux: prefix!(deci); "dlm", "decilux", "deciluxs";
@centilux: prefix!(centi); "clm", "centilux", "centiluxs";
@millilux: prefix!(milli); "mlm", "millilux", "milliluxs";
@microlux: prefix!(micro); "µlm", "microlux", "microluxs";
@nanolux: prefix!(nano); "nlm", "nanolux", "nanoluxs";
@picolux: prefix!(pico); "plm", "picolux", "picoluxs";
@femtolux: prefix!(femto); "flm", "femtolux", "femtoluxs";
@attolux: prefix!(atto); "alm", "attolux", "attoluxs";
@zeptolux: prefix!(zepto); "zlm", "zeptolux", "zeptoluxs";
@yoctolux: prefix!(yocto); "ylm", "yoctolux", "yoctoluxs";
}
}

#[cfg(test)]
mod tests {
storage_types! {
use crate::si::quantities::*;
use crate::si::luminous_flux as lf;
use crate::si::area as a;
use crate::si::illuminance as i;
use crate::tests::{A, Test};

quickcheck! {
#[allow(trivial_casts)]
fn add(l: A<V>, r: A<V>) -> bool {
Test::eq(&Illuminance::<V>::new::<i::lux>(&*l / &*r),
&(LuminousFlux::<V>::new::<lf::lumen>((*l).clone())
/ Area::<V>::new::<a::square_meter>((*r).clone())).into())
}
}
Comment on lines +52 to +59
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than doing quickcheck test, will you replace with a test to confirm the dimensions as well as another test to confirm the derived units. See other quantities such as MagneticFlux for an example:

#[test]
fn check_dimension() {
let _: MagneticFlux<V> = ElectricPotential::new::<v::volt>(V::one())
* Time::new::<t::second>(V::one());
}
#[test]
fn check_units() {
test::<v::yottavolt, f::yottaweber>();
test::<v::zettavolt, f::zettaweber>();
test::<v::exavolt, f::exaweber>();
test::<v::petavolt, f::petaweber>();
test::<v::teravolt, f::teraweber>();
test::<v::gigavolt, f::gigaweber>();
test::<v::megavolt, f::megaweber>();
test::<v::kilovolt, f::kiloweber>();
test::<v::hectovolt, f::hectoweber>();
test::<v::decavolt, f::decaweber>();
test::<v::volt, f::weber>();
test::<v::decivolt, f::deciweber>();
test::<v::centivolt, f::centiweber>();
test::<v::millivolt, f::milliweber>();
test::<v::microvolt, f::microweber>();
test::<v::nanovolt, f::nanoweber>();
test::<v::picovolt, f::picoweber>();
test::<v::femtovolt, f::femtoweber>();
test::<v::attovolt, f::attoweber>();
test::<v::zeptovolt, f::zeptoweber>();
test::<v::yoctovolt, f::yoctoweber>();
fn test<U: v::Conversion<V>, F: f::Conversion<V>>() {
Test::assert_approx_eq(&MagneticFlux::new::<F>(V::one()),
&(ElectricPotential::new::<U>(V::one())
* Time::new::<t::second>(V::one())));
}

}
}
114 changes: 114 additions & 0 deletions src/si/luminous_flux.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//! Luminous flux (base unit lumen, lm, cd · sr).

use crate::si::luminous_intensity::LuminousIntensity;
use crate::si::solid_angle::SolidAngle;

quantity! {
/// Luminous flux (base unit lumen, lm, cd · sr).
quantity: LuminousFlux; "luminous flux";
/// Dimension of luminous flux, Φ (base unit lumen, lm, cd · sr).
dimension: ISQ<
Z0, // length
Z0, // mass
Z0, // time
Z0, // electric current
Z0, // thermodynamic temperature
Z0, // amount of substance
P1>; // luminous intensity
kind: dyn (crate::si::marker::LuminousFluxKind);
units {
@yottalumen: prefix!(yotta); "Ylm", "yottalumen", "yottalumens";
@zettalumen: prefix!(zetta); "Zlm", "zettalumen", "zettalumens";
@exalumen: prefix!(exa); "Elm", "exalumen", "exalumens";
@petalumen: prefix!(peta); "Plm", "petalumen", "petalumens";
@teralumen: prefix!(tera); "Tlm", "teralumen", "teralumens";
@gigalumen: prefix!(giga); "Glm", "gigalumen", "gigalumens";
@megalumen: prefix!(mega); "Mlm", "megalumen", "megalumens";
@kilolumen: prefix!(kilo); "klm", "kilolumen", "kilolumens";
@hectolumen: prefix!(hecto); "hlm", "hectolumen", "hectolumens";
@decalumen: prefix!(deca); "dalm", "decalumen", "decalumens";
/// The lumen is defined to be 1 candela steradian.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// The lumen is defined to be 1 candela steradian.
/// Derived unit of luminous flux. The lumen is defined to be 1 candela steradian.

@lumen: prefix!(none); "lm", "lumen", "lumens";
@decilumen: prefix!(deci); "dlm", "decilumen", "decilumens";
@centilumen: prefix!(centi); "clm", "centilumen", "centilumens";
@millilumen: prefix!(milli); "mlm", "millilumen", "millilumens";
@microlumen: prefix!(micro); "µlm", "microlumen", "microlumens";
@nanolumen: prefix!(nano); "nlm", "nanolumen", "nanolumens";
@picolumen: prefix!(pico); "plm", "picolumen", "picolumens";
@femtolumen: prefix!(femto); "flm", "femtolumen", "femtolumens";
@attolumen: prefix!(atto); "alm", "attolumen", "attolumens";
@zeptolumen: prefix!(zepto); "zlm", "zeptolumen", "zeptolumens";
@yoctolumen: prefix!(yocto); "ylm", "yoctolumen", "yoctolumens";
}
}

// TODO: Explicitly allow luminous flux = luminous intensity * solid angle using
// trait implementations such as the below.
#[doc(hidden)]
macro_rules! impl_ops {
(
$MulDivTrait:ident, $muldiv_fun:ident, $muldiv_op:tt
) => {
#[cfg(feature = "autoconvert")]
impl<Ul, Ur, V> $crate::lib::ops::$MulDivTrait<SolidAngle<Ur, V>>
for LuminousIntensity<Ul, V>
where
Ul: super::Units<V> + ?Sized,
Ur: super::Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>,
{
type Output = LuminousFlux<Ul, V>;

#[inline(always)]
fn $muldiv_fun(self, rhs: SolidAngle<Ur, V>) -> Self::Output {
super::Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value
$muldiv_op super::change_base::<Dimension, Ul, Ur, V>(&rhs.value),
}
}
}

#[cfg(not(feature = "autoconvert"))]
impl<U, V> $crate::lib::ops::$MulDivTrait<SolidAngle<U, V>>
for LuminousIntensity<U, V>
where
U: super::Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>,
{
type Output = LuminousFlux<U, V>;

#[inline(always)]
fn $muldiv_fun(self, rhs: SolidAngle<U, V>) -> Self::Output {
super::Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value $muldiv_op rhs.value,
}
}
}
};
}

//impl_ops!(Mul, mul, *);

#[cfg(test)]
mod tests {
storage_types! {
use crate::si::quantities::*;
use crate::si::luminous_flux as lf;
use crate::si::luminous_intensity as li;
use crate::si::solid_angle as sa;
use crate::tests::{A, Test};

quickcheck! {
#[allow(trivial_casts)]
fn add(l: A<V>, r: A<V>) -> bool {
Test::eq(&LuminousFlux::<V>::new::<lf::lumen>(&*l * &*r),
&(LuminousIntensity::<V>::new::<li::candela>((*l).clone())
* SolidAngle::<V>::new::<sa::steradian>((*r).clone())).into())
}
}
}
}
36 changes: 36 additions & 0 deletions src/si/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,14 @@ system! {
heat_capacity::HeatCapacity,
heat_flux_density::HeatFluxDensity,
heat_transfer::HeatTransfer,
illuminance::Illuminance,
inductance::Inductance,
information::Information,
information_rate::InformationRate,
jerk::Jerk,
length::Length,
luminance::Luminance,
luminous_flux::LuminousFlux,
luminous_intensity::LuminousIntensity,
magnetic_flux::MagneticFlux,
magnetic_flux_density::MagneticFluxDensity,
Expand Down Expand Up @@ -148,6 +150,36 @@ pub mod marker {
/// ```
pub trait SolidAngleKind: Kind {}

/// `IlluminanceKind` is a `Kind` for separating quantities of illuminance from other
/// identically dimensioned quantities. Conversions to and from `IlluminanceKind` quantities are
/// supported through implementations of the `From` trait.
///
#[cfg_attr(feature = "f32", doc = " ```rust")]
#[cfg_attr(not(feature = "f32"), doc = " ```rust,ignore")]
/// # use uom::si::f32::*;
/// # use uom::si::luminous_flux::lumen;
/// # use uom::si::area::square_meter;
/// let a: LuminousFlux = LuminousFlux::new::<lumen>(1.0);
/// let b: Area = Area::new::<square_meter>(1.0);
/// let r: Illuminance = (a / b).into();
/// ```
pub trait IlluminanceKind: Kind {}

/// `LuminousFluxKind` is a `Kind` for separating quantities of luminous flux from other
/// identically dimensioned quantities. Conversions to and from `LuminousFluxKind` quantities are
/// supported through implementations of the `From` trait.
///
#[cfg_attr(feature = "f32", doc = " ```rust")]
#[cfg_attr(not(feature = "f32"), doc = " ```rust,ignore")]
/// # use uom::si::f32::*;
/// # use uom::si::luminous_intensity::candela;
/// # use uom::si::solid_angle::steradian;
/// let a: LuminousIntensity = LuminousIntensity::new::<candela>(1.0);
/// let b: SolidAngle = SolidAngle::new::<steradian>(1.0);
/// let r: LuminousFlux = (a * b).into();
/// ```
pub trait LuminousFluxKind: Kind {}

/// `InformationKind` is a `Kind` for separating information quantities from their identically
/// dimensioned non-information quantity counterparts. Conversions to and from `InformationKind`
/// quantities are supported through implementations of the `From` trait.
Expand Down Expand Up @@ -332,6 +364,10 @@ pub mod marker {
impl_from!(Kind, AngleKind);
impl_from!(SolidAngleKind, Kind);
impl_from!(Kind, SolidAngleKind);
impl_from!(IlluminanceKind, Kind);
impl_from!(Kind, IlluminanceKind);
impl_from!(LuminousFluxKind, Kind);
impl_from!(Kind, LuminousFluxKind);
impl_from!(InformationKind, Kind);
impl_from!(Kind, InformationKind);
impl_from!(ConstituentConcentrationKind, Kind);
Expand Down