hestia-earth-models 0.73.7__py3-none-any.whl → 0.74.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of hestia-earth-models might be problematic. Click here for more details.
- hestia_earth/models/aware/scarcityWeightedWaterUse.py +7 -6
- hestia_earth/models/aware2_0/__init__.py +14 -0
- hestia_earth/models/aware2_0/scarcityWeightedWaterUse.py +115 -0
- hestia_earth/models/config/Cycle.json +121 -29
- hestia_earth/models/config/ImpactAssessment.json +240 -200
- hestia_earth/models/config/__init__.py +26 -2
- hestia_earth/models/cycle/animal/input/hestiaAggregatedData.py +2 -2
- hestia_earth/models/cycle/animal/input/properties.py +6 -5
- hestia_earth/models/cycle/animal/milkYield.py +8 -3
- hestia_earth/models/cycle/utils.py +6 -6
- hestia_earth/models/dammgen2009/noxToAirExcreta.py +11 -9
- hestia_earth/models/data/ecoinventV3/__init__.py +8 -26
- hestia_earth/models/ecoalimV9/cycle.py +51 -45
- hestia_earth/models/ecoalimV9/impact_assessment.py +63 -45
- hestia_earth/models/ecoalimV9/utils.py +21 -15
- hestia_earth/models/ecoinventV3/__init__.py +8 -140
- hestia_earth/models/ecoinventV3/cycle.py +140 -0
- hestia_earth/models/ecoinventV3/utils.py +28 -1
- hestia_earth/models/ecoinventV3AndEmberClimate/__init__.py +8 -137
- hestia_earth/models/ecoinventV3AndEmberClimate/cycle.py +144 -0
- hestia_earth/models/emepEea2019/n2OToAirFuelCombustionDirect.py +2 -2
- hestia_earth/models/emepEea2019/utils.py +2 -3
- hestia_earth/models/environmentalFootprintV3_1/environmentalFootprintSingleOverallScore.py +5 -7
- hestia_earth/models/frischknechtEtAl2000/ionisingRadiationKbqU235Eq.py +41 -43
- hestia_earth/models/geospatialDatabase/awareWaterBasinId.py +2 -2
- hestia_earth/models/geospatialDatabase/awareWaterBasinId_v1.py +45 -0
- hestia_earth/models/hestia/default_emissions.py +7 -7
- hestia_earth/models/hestia/default_resourceUse.py +7 -6
- hestia_earth/models/hestia/landCover.py +110 -12
- hestia_earth/models/hestia/seed_emissions.py +7 -3
- hestia_earth/models/hestia/utils.py +1 -0
- hestia_earth/models/hestia/waterSalinity.py +2 -3
- hestia_earth/models/impact_assessment/emissions.py +3 -5
- hestia_earth/models/ipcc2019/biocharOrganicCarbonPerHa.py +9 -3
- hestia_earth/models/ipcc2019/co2ToAirAboveGroundBiomassStockChange.py +1 -5
- hestia_earth/models/ipcc2019/co2ToAirBelowGroundBiomassStockChange.py +1 -5
- hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +1 -33
- hestia_earth/models/ipcc2019/co2ToAirSoilOrganicCarbonStockChange.py +1 -5
- hestia_earth/models/ipcc2019/n2OToAirAquacultureSystemsIndirect.py +44 -0
- hestia_earth/models/ipcc2019/n2OToAirCropResidueBurningIndirect.py +43 -0
- hestia_earth/models/ipcc2019/n2OToAirCropResidueDecompositionIndirect.py +13 -70
- hestia_earth/models/ipcc2019/n2OToAirExcretaIndirect.py +13 -70
- hestia_earth/models/ipcc2019/n2OToAirFuelCombustionIndirect.py +43 -0
- hestia_earth/models/ipcc2019/n2OToAirInorganicFertiliserIndirect.py +13 -70
- hestia_earth/models/ipcc2019/n2OToAirNaturalVegetationBurningIndirect.py +43 -0
- hestia_earth/models/ipcc2019/n2OToAirOrganicFertiliserIndirect.py +13 -70
- hestia_earth/models/ipcc2019/n2OToAirOrganicSoilBurningIndirect.py +43 -0
- hestia_earth/models/ipcc2019/n2OToAirOrganicSoilCultivationIndirect.py +43 -0
- hestia_earth/models/ipcc2019/n2OToAir_indirect_emissions_utils.py +112 -0
- hestia_earth/models/ipcc2019/utils.py +0 -25
- hestia_earth/models/jarvisAndPain1994/n2ToAirExcreta.py +11 -9
- hestia_earth/models/linkedImpactAssessment/emissions.py +25 -16
- hestia_earth/models/linkedImpactAssessment/utils.py +5 -1
- hestia_earth/models/log.py +8 -3
- hestia_earth/models/mocking/search-results.json +1670 -1666
- hestia_earth/models/utils/__init__.py +3 -0
- hestia_earth/models/utils/background_emissions.py +121 -14
- hestia_earth/models/utils/blank_node.py +1 -11
- hestia_earth/models/utils/emission.py +18 -8
- hestia_earth/models/utils/feedipedia.py +2 -2
- hestia_earth/models/utils/impact_assessment.py +4 -6
- hestia_earth/models/utils/indicator.py +8 -1
- hestia_earth/models/utils/lookup.py +30 -18
- hestia_earth/models/utils/productivity.py +1 -1
- hestia_earth/models/version.py +1 -1
- hestia_earth/orchestrator/log.py +8 -3
- hestia_earth/orchestrator/strategies/merge/merge_list.py +41 -54
- {hestia_earth_models-0.73.7.dist-info → hestia_earth_models-0.74.0.dist-info}/METADATA +3 -3
- {hestia_earth_models-0.73.7.dist-info → hestia_earth_models-0.74.0.dist-info}/RECORD +99 -75
- tests/models/aware2_0/__init__.py +0 -0
- tests/models/aware2_0/test_scarcityWeightedWaterUse.py +58 -0
- tests/models/dammgen2009/test_noxToAirExcreta.py +2 -2
- tests/models/ecoalimV9/test_cycle.py +1 -1
- tests/models/ecoalimV9/test_impact_assessment.py +1 -1
- tests/models/ecoinventV3/__init__.py +0 -0
- tests/models/{test_ecoinventV3.py → ecoinventV3/test_cycle.py} +5 -5
- tests/models/ecoinventV3AndEmberClimate/__init__.py +0 -0
- tests/models/{test_ecoinventV3AndEmberClimate.py → ecoinventV3AndEmberClimate/test_cycle.py} +6 -4
- tests/models/environmentalFootprintV3_1/test_environmentalFootprintSingleOverallScore.py +2 -2
- tests/models/frischknechtEtAl2000/test_ionisingRadiationKbqU235Eq.py +18 -27
- tests/models/hestia/test_landCover.py +16 -6
- tests/models/ipcc2019/test_biocharOrganicCarbonPerHa.py +2 -1
- tests/models/ipcc2019/test_n2OToAirAquacultureSystemsIndirect.py +45 -0
- tests/models/ipcc2019/test_n2OToAirCropResidueBurningIndirect.py +45 -0
- tests/models/ipcc2019/test_n2OToAirCropResidueDecompositionIndirect.py +6 -32
- tests/models/ipcc2019/test_n2OToAirExcretaIndirect.py +6 -32
- tests/models/ipcc2019/test_n2OToAirFuelCombustionIndirect.py +45 -0
- tests/models/ipcc2019/test_n2OToAirInorganicFertiliserIndirect.py +6 -32
- tests/models/ipcc2019/test_n2OToAirNaturalVegetationBurningIndirect.py +45 -0
- tests/models/ipcc2019/test_n2OToAirOrganicFertiliserIndirect.py +6 -32
- tests/models/ipcc2019/test_n2OToAirOrganicSoilBurningIndirect.py +45 -0
- tests/models/ipcc2019/test_n2OToAirOrganicSoilCultivationIndirect.py +45 -0
- tests/models/ipcc2019/test_n2OToAir_indirect_emissions_utils.py +19 -0
- tests/models/site/pre_checks/test_cache_geospatialDatabase.py +4 -4
- tests/models/test_config.py +53 -7
- tests/models/utils/test_background_emissions.py +13 -0
- {hestia_earth_models-0.73.7.dist-info → hestia_earth_models-0.74.0.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.73.7.dist-info → hestia_earth_models-0.74.0.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.73.7.dist-info → hestia_earth_models-0.74.0.dist-info}/top_level.txt +0 -0
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import json
|
|
3
|
+
from enum import Enum
|
|
3
4
|
from hestia_earth.utils.tools import flatten
|
|
4
5
|
|
|
5
6
|
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
6
7
|
|
|
7
8
|
|
|
9
|
+
class AWARE_VERSION(Enum):
|
|
10
|
+
V1 = '1.2'
|
|
11
|
+
V2 = '2.0'
|
|
12
|
+
|
|
13
|
+
|
|
8
14
|
def _is_aggregated_model(model: dict):
|
|
9
15
|
return isinstance(model, dict) and 'aggregated' in model.get('value', '').lower()
|
|
10
16
|
|
|
@@ -17,12 +23,26 @@ def _remove_aggregated(models: list):
|
|
|
17
23
|
return list(filter(lambda v: v is not None, values))
|
|
18
24
|
|
|
19
25
|
|
|
26
|
+
def _use_aware_1(models: list):
|
|
27
|
+
return [
|
|
28
|
+
_use_aware_1(m) if isinstance(m, list) else
|
|
29
|
+
m | {'model': 'aware'} if m.get('model') == 'aware2-0' else
|
|
30
|
+
m | {'value': 'awareWaterBasinId_v1'} if m.get('value') == 'awareWaterBasinId' else
|
|
31
|
+
m
|
|
32
|
+
for m in models
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
|
|
20
36
|
def _load_config(filename: str) -> dict:
|
|
21
37
|
with open(os.path.join(CURRENT_DIR, f"{filename}.json"), 'r') as f:
|
|
22
38
|
return json.load(f)
|
|
23
39
|
|
|
24
40
|
|
|
25
|
-
def load_config(
|
|
41
|
+
def load_config(
|
|
42
|
+
node_type: str,
|
|
43
|
+
skip_aggregated_models: bool = False,
|
|
44
|
+
use_aware_version: AWARE_VERSION = AWARE_VERSION.V2
|
|
45
|
+
) -> dict:
|
|
26
46
|
"""
|
|
27
47
|
Load the configuration associated with the Node Type.
|
|
28
48
|
|
|
@@ -32,11 +52,15 @@ def load_config(node_type: str, skip_aggregated_models: bool = False) -> dict:
|
|
|
32
52
|
The Node Type to load configuration. Can be: `Cycle`, `Site`, `ImpactAssessment`.
|
|
33
53
|
skip_aggregated_models : bool
|
|
34
54
|
Include models using aggregated data. Included by default.
|
|
55
|
+
use_aware_version : AWARE_VERSION
|
|
56
|
+
Choose which AWARE version to use. Defaults to using version `2.0`.
|
|
35
57
|
"""
|
|
36
58
|
try:
|
|
37
59
|
config = _load_config(node_type)
|
|
38
60
|
models = config.get('models')
|
|
39
|
-
|
|
61
|
+
models = _remove_aggregated(models) if skip_aggregated_models else models
|
|
62
|
+
models = _use_aware_1(models) if use_aware_version == AWARE_VERSION.V1 else models
|
|
63
|
+
return config | {'models': models}
|
|
40
64
|
except FileNotFoundError:
|
|
41
65
|
raise Exception(f"Invalid type {node_type}.")
|
|
42
66
|
|
|
@@ -56,12 +56,12 @@ def _should_run_animal(cycle: dict, animal: dict):
|
|
|
56
56
|
inputs = list(filter(should_link_input_to_impact(cycle), inputs))
|
|
57
57
|
nb_inputs = len(inputs)
|
|
58
58
|
|
|
59
|
-
logRequirements(cycle, model=MODEL_ID, term=term_id, key=MODEL_KEY,
|
|
59
|
+
logRequirements(cycle, model=MODEL_ID, term=term_id, key=MODEL_KEY, animalId=animal.get('animalId'),
|
|
60
60
|
end_date=end_date,
|
|
61
61
|
nb_inputs=nb_inputs)
|
|
62
62
|
|
|
63
63
|
should_run = all([end_date, nb_inputs > 0])
|
|
64
|
-
logShouldRun(cycle, MODEL_ID, term_id, should_run, key=MODEL_KEY)
|
|
64
|
+
logShouldRun(cycle, MODEL_ID, term_id, should_run, key=MODEL_KEY, animalId=animal.get('animalId'))
|
|
65
65
|
return should_run, inputs
|
|
66
66
|
|
|
67
67
|
|
|
@@ -50,7 +50,7 @@ def _find_related_product(input: dict):
|
|
|
50
50
|
return find_term_match(products, input.get('term', {}).get('@id'))
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
def _run_input_by_impactAssessment(cycle: dict):
|
|
53
|
+
def _run_input_by_impactAssessment(cycle: dict, **log_args):
|
|
54
54
|
def exec(input: dict):
|
|
55
55
|
term_id = input.get('term', {}).get('@id')
|
|
56
56
|
product = _find_related_product(input)
|
|
@@ -58,7 +58,7 @@ def _run_input_by_impactAssessment(cycle: dict):
|
|
|
58
58
|
all_properties = input.get('properties', [])
|
|
59
59
|
new_properties = [p for p in properties if not find_term_match(all_properties, p.get('term', {}).get('@id'))]
|
|
60
60
|
for prop in new_properties:
|
|
61
|
-
logShouldRun(cycle, MODEL, term_id, True, property=prop.get('term', {}).get('@id'))
|
|
61
|
+
logShouldRun(cycle, MODEL, term_id, True, property=prop.get('term', {}).get('@id'), **log_args)
|
|
62
62
|
return {**input, 'properties': merge_blank_nodes(all_properties, new_properties)} if new_properties else input
|
|
63
63
|
return exec
|
|
64
64
|
|
|
@@ -80,9 +80,10 @@ def _run_animal(cycle: dict, animal: dict):
|
|
|
80
80
|
should_run_properties_value(i)
|
|
81
81
|
])
|
|
82
82
|
]
|
|
83
|
-
|
|
84
|
-
inputs =
|
|
85
|
-
inputs =
|
|
83
|
+
log_args = {'animalId': animal.get('animalId')}
|
|
84
|
+
inputs = list(map(_run_input_by_impactAssessment(cycle, **log_args), inputs))
|
|
85
|
+
inputs = rescale_properties_from_dryMatter(MODEL, cycle, inputs, **log_args)
|
|
86
|
+
inputs = average_blank_node_properties_value(cycle, inputs, **log_args)
|
|
86
87
|
return animal | {'inputs': inputs}
|
|
87
88
|
|
|
88
89
|
|
|
@@ -42,12 +42,17 @@ def _run(cycle: dict, animal: dict):
|
|
|
42
42
|
practices = non_empty_list(
|
|
43
43
|
[p for p in cycle.get('practices', []) if p.get('term', {}).get('@id') in practice_ids]
|
|
44
44
|
)
|
|
45
|
+
log_args = {
|
|
46
|
+
'model_key': MODEL_KEY,
|
|
47
|
+
'animalId': animal.get('animalId')
|
|
48
|
+
}
|
|
45
49
|
|
|
46
|
-
logRequirements(cycle, model=MODEL, term=term_id,
|
|
47
|
-
practice_ids=log_blank_nodes_id(practices)
|
|
50
|
+
logRequirements(cycle, model=MODEL, term=term_id,
|
|
51
|
+
practice_ids=log_blank_nodes_id(practices),
|
|
52
|
+
**log_args)
|
|
48
53
|
|
|
49
54
|
for practice in practices:
|
|
50
|
-
logShouldRun(cycle, MODEL, practice.get('term', {}).get('@id'), True,
|
|
55
|
+
logShouldRun(cycle, MODEL, practice.get('term', {}).get('@id'), True, **log_args)
|
|
51
56
|
|
|
52
57
|
return {
|
|
53
58
|
**animal,
|
|
@@ -11,21 +11,21 @@ def _should_run_property_by_min_max(property: dict):
|
|
|
11
11
|
])
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
def _run_property(cycle: dict, property: dict):
|
|
14
|
+
def _run_property(cycle: dict, property: dict, **log_args):
|
|
15
15
|
term_id = property.get('term', {}).get('@id')
|
|
16
16
|
|
|
17
17
|
should_run = _should_run_property_by_min_max(property)
|
|
18
|
-
logShouldRun(cycle, MODEL, term_id, should_run, key='value')
|
|
18
|
+
logShouldRun(cycle, MODEL, term_id, should_run, key='value', **log_args)
|
|
19
19
|
|
|
20
20
|
return property | ({
|
|
21
21
|
'value': list_average([property.get('min'), property.get('max')])
|
|
22
22
|
} if should_run else {})
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
def _run_properties(cycle: dict, blank_node: dict):
|
|
25
|
+
def _run_properties(cycle: dict, blank_node: dict, **log_args):
|
|
26
26
|
properties = blank_node.get('properties', [])
|
|
27
27
|
return blank_node | ({
|
|
28
|
-
'properties': [_run_property(cycle, p) for p in properties]
|
|
28
|
+
'properties': [_run_property(cycle, p, **log_args) for p in properties]
|
|
29
29
|
} if properties else {})
|
|
30
30
|
|
|
31
31
|
|
|
@@ -33,5 +33,5 @@ def should_run_properties_value(blank_node: dict):
|
|
|
33
33
|
return any(map(_should_run_property_by_min_max, blank_node.get('properties', [])))
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
def average_blank_node_properties_value(cycle: dict, blank_nodes: list):
|
|
37
|
-
return [_run_properties(cycle, v) for v in blank_nodes]
|
|
36
|
+
def average_blank_node_properties_value(cycle: dict, blank_nodes: list, **log_args):
|
|
37
|
+
return [_run_properties(cycle, v, **log_args) for v in blank_nodes]
|
|
@@ -22,7 +22,7 @@ RETURNS = {
|
|
|
22
22
|
}
|
|
23
23
|
TERM_ID = 'noxToAirExcreta'
|
|
24
24
|
TIER = EmissionMethodTier.TIER_1.value
|
|
25
|
-
|
|
25
|
+
_N2O_TERM_ID = 'n2OToAirExcretaDirect'
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
def _emission(value: float):
|
|
@@ -32,22 +32,24 @@ def _emission(value: float):
|
|
|
32
32
|
return emission
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
def _run(
|
|
36
|
-
value = 0.1 *
|
|
35
|
+
def _run(n2o_value: float):
|
|
36
|
+
value = 0.1 * n2o_value / get_atomic_conversion(Units.KG_N2O, Units.TO_N)
|
|
37
37
|
value = value * get_atomic_conversion(Units.KG_NOX, Units.TO_N)
|
|
38
38
|
return [_emission(value)]
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
def _should_run(cycle: dict):
|
|
42
|
-
n2o = find_term_match(cycle.get('emissions', []),
|
|
42
|
+
n2o = find_term_match(cycle.get('emissions', []), _N2O_TERM_ID)
|
|
43
|
+
n2o_value = list_sum(n2o.get("value", []), default=None)
|
|
43
44
|
|
|
44
|
-
logRequirements(cycle, model=MODEL, term=TERM_ID,
|
|
45
|
+
logRequirements(cycle, model=MODEL, term=TERM_ID,
|
|
46
|
+
**{_N2O_TERM_ID: n2o_value})
|
|
45
47
|
|
|
46
|
-
should_run = all([
|
|
48
|
+
should_run = all([n2o_value is not None])
|
|
47
49
|
logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
|
|
48
|
-
return should_run,
|
|
50
|
+
return should_run, n2o_value
|
|
49
51
|
|
|
50
52
|
|
|
51
53
|
def run(cycle: dict):
|
|
52
|
-
should_run,
|
|
53
|
-
return _run(
|
|
54
|
+
should_run, n2o_value = _should_run(cycle)
|
|
55
|
+
return _run(n2o_value) if should_run else []
|
|
@@ -1,36 +1,18 @@
|
|
|
1
1
|
import os
|
|
2
|
-
from functools import lru_cache
|
|
3
|
-
from hestia_earth.utils.lookup import column_name, get_table_value, load_lookup, lookup_columns
|
|
4
|
-
from hestia_earth.utils.tools import non_empty_list
|
|
5
2
|
|
|
6
3
|
from hestia_earth.models.log import logger
|
|
7
4
|
|
|
8
5
|
_CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
9
|
-
|
|
6
|
+
_ENV_FOLDER = 'ECOINVENT_V3_FOLDER'
|
|
7
|
+
_ECOINVENT_FOLDER = os.getenv(_ENV_FOLDER) or _CURRENT_DIR
|
|
8
|
+
_ECOINVENT_VERSION = os.getenv('ECOINVENT_VERSION', '3.9')
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
filepath = os.
|
|
15
|
-
|
|
11
|
+
def get_filepath(term_type: str):
|
|
12
|
+
filename = f"ecoinventV{_ECOINVENT_VERSION.replace('.', '_')}-{term_type}.csv"
|
|
13
|
+
filepath = os.path.join(_ECOINVENT_FOLDER, filename)
|
|
16
14
|
if not os.path.exists(filepath):
|
|
17
|
-
logger.warning('Ecoinvent file not found. Please make sure to set env variable "%s".',
|
|
15
|
+
logger.warning('Ecoinvent file not found. Please make sure to set env variable "%s".', _ENV_FOLDER)
|
|
18
16
|
return None
|
|
19
17
|
|
|
20
|
-
return
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def ecoinventV3_emissions(ecoinventName: str):
|
|
24
|
-
lookup = _get_file()
|
|
25
|
-
col_name = column_name('ecoinventName')
|
|
26
|
-
|
|
27
|
-
def emission(column: str):
|
|
28
|
-
id = get_table_value(lookup, col_name, ecoinventName, column_name(column))
|
|
29
|
-
value = get_table_value(lookup, col_name, ecoinventName, column_name(column.replace('termid', 'value')))
|
|
30
|
-
return (id, value) if id else None
|
|
31
|
-
|
|
32
|
-
columns = [
|
|
33
|
-
col for col in lookup_columns(lookup)
|
|
34
|
-
if col.endswith(column_name('termid'))
|
|
35
|
-
]
|
|
36
|
-
return non_empty_list(map(emission, columns))
|
|
18
|
+
return filepath
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
from functools import reduce
|
|
2
1
|
from statistics import mean
|
|
3
|
-
from hestia_earth.schema import EmissionMethodTier
|
|
2
|
+
from hestia_earth.schema import EmissionMethodTier, TermTermType
|
|
4
3
|
from hestia_earth.utils.tools import flatten, list_sum
|
|
4
|
+
from hestia_earth.utils.blank_node import group_by_keys
|
|
5
5
|
|
|
6
|
-
from hestia_earth.models.log import
|
|
6
|
+
from hestia_earth.models.log import logShouldRun, logRequirements
|
|
7
7
|
from hestia_earth.models.utils.emission import _new_emission
|
|
8
|
-
from hestia_earth.models.utils.background_emissions import
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
from hestia_earth.models.utils.background_emissions import (
|
|
9
|
+
get_background_inputs,
|
|
10
|
+
no_gap_filled_background_emissions,
|
|
11
|
+
log_missing_emissions,
|
|
12
|
+
parse_term_id,
|
|
13
|
+
process_input_mappings
|
|
14
|
+
)
|
|
15
|
+
from .utils import get_input_mappings, extract_input_mapping
|
|
11
16
|
from . import MODEL
|
|
12
17
|
|
|
13
18
|
REQUIREMENTS = {
|
|
@@ -46,19 +51,20 @@ RETURNS = {
|
|
|
46
51
|
}]
|
|
47
52
|
}
|
|
48
53
|
LOOKUPS = {
|
|
49
|
-
"ecoalim-
|
|
50
|
-
"
|
|
51
|
-
"processedFood": "ecoalimMapping",
|
|
54
|
+
"ecoalim-emission": "emission-",
|
|
55
|
+
"emission": "inputProductionGroupId",
|
|
52
56
|
"animalProduct": "ecoalimMapping",
|
|
57
|
+
"crop": "ecoalimMapping",
|
|
58
|
+
"feedFoodAdditive": "ecoalimMapping",
|
|
53
59
|
"forage": "ecoalimMapping",
|
|
54
|
-
"
|
|
60
|
+
"processedFood": "ecoalimMapping"
|
|
55
61
|
}
|
|
56
62
|
MODEL_KEY = 'cycle'
|
|
57
63
|
TIER = EmissionMethodTier.BACKGROUND.value
|
|
58
64
|
|
|
59
65
|
|
|
60
|
-
def _emission(term_id: str, value: float, input: dict):
|
|
61
|
-
emission = _new_emission(term_id, MODEL)
|
|
66
|
+
def _emission(term_id: str, value: float, input: dict, country_id: str = None, key_id: str = None):
|
|
67
|
+
emission = _new_emission(term_id, MODEL, country_id, key_id)
|
|
62
68
|
emission['value'] = [value]
|
|
63
69
|
emission['methodTier'] = TIER
|
|
64
70
|
emission['inputs'] = [input.get('term')]
|
|
@@ -69,32 +75,9 @@ def _emission(term_id: str, value: float, input: dict):
|
|
|
69
75
|
return emission
|
|
70
76
|
|
|
71
77
|
|
|
72
|
-
def _add_emission(cycle: dict, input: dict):
|
|
73
|
-
input_term_id = input.get('term', {}).get('@id')
|
|
74
|
-
operation_term_id = input.get('operation', {}).get('@id')
|
|
75
|
-
animal_term_id = input.get('animal', {}).get('@id')
|
|
76
|
-
|
|
77
|
-
def add(prev: dict, mapping: tuple):
|
|
78
|
-
gadm_id, ecoalim_key = mapping
|
|
79
|
-
# all countries have the same coefficient
|
|
80
|
-
coefficient = 1
|
|
81
|
-
emissions = ecoalim_values(ecoalim_key, 'emission')
|
|
82
|
-
for emission_term_id, value in emissions:
|
|
83
|
-
# log run on each emission so we know it did run
|
|
84
|
-
logShouldRun(cycle, MODEL, input_term_id, True, methodTier=TIER, emission_id=emission_term_id)
|
|
85
|
-
debugValues(cycle, model=MODEL, term=emission_term_id, model_key=MODEL_KEY,
|
|
86
|
-
value=value,
|
|
87
|
-
coefficient=coefficient,
|
|
88
|
-
input=input_term_id,
|
|
89
|
-
operation=operation_term_id,
|
|
90
|
-
animal=animal_term_id)
|
|
91
|
-
prev[emission_term_id] = prev.get(emission_term_id, []) + [value * coefficient]
|
|
92
|
-
return prev
|
|
93
|
-
return add
|
|
94
|
-
|
|
95
|
-
|
|
96
78
|
def _run_input(cycle: dict):
|
|
97
79
|
no_gap_filled_background_emissions_func = no_gap_filled_background_emissions(cycle)
|
|
80
|
+
log_missing_emissions_func = log_missing_emissions(cycle, model=MODEL, methodTier=TIER)
|
|
98
81
|
|
|
99
82
|
def run(inputs: list):
|
|
100
83
|
input = inputs[0]
|
|
@@ -103,27 +86,50 @@ def _run_input(cycle: dict):
|
|
|
103
86
|
mappings = get_input_mappings(MODEL, input)
|
|
104
87
|
has_mappings = len(mappings) > 0
|
|
105
88
|
|
|
89
|
+
# grouping the inputs together in the logs
|
|
90
|
+
input_parent_term_id = (input.get('parent', {})).get('@id') or input.get('animalId', {})
|
|
91
|
+
extra_logs = {
|
|
92
|
+
**({'input_group_id': input_parent_term_id} if input_parent_term_id else {}),
|
|
93
|
+
**({'animalId': input.get('animalId')} if input.get('animalId') else {})
|
|
94
|
+
}
|
|
95
|
+
|
|
106
96
|
# skip input that has background emissions we have already gap-filled (model run before)
|
|
107
97
|
has_no_gap_filled_background_emissions = no_gap_filled_background_emissions_func(input)
|
|
108
98
|
|
|
109
99
|
logRequirements(cycle, model=MODEL, term=input_term_id, model_key=MODEL_KEY,
|
|
110
|
-
|
|
111
|
-
|
|
100
|
+
has_mappings=has_mappings,
|
|
101
|
+
mappings=';'.join([v[1] for v in mappings]),
|
|
112
102
|
has_no_gap_filled_background_emissions=has_no_gap_filled_background_emissions,
|
|
113
|
-
input_value=input_value
|
|
103
|
+
input_value=input_value,
|
|
104
|
+
**extra_logs)
|
|
114
105
|
|
|
115
106
|
should_run = all([has_mappings, has_no_gap_filled_background_emissions, input_value])
|
|
116
|
-
logShouldRun(cycle, MODEL, input_term_id, should_run, methodTier=TIER, model_key=MODEL_KEY)
|
|
117
|
-
|
|
118
|
-
|
|
107
|
+
logShouldRun(cycle, MODEL, input_term_id, should_run, methodTier=TIER, model_key=MODEL_KEY, **extra_logs)
|
|
108
|
+
|
|
109
|
+
results = process_input_mappings(
|
|
110
|
+
cycle, input, mappings, TermTermType.EMISSION,
|
|
111
|
+
extract_mapping=extract_input_mapping,
|
|
112
|
+
**(
|
|
113
|
+
extra_logs | {'model': MODEL, 'model_key': MODEL_KEY}
|
|
114
|
+
)
|
|
115
|
+
) if should_run else {}
|
|
116
|
+
log_missing_emissions_func(input_term_id, list(map(parse_term_id, results.keys())), **(
|
|
117
|
+
extra_logs | {'has_mappings': has_mappings}
|
|
118
|
+
))
|
|
119
119
|
return [
|
|
120
|
-
_emission(
|
|
121
|
-
|
|
120
|
+
_emission(
|
|
121
|
+
term_id=parse_term_id(term_id),
|
|
122
|
+
value=mean([v['value'] * v['coefficient'] for v in values]) * input_value,
|
|
123
|
+
input=input,
|
|
124
|
+
country_id=values[0].get('country'),
|
|
125
|
+
key_id=values[0].get('key'),
|
|
126
|
+
)
|
|
127
|
+
for term_id, values in results.items()
|
|
122
128
|
]
|
|
123
129
|
return run
|
|
124
130
|
|
|
125
131
|
|
|
126
132
|
def run(cycle: dict):
|
|
127
133
|
inputs = get_background_inputs(cycle)
|
|
128
|
-
grouped_inputs =
|
|
134
|
+
grouped_inputs = group_by_keys(inputs, ['term', 'operation', 'animal'])
|
|
129
135
|
return flatten(map(_run_input(cycle), grouped_inputs.values()))
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
from functools import reduce
|
|
2
1
|
from statistics import mean
|
|
3
|
-
from hestia_earth.schema import IndicatorMethodTier
|
|
2
|
+
from hestia_earth.schema import IndicatorMethodTier, TermTermType
|
|
4
3
|
from hestia_earth.utils.tools import flatten, list_sum
|
|
4
|
+
from hestia_earth.utils.blank_node import group_by_keys
|
|
5
5
|
|
|
6
|
-
from hestia_earth.models.log import
|
|
6
|
+
from hestia_earth.models.log import logShouldRun, logRequirements
|
|
7
7
|
from hestia_earth.models.utils.indicator import _new_indicator
|
|
8
|
-
from hestia_earth.models.utils.background_emissions import
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
from hestia_earth.models.utils.background_emissions import (
|
|
9
|
+
get_background_inputs,
|
|
10
|
+
log_missing_emissions,
|
|
11
|
+
parse_term_id,
|
|
12
|
+
process_input_mappings
|
|
13
|
+
)
|
|
14
|
+
from .utils import get_input_mappings, extract_input_mapping
|
|
11
15
|
from . import MODEL
|
|
12
16
|
|
|
13
17
|
REQUIREMENTS = {
|
|
@@ -48,53 +52,42 @@ RETURNS = {
|
|
|
48
52
|
}]
|
|
49
53
|
}
|
|
50
54
|
LOOKUPS = {
|
|
51
|
-
"ecoalim-
|
|
52
|
-
"crop": "ecoalimMapping",
|
|
53
|
-
"processedFood": "ecoalimMapping",
|
|
55
|
+
"ecoalim-resourceUse": "resourceUse-",
|
|
54
56
|
"animalProduct": "ecoalimMapping",
|
|
57
|
+
"crop": "ecoalimMapping",
|
|
58
|
+
"feedFoodAdditive": "ecoalimMapping",
|
|
55
59
|
"forage": "ecoalimMapping",
|
|
56
|
-
"
|
|
60
|
+
"processedFood": "ecoalimMapping"
|
|
57
61
|
}
|
|
58
62
|
MODEL_KEY = 'impact_assessment'
|
|
59
63
|
TIER = IndicatorMethodTier.BACKGROUND.value
|
|
60
64
|
|
|
61
65
|
|
|
62
|
-
def _indicator(
|
|
63
|
-
|
|
66
|
+
def _indicator(
|
|
67
|
+
term_id: str,
|
|
68
|
+
value: float,
|
|
69
|
+
input: dict,
|
|
70
|
+
country_id: str = None,
|
|
71
|
+
key_id: str = None,
|
|
72
|
+
land_cover_id: str = None,
|
|
73
|
+
previous_land_cover_id: str = None,
|
|
74
|
+
):
|
|
75
|
+
indicator = _new_indicator(term_id, MODEL, land_cover_id, previous_land_cover_id, country_id, key_id)
|
|
64
76
|
indicator['value'] = value
|
|
65
77
|
indicator['methodTier'] = TIER
|
|
66
78
|
indicator['inputs'] = [input.get('term')]
|
|
67
79
|
if input.get('operation'):
|
|
68
80
|
indicator['operation'] = input.get('operation')
|
|
81
|
+
if input.get('animal'):
|
|
82
|
+
indicator['animals'] = [input.get('animal')]
|
|
69
83
|
return indicator
|
|
70
84
|
|
|
71
85
|
|
|
72
|
-
def _add_indicator(cycle: dict, input: dict):
|
|
73
|
-
input_term_id = input.get('term', {}).get('@id')
|
|
74
|
-
operation_term_id = input.get('operation', {}).get('@id')
|
|
75
|
-
animal_term_id = input.get('animal', {}).get('@id')
|
|
76
|
-
|
|
77
|
-
def add(prev: dict, mapping: tuple):
|
|
78
|
-
gadm_id, ecoalim_key = mapping
|
|
79
|
-
# all countries have the same coefficient
|
|
80
|
-
coefficient = 1
|
|
81
|
-
indicators = ecoalim_values(ecoalim_key, 'resourceUse')
|
|
82
|
-
for indicator_term_id, value in indicators:
|
|
83
|
-
# log run on each indicator so we know it did run
|
|
84
|
-
logShouldRun(cycle, MODEL, input_term_id, True, methodTier=TIER, emission_id=indicator_term_id)
|
|
85
|
-
debugValues(cycle, model=MODEL, term=indicator_term_id, model_key=MODEL_KEY,
|
|
86
|
-
value=value,
|
|
87
|
-
coefficient=coefficient,
|
|
88
|
-
input=input_term_id,
|
|
89
|
-
operation=operation_term_id,
|
|
90
|
-
animal=animal_term_id)
|
|
91
|
-
if value is not None:
|
|
92
|
-
prev[indicator_term_id] = prev.get(indicator_term_id, []) + [value * coefficient]
|
|
93
|
-
return prev
|
|
94
|
-
return add
|
|
95
|
-
|
|
96
|
-
|
|
97
86
|
def _run_input(impact_assessment: dict):
|
|
87
|
+
log_missing_emissions_func = log_missing_emissions(
|
|
88
|
+
impact_assessment, TermTermType.RESOURCEUSE, model=MODEL, methodTier=TIER
|
|
89
|
+
)
|
|
90
|
+
|
|
98
91
|
def run(inputs: list):
|
|
99
92
|
input = inputs[0]
|
|
100
93
|
input_term_id = input.get('term', {}).get('@id')
|
|
@@ -102,25 +95,50 @@ def _run_input(impact_assessment: dict):
|
|
|
102
95
|
mappings = get_input_mappings(MODEL, input)
|
|
103
96
|
has_mappings = len(mappings) > 0
|
|
104
97
|
|
|
98
|
+
# grouping the inputs together in the logs
|
|
99
|
+
input_parent_term_id = (input.get('parent', {})).get('@id') or input.get('animalId', {})
|
|
100
|
+
extra_logs = {
|
|
101
|
+
**({'input_group_id': input_parent_term_id} if input_parent_term_id else {}),
|
|
102
|
+
**({'animalId': input.get('animalId')} if input.get('animalId') else {})
|
|
103
|
+
}
|
|
104
|
+
|
|
105
105
|
logRequirements(impact_assessment, model=MODEL, term=input_term_id, model_key=MODEL_KEY,
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
input_value=input_value
|
|
106
|
+
has_mappings=has_mappings,
|
|
107
|
+
mappings=';'.join([v[1] for v in mappings]),
|
|
108
|
+
input_value=input_value,
|
|
109
|
+
**extra_logs)
|
|
109
110
|
|
|
110
111
|
should_run = all([has_mappings, input_value])
|
|
111
112
|
logShouldRun(
|
|
112
|
-
impact_assessment, MODEL, input_term_id, should_run, methodTier=TIER, model_key=MODEL_KEY
|
|
113
|
+
impact_assessment, MODEL, input_term_id, should_run, methodTier=TIER, model_key=MODEL_KEY, **extra_logs
|
|
113
114
|
)
|
|
114
115
|
|
|
115
|
-
|
|
116
|
+
results = process_input_mappings(
|
|
117
|
+
impact_assessment, input, mappings, TermTermType.RESOURCEUSE,
|
|
118
|
+
extract_mapping=extract_input_mapping,
|
|
119
|
+
**(
|
|
120
|
+
extra_logs | {'model': MODEL, 'model_key': MODEL_KEY}
|
|
121
|
+
)
|
|
122
|
+
) if should_run else {}
|
|
123
|
+
log_missing_emissions_func(input_term_id, list(map(parse_term_id, results.keys())), **(
|
|
124
|
+
extra_logs | {'has_mappings': has_mappings}
|
|
125
|
+
))
|
|
116
126
|
return [
|
|
117
|
-
_indicator(
|
|
118
|
-
|
|
127
|
+
_indicator(
|
|
128
|
+
term_id=parse_term_id(term_id),
|
|
129
|
+
value=mean([v['value'] * v['coefficient'] for v in values]) * input_value,
|
|
130
|
+
input=input,
|
|
131
|
+
country_id=values[0].get('country'),
|
|
132
|
+
key_id=values[0].get('key'),
|
|
133
|
+
land_cover_id=values[0].get('landCover'),
|
|
134
|
+
previous_land_cover_id=values[0].get('previousLandCover'),
|
|
135
|
+
)
|
|
136
|
+
for term_id, values in results.items()
|
|
119
137
|
]
|
|
120
138
|
return run
|
|
121
139
|
|
|
122
140
|
|
|
123
141
|
def run(impact_assessment: dict):
|
|
124
142
|
inputs = get_background_inputs(impact_assessment.get('cycle', {}))
|
|
125
|
-
grouped_inputs =
|
|
143
|
+
grouped_inputs = group_by_keys(inputs, ['term', 'operation', 'animal'])
|
|
126
144
|
return flatten(map(_run_input(impact_assessment), grouped_inputs.values()))
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
from
|
|
1
|
+
from functools import lru_cache
|
|
2
|
+
from hestia_earth.schema import TermTermType
|
|
3
|
+
from hestia_earth.utils.lookup import download_lookup, column_name
|
|
2
4
|
from hestia_earth.utils.tools import non_empty_list
|
|
3
5
|
|
|
4
6
|
from hestia_earth.models.utils.term import get_lookup_value
|
|
7
|
+
from hestia_earth.models.utils.background_emissions import convert_background_lookup
|
|
5
8
|
|
|
6
|
-
|
|
7
|
-
_LOOKUP = "ecoalim-emissionsResourceUse.csv"
|
|
9
|
+
_LOOKUP_INDEX_KEY = column_name('ecoalimMappingName')
|
|
8
10
|
|
|
9
11
|
|
|
10
12
|
def get_input_mappings(model: str, input: dict):
|
|
@@ -15,17 +17,21 @@ def get_input_mappings(model: str, input: dict):
|
|
|
15
17
|
return [(m.split(':')[0], m.split(':')[1]) for m in mappings]
|
|
16
18
|
|
|
17
19
|
|
|
18
|
-
def
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
def extract_input_mapping(mapping: tuple, term_type: TermTermType):
|
|
21
|
+
gadm_id, mapping_name = mapping
|
|
22
|
+
# # all countries have the same coefficient
|
|
23
|
+
coefficient = 1
|
|
24
|
+
values = ecoalim_values(mapping_name, term_type)
|
|
25
|
+
return values, coefficient
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@lru_cache()
|
|
29
|
+
def _build_lookup(term_type: str):
|
|
30
|
+
lookup = download_lookup(f"ecoalim-{term_type}.csv", keep_in_memory=False)
|
|
31
|
+
return convert_background_lookup(lookup=lookup, index_column=_LOOKUP_INDEX_KEY)
|
|
21
32
|
|
|
22
|
-
def emission(column: str):
|
|
23
|
-
id = get_table_value(lookup, col_name, mapping, column)
|
|
24
|
-
value = get_table_value(lookup, col_name, mapping, column.replace('term', 'value'))
|
|
25
|
-
return (id, value) if id else None
|
|
26
33
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
]
|
|
31
|
-
return non_empty_list(map(emission, columns))
|
|
34
|
+
@lru_cache()
|
|
35
|
+
def ecoalim_values(mapping: str, term_type: TermTermType):
|
|
36
|
+
data = _build_lookup(term_type.value)
|
|
37
|
+
return list(data[mapping].items())
|