Skip to content

Commit

Permalink
Fix #4
Browse files Browse the repository at this point in the history
  • Loading branch information
cmutel committed Jul 5, 2024
1 parent 1450e86 commit 5499ab9
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 10 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ To create custom allocation functions which apply a single allocation factor to

* edge_data (dict): Data on functional edge
* node: An instance of `multifunctional.MaybeMultifunctionalProcess`
* strategy_label: An optional string to label the allocation strategy used

The custom function should return a number.

Expand All @@ -106,7 +107,11 @@ def allocation_factor(edge_data: dict, node: mf.MaybeMultifunctionalProcess) ->
else:
return 7

mf.allocation_strategies['silly'] = partial(mf.generic_allocation, func=allocation_factor)
mf.allocation_strategies['silly'] = partial(
mf.generic_allocation,
func=allocation_factor,
strategy_label="something silly"
)
```

### Other custom allocation functions
Expand Down
21 changes: 15 additions & 6 deletions multifunctional/allocation.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
from copy import deepcopy
from functools import partial
from typing import Callable, List
from typing import Callable, List, Optional
from uuid import uuid4

from bw2data import get_node
from bw2data.errors import UnknownObject
from bw2io.utils import rescale_exchange
from loguru import logger
from bw2data.errors import UnknownObject
from bw2data import get_node

from .node_classes import (
MaybeMultifunctionalProcess,
ReadOnlyProcessWithReferenceProduct,
)


def generic_allocation(act: MaybeMultifunctionalProcess, func: Callable) -> List[dict]:
def generic_allocation(
act: MaybeMultifunctionalProcess,
func: Callable,
strategy_label: Optional[str] = None,
) -> List[dict]:
"""Allocation by single allocation factor generated by `func`.
Allocation amount is edge amount times function(edge_data, act) divided by sum of all edge
Expand Down Expand Up @@ -74,22 +78,26 @@ def generic_allocation(act: MaybeMultifunctionalProcess, func: Callable) -> List
)

try:
assert not exc.get('mf_artificial_code')
assert not exc.get("mf_artificial_code")
product = get_node(database=exc["input"][0], code=exc["input"][1])
except (KeyError, UnknownObject, AssertionError):
product = None

allocated_process = deepcopy(act._data)
if "id" in allocated_process:
del allocated_process["id"]
if strategy_label:
allocated_process["mf_strategy_label"] = strategy_label
allocated_process["code"] = process_code
allocated_process["multifunctional_parent_id"] = act.id
allocated_process["type"] = "readonly_process"

if "name" in exc:
allocated_process["reference product"] = exc["name"]
elif product:
allocated_process["reference product"] = product.get("name", "(unnamed product)")
allocated_process["reference product"] = product.get(
"name", "(unnamed product)"
)
else:
allocated_process["reference product"] = "(unnamed)"

Expand Down Expand Up @@ -141,6 +149,7 @@ def property_allocation(property_label: str) -> Callable:
func=partial(
get_allocation_factor_from_property, property_label=property_label
),
strategy_label=f"property allocation by '{property_label}'"
)


Expand Down
11 changes: 11 additions & 0 deletions tests/test_allocation.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,17 @@ def test_without_allocation(basic):
assert nodes[1][key] == value


def test_price_allocation_strategy_label(basic):
basic.metadata["default_allocation"] = "price"
bd.get_node(code="1").allocate()
nodes = sorted(basic, key=lambda x: (x["name"], x.get("reference product", "")))

assert not nodes[0].get("mf_strategy_label")
assert not nodes[1].get("mf_strategy_label")
assert nodes[2].get("mf_strategy_label") == "property allocation by 'price'"
assert nodes[3].get("mf_strategy_label") == "property allocation by 'price'"


def test_price_allocation(basic):
basic.metadata["default_allocation"] = "price"
bd.get_node(code="1").allocate()
Expand Down
12 changes: 9 additions & 3 deletions tests/test_allocation_with_products.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@


def check_products_allocation_results(factor_1, factor_2, database):
nodes = sorted(database, key=lambda x: (x["name"], x.get("reference product", ""), x["type"]))
nodes = sorted(
database, key=lambda x: (x["name"], x.get("reference product", ""), x["type"])
)

assert isinstance(nodes[0], MaybeMultifunctionalProcess)
assert nodes[0]["name"] == "first product"
Expand Down Expand Up @@ -105,7 +107,9 @@ def check_products_allocation_results(factor_1, factor_2, database):


def test_without_allocation(products):
nodes = sorted(products, key=lambda x: (x["name"], x.get("reference product", ""), x["type"]))
nodes = sorted(
products, key=lambda x: (x["name"], x.get("reference product", ""), x["type"])
)

assert len(nodes) == 3

Expand Down Expand Up @@ -162,7 +166,9 @@ def test_allocation_uses_existing(products):
def test_allocation_already_allocated(products):
products.metadata["default_allocation"] = "price"
bd.get_node(code="1").allocate()
node = sorted(products, key=lambda x: (x["name"], x.get("reference product", "")))[3]
node = sorted(products, key=lambda x: (x["name"], x.get("reference product", "")))[
3
]

assert generic_allocation(node, None) == []

Expand Down

0 comments on commit 5499ab9

Please sign in to comment.