Skip to content

Commit

Permalink
Improved emissions calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgecarleitao committed Jan 28, 2024
1 parent 5bbee35 commit c4264a5
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 31 deletions.
55 changes: 28 additions & 27 deletions examples/single_day.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ async fn flight_date(
aircrafts: &Aircrafts,
client: Option<&fs_azure::ContainerClient>,
) -> Result<Vec<Event>, Box<dyn Error>> {
let consumptions = load_aircraft_consumption()?;
let airports = airports_cached().await?;
let aircraft_owner = aircraft_owners
.get(tail_number)
Expand All @@ -94,43 +95,43 @@ async fn flight_date(

let aircraft = aircrafts
.get(tail_number)
.ok_or_else(|| Into::<Box<dyn Error>>::into("Aircraft ICAO number not found"))?;
.ok_or_else(|| Into::<Box<dyn Error>>::into("Aircraft transponder number"))?;
let icao = &aircraft.icao_number;
log::info!("ICAO number: {}", icao);
log::info!("transponder number: {}", icao);

let consumption = consumptions
.get(&aircraft.model)
.ok_or_else(|| Into::<Box<dyn Error>>::into("Consumption not found"))?;
log::info!("Consumption: {} [gallon/h]", consumption.gph);

let positions = positions(icao, date, client).await?;
let legs = legs(positions);

log::info!("Number of legs: {}", legs.len());

Ok(legs.into_iter().filter_map(|leg| {
let is_leg = matches!(leg.from(), Position::Grounded{..}) & matches!(leg.to(), Position::Grounded{..});
if !is_leg {
log::info!("{:?} -> {:?} skipped", leg.from(), leg.to());
}
is_leg.then_some((leg.from().clone(), leg.to().clone()))
}).map(|(from, to)| {
let emissions = emissions(from.pos(), to.pos(), Class::First);
Ok(legs.into_iter().map(|leg| {
let commercial_emissions_kg = Fact {
claim: emissions(leg.from().pos(), leg.to().pos(), Class::First) as usize,
source: "https://www.myclimate.org/en/information/about-myclimate/downloads/flight-emission-calculator/".to_string(),
date: "2023-10-19".to_string()
};
let emissions_kg = Fact {
claim: leg_co2_kg(consumption.gph as f64, leg.duration()) as usize,
source: "See [methodology M-7](https://github.com/jorgecardleitao/private-jets/blob/main/methodology.md)".to_string(),
date: time::OffsetDateTime::now_utc().date().to_string(),
};

Event {
tail_number: tail_number.to_string(),
owner: owner.clone(),
date: date.to_string(),
from_airport: closest(from.pos(), &airports).name.clone(),
to_airport: closest(to.pos(), &airports).name.clone(),
two_way: false,
commercial_emissions_kg: Fact {
claim: emissions as usize,
source: "https://www.myclimate.org/en/information/about-myclimate/downloads/flight-emission-calculator/".to_string(),
date: "2023-10-19".to_string()
},
emissions_kg: Fact {
claim: (emissions * 10.0) as usize,
source: "Private jets emit 5-14x times. 10x was used here https://www.transportenvironment.org/discover/private-jets-can-the-super-rich-supercharge-zero-emission-aviation/".to_string(),
date: "2023-10-05, from 2021-05-27".to_string(),
},
source: format!("https://globe.adsbexchange.com/?icao={icao}&showTrace={date}"),
source_date: date.to_string(),
owner: owner.clone(),
date: date.to_string(),
from_airport: closest(leg.from().pos(), &airports).name.clone(),
to_airport: closest(leg.to().pos(), &airports).name.clone(),
two_way: false,
commercial_emissions_kg,
emissions_kg,
source: format!("https://globe.adsbexchange.com/?icao={icao}&showTrace={date}"),
source_date: date.to_string(),
}
}).collect())
}
Expand Down
35 changes: 34 additions & 1 deletion methodology.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,40 @@ flight in first class.

Details are available in the source code, [src/emissions.rs](./src/emissions.rs).

### M-6: Identify aircraft owner in Denmark
### M-6: Consumption of private jet

This was performed by a human, and consisted in going through different aircraft
manufacturers' websites and identifying the aircrafts that were advertised as used
for private flying.

This was performed by a human, and consisted:
* access websites of companies that sell private jets
* extract the consumption in gallons per hour (GPH) of each private jet model
* store it in a table with the jet's model, GPH, source and date of extraction, at [`./src/consumption.csv`](./src/consumption.csv).

### M-7: Emissions of a private jet over a leg

This was performed automatically by the program and consisted in performing the
following calculation:

```
leg emissions [kg CO2] =
consumption [gallon/h]
x liters / gallons [L/gallon]
x liters to kg of jet fuel [L/kg]
x emissions per kg [kg CO2 / kg jet fuel]
x leg time [h]
```

Where:

* `consumption [gallon/h]` is obtained via the methodology `M-6` in this document.
* `liters / gallons [L/gallon] = 3.78541 [L/gallon]`, as specified in [NIST's guide to SI](https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication811e2008.pdf)
* `liters to kg of jet fuel A-1 [kg/L] = 0.8 [kg/L]`, as [recommended by ICAO](https://data.icao.int/newDataPlus/content/docs/glossary.pdf)
* `emissions per kg = 3.16 [kg CO2 / kg jet fuel]`, as used on [ICAO Carbon Emissions Calculator Methodology, v12 from Sep. 2023](https://applications.icao.int/icec/Methodology%20ICAO%20Carbon%20Calculator_v12-2023.pdf)
* `leg time [h]` is obtained by computing the time difference between the last and first position of the leg, identified via the methodology `M-4` in this document.

### M-8: Identify aircraft owner in Denmark

This was performed by a human, and consisted in extracting the ownership of the active
tail number from website https://www.danishaircraft.dk.
Expand Down
56 changes: 56 additions & 0 deletions src/consumption.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
icao gph source date
CL30 295 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Bombardier-CL-300-6 2024-01-26
CL35 297 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Bombardier-CL-350-185 2024-01-26
CL60 329 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Bombardier-CL-650-193 2024-01-26
GLEX 512 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Bombardier-Global-6000-52 2024-01-26
GL7T 528 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Bombardier-Global-7500-203 2024-01-26
LJ31 202 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Bombardier-Learjet-31A-3 2024-01-26
LJ40 224 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Bombardier-Learjet-40XR-55 2024-01-26
LJ45 205 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Bombardier-Learjet-45-56 2024-01-26
LJ60 239 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Bombardier-Learjet-60-59 2024-01-26
LJ75 199 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Bombardier-Learjet-75-181 2024-01-26
C25A 141 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Cessna/Textron-CJ2-74 2024-01-26
C25B 149 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Cessna/Textron-CJ3-76 2024-01-26
C25C 209 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Cessna/Textron-CJ4-77 2024-01-26
C68A 315 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Cessna/Textron-Latitude-192 2024-01-26
C700 316 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Cessna/Textron-Longitude-199 2024-01-26
C25M 134 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Cessna/Textron-Citation-M2-182 2024-01-26
C510 90 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Cessna/Textron-Mustang-81 2024-01-26
C680 281 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Cessna/Textron-Sovereign-82 2024-01-26
C56X 386 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Cessna/Textron-Citation-X-86 2024-01-26
C550 116 https://www.flyingmag.com/gear-mods-refurbish-citation-iis-sierra-style/ (775 pounds/h) 2024-01-26
FA10 274 https://jetadvisors.com/jet/falcon-10/ 2024-01-26
FA50 356 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Dassault-Falcon-50-96 2024-01-26
F2TH 287 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Dassault-Falcon-2000-92 2024-01-26
FA6X 444 https://jetadvisors.com/jet/falcon-6x/ 2024-01-26
FA7X 385 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Dassault-Falcon-7X-98 2024-01-26
FA8X 377 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Dassault-Falcon-8X-194 2024-01-26
F900 304 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Dassault-Falcon-900LX-103 2024-01-26
EA40 59 https://www.blade.com/eclipse400 2024-01-26
EA50 76 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Eclipse-Aerospace-Eclipse-500-220 2024-01-26
E50P 113 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Embraer-Phenom-100-106 2024-01-26
E55P 179 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Embraer-Phenom-300-107 2024-01-26
E545 285 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Embraer-Legacy-450-196 2024-01-26
E550 287 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Embraer-Legacy-500-190 2024-01-26
E35L 381 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Embraer-Legacy-650-162 2024-01-26
E545 287 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Embraer-Praetor-500-200 2024-01-26
E550 298 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Embraer-Praetor-600-201 2024-01-26
GL5T 472 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Bombardier-Global-5500-206 2024-01-26
GLEX 509 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Bombardier-Global-6500-204 2024-01-26
G150 288 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Gulfstream-G150-126 2024-01-26
GALX 278 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Gulfstream-G200-127 2024-01-26
G280 286 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Gulfstream-G280-30 2024-01-26
GLF4 517 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Gulfstream-G350-129 2024-01-26
GA4C 540 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Gulfstream-G400-(Heritage)-130 2024-01-26
GA5C 455 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Gulfstream-G500-211 2024-01-26
GA6C 500 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Gulfstream-G600-202 2024-01-26
GLF6 500 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Gulfstream-G650-29 2024-01-26
GA7C 509 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Gulfstream-G700-208 2024-01-26
GA8C 462 https://jetadvisors.com/jet/gulfstream-g800-gviii/ 2024-01-26
BE40 222 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Hawker/Textron-400XP-140 2024-01-26
HA4T 321 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Hawker/Textron-4000-138 2024-01-26
BE40W 152 https://planephd.com/wizard/details/967/HAWKER-400XPR-specifications-performance-operating-cost-valuation 2024-01-26
H25B 265 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Hawker/Textron-900XP-146 2024-01-26
HDJT 120 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Honda-Aircraft-Company-Honda-Jet-216 2024-01-26
PC12 76 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Pilatus-PC-12-147 2024-01-26
PC24 191 https://www.guardianjet.com/jet-aircraft-online-tools/aircraft-brochure.cfm?m=Pilatus-PC-24-215 2024-01-26
27 changes: 27 additions & 0 deletions src/consumption.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use std::{collections::HashMap, error::Error};

use serde::{Deserialize, Serialize};

pub type AircraftTypeConsumptions = HashMap<String, AircraftTypeConsumption>;

/// The in-memory representation of the consumption of an aircraft type
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AircraftTypeConsumption {
/// the type (e.g. `CL30`)
pub icao: String,
/// the consumption in GPH
pub gph: usize,
/// the source of the consumption
pub source: String,
/// the date of when the source was retrieved
pub date: String,
}

/// Loads consumption from `src/consumption.csv` into memory has a map `icao: AircraftTypeConsumption`.
/// # Error
/// Errors if the file cannot be read
pub fn load_aircraft_consumption() -> Result<AircraftTypeConsumptions, Box<dyn Error>> {
super::csv::load("src/consumption.csv", |a: AircraftTypeConsumption| {
(a.icao.clone(), a)
})
}
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod aircraft_db;
mod aircraft_owners;
mod aircraft_types;
mod airports;
mod consumption;
mod csv;
mod emissions;
pub(crate) mod fs;
Expand All @@ -10,6 +11,7 @@ mod icao_to_trace;
mod legs;
mod model;
mod owners;
mod private_emissions;
mod trace_month;

use std::sync::Arc;
Expand All @@ -18,12 +20,14 @@ pub use aircraft_db::*;
pub use aircraft_owners::*;
pub use aircraft_types::*;
pub use airports::*;
pub use consumption::*;
pub use emissions::*;
pub use fs::BlobStorageProvider;
pub use icao_to_trace::*;
pub use legs::*;
pub use model::*;
pub use owners::*;
pub use private_emissions::leg_co2_kg;

/// A position of an aircraft
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
Expand Down
11 changes: 11 additions & 0 deletions src/private_emissions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
static LITER_PER_GALON: f64 = 3.78541;
static KG_PER_LITER: f64 = 0.8;
static EMISSIONS_PER_KG: f64 = 3.16;

/// Returns the total CO2 emissions in kg of an aircraft with a given
/// consumption (in GPH) of Jet-A fuel flying for a given amount of time,
/// as specified in [methodology `M-7`](../methodology.md).
pub fn leg_co2_kg(consumption: f64, duration: time::Duration) -> f64 {
let hours = duration.as_seconds_f64() / 60.0 / 60.0;
consumption * hours * LITER_PER_GALON * KG_PER_LITER * EMISSIONS_PER_KG
}
17 changes: 14 additions & 3 deletions tests/it/main.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use std::error::Error;

use flights::Leg;
use time::{macros::date, Date};
use time::{
macros::{date, datetime},
Date,
};

/// Verifies that we compute the correct number of legs.
/// The expected 2 was confirmed by manual inspection of
/// Verifies that we compute the same number of legs and their duration
/// as in source
/// https://globe.adsbexchange.com/?icao=45d2ed&lat=54.128&lon=9.185&zoom=5.0&showTrace=2023-10-13
#[tokio::test]
async fn acceptance_legs() -> Result<(), Box<dyn Error>> {
Expand All @@ -13,6 +16,14 @@ async fn acceptance_legs() -> Result<(), Box<dyn Error>> {

assert_eq!(legs.len(), 2);

let expected = datetime!(2023 - 10 - 13 15:24:49) - datetime!(2023 - 10 - 13 13:21:59);
let diff = (legs[0].duration().as_seconds_f32() - expected.as_seconds_f32()).abs();
assert!(diff < 300.0);

let expected = datetime!(2023 - 10 - 13 17:34:02) - datetime!(2023 - 10 - 13 15:58:33);
let diff = (legs[1].duration().as_seconds_f32() - expected.as_seconds_f32()).abs();
assert!(diff < 300.0);

Ok(())
}

Expand Down

0 comments on commit c4264a5

Please sign in to comment.