hestia-earth-models 0.62.1__py3-none-any.whl → 0.62.3__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/agribalyse2016/fuelElectricity.py +1 -1
- hestia_earth/models/cycle/animal/input/hestiaAggregatedData.py +1 -1
- hestia_earth/models/cycle/coldCarcassWeightPerHead.py +4 -2
- hestia_earth/models/cycle/coldDressedCarcassWeightPerHead.py +2 -2
- hestia_earth/models/cycle/concentrateFeed.py +3 -3
- hestia_earth/models/cycle/cycleDuration.py +7 -2
- hestia_earth/models/cycle/feedConversionRatio/feedConversionRatioNitrogen.py +2 -1
- hestia_earth/models/cycle/input/hestiaAggregatedData.py +1 -1
- hestia_earth/models/cycle/product/price.py +5 -1
- hestia_earth/models/cycle/product/revenue.py +6 -7
- hestia_earth/models/cycle/readyToCookWeightPerHead.py +2 -2
- hestia_earth/models/ecoinventV3/__init__.py +25 -52
- hestia_earth/models/ecoinventV3/utils.py +40 -0
- hestia_earth/models/ecoinventV3AndEmberClimate/__init__.py +92 -91
- hestia_earth/models/ecoinventV3AndEmberClimate/utils.py +15 -105
- hestia_earth/models/faostat2018/product/price.py +1 -2
- hestia_earth/models/geospatialDatabase/croppingIntensity.py +2 -1
- hestia_earth/models/geospatialDatabase/utils.py +1 -1
- hestia_earth/models/ipcc2019/aboveGroundCropResidueTotal.py +15 -10
- hestia_earth/models/ipcc2019/animal/pastureGrass.py +50 -40
- hestia_earth/models/ipcc2019/belowGroundCropResidue.py +16 -11
- hestia_earth/models/ipcc2019/carbonContent.py +1 -1
- hestia_earth/models/ipcc2019/croppingDuration.py +2 -2
- hestia_earth/models/ipcc2019/ligninContent.py +1 -1
- hestia_earth/models/ipcc2019/nitrogenContent.py +1 -1
- hestia_earth/models/ipcc2019/organicCarbonPerHa.py +3 -3
- hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_1_utils.py +5 -5
- hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_2_utils.py +217 -48
- hestia_earth/models/ipcc2019/organicCarbonPerHa_utils.py +2 -6
- hestia_earth/models/ipcc2019/pastureGrass.py +43 -41
- hestia_earth/models/ipcc2019/pastureGrass_utils.py +63 -109
- hestia_earth/models/koble2014/cropResidueManagement.py +1 -1
- hestia_earth/models/linkedImpactAssessment/emissions.py +15 -14
- hestia_earth/models/mocking/search-results.json +249 -257
- hestia_earth/models/pooreNemecek2018/longFallowPeriod.py +1 -1
- hestia_earth/models/preload_requests.py +1 -1
- hestia_earth/models/requirements.py +6 -6
- hestia_earth/models/site/organicCarbonPerHa.py +1 -1
- hestia_earth/models/utils/__init__.py +1 -1
- hestia_earth/models/utils/blank_node.py +52 -9
- hestia_earth/models/utils/cycle.py +12 -12
- hestia_earth/models/utils/measurement.py +3 -3
- hestia_earth/models/utils/property.py +6 -6
- hestia_earth/models/utils/term.py +2 -1
- hestia_earth/models/version.py +1 -1
- {hestia_earth_models-0.62.1.dist-info → hestia_earth_models-0.62.3.dist-info}/METADATA +12 -12
- {hestia_earth_models-0.62.1.dist-info → hestia_earth_models-0.62.3.dist-info}/RECORD +56 -55
- {hestia_earth_models-0.62.1.dist-info → hestia_earth_models-0.62.3.dist-info}/WHEEL +1 -1
- tests/models/cycle/product/test_revenue.py +0 -3
- tests/models/cycle/test_cycleDuration.py +1 -1
- tests/models/ipcc2019/test_organicCarbonPerHa.py +9 -20
- tests/models/ipcc2019/test_organicCarbonPerHa_tier_2_utils.py +0 -8
- tests/models/test_ecoinventV3.py +12 -0
- tests/models/test_ecoinventV3AndEmberClimate.py +5 -72
- {hestia_earth_models-0.62.1.dist-info → hestia_earth_models-0.62.3.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.62.1.dist-info → hestia_earth_models-0.62.3.dist-info}/top_level.txt +0 -0
|
@@ -1,116 +1,26 @@
|
|
|
1
|
-
from typing import Dict, Any, Union, List
|
|
2
|
-
|
|
3
1
|
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
|
|
2
|
+
from hestia_earth.utils.tools import safe_parse_float
|
|
5
3
|
|
|
6
4
|
from hestia_earth.models.log import debugMissingLookup
|
|
7
|
-
from hestia_earth.models.
|
|
8
|
-
|
|
5
|
+
from hestia_earth.models.utils.cycle import cycle_end_year
|
|
9
6
|
|
|
10
7
|
EMBER_ECOINVENT_LOOKUP_NAME = "ember-ecoinvent-mapping.csv"
|
|
8
|
+
REGION_EMBER_SOURCES_LOOKUP_NAME = "region-ember-energySources.csv"
|
|
11
9
|
|
|
12
10
|
|
|
13
|
-
def
|
|
14
|
-
|
|
15
|
-
column = column_name(grouping)
|
|
16
|
-
data = get_table_value(lookup, 'termid', country_id, column)
|
|
17
|
-
percentage = extract_grouped_data(data, year)
|
|
18
|
-
debugMissingLookup(lookup_name, 'termid', country_id, column, percentage, year=year, term=term_id, **log_args)
|
|
19
|
-
return safe_parse_float(percentage, None)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def _convert_name(name: str) -> str: return name.replace(";", ",")
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def _zero_from_non_numeric(value: Any) -> float:
|
|
26
|
-
try:
|
|
27
|
-
return float(value)
|
|
28
|
-
except (ValueError, TypeError):
|
|
29
|
-
return 0.0
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def _extract_emission_value(value_iter: Any) -> Union[float, None]:
|
|
33
|
-
value_list = list(value_iter)
|
|
34
|
-
try:
|
|
35
|
-
if len(list(value_list)) > 0 and len(list(value_list)[0]) > 1:
|
|
36
|
-
return safe_parse_float(list(value_list)[0][1], None)
|
|
37
|
-
except ValueError:
|
|
38
|
-
return None
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def _get_emission_rate_per_source(ember_ecoinvent_mapping: Dict, emission_term_id: str) -> Dict:
|
|
42
|
-
"""
|
|
43
|
-
Returns the emissions rate in kg/kWh as a mapping indexed by ember energy source name.
|
|
44
|
-
eg: {"bioenergy": 0.8947372128046288, "coal": 0.000124581084822, ... }
|
|
45
|
-
"""
|
|
11
|
+
def get_input_coefficient(model: str, cycle: dict, country_id: str, ecoinventName: str):
|
|
12
|
+
year = cycle_end_year(cycle)
|
|
46
13
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
lambda x: x[0] == emission_term_id,
|
|
50
|
-
ecoinventV3_emissions(ecoinvent_lookup["ecoinventname"])
|
|
51
|
-
))
|
|
52
|
-
for ember_source, ecoinvent_lookup in ember_ecoinvent_mapping.items()
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def get_emission(term_id: str, country: str, year: int, energy: float, model: str) -> float:
|
|
57
|
-
"""
|
|
58
|
-
Get the <term_id> emissions in kg for the energy consumed.
|
|
59
|
-
a: ecoInventId of each source - from "ember-ecoinvent-mapping.csv"
|
|
60
|
-
b: Ember sources list - from b
|
|
61
|
-
c: Percentages per source - from region-ember-energySources.csv (country, ember-source, year:value)
|
|
62
|
-
d: Energy per source (kWh) - from energy * each of c
|
|
63
|
-
e: Emissions/kWh per source - from ecoinvent (using id from b)
|
|
64
|
-
f: Emissions per source (kg) - from e * d for each source
|
|
65
|
-
g: Total emissions - from sum(f)
|
|
66
|
-
"""
|
|
67
|
-
# a: ecoInventId of each source
|
|
14
|
+
# find the matching ember source with the ecoinventName.
|
|
15
|
+
# example: "electricity, high voltage, electricity production, hard coal" > "Coal"
|
|
68
16
|
ember_ecoinvent_lookup = download_lookup(EMBER_ECOINVENT_LOOKUP_NAME)
|
|
69
|
-
|
|
70
|
-
row["ember"].lower(): {"ecoinventid": row["ecoinventid"], "ecoinventname": _convert_name(row["ecoinventname"])}
|
|
71
|
-
for row in ember_ecoinvent_lookup
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
# b: Ember sources
|
|
75
|
-
ember_sources = list(ember_ecoinvent_mapping.keys())
|
|
76
|
-
|
|
77
|
-
# c: Percentages per source
|
|
78
|
-
percentages_per_source = {
|
|
79
|
-
source: _lookup_data(
|
|
80
|
-
term_id=source,
|
|
81
|
-
grouping=source,
|
|
82
|
-
country_id=country,
|
|
83
|
-
year=str(year),
|
|
84
|
-
lookup_name="region-ember-energySources.csv",
|
|
85
|
-
model=model
|
|
86
|
-
)
|
|
87
|
-
for source in ember_sources
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
# d: Energy per source (kWh)
|
|
91
|
-
energy_per_source = {
|
|
92
|
-
source: energy * _zero_from_non_numeric(percentage) / 100
|
|
93
|
-
for source, percentage in percentages_per_source.items()
|
|
94
|
-
}
|
|
17
|
+
source_name = get_table_value(ember_ecoinvent_lookup, column_name('ecoinventName'), ecoinventName, 'ember')
|
|
95
18
|
|
|
96
|
-
#
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
19
|
+
# find the ratio for the country / year
|
|
20
|
+
region_ember_sources_lookup = download_lookup(REGION_EMBER_SOURCES_LOOKUP_NAME)
|
|
21
|
+
data = get_table_value(region_ember_sources_lookup, 'termid', country_id, column_name(source_name))
|
|
22
|
+
percentage = extract_grouped_data(data, str(year))
|
|
23
|
+
debugMissingLookup(REGION_EMBER_SOURCES_LOOKUP_NAME,
|
|
24
|
+
'termid', country_id, source_name, percentage, year=year, model=model)
|
|
101
25
|
|
|
102
|
-
|
|
103
|
-
emissions_per_source = {
|
|
104
|
-
source: energy_per_source[source] * emission_rate_per_source[source]
|
|
105
|
-
for source in ember_sources
|
|
106
|
-
if energy_per_source[source] is not None and emission_rate_per_source[source] is not None
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
# g: Total emissions (kg of <term_id>)
|
|
110
|
-
return sum(emissions_per_source.values())
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
def get_all_emission_terms() -> List[str]:
|
|
114
|
-
ember_ecoinvent_lookup = download_lookup(EMBER_ECOINVENT_LOOKUP_NAME)
|
|
115
|
-
eco_invent_name = _convert_name(ember_ecoinvent_lookup[0]["ecoinventname"])
|
|
116
|
-
return [e[0] for e in non_empty_list(ecoinventV3_emissions(eco_invent_name))]
|
|
26
|
+
return safe_parse_float(percentage, 0) / 100
|
|
@@ -157,8 +157,7 @@ def _run_by_country(cycle: dict, product: dict, country_id: str, year: int = Non
|
|
|
157
157
|
return _product(product, value / 1000 * conversion_to_number) if value is not None else None
|
|
158
158
|
|
|
159
159
|
|
|
160
|
-
def _should_run_product(product: dict):
|
|
161
|
-
return product.get(MODEL_KEY) is None
|
|
160
|
+
def _should_run_product(product: dict): return product.get(MODEL_KEY) is None
|
|
162
161
|
|
|
163
162
|
|
|
164
163
|
def run(cycle: dict):
|
|
@@ -37,7 +37,8 @@ TERM_ID = 'croppingIntensity'
|
|
|
37
37
|
|
|
38
38
|
def _practice(value: float):
|
|
39
39
|
practice = _new_practice(TERM_ID)
|
|
40
|
-
|
|
40
|
+
# force conversion to float from numpy, avoiding errors when reading it in other models
|
|
41
|
+
practice['value'] = [float(round(value, 7))]
|
|
41
42
|
return practice
|
|
42
43
|
|
|
43
44
|
|
|
@@ -152,7 +152,7 @@ def _get_cached_data(term: str, site: dict, data: dict):
|
|
|
152
152
|
|
|
153
153
|
def download(term: str, site: dict, data: dict, only_coordinates=False) -> dict:
|
|
154
154
|
"""
|
|
155
|
-
Downloads data from
|
|
155
|
+
Downloads data from HESTIA Earth Engine API.
|
|
156
156
|
|
|
157
157
|
Returns
|
|
158
158
|
-------
|
|
@@ -2,7 +2,7 @@ from hestia_earth.schema import TermTermType
|
|
|
2
2
|
from hestia_earth.utils.model import filter_list_term_type
|
|
3
3
|
from hestia_earth.utils.tools import list_sum
|
|
4
4
|
|
|
5
|
-
from hestia_earth.models.log import debugValues, logRequirements, logShouldRun
|
|
5
|
+
from hestia_earth.models.log import debugValues, logRequirements, logShouldRun, log_as_table
|
|
6
6
|
from hestia_earth.models.utils.completeness import _is_term_type_incomplete
|
|
7
7
|
from hestia_earth.models.utils.product import _new_product
|
|
8
8
|
from hestia_earth.models.utils.property import get_node_property
|
|
@@ -46,16 +46,21 @@ def _product_value(product: dict):
|
|
|
46
46
|
value = list_sum(product.get('value'))
|
|
47
47
|
dm = get_node_property(product, PROPERTY_KEY).get('value', 0)
|
|
48
48
|
yield_dm = get_yield_dm(TERM_ID, term) or 0
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
total = value * dm / 100 * yield_dm
|
|
50
|
+
return {
|
|
51
|
+
'id': term_id,
|
|
52
|
+
'value': value,
|
|
53
|
+
'dryMatter': dm,
|
|
54
|
+
'RatioYieldDM': yield_dm,
|
|
55
|
+
'total': total
|
|
56
|
+
}
|
|
55
57
|
|
|
56
58
|
|
|
57
|
-
def _run(products: list):
|
|
58
|
-
|
|
59
|
+
def _run(cycle: dict, products: list):
|
|
60
|
+
values = list(map(_product_value, products))
|
|
61
|
+
debugValues(cycle, model=MODEL, term=TERM_ID,
|
|
62
|
+
details=log_as_table(values))
|
|
63
|
+
value = sum([value.get('total', 0) for value in values])
|
|
59
64
|
return [_product(value)]
|
|
60
65
|
|
|
61
66
|
|
|
@@ -85,4 +90,4 @@ def _should_run(cycle: dict):
|
|
|
85
90
|
|
|
86
91
|
def run(cycle: dict):
|
|
87
92
|
should_run, products = _should_run(cycle)
|
|
88
|
-
return _run(products) if should_run else []
|
|
93
|
+
return _run(cycle, products) if should_run else []
|
|
@@ -12,7 +12,8 @@ from hestia_earth.schema import TermTermType
|
|
|
12
12
|
from hestia_earth.utils.model import filter_list_term_type
|
|
13
13
|
from hestia_earth.utils.tools import list_sum
|
|
14
14
|
|
|
15
|
-
from hestia_earth.models.log import logRequirements, logShouldRun, debugValues
|
|
15
|
+
from hestia_earth.models.log import logRequirements, logShouldRun, debugValues, log_as_table
|
|
16
|
+
from hestia_earth.models.utils.blank_node import lookups_logs, properties_logs
|
|
16
17
|
from hestia_earth.models.utils.input import _new_input
|
|
17
18
|
from hestia_earth.models.utils.term import get_wool_terms, get_lookup_value
|
|
18
19
|
from hestia_earth.models.utils.completeness import _is_term_type_complete, _is_term_type_incomplete
|
|
@@ -26,6 +27,7 @@ from ..pastureGrass_utils import (
|
|
|
26
27
|
calculate_REM,
|
|
27
28
|
calculate_REG,
|
|
28
29
|
calculate_NEfeed,
|
|
30
|
+
calculate_GE,
|
|
29
31
|
product_wool_energy,
|
|
30
32
|
get_animals,
|
|
31
33
|
get_animal_values
|
|
@@ -115,7 +117,8 @@ REQUIREMENTS = {
|
|
|
115
117
|
}
|
|
116
118
|
LOOKUPS = {
|
|
117
119
|
"animalManagement": [
|
|
118
|
-
"mjKgEvMilkIpcc2019"
|
|
120
|
+
"mjKgEvMilkIpcc2019",
|
|
121
|
+
"defaultFatContentEvMilkIpcc2019"
|
|
119
122
|
],
|
|
120
123
|
"animalProduct": ["mjKgEvWoolNetEnergyWoolIpcc2019", "allowedLiveAnimalTermIds"],
|
|
121
124
|
"liveAnimal": [
|
|
@@ -184,38 +187,50 @@ def calculate_NEwool(cycle: dict, animal: dict, products: list, total_weight: fl
|
|
|
184
187
|
return total_energy * animal_weight/total_weight
|
|
185
188
|
|
|
186
189
|
|
|
187
|
-
def
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
NEm, NEa, NEl, NEwork, NEp, NEg = get_animal_values(cycle, animal, system, log_node=animal)
|
|
193
|
-
|
|
194
|
-
NEm_feed, NEg_feed = calculate_NEfeed(animal)
|
|
195
|
-
debugValues(animal, model=MODEL, term=term_id, model_key=MODEL_KEY,
|
|
196
|
-
NEm=NEm,
|
|
197
|
-
NEa=NEa,
|
|
198
|
-
NEl=NEl,
|
|
199
|
-
NEwork=NEwork,
|
|
200
|
-
NEp=NEp,
|
|
201
|
-
NEg=NEg,
|
|
202
|
-
NEm_feed=NEm_feed,
|
|
203
|
-
NEg_feed=NEg_feed)
|
|
204
|
-
|
|
205
|
-
return (NEm + NEa + NEl + NEwork + NEp - NEm_feed)/REM + (NEg + NEwool - NEg_feed)/REG
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
def _run_practice(animal: dict, GE: float, meanECHHV: float):
|
|
190
|
+
def _run_practice(
|
|
191
|
+
animal: dict, values: dict, meanDE: float, meanECHHV: float, REM: float, REG: float,
|
|
192
|
+
NEwool: float, NEm_feed: float, NEg_feed: float
|
|
193
|
+
):
|
|
209
194
|
def run(practice: dict):
|
|
210
195
|
key = practice.get('key', {})
|
|
211
196
|
key_id = key.get('@id')
|
|
212
197
|
input_term_id = practice_input_id(practice)
|
|
198
|
+
|
|
199
|
+
GE = (
|
|
200
|
+
calculate_GE([values], REM, REG, NEwool, NEm_feed, NEg_feed) / (meanDE/100)
|
|
201
|
+
) if meanDE else 0
|
|
202
|
+
|
|
213
203
|
value = (GE / meanECHHV) * (list_sum(practice.get('value', [0])) / 100)
|
|
214
204
|
|
|
205
|
+
logs = log_as_table(values | {
|
|
206
|
+
'animalId': animal.get('term', {}).get('@id'),
|
|
207
|
+
'practiceKeyId': key_id,
|
|
208
|
+
'GE': GE,
|
|
209
|
+
'NEmFeed': NEm_feed,
|
|
210
|
+
'NEgFeed': NEg_feed,
|
|
211
|
+
'REM': REM,
|
|
212
|
+
'REG': REG,
|
|
213
|
+
'NEwool': NEwool,
|
|
214
|
+
'meanECHHV': meanECHHV,
|
|
215
|
+
'meanDE': meanDE
|
|
216
|
+
})
|
|
217
|
+
animal_lookups = lookups_logs(MODEL, [animal], LOOKUPS, model_key=MODEL_KEY, term=input_term_id)
|
|
218
|
+
animal_properties = properties_logs([animal], properties=[
|
|
219
|
+
'liveweightPerHead',
|
|
220
|
+
'hoursWorkedPerDay',
|
|
221
|
+
'animalsPerBirth',
|
|
222
|
+
'pregnancyRateTotal',
|
|
223
|
+
'weightAtMaturity',
|
|
224
|
+
'liveweightGain',
|
|
225
|
+
'weightAtWeaning',
|
|
226
|
+
'weightAtOneYear',
|
|
227
|
+
'weightAtSlaughter'
|
|
228
|
+
])
|
|
229
|
+
|
|
215
230
|
logRequirements(animal, model=MODEL, term=input_term_id, model_key=MODEL_KEY,
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
231
|
+
animal_logs=logs,
|
|
232
|
+
animal_lookups=animal_lookups,
|
|
233
|
+
animal_properties=animal_properties)
|
|
219
234
|
|
|
220
235
|
logShouldRun(animal, MODEL, input_term_id, True, model_key=MODEL_KEY)
|
|
221
236
|
|
|
@@ -235,21 +250,16 @@ def _run_animal(cycle: dict, meanDE: float, meanECHHV: float, system: dict, prac
|
|
|
235
250
|
total_liveWeightPerHead = _sum_liveWeightPerHead(animals)
|
|
236
251
|
|
|
237
252
|
def run(animal: dict):
|
|
238
|
-
term_id = animal.get('term', {}).get('@id')
|
|
239
|
-
|
|
240
253
|
NEwool = calculate_NEwool(cycle, animal, wool_products, total_liveWeightPerHead) if (
|
|
241
254
|
total_liveWeightPerHead > 0
|
|
242
255
|
) else 0
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
debugValues(animal, model=MODEL, term=term_id, model_key=MODEL_KEY,
|
|
246
|
-
REM=REM,
|
|
247
|
-
REG=REG,
|
|
248
|
-
NEwool=NEwool,
|
|
249
|
-
GE=GE,
|
|
250
|
-
meanDE=meanDE)
|
|
256
|
+
NEm_feed, NEg_feed = calculate_NEfeed(animal)
|
|
257
|
+
animal_values = get_animal_values(cycle, animal, system)
|
|
251
258
|
|
|
252
|
-
inputs = list(map(
|
|
259
|
+
inputs = list(map(
|
|
260
|
+
_run_practice(animal, animal_values, meanDE, meanECHHV, REM, REG, NEwool, NEm_feed, NEg_feed),
|
|
261
|
+
practices
|
|
262
|
+
))
|
|
253
263
|
return animal | {
|
|
254
264
|
'inputs': animal.get('inputs', []) + inputs
|
|
255
265
|
}
|
|
@@ -289,8 +299,8 @@ def _should_run(cycle: dict, animals: list, practices: dict):
|
|
|
289
299
|
term_type_freshForage_incomplete=freshForage_incomplete,
|
|
290
300
|
no_cycle_inputs_feed=no_cycle_inputs_feed,
|
|
291
301
|
all_animals_have_value=all_animals_have_value,
|
|
292
|
-
meanDE=
|
|
293
|
-
meanECHHV=
|
|
302
|
+
meanDE=calculate_meanDE(practices, term=term_id),
|
|
303
|
+
meanECHHV=calculate_meanECHHV(practices, term=term_id))
|
|
294
304
|
|
|
295
305
|
logShouldRun(animal, MODEL, term_id, should_run, model_key=MODEL_KEY)
|
|
296
306
|
|
|
@@ -2,7 +2,7 @@ from hestia_earth.schema import TermTermType
|
|
|
2
2
|
from hestia_earth.utils.model import filter_list_term_type
|
|
3
3
|
from hestia_earth.utils.tools import list_sum, safe_parse_float
|
|
4
4
|
|
|
5
|
-
from hestia_earth.models.log import debugValues, logRequirements, logShouldRun
|
|
5
|
+
from hestia_earth.models.log import debugValues, logRequirements, logShouldRun, log_as_table
|
|
6
6
|
from hestia_earth.models.utils.completeness import _is_term_type_incomplete
|
|
7
7
|
from hestia_earth.models.utils.product import _new_product
|
|
8
8
|
from hestia_earth.models.utils.property import get_node_property
|
|
@@ -52,17 +52,22 @@ def _product_value(product: dict):
|
|
|
52
52
|
dm = get_node_property(product, PROPERTY_KEY).get('value', 0)
|
|
53
53
|
yield_dm = get_yield_dm(TERM_ID, term) or 0
|
|
54
54
|
ratio = _get_lookup_value(term, 'IPCC_2019_Ratio_BGRes_AGRes') or 0
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
total = value * dm / 100 * yield_dm * ratio
|
|
56
|
+
return {
|
|
57
|
+
'id': term_id,
|
|
58
|
+
'value': value,
|
|
59
|
+
'dryMatter': dm,
|
|
60
|
+
'RatioYieldDM': yield_dm,
|
|
61
|
+
'RatioAboveGroundToBelowGround': ratio,
|
|
62
|
+
'total': total
|
|
63
|
+
}
|
|
62
64
|
|
|
63
65
|
|
|
64
|
-
def _run(products: list):
|
|
65
|
-
|
|
66
|
+
def _run(cycle: dict, products: list):
|
|
67
|
+
values = list(map(_product_value, products))
|
|
68
|
+
debugValues(cycle, model=MODEL, term=TERM_ID,
|
|
69
|
+
details=log_as_table(values))
|
|
70
|
+
value = sum([value.get('total', 0) for value in values])
|
|
66
71
|
return [_product(value)]
|
|
67
72
|
|
|
68
73
|
|
|
@@ -92,4 +97,4 @@ def _should_run(cycle: dict):
|
|
|
92
97
|
|
|
93
98
|
def run(cycle: dict):
|
|
94
99
|
should_run, products = _should_run(cycle)
|
|
95
|
-
return _run(products) if should_run else []
|
|
100
|
+
return _run(cycle, products) if should_run else []
|
|
@@ -114,7 +114,7 @@ def _multiple_product_values(crop: dict, residue_id: str):
|
|
|
114
114
|
# LIGNIN_CONTENT_AG_CROP_RESIDUE or LIGNIN_CONTENT_BG_CROP_RESIDUE
|
|
115
115
|
c_content = _get_lookup_value(term, _crop_residue_lookup_col(residue_id))
|
|
116
116
|
ratio = _get_lookup_value(term, 'IPCC_2019_Ratio_BGRes_AGRes') if residue_id == 'belowGroundCropResidue' else 1
|
|
117
|
-
debugValues(crop, model=MODEL, term=residue_id,
|
|
117
|
+
debugValues(crop, model=MODEL, term=residue_id, property=TERM_ID,
|
|
118
118
|
crop=term_id,
|
|
119
119
|
dryMatter=dm,
|
|
120
120
|
ratio_yield_dm=yield_dm,
|
|
@@ -80,11 +80,11 @@ def _should_run(cycle: dict):
|
|
|
80
80
|
logRequirements(cycle, model=MODEL, term=TERM_ID,
|
|
81
81
|
country=country,
|
|
82
82
|
has_flooded_rice=flooded_rice,
|
|
83
|
-
cycleDuration=cycleDuration,
|
|
83
|
+
cycleDuration=cycle.get('cycleDuration'),
|
|
84
84
|
croppingDuration=croppingDuration,
|
|
85
85
|
croppingDuration_below_cycleDuration=croppingDuration_below_cycleDuration)
|
|
86
86
|
|
|
87
|
-
should_run = all([country, cycleDuration, flooded_rice])
|
|
87
|
+
should_run = all([country, cycleDuration > 0, croppingDuration_below_cycleDuration, flooded_rice])
|
|
88
88
|
logShouldRun(cycle, MODEL, TERM_ID, should_run)
|
|
89
89
|
return should_run, country
|
|
90
90
|
|
|
@@ -114,7 +114,7 @@ def _multiple_product_values(crop: dict, residue_id: str):
|
|
|
114
114
|
# LIGNIN_CONTENT_AG_CROP_RESIDUE or LIGNIN_CONTENT_BG_CROP_RESIDUE
|
|
115
115
|
l_content = _get_lookup_value(term, _crop_residue_lookup_col(residue_id))
|
|
116
116
|
ratio = _get_lookup_value(term, 'IPCC_2019_Ratio_BGRes_AGRes') if residue_id == 'belowGroundCropResidue' else 1
|
|
117
|
-
debugValues(crop, model=MODEL, term=residue_id,
|
|
117
|
+
debugValues(crop, model=MODEL, term=residue_id, property=TERM_ID,
|
|
118
118
|
crop=term_id,
|
|
119
119
|
dryMatter=dm,
|
|
120
120
|
ratio_yield_dm=yield_dm,
|
|
@@ -114,7 +114,7 @@ def _multiple_product_value(crop: dict, residue_id: str):
|
|
|
114
114
|
# N_Content_AG_Residue or N_Content_BG_Residue
|
|
115
115
|
n_content = _get_lookup_value(term, _crop_residue_lookup_col(residue_id))
|
|
116
116
|
ratio = _get_lookup_value(term, 'IPCC_2019_Ratio_BGRes_AGRes') if residue_id == 'belowGroundCropResidue' else 1
|
|
117
|
-
debugValues(crop, model=MODEL, term=residue_id,
|
|
117
|
+
debugValues(crop, model=MODEL, term=residue_id, property=TERM_ID,
|
|
118
118
|
crop=term_id,
|
|
119
119
|
dryMatter=dm,
|
|
120
120
|
ratio_yield_dm=yield_dm,
|
|
@@ -8,7 +8,7 @@ Both tier methodologies are run as Monte Carlo simulations with 10000 iterations
|
|
|
8
8
|
|
|
9
9
|
The requirements in this file are for the Tier 1 methodology only, as it has simpler requirements. The requirements for
|
|
10
10
|
the Tier 2 methodology can be found in the
|
|
11
|
-
[
|
|
11
|
+
[HESTIA SOC wiki](https://gitlab.com/hestia-earth/hestia-engine-models/-/wikis/Soil-organic-carbon-modelling)
|
|
12
12
|
alongside data recommendations, examples and explanations for both tiers.
|
|
13
13
|
"""
|
|
14
14
|
from functools import reduce
|
|
@@ -130,12 +130,12 @@ def run(site: dict) -> list[dict]:
|
|
|
130
130
|
Parameters
|
|
131
131
|
----------
|
|
132
132
|
site : dict
|
|
133
|
-
A
|
|
133
|
+
A HESTIA `Site` node, see: https://www.hestia.earth/schema/Site.
|
|
134
134
|
|
|
135
135
|
Returns
|
|
136
136
|
-------
|
|
137
137
|
list[dict]
|
|
138
|
-
A list of
|
|
138
|
+
A list of HESTIA `Measurement` nodes containing the calculated SOC stocks and additional relevant data.
|
|
139
139
|
"""
|
|
140
140
|
should_run, run_data = _should_run(site)
|
|
141
141
|
_log_data(site, should_run, run_data)
|
|
@@ -5,7 +5,7 @@ management changes.
|
|
|
5
5
|
The model cannot not run on Sites with polar moist (ecoClimateZone 5) or polar dry (ecoClimateZone 6).
|
|
6
6
|
|
|
7
7
|
More information on this model, including data requirements **and** recommendations, and examples can be found in the
|
|
8
|
-
[
|
|
8
|
+
[HESTIA SOC wiki](https://gitlab.com/hestia-earth/hestia-engine-models/-/wikis/Soil-organic-carbon-modelling).
|
|
9
9
|
|
|
10
10
|
Source: [IPCC 2019, Vol. 4, Chapter 2](https://www.ipcc-nggip.iges.or.jp/public/2019rf/vol4.html).
|
|
11
11
|
"""
|
|
@@ -92,7 +92,7 @@ def _measurement(
|
|
|
92
92
|
descriptive_stats_dict: dict
|
|
93
93
|
) -> dict:
|
|
94
94
|
"""
|
|
95
|
-
Build a
|
|
95
|
+
Build a HESTIA `Measurement` node to contain a value and descriptive statistics calculated by the models.
|
|
96
96
|
|
|
97
97
|
The `descriptive_stats_dict` parameter should include the following keys and values from the
|
|
98
98
|
[Measurement](https://www-staging.hestia.earth/schema/Measurement) schema:
|
|
@@ -117,7 +117,7 @@ def _measurement(
|
|
|
117
117
|
Returns
|
|
118
118
|
-------
|
|
119
119
|
dict
|
|
120
|
-
A valid
|
|
120
|
+
A valid HESTIA `Measurement` node, see: https://www.hestia.earth/schema/Measurement.
|
|
121
121
|
"""
|
|
122
122
|
measurement = _new_measurement(_TERM_ID) | descriptive_stats_dict
|
|
123
123
|
measurement["dates"] = [f"{year}-12-31" for year in timestamps]
|
|
@@ -640,7 +640,7 @@ def should_run(site: dict) -> tuple[bool, dict, dict]:
|
|
|
640
640
|
Parameters
|
|
641
641
|
----------
|
|
642
642
|
site : dict
|
|
643
|
-
A
|
|
643
|
+
A HESTIA `Site` node, see: https://www.hestia.earth/schema/Site.
|
|
644
644
|
|
|
645
645
|
Returns
|
|
646
646
|
-------
|
|
@@ -694,7 +694,7 @@ def run(
|
|
|
694
694
|
) -> list[dict]:
|
|
695
695
|
"""
|
|
696
696
|
Run the IPCC (2019) Tier 1 methodology for calculating SOC stocks (in kg C ha-1) for each year in the inventory
|
|
697
|
-
and wrap each of the calculated values in
|
|
697
|
+
and wrap each of the calculated values in HESTIA measurement nodes. To avoid any errors, the `inventory` parameter
|
|
698
698
|
must be pre-validated by the `should_run` function.
|
|
699
699
|
|
|
700
700
|
See [IPCC (2019) Vol. 4, Ch. 2](https://www.ipcc-nggip.iges.or.jp/public/2019rf/vol4.html) for more information.
|