Skip to content

aeromaps.models.impacts.emissions.co2_emissions

co2_emissions

This module contains models for calculating CO2 emissions and related factors.

KayaFactors

KayaFactors(name='kaya_factors', *args, **kwargs)

Bases: AeroMAPSModel

Class to compute Kaya factors for CO2 emissions calculation.

Parameters:

Name Type Description Default
name str

Name of the model instance ('kaya_factors' by default).

'kaya_factors'
Source code in aeromaps/models/impacts/emissions/co2_emissions.py
233
234
def __init__(self, name="kaya_factors", *args, **kwargs):
    super().__init__(name=name, *args, **kwargs)

compute

compute(
    ask,
    rtk,
    energy_consumption_passenger_dropin_fuel_without_operations,
    energy_consumption_passenger_hydrogen_without_operations,
    energy_consumption_passenger_electric_without_operations,
    energy_consumption_passenger_dropin_fuel,
    energy_consumption_passenger_hydrogen,
    energy_consumption_passenger_electric,
    energy_consumption_freight_dropin_fuel_without_operations,
    energy_consumption_freight_hydrogen_without_operations,
    energy_consumption_freight_electric_without_operations,
    energy_consumption_freight_dropin_fuel,
    energy_consumption_freight_hydrogen,
    energy_consumption_freight_electric,
    energy_consumption_dropin_fuel,
    energy_consumption_hydrogen,
    energy_consumption_electric,
    energy_consumption,
    dropin_fuel_mean_co2_emission_factor,
    hydrogen_mean_co2_emission_factor,
    electric_mean_co2_emission_factor,
)

Execute the computation of Kaya factors for CO2 emissions calculation.

Parameters:

Name Type Description Default
ask Series

Available seat kilometers (ASK) [ASK].

required
rtk Series

Revenue ton kilometers (RTK) [RTK].

required
energy_consumption_passenger_dropin_fuel_without_operations Series

Energy consumption for passenger transport using drop-in fuels without operational improvements [MJ].

required
energy_consumption_passenger_hydrogen_without_operations Series

Energy consumption for passenger transport using hydrogen without operational improvements [MJ].

required
energy_consumption_passenger_electric_without_operations Series

Energy consumption for passenger transport using electricity without operational improvements [MJ].

required
energy_consumption_passenger_dropin_fuel Series

Energy consumption for passenger transport using drop-in fuels [MJ].

required
energy_consumption_passenger_hydrogen Series

Energy consumption for passenger transport using hydrogen [MJ].

required
energy_consumption_passenger_electric Series

Energy consumption for passenger transport using electricity [MJ].

required
energy_consumption_freight_dropin_fuel_without_operations Series

Energy consumption for freight transport using drop-in fuels without operational improvements [MJ].

required
energy_consumption_freight_hydrogen_without_operations Series

Energy consumption for freight transport using hydrogen without operational improvements [MJ].

required
energy_consumption_freight_electric_without_operations Series

Energy consumption for freight transport using electricity without operational improvements [MJ].

required
energy_consumption_freight_dropin_fuel Series

Energy consumption for freight transport using drop-in fuels [MJ].

required
energy_consumption_freight_hydrogen Series

Energy consumption for freight transport using hydrogen [MJ].

required
energy_consumption_freight_electric Series

Energy consumption for freight transport using electricity [MJ].

required
energy_consumption_dropin_fuel Series

Total energy consumption using drop-in fuels [MJ].

required
energy_consumption_hydrogen Series

Total energy consumption using hydrogen [MJ].

required
energy_consumption_electric Series

Total energy consumption using electricity [MJ].

required
energy_consumption Series

Total energy consumption [MJ].

required
dropin_fuel_mean_co2_emission_factor Series

Mean CO2 emission factor for drop-in fuels [gCO2/MJ].

required
hydrogen_mean_co2_emission_factor Series

Mean CO2 emission factor for hydrogen [gCO2/MJ].

required
electric_mean_co2_emission_factor Series

Mean CO2 emission factor for electricity [gCO2/MJ].

required

Returns:

Type Description
energy_per_ask_mean_without_operations

Energy consumption per ASK without operational improvements [MJ/ASK].

energy_per_ask_mean

Energy consumption per ASK [MJ/ASK].

energy_per_rtk_mean_without_operations

Energy consumption per RTK without operational improvements [MJ/RTK].

energy_per_rtk_mean

Energy consumption per RTK [MJ/RTK].

co2_per_energy_mean

CO2 emissions per unit of energy consumed [gCO2/MJ].

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
def compute(
    self,
    ask: pd.Series,
    rtk: pd.Series,
    energy_consumption_passenger_dropin_fuel_without_operations: pd.Series,
    energy_consumption_passenger_hydrogen_without_operations: pd.Series,
    energy_consumption_passenger_electric_without_operations: pd.Series,
    energy_consumption_passenger_dropin_fuel: pd.Series,
    energy_consumption_passenger_hydrogen: pd.Series,
    energy_consumption_passenger_electric: pd.Series,
    energy_consumption_freight_dropin_fuel_without_operations: pd.Series,
    energy_consumption_freight_hydrogen_without_operations: pd.Series,
    energy_consumption_freight_electric_without_operations: pd.Series,
    energy_consumption_freight_dropin_fuel: pd.Series,
    energy_consumption_freight_hydrogen: pd.Series,
    energy_consumption_freight_electric: pd.Series,
    energy_consumption_dropin_fuel: pd.Series,
    energy_consumption_hydrogen: pd.Series,
    energy_consumption_electric: pd.Series,
    energy_consumption: pd.Series,
    dropin_fuel_mean_co2_emission_factor: pd.Series,
    hydrogen_mean_co2_emission_factor: pd.Series,
    electric_mean_co2_emission_factor: pd.Series,
) -> Tuple[pd.Series, pd.Series, pd.Series, pd.Series, pd.Series]:
    """
    Execute the computation of Kaya factors for CO2 emissions calculation.

    Parameters
    ----------
    ask
        Available seat kilometers (ASK) [ASK].
    rtk
        Revenue ton kilometers (RTK) [RTK].
    energy_consumption_passenger_dropin_fuel_without_operations
        Energy consumption for passenger transport using drop-in fuels without operational improvements [MJ].
    energy_consumption_passenger_hydrogen_without_operations
        Energy consumption for passenger transport using hydrogen without operational improvements [MJ].
    energy_consumption_passenger_electric_without_operations
        Energy consumption for passenger transport using electricity without operational improvements [MJ].
    energy_consumption_passenger_dropin_fuel
        Energy consumption for passenger transport using drop-in fuels [MJ].
    energy_consumption_passenger_hydrogen
        Energy consumption for passenger transport using hydrogen [MJ].
    energy_consumption_passenger_electric
        Energy consumption for passenger transport using electricity [MJ].
    energy_consumption_freight_dropin_fuel_without_operations
        Energy consumption for freight transport using drop-in fuels without operational improvements [MJ].
    energy_consumption_freight_hydrogen_without_operations
        Energy consumption for freight transport using hydrogen without operational improvements [MJ].
    energy_consumption_freight_electric_without_operations
        Energy consumption for freight transport using electricity without operational improvements [MJ].
    energy_consumption_freight_dropin_fuel
        Energy consumption for freight transport using drop-in fuels [MJ].
    energy_consumption_freight_hydrogen
        Energy consumption for freight transport using hydrogen [MJ].
    energy_consumption_freight_electric
        Energy consumption for freight transport using electricity [MJ].
    energy_consumption_dropin_fuel
        Total energy consumption using drop-in fuels [MJ].
    energy_consumption_hydrogen
        Total energy consumption using hydrogen [MJ].
    energy_consumption_electric
        Total energy consumption using electricity [MJ].
    energy_consumption
        Total energy consumption [MJ].
    dropin_fuel_mean_co2_emission_factor
        Mean CO2 emission factor for drop-in fuels [gCO2/MJ].
    hydrogen_mean_co2_emission_factor
        Mean CO2 emission factor for hydrogen [gCO2/MJ].
    electric_mean_co2_emission_factor
        Mean CO2 emission factor for electricity [gCO2/MJ].

    Returns
    -------
    energy_per_ask_mean_without_operations
        Energy consumption per ASK without operational improvements [MJ/ASK].
    energy_per_ask_mean
        Energy consumption per ASK [MJ/ASK].
    energy_per_rtk_mean_without_operations
        Energy consumption per RTK without operational improvements [MJ/RTK].
    energy_per_rtk_mean
        Energy consumption per RTK [MJ/RTK].
    co2_per_energy_mean
        CO2 emissions per unit of energy consumed [gCO2/MJ].
    """
    energy_per_ask_mean_without_operations = (
        +energy_consumption_passenger_dropin_fuel_without_operations
        + energy_consumption_passenger_hydrogen_without_operations
        + energy_consumption_passenger_electric_without_operations
    ) / ask

    energy_per_ask_mean = (
        +energy_consumption_passenger_dropin_fuel
        + energy_consumption_passenger_hydrogen
        + energy_consumption_passenger_electric
    ) / ask

    energy_per_rtk_mean_without_operations = (
        +energy_consumption_freight_dropin_fuel_without_operations
        + energy_consumption_freight_hydrogen_without_operations
        + energy_consumption_freight_electric_without_operations
    ) / rtk

    energy_per_rtk_mean = (
        +energy_consumption_freight_dropin_fuel
        + energy_consumption_freight_hydrogen
        + energy_consumption_freight_electric
    ) / rtk

    # TODO
    #  --> Better way than fillna to handle years where no energy is produced?

    co2_per_energy_mean = (
        +dropin_fuel_mean_co2_emission_factor.fillna(0) * energy_consumption_dropin_fuel
        + hydrogen_mean_co2_emission_factor.fillna(0) * energy_consumption_hydrogen
        + electric_mean_co2_emission_factor.fillna(0) * energy_consumption_electric
    ) / energy_consumption

    self.df.loc[:, "energy_per_ask_mean_without_operations"] = (
        energy_per_ask_mean_without_operations
    )
    self.df.loc[:, "energy_per_rtk_mean_without_operations"] = (
        energy_per_rtk_mean_without_operations
    )
    self.df.loc[:, "energy_per_ask_mean"] = energy_per_ask_mean
    self.df.loc[:, "energy_per_rtk_mean"] = energy_per_rtk_mean
    self.df.loc[:, "co2_per_energy_mean"] = co2_per_energy_mean

    return (
        energy_per_ask_mean_without_operations,
        energy_per_ask_mean,
        energy_per_rtk_mean_without_operations,
        energy_per_rtk_mean,
        co2_per_energy_mean,
    )

CO2Emissions

CO2Emissions(name='co2_emissions', *args, **kwargs)

Bases: AeroMAPSModel

Class to compute CO2 emissions.

Parameters:

Name Type Description Default
name str

Name of the model instance ('co2_emissions' by default).

'co2_emissions'
Documentation

Inputs - load_factor: Load factor [%]. - rpk_: Passenger RPK [RPK]. - rtk_: Freight RTK [RTK]. - energy_per_ask_: Passenger MJ/ASK. - ask_share: Passenger energy shares [%]. - energy_per_rtk: Freight MJ/RTK. - rtk_share: Freight energy shares [%]. - _mean_co2_emission_factor: Mean CO2 factor [gCO2/MJ]. Outputs - co2_emissions: Per-market CO2 [MtCO2]. - co2_emissions_passenger: Passenger total [MtCO2]. - co2_emissions_freight: Freight total [MtCO2]. - co2_emissions: Passenger + freight [MtCO2]. Notes - is the MarketManager id (passenger and freight markets). - is one of: dropin_fuel, hydrogen, electric. - I/O names are generated from configuration and passed to GEMSEO via self.input_names and self.output_names grammars.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
405
406
407
408
def __init__(self, name="co2_emissions", *args, **kwargs):
    super().__init__(name=name, model_type="custom", *args, **kwargs)
    self.climate_historical_data = None
    self.markets = None

custom_setup

custom_setup()

Dynamically build input_names and output_names based on the markets manager. Specific function for custom AeroMAPSModel instances.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
def custom_setup(self):
    """
    Dynamically build input_names and output_names based on the markets manager.
    Specific function for custom AeroMAPSModel instances.
    """
    energy_types = ["dropin_fuel", "hydrogen", "electric"]
    self.input_names = {
        "load_factor": pd.Series([0.0]),
    }
    self.output_names = {}

    # Per-passenger-market inputs and per-market output.
    for market in self.markets.get(traffic_type="passenger"):
        mid = market.id
        self.input_names[f"rpk_{mid}"] = pd.Series([0.0])
        for et in energy_types:
            self.input_names[f"energy_per_ask_{mid}_{et}"] = pd.Series([0.0])
            self.input_names[f"ask_{mid}_{et}_share"] = pd.Series([0.0])
        self.output_names[f"co2_emissions_{mid}"] = pd.Series([0.0])

    # Per-freight-market inputs and per-market output.
    for market in self.markets.get(traffic_type="freight"):
        mid = market.id
        self.input_names[f"rtk_{mid}"] = pd.Series([0.0])
        for et in energy_types:
            self.input_names[f"energy_per_rtk_{mid}_{et}"] = pd.Series([0.0])
            self.input_names[f"rtk_{mid}_{et}_share"] = pd.Series([0.0])
        self.output_names[f"co2_emissions_{mid}"] = pd.Series([0.0])

    # Mean CO2 emission factors (per energy type, global).
    for et in energy_types:
        self.input_names[f"{et}_mean_co2_emission_factor"] = pd.Series([0.0])

    # Aggregate outputs.
    self.output_names["co2_emissions_passenger"] = pd.Series([0.0])
    self.output_names["co2_emissions_freight"] = pd.Series([0.0])
    self.output_names["co2_emissions"] = pd.Series([0.0])

compute

compute(input_data)

CO2 emissions per market and aggregates.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
def compute(self, input_data) -> dict:
    """
    CO2 emissions per market and aggregates.
    """
    energy_types = ["dropin_fuel", "hydrogen", "electric"]

    # Locally fill incomplete emission factors with zeros so that sums are not nan.
    # ``fillna`` must NOT be in place: input_data holds the very Series objects the
    # MDA snapshotted as its previous iterate, so mutating one silently rewrites
    # that snapshot and corrupts the residual of this coupling variable.
    co2_emission_factor_by_energy_type = {
        energy_type: input_data[f"{energy_type}_mean_co2_emission_factor"].fillna(0)
        for energy_type in energy_types
    }

    load_factor = input_data["load_factor"]
    output_data = {}

    # Per-passenger-market CO2 emissions.
    co2_emissions_passenger = None
    for market in self.markets.get(traffic_type="passenger"):
        mid = market.id
        rpk_market = input_data[f"rpk_{mid}"]
        co2_weighted_energy_intensity_sum = None
        for energy_type in energy_types:
            energy_per_ask = input_data[f"energy_per_ask_{mid}_{energy_type}"].fillna(0)
            ask_share = input_data[f"ask_{mid}_{energy_type}_share"]
            co2_weighted_energy_intensity = (
                ask_share
                / 100
                * (energy_per_ask * co2_emission_factor_by_energy_type[energy_type])
            )
            co2_weighted_energy_intensity_sum = (
                co2_weighted_energy_intensity
                if co2_weighted_energy_intensity_sum is None
                else co2_weighted_energy_intensity_sum + co2_weighted_energy_intensity
            )
        co2_emissions_market = (
            rpk_market / (load_factor / 100) * co2_weighted_energy_intensity_sum * 10 ** (-12)
        )
        output_data[f"co2_emissions_{mid}"] = co2_emissions_market
        co2_emissions_passenger = (
            co2_emissions_market
            if co2_emissions_passenger is None
            else co2_emissions_passenger + co2_emissions_market
        )

    # Per-freight-market CO2 emissions.
    co2_emissions_freight = None
    for market in self.markets.get(traffic_type="freight"):
        mid = market.id
        rtk_market = input_data[f"rtk_{mid}"]
        co2_weighted_energy_intensity_sum = None
        for energy_type in energy_types:
            energy_per_rtk = input_data[f"energy_per_rtk_{mid}_{energy_type}"].fillna(0)
            rtk_share = input_data[f"rtk_{mid}_{energy_type}_share"]
            co2_weighted_energy_intensity = (
                rtk_share
                / 100
                * (energy_per_rtk * co2_emission_factor_by_energy_type[energy_type])
            )
            co2_weighted_energy_intensity_sum = (
                co2_weighted_energy_intensity
                if co2_weighted_energy_intensity_sum is None
                else co2_weighted_energy_intensity_sum + co2_weighted_energy_intensity
            )
        co2_emissions_market = rtk_market * co2_weighted_energy_intensity_sum * 10 ** (-12)
        output_data[f"co2_emissions_{mid}"] = co2_emissions_market
        co2_emissions_freight = (
            co2_emissions_market
            if co2_emissions_freight is None
            else co2_emissions_freight + co2_emissions_market
        )

    # Defensive defaults if no markets.
    if co2_emissions_passenger is None:
        co2_emissions_passenger = pd.Series(0.0, index=self.df.index)
    if co2_emissions_freight is None:
        co2_emissions_freight = pd.Series(0.0, index=self.df.index)

    # Update climate DataFrame side-effect (matches legacy behaviour).
    historical_co2_emissions_for_temperature = self.climate_historical_data[:, 1]
    self.df_climate.loc[
        self.climate_historic_start_year : self.historic_start_year - 1, "co2_emissions"
    ] = historical_co2_emissions_for_temperature[
        : self.historic_start_year - self.climate_historic_start_year
    ]
    self.df_climate.loc[self.historic_start_year : self.end_year, "co2_emissions"] = (
        co2_emissions_passenger + co2_emissions_freight
    )

    co2_emissions_total = self.df_climate["co2_emissions"]

    output_data["co2_emissions_passenger"] = co2_emissions_passenger
    output_data["co2_emissions_freight"] = co2_emissions_freight
    output_data["co2_emissions"] = co2_emissions_total

    self._store_outputs(output_data, climate_outputs_keys=["co2_emissions"])
    return output_data

CumulativeCO2Emissions

CumulativeCO2Emissions(
    name="cumulative_co2_emissions", *args, **kwargs
)

Bases: AeroMAPSModel

Class to compute cumulative CO2 emissions.

Parameters:

Name Type Description Default
name str

Name of the model instance ('cumulative_co2_emissions' by default).

'cumulative_co2_emissions'
Source code in aeromaps/models/impacts/emissions/co2_emissions.py
559
560
def __init__(self, name="cumulative_co2_emissions", *args, **kwargs):
    super().__init__(name=name, *args, **kwargs)

compute

compute(co2_emissions, carbon_budget_reference_year)

Execute the computation of cumulative CO2 emissions.

Parameters:

Name Type Description Default
co2_emissions Series

Annual CO2 emissions [MtCO2].

required
carbon_budget_reference_year int

Fixed reference year from which the budget-comparable cumulative is summed (default 2019), matching the aviation carbon budget framing.

required

Returns:

Type Description
cumulative_co2_emissions

Cumulative CO2 emissions over the prospective window (prospection_start_year -> end_year) [GtCO2].

cumulative_co2_emissions_from_carbon_budget_reference_year

Cumulative CO2 emissions summed from carbon_budget_reference_year -> end_year [GtCO2]. Includes observed historic emissions from the reference year onward, so it is directly comparable to the aviation carbon budget regardless of prospection_start_year.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
def compute(
    self,
    co2_emissions: pd.Series,
    carbon_budget_reference_year: int,
) -> Tuple[pd.Series, pd.Series]:
    """
    Execute the computation of cumulative CO2 emissions.

    Parameters
    ----------
    co2_emissions
        Annual CO2 emissions [MtCO2].
    carbon_budget_reference_year
        Fixed reference year from which the budget-comparable cumulative is
        summed (default 2019), matching the aviation carbon budget framing.

    Returns
    -------
    cumulative_co2_emissions
        Cumulative CO2 emissions over the prospective window
        (prospection_start_year -> end_year) [GtCO2].
    cumulative_co2_emissions_from_carbon_budget_reference_year
        Cumulative CO2 emissions summed from carbon_budget_reference_year ->
        end_year [GtCO2]. Includes observed historic emissions from the
        reference year onward, so it is directly comparable to the aviation
        carbon budget regardless of prospection_start_year.

    """
    cumulative_co2_emissions = (
        co2_emissions.loc[self.prospection_start_year : self.end_year] / 1000
    ).cumsum()

    cumulative_co2_emissions_from_carbon_budget_reference_year = (
        co2_emissions.loc[carbon_budget_reference_year : self.end_year] / 1000
    ).cumsum()

    self.df["cumulative_co2_emissions"] = cumulative_co2_emissions
    self.df["cumulative_co2_emissions_from_carbon_budget_reference_year"] = (
        cumulative_co2_emissions_from_carbon_budget_reference_year
    )

    return (
        cumulative_co2_emissions,
        cumulative_co2_emissions_from_carbon_budget_reference_year,
    )

DetailedCo2Emissions

DetailedCo2Emissions(
    name="detailed_co2_emissions", *args, **kwargs
)

Bases: AeroMAPSModel

Class to compute detailed CO2 emissions breakdown.

Parameters:

Name Type Description Default
name str

Name of the model instance ('detailed_co2_emissions' by default).

'detailed_co2_emissions'
Source code in aeromaps/models/impacts/emissions/co2_emissions.py
619
620
def __init__(self, name="detailed_co2_emissions", *args, **kwargs):
    super().__init__(name=name, *args, **kwargs)

compute

compute(
    rpk_reference,
    rtk_reference,
    rpk,
    rtk,
    load_factor,
    energy_per_ask_mean,
    energy_per_rtk_mean,
    energy_per_ask_mean_without_operations,
    energy_per_rtk_mean_without_operations,
    co2_per_energy_mean,
)

Execute the computation of detailed CO2 emissions breakdown.

Parameters:

Name Type Description Default
rpk_reference Series

Number of Revenue Passenger Kilometer (RPK) for all passenger air transport with a baseline air traffic growth [RPK].

required
rtk_reference Series

Number of Revenue Tonne Kilometer (RTK) for freight air transport with a baseline air traffic growth [RTK].

required
rpk Series

Revenue passenger kilometers (RPK) [RPK].

required
rtk Series

Revenue ton kilometers (RTK) [RTK].

required
load_factor Series

Load factor [%].

required
energy_per_ask_mean Series

Mean energy consumption per ASK for passenger market [MJ/ASK].

required
energy_per_rtk_mean Series

Mean energy consumption per RTK for freight market [MJ/RTK].

required
energy_per_ask_mean_without_operations Series

Mean energy consumption per ASK for passenger market without considering operation improvements [MJ/ASK].

required
energy_per_rtk_mean_without_operations Series

Mean energy consumption per RTK for freight market without considering operation improvements [MJ/RTK].

required
co2_per_energy_mean Series

Mean emission factor of aircraft energy [gCO2/MJ].

required

Returns:

Type Description
co2_emissions_last_historical_year_technology_baseline3

CO2 emissions from all commercial air transport based on last-historical-year technological level with a baseline air traffic growth [MtCO2].

co2_emissions_last_historical_year_technology

CO2 emissions from all commercial air transport based on last-historical-year technological level [MtCO2].

co2_emissions_including_aircraft_efficiency

CO2 emissions from all commercial air transport including aircraft efficiency improvements [MtCO2].

co2_emissions_including_operations

CO2 emissions from all commercial air transport including aircraft efficiency and operation improvements [MtCO2].

co2_emissions_including_load_factor

CO2 emissions from all commercial air transport including aircraft efficiency, operation and load factor improvements [MtCO2].

co2_emissions_including_energy

CO2 emissions from all commercial air transport including aircraft efficiency, operation and load factor improvements and energy decarbonization [MtCO2].

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
def compute(
    self,
    rpk_reference: pd.Series,
    rtk_reference: pd.Series,
    rpk: pd.Series,
    rtk: pd.Series,
    load_factor: pd.Series,
    energy_per_ask_mean: pd.Series,
    energy_per_rtk_mean: pd.Series,
    energy_per_ask_mean_without_operations: pd.Series,
    energy_per_rtk_mean_without_operations: pd.Series,
    co2_per_energy_mean: pd.Series,
) -> Tuple[pd.Series, pd.Series, pd.Series, pd.Series, pd.Series, pd.Series]:
    """
    Execute the computation of detailed CO2 emissions breakdown.

    Parameters
    ----------
    rpk_reference
        Number of Revenue Passenger Kilometer (RPK) for all passenger air transport with a baseline air traffic growth [RPK].
    rtk_reference
        Number of Revenue Tonne Kilometer (RTK) for freight air transport with a baseline air traffic growth [RTK].
    rpk
        Revenue passenger kilometers (RPK) [RPK].
    rtk
        Revenue ton kilometers (RTK) [RTK].
    load_factor
        Load factor [%].
    energy_per_ask_mean
        Mean energy consumption per ASK for passenger market [MJ/ASK].
    energy_per_rtk_mean
        Mean energy consumption per RTK for freight market [MJ/RTK].
    energy_per_ask_mean_without_operations
        Mean energy consumption per ASK for passenger market without considering operation improvements [MJ/ASK].
    energy_per_rtk_mean_without_operations
        Mean energy consumption per RTK for freight market without considering operation improvements [MJ/RTK].
    co2_per_energy_mean
        Mean emission factor of aircraft energy [gCO2/MJ].


    Returns
    -------
    co2_emissions_last_historical_year_technology_baseline3
        CO2 emissions from all commercial air transport based on last-historical-year technological level with a baseline air traffic growth [MtCO2].
    co2_emissions_last_historical_year_technology
        CO2 emissions from all commercial air transport based on last-historical-year technological level [MtCO2].
    co2_emissions_including_aircraft_efficiency
        CO2 emissions from all commercial air transport including aircraft efficiency improvements [MtCO2].
    co2_emissions_including_operations
        CO2 emissions from all commercial air transport including aircraft efficiency and operation improvements [MtCO2].
    co2_emissions_including_load_factor
        CO2 emissions from all commercial air transport including aircraft efficiency, operation and load factor improvements [MtCO2].
    co2_emissions_including_energy
        CO2 emissions from all commercial air transport including aircraft efficiency, operation and load factor improvements and energy decarbonization [MtCO2].

    """
    years = range(self.prospection_start_year - 1, self.end_year + 1)

    # Speedup operations: access right portions of vectors
    rpk_reference_local = rpk_reference.loc[years]
    rtk_reference_local = rtk_reference.loc[years]
    rpk_local = rpk.loc[years]
    rtk_local = rtk.loc[years]
    load_factor_local = load_factor.loc[years]
    energy_per_ask_mean_local = energy_per_ask_mean.loc[years]
    energy_per_rtk_mean_local = energy_per_rtk_mean.loc[years]
    energy_per_ask_mean_without_operations_local = energy_per_ask_mean_without_operations.loc[
        years
    ]
    energy_per_rtk_mean_without_operations_local = energy_per_rtk_mean_without_operations.loc[
        years
    ]
    co2_per_energy_mean_local = co2_per_energy_mean.loc[years]

    # Start year values
    load_factor_start_year_local = load_factor.loc[self.prospection_start_year - 1]
    energy_per_ask_mean_start_year_local = energy_per_ask_mean.loc[
        self.prospection_start_year - 1
    ]
    energy_per_rtk_mean_start_year_local = energy_per_rtk_mean.loc[
        self.prospection_start_year - 1
    ]
    energy_per_ask_mean_without_operations_start_year_local = (
        energy_per_ask_mean_without_operations.loc[self.prospection_start_year - 1]
    )
    energy_per_rtk_mean_without_operations_start_year_local = (
        energy_per_rtk_mean_without_operations.loc[self.prospection_start_year - 1]
    )
    co2_per_energy_mean_start_year_local = co2_per_energy_mean.loc[
        self.prospection_start_year - 1
    ]

    co2_emissions_last_historical_year_technology_baseline3 = (
        rpk_reference_local
        * energy_per_ask_mean_without_operations_start_year_local
        * energy_per_ask_mean_start_year_local
        / energy_per_ask_mean_without_operations_start_year_local
        / (load_factor_start_year_local / 100)
        * co2_per_energy_mean_start_year_local
        * 10 ** (-12)
    ) + (
        rtk_reference_local
        * energy_per_rtk_mean_without_operations_start_year_local
        * energy_per_rtk_mean_start_year_local
        / energy_per_rtk_mean_without_operations_start_year_local
        * co2_per_energy_mean_start_year_local
        * 10 ** (-12)
    )

    co2_emissions_last_historical_year_technology = (
        rpk_local
        * energy_per_ask_mean_without_operations_start_year_local
        * energy_per_ask_mean_start_year_local
        / energy_per_ask_mean_without_operations_start_year_local
        / (load_factor_start_year_local / 100)
        * co2_per_energy_mean_start_year_local
        * 10 ** (-12)
    ) + (
        rtk_local
        * energy_per_rtk_mean_without_operations_start_year_local
        * energy_per_rtk_mean_start_year_local
        / energy_per_rtk_mean_without_operations_start_year_local
        * co2_per_energy_mean_start_year_local
        * 10 ** (-12)
    )

    co2_emissions_including_aircraft_efficiency = (
        rpk_local
        * energy_per_ask_mean_without_operations_local
        * energy_per_ask_mean_start_year_local
        / energy_per_ask_mean_without_operations_start_year_local
        / (load_factor_start_year_local / 100)
        * co2_per_energy_mean_start_year_local
        * 10 ** (-12)
    ) + (
        rtk_local
        * energy_per_rtk_mean_without_operations_local
        * energy_per_rtk_mean_start_year_local
        / energy_per_rtk_mean_without_operations_start_year_local
        * co2_per_energy_mean_start_year_local
        * 10 ** (-12)
    )

    co2_emissions_including_operations = (
        rpk_local
        * energy_per_ask_mean_without_operations_local
        * energy_per_ask_mean_local
        / energy_per_ask_mean_without_operations_local
        / (load_factor_start_year_local / 100)
        * co2_per_energy_mean_start_year_local
        * 10 ** (-12)
    ) + (
        rtk_local
        * energy_per_rtk_mean_without_operations_local
        * energy_per_rtk_mean_local
        / energy_per_rtk_mean_without_operations_local
        * co2_per_energy_mean_start_year_local
        * 10 ** (-12)
    )

    co2_emissions_including_load_factor = (
        rpk_local
        * energy_per_ask_mean_without_operations_local
        * energy_per_ask_mean_local
        / energy_per_ask_mean_without_operations_local
        / (load_factor_local / 100)
        * co2_per_energy_mean_start_year_local
        * 10 ** (-12)
    ) + (
        rtk_local
        * energy_per_rtk_mean_without_operations_local
        * energy_per_rtk_mean_local
        / energy_per_rtk_mean_without_operations_local
        * co2_per_energy_mean_start_year_local
        * 10 ** (-12)
    )

    co2_emissions_including_energy = (
        rpk_local
        * energy_per_ask_mean_without_operations_local
        * energy_per_ask_mean_local
        / energy_per_ask_mean_without_operations_local
        / (load_factor_local / 100)
        * co2_per_energy_mean_local
        * 10 ** (-12)
    ) + (
        rtk_local
        * energy_per_rtk_mean_without_operations_local
        * energy_per_rtk_mean_local
        / energy_per_rtk_mean_without_operations_local
        * co2_per_energy_mean_local
        * 10 ** (-12)
    )

    self.df.loc[years, "co2_emissions_last_historical_year_technology_baseline3"] = (
        co2_emissions_last_historical_year_technology_baseline3
    )
    self.df.loc[years, "co2_emissions_last_historical_year_technology"] = (
        co2_emissions_last_historical_year_technology
    )
    self.df.loc[years, "co2_emissions_including_aircraft_efficiency"] = (
        co2_emissions_including_aircraft_efficiency
    )
    self.df.loc[years, "co2_emissions_including_operations"] = (
        co2_emissions_including_operations
    )
    self.df.loc[years, "co2_emissions_including_load_factor"] = (
        co2_emissions_including_load_factor
    )
    self.df.loc[years, "co2_emissions_including_energy"] = co2_emissions_including_energy

    return (
        co2_emissions_last_historical_year_technology_baseline3,
        co2_emissions_last_historical_year_technology,
        co2_emissions_including_aircraft_efficiency,
        co2_emissions_including_operations,
        co2_emissions_including_load_factor,
        co2_emissions_including_energy,
    )

DetailedCumulativeCO2Emissions

DetailedCumulativeCO2Emissions(
    name="detailed_cumulative_co2_emissions",
    *args,
    **kwargs,
)

Bases: AeroMAPSModel

Class to compute detailed cumulative CO2 emissions breakdown.

Parameters:

Name Type Description Default
name str

Name of the model instance ('detailed_cumulative_co2_emissions' by default).

'detailed_cumulative_co2_emissions'
Source code in aeromaps/models/impacts/emissions/co2_emissions.py
853
854
def __init__(self, name="detailed_cumulative_co2_emissions", *args, **kwargs):
    super().__init__(name=name, *args, **kwargs)

compute

compute(
    co2_emissions_last_historical_year_technology_baseline3,
    co2_emissions_last_historical_year_technology,
    co2_emissions_including_aircraft_efficiency,
    co2_emissions_including_operations,
    co2_emissions_including_load_factor,
    co2_emissions_including_energy,
)

Execute the computation of detailed cumulative CO2 emissions breakdown.

Parameters:

Name Type Description Default
co2_emissions_last_historical_year_technology_baseline3 Series

CO2 emissions from all commercial air transport based on last-historical-year technological level with a baseline air traffic growth [MtCO2].

required
co2_emissions_last_historical_year_technology Series

CO2 emissions from all commercial air transport based on last-historical-year technological level [MtCO2].

required
co2_emissions_including_aircraft_efficiency Series

CO2 emissions from all commercial air transport including aircraft efficiency improvements [MtCO2].

required
co2_emissions_including_operations Series

CO2 emissions from all commercial air transport including aircraft efficiency and operations improvements [MtCO2].

required
co2_emissions_including_load_factor Series

CO2 emissions from all commercial air transport including aircraft efficiency, operation and load factor improvements [MtCO2].

required
co2_emissions_including_energy Series

CO2 emissions from all commercial air transport including aircraft efficiency, operation and load factor improvements and energy decarbonization [MtCO2].

required

Returns:

Type Description
cumulative_co2_emissions_last_historical_year_technology_baseline3

Cumulative CO2 emissions from all commercial air transport based on last-historical-year technological level with a baseline air traffic growth [GtCO2].

cumulative_co2_emissions_last_historical_year_technology

Cumulative CO2 emissions from all commercial air transport based on last-historical-year technological level [GtCO2].

cumulative_co2_emissions_including_aircraft_efficiency

Cumulative CO2 emissions from all commercial air transport including aircraft efficiency improvements [GtCO2].

cumulative_co2_emissions_including_operations

Cumulative CO2 emissions from all commercial air transport including aircraft efficiency and operations improvements [GtCO2].

cumulative_co2_emissions_including_load_factor

Cumulative CO2 emissions from all commercial air transport including aircraft efficiency, operation and load factor improvements [GtCO2].

cumulative_co2_emissions_including_energy

Cumulative CO2 emissions from all commercial air transport including aircraft efficiency, operation and load factor improvements and energy decarbonization [GtCO2].

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
def compute(
    self,
    co2_emissions_last_historical_year_technology_baseline3: pd.Series,
    co2_emissions_last_historical_year_technology: pd.Series,
    co2_emissions_including_aircraft_efficiency: pd.Series,
    co2_emissions_including_operations: pd.Series,
    co2_emissions_including_load_factor: pd.Series,
    co2_emissions_including_energy: pd.Series,
) -> Tuple[pd.Series, pd.Series, pd.Series, pd.Series, pd.Series, pd.Series]:
    """
    Execute the computation of detailed cumulative CO2 emissions breakdown.
    Parameters
    ----------
    co2_emissions_last_historical_year_technology_baseline3
        CO2 emissions from all commercial air transport based on last-historical-year technological level with a baseline air traffic growth [MtCO2].
    co2_emissions_last_historical_year_technology
        CO2 emissions from all commercial air transport based on last-historical-year technological level [MtCO2].
    co2_emissions_including_aircraft_efficiency
        CO2 emissions from all commercial air transport including aircraft efficiency improvements [MtCO2].
    co2_emissions_including_operations
        CO2 emissions from all commercial air transport including aircraft efficiency and operations improvements [MtCO2].
    co2_emissions_including_load_factor
        CO2 emissions from all commercial air transport including aircraft efficiency, operation and load factor improvements [MtCO2].
    co2_emissions_including_energy
        CO2 emissions from all commercial air transport including aircraft efficiency, operation and load factor improvements and energy decarbonization [MtCO2].

    Returns
    -------
    cumulative_co2_emissions_last_historical_year_technology_baseline3
        Cumulative CO2 emissions from all commercial air transport based on last-historical-year technological level with a baseline air traffic growth [GtCO2].
    cumulative_co2_emissions_last_historical_year_technology
        Cumulative CO2 emissions from all commercial air transport based on last-historical-year technological level [GtCO2].
    cumulative_co2_emissions_including_aircraft_efficiency
        Cumulative CO2 emissions from all commercial air transport including aircraft efficiency improvements [GtCO2].
    cumulative_co2_emissions_including_operations
        Cumulative CO2 emissions from all commercial air transport including aircraft efficiency and operations improvements [GtCO2].
    cumulative_co2_emissions_including_load_factor
        Cumulative CO2 emissions from all commercial air transport including aircraft efficiency, operation and load factor
        improvements [GtCO2].
    cumulative_co2_emissions_including_energy
        Cumulative CO2 emissions from all commercial air transport including aircraft efficiency, operation and load factor
        improvements and energy decarbonization [GtCO2].

    """
    cumulative_co2_emissions_last_historical_year_technology_baseline3 = (
        co2_emissions_last_historical_year_technology_baseline3.loc[
            self.prospection_start_year : self.end_year
        ]
        / 1000
    ).cumsum()

    cumulative_co2_emissions_last_historical_year_technology = (
        co2_emissions_last_historical_year_technology.loc[
            self.prospection_start_year : self.end_year
        ]
        / 1000
    ).cumsum()

    cumulative_co2_emissions_including_aircraft_efficiency = (
        co2_emissions_including_aircraft_efficiency.loc[
            self.prospection_start_year : self.end_year
        ]
        / 1000
    ).cumsum()

    cumulative_co2_emissions_including_operations = (
        co2_emissions_including_operations.loc[self.prospection_start_year : self.end_year]
        / 1000
    ).cumsum()

    cumulative_co2_emissions_including_load_factor = (
        co2_emissions_including_load_factor.loc[self.prospection_start_year : self.end_year]
        / 1000
    ).cumsum()

    cumulative_co2_emissions_including_energy = (
        co2_emissions_including_energy.loc[self.prospection_start_year : self.end_year] / 1000
    ).cumsum()

    self.df["cumulative_co2_emissions_last_historical_year_technology_baseline3"] = (
        cumulative_co2_emissions_last_historical_year_technology_baseline3
    )
    self.df["cumulative_co2_emissions_last_historical_year_technology"] = (
        cumulative_co2_emissions_last_historical_year_technology
    )
    self.df["cumulative_co2_emissions_including_aircraft_efficiency"] = (
        cumulative_co2_emissions_including_aircraft_efficiency
    )
    self.df["cumulative_co2_emissions_including_operations"] = (
        cumulative_co2_emissions_including_operations
    )
    self.df["cumulative_co2_emissions_including_load_factor"] = (
        cumulative_co2_emissions_including_load_factor
    )
    self.df["cumulative_co2_emissions_including_energy"] = (
        cumulative_co2_emissions_including_energy
    )

    return (
        cumulative_co2_emissions_last_historical_year_technology_baseline3,
        cumulative_co2_emissions_last_historical_year_technology,
        cumulative_co2_emissions_including_aircraft_efficiency,
        cumulative_co2_emissions_including_operations,
        cumulative_co2_emissions_including_load_factor,
        cumulative_co2_emissions_including_energy,
    )

DetailedCo2EmissionsPerPathway

DetailedCo2EmissionsPerPathway(
    name="detailed_co2_emissions_per_pathway",
    *args,
    **kwargs,
)

Bases: AeroMAPSModel

Class to decompose the "aircraft energy" lever of action into sub-levers, one per energy pathway (e.g. each biofuel or electrofuel pathway).

For each pathway, the annual CO2 emissions reduction is computed as the energy consumption of the pathway multiplied by the difference between the reference (start year) mean CO2 emission factor and the pathway emission factor. By construction, the sum of the pathway contributions and of the residual term equals the difference between co2_emissions_including_load_factor and co2_emissions_including_energy computed by DetailedCo2Emissions.

Parameters:

Name Type Description Default
name str

Name of the model instance ('detailed_co2_emissions_per_pathway' by default).

'detailed_co2_emissions_per_pathway'

Attributes:

Name Type Description
pathways_manager EnergyCarrierManager

Instance of the EnergyCarrierManager containing all defined energy pathways.

input_names dict

Dictionary of input variable names populated at model initialisation before MDA chain creation.

output_names dict

Dictionary of output variable names populated at model initialisation before MDA chain creation.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
991
992
993
def __init__(self, name="detailed_co2_emissions_per_pathway", *args, **kwargs):
    super().__init__(name=name, model_type="custom", *args, **kwargs)
    self.pathways_manager = None

custom_setup

custom_setup()

Sets up input and output names for the model based on the pathways in the pathways_manager.

Returns:

Type Description
None
Source code in aeromaps/models/impacts/emissions/co2_emissions.py
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
def custom_setup(self):
    """
    Sets up input and output names for the model based on the pathways in the pathways_manager.

    Returns
    -------
    None
    """
    self.input_names = {
        "co2_emissions_including_load_factor": pd.Series([0.0]),
        "co2_emissions_including_energy": pd.Series([0.0]),
        "co2_per_energy_mean": pd.Series([0.0]),
    }
    self.output_names = {
        ENERGY_SUB_LEVER_OTHER: pd.Series([0.0]),
    }

    for pathway in self.pathways_manager.get_all():
        self.input_names.update(
            {
                f"{pathway.name}_energy_consumption": pd.Series([0.0]),
                f"{pathway.name}_mean_co2_emission_factor": pd.Series([0.0]),
            }
        )
        self.output_names.update(
            {
                pathway_energy_column(pathway.name): pd.Series([0.0]),
            }
        )

compute

compute(input_data)

Execute the decomposition of the energy lever of action per energy pathway.

Parameters:

Name Type Description Default
input_data

Dictionary containing all input data required for the computation, completed at model instantiation with information from yaml files and outputs of other models.

required

Returns:

Type Description
output_data

Dictionary containing, for each pathway, the annual CO2 emissions avoided thanks to the pathway [MtCO2], plus a residual term so that the sum of all contributions equals the total energy lever of action.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
def compute(self, input_data) -> dict:
    """
    Execute the decomposition of the energy lever of action per energy pathway.

    Parameters
    ----------
    input_data
        Dictionary containing all input data required for the computation, completed at model instantiation with information from yaml files and outputs of other models.

    Returns
    -------
    output_data
        Dictionary containing, for each pathway, the annual CO2 emissions avoided
        thanks to the pathway [MtCO2], plus a residual term so that the sum of all
        contributions equals the total energy lever of action.
    """
    output_data = {}

    reference_year = self.prospection_start_year - 1
    years = range(reference_year, self.end_year + 1)

    co2_emission_factor_reference = input_data["co2_per_energy_mean"].loc[reference_year]

    total_lever = (
        input_data["co2_emissions_including_load_factor"]
        - input_data["co2_emissions_including_energy"]
    ).loc[years]

    cumulated_contributions = pd.Series(0.0, index=total_lever.index)

    for pathway in self.pathways_manager.get_all():
        pathway_energy_consumption = input_data[f"{pathway.name}_energy_consumption"]
        pathway_co2_emission_factor = input_data[f"{pathway.name}_mean_co2_emission_factor"]

        pathway_contribution = (
            pathway_energy_consumption
            * (co2_emission_factor_reference - pathway_co2_emission_factor)
        ).fillna(0) * 10 ** (-12)
        pathway_contribution = pathway_contribution.reindex(total_lever.index).fillna(0.0)

        cumulated_contributions += pathway_contribution

        contribution = get_default_series(
            self.historic_start_year, self.end_year, fill_value=float("nan")
        )
        contribution.loc[years] = pathway_contribution
        output_data[pathway_energy_column(pathway.name)] = contribution

    other = get_default_series(self.historic_start_year, self.end_year, fill_value=float("nan"))
    other.loc[years] = total_lever.fillna(0) - cumulated_contributions
    output_data[ENERGY_SUB_LEVER_OTHER] = other

    output_data = {name: _denoise(series) for name, series in output_data.items()}
    self._store_outputs(output_data)

    return output_data

DetailedCo2EmissionsPerAircraft

DetailedCo2EmissionsPerAircraft(
    name="detailed_co2_emissions_per_aircraft",
    *args,
    **kwargs,
)

Bases: AeroMAPSModel

Class to decompose the "aircraft efficiency" lever of action into sub-levers: fleet renewal with reference (already existing) aircraft, continuous improvement of the recent reference aircraft, introduction of each new aircraft of the fleet, freight fleet efficiency, and a residual term (traffic mix effects between markets).

The decomposition builds on the per-aircraft energy efficiency contributions computed by the fleet model (see FleetPerformanceMixin), which quantify how much each aircraft shifts the market mean energy consumption per ASK with respect to the recent reference aircraft. The evolution of these contributions with respect to the reference (start) year is converted into avoided CO2 emissions using the same factors as DetailedCo2Emissions. By construction, the sum of all sub-lever contributions equals the difference between co2_emissions_last_historical_year_technology and co2_emissions_including_aircraft_efficiency.

With this convention, the "fleet renewal" sub-lever measures the gain from replacing old reference aircraft by recent reference aircraft, and each new aircraft is only credited for its additional gain beyond fleet renewal.

The fleet model measures every contribution against the recent reference aircraft including its own continuous_improvement_factor_energy, so the drift of that baseline over time belongs to none of the aircraft bands. It is reported as the "continuous improvement" sub-lever rather than left in the residual, which then only carries the traffic mix between markets.

This model requires the bottom-up fleet model.

Parameters:

Name Type Description Default
name str

Name of the model instance ('detailed_co2_emissions_per_aircraft' by default).

'detailed_co2_emissions_per_aircraft'

Attributes:

Name Type Description
fleet_model FleetModel

FleetModel instance containing the fleet structure and computed aircraft shares and efficiency contributions.

markets MarketManager

MarketManager instance used to map fleet categories to the markets they serve.

input_names dict

Dictionary of input variable names populated at model initialisation before MDA chain creation.

output_names dict

Dictionary of output variable names populated at model initialisation before MDA chain creation.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
1130
1131
1132
1133
1134
def __init__(self, name="detailed_co2_emissions_per_aircraft", *args, **kwargs):
    super().__init__(name=name, model_type="custom", *args, **kwargs)
    self.fleet_model = None
    self.markets = None
    self.aircraft_lever_names = {}

custom_setup

custom_setup()

Sets up input and output names for the model based on the fleet structure.

Returns:

Type Description
None
Source code in aeromaps/models/impacts/emissions/co2_emissions.py
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
def custom_setup(self):
    """
    Sets up input and output names for the model based on the fleet structure.

    Returns
    -------
    None
    """
    if self.fleet_model is None:
        raise RuntimeError(
            f"Model '{self.name}' requires the bottom-up fleet model. "
            "Add 'models.fleet' to your configuration."
        )

    self.input_names = {
        "ask": pd.Series([0.0]),
        "rpk": pd.Series([0.0]),
        "rtk": pd.Series([0.0]),
        "load_factor": pd.Series([0.0]),
        "energy_per_ask_mean": pd.Series([0.0]),
        "energy_per_ask_mean_without_operations": pd.Series([0.0]),
        "energy_per_rtk_mean": pd.Series([0.0]),
        "energy_per_rtk_mean_without_operations": pd.Series([0.0]),
        "co2_per_energy_mean": pd.Series([0.0]),
        "co2_emissions_last_historical_year_technology": pd.Series([0.0]),
        "co2_emissions_including_aircraft_efficiency": pd.Series([0.0]),
    }
    self.output_names = {
        "co2_emissions_lever_efficiency_fleet_renewal": pd.Series([0.0]),
        "co2_emissions_lever_efficiency_continuous_improvement": pd.Series([0.0]),
        "co2_emissions_lever_efficiency_freight": pd.Series([0.0]),
        "co2_emissions_lever_efficiency_other": pd.Series([0.0]),
    }

    # ASK of the market served by each category, for weighting the contributions
    for category in self.fleet_model.fleet.categories.values():
        self.input_names[f"ask_{category.market_id}"] = pd.Series([0.0])

    # Map each aircraft of the fleet to a unique output variable name
    self.aircraft_lever_names = aircraft_efficiency_lever_names(self.fleet_model.fleet)
    for lever_name in self.aircraft_lever_names.values():
        self.output_names[lever_name] = pd.Series([0.0])

compute

compute(input_data)

Execute the decomposition of the aircraft efficiency lever of action per aircraft.

Parameters:

Name Type Description Default
input_data

Dictionary containing all input data required for the computation, completed at model instantiation with information from yaml files and outputs of other models.

required

Returns:

Type Description
output_data

Dictionary containing, for each sub-lever (fleet renewal, continuous improvement, each new aircraft, freight, residual), the annual CO2 emissions avoided [MtCO2].

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
def compute(self, input_data) -> dict:
    """
    Execute the decomposition of the aircraft efficiency lever of action per aircraft.

    Parameters
    ----------
    input_data
        Dictionary containing all input data required for the computation, completed at model instantiation with information from yaml files and outputs of other models.

    Returns
    -------
    output_data
        Dictionary containing, for each sub-lever (fleet renewal, continuous
        improvement, each new aircraft, freight, residual), the annual CO2
        emissions avoided [MtCO2].
    """
    output_data = {}

    reference_year = self.prospection_start_year - 1
    years = range(reference_year, self.end_year + 1)

    fleet_df = self.fleet_model.df

    load_factor_reference = input_data["load_factor"].loc[reference_year]
    energy_per_ask_mean_reference = input_data["energy_per_ask_mean"].loc[reference_year]
    energy_per_ask_mean_without_operations_reference = input_data[
        "energy_per_ask_mean_without_operations"
    ].loc[reference_year]
    energy_per_rtk_mean_reference = input_data["energy_per_rtk_mean"].loc[reference_year]
    energy_per_rtk_mean_without_operations_reference = input_data[
        "energy_per_rtk_mean_without_operations"
    ].loc[reference_year]
    co2_emission_factor_reference = input_data["co2_per_energy_mean"].loc[reference_year]

    ask = input_data["ask"].loc[years]
    rpk = input_data["rpk"].loc[years]
    rtk = input_data["rtk"].loc[years]

    # Common factor of the passenger part of the aircraft efficiency lever
    # (see DetailedCo2Emissions for the corresponding formulas)
    passenger_factor = (
        rpk
        * (energy_per_ask_mean_reference / energy_per_ask_mean_without_operations_reference)
        / (load_factor_reference / 100)
        * co2_emission_factor_reference
        * 10 ** (-12)
    )

    fleet_renewal = pd.Series(0.0, index=pd.Index(years))
    continuous_improvement = pd.Series(0.0, index=pd.Index(years))
    cumulated_contributions = pd.Series(0.0, index=pd.Index(years))
    current_names = aircraft_efficiency_lever_names(self.fleet_model.fleet)
    unknown_aircraft = []

    def co2_contribution(category_ask_share, contribution_column):
        """Convert a fleet energy efficiency contribution [MJ/ASK] into avoided CO2 [MtCO2]."""
        contribution = fleet_df.loc[years, contribution_column]
        contribution_reference = fleet_df.loc[reference_year, contribution_column]
        return passenger_factor * category_ask_share * (contribution - contribution_reference)

    for category in self.fleet_model.fleet.categories.values():
        category_ask_share = input_data[f"ask_{category.market_id}"].loc[years] / ask

        # Fleet renewal: replacement of the old reference aircraft by the recent
        # one. The recent reference is the baseline of the fleet model, so its
        # own contribution is zero and only the old reference term remains.
        first_subcategory = category.subcategories[0]
        contribution = co2_contribution(
            category_ask_share,
            f"{category.name}:{first_subcategory.name}:old_reference:"
            "energy_efficiency_contribution",
        )
        fleet_renewal += contribution
        cumulated_contributions += contribution

        # Continuous improvement: the contributions above are measured against
        # the recent reference baseline, which itself improves over time when a
        # continuous improvement factor is set. The identity
        # mean(t) = baseline(t) - sum(contributions(t)) makes the baseline drift
        # a gain of its own (sign flipped: a lower baseline is avoided CO2).
        contribution = -co2_contribution(
            category_ask_share,
            f"{category.name}:{first_subcategory.name}:recent_reference:"
            "energy_efficiency_contribution_baseline",
        )
        continuous_improvement += contribution
        cumulated_contributions += contribution

        # New aircraft: additional gain beyond fleet renewal. The fleet may have
        # been rebuilt since setup (the GUI does so), while the output grammar is
        # fixed: an aircraft unknown at setup cannot get a column, so its gain is
        # left in the residual, and a declared aircraft that disappeared is zero.
        for subcategory in category.subcategories.values():
            for aircraft in subcategory.aircraft.values():
                key = (category.name, subcategory.name, aircraft.name)
                contribution = co2_contribution(
                    category_ask_share,
                    f"{category.name}:{subcategory.name}:{aircraft.name}:energy_efficiency_contribution",
                )
                lever_name = self.aircraft_lever_names.get(key, current_names.get(key))
                if lever_name not in self.output_names:
                    unknown_aircraft.append(aircraft.name)
                    continue
                cumulated_contributions += contribution
                series = get_default_series(
                    self.historic_start_year, self.end_year, fill_value=float("nan")
                )
                series.loc[years] = contribution
                output_data[lever_name] = series

    if unknown_aircraft:
        logging.warning(
            "Aircraft %s were added to the fleet after the process was set up: their "
            "efficiency gain is reported in the residual sub-lever. Set the process up "
            "again to get one sub-lever per aircraft.",
            unknown_aircraft,
        )
    for lever_name in self.aircraft_lever_names.values():
        if lever_name not in output_data:
            output_data[lever_name] = get_default_series(
                self.historic_start_year, self.end_year, fill_value=0.0
            )

    # Freight part of the aircraft efficiency lever
    freight = (
        rtk
        * (
            energy_per_rtk_mean_without_operations_reference
            - input_data["energy_per_rtk_mean_without_operations"].loc[years]
        )
        * (energy_per_rtk_mean_reference / energy_per_rtk_mean_without_operations_reference)
        * co2_emission_factor_reference
        * 10 ** (-12)
    )
    cumulated_contributions += freight

    # Residual term (traffic mix effects between markets) so that the sum of
    # all sub-levers equals the total aircraft efficiency lever
    total_lever = (
        input_data["co2_emissions_last_historical_year_technology"]
        - input_data["co2_emissions_including_aircraft_efficiency"]
    ).loc[years]
    other = total_lever.fillna(0) - cumulated_contributions

    for name, values in [
        ("co2_emissions_lever_efficiency_fleet_renewal", fleet_renewal),
        ("co2_emissions_lever_efficiency_continuous_improvement", continuous_improvement),
        ("co2_emissions_lever_efficiency_freight", freight),
        ("co2_emissions_lever_efficiency_other", other),
    ]:
        series = get_default_series(
            self.historic_start_year, self.end_year, fill_value=float("nan")
        )
        series.loc[years] = values
        output_data[name] = series

    output_data = {name: _denoise(series) for name, series in output_data.items()}
    self._store_outputs(output_data)

    return output_data

DetailedCo2EmissionsPerMarket

DetailedCo2EmissionsPerMarket(
    name="detailed_co2_emissions_per_market",
    *args,
    **kwargs,
)

Bases: AeroMAPSModel

Class to decompose every lever of action of the CO2 emissions cascade by market (each passenger market and each freight market).

The global CO2 emissions cascade computed by DetailedCo2Emissions goes, for a given year, through six successive emission levels::

last-historical-year technology with baseline traffic growth
  -> last-historical-year technology (demand lever)
  -> including aircraft efficiency
  -> including operations
  -> including load factor
  -> including energy (actual emissions)

and defines five levers of action as the differences between consecutive levels. This model recomputes the same cascade per market, using the per-market traffic (rpk_<market> / rtk_<market>, and their baseline growth counterparts rpk_reference_<market> / rtk_reference_<market> for the demand lever) and the per-market, per-energy-type physical intensities (energy_per_ask_<market>_<energy> and their without_operations counterparts). Each lever therefore gets a per-market contribution answering "how much of this lever is attributable to the short/medium/long-range (or freight) market?".

Because the global cascade uses fleet-wide mean intensities and a fleet-wide load factor while the per-market cascade uses market-resolved quantities, the sum of the per-market contributions does not exactly reproduce the global lever: the difference is a genuine cross-market traffic-mix term. It is emitted as a ..._market_cross_mix residual for each lever, so that by construction::

sum_over_markets(lever_market) + lever_market_cross_mix == global lever

The energy lever additionally uses the per-market, per-energy-type CO2 emission factors (exactly as :class:CO2Emissions), so the per-market energy lever captures market-specific fuel-mix decarbonisation.

This model only needs the per-market intensities, which every efficiency model group produces (top-down, push and bottom-up), so it is registered in each of them.

Parameters:

Name Type Description Default
name str

Name of the model instance ('detailed_co2_emissions_per_market' by default).

'detailed_co2_emissions_per_market'

Attributes:

Name Type Description
markets MarketManager

MarketManager instance enumerating the passenger and freight markets.

input_names dict

Dictionary of input variable names populated at model initialisation before MDA chain creation.

output_names dict

Dictionary of output variable names populated at model initialisation before MDA chain creation.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
1400
1401
1402
def __init__(self, name="detailed_co2_emissions_per_market", *args, **kwargs):
    super().__init__(name=name, model_type="custom", *args, **kwargs)
    self.markets = None

custom_setup

custom_setup()

Sets up input and output names for the model based on the markets manager.

Returns:

Type Description
None
Source code in aeromaps/models/impacts/emissions/co2_emissions.py
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
def custom_setup(self):
    """
    Sets up input and output names for the model based on the markets manager.

    Returns
    -------
    None
    """
    self.input_names = {
        "load_factor": pd.Series([0.0]),
        "co2_per_energy_mean": pd.Series([0.0]),
        "co2_emissions_last_historical_year_technology_baseline3": pd.Series([0.0]),
        "co2_emissions_last_historical_year_technology": pd.Series([0.0]),
        "co2_emissions_including_aircraft_efficiency": pd.Series([0.0]),
        "co2_emissions_including_operations": pd.Series([0.0]),
        "co2_emissions_including_load_factor": pd.Series([0.0]),
        "co2_emissions_including_energy": pd.Series([0.0]),
    }
    for energy_type in self.ENERGY_TYPES:
        self.input_names[f"{energy_type}_mean_co2_emission_factor"] = pd.Series([0.0])

    for market in self.markets.get(traffic_type="passenger"):
        mid = market.id
        self.input_names[f"rpk_{mid}"] = pd.Series([0.0])
        self.input_names[f"rpk_reference_{mid}"] = pd.Series([0.0])
        for energy_type in self.ENERGY_TYPES:
            self.input_names[f"ask_{mid}_{energy_type}_share"] = pd.Series([0.0])
            self.input_names[f"energy_per_ask_{mid}_{energy_type}"] = pd.Series([0.0])
            self.input_names[f"energy_per_ask_without_operations_{mid}_{energy_type}"] = (
                pd.Series([0.0])
            )

    for market in self.markets.get(traffic_type="freight"):
        mid = market.id
        self.input_names[f"rtk_{mid}"] = pd.Series([0.0])
        self.input_names[f"rtk_reference_{mid}"] = pd.Series([0.0])
        for energy_type in self.ENERGY_TYPES:
            self.input_names[f"rtk_{mid}_{energy_type}_share"] = pd.Series([0.0])
            self.input_names[f"energy_per_rtk_{mid}_{energy_type}"] = pd.Series([0.0])
            self.input_names[f"energy_per_rtk_without_operations_{mid}_{energy_type}"] = (
                pd.Series([0.0])
            )

    # Output columns come from the shared naming helper (single source of truth).
    self.output_names = {
        column: pd.Series([0.0]) for column in market_lever_names(self.markets).values()
    }

compute

compute(input_data)

Execute the per-market decomposition of the CO2 emissions levers.

Parameters:

Name Type Description Default
input_data

Dictionary containing all input data required for the computation, completed at model instantiation with information from yaml files and outputs of other models.

required

Returns:

Type Description
output_data

Dictionary containing, for each market and each lever (efficiency, operations, load factor, energy), the annual CO2 emissions avoided [MtCO2], plus a cross-market-mix residual per lever.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
def compute(self, input_data) -> dict:
    """
    Execute the per-market decomposition of the CO2 emissions levers.

    Parameters
    ----------
    input_data
        Dictionary containing all input data required for the computation, completed at model instantiation with information from yaml files and outputs of other models.

    Returns
    -------
    output_data
        Dictionary containing, for each market and each lever (efficiency,
        operations, load factor, energy), the annual CO2 emissions avoided
        [MtCO2], plus a cross-market-mix residual per lever.
    """
    output_data = {}

    reference_year = self.prospection_start_year - 1
    years = pd.Index(range(reference_year, self.end_year + 1))

    load_factor = input_data["load_factor"].loc[years]
    load_factor_reference = input_data["load_factor"].loc[reference_year]
    co2_emission_factor_reference = input_data["co2_per_energy_mean"].loc[reference_year]

    co2_factor = {
        energy_type: input_data[f"{energy_type}_mean_co2_emission_factor"].fillna(0).loc[years]
        for energy_type in self.ENERGY_TYPES
    }

    def emit(name, series):
        out = get_default_series(
            self.historic_start_year, self.end_year, fill_value=float("nan")
        )
        out.loc[years] = series
        output_data[name] = out

    # Per-lever accumulators of the market contributions (to derive the
    # cross-market-mix residual against the global levers).
    lever_sum = {lever: pd.Series(0.0, index=years) for lever in MARKET_LEVERS_PASSENGER}

    def weighted_intensity(prefix, share_prefix, mid):
        """Traffic-weighted market mean of a per-energy-type intensity [MJ/ASK or MJ/RTK]."""
        total = pd.Series(0.0, index=years)
        for energy_type in self.ENERGY_TYPES:
            share = input_data[f"{share_prefix}_{mid}_{energy_type}_share"].loc[years] / 100
            intensity = input_data[f"{prefix}_{mid}_{energy_type}"].fillna(0).loc[years]
            total = total + share * intensity
        return total

    def co2_weighted_intensity(prefix, share_prefix, mid):
        """Traffic-weighted market mean of intensity x CO2 factor [gCO2/ASK or /RTK]."""
        total = pd.Series(0.0, index=years)
        for energy_type in self.ENERGY_TYPES:
            share = input_data[f"{share_prefix}_{mid}_{energy_type}_share"].loc[years] / 100
            intensity = input_data[f"{prefix}_{mid}_{energy_type}"].fillna(0).loc[years]
            total = total + share * intensity * co2_factor[energy_type]
        return total

    # --- Passenger markets ---
    for market in self.markets.get(traffic_type="passenger"):
        mid = market.id
        rpk = input_data[f"rpk_{mid}"].loc[years]
        rpk_reference = input_data[f"rpk_reference_{mid}"].loc[years]

        energy_per_ask = weighted_intensity("energy_per_ask", "ask", mid)
        energy_per_ask_without_operations = weighted_intensity(
            "energy_per_ask_without_operations", "ask", mid
        )
        co2_per_ask = co2_weighted_intensity("energy_per_ask", "ask", mid)

        energy_per_ask_reference = energy_per_ask.loc[reference_year]
        energy_per_ask_without_operations_reference = energy_per_ask_without_operations.loc[
            reference_year
        ]

        # Emission levels of the cascade for this market [MtCO2].
        level_baseline_traffic = (
            rpk_reference
            * energy_per_ask_reference
            / (load_factor_reference / 100)
            * co2_emission_factor_reference
            * 10 ** (-12)
        )
        level_last_historical_year = (
            rpk
            * energy_per_ask_reference
            / (load_factor_reference / 100)
            * co2_emission_factor_reference
            * 10 ** (-12)
        )
        level_efficiency = (
            rpk
            * energy_per_ask_without_operations
            * (energy_per_ask_reference / energy_per_ask_without_operations_reference)
            / (load_factor_reference / 100)
            * co2_emission_factor_reference
            * 10 ** (-12)
        )
        level_operations = (
            rpk
            * energy_per_ask
            / (load_factor_reference / 100)
            * co2_emission_factor_reference
            * 10 ** (-12)
        )
        level_load_factor = (
            rpk
            * energy_per_ask
            / (load_factor / 100)
            * co2_emission_factor_reference
            * 10 ** (-12)
        )
        level_energy = rpk / (load_factor / 100) * co2_per_ask * 10 ** (-12)

        levers = {
            "demand": level_baseline_traffic - level_last_historical_year,
            "efficiency": level_last_historical_year - level_efficiency,
            "operations": level_efficiency - level_operations,
            "loadfactor": level_operations - level_load_factor,
            "energy": level_load_factor - level_energy,
        }
        for lever, values in levers.items():
            emit(market_lever_column(lever, mid), values)
            lever_sum[lever] = lever_sum[lever] + values

    # --- Freight markets (no passenger load factor lever) ---
    for market in self.markets.get(traffic_type="freight"):
        mid = market.id
        rtk = input_data[f"rtk_{mid}"].loc[years]
        rtk_reference = input_data[f"rtk_reference_{mid}"].loc[years]

        energy_per_rtk = weighted_intensity("energy_per_rtk", "rtk", mid)
        energy_per_rtk_without_operations = weighted_intensity(
            "energy_per_rtk_without_operations", "rtk", mid
        )
        co2_per_rtk = co2_weighted_intensity("energy_per_rtk", "rtk", mid)

        energy_per_rtk_reference = energy_per_rtk.loc[reference_year]
        energy_per_rtk_without_operations_reference = energy_per_rtk_without_operations.loc[
            reference_year
        ]

        level_baseline_traffic = (
            rtk_reference
            * energy_per_rtk_reference
            * co2_emission_factor_reference
            * 10 ** (-12)
        )
        level_last_historical_year = (
            rtk * energy_per_rtk_reference * co2_emission_factor_reference * 10 ** (-12)
        )
        level_efficiency = (
            rtk
            * energy_per_rtk_without_operations
            * (energy_per_rtk_reference / energy_per_rtk_without_operations_reference)
            * co2_emission_factor_reference
            * 10 ** (-12)
        )
        level_operations = rtk * energy_per_rtk * co2_emission_factor_reference * 10 ** (-12)
        level_energy = rtk * co2_per_rtk * 10 ** (-12)

        levers = {
            "demand": level_baseline_traffic - level_last_historical_year,
            "efficiency": level_last_historical_year - level_efficiency,
            "operations": level_efficiency - level_operations,
            "energy": level_operations - level_energy,
        }
        for lever, values in levers.items():
            emit(market_lever_column(lever, mid), values)
            lever_sum[lever] = lever_sum[lever] + values

    # --- Cross-market-mix residual per lever ---
    # Global levers from the DetailedCo2Emissions cascade.
    global_levers = {
        "demand": input_data["co2_emissions_last_historical_year_technology_baseline3"]
        - input_data["co2_emissions_last_historical_year_technology"],
        "efficiency": input_data["co2_emissions_last_historical_year_technology"]
        - input_data["co2_emissions_including_aircraft_efficiency"],
        "operations": input_data["co2_emissions_including_aircraft_efficiency"]
        - input_data["co2_emissions_including_operations"],
        "loadfactor": input_data["co2_emissions_including_operations"]
        - input_data["co2_emissions_including_load_factor"],
        "energy": input_data["co2_emissions_including_load_factor"]
        - input_data["co2_emissions_including_energy"],
    }
    for lever, global_lever in global_levers.items():
        residual = global_lever.loc[years].fillna(0) - lever_sum[lever]
        emit(market_lever_column(lever, MARKET_CROSS_MIX), residual)

    output_data = {name: _denoise(series) for name, series in output_data.items()}
    self._store_outputs(output_data)

    return output_data

DetailedCo2EmissionsPerOperationalConcept

DetailedCo2EmissionsPerOperationalConcept(
    name="detailed_co2_emissions_per_operational_concept",
    operations_manager=None,
    *args,
    **kwargs,
)

Bases: AeroMAPSModel

Class to decompose the "fleet operations" lever of action into sub-levers, one per operational concept (and one per category of concepts) declared in the generic operations module.

The operations lever of DetailedCo2Emissions is proportional to the aggregate operations_gain: emissions including operations equal emissions including aircraft efficiency scaled by 1 - operations_gain / 100, for passenger and freight alike. The lever is therefore shared between concepts in proportion to their contribution to operations_gain as attributed by OperationsUseChoice (logarithmic share, order independent). A residual term keeps the sum of the sub-levers equal to the global lever by construction; it is zero unless the operational gain is applied differently to some traffic.

Parameters:

Name Type Description Default
name str

Name of the model instance ('detailed_co2_emissions_per_operational_concept' by default).

'detailed_co2_emissions_per_operational_concept'
operations_manager OperationalConceptManager

Manager enumerating the operational concepts and their categories.

None

Attributes:

Name Type Description
input_names dict

Dictionary of input variable names populated at model initialisation before MDA chain creation.

output_names dict

Dictionary of output variable names populated at model initialisation before MDA chain creation.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
def __init__(
    self,
    name="detailed_co2_emissions_per_operational_concept",
    operations_manager=None,
    *args,
    **kwargs,
):
    super().__init__(name=name, model_type="custom", *args, **kwargs)
    # Metadata only (not a coupling variable).
    self.operations_manager = operations_manager

    self.input_names = {
        "co2_emissions_including_aircraft_efficiency": pd.Series([0.0]),
        "co2_emissions_including_operations": pd.Series([0.0]),
        "operations_gain": pd.Series([0.0]),
    }
    self.output_names = {
        operations_concept_column(OPERATIONS_OTHER): pd.Series([0.0]),
    }
    for concept in self._fuel_concepts():
        self.input_names[f"{concept.name}_operations_gain_contribution"] = pd.Series([0.0])
        self.output_names[operations_concept_column(concept.name)] = pd.Series([0.0])
    for category in self._categories():
        self.output_names[operations_category_column(category)] = pd.Series([0.0])

compute

compute(input_data)

Execute the decomposition of the operations lever of action per operational concept.

Parameters:

Name Type Description Default
input_data

Dictionary containing all input data required for the computation, completed at model instantiation with information from yaml files and outputs of other models.

required

Returns:

Type Description
output_data

Dictionary containing, for each concept and each category, the annual CO2 emissions avoided [MtCO2], plus a residual term.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
def compute(self, input_data) -> dict:
    """
    Execute the decomposition of the operations lever of action per operational concept.

    Parameters
    ----------
    input_data
        Dictionary containing all input data required for the computation, completed at model instantiation with information from yaml files and outputs of other models.

    Returns
    -------
    output_data
        Dictionary containing, for each concept and each category, the annual CO2
        emissions avoided [MtCO2], plus a residual term.
    """
    output_data = {}

    reference_year = self.prospection_start_year - 1
    years = pd.Index(range(reference_year, self.end_year + 1))

    total_lever = (
        (
            input_data["co2_emissions_including_aircraft_efficiency"]
            - input_data["co2_emissions_including_operations"]
        )
        .loc[years]
        .fillna(0)
    )
    operations_gain = input_data["operations_gain"].reindex(years).fillna(0)

    def emit(name, series):
        out = get_default_series(
            self.historic_start_year, self.end_year, fill_value=float("nan")
        )
        out.loc[years] = series
        output_data[name] = out

    cumulated = pd.Series(0.0, index=years)
    per_category = {category: pd.Series(0.0, index=years) for category in self._categories()}
    for concept in self._fuel_concepts():
        contribution = (
            input_data[f"{concept.name}_operations_gain_contribution"].reindex(years).fillna(0)
        )
        share = (contribution / operations_gain).where(operations_gain != 0, 0.0)
        sub_lever = total_lever * share
        emit(operations_concept_column(concept.name), sub_lever)
        cumulated = cumulated + sub_lever
        if concept.category in per_category:
            per_category[concept.category] = per_category[concept.category] + sub_lever

    for category, values in per_category.items():
        emit(operations_category_column(category), values)
    emit(operations_concept_column(OPERATIONS_OTHER), total_lever - cumulated)

    output_data = {name: _denoise(series) for name, series in output_data.items()}
    self._store_outputs(output_data)

    return output_data

SimpleCO2Emissions

SimpleCO2Emissions(
    name="simple_co2_emissions", *args, **kwargs
)

Bases: AeroMAPSModel

Class to compute simple CO2 emissions.

Parameters:

Name Type Description Default
name str

Name of the model instance ('simple_co2_emissions' by default).

'simple_co2_emissions'
Source code in aeromaps/models/impacts/emissions/co2_emissions.py
1780
1781
1782
def __init__(self, name="simple_co2_emissions", *args, **kwargs):
    super().__init__(name=name, *args, **kwargs)
    self.climate_historical_data = None

compute

compute(
    energy_consumption_init,
    dropin_fuel_mean_co2_emission_factor,
    hydrogen_mean_co2_emission_factor,
    electric_mean_co2_emission_factor,
    energy_consumption_dropin_fuel,
    energy_consumption_hydrogen,
    energy_consumption_electricity,
)

Simple CO2 emissions calculation

Parameters:

Name Type Description Default
energy_consumption_init Series

Historical energy consumption of aviation over 2000-2019 [MJ].

required
dropin_fuel_mean_co2_emission_factor Series

Mean CO2 emission factor for drop-in fuels [gCO2/MJ].

required
hydrogen_mean_co2_emission_factor Series

Mean CO2 emission factor for hydrogen [gCO2/MJ].

required
electric_mean_co2_emission_factor Series

Mean CO2 emission factor for electric aviation [gCO2/MJ].

required
energy_consumption_dropin_fuel Series

Energy consumption in the form of drop-in fuels from all commercial air transport [MJ].

required
energy_consumption_hydrogen Series

Energy consumption in the form of hydrogen from all commercial air transport [MJ].

required
energy_consumption_electricity Series

Energy consumption in the form of electricity from all commercial air transport [MJ].

required

Returns:

Type Description
co2_emissions

CO2 emissions from all commercial air transport [MtCO2].

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
def compute(
    self,
    energy_consumption_init: pd.Series,
    dropin_fuel_mean_co2_emission_factor: pd.Series,
    hydrogen_mean_co2_emission_factor: pd.Series,
    electric_mean_co2_emission_factor: pd.Series,
    energy_consumption_dropin_fuel: pd.Series,
    energy_consumption_hydrogen: pd.Series,
    energy_consumption_electricity: pd.Series,
) -> pd.Series:
    """
    Simple CO2 emissions calculation

    Parameters
    ----------
    energy_consumption_init
        Historical energy consumption of aviation over 2000-2019 [MJ].
    dropin_fuel_mean_co2_emission_factor
        Mean CO2 emission factor for drop-in fuels [gCO2/MJ].
    hydrogen_mean_co2_emission_factor
        Mean CO2 emission factor for hydrogen [gCO2/MJ].
    electric_mean_co2_emission_factor
        Mean CO2 emission factor for electric aviation [gCO2/MJ].
    energy_consumption_dropin_fuel
        Energy consumption in the form of drop-in fuels from all commercial air transport [MJ].
    energy_consumption_hydrogen
        Energy consumption in the form of hydrogen from all commercial air transport [MJ].
    energy_consumption_electricity
        Energy consumption in the form of electricity from all commercial air transport [MJ].

    Returns
    -------
    co2_emissions
        CO2 emissions from all commercial air transport [MtCO2].
    """

    ## Initialization
    historical_co2_emissions_for_temperature = self.climate_historical_data[:, 1]

    # Calculation
    for k in range(self.climate_historic_start_year, self.historic_start_year):
        self.df_climate.loc[k, "co2_emissions"] = historical_co2_emissions_for_temperature[
            k - self.climate_historic_start_year
        ]

    for k in range(self.historic_start_year, self.prospection_start_year):
        self.df_climate.loc[k, "co2_emissions"] = (
            dropin_fuel_mean_co2_emission_factor.loc[k]
            / 10**12
            * energy_consumption_init.loc[k]
        )

    for k in range(self.prospection_start_year, self.end_year + 1):
        self.df_climate.loc[k, "co2_emissions"] = (
            dropin_fuel_mean_co2_emission_factor.loc[k]
            / 10**12
            * energy_consumption_dropin_fuel.loc[k]
            + electric_mean_co2_emission_factor.loc[k]
            / 10**12
            * energy_consumption_electricity.loc[k]
            + hydrogen_mean_co2_emission_factor.loc[k]
            / 10**12
            * energy_consumption_hydrogen.loc[k]
        )

    co2_emissions = self.df_climate.loc[:, "co2_emissions"]

    return co2_emissions

slugify

slugify(name)

Convert an arbitrary name (aircraft, category...) into a valid variable name chunk.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
17
18
19
def slugify(name: str) -> str:
    """Convert an arbitrary name (aircraft, category...) into a valid variable name chunk."""
    return re.sub(r"[^0-9a-zA-Z]+", "_", name).strip("_").lower()

efficiency_sub_lever_column

efficiency_sub_lever_column(name)

Output column of a named efficiency sub-lever (fleet renewal, freight...).

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
29
30
31
def efficiency_sub_lever_column(name: str) -> str:
    """Output column of a named efficiency sub-lever (fleet renewal, freight...)."""
    return f"co2_emissions_lever_efficiency_{name}"

aircraft_efficiency_column

aircraft_efficiency_column(aircraft_slug)

Output column holding the contribution of one aircraft to the efficiency lever.

The aircraft segment keeps these columns apart from the per-market ones (..._efficiency_market_<id>), so consumers never have to filter by prefix.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
34
35
36
37
38
39
40
def aircraft_efficiency_column(aircraft_slug: str) -> str:
    """Output column holding the contribution of one aircraft to the efficiency lever.

    The ``aircraft`` segment keeps these columns apart from the per-market ones
    (``..._efficiency_market_<id>``), so consumers never have to filter by prefix.
    """
    return f"co2_emissions_lever_efficiency_aircraft_{aircraft_slug}"

pathway_energy_column

pathway_energy_column(pathway)

Output column holding the contribution of one energy pathway to the energy lever.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
43
44
45
def pathway_energy_column(pathway: str) -> str:
    """Output column holding the contribution of one energy pathway to the energy lever."""
    return f"co2_emissions_lever_energy_pathway_{pathway}"

aircraft_efficiency_lever_names

aircraft_efficiency_lever_names(fleet)

Map each aircraft of a fleet to the name of the output variable containing its contribution to the aircraft efficiency lever of action.

Used both by DetailedCo2EmissionsPerAircraft and by the plots so that variable names are built consistently.

Parameters:

Name Type Description Default
fleet

Fleet instance containing the fleet structure and aircraft definitions.

required

Returns:

Type Description
lever_names

Dictionary mapping (category name, subcategory name, aircraft name) tuples to output variable names.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
def aircraft_efficiency_lever_names(fleet) -> dict:
    """
    Map each aircraft of a fleet to the name of the output variable containing its
    contribution to the aircraft efficiency lever of action.

    Used both by DetailedCo2EmissionsPerAircraft and by the plots so that variable
    names are built consistently.

    Parameters
    ----------
    fleet
        Fleet instance containing the fleet structure and aircraft definitions.

    Returns
    -------
    lever_names
        Dictionary mapping (category name, subcategory name, aircraft name) tuples
        to output variable names.
    """
    lever_names = {}
    for category in fleet.categories.values():
        for subcategory in category.subcategories.values():
            for aircraft in subcategory.aircraft.values():
                lever_name = aircraft_efficiency_column(
                    f"{slugify(category.name)}_{slugify(aircraft.name)}"
                )
                if lever_name in lever_names.values():
                    lever_name = aircraft_efficiency_column(
                        f"{slugify(category.name)}_{slugify(subcategory.name)}_"
                        f"{slugify(aircraft.name)}"
                    )
                lever_names[(category.name, subcategory.name, aircraft.name)] = lever_name
    return lever_names

aircraft_efficiency_sub_lever_columns

aircraft_efficiency_sub_lever_columns(fleet)

All columns of the per-aircraft decomposition of the efficiency lever.

Named sub-levers first (fleet renewal, continuous improvement, freight, residual), then one column per aircraft of fleet. Their sum is the global efficiency lever.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
83
84
85
86
87
88
89
90
91
def aircraft_efficiency_sub_lever_columns(fleet) -> list:
    """All columns of the per-aircraft decomposition of the efficiency lever.

    Named sub-levers first (fleet renewal, continuous improvement, freight, residual),
    then one column per aircraft of ``fleet``. Their sum is the global efficiency lever.
    """
    return [efficiency_sub_lever_column(name) for name in EFFICIENCY_SUB_LEVERS] + list(
        aircraft_efficiency_lever_names(fleet).values()
    )

pathway_energy_sub_lever_columns

pathway_energy_sub_lever_columns(pathways_manager)

All columns of the per-pathway decomposition of the energy lever, residual last.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
94
95
96
97
98
def pathway_energy_sub_lever_columns(pathways_manager) -> list:
    """All columns of the per-pathway decomposition of the energy lever, residual last."""
    return [pathway_energy_column(pathway.name) for pathway in pathways_manager.get_all()] + [
        ENERGY_SUB_LEVER_OTHER
    ]

market_lever_column

market_lever_column(lever, market)

Output column holding the contribution of market to the CO2 lever.

Single source of truth for the per-market decomposition variable names, shared by DetailedCo2EmissionsPerMarket, its plot and the tests so that the naming never drifts and consumers never have to guess it via prefix matching.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
110
111
112
113
114
115
116
117
def market_lever_column(lever: str, market: str) -> str:
    """Output column holding the contribution of `market` to the CO2 `lever`.

    Single source of truth for the per-market decomposition variable names, shared
    by DetailedCo2EmissionsPerMarket, its plot and the tests so that the naming
    never drifts and consumers never have to guess it via prefix matching.
    """
    return f"co2_emissions_lever_{lever}_market_{market}"

market_lever_names

market_lever_names(markets)

Map each (lever, market) pair to its per-market decomposition output column.

Parameters:

Name Type Description Default
markets

MarketManager enumerating the passenger and freight markets.

required

Returns:

Type Description
names

Dictionary mapping (lever, market_id) tuples — plus (lever, "cross_mix") for the cross-market-mix residual of each lever — to output variable names.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
def market_lever_names(markets) -> dict:
    """
    Map each (lever, market) pair to its per-market decomposition output column.

    Parameters
    ----------
    markets
        MarketManager enumerating the passenger and freight markets.

    Returns
    -------
    names
        Dictionary mapping ``(lever, market_id)`` tuples — plus
        ``(lever, "cross_mix")`` for the cross-market-mix residual of each lever —
        to output variable names.
    """
    names = {}
    for market in markets.get(traffic_type="passenger"):
        for lever in MARKET_LEVERS_PASSENGER:
            names[(lever, market.id)] = market_lever_column(lever, market.id)
    for market in markets.get(traffic_type="freight"):
        for lever in MARKET_LEVERS_FREIGHT:
            names[(lever, market.id)] = market_lever_column(lever, market.id)
    for lever in MARKET_LEVERS_PASSENGER:
        names[(lever, MARKET_CROSS_MIX)] = market_lever_column(lever, MARKET_CROSS_MIX)
    return names

market_lever_dataframe

market_lever_dataframe(df, markets)

Reshape the flat per-market lever columns of df into a tidy view.

The returned DataFrame keeps the years index of df and carries a (lever, market) MultiIndex on its columns, so the multidimensional decomposition can be filtered efficiently, e.g.::

per_market = market_lever_dataframe(df, markets)
per_market.xs("energy", level="lever", axis=1)      # all markets, energy lever
per_market.xs("short_range", level="market", axis=1)  # all levers, one market

Columns absent from df (e.g. freight has no load factor lever) are simply omitted.

Parameters:

Name Type Description Default
df DataFrame

Vector-outputs DataFrame produced by a computed process.

required
markets

MarketManager enumerating the passenger and freight markets.

required

Returns:

Type Description
tidy

DataFrame with a (lever, market) column MultiIndex.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
def market_lever_dataframe(df: pd.DataFrame, markets) -> pd.DataFrame:
    """
    Reshape the flat per-market lever columns of `df` into a tidy view.

    The returned DataFrame keeps the years index of `df` and carries a
    ``(lever, market)`` MultiIndex on its columns, so the multidimensional
    decomposition can be filtered efficiently, e.g.::

        per_market = market_lever_dataframe(df, markets)
        per_market.xs("energy", level="lever", axis=1)      # all markets, energy lever
        per_market.xs("short_range", level="market", axis=1)  # all levers, one market

    Columns absent from `df` (e.g. freight has no load factor lever) are simply
    omitted.

    Parameters
    ----------
    df
        Vector-outputs DataFrame produced by a computed process.
    markets
        MarketManager enumerating the passenger and freight markets.

    Returns
    -------
    tidy
        DataFrame with a ``(lever, market)`` column MultiIndex.
    """
    names = market_lever_names(markets)
    data = {key: df[column] for key, column in names.items() if column in df.columns}
    tidy = pd.DataFrame(data, index=df.index)
    if not tidy.empty:
        tidy.columns = pd.MultiIndex.from_tuples(tidy.columns, names=["lever", "market"])
    return tidy

operations_concept_column

operations_concept_column(concept)

Output column holding the contribution of an operational concept to the operations lever.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
187
188
189
def operations_concept_column(concept: str) -> str:
    """Output column holding the contribution of an operational concept to the operations lever."""
    return f"co2_emissions_lever_operations_concept_{concept}"

operations_category_column

operations_category_column(category)

Output column holding the contribution of an operational category to the operations lever.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
192
193
194
def operations_category_column(category: str) -> str:
    """Output column holding the contribution of an operational category to the operations lever."""
    return f"co2_emissions_lever_operations_category_{category}"

offset_scheme_column

offset_scheme_column(scheme)

Output column holding the offset quantity of one offsetting scheme [MtCO2].

The carbon offset is the plain sum of its schemes, so these columns are the sub-levers of the offsetting lever of the CO2 cascade with no residual term.

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
197
198
199
200
201
202
203
def offset_scheme_column(scheme: str) -> str:
    """Output column holding the offset quantity of one offsetting scheme [MtCO2].

    The carbon offset is the plain sum of its schemes, so these columns are the
    sub-levers of the offsetting lever of the CO2 cascade with no residual term.
    """
    return f"co2_emissions_lever_offset_scheme_{scheme}"

offset_category_column

offset_category_column(category)

Output column holding the offset quantity of one category of schemes [MtCO2].

Source code in aeromaps/models/impacts/emissions/co2_emissions.py
206
207
208
def offset_category_column(category: str) -> str:
    """Output column holding the offset quantity of one category of schemes [MtCO2]."""
    return f"co2_emissions_lever_offset_category_{category}"