From ba46049b8f78c58537de67e2e4eca8a08d21fc99 Mon Sep 17 00:00:00 2001 From: Chris Mutel Date: Sun, 16 Jun 2024 22:41:17 +0200 Subject: [PATCH] Evaluate allocation formulae --- bw_simapro_csv/blocks/process.py | 4 +++ bw_simapro_csv/blocks/products.py | 33 +++++++++++++---------- bw_simapro_csv/parameters.py | 45 ++++++++++++++++--------------- 3 files changed, 47 insertions(+), 35 deletions(-) diff --git a/bw_simapro_csv/blocks/process.py b/bw_simapro_csv/blocks/process.py index 7691669..4180ca3 100644 --- a/bw_simapro_csv/blocks/process.py +++ b/bw_simapro_csv/blocks/process.py @@ -148,10 +148,14 @@ def resolve_local_parameters(self, global_params: dict, substitutes: dict) -> No if not getattr(block, "has_formula", None): continue prepare_formulas(block.parsed, self.header) + prepare_formulas(block.parsed, self.header, formula_field="allocation_formula") for obj in block.parsed: if "formula" in obj: substitute_in_formulas(obj, visitor) obj["amount"] = interpreter(obj["formula"]) + if "allocation_formula" in obj: + substitute_in_formulas(obj, visitor, formula_field="allocation_formula") + obj["allocation"] = interpreter(obj["allocation_formula"]) if "field1" in obj: # We can only now construct and validate an uncertainty distribution, # because we finally have an `amount` field. diff --git a/bw_simapro_csv/blocks/products.py b/bw_simapro_csv/blocks/products.py index 05fe333..5753797 100644 --- a/bw_simapro_csv/blocks/products.py +++ b/bw_simapro_csv/blocks/products.py @@ -29,18 +29,23 @@ def __init__(self, block: list[tuple], header: dict, **kwargs): self.has_formula = True for line_no, line in skip_empty(block): - self.parsed.append( - add_amount_or_formula( - { - "name": line[0], - "unit": line[1], - "allocation_raw": line[3], - "waste_type": line[4], - "category": line[5], - "comment": line[6], - "line_no": line_no, - }, - line[2], - header["decimal_separator"], - ) + ds = add_amount_or_formula( + { + "name": line[0], + "unit": line[1], + "waste_type": line[4], + "category": line[5], + "comment": line[6], + "line_no": line_no, + }, + line[2], + header["decimal_separator"], ) + ds = add_amount_or_formula( + data=ds, + value=line[3], + decimal_separator=header["decimal_separator"], + amount_key="allocation", + formula_key="allocation_formula", + ) + self.parsed.append(ds) diff --git a/bw_simapro_csv/parameters.py b/bw_simapro_csv/parameters.py index dca15c6..0798cce 100644 --- a/bw_simapro_csv/parameters.py +++ b/bw_simapro_csv/parameters.py @@ -111,7 +111,7 @@ def fix_iff_formula(formula: str, pattern: Pattern) -> str: return formula -def prepare_formulas(block: list[dict], header: dict) -> list[dict]: +def prepare_formulas(block: list[dict], header: dict, formula_field: str = "formula") -> list[dict]: """Make necessary conversions so formulas can be parsed by Python. Does the following: @@ -123,26 +123,26 @@ def prepare_formulas(block: list[dict], header: dict) -> list[dict]: iff_re = compile_iff_re(header) for obj in block: - if "formula" in obj: - if "^" in obj["formula"]: - new_formula = obj["formula"].replace("^", "**") - logger.info( + if formula_field in obj: + if "^" in obj[formula_field]: + new_formula = obj[formula_field].replace("^", "**") + logger.debug( f"""Replacing `^` in formula on line {obj['line_no']}: - {obj['formula']} >>> {new_formula}""" + {obj[formula_field]} >>> {new_formula}""" ) - if "original_formula" not in obj["formula"]: - obj["original_formula"] = obj["formula"] - obj["formula"] = new_formula + if f"original_{formula_field}" not in obj: + obj[f"original_{formula_field}"] = obj[formula_field] + obj[formula_field] = new_formula - new_formula = fix_iff_formula(obj["formula"], iff_re) - if new_formula != obj["formula"]: - logger.info( + new_formula = fix_iff_formula(obj[formula_field], iff_re) + if new_formula != obj[formula_field]: + logger.debug( f"""Replacing `Iff` expression in formula on line {obj['line_no']}: - {obj['formula']} >>> {new_formula}""" + {obj[formula_field]} >>> {new_formula}""" ) - if "original_formula" not in obj["formula"]: - obj["original_formula"] = obj["formula"] - obj["formula"] = new_formula + if f"original_{formula_field}" not in obj: + obj[f"original_{formula_field}"] = obj[formula_field] + obj[formula_field] = new_formula return block @@ -176,8 +176,8 @@ def __call__(self, formula): return unparse(parsed).strip() -def substitute_in_formulas(obj: dict, visitor: Type) -> dict: - """Substitute variable names in `obj['formula']` based on `substitutions`. +def substitute_in_formulas(obj: dict, visitor: Type, formula_field: str = "formula") -> dict: + """Substitute variable names in `obj[formula_field]` based on `substitutions`. Keeps `original_formula`. @@ -191,8 +191,11 @@ def substitute_in_formulas(obj: dict, visitor: Type) -> dict: {'formula': 'hi_mom * 2', 'original_formula': 'a * 2'} """ - if "formula" in obj: - obj["original_formula"] = obj["formula"] - obj["formula"] = visitor(obj["formula"]) + if formula_field in obj: + obj[f"original_{formula_field}"] = obj[formula_field] + obj[formula_field] = visitor(obj[formula_field]) + + if obj[f"original_{formula_field}"] == obj[formula_field]: + del obj[f"original_{formula_field}"] return obj