use log::{debug, trace};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use super::{LegPerformance, Performance};
use crate::aircraft::Aircraft;
use crate::measurements::Duration;
use crate::route::Route;
use crate::{Fuel, VerticalDistance};
#[repr(C)]
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Reserve {
Manual(Duration),
}
impl Reserve {
pub fn fuel(self, perf: &Performance, cruise: &VerticalDistance) -> Fuel {
match self {
Self::Manual(duration) => perf.ff(cruise) * duration,
}
}
}
impl Default for Reserve {
fn default() -> Self {
Self::Manual(Duration::default())
}
}
#[repr(C)]
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum FuelPolicy {
MinimumFuel,
MaximumFuel,
ManualFuel(Fuel),
FuelAtLanding(Fuel),
ExtraFuel(Fuel),
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct FuelPlanning {
taxi: Fuel,
trip: Fuel,
alternate: Option<Fuel>,
reserve: Fuel,
total: Fuel,
min: Fuel,
extra: Option<Fuel>,
after_landing: Fuel,
}
impl FuelPlanning {
pub fn new(
aircraft: &Aircraft,
policy: &FuelPolicy,
taxi: Fuel,
route: &Route,
reserve: &Reserve,
perf: &LegPerformance,
) -> Option<Self> {
let trip = *route.totals(Some(perf))?.fuel()?.total();
let last_level = route.legs().last().and_then(|l| l.level()).cloned()?;
let alternate = route
.alternate()
.and_then(|alternate| alternate.fuel(perf))
.map(|lf| *lf.total());
let reserve = reserve.fuel(perf.cruise()?, &last_level);
trace!(
"fuel planning: trip={:.1}, alternate={:.1?}, reserve={:.1?}",
trip,
alternate,
reserve
);
let min = {
let mut min = taxi + trip + reserve;
if let Some(alternate) = alternate {
min = min + alternate;
}
min
};
let extra = {
match policy {
FuelPolicy::MinimumFuel => None,
FuelPolicy::MaximumFuel => {
aircraft.usable_fuel().map(|usable_fuel| usable_fuel - min)
}
FuelPolicy::ManualFuel(fuel) => Some(*fuel - min),
FuelPolicy::FuelAtLanding(fuel) => Some(*fuel), FuelPolicy::ExtraFuel(fuel) => Some(*fuel),
}
};
let total = {
match extra {
Some(extra) => min + extra,
None => min,
}
};
let after_landing = total - taxi - trip;
debug!(
"fuel planning: min={:.1}, total={:.1}, extra={:.1?}, after_landing={:.1}",
min, total, extra, after_landing
);
Some(Self {
taxi,
trip,
alternate,
reserve,
total,
min,
extra,
after_landing,
})
}
pub fn taxi(&self) -> &Fuel {
&self.taxi
}
pub fn trip(&self) -> &Fuel {
&self.trip
}
pub fn alternate(&self) -> Option<&Fuel> {
self.alternate.as_ref()
}
pub fn reserve(&self) -> &Fuel {
&self.reserve
}
pub fn total(&self) -> &Fuel {
&self.total
}
pub fn min(&self) -> &Fuel {
&self.min
}
pub fn extra(&self) -> Option<&Fuel> {
self.extra.as_ref()
}
pub fn on_ramp(&self) -> &Fuel {
&self.total
}
pub fn after_landing(&self) -> &Fuel {
&self.after_landing
}
}