From 2df77db80f7df074aaa31d79decf3f6f997c7d19 Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 12:23:51 +0100 Subject: [PATCH 01/24] remove leftover prints --- src/relative_humidity.rs | 1 - src/tests_framework.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/relative_humidity.rs b/src/relative_humidity.rs index c65895c..097f720 100644 --- a/src/relative_humidity.rs +++ b/src/relative_humidity.rs @@ -135,7 +135,6 @@ pub fn general5(temperature: Float, dewpoint: Float, pressure: Float) -> Result< let mixing_ratio = mixing_ratio::accuracy1(dewpoint, pressure)?; let saturation_mixing_ratio = mixing_ratio::accuracy1(temperature, pressure)?; - //println!("{} {}", mixing_ratio, saturation_mixing_ratio); let result = general1(mixing_ratio, saturation_mixing_ratio)?; Ok(result) diff --git a/src/tests_framework.rs b/src/tests_framework.rs index ed35883..5bd0fc9 100644 --- a/src/tests_framework.rs +++ b/src/tests_framework.rs @@ -169,7 +169,6 @@ pub fn test_with_3args( == discriminant(&result.unwrap_err()) ); } else { - println!("{} {} {} {:?}", arg1_tmp, arg2_tmp, arg3_tmp, result); assert!(result.unwrap().is_finite()); } } From b3522d350bd6a71e4dcd9ff369f91a43cac939fe Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 12:31:17 +0100 Subject: [PATCH 02/24] virtual temperature --- src/virtual_temperature.rs | 52 +++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/src/virtual_temperature.rs b/src/virtual_temperature.rs index 80c26ed..0cbfae9 100644 --- a/src/virtual_temperature.rs +++ b/src/virtual_temperature.rs @@ -4,10 +4,10 @@ //!at which a theoretical dry air parcel would have a total pressure and density equal //!to the moist parcel of air ([Wikipedia](https://en.wikipedia.org/wiki/Virtual_temperature)). -use crate::{constants::EPSILON, errors::InputError}; use crate::Float; +use crate::{constants::EPSILON, errors::InputError}; -#[cfg(feature="debug")] +#[cfg(feature = "debug")] use floccus_proc::logerr; ///Formula for computing virtual temperature from temperature and mixing ratio. @@ -17,8 +17,13 @@ use floccus_proc::logerr; ///Returns [`InputError::OutOfRange`] when one of inputs is out of range.\ ///Valid `temperature` range: 173K - 373K\ ///Valid `mixing_ratio` range: 0.0000000001 - 0.5 -#[cfg_attr(feature = "debug", logerr)] pub fn general1(temperature: Float, mixing_ratio: Float) -> Result { + general1_validate(temperature, mixing_ratio)?; + Ok(general1_unchecked(temperature, mixing_ratio)) +} + +#[cfg_attr(feature = "debug", logerr)] +pub fn general1_validate(temperature: Float, mixing_ratio: Float) -> Result<(), InputError> { if !(173.0..=354.0).contains(&temperature) { return Err(InputError::OutOfRange(String::from("temperature"))); } @@ -27,9 +32,11 @@ pub fn general1(temperature: Float, mixing_ratio: Float) -> Result Float { + temperature * ((mixing_ratio + EPSILON) / (EPSILON * (1.0 + mixing_ratio))) } ///Formula for computing virtual temperature from air temperature, pressure and vapour pressure. @@ -40,8 +47,21 @@ pub fn general1(temperature: Float, mixing_ratio: Float) -> Result Result { + general2_validate(temperature, pressure, vapour_pressure)?; + Ok(general2_unchecked(temperature, pressure, vapour_pressure)) +} + #[cfg_attr(feature = "debug", logerr)] -pub fn general2(temperature: Float, pressure: Float, vapour_pressure: Float) -> Result { +pub fn general2_validate( + temperature: Float, + pressure: Float, + vapour_pressure: Float, +) -> Result<(), InputError> { if !(173.0..=354.0).contains(&temperature) { return Err(InputError::OutOfRange(String::from("temperature"))); } @@ -53,10 +73,11 @@ pub fn general2(temperature: Float, pressure: Float, vapour_pressure: Float) -> if !(0.0..=10_000.0).contains(&vapour_pressure) { return Err(InputError::OutOfRange(String::from("vapour_pressure"))); } + Ok(()) +} - let result = temperature / (1.0 - ((vapour_pressure / pressure) * (1.0 - EPSILON))); - - Ok(result) +pub fn general2_unchecked(temperature: Float, pressure: Float, vapour_pressure: Float) -> Float { + temperature / (1.0 - ((vapour_pressure / pressure) * (1.0 - EPSILON))) } ///Formula for computing virtual temperature from air temperature and specific humidity. @@ -66,8 +87,13 @@ pub fn general2(temperature: Float, pressure: Float, vapour_pressure: Float) -> ///Returns [`InputError::OutOfRange`] when one of inputs is out of range.\ ///Valid `temperature` range: 173K - 373K\ ///Valid `specific_humidity` range: 100Pa - 150000Pa -#[cfg_attr(feature = "debug", logerr)] pub fn general3(temperature: Float, specific_humidity: Float) -> Result { + general3_validate(temperature, specific_humidity)?; + Ok(general3_unchecked(temperature, specific_humidity)) +} + +#[cfg_attr(feature = "debug", logerr)] +pub fn general3_validate(temperature: Float, specific_humidity: Float) -> Result<(), InputError> { if !(173.0..=354.0).contains(&temperature) { return Err(InputError::OutOfRange(String::from("temperature"))); } @@ -76,9 +102,11 @@ pub fn general3(temperature: Float, specific_humidity: Float) -> Result Float { + temperature * (1.0 + (specific_humidity * ((1.0 / EPSILON) - 1.0))) } #[cfg(test)] From 391198384e457d23e3e2ac59546e0e8a62d04dc7 Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 12:45:35 +0100 Subject: [PATCH 03/24] vapour pressure --- src/vapour_pressure.rs | 180 +++++++++++++++++++++++++++++++++-------- 1 file changed, 146 insertions(+), 34 deletions(-) diff --git a/src/vapour_pressure.rs b/src/vapour_pressure.rs index ab98289..aa04dfc 100644 --- a/src/vapour_pressure.rs +++ b/src/vapour_pressure.rs @@ -8,7 +8,7 @@ use crate::{ errors::InputError, }; -#[cfg(feature="debug")] +#[cfg(feature = "debug")] use floccus_proc::logerr; ///Formula for computing vapour pressure from specific humidity and pressure. @@ -21,9 +21,13 @@ use floccus_proc::logerr; ///Returns [`InputError::OutOfRange`] when one of inputs is out of range.\ ///Valid `specific_humidity` range: 0.00001 - 2.0\ ///Valid `pressure` range: 100Pa - 150000Pa -#[cfg_attr(feature = "debug", logerr)] pub fn general1(specific_humidity: Float, pressure: Float) -> Result { - //validate inputs + general1_validate(specific_humidity, pressure)?; + Ok(general1_unchecked(specific_humidity, pressure)) +} + +#[cfg_attr(feature = "debug", logerr)] +pub fn general1_validate(specific_humidity: Float, pressure: Float) -> Result<(), InputError> { if !(0.00001..=2.0).contains(&specific_humidity) { return Err(InputError::OutOfRange(String::from("specific_humidity"))); } @@ -32,10 +36,11 @@ pub fn general1(specific_humidity: Float, pressure: Float) -> Result Float { + -((pressure * specific_humidity) / ((specific_humidity * (EPSILON - 1.0)) - EPSILON)) } ///Formula for computing vapour pressure from dewpoint temperature and pressure. @@ -47,9 +52,13 @@ pub fn general1(specific_humidity: Float, pressure: Float) -> Result Result { - //validate inputs + buck1_validate(dewpoint, pressure)?; + Ok(buck1_unchecked(dewpoint, pressure)) +} + +#[cfg_attr(feature = "debug", logerr)] +pub fn buck1_validate(dewpoint: Float, pressure: Float) -> Result<(), InputError> { if !(232.0..=324.0).contains(&dewpoint) { return Err(InputError::OutOfRange(String::from("dewpoint"))); } @@ -58,6 +67,10 @@ pub fn buck1(dewpoint: Float, pressure: Float) -> Result { return Err(InputError::OutOfRange(String::from("pressure"))); } + Ok(()) +} + +pub fn buck1_unchecked(dewpoint: Float, pressure: Float) -> Float { let dewpoint = dewpoint - ZERO_CELSIUS; //convert to C let pressure = pressure / 100.0; //convert to hPa @@ -74,7 +87,7 @@ pub fn buck1(dewpoint: Float, pressure: Float) -> Result { lower_a * (((lower_b - (dewpoint / lower_d)) * dewpoint) / (dewpoint + lower_c)).exp(); let lower_f = 1.0 + upper_a + (pressure * (upper_b + (upper_c * dewpoint * dewpoint))); - Ok((lower_e * lower_f) * 100.0) //return in Pa + (lower_e * lower_f) * 100.0 //return in Pa } ///Formula for computing vapour pressure from dewpoint temperature and pressure. @@ -86,9 +99,13 @@ pub fn buck1(dewpoint: Float, pressure: Float) -> Result { ///Returns [`InputError::OutOfRange`] when one of inputs is out of range.\ ///Valid `dewpoint` range: 193K - 274K\ ///Valid `pressure` range: 100Pa - 150000Pa -#[cfg_attr(feature = "debug", logerr)] pub fn buck2(dewpoint: Float, pressure: Float) -> Result { - //validate inputs + buck2_validate(dewpoint, pressure)?; + Ok(buck2_unchecked(dewpoint, pressure)) +} + +#[cfg_attr(feature = "debug", logerr)] +pub fn buck2_validate(dewpoint: Float, pressure: Float) -> Result<(), InputError> { if !(193.0..=274.0).contains(&dewpoint) { return Err(InputError::OutOfRange(String::from("dewpoint"))); } @@ -97,6 +114,10 @@ pub fn buck2(dewpoint: Float, pressure: Float) -> Result { return Err(InputError::OutOfRange(String::from("pressure"))); } + Ok(()) +} + +pub fn buck2_unchecked(dewpoint: Float, pressure: Float) -> Float { let dewpoint = dewpoint - ZERO_CELSIUS; //convert to C let pressure = pressure / 100.0; //convert to hPa @@ -113,7 +134,7 @@ pub fn buck2(dewpoint: Float, pressure: Float) -> Result { lower_a * (((lower_b - (dewpoint / lower_d)) * dewpoint) / (dewpoint + lower_c)).exp(); let lower_f = 1.0 + upper_a + (pressure * (upper_b + (upper_c * dewpoint * dewpoint))); - Ok((lower_e * lower_f) * 100.0) //return in Pa + (lower_e * lower_f) * 100.0 //return in Pa } ///Formula for computing vapour pressure from dewpoint temperature and pressure. @@ -125,9 +146,13 @@ pub fn buck2(dewpoint: Float, pressure: Float) -> Result { ///Returns [`InputError::OutOfRange`] when one of inputs is out of range.\ ///Valid `dewpoint` range: 253K - 324K\ ///Valid `pressure` range: 100Pa - 150000Pa -#[cfg_attr(feature = "debug", logerr)] pub fn buck3(dewpoint: Float, pressure: Float) -> Result { - //validate inputs + buck3_validate(dewpoint, pressure)?; + Ok(buck3_unchecked(dewpoint, pressure)) +} + +#[cfg_attr(feature = "debug", logerr)] +pub fn buck3_validate(dewpoint: Float, pressure: Float) -> Result<(), InputError> { if !(253.0..=324.0).contains(&dewpoint) { return Err(InputError::OutOfRange(String::from("dewpoint"))); } @@ -136,6 +161,10 @@ pub fn buck3(dewpoint: Float, pressure: Float) -> Result { return Err(InputError::OutOfRange(String::from("pressure"))); } + Ok(()) +} + +pub fn buck3_unchecked(dewpoint: Float, pressure: Float) -> Float { let dewpoint = dewpoint - ZERO_CELSIUS; //convert to C let pressure = pressure / 100.0; //convert to hPa @@ -149,7 +178,7 @@ pub fn buck3(dewpoint: Float, pressure: Float) -> Result { let lower_e = lower_a * ((lower_b * dewpoint) / (dewpoint + lower_c)).exp(); let lower_f = 1.0 + upper_a + (pressure * upper_b); - Ok((lower_e * lower_f) * 100.0) //return in Pa + (lower_e * lower_f) * 100.0 //return in Pa } ///Formula for computing vapour pressure from dewpoint temperature. @@ -160,13 +189,21 @@ pub fn buck3(dewpoint: Float, pressure: Float) -> Result { /// ///Returns [`InputError::OutOfRange`] when one of inputs is out of range.\ ///Valid `dewpoint` range: 253K - 324K -#[cfg_attr(feature = "debug", logerr)] pub fn buck3_simplified(dewpoint: Float) -> Result { - //validate inputs + buck3_simplified_validate(dewpoint)?; + Ok(buck3_simplified_unchecked(dewpoint)) +} + +#[cfg_attr(feature = "debug", logerr)] +pub fn buck3_simplified_validate(dewpoint: Float) -> Result<(), InputError> { if !(253.0..=324.0).contains(&dewpoint) { return Err(InputError::OutOfRange(String::from("dewpoint"))); } + Ok(()) +} + +pub fn buck3_simplified_unchecked(dewpoint: Float) -> Float { let dewpoint = dewpoint - ZERO_CELSIUS; //convert to C let lower_a = 6.1121; @@ -175,7 +212,7 @@ pub fn buck3_simplified(dewpoint: Float) -> Result { let lower_e = lower_a * ((lower_b * dewpoint) / (dewpoint + lower_c)).exp(); - Ok(lower_e * 100.0) //return in Pa + lower_e * 100.0 //return in Pa } ///Formula for computing vapour pressure from dewpoint temperature and pressure. @@ -187,9 +224,13 @@ pub fn buck3_simplified(dewpoint: Float) -> Result { ///Returns [`InputError::OutOfRange`] when one of inputs is out of range.\ ///Valid `dewpoint` range: 223K - 274K\ ///Valid `pressure` range: 100Pa - 150000Pa -#[cfg_attr(feature = "debug", logerr)] pub fn buck4(dewpoint: Float, pressure: Float) -> Result { - //validate inputs + buck4_validate(dewpoint, pressure)?; + Ok(buck4_unchecked(dewpoint, pressure)) +} + +#[cfg_attr(feature = "debug", logerr)] +pub fn buck4_validate(dewpoint: Float, pressure: Float) -> Result<(), InputError> { if !(223.0..=274.0).contains(&dewpoint) { return Err(InputError::OutOfRange(String::from("dewpoint"))); } @@ -198,6 +239,10 @@ pub fn buck4(dewpoint: Float, pressure: Float) -> Result { return Err(InputError::OutOfRange(String::from("pressure"))); } + Ok(()) +} + +pub fn buck4_unchecked(dewpoint: Float, pressure: Float) -> Float { let dewpoint = dewpoint - ZERO_CELSIUS; //convert to C let pressure = pressure / 100.0; //convert to hPa @@ -211,7 +256,7 @@ pub fn buck4(dewpoint: Float, pressure: Float) -> Result { let lower_e = lower_a * ((lower_b * dewpoint) / (dewpoint + lower_c)).exp(); let lower_f = 1.0 + upper_a + (pressure * upper_b); - Ok((lower_e * lower_f) * 100.0) //return in Pa + (lower_e * lower_f) * 100.0 //return in Pa } ///Formula for computing vapour pressure from dewpoint temperature. @@ -222,13 +267,22 @@ pub fn buck4(dewpoint: Float, pressure: Float) -> Result { /// ///Returns [`InputError::OutOfRange`] when one of inputs is out of range.\ ///Valid `dewpoint` range: 223K - 274K -#[cfg_attr(feature = "debug", logerr)] pub fn buck4_simplified(dewpoint: Float) -> Result { + buck4_simplified_validate(dewpoint)?; + Ok(buck4_simplified_unchecked(dewpoint)) +} + +#[cfg_attr(feature = "debug", logerr)] +pub fn buck4_simplified_validate(dewpoint: Float) -> Result<(), InputError> { //validate inputs if !(223.0..=274.0).contains(&dewpoint) { return Err(InputError::OutOfRange(String::from("dewpoint"))); } + Ok(()) +} + +pub fn buck4_simplified_unchecked(dewpoint: Float) -> Float { let dewpoint = dewpoint - ZERO_CELSIUS; //convert to C let lower_a = 6.1115; @@ -237,7 +291,7 @@ pub fn buck4_simplified(dewpoint: Float) -> Result { let lower_e = lower_a * ((lower_b * dewpoint) / (dewpoint + lower_c)).exp(); - Ok(lower_e * 100.0) //return in Pa + lower_e * 100.0 //return in Pa } ///Formula for computing vapour pressure over water from dewpoint temperature. @@ -249,13 +303,21 @@ pub fn buck4_simplified(dewpoint: Float) -> Result { /// ///Returns [`InputError::OutOfRange`] when input is out of range.\ ///Valid `dewpoint` range: 273K - 353K -#[cfg_attr(feature = "debug", logerr)] pub fn tetens1(dewpoint: Float) -> Result { - //validate inputs + tetens1_validate(dewpoint)?; + Ok(tetens1_unchecked(dewpoint)) +} + +#[cfg_attr(feature = "debug", logerr)] +pub fn tetens1_validate(dewpoint: Float) -> Result<(), InputError> { if !(273.0..=353.0).contains(&dewpoint) { return Err(InputError::OutOfRange(String::from("dewpoint"))); } + Ok(()) +} + +pub fn tetens1_unchecked(dewpoint: Float) -> Float { let dewpoint = dewpoint - ZERO_CELSIUS; //convert to C let lower_a = 0.61078; @@ -264,7 +326,7 @@ pub fn tetens1(dewpoint: Float) -> Result { let result = lower_a * ((lower_b * dewpoint) / (dewpoint + lower_c)).exp(); - Ok(result * 1000.0) //return in Pa + result * 1000.0 //return in Pa } ///Formula for computing **ONLY** vapour pressure from saturation vapour pressure and relative humidity. @@ -275,11 +337,22 @@ pub fn tetens1(dewpoint: Float) -> Result { ///Returns [`InputError::OutOfRange`] when input is out of range.\ ///Valid `saturation_vapour_pressure` range: 0Pa - 10000Pa\ ///Valid `relative_humidity` range: 0.0 - 1.0 -#[cfg_attr(feature = "debug", logerr)] pub fn saturation_specific1( saturation_vapour_pressure: Float, relative_humidity: Float, ) -> Result { + saturation_specific1_validate(saturation_vapour_pressure, relative_humidity)?; + Ok(saturation_specific1_unchecked( + saturation_vapour_pressure, + relative_humidity, + )) +} + +#[cfg_attr(feature = "debug", logerr)] +pub fn saturation_specific1_validate( + saturation_vapour_pressure: Float, + relative_humidity: Float, +) -> Result<(), InputError> { if !(0.0..=2.0).contains(&relative_humidity) { return Err(InputError::OutOfRange(String::from("relative_humidity"))); } @@ -290,7 +363,14 @@ pub fn saturation_specific1( ))); } - Ok(saturation_vapour_pressure * relative_humidity) + Ok(()) +} + +pub fn saturation_specific1_unchecked( + saturation_vapour_pressure: Float, + relative_humidity: Float, +) -> Float { + saturation_vapour_pressure * relative_humidity } ///Formula for computing **ONLY** saturation vapour pressure from vapour pressure and relative humidity. @@ -301,11 +381,22 @@ pub fn saturation_specific1( ///Returns [`InputError::OutOfRange`] when input is out of range.\ ///Valid `vapour_pressure` range: 0Pa - 10000Pa\ ///Valid `relative_humidity` range: 0.00001 - 1.0 -#[cfg_attr(feature = "debug", logerr)] pub fn saturation_specific2( vapour_pressure: Float, relative_humidity: Float, ) -> Result { + saturation_specific2_validate(vapour_pressure, relative_humidity)?; + Ok(saturation_specific2_uchecked( + vapour_pressure, + relative_humidity, + )) +} + +#[cfg_attr(feature = "debug", logerr)] +pub fn saturation_specific2_validate( + vapour_pressure: Float, + relative_humidity: Float, +) -> Result<(), InputError> { if !(0.00001..=2.0).contains(&relative_humidity) { return Err(InputError::OutOfRange(String::from("relative_humidity"))); } @@ -314,7 +405,11 @@ pub fn saturation_specific2( return Err(InputError::OutOfRange(String::from("vapour_pressure"))); } - Ok(vapour_pressure / relative_humidity) + Ok(()) +} + +pub fn saturation_specific2_uchecked(vapour_pressure: Float, relative_humidity: Float) -> Float { + vapour_pressure / relative_humidity } ///Formula for computing vapour pressure over water from dewpoint temperature. @@ -327,12 +422,21 @@ pub fn saturation_specific2( /// ///Returns [`InputError::OutOfRange`] when one of inputs is out of range.\ ///Valid `dewpoint` range: 273K - 374K -#[cfg_attr(feature = "debug", logerr)] pub fn wexler1(dewpoint: Float) -> Result { + wexler1_validate(dewpoint)?; + Ok(wexler1_unchecked(dewpoint)) +} + +#[cfg_attr(feature = "debug", logerr)] +pub fn wexler1_validate(dewpoint: Float) -> Result<(), InputError> { if !(273.0..=374.0).contains(&dewpoint) { return Err(InputError::OutOfRange(String::from("dewpoint"))); } + Ok(()) +} + +pub fn wexler1_unchecked(dewpoint: Float) -> Float { // constants from the paper let g: [Float; 8] = [ -2991.2729, @@ -351,7 +455,7 @@ pub fn wexler1(dewpoint: Float) -> Result { ln_p += g[i] * dewpoint.powi(i as i32 - 2); } - Ok(ln_p.exp()) + ln_p.exp() } ///Formula for computing vapour over ice pressure from dewpoint temperature. @@ -364,12 +468,20 @@ pub fn wexler1(dewpoint: Float) -> Result { /// ///Returns [`InputError::OutOfRange`] when one of inputs is out of range.\ ///Valid `dewpoint` range: 173K - 274K -#[cfg_attr(feature = "debug", logerr)] pub fn wexler2(dewpoint: Float) -> Result { + wexler2_validate(dewpoint)?; + Ok(wexler2_unchecked(dewpoint)) +} + +#[cfg_attr(feature = "debug", logerr)] +pub fn wexler2_validate(dewpoint: Float) -> Result<(), InputError> { if !(173.0..=274.0).contains(&dewpoint) { return Err(InputError::OutOfRange(String::from("dewpoint"))); } + Ok(()) +} +pub fn wexler2_unchecked(dewpoint: Float) -> Float { // constants from the paper let big_k: [Float; 6] = [ -5865.3696, @@ -386,7 +498,7 @@ pub fn wexler2(dewpoint: Float) -> Result { ln_p += big_k[j] * dewpoint.powi(j as i32 - 1); } - Ok(ln_p.exp()) + ln_p.exp() } #[cfg(test)] From 57b5e19d3467dd4e8efde5b0cc9432ccb2cae3e0 Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 12:45:47 +0100 Subject: [PATCH 04/24] bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 80b73e4..4e8bdaf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "floccus" -version = "0.3.7" +version = "0.4.0" authors = ["Jakub Lewandowski "] edition = "2021" description = "Formulae for air thermodynamic calculations" From d16573a9de88f451ff587777647d8565bb87dd24 Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 12:56:12 +0100 Subject: [PATCH 05/24] define clippy --- src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 76ebfae..26d240d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,8 @@ +#![warn(clippy::pedantic)] +#![warn(missing_docs)] +#![warn(clippy::cargo)] +#![allow(clippy::excessive_precision)] + //! Crate providing formulae for air thermodynamic calculations. //! //! # How to use From b87c335adf2eb0e6c2002476c0e0f3406bbc1327 Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 13:12:46 +0100 Subject: [PATCH 06/24] start refactor --- .github/workflows/basic.yml | 28 ++++++++++++++++++++++ .github/workflows/rust.yml | 46 ------------------------------------- 2 files changed, 28 insertions(+), 46 deletions(-) create mode 100644 .github/workflows/basic.yml delete mode 100644 .github/workflows/rust.yml diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml new file mode 100644 index 0000000..2d370ba --- /dev/null +++ b/.github/workflows/basic.yml @@ -0,0 +1,28 @@ +name: Basic Validation + +on: [push, pull_request, workflow_dispatch] + +env: + CARGO_TERM_COLOR: always + +jobs: + build-and-test: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Prepare environment + run: | + rustup update stable + cargo clean + - name: Build with cargo + run: | + cargo build --release + cargo build --release --features "double_precision" + cargo clean + - name: Test with cargo + run: | + cargo test + cargo test --features "double_precision" + cargo clean diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml deleted file mode 100644 index 989d3fc..0000000 --- a/.github/workflows/rust.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: cargo - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - workflow_dispatch: - -env: - CARGO_TERM_COLOR: always - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Prepare environment - run: | - sudo apt-get update - sudo apt-get install clang - sudo apt-get install libclang1 - sudo apt-get install gnuplot - rustup update stable - cargo install cargo-criterion - cargo clean - - name: Build with cargo - run: | - cargo build --release - cargo build --release --features "double_precision" - cargo clean - - name: Check with clippy - run: | - cargo clippy -- -W clippy::pedantic - cargo clean - - name: Test with cargo - run: | - cargo test - cargo test --features "double_precision" - cargo clean - - name: Benchmark with criterion - run: | - cargo criterion - cargo criterion --features "double_precision" From b2bfda0195a3e69ed18094453ad8b37d6291cc18 Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 13:17:04 +0100 Subject: [PATCH 07/24] update readme and add scheduled jobs --- .github/workflows/basic.yml | 7 ++++++- README.md | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index 2d370ba..0e4b324 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -1,6 +1,11 @@ name: Basic Validation -on: [push, pull_request, workflow_dispatch] +on: + push: + pull_request: + workflow_dispatch: + schedule: + - cron: '26 3 20 * *' env: CARGO_TERM_COLOR: always diff --git a/README.md b/README.md index 7282a4e..e0267cd 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![License](https://img.shields.io/github/license/ScaleWeather/floccus)](https://choosealicense.com/licenses/apache-2.0/) [![Crates.io](https://img.shields.io/crates/v/floccus)](https://crates.io/crates/floccus) [![dependency status](https://deps.rs/repo/github/ScaleWeather/floccus/status.svg)](https://deps.rs/repo/github/ScaleWeather/floccus) -[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/ScaleWeather/floccus/rust.yml?branch=main&label=cargo%20build)](https://github.com/ScaleWeather/floccus/actions) +[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/ScaleWeather/floccus/basic.yml?branch=main&label=cargo%20build)](https://github.com/ScaleWeather/floccus/actions) Rust crate providing formulae for air thermodynamic calculations. From 146484e10cbbac874b1b4bd0816896d85b402a18 Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 13:22:56 +0100 Subject: [PATCH 08/24] extend basic tests --- .github/workflows/basic.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index 0e4b324..b737cfe 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -9,6 +9,7 @@ on: env: CARGO_TERM_COLOR: always + RUSTFLAGS: "-Dwarnings" jobs: build-and-test: @@ -23,11 +24,14 @@ jobs: cargo clean - name: Build with cargo run: | + cargo build --features "double_precision" + cargo build --features "debug" cargo build --release - cargo build --release --features "double_precision" cargo clean - name: Test with cargo run: | cargo test cargo test --features "double_precision" + cargo test --features "debug" + cargo test --all-targets cargo clean From d9c5a80e5db599016edde9eaf4a9fef25a33f9f5 Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 13:29:47 +0100 Subject: [PATCH 09/24] add doc coverage action --- .github/workflows/basic.yml | 1 - .github/workflows/doc-coverage.yml | 45 ++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/doc-coverage.yml diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index b737cfe..282bd44 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -33,5 +33,4 @@ jobs: cargo test cargo test --features "double_precision" cargo test --features "debug" - cargo test --all-targets cargo clean diff --git a/.github/workflows/doc-coverage.yml b/.github/workflows/doc-coverage.yml new file mode 100644 index 0000000..57f5b73 --- /dev/null +++ b/.github/workflows/doc-coverage.yml @@ -0,0 +1,45 @@ +name: Doc Coverage PR Comment + +on: + pull_request + +jobs: + pr-comment: + name: Doc Coverage PR Comment + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install rust toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + - name: Fetch base + run: git fetch origin ${{ github.event.pull_request.base.sha }} + - name: Checkout base + run: git checkout ${{ github.event.pull_request.base.sha }} + - name: Calculate base doc coverage + uses: bewee/rustdoc-coverage-action@v1 + - name: Fetch head + run: git fetch origin ${{ github.event.pull_request.head.sha }} + - name: Checkout head + run: git checkout ${{ github.event.pull_request.head.sha }} + - name: Calculate doc coverage + id: coverage + uses: bewee/rustdoc-coverage-action@v1 + - name: Find Comment + uses: peter-evans/find-comment@v1 + id: fc + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: "github-actions[bot]" + body-includes: "## Documentation Coverage:" + - name: Create or update comment + uses: peter-evans/create-or-update-comment@v1 + with: + comment-id: ${{ steps.fc.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + body: | + ## Documentation Coverage: + ${{ steps.coverage.outputs.table }} + edit-mode: replace \ No newline at end of file From 5206459958b61bbb0c9100503b75016e0e27cb9e Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 13:35:06 +0100 Subject: [PATCH 10/24] add clippy check --- .github/workflows/basic.yml | 2 ++ .github/workflows/clippy-check.yml | 15 +++++++++++++++ .github/workflows/doc-coverage.yml | 4 ++-- 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/clippy-check.yml diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index 282bd44..2f69821 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -14,6 +14,8 @@ env: jobs: build-and-test: + name: Build and Test + runs-on: ubuntu-latest steps: diff --git a/.github/workflows/clippy-check.yml b/.github/workflows/clippy-check.yml new file mode 100644 index 0000000..5d2b53b --- /dev/null +++ b/.github/workflows/clippy-check.yml @@ -0,0 +1,15 @@ +on: pull_request + +name: Cargo Clippy + +jobs: + clippy_check: + name: Check + + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: rustup component add clippy + - uses: actions-rs/clippy-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/doc-coverage.yml b/.github/workflows/doc-coverage.yml index 57f5b73..6ed7ab3 100644 --- a/.github/workflows/doc-coverage.yml +++ b/.github/workflows/doc-coverage.yml @@ -1,11 +1,11 @@ -name: Doc Coverage PR Comment +name: Cargo Doc on: pull_request jobs: pr-comment: - name: Doc Coverage PR Comment + name: Check Coverage runs-on: ubuntu-latest steps: - name: Checkout From b36854a1a004f6a04f616e40d8098651da452b0a Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 13:39:32 +0100 Subject: [PATCH 11/24] use basic clippy --- .github/workflows/clippy-check.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/clippy-check.yml b/.github/workflows/clippy-check.yml index 5d2b53b..78dddbf 100644 --- a/.github/workflows/clippy-check.yml +++ b/.github/workflows/clippy-check.yml @@ -2,6 +2,10 @@ on: pull_request name: Cargo Clippy +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: "-Dwarnings" + jobs: clippy_check: name: Check @@ -9,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - run: rustup component add clippy - - uses: actions-rs/clippy-check@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} + - name: Clippy + run: | + rustup component add clippy + cargo clippy -- -D warnings From 466471d88a410da5786e767f3082b92538f0f945 Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 14:02:30 +0100 Subject: [PATCH 12/24] add 0.3.7 benchmark results --- README.md | 4 +- benches/results/0_3_7.txt | 92 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 benches/results/0_3_7.txt diff --git a/README.md b/README.md index e0267cd..1683141 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,4 @@ information about the error. This feature potentially is not zero-cost so it is ## Benchmarks -Functions provided in this crate are intended for use in, i. a., numerical models. To provide the user information about performance overhead of each function all functions are benchmarked using [criterion.rs](https://bheisler.github.io/criterion.rs/book/index.html). Github Actions automatically runs all benchmarks. - -To check the latest benchmark results the newest workflow on [Github Actions page of floccus](https://github.com/ScaleWeather/floccus/actions). +Functions provided in this crate are intended for use in, i. a., numerical models. To provide the user information about performance overhead of each function all functions are can be benchmarked using [criterion.rs](https://bheisler.github.io/criterion.rs/book/index.html). diff --git a/benches/results/0_3_7.txt b/benches/results/0_3_7.txt new file mode 100644 index 0000000..525834c --- /dev/null +++ b/benches/results/0_3_7.txt @@ -0,0 +1,92 @@ +equivalent_potential_temperature::bryan1 + time: [37.789 ns 37.794 ns 37.799 ns] + +mixing_ratio::general1 + time: [2.2452 ns 2.2497 ns 2.2572 ns] + +mixing_ratio::performance1 + time: [6.9944 ns 6.9992 ns 7.0044 ns] + +mixing_ratio::accuracy1 + time: [10.147 ns 10.163 ns 10.178 ns] + +potential_temperature::davies_jones1 + time: [11.339 ns 11.340 ns 11.341 ns] + +relative_humidity::general1 + time: [1.3266 ns 1.3268 ns 1.3273 ns] + +relative_humidity::general2 + time: [1.3271 ns 1.3276 ns 1.3281 ns] + +relative_humidity::general3 + time: [8.7762 ns 8.7767 ns 8.7772 ns] + +relative_humidity::general4 + time: [10.631 ns 10.640 ns 10.649 ns] + +relative_humidity::general5 + time: [22.791 ns 22.795 ns 22.800 ns] + +specific_humidity::general1 + time: [1.4529 ns 1.4541 ns 1.4554 ns] + +vapour_pressure::general1 + time: [1.3643 ns 1.3831 ns 1.4079 ns] + +vapour_pressure::tetens1 + time: [4.0723 ns 4.0742 ns 4.0760 ns] + +vapour_pressure::buck1 + time: [5.8277 ns 5.8288 ns 5.8304 ns] + +vapour_pressure::buck2 + time: [5.8274 ns 5.8276 ns 5.8279 ns] + +vapour_pressure::buck3 + time: [4.7666 ns 4.7670 ns 4.7673 ns] + +vapour_pressure::buck4 + time: [4.7652 ns 4.7657 ns 4.7661 ns] + +vapour_pressure::buck3_simplified + time: [4.0155 ns 4.0195 ns 4.0232 ns] + +vapour_pressure::buck4_simplified + time: [4.0485 ns 4.0518 ns 4.0553 ns] + +vapour_pressure::saturation_specific1 + time: [1.3148 ns 1.3183 ns 1.3218 ns] + +vapour_pressure::saturation_specific2 + time: [1.3265 ns 1.3265 ns 1.3266 ns] + +vapour_pressure::wexler1 + time: [8.5303 ns 8.5305 ns 8.5308 ns] + +vapour_pressure::wexler2 + time: [7.8834 ns 7.8839 ns 7.8846 ns] + +vapour_pressure_deficit::general1 + time: [1.2693 ns 1.2754 ns 1.2816 ns] + +vapour_pressure_deficit::general2 + time: [9.3893 ns 9.3896 ns 9.3900 ns] + +vapour_pressure_deficit::general3 + time: [6.4139 ns 6.4157 ns 6.4180 ns] + +virtual_temperature::general1 + time: [1.6099 ns 1.6103 ns 1.6109 ns] + +virtual_temperature::general2 + time: [1.8563 ns 1.8564 ns 1.8564 ns] + +virtual_temperature::general3 + time: [1.2598 ns 1.2603 ns 1.2608 ns] + +wet_bulb_potential_temperature::davies_jones1 + time: [10.616 ns 10.616 ns 10.617 ns] + +wet_bulb_temperature::stull1 + time: [27.765 ns 27.767 ns 27.770 ns] From c51617e999b802536095a39d67184dd7482cc4a0 Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 14:12:15 +0100 Subject: [PATCH 13/24] fix clippy --- src/lib.rs | 1 + src/tests_framework.rs | 6 +++--- src/vapour_pressure.rs | 40 ++++++++++++++++++++++++++++++++++++++ src/virtual_temperature.rs | 9 +++++++++ 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 26d240d..cd3b0c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ #![warn(missing_docs)] #![warn(clippy::cargo)] #![allow(clippy::excessive_precision)] +#![allow(clippy::must_use_candidate)] //! Crate providing formulae for air thermodynamic calculations. //! diff --git a/src/tests_framework.rs b/src/tests_framework.rs index 5bd0fc9..2cd896a 100644 --- a/src/tests_framework.rs +++ b/src/tests_framework.rs @@ -59,7 +59,7 @@ pub fn test_with_2args( if result.is_err() { assert!( - discriminant(&InputError::IncorrectArgumentSet(String::from(""))) + discriminant(&InputError::IncorrectArgumentSet(String::new())) == discriminant(&result.unwrap_err()) ); } else { @@ -110,7 +110,7 @@ pub fn test_with_1arg( if result.is_err() { assert!( - discriminant(&InputError::IncorrectArgumentSet(String::from(""))) + discriminant(&InputError::IncorrectArgumentSet(String::new())) == discriminant(&result.unwrap_err()) ); } else { @@ -165,7 +165,7 @@ pub fn test_with_3args( if result.is_err() { assert!( - discriminant(&InputError::IncorrectArgumentSet(String::from(""))) + discriminant(&InputError::IncorrectArgumentSet(String::new())) == discriminant(&result.unwrap_err()) ); } else { diff --git a/src/vapour_pressure.rs b/src/vapour_pressure.rs index aa04dfc..54e0e5d 100644 --- a/src/vapour_pressure.rs +++ b/src/vapour_pressure.rs @@ -1,3 +1,7 @@ +#![allow(clippy::needless_range_loop)] +#![allow(clippy::cast_possible_truncation)] +#![allow(clippy::cast_possible_wrap)] + //!Functions to calculate partial vapour pressure of the unsaturated air in Pa. //! //!To compute saturation vapour pressure input dry-bulb temperature in place of dewpoint temperature. @@ -26,6 +30,8 @@ pub fn general1(specific_humidity: Float, pressure: Float) -> Result Result<(), InputError> { if !(0.00001..=2.0).contains(&specific_humidity) { @@ -39,6 +45,7 @@ pub fn general1_validate(specific_humidity: Float, pressure: Float) -> Result<() Ok(()) } +#[allow(missing_docs)] pub fn general1_unchecked(specific_humidity: Float, pressure: Float) -> Float { -((pressure * specific_humidity) / ((specific_humidity * (EPSILON - 1.0)) - EPSILON)) } @@ -57,6 +64,8 @@ pub fn buck1(dewpoint: Float, pressure: Float) -> Result { Ok(buck1_unchecked(dewpoint, pressure)) } +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] #[cfg_attr(feature = "debug", logerr)] pub fn buck1_validate(dewpoint: Float, pressure: Float) -> Result<(), InputError> { if !(232.0..=324.0).contains(&dewpoint) { @@ -70,6 +79,7 @@ pub fn buck1_validate(dewpoint: Float, pressure: Float) -> Result<(), InputError Ok(()) } +#[allow(missing_docs)] pub fn buck1_unchecked(dewpoint: Float, pressure: Float) -> Float { let dewpoint = dewpoint - ZERO_CELSIUS; //convert to C let pressure = pressure / 100.0; //convert to hPa @@ -104,6 +114,8 @@ pub fn buck2(dewpoint: Float, pressure: Float) -> Result { Ok(buck2_unchecked(dewpoint, pressure)) } +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] #[cfg_attr(feature = "debug", logerr)] pub fn buck2_validate(dewpoint: Float, pressure: Float) -> Result<(), InputError> { if !(193.0..=274.0).contains(&dewpoint) { @@ -117,6 +129,7 @@ pub fn buck2_validate(dewpoint: Float, pressure: Float) -> Result<(), InputError Ok(()) } +#[allow(missing_docs)] pub fn buck2_unchecked(dewpoint: Float, pressure: Float) -> Float { let dewpoint = dewpoint - ZERO_CELSIUS; //convert to C let pressure = pressure / 100.0; //convert to hPa @@ -151,6 +164,8 @@ pub fn buck3(dewpoint: Float, pressure: Float) -> Result { Ok(buck3_unchecked(dewpoint, pressure)) } +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] #[cfg_attr(feature = "debug", logerr)] pub fn buck3_validate(dewpoint: Float, pressure: Float) -> Result<(), InputError> { if !(253.0..=324.0).contains(&dewpoint) { @@ -164,6 +179,7 @@ pub fn buck3_validate(dewpoint: Float, pressure: Float) -> Result<(), InputError Ok(()) } +#[allow(missing_docs)] pub fn buck3_unchecked(dewpoint: Float, pressure: Float) -> Float { let dewpoint = dewpoint - ZERO_CELSIUS; //convert to C let pressure = pressure / 100.0; //convert to hPa @@ -194,6 +210,8 @@ pub fn buck3_simplified(dewpoint: Float) -> Result { Ok(buck3_simplified_unchecked(dewpoint)) } +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] #[cfg_attr(feature = "debug", logerr)] pub fn buck3_simplified_validate(dewpoint: Float) -> Result<(), InputError> { if !(253.0..=324.0).contains(&dewpoint) { @@ -203,6 +221,7 @@ pub fn buck3_simplified_validate(dewpoint: Float) -> Result<(), InputError> { Ok(()) } +#[allow(missing_docs)] pub fn buck3_simplified_unchecked(dewpoint: Float) -> Float { let dewpoint = dewpoint - ZERO_CELSIUS; //convert to C @@ -229,6 +248,8 @@ pub fn buck4(dewpoint: Float, pressure: Float) -> Result { Ok(buck4_unchecked(dewpoint, pressure)) } +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] #[cfg_attr(feature = "debug", logerr)] pub fn buck4_validate(dewpoint: Float, pressure: Float) -> Result<(), InputError> { if !(223.0..=274.0).contains(&dewpoint) { @@ -242,6 +263,7 @@ pub fn buck4_validate(dewpoint: Float, pressure: Float) -> Result<(), InputError Ok(()) } +#[allow(missing_docs)] pub fn buck4_unchecked(dewpoint: Float, pressure: Float) -> Float { let dewpoint = dewpoint - ZERO_CELSIUS; //convert to C let pressure = pressure / 100.0; //convert to hPa @@ -272,6 +294,8 @@ pub fn buck4_simplified(dewpoint: Float) -> Result { Ok(buck4_simplified_unchecked(dewpoint)) } +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] #[cfg_attr(feature = "debug", logerr)] pub fn buck4_simplified_validate(dewpoint: Float) -> Result<(), InputError> { //validate inputs @@ -282,6 +306,7 @@ pub fn buck4_simplified_validate(dewpoint: Float) -> Result<(), InputError> { Ok(()) } +#[allow(missing_docs)] pub fn buck4_simplified_unchecked(dewpoint: Float) -> Float { let dewpoint = dewpoint - ZERO_CELSIUS; //convert to C @@ -308,6 +333,8 @@ pub fn tetens1(dewpoint: Float) -> Result { Ok(tetens1_unchecked(dewpoint)) } +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] #[cfg_attr(feature = "debug", logerr)] pub fn tetens1_validate(dewpoint: Float) -> Result<(), InputError> { if !(273.0..=353.0).contains(&dewpoint) { @@ -317,6 +344,7 @@ pub fn tetens1_validate(dewpoint: Float) -> Result<(), InputError> { Ok(()) } +#[allow(missing_docs)] pub fn tetens1_unchecked(dewpoint: Float) -> Float { let dewpoint = dewpoint - ZERO_CELSIUS; //convert to C @@ -348,6 +376,8 @@ pub fn saturation_specific1( )) } +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] #[cfg_attr(feature = "debug", logerr)] pub fn saturation_specific1_validate( saturation_vapour_pressure: Float, @@ -366,6 +396,7 @@ pub fn saturation_specific1_validate( Ok(()) } +#[allow(missing_docs)] pub fn saturation_specific1_unchecked( saturation_vapour_pressure: Float, relative_humidity: Float, @@ -392,6 +423,8 @@ pub fn saturation_specific2( )) } +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] #[cfg_attr(feature = "debug", logerr)] pub fn saturation_specific2_validate( vapour_pressure: Float, @@ -408,6 +441,7 @@ pub fn saturation_specific2_validate( Ok(()) } +#[allow(missing_docs)] pub fn saturation_specific2_uchecked(vapour_pressure: Float, relative_humidity: Float) -> Float { vapour_pressure / relative_humidity } @@ -427,6 +461,8 @@ pub fn wexler1(dewpoint: Float) -> Result { Ok(wexler1_unchecked(dewpoint)) } +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] #[cfg_attr(feature = "debug", logerr)] pub fn wexler1_validate(dewpoint: Float) -> Result<(), InputError> { if !(273.0..=374.0).contains(&dewpoint) { @@ -436,6 +472,7 @@ pub fn wexler1_validate(dewpoint: Float) -> Result<(), InputError> { Ok(()) } +#[allow(missing_docs)] pub fn wexler1_unchecked(dewpoint: Float) -> Float { // constants from the paper let g: [Float; 8] = [ @@ -473,6 +510,8 @@ pub fn wexler2(dewpoint: Float) -> Result { Ok(wexler2_unchecked(dewpoint)) } +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] #[cfg_attr(feature = "debug", logerr)] pub fn wexler2_validate(dewpoint: Float) -> Result<(), InputError> { if !(173.0..=274.0).contains(&dewpoint) { @@ -481,6 +520,7 @@ pub fn wexler2_validate(dewpoint: Float) -> Result<(), InputError> { Ok(()) } +#[allow(missing_docs)] pub fn wexler2_unchecked(dewpoint: Float) -> Float { // constants from the paper let big_k: [Float; 6] = [ diff --git a/src/virtual_temperature.rs b/src/virtual_temperature.rs index 0cbfae9..5bbeafa 100644 --- a/src/virtual_temperature.rs +++ b/src/virtual_temperature.rs @@ -22,6 +22,8 @@ pub fn general1(temperature: Float, mixing_ratio: Float) -> Result Result<(), InputError> { if !(173.0..=354.0).contains(&temperature) { @@ -35,6 +37,7 @@ pub fn general1_validate(temperature: Float, mixing_ratio: Float) -> Result<(), Ok(()) } +#[allow(missing_docs)] pub fn general1_unchecked(temperature: Float, mixing_ratio: Float) -> Float { temperature * ((mixing_ratio + EPSILON) / (EPSILON * (1.0 + mixing_ratio))) } @@ -56,6 +59,8 @@ pub fn general2( Ok(general2_unchecked(temperature, pressure, vapour_pressure)) } +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] #[cfg_attr(feature = "debug", logerr)] pub fn general2_validate( temperature: Float, @@ -76,6 +81,7 @@ pub fn general2_validate( Ok(()) } +#[allow(missing_docs)] pub fn general2_unchecked(temperature: Float, pressure: Float, vapour_pressure: Float) -> Float { temperature / (1.0 - ((vapour_pressure / pressure) * (1.0 - EPSILON))) } @@ -92,6 +98,8 @@ pub fn general3(temperature: Float, specific_humidity: Float) -> Result Result<(), InputError> { if !(173.0..=354.0).contains(&temperature) { @@ -105,6 +113,7 @@ pub fn general3_validate(temperature: Float, specific_humidity: Float) -> Result Ok(()) } +#[allow(missing_docs)] pub fn general3_unchecked(temperature: Float, specific_humidity: Float) -> Float { temperature * (1.0 + (specific_humidity * ((1.0 / EPSILON) - 1.0))) } From 787561b187e6110fc9f5e5d86c974503a9d93946 Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 14:12:47 +0100 Subject: [PATCH 14/24] fix unreadble literals --- src/equivalent_potential_temperature.rs | 2 +- src/vapour_pressure.rs | 22 +++++++++++----------- src/virtual_temperature.rs | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/equivalent_potential_temperature.rs b/src/equivalent_potential_temperature.rs index cd737bb..aa764ff 100644 --- a/src/equivalent_potential_temperature.rs +++ b/src/equivalent_potential_temperature.rs @@ -139,7 +139,7 @@ pub fn bolton1(pressure: Float, temperature: Float, dewpoint: Float) -> Result Float { let g: [Float; 8] = [ -2991.2729, -6017.0128, - 18.87643854, - -0.028354721, - 0.0000178383, - -0.00000000084150417, - 0.00000000000044412543, - 2.858487, + 18.876_438_54, + -0.028_354_721, + 0.000_017_838_3, + -0.000_000_000_841_504_17, + 0.000_000_000_000_444_125_43, + 2.858_487, ]; let mut ln_p = g[7] * dewpoint.ln(); @@ -525,11 +525,11 @@ pub fn wexler2_unchecked(dewpoint: Float) -> Float { // constants from the paper let big_k: [Float; 6] = [ -5865.3696, - 22.241033, - 0.013749042, - -0.00003403177, - 0.000000026967687, - 0.6918651, + 22.241_033, + 0.013_749_042, + -0.000_034_031_77, + 0.000_000_026_967_687, + 0.691_865_1, ]; let mut ln_p = big_k[5] * dewpoint.ln(); diff --git a/src/virtual_temperature.rs b/src/virtual_temperature.rs index 5bbeafa..5bff00b 100644 --- a/src/virtual_temperature.rs +++ b/src/virtual_temperature.rs @@ -106,7 +106,7 @@ pub fn general3_validate(temperature: Float, specific_humidity: Float) -> Result return Err(InputError::OutOfRange(String::from("temperature"))); } - if !(0.000000001..=2.0).contains(&specific_humidity) { + if !(0.000_000_001..=2.0).contains(&specific_humidity) { return Err(InputError::OutOfRange(String::from("specific_humidity"))); } From 89ef0fc0e62120f013cd660f2abff2bf642c60af Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 14:23:46 +0100 Subject: [PATCH 15/24] mixing ratio --- src/mixing_ratio.rs | 65 +++++++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 17 deletions(-) diff --git a/src/mixing_ratio.rs b/src/mixing_ratio.rs index 1d8f045..996e3c6 100644 --- a/src/mixing_ratio.rs +++ b/src/mixing_ratio.rs @@ -3,11 +3,11 @@ //!To calculate saturation mixing ratio input dry-bulb temperature in place of dewpoint //!or saturation vapour pressure in place of vapour pressure. +use crate::Float; use crate::{constants::EPSILON, errors::InputError, vapour_pressure}; use float_cmp::approx_eq; -use crate::Float; -#[cfg(feature="debug")] +#[cfg(feature = "debug")] use floccus_proc::logerr; ///Formula for computing mixing ratio of unsaturated air from air pressure and vapour pressure @@ -20,9 +20,15 @@ use floccus_proc::logerr; /// ///Returns [`InputError::IncorrectArgumentSet`] when inputs are equal, in which ///case division by 0 occurs. -#[cfg_attr(feature = "debug", logerr)] pub fn general1(pressure: Float, vapour_pressure: Float) -> Result { - //validate inputs + general1_validate(pressure, vapour_pressure)?; + Ok(general1_unchecked(pressure, vapour_pressure)) +} + +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] +#[cfg_attr(feature = "debug", logerr)] +pub fn general1_validate(pressure: Float, vapour_pressure: Float) -> Result<(), InputError> { if !(100.0..=150_000.0).contains(&pressure) { return Err(InputError::OutOfRange(String::from("pressure"))); } @@ -36,21 +42,31 @@ pub fn general1(pressure: Float, vapour_pressure: Float) -> Result Float { + EPSILON * (vapour_pressure / (pressure - vapour_pressure)) } ///Formula for computing mixing ratio of unsaturated air from dewpoint temperature and pressure. -///Optimised by performance. +///Optimised for performance. /// ///# Errors /// ///Returns [`InputError::OutOfRange`] when one of inputs is out of range.\ ///Valid `dewpoint` range: 273K - 353K\ ///Valid `pressure` range: 100Pa - 150000Pa -#[cfg_attr(feature = "debug", logerr)] pub fn performance1(dewpoint: Float, pressure: Float) -> Result { + performance1_validate(dewpoint, pressure)?; + Ok(performance1_unchecked(dewpoint, pressure)) +} + +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] +#[cfg_attr(feature = "debug", logerr)] +pub fn performance1_validate(dewpoint: Float, pressure: Float) -> Result<(), InputError> { //validate inputs if !(273.0..=353.0).contains(&dewpoint) { return Err(InputError::OutOfRange(String::from("dewpoint"))); @@ -60,22 +76,33 @@ pub fn performance1(dewpoint: Float, pressure: Float) -> Result Float { + let vapour_pressure = vapour_pressure::tetens1_unchecked(dewpoint); + let result = general1_unchecked(pressure, vapour_pressure); + result } ///Formula for computing mixing ratio of unsaturated air from dewpoint temperature and pressure. -///Optimised by accuracy. +///Optimised for accuracy. /// ///# Errors /// ///Returns [`InputError::OutOfRange`] when one of inputs is out of range.\ ///Valid `dewpoint` range: 232K - 324K\ ///Valid `pressure` range: 100Pa - 150000Pa -#[cfg_attr(feature = "debug", logerr)] pub fn accuracy1(dewpoint: Float, pressure: Float) -> Result { - //validate inputs + accuracy1_validate(dewpoint, pressure)?; + Ok(accuracy1_unchecked(dewpoint, pressure)) +} + +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] +#[cfg_attr(feature = "debug", logerr)] +pub fn accuracy1_validate(dewpoint: Float, pressure: Float) -> Result<(), InputError> { if !(232.0..=324.0).contains(&dewpoint) { return Err(InputError::OutOfRange(String::from("dewpoint"))); } @@ -83,10 +110,14 @@ pub fn accuracy1(dewpoint: Float, pressure: Float) -> Result if !(100.0..=150_000.0).contains(&pressure) { return Err(InputError::OutOfRange(String::from("pressure"))); } + Ok(()) +} - let vapour_pressure = vapour_pressure::buck1(dewpoint, pressure)?; - let result = general1(pressure, vapour_pressure)?; - Ok(result) +#[allow(missing_docs)] +pub fn accuracy1_unchecked(dewpoint: Float, pressure: Float) -> Float { + let vapour_pressure = vapour_pressure::buck1_unchecked(dewpoint, pressure); + let result = general1_unchecked(pressure, vapour_pressure); + result } #[cfg(test)] From e73278f2034494e36450ee981e0b4ef8a8b2dcab Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 14:33:09 +0100 Subject: [PATCH 16/24] relative humidity --- src/relative_humidity.rs | 129 +++++++++++++++++++++++++++++++-------- 1 file changed, 104 insertions(+), 25 deletions(-) diff --git a/src/relative_humidity.rs b/src/relative_humidity.rs index 097f720..2218cb8 100644 --- a/src/relative_humidity.rs +++ b/src/relative_humidity.rs @@ -1,9 +1,9 @@ //!Functions to calculate relative humidity in %/100 -use crate::{errors::InputError, mixing_ratio, vapour_pressure}; use crate::Float; +use crate::{errors::InputError, mixing_ratio, vapour_pressure}; -#[cfg(feature="debug")] +#[cfg(feature = "debug")] use floccus_proc::logerr; ///Formula for computing relative humidity from mixing ratio and saturation mixing ratio. @@ -17,8 +17,18 @@ use floccus_proc::logerr; ///Returns [`InputError::OutOfRange`] when one of inputs is out of range.\ ///Valid `mixing_ratio` range: 0.00001 - 0.5\ ///Valid `saturation_mixing_ratio` range: 0.00001 - 0.5 -#[cfg_attr(feature = "debug", logerr)] pub fn general1(mixing_ratio: Float, saturation_mixing_ratio: Float) -> Result { + general1_validate(mixing_ratio, saturation_mixing_ratio)?; + Ok(general1_unchecked(mixing_ratio, saturation_mixing_ratio)) +} + +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] +#[cfg_attr(feature = "debug", logerr)] +pub fn general1_validate( + mixing_ratio: Float, + saturation_mixing_ratio: Float, +) -> Result<(), InputError> { if !(0.00001..=10.0).contains(&mixing_ratio) { return Err(InputError::OutOfRange(String::from("mixing_ratio"))); } @@ -29,7 +39,12 @@ pub fn general1(mixing_ratio: Float, saturation_mixing_ratio: Float) -> Result Float { + mixing_ratio / saturation_mixing_ratio } ///Formula for computing relative humidity from vapour pressure and saturation vapour pressure. @@ -40,8 +55,24 @@ pub fn general1(mixing_ratio: Float, saturation_mixing_ratio: Float) -> Result Result { + general2_validate(vapour_pressure, saturation_vapour_pressure)?; + Ok(general2_unchecked( + vapour_pressure, + saturation_vapour_pressure, + )) +} + +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] #[cfg_attr(feature = "debug", logerr)] -pub fn general2(vapour_pressure: Float, saturation_vapour_pressure: Float) -> Result { +pub fn general2_validate( + vapour_pressure: Float, + saturation_vapour_pressure: Float, +) -> Result<(), InputError> { if !(0.0..=50_000.0).contains(&vapour_pressure) { return Err(InputError::OutOfRange(String::from("vapour_pressure"))); } @@ -52,9 +83,13 @@ pub fn general2(vapour_pressure: Float, saturation_vapour_pressure: Float) -> Re ))); } - Ok(vapour_pressure / saturation_vapour_pressure) + Ok(()) } +#[allow(missing_docs)] +pub fn general2_unchecked(vapour_pressure: Float, saturation_vapour_pressure: Float) -> Float { + vapour_pressure / saturation_vapour_pressure +} ///Formula for computing relative humidity from temperature and dewpoint using [`tetens1`](vapour_pressure::tetens1) ///function for vapour pressure calculation /// @@ -63,21 +98,33 @@ pub fn general2(vapour_pressure: Float, saturation_vapour_pressure: Float) -> Re ///Returns [`InputError::OutOfRange`] when one of inputs is out of range.\ ///Valid `temperature` range: 273K - 353K ///Valid `dewpoint` range: 273K - 353K -#[cfg_attr(feature = "debug", logerr)] pub fn general3(temperature: Float, dewpoint: Float) -> Result { + general3_validate(temperature, dewpoint)?; + Ok(general3_unchecked(temperature, dewpoint)) +} + +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] +#[cfg_attr(feature = "debug", logerr)] +pub fn general3_validate(temperature: Float, dewpoint: Float) -> Result<(), InputError> { if !(273.0..=353.0).contains(&temperature) { return Err(InputError::OutOfRange(String::from("temperature"))); } - if !(273.0..=353.0).contains(&temperature) { - return Err(InputError::OutOfRange(String::from("temperature"))); + if !(273.0..=353.0).contains(&dewpoint) { + return Err(InputError::OutOfRange(String::from("dewpoint"))); } - let vapour_pressure = vapour_pressure::tetens1(dewpoint)?; - let saturation_vapour_pressure = vapour_pressure::tetens1(temperature)?; - let result = general2(vapour_pressure, saturation_vapour_pressure)?; + Ok(()) +} + +#[allow(missing_docs)] +pub fn general3_unchecked(temperature: Float, dewpoint: Float) -> Float { + let vapour_pressure = vapour_pressure::tetens1_unchecked(dewpoint); + let saturation_vapour_pressure = vapour_pressure::tetens1_unchecked(temperature); + let result = general2_unchecked(vapour_pressure, saturation_vapour_pressure); - Ok(result) + result } ///Formula for computing relative humidity from temperature, dewpoint and pressure using [`buck3`](vapour_pressure::buck3) @@ -89,25 +136,41 @@ pub fn general3(temperature: Float, dewpoint: Float) -> Result Result { + general4_validate(temperature, dewpoint, pressure)?; + Ok(general4_unchecked(temperature, dewpoint, pressure)) +} + +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] +#[cfg_attr(feature = "debug", logerr)] +pub fn general4_validate( + temperature: Float, + dewpoint: Float, + pressure: Float, +) -> Result<(), InputError> { if !(253.0..=324.0).contains(&temperature) { return Err(InputError::OutOfRange(String::from("temperature"))); } - if !(253.0..=324.0).contains(&temperature) { - return Err(InputError::OutOfRange(String::from("temperature"))); + if !(253.0..=324.0).contains(&dewpoint) { + return Err(InputError::OutOfRange(String::from("dewpoint"))); } if !(100.0..=150_000.0).contains(&pressure) { return Err(InputError::OutOfRange(String::from("pressure"))); } - let vapour_pressure = vapour_pressure::buck3(dewpoint, pressure)?; - let saturation_vapour_pressure = vapour_pressure::buck3(temperature, pressure)?; - let result = general2(vapour_pressure, saturation_vapour_pressure)?; + Ok(()) +} + +#[allow(missing_docs)] +pub fn general4_unchecked(temperature: Float, dewpoint: Float, pressure: Float) -> Float { + let vapour_pressure = vapour_pressure::buck3_unchecked(dewpoint, pressure); + let saturation_vapour_pressure = vapour_pressure::buck3_unchecked(temperature, pressure); + let result = general2_unchecked(vapour_pressure, saturation_vapour_pressure); - Ok(result) + result } ///Formula for computing relative humidity from temperature, dewpoint and pressure using [`accuracy1`](mixing_ratio::accuracy1) @@ -119,8 +182,19 @@ pub fn general4(temperature: Float, dewpoint: Float, pressure: Float) -> Result< ///Valid `temperature` range: 232K - 324K\ ///Valid `dewpoint` range: 232K - 324K\ ///Valid `pressure` range: 100Pa - 150000Pa -#[cfg_attr(feature = "debug", logerr)] pub fn general5(temperature: Float, dewpoint: Float, pressure: Float) -> Result { + general5_validate(temperature, dewpoint, pressure)?; + Ok(general5_unchecked(temperature, dewpoint, pressure)) +} + +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] +#[cfg_attr(feature = "debug", logerr)] +pub fn general5_validate( + temperature: Float, + dewpoint: Float, + pressure: Float, +) -> Result<(), InputError> { if !(232.0..=314.0).contains(&temperature) { return Err(InputError::OutOfRange(String::from("temperature"))); } @@ -133,11 +207,16 @@ pub fn general5(temperature: Float, dewpoint: Float, pressure: Float) -> Result< return Err(InputError::OutOfRange(String::from("pressure"))); } - let mixing_ratio = mixing_ratio::accuracy1(dewpoint, pressure)?; - let saturation_mixing_ratio = mixing_ratio::accuracy1(temperature, pressure)?; - let result = general1(mixing_ratio, saturation_mixing_ratio)?; + Ok(()) +} + +#[allow(missing_docs)] +pub fn general5_unchecked(temperature: Float, dewpoint: Float, pressure: Float) -> Float { + let mixing_ratio = mixing_ratio::accuracy1_unchecked(dewpoint, pressure); + let saturation_mixing_ratio = mixing_ratio::accuracy1_unchecked(temperature, pressure); + let result = general1_unchecked(mixing_ratio, saturation_mixing_ratio); - Ok(result) + result } #[cfg(test)] From 777533fa50e1e4db3a228b6012269742dbe3f8cd Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 14:33:29 +0100 Subject: [PATCH 17/24] clippy --- src/mixing_ratio.rs | 8 ++++---- src/relative_humidity.rs | 9 +++------ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/mixing_ratio.rs b/src/mixing_ratio.rs index 996e3c6..54826d5 100644 --- a/src/mixing_ratio.rs +++ b/src/mixing_ratio.rs @@ -82,8 +82,8 @@ pub fn performance1_validate(dewpoint: Float, pressure: Float) -> Result<(), Inp #[allow(missing_docs)] pub fn performance1_unchecked(dewpoint: Float, pressure: Float) -> Float { let vapour_pressure = vapour_pressure::tetens1_unchecked(dewpoint); - let result = general1_unchecked(pressure, vapour_pressure); - result + + general1_unchecked(pressure, vapour_pressure) } ///Formula for computing mixing ratio of unsaturated air from dewpoint temperature and pressure. @@ -116,8 +116,8 @@ pub fn accuracy1_validate(dewpoint: Float, pressure: Float) -> Result<(), InputE #[allow(missing_docs)] pub fn accuracy1_unchecked(dewpoint: Float, pressure: Float) -> Float { let vapour_pressure = vapour_pressure::buck1_unchecked(dewpoint, pressure); - let result = general1_unchecked(pressure, vapour_pressure); - result + + general1_unchecked(pressure, vapour_pressure) } #[cfg(test)] diff --git a/src/relative_humidity.rs b/src/relative_humidity.rs index 2218cb8..a625b48 100644 --- a/src/relative_humidity.rs +++ b/src/relative_humidity.rs @@ -122,9 +122,8 @@ pub fn general3_validate(temperature: Float, dewpoint: Float) -> Result<(), Inpu pub fn general3_unchecked(temperature: Float, dewpoint: Float) -> Float { let vapour_pressure = vapour_pressure::tetens1_unchecked(dewpoint); let saturation_vapour_pressure = vapour_pressure::tetens1_unchecked(temperature); - let result = general2_unchecked(vapour_pressure, saturation_vapour_pressure); - result + general2_unchecked(vapour_pressure, saturation_vapour_pressure) } ///Formula for computing relative humidity from temperature, dewpoint and pressure using [`buck3`](vapour_pressure::buck3) @@ -168,9 +167,8 @@ pub fn general4_validate( pub fn general4_unchecked(temperature: Float, dewpoint: Float, pressure: Float) -> Float { let vapour_pressure = vapour_pressure::buck3_unchecked(dewpoint, pressure); let saturation_vapour_pressure = vapour_pressure::buck3_unchecked(temperature, pressure); - let result = general2_unchecked(vapour_pressure, saturation_vapour_pressure); - result + general2_unchecked(vapour_pressure, saturation_vapour_pressure) } ///Formula for computing relative humidity from temperature, dewpoint and pressure using [`accuracy1`](mixing_ratio::accuracy1) @@ -214,9 +212,8 @@ pub fn general5_validate( pub fn general5_unchecked(temperature: Float, dewpoint: Float, pressure: Float) -> Float { let mixing_ratio = mixing_ratio::accuracy1_unchecked(dewpoint, pressure); let saturation_mixing_ratio = mixing_ratio::accuracy1_unchecked(temperature, pressure); - let result = general1_unchecked(mixing_ratio, saturation_mixing_ratio); - result + general1_unchecked(mixing_ratio, saturation_mixing_ratio) } #[cfg(test)] From 62a943e101b5045f57bc62d9e4509bb1a8cb2c03 Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 14:36:38 +0100 Subject: [PATCH 18/24] potential temperature --- src/potential_temperature.rs | 37 ++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/potential_temperature.rs b/src/potential_temperature.rs index 66610f8..2580178 100644 --- a/src/potential_temperature.rs +++ b/src/potential_temperature.rs @@ -1,13 +1,13 @@ //!Functions to calculate potential temperature of dry air in K. -use float_cmp::approx_eq; use crate::Float; use crate::{ constants::{C_P, R_D}, errors::InputError, }; +use float_cmp::approx_eq; -#[cfg(feature="debug")] +#[cfg(feature = "debug")] use floccus_proc::logerr; ///Formula for computing potential temperature of dry air from temperature, pressure and vapour pressure. @@ -26,12 +26,27 @@ use floccus_proc::logerr; /// ///Returns [`InputError::IncorrectArgumentSet`] when `pressure` is lower than `vapour_pressure`, ///in which case floating-point exponentation of negative number occurs. -#[cfg_attr(feature = "debug", logerr)] pub fn davies_jones1( temperature: Float, pressure: Float, vapour_pressure: Float, ) -> Result { + davies_jones1_validate(temperature, pressure, vapour_pressure)?; + Ok(davies_jones1_unchecked( + temperature, + pressure, + vapour_pressure, + )) +} + +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] +#[cfg_attr(feature = "debug", logerr)] +pub fn davies_jones1_validate( + temperature: Float, + pressure: Float, + vapour_pressure: Float, +) -> Result<(), InputError> { if !(253.0..=324.0).contains(&temperature) { return Err(InputError::OutOfRange(String::from("temperature"))); } @@ -56,18 +71,24 @@ pub fn davies_jones1( ))); } - let kappa = R_D / C_P; - - let result = temperature * (100_000.0 / (pressure - vapour_pressure)).powf(kappa); + Ok(()) +} - Ok(result) +#[allow(missing_docs)] +pub fn davies_jones1_unchecked( + temperature: Float, + pressure: Float, + vapour_pressure: Float, +) -> Float { + let kappa = R_D / C_P; + temperature * (100_000.0 / (pressure - vapour_pressure)).powf(kappa) } #[cfg(test)] mod tests { use crate::{ - tests_framework::{self, Argument}, potential_temperature, + tests_framework::{self, Argument}, }; #[test] From 3499124693b324123cb4d73d550be41cb3f41b18 Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 14:38:16 +0100 Subject: [PATCH 19/24] specific humidity --- src/specific_humidity.rs | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/specific_humidity.rs b/src/specific_humidity.rs index 4f4af45..c88e690 100644 --- a/src/specific_humidity.rs +++ b/src/specific_humidity.rs @@ -5,10 +5,10 @@ //! //!Specific humidity is approximately equal to mixing ratio. -use crate::{constants::EPSILON, errors::InputError}; use crate::Float; +use crate::{constants::EPSILON, errors::InputError}; -#[cfg(feature="debug")] +#[cfg(feature = "debug")] use floccus_proc::logerr; ///Formula for computing specific humidity from vapour pressure and pressure. @@ -22,8 +22,15 @@ use floccus_proc::logerr; ///Returns [`InputError::OutOfRange`] when one of inputs is out of range.\ ///Valid `vapour_pressure` range: 0Pa - 50000OPa\, ///Valid `pressure` range: 100Pa - 150000Pa -#[cfg_attr(feature = "debug", logerr)] pub fn general1(vapour_pressure: Float, pressure: Float) -> Result { + general1_validate(vapour_pressure, pressure)?; + Ok(general1_unchecked(vapour_pressure, pressure)) +} + +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] +#[cfg_attr(feature = "debug", logerr)] +pub fn general1_validate(vapour_pressure: Float, pressure: Float) -> Result<(), InputError> { if !(0.0..=50_000.0).contains(&vapour_pressure) { return Err(InputError::OutOfRange(String::from("vapour_pressure"))); } @@ -32,8 +39,12 @@ pub fn general1(vapour_pressure: Float, pressure: Float) -> Result Float { + EPSILON * (vapour_pressure / (pressure - (vapour_pressure * (1.0 - EPSILON)))) } #[cfg(test)] From ea0c0a30bf2246b8e8efb505f7649dca323b43d7 Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 14:43:19 +0100 Subject: [PATCH 20/24] vpd --- src/vapour_pressure_deficit.rs | 82 +++++++++++++++++++++++++++------- 1 file changed, 66 insertions(+), 16 deletions(-) diff --git a/src/vapour_pressure_deficit.rs b/src/vapour_pressure_deficit.rs index f42d17a..4d8a399 100644 --- a/src/vapour_pressure_deficit.rs +++ b/src/vapour_pressure_deficit.rs @@ -4,10 +4,10 @@ //!the amount of moisture in the air and how much moisture the air can hold //!when it is saturated ([Wikipedia](https://en.wikipedia.org/wiki/Vapour-pressure_deficit)). -use crate::{errors::InputError, vapour_pressure}; use crate::Float; +use crate::{errors::InputError, vapour_pressure}; -#[cfg(feature="debug")] +#[cfg(feature = "debug")] use floccus_proc::logerr; ///Formula for computing vapour pressure deficit from vapour pressure and saturation vapour pressure @@ -17,8 +17,24 @@ use floccus_proc::logerr; ///Returns [`InputError::OutOfRange`] when one of inputs is out of range.\ ///Valid `vapour_pressure` range: 0Pa - 10000Pa ///Valid `saturation_vapour_pressure` range: 0Pa - 10000Pa +pub fn general1( + vapour_pressure: Float, + saturation_vapour_pressure: Float, +) -> Result { + general1_validate(vapour_pressure, saturation_vapour_pressure)?; + Ok(general1_unchecked( + vapour_pressure, + saturation_vapour_pressure, + )) +} + +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] #[cfg_attr(feature = "debug", logerr)] -pub fn general1(vapour_pressure: Float, saturation_vapour_pressure: Float) -> Result { +pub fn general1_validate( + vapour_pressure: Float, + saturation_vapour_pressure: Float, +) -> Result<(), InputError> { if !(0.0..=50_000.0).contains(&vapour_pressure) { return Err(InputError::OutOfRange(String::from("vapour_pressure"))); } @@ -29,7 +45,12 @@ pub fn general1(vapour_pressure: Float, saturation_vapour_pressure: Float) -> Re ))); } - Ok(saturation_vapour_pressure - vapour_pressure) + Ok(()) +} + +#[allow(missing_docs)] +pub fn general1_unchecked(vapour_pressure: Float, saturation_vapour_pressure: Float) -> Float { + saturation_vapour_pressure - vapour_pressure } ///Formula for computing vapour pressure deficit from temperature, dewpoint and pressure @@ -40,8 +61,19 @@ pub fn general1(vapour_pressure: Float, saturation_vapour_pressure: Float) -> Re ///Returns [`InputError::OutOfRange`] when one of inputs is out of range.\ ///Valid `vapour_pressure` range: 0Pa - 10000Pa ///Valid `saturation_vapour_pressure` range: 0Pa - 10000Pa -#[cfg_attr(feature = "debug", logerr)] pub fn general2(temperature: Float, dewpoint: Float, pressure: Float) -> Result { + general2_validate(temperature, dewpoint, pressure)?; + Ok(general2_unchecked(temperature, dewpoint, pressure)) +} + +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] +#[cfg_attr(feature = "debug", logerr)] +pub fn general2_validate( + temperature: Float, + dewpoint: Float, + pressure: Float, +) -> Result<(), InputError> { if !(253.0..=324.0).contains(&temperature) { return Err(InputError::OutOfRange(String::from("temperature"))); } @@ -53,13 +85,15 @@ pub fn general2(temperature: Float, dewpoint: Float, pressure: Float) -> Result< if !(100.0..=150_000.0).contains(&pressure) { return Err(InputError::OutOfRange(String::from("pressure"))); } + Ok(()) +} - let vapour_pressure = vapour_pressure::buck3(dewpoint, pressure)?; - let saturation_vapour_pressure = vapour_pressure::buck3(temperature, pressure)?; - - let result = general1(vapour_pressure, saturation_vapour_pressure)?; +#[allow(missing_docs)] +pub fn general2_unchecked(temperature: Float, dewpoint: Float, pressure: Float) -> Float { + let vapour_pressure = vapour_pressure::buck3_unchecked(dewpoint, pressure); + let saturation_vapour_pressure = vapour_pressure::buck3_unchecked(temperature, pressure); - Ok(result) + general1_unchecked(vapour_pressure, saturation_vapour_pressure) } ///Formula for computing vapour pressure deficit from temperature, relative humidity and pressure @@ -70,12 +104,23 @@ pub fn general2(temperature: Float, dewpoint: Float, pressure: Float) -> Result< ///Returns [`InputError::OutOfRange`] when one of inputs is out of range.\ ///Valid `vapour_pressure` range: 0Pa - 10000Pa ///Valid `saturation_vapour_pressure` range: 0Pa - 10000Pa -#[cfg_attr(feature = "debug", logerr)] pub fn general3( temperature: Float, relative_humidity: Float, pressure: Float, ) -> Result { + general3_validate(temperature, relative_humidity, pressure)?; + Ok(general3_unchecked(temperature, relative_humidity, pressure)) +} + +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] +#[cfg_attr(feature = "debug", logerr)] +pub fn general3_validate( + temperature: Float, + relative_humidity: Float, + pressure: Float, +) -> Result<(), InputError> { if !(253.0..=319.0).contains(&temperature) { return Err(InputError::OutOfRange(String::from("temperature"))); } @@ -88,13 +133,18 @@ pub fn general3( return Err(InputError::OutOfRange(String::from("pressure"))); } - let saturation_vapour_pressure = vapour_pressure::buck3(temperature, pressure)?; - let vapour_pressure = - vapour_pressure::saturation_specific1(saturation_vapour_pressure, relative_humidity)?; + Ok(()) +} - let result = general1(vapour_pressure, saturation_vapour_pressure)?; +#[allow(missing_docs)] +pub fn general3_unchecked(temperature: Float, relative_humidity: Float, pressure: Float) -> Float { + let saturation_vapour_pressure = vapour_pressure::buck3_unchecked(temperature, pressure); + let vapour_pressure = vapour_pressure::saturation_specific1_unchecked( + saturation_vapour_pressure, + relative_humidity, + ); - Ok(result) + general1_unchecked(vapour_pressure, saturation_vapour_pressure) } #[cfg(test)] From 12ee81313716fd4e4cc93c9052b6c6669ca0c931 Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 14:53:52 +0100 Subject: [PATCH 21/24] theta e --- src/equivalent_potential_temperature.rs | 97 ++++++++++++++++++------- 1 file changed, 70 insertions(+), 27 deletions(-) diff --git a/src/equivalent_potential_temperature.rs b/src/equivalent_potential_temperature.rs index aa764ff..0722248 100644 --- a/src/equivalent_potential_temperature.rs +++ b/src/equivalent_potential_temperature.rs @@ -15,6 +15,8 @@ use floccus_proc::logerr; /// ///Implementation of this formula assumes no liquid or solid water in the air parcel. /// +///First appeared in Paluch, Ilga (1979). J. Atmos. Sci., 36, 2467-2478 +/// ///Provided in Emmanuel, Kerry (1994). Atmospheric Convection. Oxford University Press. /// ///# Errors @@ -23,12 +25,23 @@ use floccus_proc::logerr; ///Valid `temperature` range: 253K - 324K\ ///Valid `pressure` range: 100Pa - 150000Pa\ ///Valid `vapour_pressure` range: 0Pa - 10000Pa -#[cfg_attr(feature = "debug", logerr)] -pub fn general1( +pub fn paluch1( temperature: Float, pressure: Float, vapour_pressure: Float, ) -> Result { + paluch1_validate(temperature, pressure, vapour_pressure)?; + Ok(paluch1_unchecked(temperature, pressure, vapour_pressure)) +} + +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] +#[cfg_attr(feature = "debug", logerr)] +pub fn paluch1_validate( + temperature: Float, + pressure: Float, + vapour_pressure: Float, +) -> Result<(), InputError> { if !(253.0..=324.0).contains(&temperature) { return Err(InputError::OutOfRange(String::from("temperature"))); } @@ -41,20 +54,23 @@ pub fn general1( return Err(InputError::OutOfRange(String::from("vapour_pressure"))); } + Ok(()) +} + +#[allow(missing_docs)] +pub fn paluch1_unchecked(temperature: Float, pressure: Float, vapour_pressure: Float) -> Float { let p0 = 100_000.0; - let mixing_ratio = mixing_ratio::general1(pressure, vapour_pressure)?; - let saturation_vapour_pressure = vapour_pressure::buck1(temperature, pressure)?; + let mixing_ratio = mixing_ratio::general1_unchecked(pressure, vapour_pressure); + let saturation_vapour_pressure = vapour_pressure::buck1_unchecked(temperature, pressure); let relative_humidity = - relative_humidity::general2(vapour_pressure, saturation_vapour_pressure)?; + relative_humidity::general2_unchecked(vapour_pressure, saturation_vapour_pressure); - let result = temperature + temperature * (p0 / pressure).powf(R_D / (C_P + mixing_ratio * C_L)) * relative_humidity.powf((-mixing_ratio * R_V) / (C_P + mixing_ratio * C_L)) - * ((L_V * mixing_ratio) / (temperature * (C_P + mixing_ratio * C_L))).exp(); - - Ok(result) + * ((L_V * mixing_ratio) / (temperature * (C_P + mixing_ratio * C_L))).exp() } ///Formula for computing equivalent potential temperature of unsaturated air from @@ -68,12 +84,23 @@ pub fn general1( ///Valid `temperature` range: 253K - 324K\ ///Valid `pressure` range: 100Pa - 150000Pa\ ///Valid `vapour_pressure` range: 0Pa - 10000Pa -#[cfg_attr(feature = "debug", logerr)] pub fn bryan1( temperature: Float, pressure: Float, vapour_pressure: Float, ) -> Result { + bryan1_validate(temperature, pressure, vapour_pressure)?; + Ok(bryan1_unchecked(temperature, pressure, vapour_pressure)) +} + +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] +#[cfg_attr(feature = "debug", logerr)] +pub fn bryan1_validate( + temperature: Float, + pressure: Float, + vapour_pressure: Float, +) -> Result<(), InputError> { if !(253.0..=324.0).contains(&temperature) { return Err(InputError::OutOfRange(String::from("temperature"))); } @@ -86,22 +113,25 @@ pub fn bryan1( return Err(InputError::OutOfRange(String::from("vapour_pressure"))); } + Ok(()) +} + +#[allow(missing_docs)] +pub fn bryan1_unchecked(temperature: Float, pressure: Float, vapour_pressure: Float) -> Float { let kappa = R_D / C_P; let potential_temperature = - potential_temperature::davies_jones1(temperature, pressure, vapour_pressure)?; + potential_temperature::davies_jones1_unchecked(temperature, pressure, vapour_pressure); - let saturation_vapour_pressure = vapour_pressure::buck3(temperature, pressure)?; + let saturation_vapour_pressure = vapour_pressure::buck3_unchecked(temperature, pressure); let relative_humidity = - relative_humidity::general2(vapour_pressure, saturation_vapour_pressure)?; + relative_humidity::general2_unchecked(vapour_pressure, saturation_vapour_pressure); - let mixing_ratio = mixing_ratio::general1(pressure, vapour_pressure)?; + let mixing_ratio = mixing_ratio::general1_unchecked(pressure, vapour_pressure); - let result = potential_temperature + potential_temperature * relative_humidity.powf((-kappa) * (mixing_ratio / EPSILON)) - * ((L_V * mixing_ratio) / (C_P * temperature)).exp(); - - Ok(result) + * ((L_V * mixing_ratio) / (C_P * temperature)).exp() } ///Approximate formula for computing equivalent potential temperature of unsaturated air from @@ -116,8 +146,19 @@ pub fn bryan1( ///Valid `pressure` range: 100Pa - 150000Pa\ ///Valid `temperature` range: 253K - 324K\ ///Valid `dewpoint` range: 253K - 324K -#[cfg_attr(feature = "debug", logerr)] pub fn bolton1(pressure: Float, temperature: Float, dewpoint: Float) -> Result { + bolton1_validate(pressure, temperature, dewpoint)?; + Ok(bolton1_unchecked(pressure, temperature, dewpoint)) +} + +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] +#[cfg_attr(feature = "debug", logerr)] +pub fn bolton1_validate( + pressure: Float, + temperature: Float, + dewpoint: Float, +) -> Result<(), InputError> { if !(20000.0..=150_000.0).contains(&pressure) { return Err(InputError::OutOfRange(String::from("pressure"))); } @@ -130,10 +171,15 @@ pub fn bolton1(pressure: Float, temperature: Float, dewpoint: Float) -> Result Float { let kappa = R_D / C_P; - let vapour_pressure = vapour_pressure::buck3(dewpoint, pressure)?; - let mixing_ratio = mixing_ratio::general1(pressure, vapour_pressure)?; + let vapour_pressure = vapour_pressure::buck3_unchecked(dewpoint, pressure); + let mixing_ratio = mixing_ratio::general1_unchecked(pressure, vapour_pressure); let lcl_temp = (1.0 / ((1.0 / (dewpoint - 56.0)) + ((temperature / dewpoint).ln() / 800.0))) + 56.0; @@ -142,10 +188,7 @@ pub fn bolton1(pressure: Float, temperature: Float, dewpoint: Float) -> Result Date: Mon, 19 Feb 2024 14:55:46 +0100 Subject: [PATCH 22/24] wet bulb temperature --- src/wet_bulb_temperature.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/wet_bulb_temperature.rs b/src/wet_bulb_temperature.rs index 1801500..c162d1d 100644 --- a/src/wet_bulb_temperature.rs +++ b/src/wet_bulb_temperature.rs @@ -1,9 +1,9 @@ //!Functions to calculate wet bulb temperature of unsaturated air in K. -use crate::{constants::ZERO_CELSIUS, errors::InputError}; use crate::Float; +use crate::{constants::ZERO_CELSIUS, errors::InputError}; -#[cfg(feature="debug")] +#[cfg(feature = "debug")] use floccus_proc::logerr; ///Formula for computing wet bulb temperature pressure from dry bulb temperature and relative humidity. @@ -17,8 +17,15 @@ use floccus_proc::logerr; ///Returns [`InputError::OutOfRange`] when one of inputs is out of range.\ ///Valid `temperature` range: 253K - 324K\ ///Valid `relative_humidity` range: 0.05 - 0.99 -#[cfg_attr(feature = "debug", logerr)] pub fn stull1(temperature: Float, relative_humidity: Float) -> Result { + stull1_validate(temperature, relative_humidity)?; + Ok(stull1_unchecked(temperature, relative_humidity)) +} + +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] +#[cfg_attr(feature = "debug", logerr)] +pub fn stull1_validate(temperature: Float, relative_humidity: Float) -> Result<(), InputError> { if !(253.0..=324.0).contains(&temperature) { return Err(InputError::OutOfRange(String::from("temperature"))); } @@ -26,7 +33,11 @@ pub fn stull1(temperature: Float, relative_humidity: Float) -> Result Float { //convert units let temperature = temperature - ZERO_CELSIUS; let relative_humidity = relative_humidity * 100.0; @@ -37,7 +48,7 @@ pub fn stull1(temperature: Float, relative_humidity: Float) -> Result Date: Mon, 19 Feb 2024 14:58:06 +0100 Subject: [PATCH 23/24] theta w --- src/wet_bulb_potential_temperature.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/wet_bulb_potential_temperature.rs b/src/wet_bulb_potential_temperature.rs index 192e303..f0947f6 100644 --- a/src/wet_bulb_potential_temperature.rs +++ b/src/wet_bulb_potential_temperature.rs @@ -6,7 +6,7 @@ use crate::{ errors::InputError, }; -#[cfg(feature="debug")] +#[cfg(feature = "debug")] use floccus_proc::logerr; ///Formula for computing wet bulb potential temperature from equivalent potential temperature. @@ -17,18 +17,29 @@ use floccus_proc::logerr; /// ///Returns [`InputError::OutOfRange`] when one of inputs is out of range.\ ///Valid `temperature` range: 257K - 377K\ -#[cfg_attr(feature = "debug", logerr)] pub fn davies_jones1(equivalent_potential_temperature: Float) -> Result { + davies_jones1_validate(equivalent_potential_temperature)?; + Ok(davies_jones1_unchecked(equivalent_potential_temperature)) +} + +#[allow(missing_docs)] +#[allow(clippy::missing_errors_doc)] +#[cfg_attr(feature = "debug", logerr)] +pub fn davies_jones1_validate(equivalent_potential_temperature: Float) -> Result<(), InputError> { if !(257.0..=377.0).contains(&equivalent_potential_temperature) { return Err(InputError::OutOfRange(String::from( "equivalent_potential_temperature", ))); } - let lambda = C_P / R_D; + Ok(()) +} +#[allow(missing_docs)] +pub fn davies_jones1_unchecked(equivalent_potential_temperature: Float) -> Float { + let lambda = C_P / R_D; let result = 45.114 - 51.489 * (ZERO_CELSIUS / equivalent_potential_temperature).powf(lambda); - Ok(result + ZERO_CELSIUS) + result + ZERO_CELSIUS } #[cfg(test)] From 8a4818e344243f63af9e2463742eec8ec12d3d52 Mon Sep 17 00:00:00 2001 From: Quba1 <22771850+Quba1@users.noreply.github.com> Date: Mon, 19 Feb 2024 15:06:06 +0100 Subject: [PATCH 24/24] update docs --- README.md | 3 +++ src/lib.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/README.md b/README.md index 1683141..958f710 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,9 @@ To prevent any unexpected behavior, all functions check whether provided inputs Exact limits are specified in the documentation of each function. If the input is out of range the function will return an `InputError::OutOfRange` with erroneous input specified. +Each function also has `_unchecked` and `_validate` versions. The `_validate` version only checks the inputs with bounds defined for its "parent" function. +The `_unchecked` version performs only the calculation without any input checking. All "parent" functions simply call `_validate` and then `_unchecked`. + ## Debugging If additional information is needed about which function returns the error and why, `debug` feature can be enabled. diff --git a/src/lib.rs b/src/lib.rs index cd3b0c3..2bfc9f0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,6 +54,9 @@ //! Exact limits are specified in the documentation of each function. //! If the input is out of range the function will return an [`InputError::OutOfRange`](errors::InputError::OutOfRange) with erronous input specified. //! +//! Each function also has `_unchecked` and `_validate` versions. The `_validate` version only checks the inputs with bounds defined for its "parent" function. +//! The `_unchecked` version performs only the calculation without any input checking. All "parent" functions simply call `_validate` and then `_unchecked`. +//! //! # Units //! //! This crate uses basic SI units in the interface.