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,145 +1,13 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from
|
|
1
|
+
from os.path import dirname, abspath
|
|
2
|
+
import sys
|
|
3
|
+
from importlib import import_module
|
|
4
4
|
|
|
5
|
-
from hestia_earth.models.
|
|
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
|
-
|
|
19
|
-
|
|
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
|
-
|
|
67
|
-
TIER = EmissionMethodTier.BACKGROUND.value
|
|
10
|
+
PKG = '.'.join(['hestia_earth', 'models', MODEL])
|
|
68
11
|
|
|
69
12
|
|
|
70
|
-
def
|
|
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
|
-
grouped_emissions = reduce(_add_emission(cycle, input, **extra_logs), mappings, {}) if should_run else {}
|
|
133
|
-
log_missing_emissions_func(input_term_id, list(grouped_emissions.keys()), **extra_logs)
|
|
134
|
-
return [
|
|
135
|
-
_emission(term_id, value * input_value, input)
|
|
136
|
-
for term_id, value in grouped_emissions.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
|
-
|
|
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
|
|
2
|
-
|
|
3
|
-
from
|
|
1
|
+
from os.path import dirname, abspath
|
|
2
|
+
import sys
|
|
3
|
+
from importlib import import_module
|
|
4
4
|
|
|
5
|
-
from hestia_earth.models.
|
|
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
|
-
|
|
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(
|
|
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))
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
from functools import reduce
|
|
2
|
+
from hestia_earth.utils.tools import list_sum, flatten
|
|
3
|
+
from hestia_earth.schema import EmissionMethodTier, TermTermType
|
|
4
|
+
from hestia_earth.utils.blank_node import group_by_keys
|
|
5
|
+
|
|
6
|
+
from hestia_earth.models.log import logShouldRun, logRequirements, debugValues
|
|
7
|
+
from hestia_earth.models.utils.emission import _new_emission
|
|
8
|
+
from hestia_earth.models.utils.background_emissions import get_background_inputs, no_gap_filled_background_emissions
|
|
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 .utils import get_input_coefficient
|
|
12
|
+
from ..ecoinventV3.utils import get_input_mappings, ecoinvent_values
|
|
13
|
+
from . import MODEL
|
|
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
|
+
"term": "",
|
|
50
|
+
"value": "",
|
|
51
|
+
"methodTier": "background",
|
|
52
|
+
"inputs": "",
|
|
53
|
+
"operation": "",
|
|
54
|
+
"animals": ""
|
|
55
|
+
}]
|
|
56
|
+
}
|
|
57
|
+
LOOKUPS = {
|
|
58
|
+
"emission": "inputProductionGroupId",
|
|
59
|
+
"electricity": "ecoinventMapping",
|
|
60
|
+
"region-ember-energySources": "",
|
|
61
|
+
"ember-ecoinvent-mapping": ["ember", "ecoinventId", "ecoinventName"]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
MODEL_KEY = 'cycle'
|
|
65
|
+
TIER = EmissionMethodTier.BACKGROUND.value
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _emission(term_id: str, value: float, input: dict):
|
|
69
|
+
emission = _new_emission(term_id, MODEL)
|
|
70
|
+
emission['value'] = [value]
|
|
71
|
+
emission['methodTier'] = TIER
|
|
72
|
+
emission['inputs'] = [input.get('term')]
|
|
73
|
+
if input.get('operation'):
|
|
74
|
+
emission['operation'] = input.get('operation')
|
|
75
|
+
if input.get('animal'):
|
|
76
|
+
emission['animals'] = [input.get('animal')]
|
|
77
|
+
return emission
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _add_emission(cycle: dict, input: dict):
|
|
81
|
+
input_term_id = input.get('term', {}).get('@id')
|
|
82
|
+
operation_term_id = input.get('operation', {}).get('@id')
|
|
83
|
+
animal_term_id = input.get('animal', {}).get('@id')
|
|
84
|
+
# TODO: as inputs are grouped, there could be more than 1 country
|
|
85
|
+
country_id = input.get('country', cycle.get('site', {}).get('country', {})).get('@id')
|
|
86
|
+
|
|
87
|
+
def add(prev: dict, mapping: tuple):
|
|
88
|
+
ecoinventName, _coefficient = mapping
|
|
89
|
+
# recalculate the coefficient using the country and year if it should be included
|
|
90
|
+
coefficient = get_input_coefficient(MODEL, cycle, country_id, ecoinventName) if _coefficient > 0 else 0
|
|
91
|
+
emissions = ecoinvent_values(ecoinventName, TermTermType.EMISSION)
|
|
92
|
+
for emission_term_id, data in emissions:
|
|
93
|
+
# log run on each emission so we know it did run
|
|
94
|
+
logShouldRun(cycle, MODEL, input_term_id, True, methodTier=TIER, emission_id=emission_term_id)
|
|
95
|
+
debugValues(cycle, model=MODEL, term=emission_term_id,
|
|
96
|
+
value=data.get('value'),
|
|
97
|
+
coefficient=coefficient,
|
|
98
|
+
input=input_term_id,
|
|
99
|
+
operation=operation_term_id,
|
|
100
|
+
animal=animal_term_id)
|
|
101
|
+
prev[emission_term_id] = prev.get(emission_term_id, 0) + (data.get('value') * coefficient)
|
|
102
|
+
return prev
|
|
103
|
+
return add
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _run_input(cycle: dict):
|
|
107
|
+
electricity_complete = _is_term_type_complete(cycle, 'electricityFuel')
|
|
108
|
+
no_gap_filled_background_emissions_func = no_gap_filled_background_emissions(cycle)
|
|
109
|
+
|
|
110
|
+
def run(inputs: list):
|
|
111
|
+
input = inputs[0]
|
|
112
|
+
input_value = list_sum(flatten(input.get('value', []) for input in inputs))
|
|
113
|
+
input_term_id = input.get('term', {}).get('@id')
|
|
114
|
+
mappings = get_input_mappings(MODEL, input)
|
|
115
|
+
has_mappings = len(mappings) > 0
|
|
116
|
+
|
|
117
|
+
# skip input that has background emissions we have already gap-filled (model run before)
|
|
118
|
+
has_no_gap_filled_background_emissions = no_gap_filled_background_emissions_func(input)
|
|
119
|
+
|
|
120
|
+
logRequirements(cycle, model=MODEL, term=input_term_id,
|
|
121
|
+
has_ecoinvent_mappings=has_mappings,
|
|
122
|
+
ecoinvent_mappings=';'.join([v[0] for v in mappings]),
|
|
123
|
+
has_no_gap_filled_background_emissions=has_no_gap_filled_background_emissions,
|
|
124
|
+
termType_electricityFuel_complete=electricity_complete,
|
|
125
|
+
input_value=input_value)
|
|
126
|
+
|
|
127
|
+
should_run = all([electricity_complete, has_mappings, has_no_gap_filled_background_emissions, input_value])
|
|
128
|
+
logShouldRun(cycle, MODEL, input_term_id, should_run, methodTier=TIER)
|
|
129
|
+
|
|
130
|
+
grouped_emissions = reduce(_add_emission(cycle, input), mappings, {}) if should_run else {}
|
|
131
|
+
return [
|
|
132
|
+
_emission(term_id, value * input_value, input)
|
|
133
|
+
for term_id, value in grouped_emissions.items()
|
|
134
|
+
]
|
|
135
|
+
return run
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def run(cycle: dict):
|
|
139
|
+
terms = get_electricity_grid_mix_terms()
|
|
140
|
+
inputs = get_background_inputs(cycle)
|
|
141
|
+
# only keep the inputs matching the grid terms
|
|
142
|
+
inputs = [i for i in inputs if i.get('term', {}).get('@id') in terms]
|
|
143
|
+
grouped_inputs = group_by_keys(inputs, ['term', 'operation', 'animal'])
|
|
144
|
+
return flatten(map(_run_input(cycle), grouped_inputs.values()))
|
|
@@ -26,8 +26,8 @@ RETURNS = {
|
|
|
26
26
|
}]
|
|
27
27
|
}
|
|
28
28
|
LOOKUPS = {
|
|
29
|
-
"fuel": "
|
|
30
|
-
"operation": "
|
|
29
|
+
"fuel": "n2oToAirFuelCombustionEmepEea2019",
|
|
30
|
+
"operation": "n2oToAirFuelCombustionEmepEea2019"
|
|
31
31
|
}
|
|
32
32
|
TERM_ID = 'n2OToAirFuelCombustionDirect'
|
|
33
33
|
TIER = EmissionMethodTier.TIER_1.value
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
from functools import reduce
|
|
2
1
|
from hestia_earth.schema import TermTermType, SiteSiteType
|
|
3
2
|
from hestia_earth.utils.model import filter_list_term_type
|
|
4
3
|
from hestia_earth.utils.lookup import extract_grouped_data
|
|
4
|
+
from hestia_earth.utils.blank_node import group_by_keys
|
|
5
5
|
from hestia_earth.utils.tools import list_sum, safe_parse_float
|
|
6
6
|
|
|
7
7
|
from hestia_earth.models.log import logRequirements, logShouldRun
|
|
8
8
|
from hestia_earth.models.utils.completeness import _is_term_type_complete
|
|
9
|
-
from hestia_earth.models.utils.blank_node import group_by_keys
|
|
10
9
|
from hestia_earth.models.utils.term import get_lookup_value
|
|
11
10
|
from hestia_earth.models.utils.cycle import get_animals_by_period
|
|
12
11
|
from hestia_earth.models.utils.emission import _new_emission
|
|
@@ -90,7 +89,7 @@ def get_fuel_inputs(term_id: str, cycle: dict, lookup_col: str):
|
|
|
90
89
|
|
|
91
90
|
|
|
92
91
|
def group_fuel_inputs(inputs: list):
|
|
93
|
-
return
|
|
92
|
+
return group_by_keys(inputs, ['input-id', 'operation-id']) if len(inputs) > 0 else None
|
|
94
93
|
|
|
95
94
|
|
|
96
95
|
def _get_emissions_factor(animal: dict, lookup_col: str) -> float:
|