hestia-earth-models 0.61.2__py3-none-any.whl → 0.61.4__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/cycle/startDateDefinition.py +0 -1
- hestia_earth/models/ecoinventV3/__init__.py +6 -2
- hestia_earth/models/ecoinventV3AndEmberClimate/__init__.py +125 -0
- hestia_earth/models/ecoinventV3AndEmberClimate/utils.py +125 -0
- hestia_earth/models/emepEea2019/nh3ToAirInorganicFertiliser.py +10 -4
- hestia_earth/models/ipcc2006/n2OToAirInorganicFertiliserDirect.py +16 -8
- hestia_earth/models/ipcc2006/n2OToAirInorganicFertiliserIndirect.py +16 -8
- hestia_earth/models/ipcc2006/n2OToAirOrganicFertiliserDirect.py +15 -7
- hestia_earth/models/ipcc2006/n2OToAirOrganicFertiliserIndirect.py +15 -7
- hestia_earth/models/ipcc2019/animal/pastureGrass.py +1 -1
- hestia_earth/models/ipcc2019/animal/weightAtMaturity.py +104 -0
- hestia_earth/models/ipcc2019/ch4ToAirFloodedRice.py +15 -2
- hestia_earth/models/ipcc2019/n2OToAirInorganicFertiliserDirect.py +16 -8
- hestia_earth/models/ipcc2019/n2OToAirOrganicFertiliserDirect.py +16 -9
- hestia_earth/models/ipcc2019/nh3ToAirInorganicFertiliser.py +6 -0
- hestia_earth/models/ipcc2019/nh3ToAirOrganicFertiliser.py +9 -3
- hestia_earth/models/ipcc2019/no3ToGroundwaterInorganicFertiliser.py +16 -8
- hestia_earth/models/ipcc2019/no3ToGroundwaterOrganicFertiliser.py +6 -0
- hestia_earth/models/ipcc2019/noxToAirInorganicFertiliser.py +6 -0
- hestia_earth/models/ipcc2019/noxToAirOrganicFertiliser.py +9 -3
- hestia_earth/models/mocking/search-results.json +165 -114
- hestia_earth/models/pooreNemecek2018/no3ToGroundwaterInorganicFertiliser.py +16 -8
- hestia_earth/models/pooreNemecek2018/no3ToGroundwaterOrganicFertiliser.py +16 -8
- hestia_earth/models/schererPfister2015/pToDrainageWaterSoilFlux.py +13 -1
- hestia_earth/models/schererPfister2015/pToSurfaceWaterSoilFlux.py +13 -1
- hestia_earth/models/schererPfister2015/utils.py +3 -3
- hestia_earth/models/site/management.py +13 -6
- hestia_earth/models/site/organicCarbonPerHa.py +6 -4
- hestia_earth/models/stehfestBouwman2006/n2OToAirInorganicFertiliserDirect.py +16 -8
- hestia_earth/models/stehfestBouwman2006/n2OToAirOrganicFertiliserDirect.py +16 -8
- hestia_earth/models/stehfestBouwman2006/noxToAirInorganicFertiliser.py +16 -8
- hestia_earth/models/stehfestBouwman2006/noxToAirOrganicFertiliser.py +16 -8
- hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirInorganicFertiliser.py +16 -8
- hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirOrganicFertiliser.py +16 -8
- hestia_earth/models/utils/blank_node.py +29 -0
- hestia_earth/models/utils/cycle.py +6 -4
- hestia_earth/models/utils/fertiliser.py +14 -0
- hestia_earth/models/utils/inorganicFertiliser.py +7 -0
- hestia_earth/models/utils/organicFertiliser.py +9 -0
- hestia_earth/models/utils/pesticideAI.py +6 -17
- hestia_earth/models/utils/term.py +22 -0
- hestia_earth/models/version.py +1 -1
- hestia_earth/models/webbEtAl2012AndSintermannEtAl2012/nh3ToAirOrganicFertiliser.py +17 -9
- {hestia_earth_models-0.61.2.dist-info → hestia_earth_models-0.61.4.dist-info}/METADATA +2 -2
- {hestia_earth_models-0.61.2.dist-info → hestia_earth_models-0.61.4.dist-info}/RECORD +53 -46
- tests/models/ipcc2019/animal/test_weightAtMaturity.py +20 -0
- tests/models/ipcc2019/test_ch4ToAirEntericFermentation.py +0 -5
- tests/models/site/test_management.py +8 -4
- tests/models/test_ecoinventV3.py +1 -1
- tests/models/test_ecoinventV3AndEmberClimate.py +93 -0
- {hestia_earth_models-0.61.2.dist-info → hestia_earth_models-0.61.4.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.61.2.dist-info → hestia_earth_models-0.61.4.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.61.2.dist-info → hestia_earth_models-0.61.4.dist-info}/top_level.txt +0 -0
|
@@ -42,7 +42,6 @@ def _run(cycle: dict):
|
|
|
42
42
|
product = find_primary_product(cycle)
|
|
43
43
|
grouping = get_crop_grouping_fao(MODEL, MODEL_KEY, product.get('term', {}))
|
|
44
44
|
is_permanent_crop = grouping == 'Permanent crops'
|
|
45
|
-
print(is_permanent_crop)
|
|
46
45
|
return (
|
|
47
46
|
CycleStartDateDefinition.START_OF_YEAR.value if _is_last_day_of_month(cycle.get('endDate'))
|
|
48
47
|
else CycleStartDateDefinition.ONE_YEAR_PRIOR.value
|
|
@@ -23,7 +23,8 @@ from hestia_earth.models.data.ecoinventV3 import ecoinventV3_emissions
|
|
|
23
23
|
from hestia_earth.models.utils.term import get_lookup_value
|
|
24
24
|
from hestia_earth.models.utils.emission import _new_emission
|
|
25
25
|
from hestia_earth.models.utils.blank_node import group_by_keys
|
|
26
|
-
from hestia_earth.models.utils.pesticideAI import
|
|
26
|
+
from hestia_earth.models.utils.pesticideAI import get_pesticides_from_inputs
|
|
27
|
+
from hestia_earth.models.utils.fertiliser import get_fertilisers_from_inputs
|
|
27
28
|
|
|
28
29
|
REQUIREMENTS = {
|
|
29
30
|
"Cycle": {
|
|
@@ -152,7 +153,10 @@ def _animal_inputs(animal: dict):
|
|
|
152
153
|
def run(_, cycle: dict):
|
|
153
154
|
# add all the properties of some Term that inlcude others with the mapping
|
|
154
155
|
inputs = flatten(
|
|
155
|
-
cycle.get('inputs', []) +
|
|
156
|
+
cycle.get('inputs', []) +
|
|
157
|
+
list(map(_animal_inputs, cycle.get('animals', []))) +
|
|
158
|
+
get_pesticides_from_inputs(cycle) +
|
|
159
|
+
get_fertilisers_from_inputs(cycle)
|
|
156
160
|
)
|
|
157
161
|
inputs = list(filter(_should_run_input(cycle.get('products', [])), inputs))
|
|
158
162
|
# group inputs with same id/operation to avoid adding emissions twice
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ecoinvent v3 and Ember Climate
|
|
3
|
+
|
|
4
|
+
All emissions to air for the cycle.
|
|
5
|
+
"""
|
|
6
|
+
from functools import reduce
|
|
7
|
+
from typing import Tuple
|
|
8
|
+
|
|
9
|
+
from hestia_earth.utils.tools import list_sum, flatten
|
|
10
|
+
from hestia_earth.schema import EmissionMethodTier
|
|
11
|
+
|
|
12
|
+
from hestia_earth.models.log import logShouldRun, logRequirements, log_blank_nodes_id
|
|
13
|
+
from hestia_earth.models.utils.emission import _new_emission
|
|
14
|
+
from hestia_earth.models.utils.blank_node import group_by_keys
|
|
15
|
+
from hestia_earth.models.utils.completeness import _is_term_type_complete
|
|
16
|
+
from hestia_earth.models.utils.term import get_electricity_grid_mix_terms
|
|
17
|
+
from .utils import get_emission, get_all_emission_terms
|
|
18
|
+
|
|
19
|
+
REQUIREMENTS = {
|
|
20
|
+
"Cycle": {
|
|
21
|
+
"site": {
|
|
22
|
+
"@type": "Site",
|
|
23
|
+
"country": {"@type": "Term", "termType": "region"}
|
|
24
|
+
},
|
|
25
|
+
"inputs": [{
|
|
26
|
+
"@type": "Input",
|
|
27
|
+
"term.@id": ["electricityGridMarketMix", "electricityGridRenewableMix"],
|
|
28
|
+
"value": ""
|
|
29
|
+
}],
|
|
30
|
+
"completeness.electricityFuel": "True"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
RETURNS = {
|
|
34
|
+
"Emission": [{
|
|
35
|
+
"value": "",
|
|
36
|
+
"methodTier": "background",
|
|
37
|
+
"@type": "Emission",
|
|
38
|
+
"inputs": ""
|
|
39
|
+
}]
|
|
40
|
+
}
|
|
41
|
+
LOOKUPS = {
|
|
42
|
+
"region-ember-energySources": "using `country`",
|
|
43
|
+
"ember-ecoinvent-mapping": ["ember", "ecoinventId", "ecoinventName"]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
MODEL = 'ecoinventV3AndEmberClimate'
|
|
47
|
+
MODEL_KEY = 'impactAssessment' # keep to generate entry in "model-links.json"
|
|
48
|
+
TIER = EmissionMethodTier.BACKGROUND.value
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _emission(value: float, term_id: str, inputs: list, operation: dict) -> dict:
|
|
52
|
+
emission = _new_emission(term_id, MODEL)
|
|
53
|
+
emission['value'] = [value]
|
|
54
|
+
emission['methodTier'] = TIER
|
|
55
|
+
emission["inputs"] = list(inputs)
|
|
56
|
+
if operation:
|
|
57
|
+
emission["operation"] = operation
|
|
58
|
+
return emission
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _grid_inputs(inputs: list, electricity_grid_terms: list):
|
|
62
|
+
electricity_grid_term_ids = [v.get('@id') for v in electricity_grid_terms]
|
|
63
|
+
return [
|
|
64
|
+
i for i in inputs if i.get("term", {}).get("@id") in electricity_grid_term_ids
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _run_input(cycle: dict, inputs: list, emission_term_id: str, input_term: dict):
|
|
69
|
+
inputs = _grid_inputs(inputs, [input_term])
|
|
70
|
+
return [
|
|
71
|
+
_emission(
|
|
72
|
+
value=get_emission(
|
|
73
|
+
term_id=emission_term_id,
|
|
74
|
+
country=cycle.get("site", {}).get("country", {}).get("@id", ""),
|
|
75
|
+
energy=list_sum(flatten([i.get("value", []) for i in op_inputs])),
|
|
76
|
+
year=cycle.get("endDate", ""),
|
|
77
|
+
model=MODEL
|
|
78
|
+
),
|
|
79
|
+
term_id=emission_term_id,
|
|
80
|
+
inputs=[input_term],
|
|
81
|
+
operation=op_inputs[0].get("operation")
|
|
82
|
+
)
|
|
83
|
+
for op_inputs in _group_by_operation(inputs).values()
|
|
84
|
+
] if inputs else []
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _group_by_operation(inputs: list) -> dict:
|
|
88
|
+
return reduce(group_by_keys(['operation']), inputs, {})
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _run_emission(cycle: dict, electricity_grid_terms: list, inputs: list, emission_term_id: str) -> list:
|
|
92
|
+
return flatten([
|
|
93
|
+
_run_input(
|
|
94
|
+
cycle=cycle,
|
|
95
|
+
inputs=inputs,
|
|
96
|
+
emission_term_id=emission_term_id,
|
|
97
|
+
input_term=input_term
|
|
98
|
+
) for input_term in electricity_grid_terms
|
|
99
|
+
])
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _should_run_emission(cycle: dict, electricity_grid_terms: list, term_id: str) -> Tuple[bool, list]:
|
|
103
|
+
term_type_complete = _is_term_type_complete(cycle, 'electricityFuel')
|
|
104
|
+
inputs = _grid_inputs(cycle.get('inputs', []), electricity_grid_terms)
|
|
105
|
+
has_relevant_inputs = bool(inputs)
|
|
106
|
+
has_country = bool(cycle.get("site", {}).get("country", {}))
|
|
107
|
+
|
|
108
|
+
logRequirements(cycle, model=MODEL, term=term_id,
|
|
109
|
+
input_ids=log_blank_nodes_id(inputs))
|
|
110
|
+
|
|
111
|
+
should_run = all([term_type_complete, has_relevant_inputs, has_country])
|
|
112
|
+
logShouldRun(cycle, MODEL, term_id, should_run, methodTier=TIER)
|
|
113
|
+
return should_run, inputs
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _run_emissions(cycle: dict, electricity_grid_terms: list):
|
|
117
|
+
def run_emissions_for_term(term_id: str) -> list:
|
|
118
|
+
should_run, inputs = _should_run_emission(cycle, electricity_grid_terms, term_id)
|
|
119
|
+
return _run_emission(cycle, electricity_grid_terms, inputs, term_id) if should_run else []
|
|
120
|
+
return run_emissions_for_term
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def run(_, cycle: dict):
|
|
124
|
+
electricity_grid_terms = get_electricity_grid_mix_terms()
|
|
125
|
+
return flatten(list(map(_run_emissions(cycle, electricity_grid_terms), get_all_emission_terms())))
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
from typing import Dict, Any, Union, List
|
|
2
|
+
|
|
3
|
+
from hestia_earth.utils.lookup import download_lookup, get_table_value, column_name, extract_grouped_data
|
|
4
|
+
from hestia_earth.utils.tools import safe_parse_float, non_empty_list
|
|
5
|
+
|
|
6
|
+
from hestia_earth.models.log import debugMissingLookup
|
|
7
|
+
from hestia_earth.models.data.ecoinventV3 import ecoinventV3_emissions
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
EMBER_ECOINVENT_LOOKUP_NAME = "ember-ecoinvent-mapping.csv"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _lookup_data(term_id: str, grouping: str, country_id: str, year: int, lookup_name: str, **log_args):
|
|
14
|
+
lookup = download_lookup(lookup_name)
|
|
15
|
+
data = get_table_value(lookup, 'termid', country_id, column_name(grouping))
|
|
16
|
+
debugMissingLookup(lookup_name, 'termid', country_id, grouping, data, term=term_id, **log_args)
|
|
17
|
+
percentage = extract_grouped_data(data, str(year))
|
|
18
|
+
return safe_parse_float(percentage, None)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _convert_name(name: str) -> str: return name.replace(";", ",")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _safe_parse_int(value: str, default=0):
|
|
25
|
+
"""
|
|
26
|
+
Parse a string into an int.
|
|
27
|
+
"""
|
|
28
|
+
try:
|
|
29
|
+
return int(value)
|
|
30
|
+
except ValueError:
|
|
31
|
+
return default
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _zero_from_non_numeric(value: Any) -> float:
|
|
35
|
+
try:
|
|
36
|
+
return float(value)
|
|
37
|
+
except (ValueError, TypeError):
|
|
38
|
+
return 0.0
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _extract_emission_value(value_iter: Any) -> Union[float, None]:
|
|
42
|
+
value_list = list(value_iter)
|
|
43
|
+
try:
|
|
44
|
+
if len(list(value_list)) > 0 and len(list(value_list)[0]) > 1:
|
|
45
|
+
return safe_parse_float(list(value_list)[0][1])
|
|
46
|
+
except ValueError:
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _get_emission_rate_per_source(ember_ecoinvent_mapping: Dict, emission_term_id: str) -> Dict:
|
|
51
|
+
"""
|
|
52
|
+
Returns the emissions rate in kg/kWh as a mapping indexed by ember energy source name.
|
|
53
|
+
eg: {"bioenergy": 0.8947372128046288, "coal": 0.000124581084822, ... }
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
ember_source: _extract_emission_value(filter(
|
|
58
|
+
lambda x: x[0] == emission_term_id,
|
|
59
|
+
ecoinventV3_emissions(ecoinvent_lookup["ecoinventname"])
|
|
60
|
+
))
|
|
61
|
+
for ember_source, ecoinvent_lookup in ember_ecoinvent_mapping.items()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def get_emission(term_id: str, country: str, year: str, energy: float, model: str) -> float:
|
|
66
|
+
"""
|
|
67
|
+
Get the <term_id> emissions in kg for the energy consumed.
|
|
68
|
+
a: ecoInventId of each source - from "ember-ecoinvent-mapping.csv"
|
|
69
|
+
b: Ember sources list - from b
|
|
70
|
+
c: Percentages per source - from region-ember-energySources.csv (country, ember-source, year:value)
|
|
71
|
+
d: Energy per source (kWh) - from energy * each of c
|
|
72
|
+
e: Emissions/kWh per source - from ecoinvent (using id from b)
|
|
73
|
+
f: Emissions per source (kg) - from e * d for each source
|
|
74
|
+
g: Total emissions - from sum(f)
|
|
75
|
+
"""
|
|
76
|
+
# a: ecoInventId of each source
|
|
77
|
+
ember_ecoinvent_lookup = download_lookup(EMBER_ECOINVENT_LOOKUP_NAME)
|
|
78
|
+
ember_ecoinvent_mapping = {
|
|
79
|
+
row["ember"].lower(): {"ecoinventid": row["ecoinventid"], "ecoinventname": _convert_name(row["ecoinventname"])}
|
|
80
|
+
for row in ember_ecoinvent_lookup
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
# b: Ember sources
|
|
84
|
+
ember_sources = list(ember_ecoinvent_mapping.keys())
|
|
85
|
+
|
|
86
|
+
# c: Percentages per source
|
|
87
|
+
percentages_per_source = {
|
|
88
|
+
source: _lookup_data(
|
|
89
|
+
term_id=source,
|
|
90
|
+
grouping=source,
|
|
91
|
+
country_id=country,
|
|
92
|
+
year=_safe_parse_int(year),
|
|
93
|
+
lookup_name="region-ember-energySources.csv",
|
|
94
|
+
model=model
|
|
95
|
+
)
|
|
96
|
+
for source in ember_sources
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
# d: Energy per source (kWh)
|
|
100
|
+
energy_per_source = {
|
|
101
|
+
source: energy * _zero_from_non_numeric(percentage) / 100
|
|
102
|
+
for source, percentage in percentages_per_source.items()
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
# e: Emissions/kWh per source
|
|
106
|
+
emission_rate_per_source = _get_emission_rate_per_source(
|
|
107
|
+
ember_ecoinvent_mapping=ember_ecoinvent_mapping,
|
|
108
|
+
emission_term_id=term_id
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
# f: Emissions per source (kg)
|
|
112
|
+
emissions_per_source = {
|
|
113
|
+
source: energy_per_source[source] * emission_rate_per_source[source]
|
|
114
|
+
for source in ember_sources
|
|
115
|
+
if energy_per_source[source] is not None and emission_rate_per_source[source] is not None
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
# g: Total emissions (kg of <term_id>)
|
|
119
|
+
return sum(emissions_per_source.values())
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def get_all_emission_terms() -> List[str]:
|
|
123
|
+
ember_ecoinvent_lookup = download_lookup(EMBER_ECOINVENT_LOOKUP_NAME)
|
|
124
|
+
eco_invent_name = _convert_name(ember_ecoinvent_lookup[0]["ecoinventname"])
|
|
125
|
+
return [e[0] for e in non_empty_list(ecoinventV3_emissions(eco_invent_name))]
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
from functools import reduce
|
|
2
|
-
from hestia_earth.schema import EmissionMethodTier
|
|
2
|
+
from hestia_earth.schema import EmissionMethodTier
|
|
3
3
|
from hestia_earth.utils.lookup import download_lookup
|
|
4
|
-
from hestia_earth.utils.model import find_term_match
|
|
4
|
+
from hestia_earth.utils.model import find_term_match
|
|
5
5
|
from hestia_earth.utils.tools import list_sum
|
|
6
6
|
|
|
7
7
|
from hestia_earth.models.log import debugValues, logRequirements, logShouldRun
|
|
8
8
|
from hestia_earth.models.utils import _filter_list_term_unit
|
|
9
9
|
from hestia_earth.models.utils.completeness import _is_term_type_complete
|
|
10
10
|
from hestia_earth.models.utils.inorganicFertiliser import (
|
|
11
|
-
get_NH3_emission_factor, get_terms, get_term_lookup, BREAKDOWN_LOOKUP, get_country_breakdown
|
|
11
|
+
get_NH3_emission_factor, get_terms, get_term_lookup, BREAKDOWN_LOOKUP, get_country_breakdown, get_cycle_inputs
|
|
12
12
|
)
|
|
13
13
|
from hestia_earth.models.utils.constant import Units
|
|
14
14
|
from hestia_earth.models.utils.emission import _new_emission
|
|
@@ -26,6 +26,12 @@ REQUIREMENTS = {
|
|
|
26
26
|
"optional": {
|
|
27
27
|
"properties": [{"@type": "Property", "value": "", "term.@id": "nitrogenContent"}]
|
|
28
28
|
}
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"@type": "Input",
|
|
32
|
+
"value": "",
|
|
33
|
+
"term.termType": "fertiliserBrandName",
|
|
34
|
+
"properties": [{"@type": "Property", "value": "", "key.termType": "inorganicFertiliser"}]
|
|
29
35
|
}
|
|
30
36
|
],
|
|
31
37
|
"site": {
|
|
@@ -115,7 +121,7 @@ def _should_run(cycle: dict):
|
|
|
115
121
|
measurements, 'temperatureAnnual', end_date) or most_relevant_measurement_value(
|
|
116
122
|
measurements, 'temperatureLongTermAnnualMean', end_date)
|
|
117
123
|
|
|
118
|
-
inputs =
|
|
124
|
+
inputs = get_cycle_inputs(cycle)
|
|
119
125
|
N_inputs = _filter_list_term_unit(inputs, Units.KG_N)
|
|
120
126
|
has_N_inputs = len(N_inputs) > 0
|
|
121
127
|
|
|
@@ -11,15 +11,23 @@ from . import MODEL
|
|
|
11
11
|
REQUIREMENTS = {
|
|
12
12
|
"Cycle": {
|
|
13
13
|
"completeness.fertiliser": "True",
|
|
14
|
-
"inputs": [
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"
|
|
14
|
+
"inputs": [
|
|
15
|
+
{
|
|
16
|
+
"@type": "Input",
|
|
17
|
+
"value": "",
|
|
18
|
+
"term.units": ["kg", "kg N"],
|
|
19
|
+
"term.termType": "inorganicFertiliser",
|
|
20
|
+
"optional": {
|
|
21
|
+
"properties": [{"@type": "Property", "value": "", "term.@id": "nitrogenContent"}]
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"@type": "Input",
|
|
26
|
+
"value": "",
|
|
27
|
+
"term.termType": "fertiliserBrandName",
|
|
28
|
+
"properties": [{"@type": "Property", "value": "", "key.termType": "inorganicFertiliser"}]
|
|
21
29
|
}
|
|
22
|
-
|
|
30
|
+
]
|
|
23
31
|
}
|
|
24
32
|
}
|
|
25
33
|
RETURNS = {
|
|
@@ -12,15 +12,23 @@ from . import MODEL
|
|
|
12
12
|
REQUIREMENTS = {
|
|
13
13
|
"Cycle": {
|
|
14
14
|
"completeness.fertiliser": "True",
|
|
15
|
-
"inputs": [
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
15
|
+
"inputs": [
|
|
16
|
+
{
|
|
17
|
+
"@type": "Input",
|
|
18
|
+
"value": "",
|
|
19
|
+
"term.units": ["kg", "kg N"],
|
|
20
|
+
"term.termType": "inorganicFertiliser",
|
|
21
|
+
"optional": {
|
|
22
|
+
"properties": [{"@type": "Property", "value": "", "term.@id": "nitrogenContent"}]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"@type": "Input",
|
|
27
|
+
"value": "",
|
|
28
|
+
"term.termType": "fertiliserBrandName",
|
|
29
|
+
"properties": [{"@type": "Property", "value": "", "key.termType": "inorganicFertiliser"}]
|
|
22
30
|
}
|
|
23
|
-
|
|
31
|
+
],
|
|
24
32
|
"emissions": [
|
|
25
33
|
{"@type": "Emission", "value": "", "term.@id": "no3ToGroundwaterInorganicFertiliser"},
|
|
26
34
|
{"@type": "Emission", "value": "", "term.@id": "nh3ToAirInorganicFertiliser"},
|
|
@@ -11,14 +11,22 @@ from . import MODEL
|
|
|
11
11
|
REQUIREMENTS = {
|
|
12
12
|
"Cycle": {
|
|
13
13
|
"completeness.fertiliser": "True",
|
|
14
|
-
"inputs": [
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
14
|
+
"inputs": [
|
|
15
|
+
{
|
|
16
|
+
"@type": "Input",
|
|
17
|
+
"value": "",
|
|
18
|
+
"term.termType": "organicFertiliser",
|
|
19
|
+
"optional": {
|
|
20
|
+
"properties": [{"@type": "Property", "value": "", "term.@id": "nitrogenContent"}]
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"@type": "Input",
|
|
25
|
+
"value": "",
|
|
26
|
+
"term.termType": "fertiliserBrandName",
|
|
27
|
+
"properties": [{"@type": "Property", "value": "", "key.termType": "organicFertiliser"}]
|
|
20
28
|
}
|
|
21
|
-
|
|
29
|
+
]
|
|
22
30
|
}
|
|
23
31
|
}
|
|
24
32
|
RETURNS = {
|
|
@@ -12,14 +12,22 @@ from . import MODEL
|
|
|
12
12
|
REQUIREMENTS = {
|
|
13
13
|
"Cycle": {
|
|
14
14
|
"completeness.fertiliser": "True",
|
|
15
|
-
"inputs": [
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"
|
|
15
|
+
"inputs": [
|
|
16
|
+
{
|
|
17
|
+
"@type": "Input",
|
|
18
|
+
"value": "",
|
|
19
|
+
"term.termType": "organicFertiliser",
|
|
20
|
+
"optional": {
|
|
21
|
+
"properties": [{"@type": "Property", "value": "", "term.@id": "nitrogenContent"}]
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"@type": "Input",
|
|
26
|
+
"value": "",
|
|
27
|
+
"term.termType": "fertiliserBrandName",
|
|
28
|
+
"properties": [{"@type": "Property", "value": "", "key.termType": "organicFertiliser"}]
|
|
21
29
|
}
|
|
22
|
-
|
|
30
|
+
],
|
|
23
31
|
"emissions": [
|
|
24
32
|
{"@type": "Emission", "value": "", "term.@id": "no3ToGroundwaterOrganicFertiliser"},
|
|
25
33
|
{"@type": "Emission", "value": "", "term.@id": "nh3ToAirOrganicFertiliser"},
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Note: when the `liveweightPerHead` property is provided, this model will only work if the returned value is
|
|
3
|
+
greater than or equal to `liveweightPerHead` value.
|
|
4
|
+
"""
|
|
5
|
+
from hestia_earth.schema import TermTermType
|
|
6
|
+
from hestia_earth.utils.model import filter_list_term_type, find_term_match
|
|
7
|
+
from hestia_earth.utils.lookup import download_lookup, get_table_value, column_name
|
|
8
|
+
from hestia_earth.utils.tools import safe_parse_float
|
|
9
|
+
|
|
10
|
+
from hestia_earth.models.log import logRequirements, logShouldRun, debugMissingLookup
|
|
11
|
+
from hestia_earth.models.utils.property import _new_property, node_has_no_property
|
|
12
|
+
from .. import MODEL
|
|
13
|
+
|
|
14
|
+
REQUIREMENTS = {
|
|
15
|
+
"Cycle": {
|
|
16
|
+
"site": {
|
|
17
|
+
"@type": "Site",
|
|
18
|
+
"country": {"@type": "Term", "termType": "region"}
|
|
19
|
+
},
|
|
20
|
+
"animals": [{
|
|
21
|
+
"@type": "Animal",
|
|
22
|
+
"term.termType": "liveAnimal",
|
|
23
|
+
"none": {
|
|
24
|
+
"properties": [{
|
|
25
|
+
"@type": "Property",
|
|
26
|
+
"value": "",
|
|
27
|
+
"term.@id": "weightAtMaturity"
|
|
28
|
+
}]
|
|
29
|
+
},
|
|
30
|
+
"optional": {
|
|
31
|
+
"properties": [{
|
|
32
|
+
"@type": "Property",
|
|
33
|
+
"value": "",
|
|
34
|
+
"term.@id": "liveweightPerHead"
|
|
35
|
+
}]
|
|
36
|
+
}
|
|
37
|
+
}]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
LOOKUPS = {
|
|
41
|
+
"region-liveAnimal-weightAtMaturity": "weight at maturity"
|
|
42
|
+
}
|
|
43
|
+
RETURNS = {
|
|
44
|
+
"Animal": [{
|
|
45
|
+
"properties": [{
|
|
46
|
+
"@type": "Property",
|
|
47
|
+
"value": ""
|
|
48
|
+
}]
|
|
49
|
+
}]
|
|
50
|
+
}
|
|
51
|
+
TERM_ID = 'weightAtMaturity'
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _property(value: float):
|
|
55
|
+
prop = _new_property(TERM_ID, MODEL)
|
|
56
|
+
prop['value'] = value
|
|
57
|
+
return prop
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _run_animal(data: dict):
|
|
61
|
+
animal = data.get('animal')
|
|
62
|
+
value = data.get('value')
|
|
63
|
+
return animal | {
|
|
64
|
+
'properties': animal.get('properties', []) + [_property(value)]
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _lookup_value(country_id: str, animal: dict):
|
|
69
|
+
lookup_name = f"{list(LOOKUPS.keys())[0]}.csv"
|
|
70
|
+
lookup = download_lookup(lookup_name)
|
|
71
|
+
column = column_name(animal.get('term').get('@id'))
|
|
72
|
+
value = get_table_value(lookup, 'termid', country_id, column)
|
|
73
|
+
debugMissingLookup(lookup_name, 'termid', country_id, column, value, model=MODEL, term=TERM_ID)
|
|
74
|
+
return safe_parse_float(value)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _should_run(cycle: dict):
|
|
78
|
+
country_id = cycle.get('site', {}).get('country', {}).get('@id')
|
|
79
|
+
live_animals = filter_list_term_type(cycle.get('animals', []), TermTermType.LIVEANIMAL)
|
|
80
|
+
live_animals = list(filter(node_has_no_property(TERM_ID), live_animals))
|
|
81
|
+
live_animals_with_value = [{'animal': a, 'value': _lookup_value(country_id, a)} for a in live_animals]
|
|
82
|
+
|
|
83
|
+
def _should_run_animal(value: dict):
|
|
84
|
+
lookup_value = value.get('value')
|
|
85
|
+
term_id = value.get('animal').get('term').get('@id')
|
|
86
|
+
liveweightPerHead = find_term_match(value.get('animal').get('properties', []), 'liveweightPerHead', {})
|
|
87
|
+
liveweightPerHead_value = liveweightPerHead.get('value')
|
|
88
|
+
|
|
89
|
+
logRequirements(cycle, model=MODEL, term=term_id,
|
|
90
|
+
country_id=country_id,
|
|
91
|
+
weightAtMaturity=lookup_value,
|
|
92
|
+
liveweightPerHead=liveweightPerHead_value)
|
|
93
|
+
|
|
94
|
+
should_run = all([country_id, value.get('value') is not None, lookup_value >= liveweightPerHead_value])
|
|
95
|
+
logShouldRun(cycle, MODEL, term_id, should_run)
|
|
96
|
+
|
|
97
|
+
return should_run
|
|
98
|
+
|
|
99
|
+
return list(filter(_should_run_animal, live_animals_with_value))
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def run(cycle: dict):
|
|
103
|
+
animals = _should_run(cycle)
|
|
104
|
+
return list(map(_run_animal, animals))
|
|
@@ -7,6 +7,7 @@ from hestia_earth.models.log import debugValues, logRequirements, logShouldRun
|
|
|
7
7
|
from hestia_earth.models.utils.term import get_lookup_value
|
|
8
8
|
from hestia_earth.models.utils.emission import _new_emission
|
|
9
9
|
from hestia_earth.models.utils.product import has_flooded_rice
|
|
10
|
+
from hestia_earth.models.utils.organicFertiliser import get_cycle_inputs as get_organicFertiliser_inputs
|
|
10
11
|
from . import MODEL
|
|
11
12
|
|
|
12
13
|
REQUIREMENTS = {
|
|
@@ -17,7 +18,19 @@ REQUIREMENTS = {
|
|
|
17
18
|
"country": {"@type": "Term", "termType": "region"}
|
|
18
19
|
},
|
|
19
20
|
"optional": {
|
|
20
|
-
"inputs": [
|
|
21
|
+
"inputs": [
|
|
22
|
+
{
|
|
23
|
+
"@type": "Input",
|
|
24
|
+
"value": "",
|
|
25
|
+
"term.termType": "organicFertiliser"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"@type": "Input",
|
|
29
|
+
"value": "",
|
|
30
|
+
"term.termType": "fertiliserBrandName",
|
|
31
|
+
"properties": [{"@type": "Property", "value": "", "key.termType": "organicFertiliser"}]
|
|
32
|
+
}
|
|
33
|
+
],
|
|
21
34
|
"products": [{"@type": "Product", "value": "", "term.@id": "aboveGroundCropResidueIncorporated"}],
|
|
22
35
|
"practices": [
|
|
23
36
|
{"@type": "Practice", "value": "", "term.termType": "cropResidueManagement"},
|
|
@@ -99,7 +112,7 @@ def _get_fertiliser_value(input: dict, suffix: str = ''):
|
|
|
99
112
|
|
|
100
113
|
def _calculate_SFo(cycle: dict, suffix: str = ''):
|
|
101
114
|
cropResidue = _get_cropResidue_value(cycle, suffix)
|
|
102
|
-
fertilisers =
|
|
115
|
+
fertilisers = get_organicFertiliser_inputs(cycle)
|
|
103
116
|
fert_value = list_sum([_get_fertiliser_value(i, suffix) for i in fertilisers])
|
|
104
117
|
return (1 + (fert_value/1000) + (cropResidue/1000)) ** 0.59
|
|
105
118
|
|
|
@@ -12,15 +12,23 @@ from . import MODEL
|
|
|
12
12
|
REQUIREMENTS = {
|
|
13
13
|
"Cycle": {
|
|
14
14
|
"completeness.fertiliser": "True",
|
|
15
|
-
"inputs": [
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
15
|
+
"inputs": [
|
|
16
|
+
{
|
|
17
|
+
"@type": "Input",
|
|
18
|
+
"value": "",
|
|
19
|
+
"term.units": ["kg", "kg N"],
|
|
20
|
+
"term.termType": "inorganicFertiliser",
|
|
21
|
+
"optional": {
|
|
22
|
+
"properties": [{"@type": "Property", "value": "", "term.@id": "nitrogenContent"}]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"@type": "Input",
|
|
27
|
+
"value": "",
|
|
28
|
+
"term.termType": "fertiliserBrandName",
|
|
29
|
+
"properties": [{"@type": "Property", "value": "", "key.termType": "inorganicFertiliser"}]
|
|
22
30
|
}
|
|
23
|
-
|
|
31
|
+
],
|
|
24
32
|
"optional": {
|
|
25
33
|
"endDate": "",
|
|
26
34
|
"site": {
|