hestia-earth-models 0.74.1__py3-none-any.whl → 0.74.2__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/hestia/landCover.py +6 -5
- hestia_earth/models/hestia/management.py +49 -58
- hestia_earth/models/hestia/utils.py +0 -1
- hestia_earth/models/ipcc2019/animal/pastureGrass.py +11 -6
- hestia_earth/models/ipcc2019/animal/utils.py +2 -2
- hestia_earth/models/ipcc2019/pastureGrass.py +7 -2
- hestia_earth/models/mocking/search-results.json +1592 -1588
- hestia_earth/models/version.py +1 -1
- {hestia_earth_models-0.74.1.dist-info → hestia_earth_models-0.74.2.dist-info}/METADATA +1 -1
- {hestia_earth_models-0.74.1.dist-info → hestia_earth_models-0.74.2.dist-info}/RECORD +14 -14
- tests/models/hestia/test_management.py +29 -1
- {hestia_earth_models-0.74.1.dist-info → hestia_earth_models-0.74.2.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.74.1.dist-info → hestia_earth_models-0.74.2.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.74.1.dist-info → hestia_earth_models-0.74.2.dist-info}/top_level.txt +0 -0
|
@@ -28,8 +28,7 @@ from .utils import (
|
|
|
28
28
|
TOTAL_CROPLAND,
|
|
29
29
|
TOTAL_AGRICULTURAL_CHANGE,
|
|
30
30
|
ALL_LAND_USE_TERMS,
|
|
31
|
-
crop_ipcc_land_use_category
|
|
32
|
-
LAND_USE_NAMES_FROM_ID
|
|
31
|
+
crop_ipcc_land_use_category
|
|
33
32
|
)
|
|
34
33
|
from . import MODEL
|
|
35
34
|
|
|
@@ -839,15 +838,17 @@ def _should_run_historical_land_use_change_single_crop(
|
|
|
839
838
|
percent_pasture_was=percent_pasture_was
|
|
840
839
|
)
|
|
841
840
|
|
|
841
|
+
fao_name = _get_faostat_name(term)
|
|
842
|
+
|
|
842
843
|
# Cell E8
|
|
843
844
|
expansion_factor = _get_ratio_start_and_end_values(
|
|
844
|
-
expansion=changes[
|
|
845
|
+
expansion=changes[land_use_type],
|
|
845
846
|
fao_name=land_use_type,
|
|
846
847
|
country_id=country_id,
|
|
847
848
|
end_year=end_year
|
|
848
|
-
) if term.get("@id") in _TOP_LEVEL_LAND_USE_TYPE_IDS else get_ratio_of_expanded_area(
|
|
849
|
+
) if term.get("@id") in _TOP_LEVEL_LAND_USE_TYPE_IDS or fao_name == "" else get_ratio_of_expanded_area(
|
|
849
850
|
country_id=country_id,
|
|
850
|
-
fao_name=
|
|
851
|
+
fao_name=fao_name,
|
|
851
852
|
end_year=end_year
|
|
852
853
|
)
|
|
853
854
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from typing import List
|
|
2
2
|
from datetime import timedelta, datetime
|
|
3
|
-
from hestia_earth.schema import SchemaType, TermTermType,
|
|
3
|
+
from hestia_earth.schema import SchemaType, TermTermType, COMPLETENESS_MAPPING
|
|
4
4
|
from hestia_earth.utils.lookup import column_name, get_table_value, download_lookup
|
|
5
5
|
from hestia_earth.utils.model import filter_list_term_type
|
|
6
|
-
from hestia_earth.utils.tools import safe_parse_float, flatten
|
|
6
|
+
from hestia_earth.utils.tools import safe_parse_float, flatten, is_number, is_boolean
|
|
7
7
|
from hestia_earth.utils.blank_node import get_node_value
|
|
8
8
|
|
|
9
9
|
from hestia_earth.models.log import logRequirements, logShouldRun, log_as_table
|
|
@@ -16,6 +16,7 @@ from hestia_earth.models.utils.site import (
|
|
|
16
16
|
related_cycles, get_land_cover_term_id as get_landCover_term_id_from_site_type
|
|
17
17
|
)
|
|
18
18
|
from . import MODEL
|
|
19
|
+
from ..utils.property import get_property_lookup_value
|
|
19
20
|
|
|
20
21
|
REQUIREMENTS = {
|
|
21
22
|
"Site": {
|
|
@@ -67,11 +68,12 @@ RETURNS = {
|
|
|
67
68
|
}]
|
|
68
69
|
}
|
|
69
70
|
LOOKUPS = {
|
|
71
|
+
"biochar": "inputGapFillManagementTermId",
|
|
70
72
|
"crop": ["landCoverTermId", "maximumCycleDuration"],
|
|
71
73
|
"forage": ["landCoverTermId"],
|
|
72
|
-
"inorganicFertiliser": "
|
|
73
|
-
"organicFertiliser": "
|
|
74
|
-
"soilAmendment": "
|
|
74
|
+
"inorganicFertiliser": "inputGapFillManagementTermId",
|
|
75
|
+
"organicFertiliser": "inputGapFillManagementTermId",
|
|
76
|
+
"soilAmendment": "inputGapFillManagementTermId",
|
|
75
77
|
"landUseManagement": "GAP_FILL_TO_MANAGEMENT",
|
|
76
78
|
"property": "GAP_FILL_TO_MANAGEMENT"
|
|
77
79
|
}
|
|
@@ -87,41 +89,6 @@ _PRACTICES_TERM_TYPES = [
|
|
|
87
89
|
TermTermType.LANDCOVER
|
|
88
90
|
]
|
|
89
91
|
_PRACTICES_COMPLETENESS_MAPPING = COMPLETENESS_MAPPING.get(SchemaType.PRACTICE.value, {})
|
|
90
|
-
_ANIMAL_MANURE_USED_TERM_ID = "animalManureUsed"
|
|
91
|
-
_INORGANIC_NITROGEN_FERTILISER_USED_TERM_ID = "inorganicNitrogenFertiliserUsed"
|
|
92
|
-
_ORGANIC_FERTILISER_USED_TERM_ID = "organicFertiliserUsed"
|
|
93
|
-
_AMENDMENT_INCREASING_C_USED_TERM_ID = "amendmentIncreasingSoilCarbonUsed"
|
|
94
|
-
_INPUT_RULES = {
|
|
95
|
-
TermTermType.INORGANICFERTILISER.value: (
|
|
96
|
-
(
|
|
97
|
-
TermTermType.INORGANICFERTILISER.value, # Lookup column
|
|
98
|
-
lambda x: safe_parse_float(x, default=0) > 0, # Condition
|
|
99
|
-
_INORGANIC_NITROGEN_FERTILISER_USED_TERM_ID # New term.
|
|
100
|
-
),
|
|
101
|
-
),
|
|
102
|
-
TermTermType.SOILAMENDMENT.value: (
|
|
103
|
-
(
|
|
104
|
-
TermTermType.SOILAMENDMENT.value,
|
|
105
|
-
lambda x: bool(x) is True,
|
|
106
|
-
_AMENDMENT_INCREASING_C_USED_TERM_ID
|
|
107
|
-
),
|
|
108
|
-
),
|
|
109
|
-
TermTermType.ORGANICFERTILISER.value: (
|
|
110
|
-
(
|
|
111
|
-
TermTermType.SOILAMENDMENT.value,
|
|
112
|
-
lambda x: bool(x) is True,
|
|
113
|
-
_ORGANIC_FERTILISER_USED_TERM_ID
|
|
114
|
-
),
|
|
115
|
-
(
|
|
116
|
-
TermTermType.ORGANICFERTILISER.value,
|
|
117
|
-
lambda x: bool(x) is True,
|
|
118
|
-
_ANIMAL_MANURE_USED_TERM_ID
|
|
119
|
-
)
|
|
120
|
-
)
|
|
121
|
-
}
|
|
122
|
-
_SKIP_LAND_COVER_SITE_TYPES = [
|
|
123
|
-
SiteSiteType.CROPLAND.value
|
|
124
|
-
]
|
|
125
92
|
|
|
126
93
|
|
|
127
94
|
def management(data: dict):
|
|
@@ -135,6 +102,10 @@ def management(data: dict):
|
|
|
135
102
|
return node
|
|
136
103
|
|
|
137
104
|
|
|
105
|
+
def _is_cover_crop(term_id: str) -> bool:
|
|
106
|
+
return get_property_lookup_value(model=MODEL, term_id=term_id, column="blankNodesGroup") == "Cover crops"
|
|
107
|
+
|
|
108
|
+
|
|
138
109
|
def _get_cycle_duration(cycle: dict, land_cover_id: str = None):
|
|
139
110
|
cycle_duration = cycle.get('cycleDuration')
|
|
140
111
|
lookup_value = None if cycle_duration or not land_cover_id else safe_parse_float(get_table_value(
|
|
@@ -227,43 +198,63 @@ def _get_relevant_items(cycle: dict, item_name: str, term_types: List[TermTermTy
|
|
|
227
198
|
]
|
|
228
199
|
|
|
229
200
|
|
|
230
|
-
def
|
|
231
|
-
|
|
232
|
-
for column, condition, new_term in _INPUT_RULES[term.get('termType')]:
|
|
233
|
-
lookup_result = get_lookup_value(term, LOOKUPS[column], model=MODEL, term=term.get('@id'), model_key=MODEL_KEY)
|
|
201
|
+
def _input_gap_fill_term_id(input: dict):
|
|
202
|
+
return get_lookup_value(input.get('term'), 'inputGapFillManagementTermId')
|
|
234
203
|
|
|
235
|
-
if condition(lookup_result):
|
|
236
|
-
term_types.append(node | {'id': new_term})
|
|
237
204
|
|
|
238
|
-
|
|
205
|
+
def _input_value_valid(input: dict):
|
|
206
|
+
value = get_node_value(input)
|
|
207
|
+
return value > 0 if is_number(value) else bool(value) is True if is_boolean(value) else False
|
|
239
208
|
|
|
240
209
|
|
|
241
|
-
def _run_from_inputs(
|
|
242
|
-
|
|
243
|
-
|
|
210
|
+
def _run_from_inputs(cycle: dict) -> list:
|
|
211
|
+
inputs_with_ids = [
|
|
212
|
+
{
|
|
213
|
+
'input-id': input.get('term', {}).get('@id'),
|
|
214
|
+
'input-valid': _input_value_valid(input),
|
|
215
|
+
'term-id': _input_gap_fill_term_id(input)
|
|
216
|
+
} for input in cycle.get('inputs', [])
|
|
217
|
+
]
|
|
218
|
+
return [
|
|
219
|
+
{
|
|
220
|
+
'id': input.get('term-id'),
|
|
244
221
|
'value': True,
|
|
245
222
|
'startDate': cycle.get('startDate'),
|
|
246
223
|
'endDate': cycle.get('endDate')
|
|
247
|
-
}
|
|
248
|
-
for input in
|
|
249
|
-
if
|
|
224
|
+
}
|
|
225
|
+
for input in inputs_with_ids
|
|
226
|
+
if all([
|
|
227
|
+
input.get('term-id'),
|
|
228
|
+
input.get('input-valid')
|
|
229
|
+
])
|
|
230
|
+
]
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def _cycle_has_existing_non_cover_land_cover_nodes(cycle: dict) -> bool:
|
|
234
|
+
# if there are any landCover blank nodes in Practices without a Property from the
|
|
235
|
+
# blankNodesGroup = Cover crops lookup, return True, else False
|
|
236
|
+
return any([
|
|
237
|
+
practice for practice in cycle.get("practices", [])
|
|
238
|
+
if practice.get("term", {}).get("termType") == TermTermType.LANDCOVER.value
|
|
239
|
+
and not any(prop for prop in practice.get("properties", [])
|
|
240
|
+
if _is_cover_crop(prop.get("term", {}).get("@id")))
|
|
250
241
|
])
|
|
251
|
-
return inputs
|
|
252
242
|
|
|
253
243
|
|
|
254
244
|
def _run_from_siteType(site: dict, cycle: dict):
|
|
255
245
|
site_type = site.get('siteType')
|
|
256
|
-
site_type_id = get_landCover_term_id_from_site_type(site_type)
|
|
257
|
-
else None
|
|
246
|
+
site_type_id = get_landCover_term_id_from_site_type(site_type)
|
|
258
247
|
start_date = cycle.get('startDate') or _gap_filled_start_date(
|
|
259
248
|
cycle=cycle,
|
|
260
249
|
end_date=cycle.get('endDate'),
|
|
261
250
|
land_cover_id=site_type_id
|
|
262
251
|
).get('startDate')
|
|
252
|
+
no_land_cover_blank_node = not _cycle_has_existing_non_cover_land_cover_nodes(cycle)
|
|
263
253
|
|
|
264
|
-
should_run = all([site_type_id, start_date])
|
|
254
|
+
should_run = all([site_type_id, start_date, no_land_cover_blank_node])
|
|
265
255
|
return [{
|
|
266
256
|
'id': site_type_id,
|
|
257
|
+
'termType': TermTermType.LANDCOVER.value,
|
|
267
258
|
'value': 100,
|
|
268
259
|
'startDate': start_date,
|
|
269
260
|
'endDate': cycle.get('endDate')
|
|
@@ -296,7 +287,7 @@ def _run_from_practices(cycle: dict):
|
|
|
296
287
|
|
|
297
288
|
|
|
298
289
|
def _run_cycle(site: dict, cycle: dict):
|
|
299
|
-
inputs = _run_from_inputs(
|
|
290
|
+
inputs = _run_from_inputs(cycle)
|
|
300
291
|
site_types = _run_from_siteType(site=site, cycle=cycle)
|
|
301
292
|
practices = _run_from_practices(cycle)
|
|
302
293
|
return [
|
|
@@ -35,7 +35,6 @@ LAND_USE_TERMS_FOR_TRANSFORMATION = {
|
|
|
35
35
|
PERMANENT_PASTURE: ("permanentPasture", "Permanent pasture"),
|
|
36
36
|
OTHER_LAND: ("otherLand", OTHER_LAND) # Not used yet
|
|
37
37
|
}
|
|
38
|
-
LAND_USE_NAMES_FROM_ID = {v[0]: k for k, v in LAND_USE_TERMS_FOR_TRANSFORMATION.items()} | {"cropland": TOTAL_CROPLAND}
|
|
39
38
|
|
|
40
39
|
|
|
41
40
|
def crop_ipcc_land_use_category(
|
|
@@ -225,7 +225,7 @@ def _run_practice(animal: dict, values: dict, meanDE: float, meanECHHV: float, R
|
|
|
225
225
|
])
|
|
226
226
|
has_positive_feed_values = all([NEm_feed >= 0, NEg_feed >= 0])
|
|
227
227
|
|
|
228
|
-
logRequirements(animal, model=MODEL, term=input_term_id, model_key=MODEL_KEY,
|
|
228
|
+
logRequirements(animal, model=MODEL, term=input_term_id, animalId=animal.get('animalId'), model_key=MODEL_KEY,
|
|
229
229
|
feed_logs=log_as_table(log_feed),
|
|
230
230
|
has_positive_feed_values=has_positive_feed_values,
|
|
231
231
|
animal_logs=logs,
|
|
@@ -233,7 +233,7 @@ def _run_practice(animal: dict, values: dict, meanDE: float, meanECHHV: float, R
|
|
|
233
233
|
animal_properties=animal_properties)
|
|
234
234
|
|
|
235
235
|
should_run = all([has_positive_feed_values])
|
|
236
|
-
logShouldRun(animal, MODEL, input_term_id, should_run, model_key=MODEL_KEY)
|
|
236
|
+
logShouldRun(animal, MODEL, input_term_id, should_run, animalId=animal.get('animalId'), model_key=MODEL_KEY)
|
|
237
237
|
|
|
238
238
|
return _input(input_term_id, value) if should_run else None
|
|
239
239
|
|
|
@@ -278,32 +278,37 @@ def _should_run(cycle: dict, animals: list, practices: dict):
|
|
|
278
278
|
REM = calculate_REM(meanDE)
|
|
279
279
|
REG = calculate_REG(meanDE)
|
|
280
280
|
|
|
281
|
+
has_practice_termType_system = len(systems) > 0
|
|
282
|
+
has_practice_pastureGrass_with_landCover_key = len(practices) > 0
|
|
283
|
+
|
|
281
284
|
should_run = all([
|
|
282
285
|
animalFeed_complete,
|
|
283
286
|
animalPopulation_complete,
|
|
284
287
|
freshForage_incomplete,
|
|
285
288
|
no_cycle_inputs_feed,
|
|
286
289
|
all_animals_have_value,
|
|
287
|
-
|
|
288
|
-
|
|
290
|
+
has_practice_termType_system,
|
|
291
|
+
has_practice_pastureGrass_with_landCover_key,
|
|
289
292
|
meanDE > 0,
|
|
290
293
|
meanECHHV > 0
|
|
291
294
|
])
|
|
292
295
|
|
|
293
296
|
for term_id in [MODEL_KEY] + [practice_input_id(p) for p in practices]:
|
|
294
297
|
for animal in animals:
|
|
295
|
-
logRequirements(
|
|
298
|
+
logRequirements(cycle, model=MODEL, term=term_id, animalId=animal.get('animalId'), model_key=MODEL_KEY,
|
|
296
299
|
term_type_animalFeed_complete=animalFeed_complete,
|
|
297
300
|
term_type_animalPopulation_complete=animalPopulation_complete,
|
|
298
301
|
term_type_freshForage_incomplete=freshForage_incomplete,
|
|
299
302
|
no_cycle_inputs_feed=no_cycle_inputs_feed,
|
|
300
303
|
all_animals_have_value=all_animals_have_value,
|
|
304
|
+
has_practice_termType_system=has_practice_termType_system,
|
|
305
|
+
has_practice_pastureGrass_with_landCover_key=has_practice_pastureGrass_with_landCover_key,
|
|
301
306
|
grass_MeanDE=calculate_meanDE(practices, term=term_id),
|
|
302
307
|
grass_MeanECHHV=calculate_meanECHHV(practices, term=term_id),
|
|
303
308
|
grass_REM=REM,
|
|
304
309
|
grass_REG=REG)
|
|
305
310
|
|
|
306
|
-
logShouldRun(
|
|
311
|
+
logShouldRun(cycle, MODEL, term_id, should_run, animalId=animal.get('animalId'), model_key=MODEL_KEY)
|
|
307
312
|
|
|
308
313
|
return should_run, meanDE, meanECHHV, REM, REG, systems
|
|
309
314
|
|
|
@@ -62,7 +62,7 @@ def should_run_by_productivity_lookup(
|
|
|
62
62
|
practice = value.get('practice')
|
|
63
63
|
animal_term_id = animal.get('term').get('@id')
|
|
64
64
|
|
|
65
|
-
logRequirements(cycle, model=MODEL, term=animal_term_id, property=term_id,
|
|
65
|
+
logRequirements(cycle, model=MODEL, term=animal_term_id, animalId=animal.get('animalId'), property=term_id,
|
|
66
66
|
country_id=country_id,
|
|
67
67
|
**({
|
|
68
68
|
lookup_col.replace('-', '_'): lookup_value
|
|
@@ -75,7 +75,7 @@ def should_run_by_productivity_lookup(
|
|
|
75
75
|
not practice_column or bool(practice),
|
|
76
76
|
lookup_value is not None
|
|
77
77
|
])
|
|
78
|
-
logShouldRun(cycle, MODEL, animal_term_id, should_run, property=term_id)
|
|
78
|
+
logShouldRun(cycle, MODEL, animal_term_id, should_run, animalId=animal.get('animalId'), property=term_id)
|
|
79
79
|
|
|
80
80
|
return should_run
|
|
81
81
|
|
|
@@ -233,14 +233,17 @@ def _should_run(cycle: dict, practices: dict):
|
|
|
233
233
|
REM = calculate_REM(meanDE)
|
|
234
234
|
REG = calculate_REG(meanDE)
|
|
235
235
|
|
|
236
|
+
has_practice_termType_system = len(systems) > 0
|
|
237
|
+
has_practice_pastureGrass_with_landCover_key = len(practices) > 0
|
|
238
|
+
|
|
236
239
|
should_run = all([
|
|
237
240
|
animalFeed_complete,
|
|
238
241
|
animalPopulation_complete,
|
|
239
242
|
freshForage_incomplete,
|
|
240
243
|
has_cycle_inputs_feed,
|
|
241
244
|
all_animals_have_value,
|
|
242
|
-
|
|
243
|
-
|
|
245
|
+
has_practice_termType_system,
|
|
246
|
+
has_practice_pastureGrass_with_landCover_key,
|
|
244
247
|
meanDE > 0,
|
|
245
248
|
meanECHHV > 0
|
|
246
249
|
])
|
|
@@ -252,6 +255,8 @@ def _should_run(cycle: dict, practices: dict):
|
|
|
252
255
|
term_type_freshForage_incomplete=freshForage_incomplete,
|
|
253
256
|
has_cycle_inputs_feed=has_cycle_inputs_feed,
|
|
254
257
|
all_animals_have_value=all_animals_have_value,
|
|
258
|
+
has_practice_termType_system=has_practice_termType_system,
|
|
259
|
+
has_practice_pastureGrass_with_landCover_key=has_practice_pastureGrass_with_landCover_key,
|
|
255
260
|
grass_MeanDE=calculate_meanDE(practices, term=term_id),
|
|
256
261
|
grass_MeanECHHV=calculate_meanECHHV(practices, term=term_id),
|
|
257
262
|
grass_REM=REM,
|