hestia-earth-models 0.73.8__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.

Files changed (58) hide show
  1. hestia_earth/models/aware/scarcityWeightedWaterUse.py +7 -6
  2. hestia_earth/models/aware2_0/__init__.py +14 -0
  3. hestia_earth/models/aware2_0/scarcityWeightedWaterUse.py +115 -0
  4. hestia_earth/models/config/Cycle.json +5 -3
  5. hestia_earth/models/config/ImpactAssessment.json +1 -1
  6. hestia_earth/models/config/__init__.py +26 -2
  7. hestia_earth/models/cycle/animal/input/hestiaAggregatedData.py +2 -2
  8. hestia_earth/models/cycle/animal/input/properties.py +6 -5
  9. hestia_earth/models/cycle/animal/milkYield.py +8 -3
  10. hestia_earth/models/cycle/utils.py +6 -6
  11. hestia_earth/models/data/ecoinventV3/__init__.py +8 -26
  12. hestia_earth/models/ecoalimV9/cycle.py +26 -10
  13. hestia_earth/models/ecoalimV9/impact_assessment.py +30 -10
  14. hestia_earth/models/ecoalimV9/utils.py +12 -72
  15. hestia_earth/models/ecoinventV3/__init__.py +8 -140
  16. hestia_earth/models/ecoinventV3/cycle.py +140 -0
  17. hestia_earth/models/ecoinventV3/utils.py +28 -1
  18. hestia_earth/models/ecoinventV3AndEmberClimate/__init__.py +8 -137
  19. hestia_earth/models/ecoinventV3AndEmberClimate/cycle.py +144 -0
  20. hestia_earth/models/emepEea2019/utils.py +2 -3
  21. hestia_earth/models/environmentalFootprintV3_1/environmentalFootprintSingleOverallScore.py +5 -7
  22. hestia_earth/models/frischknechtEtAl2000/ionisingRadiationKbqU235Eq.py +41 -43
  23. hestia_earth/models/geospatialDatabase/awareWaterBasinId.py +2 -2
  24. hestia_earth/models/geospatialDatabase/awareWaterBasinId_v1.py +45 -0
  25. hestia_earth/models/hestia/default_emissions.py +5 -1
  26. hestia_earth/models/hestia/default_resourceUse.py +5 -1
  27. hestia_earth/models/hestia/landCover.py +110 -12
  28. hestia_earth/models/hestia/utils.py +1 -0
  29. hestia_earth/models/hestia/waterSalinity.py +2 -3
  30. hestia_earth/models/impact_assessment/emissions.py +1 -1
  31. hestia_earth/models/linkedImpactAssessment/emissions.py +2 -2
  32. hestia_earth/models/log.py +8 -3
  33. hestia_earth/models/mocking/search-results.json +1549 -1545
  34. hestia_earth/models/utils/__init__.py +3 -0
  35. hestia_earth/models/utils/background_emissions.py +109 -9
  36. hestia_earth/models/utils/blank_node.py +1 -11
  37. hestia_earth/models/utils/feedipedia.py +2 -2
  38. hestia_earth/models/utils/impact_assessment.py +1 -3
  39. hestia_earth/models/utils/lookup.py +1 -1
  40. hestia_earth/models/version.py +1 -1
  41. hestia_earth/orchestrator/log.py +8 -3
  42. {hestia_earth_models-0.73.8.dist-info → hestia_earth_models-0.74.0.dist-info}/METADATA +2 -2
  43. {hestia_earth_models-0.73.8.dist-info → hestia_earth_models-0.74.0.dist-info}/RECORD +58 -49
  44. tests/models/aware2_0/__init__.py +0 -0
  45. tests/models/aware2_0/test_scarcityWeightedWaterUse.py +58 -0
  46. tests/models/ecoinventV3/__init__.py +0 -0
  47. tests/models/{test_ecoinventV3.py → ecoinventV3/test_cycle.py} +5 -5
  48. tests/models/ecoinventV3AndEmberClimate/__init__.py +0 -0
  49. tests/models/{test_ecoinventV3AndEmberClimate.py → ecoinventV3AndEmberClimate/test_cycle.py} +6 -4
  50. tests/models/environmentalFootprintV3_1/test_environmentalFootprintSingleOverallScore.py +2 -2
  51. tests/models/frischknechtEtAl2000/test_ionisingRadiationKbqU235Eq.py +18 -27
  52. tests/models/hestia/test_landCover.py +16 -6
  53. tests/models/site/pre_checks/test_cache_geospatialDatabase.py +4 -4
  54. tests/models/test_config.py +53 -7
  55. tests/models/{ecoalimV9/test_utils.py → utils/test_background_emissions.py} +2 -2
  56. {hestia_earth_models-0.73.8.dist-info → hestia_earth_models-0.74.0.dist-info}/LICENSE +0 -0
  57. {hestia_earth_models-0.73.8.dist-info → hestia_earth_models-0.74.0.dist-info}/WHEEL +0 -0
  58. {hestia_earth_models-0.73.8.dist-info → hestia_earth_models-0.74.0.dist-info}/top_level.txt +0 -0
@@ -1,15 +1,12 @@
1
- from functools import lru_cache, reduce
2
- from hestia_earth.schema import EmissionMethodTier, TermTermType
3
- from hestia_earth.utils.lookup import download_lookup, _is_missing_value, column_name, lookup_columns
4
- from hestia_earth.utils.tools import non_empty_list, safe_parse_float
1
+ from functools import lru_cache
2
+ from hestia_earth.schema import TermTermType
3
+ from hestia_earth.utils.lookup import download_lookup, column_name
4
+ from hestia_earth.utils.tools import non_empty_list
5
5
 
6
- from hestia_earth.models.log import debugValues, logShouldRun
7
- from hestia_earth.models.utils import _omit
8
6
  from hestia_earth.models.utils.term import get_lookup_value
9
- from . import MODEL
7
+ from hestia_earth.models.utils.background_emissions import convert_background_lookup
10
8
 
11
9
  _LOOKUP_INDEX_KEY = column_name('ecoalimMappingName')
12
- _TIER = EmissionMethodTier.BACKGROUND.value
13
10
 
14
11
 
15
12
  def get_input_mappings(model: str, input: dict):
@@ -20,75 +17,18 @@ def get_input_mappings(model: str, input: dict):
20
17
  return [(m.split(':')[0], m.split(':')[1]) for m in mappings]
21
18
 
22
19
 
23
- def parse_term_id(term_id: str): return term_id.split('-')[0]
24
-
25
-
26
- def _process_mapping(node: dict, input: dict, term_type: TermTermType, **log_args):
27
- input_term_id = input.get('term', {}).get('@id')
28
- operation_term_id = input.get('operation', {}).get('@id')
29
- animal_term_id = input.get('animal', {}).get('@id')
30
-
31
- def add(prev: dict, mapping: tuple):
32
- gadm_id, ecoalim_key = mapping
33
- # all countries have the same coefficient
34
- coefficient = 1
35
- values = ecoalim_values(ecoalim_key, term_type)
36
- for term_id, data in values:
37
- # log run on each node so we know it did run
38
- logShouldRun(node, MODEL, input_term_id, True, methodTier=_TIER, emission_id=term_id)
39
- debugValues(node, model=MODEL, term=term_id,
40
- value=data.get('value'),
41
- coefficient=coefficient,
42
- input=input_term_id,
43
- operation=operation_term_id,
44
- animal=animal_term_id,
45
- **log_args)
46
- group_id = '-'.join(non_empty_list([term_id] + list(_omit(data, ['value']).values())))
47
- prev[group_id] = prev.get(group_id, []) + [data | {'coefficient': coefficient}]
48
- return prev
49
- return add
50
-
51
-
52
- def process_input(node: dict, input: dict, mappings: list, term_type: TermTermType, **log_args):
53
- return reduce(_process_mapping(node, input, term_type, **log_args), mappings, {})
54
-
55
-
56
- _KEY_TO_FIELD = {
57
- 'inputs': 'key'
58
- }
59
-
60
-
61
- def _key_to_field(key: str): return _KEY_TO_FIELD.get(key) or key
62
-
63
-
64
- def _values_from_column(column: str, value: str):
65
- values = column.split('+')
66
- term_id = values[0]
67
- value = safe_parse_float(value, default=None)
68
- return {
69
- term_id: {
70
- 'value': value
71
- } | {
72
- _key_to_field(v.split('[')[0]): v.split('[')[1][:-1] for v in values[1:]
73
- }
74
- } if all([
75
- column != _LOOKUP_INDEX_KEY,
76
- not _is_missing_value(value)
77
- ]) else {}
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
78
26
 
79
27
 
80
28
  @lru_cache()
81
29
  def _build_lookup(term_type: str):
82
30
  lookup = download_lookup(f"ecoalim-{term_type}.csv", keep_in_memory=False)
83
- columns = lookup_columns(lookup)
84
- return {
85
- row[_LOOKUP_INDEX_KEY]: reduce(
86
- lambda prev, curr: prev | _values_from_column(curr, row[curr]),
87
- columns,
88
- {}
89
- )
90
- for row in lookup
91
- }
31
+ return convert_background_lookup(lookup=lookup, index_column=_LOOKUP_INDEX_KEY)
92
32
 
93
33
 
94
34
  @lru_cache()
@@ -1,145 +1,13 @@
1
- from functools import reduce
2
- from hestia_earth.schema import EmissionMethodTier
3
- from hestia_earth.utils.tools import flatten, list_sum
1
+ from os.path import dirname, abspath
2
+ import sys
3
+ from importlib import import_module
4
4
 
5
- from hestia_earth.models.log import debugValues, logShouldRun, logRequirements
6
- from hestia_earth.models.data.ecoinventV3 import ecoinventV3_emissions
7
- from hestia_earth.models.utils.emission import _new_emission
8
- from hestia_earth.models.utils.background_emissions import (
9
- get_background_inputs,
10
- no_gap_filled_background_emissions,
11
- log_missing_emissions
12
- )
13
- from hestia_earth.models.utils.blank_node import group_by_keys
14
- from hestia_earth.models.utils.pesticideAI import get_pesticides_from_inputs
15
- from hestia_earth.models.utils.fertiliser import get_fertilisers_from_inputs
16
- from .utils import get_input_mappings
5
+ from hestia_earth.models.utils.blank_node import run_if_required
17
6
 
18
- REQUIREMENTS = {
19
- "Cycle": {
20
- "inputs": [{
21
- "@type": "Input",
22
- "value": "> 0",
23
- "none": {
24
- "fromCycle": "True",
25
- "producedInCycle": "True"
26
- }
27
- }],
28
- "optional": {
29
- "animals": [{
30
- "@type": "Animal",
31
- "inputs": [{
32
- "@type": "Input",
33
- "value": "> 0",
34
- "none": {
35
- "fromCycle": "True",
36
- "producedInCycle": "True"
37
- }
38
- }]
39
- }]
40
- }
41
- }
42
- }
43
- RETURNS = {
44
- "Emission": [{
45
- "term": "",
46
- "value": "",
47
- "methodTier": "background",
48
- "inputs": "",
49
- "operation": "",
50
- "animals": ""
51
- }]
52
- }
53
- LOOKUPS = {
54
- "emission": "inputProductionGroupId",
55
- "electricity": "ecoinventMapping",
56
- "fuel": "ecoinventMapping",
57
- "inorganicFertiliser": "ecoinventMapping",
58
- "material": "ecoinventMapping",
59
- "pesticideAI": "ecoinventMapping",
60
- "soilAmendment": "ecoinventMapping",
61
- "transport": "ecoinventMapping",
62
- "veterinaryDrugs": "ecoinventMapping",
63
- "feedFoodAdditive": "ecoinventMapping"
64
- }
7
+ CURRENT_DIR = dirname(abspath(__file__)) + '/'
8
+ sys.path.append(CURRENT_DIR)
65
9
  MODEL = 'ecoinventV3'
66
- MODEL_KEY = 'impactAssessment' # keep to generate entry in "model-links.json"
67
- TIER = EmissionMethodTier.BACKGROUND.value
10
+ PKG = '.'.join(['hestia_earth', 'models', MODEL])
68
11
 
69
12
 
70
- def _emission(term_id: str, value: float, input: dict):
71
- emission = _new_emission(term_id, MODEL)
72
- emission['value'] = [value]
73
- emission['methodTier'] = TIER
74
- emission['inputs'] = [input.get('term')]
75
- if input.get('operation'):
76
- emission['operation'] = input.get('operation')
77
- if input.get('animal'):
78
- emission['animals'] = [input.get('animal')]
79
- return emission
80
-
81
-
82
- def _add_emission(cycle: dict, input: dict, **extra_logs):
83
- input_term_id = input.get('term', {}).get('@id')
84
- operation_term_id = input.get('operation', {}).get('@id')
85
- animal_term_id = input.get('animal', {}).get('@id')
86
-
87
- def add(prev: dict, mapping: tuple):
88
- ecoinventName, coefficient = mapping
89
- emissions = ecoinventV3_emissions(ecoinventName)
90
- for emission_term_id, value in emissions:
91
- # log run on each emission so we know it did run
92
- logShouldRun(cycle, MODEL, input_term_id, True, methodTier=TIER, emission_id=emission_term_id, **extra_logs)
93
- debugValues(cycle, model=MODEL, term=emission_term_id,
94
- value=value,
95
- coefficient=coefficient,
96
- input=input_term_id,
97
- operation=operation_term_id,
98
- animal=animal_term_id)
99
- prev[emission_term_id] = prev.get(emission_term_id, 0) + (value * coefficient)
100
- return prev
101
- return add
102
-
103
-
104
- def _run_input(cycle: dict):
105
- no_gap_filled_background_emissions_func = no_gap_filled_background_emissions(cycle)
106
- log_missing_emissions_func = log_missing_emissions(cycle, model=MODEL, methodTier=TIER)
107
-
108
- def run(inputs: list):
109
- input = inputs[0]
110
- input_term_id = input.get('term', {}).get('@id')
111
- input_value = list_sum(flatten(input.get('value', []) for input in inputs))
112
- mappings = get_input_mappings(MODEL, cycle, input)
113
- has_mappings = len(mappings) > 0
114
-
115
- # grouping the inputs together in the logs
116
- input_parent_term_id = input.get('parent', {}).get('@id')
117
- extra_logs = {'input_group_id': input_parent_term_id} if input_parent_term_id else {}
118
-
119
- # skip input that has background emissions we have already gap-filled (model run before)
120
- has_no_gap_filled_background_emissions = no_gap_filled_background_emissions_func(input)
121
-
122
- logRequirements(cycle, model=MODEL, term=input_term_id,
123
- has_ecoinvent_mappings=has_mappings,
124
- ecoinvent_mappings=';'.join([v[0] for v in mappings]),
125
- has_no_gap_filled_background_emissions=has_no_gap_filled_background_emissions,
126
- input_value=input_value,
127
- **extra_logs)
128
-
129
- should_run = all([has_mappings, has_no_gap_filled_background_emissions, input_value])
130
- logShouldRun(cycle, MODEL, input_term_id, should_run, methodTier=TIER, **extra_logs)
131
-
132
- results = reduce(_add_emission(cycle, input, **extra_logs), mappings, {}) if should_run else {}
133
- log_missing_emissions_func(input_term_id, list(results.keys()), **extra_logs)
134
- return [
135
- _emission(term_id, value * input_value, input)
136
- for term_id, value in results.items()
137
- ]
138
- return run
139
-
140
-
141
- def run(_, cycle: dict):
142
- extra_inputs = get_pesticides_from_inputs(cycle) + get_fertilisers_from_inputs(cycle)
143
- inputs = get_background_inputs(cycle, extra_inputs=extra_inputs)
144
- grouped_inputs = reduce(group_by_keys(['term', 'operation', 'animal']), inputs, {})
145
- return flatten(map(_run_input(cycle), grouped_inputs.values()))
13
+ def run(model: str, data): return run_if_required(MODEL, model, data, import_module(f".{model}", package=PKG))
@@ -0,0 +1,140 @@
1
+ from hestia_earth.schema import EmissionMethodTier, TermTermType
2
+ from hestia_earth.utils.tools import flatten, list_sum
3
+ from hestia_earth.utils.blank_node import group_by_keys
4
+
5
+ from hestia_earth.models.log import logShouldRun, logRequirements
6
+ from hestia_earth.models.utils.emission import _new_emission
7
+ from hestia_earth.models.utils.background_emissions import (
8
+ get_background_inputs,
9
+ no_gap_filled_background_emissions,
10
+ log_missing_emissions,
11
+ parse_term_id,
12
+ process_input_mappings
13
+ )
14
+ from hestia_earth.models.utils.pesticideAI import get_pesticides_from_inputs
15
+ from hestia_earth.models.utils.fertiliser import get_fertilisers_from_inputs
16
+ from .utils import get_input_mappings, extract_input_mapping
17
+ from . import MODEL
18
+
19
+ REQUIREMENTS = {
20
+ "Cycle": {
21
+ "inputs": [{
22
+ "@type": "Input",
23
+ "value": "> 0",
24
+ "none": {
25
+ "fromCycle": "True",
26
+ "producedInCycle": "True"
27
+ }
28
+ }],
29
+ "optional": {
30
+ "animals": [{
31
+ "@type": "Animal",
32
+ "inputs": [{
33
+ "@type": "Input",
34
+ "value": "> 0",
35
+ "none": {
36
+ "fromCycle": "True",
37
+ "producedInCycle": "True"
38
+ }
39
+ }]
40
+ }]
41
+ }
42
+ }
43
+ }
44
+ RETURNS = {
45
+ "Emission": [{
46
+ "term": "",
47
+ "value": "",
48
+ "methodTier": "background",
49
+ "inputs": "",
50
+ "operation": "",
51
+ "animals": ""
52
+ }]
53
+ }
54
+ LOOKUPS = {
55
+ "emission": "inputProductionGroupId",
56
+ "electricity": "ecoinventMapping",
57
+ "fuel": "ecoinventMapping",
58
+ "inorganicFertiliser": "ecoinventMapping",
59
+ "material": "ecoinventMapping",
60
+ "pesticideAI": "ecoinventMapping",
61
+ "soilAmendment": "ecoinventMapping",
62
+ "transport": "ecoinventMapping",
63
+ "veterinaryDrugs": "ecoinventMapping",
64
+ "feedFoodAdditive": "ecoinventMapping"
65
+ }
66
+ MODEL_KEY = 'cycle'
67
+ TIER = EmissionMethodTier.BACKGROUND.value
68
+
69
+
70
+ def _emission(term_id: str, value: float, input: dict, country_id: str = None, key_id: str = None):
71
+ emission = _new_emission(term_id, MODEL, country_id, key_id)
72
+ emission['value'] = [value]
73
+ emission['methodTier'] = TIER
74
+ emission['inputs'] = [input.get('term')]
75
+ if input.get('operation'):
76
+ emission['operation'] = input.get('operation')
77
+ if input.get('animal'):
78
+ emission['animals'] = [input.get('animal')]
79
+ return emission
80
+
81
+
82
+ def _run_input(cycle: dict):
83
+ no_gap_filled_background_emissions_func = no_gap_filled_background_emissions(cycle)
84
+ log_missing_emissions_func = log_missing_emissions(cycle, model=MODEL, methodTier=TIER)
85
+
86
+ def run(inputs: list):
87
+ input = inputs[0]
88
+ input_term_id = input.get('term', {}).get('@id')
89
+ input_value = list_sum(flatten(input.get('value', []) for input in inputs))
90
+ mappings = get_input_mappings(MODEL, input)
91
+ has_mappings = len(mappings) > 0
92
+
93
+ # grouping the inputs together in the logs
94
+ input_parent_term_id = (input.get('parent', {})).get('@id') or input.get('animalId', {})
95
+ extra_logs = {
96
+ **({'input_group_id': input_parent_term_id} if input_parent_term_id else {}),
97
+ **({'animalId': input.get('animalId')} if input.get('animalId') else {})
98
+ }
99
+
100
+ # skip input that has background emissions we have already gap-filled (model run before)
101
+ has_no_gap_filled_background_emissions = no_gap_filled_background_emissions_func(input)
102
+
103
+ logRequirements(cycle, model=MODEL, term=input_term_id, model_key=MODEL_KEY,
104
+ has_mappings=has_mappings,
105
+ mappings=';'.join([v[0] for v in mappings]),
106
+ has_no_gap_filled_background_emissions=has_no_gap_filled_background_emissions,
107
+ input_value=input_value,
108
+ **extra_logs)
109
+
110
+ should_run = all([has_mappings, has_no_gap_filled_background_emissions, input_value])
111
+ logShouldRun(cycle, MODEL, input_term_id, should_run, methodTier=TIER, model_key=MODEL_KEY, **extra_logs)
112
+
113
+ results = process_input_mappings(
114
+ cycle, input, mappings, TermTermType.EMISSION,
115
+ extract_mapping=extract_input_mapping,
116
+ **(
117
+ extra_logs | {'model': MODEL, 'model_key': MODEL_KEY}
118
+ )
119
+ ) if should_run else {}
120
+ log_missing_emissions_func(input_term_id, list(map(parse_term_id, results.keys())), **(
121
+ extra_logs | {'has_mappings': has_mappings}
122
+ ))
123
+ return [
124
+ _emission(
125
+ term_id=parse_term_id(term_id),
126
+ value=sum([v['value'] * v['coefficient'] for v in values]) * input_value,
127
+ input=input,
128
+ country_id=values[0].get('country'),
129
+ key_id=values[0].get('key'),
130
+ )
131
+ for term_id, values in results.items()
132
+ ]
133
+ return run
134
+
135
+
136
+ def run(cycle: dict):
137
+ extra_inputs = get_pesticides_from_inputs(cycle) + get_fertilisers_from_inputs(cycle)
138
+ inputs = get_background_inputs(cycle, extra_inputs=extra_inputs)
139
+ grouped_inputs = group_by_keys(inputs, ['term', 'operation', 'animal'])
140
+ return flatten(map(_run_input(cycle), grouped_inputs.values()))
@@ -1,11 +1,38 @@
1
+ from functools import lru_cache
2
+ from hestia_earth.schema import TermTermType
3
+ from hestia_earth.utils.lookup import column_name, load_lookup
1
4
  from hestia_earth.utils.tools import non_empty_list
2
5
 
6
+ from hestia_earth.models.data.ecoinventV3 import get_filepath
3
7
  from hestia_earth.models.utils.term import get_lookup_value
8
+ from hestia_earth.models.utils.background_emissions import convert_background_lookup
4
9
 
10
+ _LOOKUP_INDEX_KEY = column_name('ecoinventName')
5
11
 
6
- def get_input_mappings(model: str, cycle: dict, input: dict):
12
+
13
+ def get_input_mappings(model: str, input: dict):
7
14
  term = input.get('term', {})
8
15
  term_id = term.get('@id')
9
16
  value = get_lookup_value(term, 'ecoinventMapping', model=model, term=term_id)
10
17
  mappings = non_empty_list(value.split(';')) if value else []
11
18
  return [(m.split(':')[0], float(m.split(':')[1])) for m in mappings]
19
+
20
+
21
+ def extract_input_mapping(mapping: tuple, term_type: TermTermType):
22
+ mapping_name, coefficient = mapping
23
+ values = ecoinvent_values(mapping_name, term_type)
24
+ return values, coefficient
25
+
26
+
27
+ @lru_cache()
28
+ def _build_lookup(term_type: str):
29
+ filepath = get_filepath(term_type)
30
+
31
+ lookup = load_lookup(filepath=filepath, keep_in_memory=False)
32
+ return convert_background_lookup(lookup=lookup, index_column=_LOOKUP_INDEX_KEY)
33
+
34
+
35
+ @lru_cache()
36
+ def ecoinvent_values(mapping: str, term_type: TermTermType):
37
+ data = _build_lookup(term_type.value)
38
+ return list(data.get(mapping, {}).items())
@@ -1,142 +1,13 @@
1
- from functools import reduce
2
- from hestia_earth.utils.tools import list_sum, flatten
3
- from hestia_earth.schema import EmissionMethodTier
1
+ from os.path import dirname, abspath
2
+ import sys
3
+ from importlib import import_module
4
4
 
5
- from hestia_earth.models.log import logShouldRun, logRequirements, debugValues
6
- from hestia_earth.models.utils.emission import _new_emission
7
- from hestia_earth.models.utils.background_emissions import get_background_inputs, no_gap_filled_background_emissions
8
- from hestia_earth.models.utils.blank_node import group_by_keys
9
- from hestia_earth.models.utils.completeness import _is_term_type_complete
10
- from hestia_earth.models.utils.term import get_electricity_grid_mix_terms
11
- from hestia_earth.models.data.ecoinventV3 import ecoinventV3_emissions
12
- from .utils import get_input_coefficient
13
- from ..ecoinventV3.utils import get_input_mappings
14
-
15
- REQUIREMENTS = {
16
- "Cycle": {
17
- "completeness.electricityFuel": "True",
18
- "site": {
19
- "@type": "Site",
20
- "country": {"@type": "Term", "termType": "region"}
21
- },
22
- "inputs": [{
23
- "@type": "Input",
24
- "term.@id": ["electricityGridMarketMix", "electricityGridRenewableMix"],
25
- "value": "> 0",
26
- "none": {
27
- "fromCycle": "True",
28
- "producedInCycle": "True"
29
- }
30
- }],
31
- "optional": {
32
- "animals": [{
33
- "@type": "Animal",
34
- "inputs": [{
35
- "@type": "Input",
36
- "term.@id": ["electricityGridMarketMix", "electricityGridRenewableMix"],
37
- "value": "> 0",
38
- "none": {
39
- "fromCycle": "True",
40
- "producedInCycle": "True"
41
- }
42
- }]
43
- }]
44
- }
45
- }
46
- }
47
- RETURNS = {
48
- "Emission": [{
49
- "value": "",
50
- "methodTier": "background",
51
- "@type": "Emission",
52
- "inputs": ""
53
- }]
54
- }
55
- LOOKUPS = {
56
- "electricity": "ecoinventMapping",
57
- "region-ember-energySources": "",
58
- "ember-ecoinvent-mapping": ["ember", "ecoinventId", "ecoinventName"]
59
- }
5
+ from hestia_earth.models.utils.blank_node import run_if_required
60
6
 
7
+ CURRENT_DIR = dirname(abspath(__file__)) + '/'
8
+ sys.path.append(CURRENT_DIR)
61
9
  MODEL = 'ecoinventV3AndEmberClimate'
62
- MODEL_KEY = 'impactAssessment' # keep to generate entry in "model-links.json"
63
- TIER = EmissionMethodTier.BACKGROUND.value
64
-
65
-
66
- def _emission(term_id: str, value: float, input: dict):
67
- emission = _new_emission(term_id, MODEL)
68
- emission['value'] = [value]
69
- emission['methodTier'] = TIER
70
- emission['inputs'] = [input.get('term')]
71
- if input.get('operation'):
72
- emission['operation'] = input.get('operation')
73
- if input.get('animal'):
74
- emission['animals'] = [input.get('animal')]
75
- return emission
76
-
77
-
78
- def _add_emission(cycle: dict, input: dict):
79
- input_term_id = input.get('term', {}).get('@id')
80
- operation_term_id = input.get('operation', {}).get('@id')
81
- animal_term_id = input.get('animal', {}).get('@id')
82
- # TODO: as inputs are grouped, there could be more than 1 country
83
- country_id = input.get('country', cycle.get('site', {}).get('country', {})).get('@id')
84
-
85
- def add(prev: dict, mapping: tuple):
86
- ecoinventName, _coefficient = mapping
87
- # recalculate the coefficient using the country and year if it should be included
88
- coefficient = get_input_coefficient(MODEL, cycle, country_id, ecoinventName) if _coefficient > 0 else 0
89
- emissions = ecoinventV3_emissions(ecoinventName)
90
- for emission_term_id, value in emissions:
91
- # log run on each emission so we know it did run
92
- logShouldRun(cycle, MODEL, input_term_id, True, methodTier=TIER, emission_id=emission_term_id)
93
- debugValues(cycle, model=MODEL, term=emission_term_id,
94
- value=value,
95
- coefficient=coefficient,
96
- input=input_term_id,
97
- operation=operation_term_id,
98
- animal=animal_term_id)
99
- prev[emission_term_id] = prev.get(emission_term_id, 0) + (value * coefficient)
100
- return prev
101
- return add
102
-
103
-
104
- def _run_input(cycle: dict):
105
- electricity_complete = _is_term_type_complete(cycle, 'electricityFuel')
106
- no_gap_filled_background_emissions_func = no_gap_filled_background_emissions(cycle)
107
-
108
- def run(inputs: list):
109
- input = inputs[0]
110
- input_value = list_sum(flatten(input.get('value', []) for input in inputs))
111
- input_term_id = input.get('term', {}).get('@id')
112
- mappings = get_input_mappings(MODEL, cycle, input)
113
- has_mappings = len(mappings) > 0
114
-
115
- # skip input that has background emissions we have already gap-filled (model run before)
116
- has_no_gap_filled_background_emissions = no_gap_filled_background_emissions_func(input)
117
-
118
- logRequirements(cycle, model=MODEL, term=input_term_id,
119
- has_ecoinvent_mappings=has_mappings,
120
- ecoinvent_mappings=';'.join([v[0] for v in mappings]),
121
- has_no_gap_filled_background_emissions=has_no_gap_filled_background_emissions,
122
- termType_electricityFuel_complete=electricity_complete,
123
- input_value=input_value)
124
-
125
- should_run = all([electricity_complete, has_mappings, has_no_gap_filled_background_emissions, input_value])
126
- logShouldRun(cycle, MODEL, input_term_id, should_run, methodTier=TIER)
127
-
128
- grouped_emissions = reduce(_add_emission(cycle, input), mappings, {}) if should_run else {}
129
- return [
130
- _emission(term_id, value * input_value, input)
131
- for term_id, value in grouped_emissions.items()
132
- ]
133
- return run
10
+ PKG = '.'.join(['hestia_earth', 'models', MODEL])
134
11
 
135
12
 
136
- def run(_, cycle: dict):
137
- terms = get_electricity_grid_mix_terms()
138
- inputs = get_background_inputs(cycle)
139
- # only keep the inputs matching the grid terms
140
- inputs = [i for i in inputs if i.get('term', {}).get('@id') in terms]
141
- grouped_inputs = reduce(group_by_keys(['term', 'operation', 'animal']), inputs, {})
142
- return flatten(map(_run_input(cycle), grouped_inputs.values()))
13
+ def run(model: str, data): return run_if_required(MODEL, model, data, import_module(f".{model}", package=PKG))