From 00c3c888ca78af56e4d1648c5096eb8f84e2b7b7 Mon Sep 17 00:00:00 2001 From: Chris Mutel Date: Sun, 7 Jul 2024 18:59:36 +0200 Subject: [PATCH] Manual allocation isn't normalized --- README.md | 2 +- multifunctional/allocation.py | 21 ++++++++++++++++----- tests/fixtures/basic.py | 2 ++ tests/test_allocation.py | 10 +++++++++- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index f0df9e7..71ba7d3 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ There is currently no built-in functionality to determine if an edge is function * `price`: Does economic allocation based on the property "price" in each functional edge. * `mass`: Does economic allocation based on the property "mass" in each functional edge. -* `manual`: Does economic allocation based on the property "manual" in each functional edge. +* `manual`: Does allocation based on the property "manual" in each functional edge. Doesn't normalize by amount of production exchange. * `equal`: Splits burdens equally among all functional edges. Property-based allocation assumes that each functional edge has a `properties` dictionary, and this dictionary has the relevant key with a corresponding numeric value. For example, for `price` allocation, each functional edge needs to have `'properties' = {'price': some_number}`. diff --git a/multifunctional/allocation.py b/multifunctional/allocation.py index f96d365..459949b 100644 --- a/multifunctional/allocation.py +++ b/multifunctional/allocation.py @@ -132,30 +132,41 @@ def generic_allocation( return processes -def get_allocation_factor_from_property(edge_data: dict, node: dict, property_label: str) -> float: +def get_allocation_factor_from_property( + edge_data: dict, node: dict, property_label: str, normalize_by_production_amount: bool = True +) -> float: if "properties" not in edge_data: raise KeyError( f"Edge {edge_data} from process {node.get('name')} (id {node.get('id')}) doesn't have properties" ) try: - return edge_data["amount"] * edge_data["properties"][property_label] + if normalize_by_production_amount: + return edge_data["amount"] * edge_data["properties"][property_label] + else: + return edge_data["properties"][property_label] except KeyError as err: raise KeyError( f"Edge {edge_data} from process {node.get('name')} (id {node.get('id')}) missing property {property_label}" ) from err -def property_allocation(property_label: str) -> Callable: +def property_allocation( + property_label: str, normalize_by_production_amount: bool = True +) -> Callable: return partial( generic_allocation, - func=partial(get_allocation_factor_from_property, property_label=property_label), + func=partial( + get_allocation_factor_from_property, + property_label=property_label, + normalize_by_production_amount=normalize_by_production_amount, + ), strategy_label=f"property allocation by '{property_label}'", ) allocation_strategies = { "price": property_allocation("price"), - "manual": property_allocation("manual"), + "manual": property_allocation("manual", normalize_by_production_amount=False), "mass": property_allocation("mass"), "equal": partial(generic_allocation, func=lambda x, y: 1.0), } diff --git a/tests/fixtures/basic.py b/tests/fixtures/basic.py index 3d3dbd6..1a5f498 100644 --- a/tests/fixtures/basic.py +++ b/tests/fixtures/basic.py @@ -22,6 +22,7 @@ "properties": { "price": 7, "mass": 6, + "manual": 2, }, }, { @@ -33,6 +34,7 @@ "properties": { "price": 12, "mass": 4, + "manual": 8, }, }, { diff --git a/tests/test_allocation.py b/tests/test_allocation.py index 9c8b7fb..409f8d3 100644 --- a/tests/test_allocation.py +++ b/tests/test_allocation.py @@ -140,6 +140,14 @@ def test_price_allocation(basic): ) +def test_manual_allocation(basic): + basic.metadata["default_allocation"] = "manual" + bd.get_node(code="1").allocate() + check_basic_allocation_results( + 0.2 * 10, 0.8 * 10, basic + ) + + def test_mass_allocation(basic): basic.metadata["default_allocation"] = "mass" bd.get_node(code="1").allocate() @@ -149,7 +157,7 @@ def test_mass_allocation(basic): def test_equal_allocation(basic): - basic.metadata["default_allocation"] = "mass" + basic.metadata["default_allocation"] = "equal" bd.get_node(code="1").allocate() check_basic_allocation_results(5, 5, basic)