Skip to content

aeromaps.models.impacts.life_cycle_assessment.life_cycle_assessment

Model for Life Cycle Assessment (LCA) of air transportation systems

LifeCycleAssessment

LifeCycleAssessment(name='life_cycle_assessment', configuration_file=None, split_by=None, *args, **kwargs)

Bases: AeroMAPSModel

Life Cycle Assessment (LCA) model to compute multiple environmental impacts beyond climate change.

This model requires a valid ecoinvent license stored in a private '.env' file (that you will not share /commit) in the notebooks or project root folder, containing the following variables: ECOINVENT_LOGIN= ECOINVENT_PASSWORD=

This model uses the lca_modeller library to build a parametric LCA model from a user-provided configuration file, and the lca_algebraic library (a layer on top of brightway) to compute LCA results efficiently for multiple years. The life cycle inventory relies on the ecoinvent database, projected to future years using the premise library.

Parameters:

Name Type Description Default
name str

Name of the model instance.

'life_cycle_assessment'
configuration_file str

Path to the LCA configuration file defining the model and LCIA methods.

None
split_by str

Axis to split impacts by (typically, "phase"). Should match an axis defined in the configuration file through the "attribute" field.

None

Attributes:

Name Type Description
model Activity

The parametric LCA model representative of air transport, generated from the configuration file.

methods list

List of LCIA methods to compute.

axis str

Optional axis to get contributors to impacts (typically, "phase").

params_names list

List of LCA parameter names used in the model, generated automatically from the LCA model definition.

xarray_lca DataArray

The full LCA results stored as an xarray DataArray after computation.

lambdas list

List of symbolic expressions for LCIA impacts, precomputed for efficiency.

Source code in aeromaps/models/impacts/life_cycle_assessment/life_cycle_assessment.py
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
def __init__(
    self,
    name: str = "life_cycle_assessment",
    configuration_file: str = None,
    split_by: str = None,
    *args,
    **kwargs,
):
    super().__init__(
        name=name,
        model_type="custom",
        *args,
        **kwargs,
    )

    # Get LCA model and LCIA methods
    if configuration_file is None:
        raise ValueError("Configuration file is missing.")
    _, model, methods = LCAProblemConfigurator(configuration_file).generate()
    self.model = model
    self.methods = methods
    self.axis = split_by
    self.params_names = agb.all_params().keys()
    self.xarray_lca = xr.DataArray()

    # --- Add LCA parameters as inputs of this AeroMAPSModel ---
    self._skip_data_type_validation = True  # see aeromaps/core/gemseo.py
    self.input_names = []
    self.output_names = []

    for x in self.params_names:
        # Years of simulation are directly taken from AeroMAPS timeline and not as an input parameter
        if x == KEY_YEAR:
            continue

        self.input_names.append(x)
        self.input_names.append(x + "_reference_years")
        self.input_names.append(x + "_reference_years_values")

        self.default_input_data[x] = np.nan
        self.default_input_data[x + "_reference_years"] = np.nan
        self.default_input_data[x + "_reference_years_values"] = np.nan

    # Dry run with lca_algebraic to build symbolic expressions of LCIA impacts
    print("Parametrizing LCIA impacts...", end=" ")
    self.lambdas = agb.lca._preMultiLCAAlgebric(self.model, self.methods, axis=self.axis)
    print("Done.")

    # --- Add LCA impact categories the outputs to the AeroMAPSModel ---
    if getattr(self.lambdas[0], "axis_keys", None):
        for method in self.methods:
            for phase in self.lambdas[0].axis_keys:
                method_with_axis = method + (phase,)
                self.output_names.append(tuple_to_varname(method_with_axis))
    else:
        for method in self.methods:
            self.output_names.append(tuple_to_varname(method))

compute

compute(input_data)

Compute LCA impacts for the given input parameters.

Parameters:

Name Type Description Default
input_data dict

Dictionary containing values for LCA parameters.

required

Returns:

Type Description
dict

Dictionary containing computed LCA impacts as pd.Series (one per impact category).

Source code in aeromaps/models/impacts/life_cycle_assessment/life_cycle_assessment.py
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
def compute(self, input_data) -> dict:
    """
    Compute LCA impacts for the given input parameters.

    Parameters
    ----------
    input_data : dict
        Dictionary containing values for LCA parameters.

    Returns
    -------
    dict
        Dictionary containing computed LCA impacts as pd.Series (one per impact category).
    """
    # --- Assign values to parameters ---
    params_dict = self._get_param_values(input_data)

    # --- Calculate impacts for all parameters at once ---
    res = self._multi_lca_algebraic_raw(**params_dict)

    # --- Store xarray to enable user to access data after process calculation ---
    res["params"] = params_dict[KEY_YEAR]  # replace param index by actual years
    res = res.rename({"params": KEY_YEAR})  # rename 'params' dimension to 'year'
    self.xarray_lca = res

    # --- Convert xarray to pd.Series to enable connection with other models ---
    output_data = self._convert_xarray_to_series(res)
    self._store_outputs(output_data)

    return output_data

tuple_to_varname

tuple_to_varname(items)

Convert a tuple or list of strings into a clean, Python-friendly variable name.

Parameters:

Name Type Description Default
items tuple or list

The tuple or list of strings to convert.

required

Returns:

Type Description
str

A cleaned variable name string.

Source code in aeromaps/models/impacts/life_cycle_assessment/life_cycle_assessment.py
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
def tuple_to_varname(items):
    """
    Convert a tuple or list of strings into a clean, Python-friendly variable name.

    Parameters
    ----------
    items : tuple or list
        The tuple or list of strings to convert.

    Returns
    -------
    str
        A cleaned variable name string.
    """
    if isinstance(items, (list, tuple)):
        text = "__".join(items)  # join parts with double underscores
    else:
        text = str(items)

    # Lowercase everything
    text = text.lower()

    # Replace anything that’s not alphanumeric or underscore with underscore
    text = re.sub(r"[^0-9a-zA-Z_]+", "_", text)

    # Remove leading/trailing underscores and collapse multiple underscores
    text = re.sub(r"_+", "_", text).strip("_")

    # Add lca to variable
    text = "lca_" + text

    return text

is_not_nan

is_not_nan(x)

Return True if x is not NaN or None. Handles single values and arrays/lists.

Parameters:

Name Type Description Default
x any

The input to check.

required

Returns:

Type Description
bool

True if x is not NaN or None, False otherwise.

Source code in aeromaps/models/impacts/life_cycle_assessment/life_cycle_assessment.py
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
def is_not_nan(x):
    """
    Return True if x is not NaN or None. Handles single values and arrays/lists.

    Parameters
    ----------
    x : any
        The input to check.

    Returns
    -------
    bool
        True if x is not NaN or None, False otherwise.
    """
    if x is None:
        return False
    if isinstance(x, (float, int, np.number)):
        return not pd.isna(x)
    if isinstance(x, (pd.Series, np.ndarray, list, tuple)):
        return pd.notna(np.asarray(x)).any()
    return True