1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
//! Lapse rate units
use crate::types::{Feet, Km, Quantity};
use std::cmp::Ordering;

/// Marker trait for temperature lapse rate types.
pub trait TempLR: Quantity + PartialEq + PartialOrd {}

/// Marker trait for hydrolapse.
pub trait Hydrolapse: Quantity + PartialOrd + PartialEq {}

/// Temperature lapse rate in Fahrenheit per thousand feet (kft).
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "use_serde", derive(serde_derive::Serialize))]
#[cfg_attr(feature = "use_serde", derive(serde_derive::Deserialize))]
pub struct FahrenheitPKft(pub f64);

/// Temperature lapse rate in Celsius per kilometer.
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "use_serde", derive(serde_derive::Serialize))]
#[cfg_attr(feature = "use_serde", derive(serde_derive::Deserialize))]
pub struct CelsiusPKm(pub f64);

/// Temperature lapse rate in Kelvin per kilometer.
pub type KelvinPKm = CelsiusPKm;

/// Hydrolapse in for mixing ratio in km<sup>-1</sup>
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "use_serde", derive(serde_derive::Serialize))]
#[cfg_attr(feature = "use_serde", derive(serde_derive::Deserialize))]
pub struct HydrolapsePKm(pub f64);

/// Hydrolapse in for mixing ratio in g / kg/ km
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "use_serde", derive(serde_derive::Serialize))]
#[cfg_attr(feature = "use_serde", derive(serde_derive::Deserialize))]
pub struct HydrolapseGPKgPKm(pub f64);

impl TempLR for FahrenheitPKft {}
impl TempLR for CelsiusPKm {}

impl Hydrolapse for HydrolapsePKm {}

macro_rules! implQuantity {
    ($t:tt) => {
        impl Quantity for $t {
            #[inline]
            fn pack(val: f64) -> Self {
                $t(val)
            }

            #[inline]
            fn unpack(self) -> f64 {
                self.0
            }

            #[inline]
            fn unwrap(self) -> f64 {
                self.0
            }

            #[inline]
            fn into_option(self) -> Option<f64> {
                Some(self.0)
            }
        }

        implOpsForQuantity!($t);
    };
}

implQuantity!(FahrenheitPKft);
implQuantity!(CelsiusPKm);

implQuantity!(HydrolapsePKm);
implQuantity!(HydrolapseGPKgPKm);

impl From<CelsiusPKm> for FahrenheitPKft {
    #[inline]
    fn from(c: CelsiusPKm) -> Self {
        let dt = c.unpack();
        let dz = Feet::from(Km(1.0)).unpack() / 1000.0;
        FahrenheitPKft(1.8 * dt / dz)
    }
}

impl From<FahrenheitPKft> for CelsiusPKm {
    #[inline]
    fn from(f: FahrenheitPKft) -> Self {
        let dt = f.unpack();
        let dz = Km::from(Feet(1000.0)).unpack();
        CelsiusPKm(dt / dz / 1.8)
    }
}

impl From<HydrolapsePKm> for HydrolapseGPKgPKm {
    #[inline]
    fn from(hl: HydrolapsePKm) -> Self {
        HydrolapseGPKgPKm(1000.0 * hl.unpack())
    }
}

impl From<HydrolapseGPKgPKm> for HydrolapsePKm {
    #[inline]
    fn from(hl: HydrolapseGPKgPKm) -> Self {
        HydrolapsePKm(hl.unpack() / 1000.0)
    }
}