Skip to content

Commit

Permalink
Merge pull request #34 from brightway-lca/use_matrix_values
Browse files Browse the repository at this point in the history
Use matrix values instead of database amount. Fixes #11.
  • Loading branch information
cmutel committed Oct 9, 2023
2 parents 0040cf5 + 4fbf2b6 commit f3ff700
Show file tree
Hide file tree
Showing 3 changed files with 1,278 additions and 10 deletions.
63 changes: 53 additions & 10 deletions bw_temporalis/lca.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from collections.abc import Iterable
from datetime import datetime
from heapq import heappop, heappush
from typing import Union

import bw2data as bd
import numpy as np
Expand All @@ -12,6 +13,7 @@
from bw_graph_tools import NewNodeEachVisitGraphTraversal

from .temporal_distribution import TDAware
from .temporal_distribution import TemporalDistribution
from .temporal_distribution import TemporalDistribution as TD
from .timeline import Timeline

Expand Down Expand Up @@ -141,22 +143,32 @@ def build_timeline(self) -> Timeline:
for exchange in self.get_biosphere_exchanges(
flow.flow_datapackage_id, node.activity_datapackage_id
):
value = self._exchange_value(exchange)
value = self._exchange_value(
exchange=exchange,
row_id=flow.flow_datapackage_id,
col_id=node.activity_datapackage_id,
matrix_label="biosphere_matrix",
)
timeline.add_flow_temporal_distribution(
td=(td * value).simplify(),
flow=flow.flow_datapackage_id,
activity=node.activity_datapackage_id,
)

for edge in self.edge_mapping[node.unique_id]:
row_id = self.nodes[edge.producer_unique_id].activity_datapackage_id
col_id = node.activity_datapackage_id
exchange = self.get_technosphere_exchange(
input_id=self.nodes[
edge.producer_unique_id
].activity_datapackage_id,
output_id=node.activity_datapackage_id,
input_id=row_id,
output_id=col_id,
)
value = (
self._exchange_value(exchange)
self._exchange_value(
exchange=exchange,
row_id=row_id,
col_id=col_id,
matrix_label="technosphere_matrix",
)
/ node.reference_product_production_amount
)
producer = self.nodes[edge.producer_unique_id]
Expand All @@ -170,7 +182,13 @@ def build_timeline(self) -> Timeline:
)
return timeline

def _exchange_value(self, exchange):
def _exchange_value(
self,
exchange: bd.backends.ExchangeDataset,
row_id: int,
col_id: int,
matrix_label: str,
) -> Union[float, TemporalDistribution]:
from . import loader_registry

td = exchange.data.get("temporal_distribution")
Expand All @@ -189,10 +207,35 @@ def _exchange_value(self, exchange):
f"Can't understand value for `temporal_distribution` in exchange {exchange}"
)

sign = (
1
if exchange.data["type"] not in ("generic consumption", "technosphere")
else -1
)

if matrix_label == "technosphere_matrix":
amount = (
sign
* self.lca_object.technosphere_matrix[
self.lca_object.dicts.product[row_id],
self.lca_object.dicts.activity[col_id],
]
)
elif matrix_label == "biosphere_matrix":
amount = (
exchange.data.get("fraction", 1)
* self.lca_object.biosphere_matrix[
self.lca_object.dicts.biosphere[row_id],
self.lca_object.dicts.activity[col_id],
]
)
else:
raise ValueError(f"Unknown matrix type {matrix_label}")

if td is None:
return exchange.data["amount"]
return amount
else:
return td * exchange.data["amount"]
return td * amount

def _exchange_iterator(self, input_id: int, output_id: int) -> list[ED]:
inp = AD.get(AD.id == input_id)
Expand All @@ -211,7 +254,7 @@ def get_biosphere_exchanges(self, flow_id: int, activity_id: int) -> Iterable[ED
if len(exchanges) > 1:
total = sum(exc.data["amount"] for exc in exchanges)
for exc in exchanges:
exc.data["amount"] /= total
exc.data["fraction"] = exc.data["amount"] / total
yield exc
else:
yield from exchanges
Expand Down
1,106 changes: 1,106 additions & 0 deletions dev/Speed tests.ipynb

Large diffs are not rendered by default.

119 changes: 119 additions & 0 deletions tests/test_lca.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,3 +252,122 @@ def test_temporalis_lca(basic_db):
expected_df.reset_index(drop=True, inplace=True)

pd.testing.assert_frame_equal(given_df, expected_df)


def test_temporalis_lca_draw_from_matrix(basic_db):
lca = LCA({("db", "A"): 2}, ("m",))
lca.lci()
lca.lcia()

assert lca.score == 410

A = bd.get_node(code="A").id
B = bd.get_node(code="B").id

assert lca.technosphere_matrix[lca.dicts.product[B], lca.dicts.activity[A]] == -5
lca.technosphere_matrix[lca.dicts.product[B], lca.dicts.activity[A]] = -10

tlca = TemporalisLCA(
lca_object=lca,
starting_datetime="2023-01-01",
)

expected_flows = [
{
"flow_datapackage_id": 2, # CH4
"flow_index": 1,
"activity_unique_id": 2,
"activity_id": 5,
"activity_index": 2,
"amount": 20,
"score": 500,
},
{
"flow_datapackage_id": 1,
"flow_index": 0,
"activity_unique_id": 1,
"activity_id": 4,
"activity_index": 1,
"amount": 160,
"score": 160,
},
{
"flow_datapackage_id": 1,
"flow_index": 0,
"activity_unique_id": 3,
"activity_id": 6,
"activity_index": 3,
"amount": 160,
"score": 160,
},
]
expected_flows.sort(key=lambda x: x["score"], reverse=True)

assert len(tlca.flows) == 3
for a, b in zip(tlca.flows, expected_flows):
flow_equal_dict(a, b)

expected_nodes = [
{
"unique_id": -1,
"activity_datapackage_id": -1,
"activity_index": -1,
"reference_product_datapackage_id": -1,
"reference_product_index": -1,
"reference_product_production_amount": 1,
"supply_amount": 1,
"cumulative_score": 410,
"direct_emissions_score": 0,
},
{
"unique_id": 0,
"activity_datapackage_id": 3,
"activity_index": 0,
"reference_product_datapackage_id": 3,
"reference_product_index": 0,
"reference_product_production_amount": 1,
"supply_amount": 2,
"cumulative_score": 820,
"direct_emissions_score": 0,
},
{
"unique_id": 1,
"activity_datapackage_id": 4,
"activity_index": 1,
"reference_product_datapackage_id": 4,
"reference_product_index": 1,
"reference_product_production_amount": 1,
"supply_amount": 20,
"cumulative_score": 820,
"direct_emissions_score": 160,
},
{
"unique_id": 2,
"activity_datapackage_id": 5,
"activity_index": 2,
"reference_product_datapackage_id": 5,
"reference_product_index": 2,
"reference_product_production_amount": 1,
"supply_amount": 40,
"cumulative_score": 500,
"direct_emissions_score": 500,
},
{
"unique_id": 3,
"activity_datapackage_id": 6,
"activity_index": 3,
"reference_product_datapackage_id": 6,
"reference_product_index": 3,
"reference_product_production_amount": 1,
"supply_amount": 80,
"cumulative_score": 160,
"direct_emissions_score": 160,
},
]

import pprint

for a in expected_nodes:
pprint.pprint(tlca.nodes[a["unique_id"]])
pprint.pprint(a)
node_equal_dict(tlca.nodes[a["unique_id"]], a)

0 comments on commit f3ff700

Please sign in to comment.