From 804546cc0a875b6b23428d0e4ebe8d9ace112269 Mon Sep 17 00:00:00 2001 From: jorgecardleitao <149073281+jorgecardleitao@users.noreply.github.com> Date: Wed, 6 Dec 2023 08:51:01 +0100 Subject: [PATCH] Minor improvements (#13) --- Cargo.toml | 7 ++- examples/dk_jets.md | 24 ++++---- examples/dk_jets.rs | 131 ++++++++++++++++++++++++-------------------- src/lib.rs | 1 + src/types.csv | 1 - 5 files changed, 89 insertions(+), 75 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fda8cd0..5808a3c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,8 +25,10 @@ geoutils = {version="*", default_features = false} # read airport names csv = {version="*", default_features = false} -# +# async utilities async-trait = "*" +async-recursion = "1.0" +futures = "0.3" # logging log = "*" @@ -35,12 +37,11 @@ log = "*" azure_storage = "*" azure_storage_blobs = "*" azure_core = "*" -futures = "0.3" bytes = "1.5" -async-recursion = "1.0" [dev-dependencies] tinytemplate = "1.1" clap = { version = "4.4.6", features = ["derive"] } tokio = {version="1.0", features=["rt", "macros", "rt-multi-thread"]} simple_logger = "*" +num-format = "*" diff --git a/examples/dk_jets.md b/examples/dk_jets.md index f460e96..7be322a 100644 --- a/examples/dk_jets.md +++ b/examples/dk_jets.md @@ -1,8 +1,9 @@ # Use of Danish private jets -{from_date} to {to_date}, Danish private jets emitted -{emissions_tons.claim} tons of CO2e[^5], the equivalent of what **{dane_years.claim} Danes** -emit in a year[^4]. +{from_date} to {to_date}, all Danish private jets emitted +{emissions_tons.claim} tons of CO2e[^1], or what **{dane_years.claim} Danes** emit in a year[^2]. +{number_of_private_jets.claim} private jets alone[^3] jeopardize the efforts of millions +of Danes that every day act to reduce their emissions. Of these, * {number_of_legs_less_300km} trips were less than 300 km and could have been replaced by @@ -11,14 +12,15 @@ Of these, a first class ticket on a commercial aircraft, which would have emitted ~{ratio_commercial_300km}x less CO2[^5]. -Billionaires and companies alike are incapable of regulating their emissions, -recklessly destroying the common good. -Ban private jets now and until they emit what equivalent means of transportation would emit. +The use of private jets by billionaires and large companies alike is an insult +to Danes and Danish companies alike that are doing everything they can to +keep for our future. -## References +> Ban private jets _now_ -[^2]: {number_of_legs.source} - retrieved on {number_of_legs.date} -[^4]: {dane_years.source} - retrieved on {dane_years.date} -[^5]: {emissions_tons.source} - retrieved on {emissions_tons.date} +## References -Copyright Jorge Leitão, released under [CC0](https://creativecommons.org/public-domain/cc0/) - No Rights Reserved. +[^1]: {emissions_tons.source}, in {number_of_legs.claim} trips[^4] - retrieved on {emissions_tons.date} +[^2]: {dane_years.source} - retrieved on {dane_years.date} +[^3]: {number_of_private_jets.source} on {number_of_private_jets.date} +[^4]: {number_of_legs.source} - retrieved on {number_of_legs.date} diff --git a/examples/dk_jets.rs b/examples/dk_jets.rs index 52c07ee..29c976b 100644 --- a/examples/dk_jets.rs +++ b/examples/dk_jets.rs @@ -1,11 +1,12 @@ -use std::{collections::HashMap, error::Error, sync::Arc}; +use std::{collections::HashMap, error::Error}; use clap::Parser; use futures::{StreamExt, TryStreamExt}; +use num_format::{Locale, ToFormattedString}; use simple_logger::SimpleLogger; -use flights::{emissions, load_aircraft_types, load_aircrafts, Class, Fact, Position}; -use time::macros::date; +use flights::{emissions, load_aircraft_types, load_aircrafts, Aircraft, Class, Fact, Leg}; +use time::{macros::date, Date}; fn render(context: &Context) -> Result<(), Box> { let path = "all_dk_jets.md"; @@ -27,11 +28,12 @@ fn render(context: &Context) -> Result<(), Box> { pub struct Context { pub from_date: String, pub to_date: String, - pub number_of_legs: Fact, - pub emissions_tons: Fact, + pub number_of_private_jets: Fact, + pub number_of_legs: Fact, + pub emissions_tons: Fact, pub dane_years: Fact, - pub number_of_legs_less_300km: usize, - pub number_of_legs_more_300km: usize, + pub number_of_legs_less_300km: String, + pub number_of_legs_more_300km: String, pub ratio_commercial_300km: String, } @@ -51,6 +53,35 @@ struct Cli { backend: Backend, } +async fn legs( + from: Date, + to: Date, + aircraft: &Aircraft, + client: Option<&flights::fs_azure::ContainerClient>, +) -> Result, Box> { + let dates = flights::DateIter { + from, + to, + increment: time::Duration::days(1), + }; + + let tasks = dates.map(|date| async move { + Result::<_, Box>::Ok( + flights::positions(&aircraft.icao_number, date, 1000.0, client) + .await? + .collect::>(), + ) + }); + + let positions = futures::stream::iter(tasks) + // limit concurrent tasks + .buffered(50) + .try_collect::>() + .await?; + + Ok(flights::real_legs(positions.into_iter().flatten())) +} + #[tokio::main] async fn main() -> Result<(), Box> { SimpleLogger::new() @@ -78,7 +109,7 @@ async fn main() -> Result<(), Box> { let aircrafts = load_aircrafts(client.as_ref()).await?; let types = load_aircraft_types()?; - let dk_private_jets = aircrafts + let private_jets = aircrafts .into_iter() // is private jet .filter(|(_, a)| types.contains_key(&a.model)) @@ -86,62 +117,42 @@ async fn main() -> Result<(), Box> { .filter(|(a, _)| a.starts_with("OY-")) .collect::>(); + let number_of_private_jets = Fact { + claim: private_jets.len().to_formatted_string(&Locale::en), + source: format!( + "All aircrafts in [adsbexchange.com](https://globe.adsbexchange.com) whose model is a private jet and tail number starts with \"OY-\"" + ), + date: "2023-11-06".to_string(), + }; + let to = time::OffsetDateTime::now_utc().date() - time::Duration::days(1); let from = date!(2021 - 01 - 01); let from_date = from.to_string(); let to_date = to.to_string(); - let dates = flights::DateIter { - from, - to, - increment: time::Duration::days(1), - }; - - let iter = dates - .map(|date| { - let client = client.as_ref(); - dk_private_jets - .iter() - .map(move |(_, a)| flights::positions(&a.icao_number, date.clone(), 1000.0, client)) - }) - .flatten(); - - let positions = futures::stream::iter(iter) - // limit to 5 concurrent tasks - .buffer_unordered(100) - .try_collect::>() - .await?; - let positions = positions.into_iter().flatten().collect::>(); - - // group by aircraft - let mut positions = positions.into_iter().fold( - HashMap::, Vec>::default(), - |mut acc, v| { - acc.entry(v.icao().clone()) - .and_modify(|positions| positions.push(v.clone())) - .or_insert_with(|| vec![v]); - acc - }, - ); - // sort positions by datetime - positions.iter_mut().for_each(|(_, positions)| { - positions.sort_unstable_by_key(|x| x.datetime()); + let client = client.as_ref(); + let legs = private_jets.iter().map(|(_, aircraft)| async { + legs(from, to, aircraft, client) + .await + .map(|legs| (aircraft.icao_number.clone(), legs)) }); - // compute legs - let legs = positions - .into_iter() - .map(|(icao, positions)| (icao, flights::real_legs(positions.into_iter()))) - .collect::>(); + let legs = futures::future::join_all(legs).await; + let legs = legs.into_iter().collect::, _>>()?; let number_of_legs = Fact { - claim: legs.iter().map(|(_, legs)| legs.len()).sum::(), - source: format!("[adsbexchange.com](https://globe.adsbexchange.com) between {from_date} and {to_date} and all aircraft whose tail number starts with \"OY-\" and model is a private jet"), - date: to.to_string() + claim: legs + .iter() + .map(|(_, legs)| legs.len()) + .sum::() + .to_formatted_string(&Locale::en), + source: format!( + "[adsbexchange.com](https://globe.adsbexchange.com) between {from_date} and {to_date}" + ), + date: to.to_string(), }; - let commercial_to_private_ratio = 10.0; let commercial_emissions_tons = legs .iter() .map(|(_, legs)| { @@ -150,8 +161,10 @@ async fn main() -> Result<(), Box> { .sum::() }) .sum::(); + let commercial_to_private_ratio = 10.0; + let emissions_tons_value = commercial_emissions_tons * commercial_to_private_ratio; let emissions_tons = Fact { - claim: (commercial_emissions_tons * commercial_to_private_ratio) as usize, + claim: (emissions_tons_value as usize).to_formatted_string(&Locale::en), source: format!("Commercial flights would have emitted {commercial_emissions_tons:.1} tons of CO2e (based on [myclimate.org](https://www.myclimate.org/en/information/about-myclimate/downloads/flight-emission-calculator/) - retrieved on 2023-10-19). Private jets emit 5-14x times. 10x was used based on [transportenvironment.org](https://www.transportenvironment.org/discover/private-jets-can-the-super-rich-supercharge-zero-emission-aviation/)"), date: "2023-10-05, from 2021-05-27".to_string(), }; @@ -171,12 +184,9 @@ async fn main() -> Result<(), Box> { date: "2023-10-08".to_string(), }; - let dane_years = format!( - "{:.0}", - emissions_tons.claim as f32 / dane_emissions_tons.claim as f32 - ); + let dane_years = (emissions_tons_value / dane_emissions_tons.claim) as usize; let dane_years = Fact { - claim: dane_years, + claim: dane_years.to_formatted_string(&Locale::en), source: "https://ourworldindata.org/co2/country/denmark Denmark emits 5.1 t CO2/person/year in 2019.".to_string(), date: "2023-10-08".to_string(), }; @@ -184,11 +194,12 @@ async fn main() -> Result<(), Box> { let context = Context { from_date, to_date, + number_of_private_jets, number_of_legs, emissions_tons, dane_years, - number_of_legs_less_300km: short_legs, - number_of_legs_more_300km: long_legs, + number_of_legs_less_300km: short_legs.to_formatted_string(&Locale::en), + number_of_legs_more_300km: long_legs.to_formatted_string(&Locale::en), ratio_commercial_300km: format!("{:.0}", commercial_to_private_ratio), }; diff --git a/src/lib.rs b/src/lib.rs index 1da58f7..ed87b2c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -94,6 +94,7 @@ fn distance(from: (f64, f64), to: (f64, f64)) -> f64 { } /// An iterator between two [`time::Date`]s in increments +#[derive(Clone, Copy)] pub struct DateIter { pub from: time::Date, pub to: time::Date, diff --git a/src/types.csv b/src/types.csv index 1cfd6d4..5c2f4df 100644 --- a/src/types.csv +++ b/src/types.csv @@ -24,7 +24,6 @@ FA8X Dassault Falcon 8X https://www.dassaultfalcon.com/aircraft/overview-of-the- F900 Dassault Falcon 900 https://www.dassaultfalcon.com/aircraft/overview-of-the-fleet/ 2023-10-03 EA40 Eclipse 400 https://en.wikipedia.org/wiki/Eclipse_400 2023-10-03 EA50 Eclipse 500 https://en.wikipedia.org/wiki/Eclipse_500 2023-10-03 -E190 Embraer Lineage 1000 https://executive.embraer.com/global/en/lineage-1000e 2023-10-03 E50P Embraer Phenom 100 https://executive.embraer.com/global/en/phenom-100ev 2023-10-03 E55P Embraer Phenom 300 https://executive.embraer.com/global/en/phenom-300e 2023-10-03 GL5T Global 5500 https://businessaircraft.bombardier.com/en/aircraft/global-5500 2023-10-03