Aircraft — Fleet Renewal & Future Aircraft ========================================== **Implementation status:** Fleet renewal **Equivalent** (equation-level parity benchmarked, DL-028); Future Aircraft **Simplified** — all five §26 review actions implemented (opt-in), proprietary reference tables substituted (coverage matrix rows *Fleet Renewal*, *Future Aircraft*) **Source:** ``src/engine/curves.ts:fleetRenewalFraction``, ``src/engine/curves.ts:insertionCurveAt``, ``src/engine/futureAircraft.ts`` (whole module) **Test evidence:** ``tests/fleet-renewal-parity.spec.ts``, ``tests/fleet-insertion.spec.ts``, ``tests/future-aircraft.spec.ts`` Fleet renewal (piecewise quadratic phase-out) --------------------------------------------- The fraction of the legacy fleet still in service at year :math:`t` follows a piecewise quadratic — flat, quadratic ramp-down over :math:`T_{ramp}`, linear steady state, mirrored quadratic to zero at :math:`t_{endProd} + T_{out}` (cf. CASCADE *Fleet Renewal*, eqs. 103–109): .. math:: f(t) = \begin{cases} 1 & t \le t_{start} \\ 1 + a\,(t - t_{start})^2 & t_{start} < t \le t_{start} + T_{ramp} \\ m\,t + b & \text{linear interior} \\ -a\,(t_{start} + T_{out} - t)^2 & t \ge t_{start} + T_{out} - T_{ramp} \\ 0 & t \ge t_{start} + T_{out} \end{cases} with .. math:: a = \frac{1}{2\,T_{ramp}\,(T_{ramp} - T_{out})}, \qquad m = \frac{1}{T_{ramp} - T_{out}}, \qquad b = 1 + a\,T_{ramp}^2 - m\,(t_{start} + T_{ramp}) and :math:`t_{start} = t_{endProd}` (defaults: end of production 2035, ramp 5 yr, phase-out 25 yr). A pre-start shortening rule re-anchors the curve when :math:`t_{endProd}` precedes the model start year: :math:`T'_{out} = T_{out} + (t_{endProd} - t_{start})` (DL-028). .. note:: **RST-internal finding F3.** CASCADE's published closed form for the intercept :math:`b` omits the "+1" and fails continuity with its own piecewise definition by exactly 1 at :math:`t = t_{endProd} + T_{ramp}`. HyFlux's continuity-derived :math:`b` (above) is used; the discrepancy is queued on the Boeing evidence-gap list (DL-028, claim register BC-14). The aircraft wedge in the aggregate engine is gated by this curve: the wedge scales with :math:`1 - f(t)`, i.e. only the share of the fleet that has actually turned over receives the new-technology improvement. Future Aircraft module ---------------------- ``futureAircraft.ts`` implements the route-level fleet-insertion model (cf. CASCADE *Future Aircraft*). The mechanisms, as implemented: **1. Distance correction.** Flown distance adds a fixed operational correction to the great-circle distance (eq. fa_distance_correction): .. math:: d = d^* + 51\ \mathrm{km} **2. Reference range-energy tables with 1D interpolation.** Per-flight tank-to-wake energy :math:`e^*_{ref}(d)` is linear-interpolated over flown distance between table knots (eq. fa_energy_consumption_1D_linear_interp), clamped to the end knots (no extrapolation): .. math:: e^*(d) = e_i + \frac{d - d_i}{d_{i+1} - d_i}\,(e_{i+1} - e_i) **3. Custom-aircraft energy rescaling.** A user efficiency delta :math:`\Delta_{cust}` rescales the reference energy (cf. CASCADE *Future Aircraft*, "Defining Energy Consumption of a Single Future Aircraft"): .. math:: e_{fut} = e_{ref}\,\frac{1 + \Delta_{cust}}{1 + \Delta_{ref}} with :math:`\Delta_{cust} \in [-0.30, +0.70]` enforced (scenario bounds; violations raise ``RangeError``). Note the bounds discrepancy: CASCADE's own bounds page (April 2026 snapshot) states −30 %/+60 % — the module keeps the wider driving-prompt bound and the divergence is recorded (DL-025, DL-029). **4. Five-phase insertion curve.** The market share of a future type grows 0 → quadratic ramp-up → linear steady state → quadratic ramp-down → 1 (cf. CASCADE *Future Aircraft*, addressable market share equations): .. math:: x(t) = \begin{cases} 0 & t \le t_{EIS} \\ a\,(t - t_{EIS})^2 & t_{EIS} < t \le t_{EIS} + T_{ramp} \\ r_{ss}\,t + b & t_{EIS} + T_{ramp} < t \le t_{EIS} + 1/r_{ss} \\ 1 - a\,(t_{EIS} + t_{sat} - t)^2 & \text{else, until } t_{EIS} + t_{sat} \\ 1 & t \ge t_{EIS} + t_{sat} \end{cases} .. math:: a = \frac{r_{ss}}{2\,T_{ramp}}, \qquad b = -r_{ss}\left(t_{EIS} + \frac{T_{ramp}}{2}\right), \qquad t_{sat} = T_{ramp} + \frac{1}{r_{ss}} with the EIS-year decrement :math:`t_{EIS} = t^*_{EIS} - 1` and the constraint :math:`r_{ss} \le 1/T_{ramp}`. **Deviation:** CASCADE truncates violating rates to :math:`1/T_{ramp}`; HyFlux's module contract is fail-fast — invalid specs are rejected with ``RangeError`` (the truncating variant is also exported as ``truncateInsertionRate`` / ``insertionCurveAt`` for the aggregate engine). The proportional insertion rate from a global production rate (eq. proportional-insertion-rate) is provided: .. math:: r_{ss} = \frac{R_{ss}}{n_{in} + (1 + T_{ramp}/2)\,\Delta n_{in}} **5. Addressable market cap.** Shares per route satisfy :math:`\sum_{ac} x(ac, rt, t) \le 1`. **Deviation:** CASCADE freezes each type's share at the year the sum first reaches 100 % (:math:`t_{marketSat}`); HyFlux applies pro-rata normalisation :math:`x^*_i = x_i / \sum_j x_j` when the sum exceeds 1 (documented module decision). **6. Flight conservation.** Assignment conserves flight count exactly per route: .. math:: n_{fut,i} = x^*_i\,n_{in}, \qquad n_{exist} = \left(1 - \sum_i x^*_i\right) n_{in}, \qquad n_{fut} + n_{exist} = n_{in} CASCADE's payload-capacity flight-count normalisation (capacity-ratio rescaling) is **not** implemented — the synthetic dataset assumes same-class replacement. **7. Eligibility.** A type is assignable iff its size class is eligible for the route **and** route distance ≤ usable range, with usable range = 0.8 × design range — a HyFlux reserve-margin assumption the RST does not specify (``USABLE_RANGE_FRACTION``, editable). **8. Battery-electric adjustment.** Electricity drawn per unit onboard energy (eq. fa_battery_emissions): .. math:: E^*_{elec} = E_{elec}\,\frac{1}{\eta_{batt}}\left(1 + \frac{\varepsilon_{batt}}{T_{batt}}\right) = E_{elec} \times \frac{1}{0.97}\left(1 + \frac{60}{3000}\right) \approx 1.0515 \times E_{elec} (one recharge cycle per flight cycle; constants per the CASCADE data table). In the aggregate engine the electric wedge applies this to the regional class only (opt-in via ``el_ceiling`` under ``ac_eis_gating``; electric range bounded to regional operations), with emissions .. math:: g_{elec} = E_{displaced}\,(1 - r_{energy}\, m_{batt}\, CI_{elec}(y)/CI_{JetA}) where :math:`r_{energy}` (``el_energy_ratio``, default 0.45) is onboard MJ electric per MJ jet and :math:`m_{batt}` the multiplier above (DL-029). Reference-table fidelity limitation ----------------------------------- CASCADE's reference range-energy tables are generated by Boeing's proprietary aircraft sizing and mission tools and are **not public**; exact value parity for the interpolation equation is therefore not achievable and is never claimed (Phase-0 §12, DL-025). HyFlux substitutes transparent synthetic tables built from a documented per-class energy model: .. math:: e^*(d) = N_{cap}\,(f_{fix} + f_{cruise}\, d) \times k_{carrier} calibrated to order-of-magnitude public figures (ATR-72-class ≈ 0.85 MJ/seat-km cruise; A320neo-class ≈ 0.55; widebody-class ≈ 0.70; freighter ≈ 4.5 MJ/t-km; Jet-A LHV 43.1 MJ/kg), with carrier factors H₂ ×0.95, CH₄ ×1.00, electricity ×0.30 vs Jet-A, and illustrative reference deltas (−0.10/−0.15/−0.12/−0.35). All tables are **injectable** — every consumer accepts a ``tables`` override so licensed data can drop in without touching the model (``routes.ts:DEFAULT_REFERENCE_TABLES``). Aggregate-engine insertion machinery ------------------------------------ The same curve family drives the opt-in EIS-gated aircraft wedge in ``cascade.ts`` (DL-026/028/029): per size class :math:`c \in \{$regional, single-aisle, widebody, freighter$\}`, .. math:: \text{adoption}(y) = \sum_c w_c \cdot \text{ceiling}_c \cdot \text{adoption}_c(y;\, eis_c - 1) with editable fuel-burn share weights (defaults 5/43/42/10 %, literature-approximate; CASCADE weights by class traffic, which HyFlux does not resolve) and either the insertion curve (when ``ac_prod_rate`` is set, :math:`r_{ss} = 12 \times \text{rate} / \text{addressable fleet}`, default fleet 25,000) or a legacy S-curve over :math:`[eis-1, 2050]`. Future Aircraft lever UI (AircraftModal) ---------------------------------------- **Implementation status:** Wired (opt-in; engine-level tests, no DOM) **Source:** ``src/components/modals/AircraftModal.tsx`` (``FutureAircraftSection``, 🛫 Future Aircraft tab) **Test evidence:** ``tests/future-aircraft-ui.spec.ts`` (15 tests) The EIS-gated insertion machinery is exposed behind a master toggle (``ac_eis_gating``, default off — the legacy single-curve adoption stays active, every setting below inert, and results are bit-identical to legacy). With gating on, the tab offers: * **Per-size-class table** (regional / single-aisle / widebody / freighter): EIS year, 2050 ceiling slider (0–100 %) and fuel-burn share input per class. The engine defaults mirror the module (:math:`EIS_c` falls back to the base ``eis``, ceilings to 100 %, shares 5/43/42/10). Shares need not sum to 100 — the engine normalises pro-rata so :math:`\sum w = 1`, and the UI warns when they do not. UI input bounds clamp EIS to 2025–2050 while the engine accepts any year and starts insertion at EIS−1 (RST rule); ceilings outside [0, 100] % are engine-clamped. Both clamps are surfaced as inline warnings, as is the all-ceilings-zero collapse of the wedge. * **Production-rate mode** — ``ac_prod_rate`` (aircraft/month, steady state). ``0``/empty clears the field and falls back to per-class S-curve adoption; a positive rate activates the quad-linear-quad insertion curve with :math:`r_{ss} = 12 \times \text{rate} / \text{addressable fleet}` (``ac_addressable_fleet``, default 25,000) and :math:`t_{sat} = EIS{-}1 + T_{ramp} + 1/r_{ss}` (``ac_prod_ramp_years``, 1–15). The panel previews :math:`r_{ss}` truncated at :math:`1/T_{ramp}` per the RST cap rule. * **Live verification** — a readout of the 2050 aircraft wedge (Mt CO₂e) recomputed from ``computeLCA`` on every patch; it reads the 2050 slice explicitly so the readout stays correct when ``end_year`` extends the horizon (:doc:`trafficGrowth`). UI-wiring tests pin: explicit-off ≡ flag-absent bit-identity; monotonic wedge response to the per-class EIS stagger (at 2040 in S-curve mode — every class saturates by 2050 under hold-not-stretch — and at 2050 in production-rate mode, where the insertion curve has not saturated); production-rate ≠ S-curve fallback; ceiling-0 classes contribute nothing; and URL-schema round-trip of every ``ac_*`` field the tab writes. .. note:: **Pulse curve remains engine-only.** The shared ``CurveEditor`` param model (shape, entry year/value, end year/value, slope, inflection year, custom points) has no field mapping onto the pulse curve's two-sigmoid parameter set (:math:`t_0, t_{peak}, t_f, A_{peak}, A_f, a` — :doc:`extensions`). Rather than offer an approximate mapping, UI exposure is deferred; the engine implementation (``curves.ts:pulseAt``) is fully tested. Known deviations / limitations ------------------------------ * Pro-rata market cap instead of CASCADE's :math:`t_{marketSat}` freeze. * Fail-fast spec validation instead of rate truncation (module level). * Payload-capacity flight normalisation (the fleetRenewal.rst substitution + freighter/passenger capacity corrections and the seven-step RCTK conservation proof) is implemented standalone in ``src/engine/fleet-renewal-route.ts`` (DL-136, ``tests/suite-k-fleet-renewal-route.spec.ts``) but runs at shadow stage only — the production engine still renews at aggregate level with same-class replacement assumed. * Usable-range fraction 0.8 is a HyFlux assumption, not CASCADE data. * Existing-aircraft energy uses the route's typical-class Jet-A table as a stand-in for CASCADE's SET models. * Electric wedge restricted to the regional class; ≤1.3 %-of-gross overlap with the generic aircraft wedge is a documented approximation (DL-029). * Synthetic reference tables: no exact value parity possible or claimed.