TRACI v2.2 was released on March 2, 2022. The latest version of ecoinvent (3.11) includes LCIA methodology for TRACI v2.1 but not v2.2. However, many North American PCRs already require TRACI v2.2 impact assessments, and more are likely follow.
To support this updated library, modern LCA platforms can incorporate TRACI v2.2 into their ecoinvent engine in a few ways:
Reverse-engineer OpenLCA’s TRACI v2.2 method
<aside> 🚨
Notice: While this approach should work in theory, the implementing party must verify the accuracy of the adapted method and make changes where necessary.
</aside>
OpenLCA includes an implementation of the TRACI v2.2 methodology (https://nexus.openlca.org/ws/files/36003). The latest version (Methods v2.7.5) includes ecoinvent v3.11 elementary flow mappings to TRACI v2.2 indicators. You can reverse-engineer these mappings and apply the characterization factors by extending ecoinvent's universal matrix output. A sample script to accomplish this is included below. Please note:
Sample Script
import json
openlca_traci22_fp = "~/Downloads/openLCA LCIA Methods 2.7.5 2025-06-13/lcia_methods/752a90f0-5db5-4c02-8208-a8414dbb153a.json"
openlca_cats_fp = "~/Downloads/openLCA LCIA Methods 2.7.5 2025-06-13/lcia_categories/"
openlca_flows_fp = "~/Downloads/openLCA LCIA Methods 2.7.5 2025-06-13/flows/"
ecoinvent_elementary_exchanges_fp = "~/Downloads/ecoinvent 3.11_cutoff_ecoSpold02/MasterData/ElementaryExchanges.xml"
import xml.etree.ElementTree as ET
NS = {"eco": "<http://www.EcoInvent.org/EcoSpold02>"}
# Build a dict of exchanges for quick lookup (name, compartment, subcompartment)
ecoinvent_flow_map = {}
try:
root = ET.parse(ecoinvent_elementary_exchanges_fp).getroot()
except (FileNotFoundError, OSError, ET.ParseError):
root = ET.fromstring(ecoinvent_elementary_exchanges_fp)
out = {}
for ee in root.findall(".//eco:elementaryExchange", NS):
eid = ee.get("id")
name_el = ee.find("eco:name", NS)
comp_wrap = ee.find("eco:compartment", NS)
comp_el = comp_wrap.find("eco:compartment", NS) if comp_wrap is not None else None
subcomp_el = comp_wrap.find("eco:subcompartment", NS) if comp_wrap is not None else None
ecoinvent_flow_map[eid] = (name_el.text, comp_el.text, subcomp_el.text)
# Load TRACI lcia, grab reference flows by impact
with open(openlca_traci22_fp) as f:
traci_data = json.load(f)
openlca_lcia_flow_map = {}
# flow_cache = {}
for cat in traci_data["impactCategories"]:
ref_id = cat["@id"]
openlca_lcia_flow_map[cat["name"]] = {
"id": ref_id,
"name": cat["name"],
"unit": cat["refUnit"],
"flows": []
}
with open(openlca_cats_fp + ref_id + ".json") as f:
cat_data = json.load(f)
# TODO - check for flow in openlca/ecoinvent flows?? And make sure units align?
for f in cat_data["impactFactors"]:
value = f['value']
flow = f["flow"]
flow_id = flow["@id"]
unit = flow["refUnit"]
if flow_id in ecoinvent_flow_map:
name, compartment, subcompartment = ecoinvent_flow_map[flow_id]
openlca_lcia_flow_map[cat["name"]]["flows"].append({
"id": flow_id,
"value": value,
"name": name,
"compartment": compartment,
"subcompartment": subcompartment
})
import pandas as pd
# Load ee index
universal_matrix_fp = "~/Downloads/universal_matrix_export_3.11_apos/"
ee_index_fp = universal_matrix_fp + "ee_index.csv"
lcia_index = universal_matrix_fp + "LCIA_index.csv"
C_index = universal_matrix_fp + "C.csv"
def _norm(x: object) -> str:
if pd.isna(x):
return ""
s = str(x).lower()
return s.strip()
def build_tuple_index(csv_path):
# auto-detect delimiter
df = pd.read_csv(csv_path, sep=None, engine="python")
required = ["name", "compartment", "subcompartment"]
missing = [c for c in required if c not in df.columns]
if missing:
raise ValueError(f"Missing required columns: {missing}. Present: {list(df.columns)}")
use_explicit_index = "index" in df.columns
mapping = {}
dup_overwrites = 0
for i, row in df.iterrows():
key = (
_norm(row["name"]),
_norm(row["compartment"]),
_norm(row["subcompartment"]),
)
idx_val = int(row["index"]) if use_explicit_index else int(i)
if key in mapping:
dup_overwrites += 1 # last-wins
mapping[key] = idx_val
return mapping
ee_map = build_tuple_index(ee_index_fp)
# Set indices of flows in lcia flow map, set new index number of added indicators
max_existing_indicator_index = 0
with open(lcia_index, "r") as f:
for i, line in enumerate(f):
if i > 0 and ";" in line:
max_existing_indicator_index = max(max_existing_indicator_index, int(line.split(";")[-1]))
for method, method_data in openlca_lcia_flow_map.items():
max_existing_indicator_index += 1
method_data["indicator_index"] = max_existing_indicator_index
method_data["flow_indices"] = []
for flow in method_data["flows"]:
key = (flow["name"].lower().strip(), flow["compartment"].lower().strip(), flow["subcompartment"].lower().strip())
value = flow["value"]
if key in ee_map:
method_data["flow_indices"].append((ee_map[key], value))
# Append new indices LCIA_index.csv
with open(lcia_index, "a") as f:
for method, method_data in openlca_lcia_flow_map.items():
indicator_index = method_data["indicator_index"]
line = f"TRACI v2.2;{method_data['name']};{method_data['name']};{method_data['unit']};{method_data['indicator_index']}"
f.write(line + "\\n")
# Append indicator/flow indices to C.csv
with open(C_index, "a") as f:
for method, method_data in openlca_lcia_flow_map.items():
indicator_index = method_data["indicator_index"]
for flow_index, value in method_data["flow_indices"]:
line = f"{indicator_index};{flow_index};{value}"
f.write(line + "\\n")