hestia-earth-models 0.59.2__py3-none-any.whl → 0.59.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/geospatialDatabase/potentialEvapotranspirationMonthly.py +98 -0
- hestia_earth/models/geospatialDatabase/precipitationMonthly.py +98 -0
- hestia_earth/models/geospatialDatabase/temperatureAnnual.py +1 -2
- hestia_earth/models/geospatialDatabase/temperatureMonthly.py +98 -0
- hestia_earth/models/geospatialDatabase/utils.py +8 -1
- hestia_earth/models/ipcc2006/n2OToAirCropResidueDecompositionDirect.py +83 -0
- hestia_earth/models/ipcc2006/utils.py +12 -0
- hestia_earth/models/ipcc2019/nh3ToAirInorganicFertiliser.py +112 -0
- hestia_earth/models/ipcc2019/nh3ToAirOrganicFertiliser.py +6 -3
- hestia_earth/models/ipcc2019/noxToAirInorganicFertiliser.py +112 -0
- hestia_earth/models/ipcc2019/noxToAirOrganicFertiliser.py +6 -3
- hestia_earth/models/ipcc2019/organicCarbonPerHa.py +13 -28
- hestia_earth/models/mocking/search-results.json +8 -8
- hestia_earth/models/site/management.py +6 -6
- hestia_earth/models/site/pre_checks/cache_geospatialDatabase.py +27 -7
- hestia_earth/models/site/utils.py +2 -6
- hestia_earth/models/utils/__init__.py +9 -0
- hestia_earth/models/utils/site.py +8 -5
- hestia_earth/models/version.py +1 -1
- {hestia_earth_models-0.59.2.dist-info → hestia_earth_models-0.59.4.dist-info}/METADATA +2 -2
- {hestia_earth_models-0.59.2.dist-info → hestia_earth_models-0.59.4.dist-info}/RECORD +34 -22
- tests/models/geospatialDatabase/test_potentialEvapotranspirationMonthly.py +20 -0
- tests/models/geospatialDatabase/test_precipitationMonthly.py +20 -0
- tests/models/geospatialDatabase/test_temperatureMonthly.py +20 -0
- tests/models/ipcc2006/test_n2OToAirCropResidueDecompositionDirect.py +50 -0
- tests/models/ipcc2019/test_nh3ToAirInorganicFertiliser.py +47 -0
- tests/models/ipcc2019/test_noxToAirInorganicFertiliser.py +47 -0
- tests/models/ipcc2019/test_organicCarbonPerHa.py +10 -22
- tests/models/site/test_management.py +13 -13
- tests/models/utils/test_blank_node.py +5 -5
- tests/models/utils/test_site.py +1 -1
- {hestia_earth_models-0.59.2.dist-info → hestia_earth_models-0.59.4.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.59.2.dist-info → hestia_earth_models-0.59.4.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.59.2.dist-info → hestia_earth_models-0.59.4.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
from hestia_earth.schema import EmissionMethodTier, EmissionStatsDefinition, TermTermType
|
|
2
|
+
from hestia_earth.utils.model import filter_list_term_type, find_term_match
|
|
3
|
+
from hestia_earth.utils.tools import list_sum
|
|
4
|
+
|
|
5
|
+
from hestia_earth.models.log import logRequirements, logShouldRun, debugValues, log_as_table
|
|
6
|
+
from hestia_earth.models.utils.blank_node import get_N_total
|
|
7
|
+
from hestia_earth.models.utils.constant import Units, get_atomic_conversion
|
|
8
|
+
from hestia_earth.models.utils.completeness import _is_term_type_complete
|
|
9
|
+
from hestia_earth.models.utils.emission import _new_emission
|
|
10
|
+
from hestia_earth.models.utils.cycle import get_inorganic_fertiliser_N_total
|
|
11
|
+
from hestia_earth.models.utils.term import get_lookup_value
|
|
12
|
+
from . import MODEL
|
|
13
|
+
|
|
14
|
+
REQUIREMENTS = {
|
|
15
|
+
"Cycle": {
|
|
16
|
+
"completeness.fertiliser": "True",
|
|
17
|
+
"inputs": [
|
|
18
|
+
{
|
|
19
|
+
"@type": "Input",
|
|
20
|
+
"value": "",
|
|
21
|
+
"term.termType": "inorganicFertiliser",
|
|
22
|
+
"optional": {
|
|
23
|
+
"properties": [{"@type": "Property", "value": "", "term.@id": "nitrogenContent"}]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
RETURNS = {
|
|
30
|
+
"Emission": [{
|
|
31
|
+
"value": "",
|
|
32
|
+
"sd": "",
|
|
33
|
+
"min": "",
|
|
34
|
+
"max": "",
|
|
35
|
+
"methodTier": "tier 1",
|
|
36
|
+
"statsDefinition": "modelled",
|
|
37
|
+
"methodModelDescription": ["Aggregated version", "Disaggragated version"]
|
|
38
|
+
}]
|
|
39
|
+
}
|
|
40
|
+
LOOKUPS = {
|
|
41
|
+
"inorganicFertiliser": ["IPCC_2019_FRACGASF_NOx-N", "IPCC_2019_FRACGASF_NOx-N-min", "IPCC_2019_FRACGASF_NOx-N-max"]
|
|
42
|
+
}
|
|
43
|
+
TERM_ID = 'noxToAirInorganicFertiliser'
|
|
44
|
+
TIER = EmissionMethodTier.TIER_1.value
|
|
45
|
+
TERM_TYPE = TermTermType.INORGANICFERTILISER
|
|
46
|
+
UNSPECIFIED_TERM_ID = 'inorganicNitrogenFertiliserUnspecifiedKgN'
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _emission(value: float, min: float, max: float, aggregated: bool = False):
|
|
50
|
+
emission = _new_emission(TERM_ID, MODEL)
|
|
51
|
+
emission['value'] = [value]
|
|
52
|
+
emission['min'] = [min]
|
|
53
|
+
emission['max'] = [max]
|
|
54
|
+
emission['methodTier'] = TIER
|
|
55
|
+
emission['statsDefinition'] = EmissionStatsDefinition.MODELLED.value
|
|
56
|
+
emission['methodModelDescription'] = 'Aggregated version' if aggregated else 'Disaggregated version'
|
|
57
|
+
return emission
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _input_values(input: dict):
|
|
61
|
+
N_total = list_sum(get_N_total([input]))
|
|
62
|
+
lookups = LOOKUPS[TERM_TYPE.value]
|
|
63
|
+
return {
|
|
64
|
+
'id': input.get('term', {}).get('@id'),
|
|
65
|
+
'N': N_total,
|
|
66
|
+
'value': get_lookup_value(input.get('term', {}), lookups[0]),
|
|
67
|
+
'min': get_lookup_value(input.get('term', {}), lookups[1]),
|
|
68
|
+
'max': get_lookup_value(input.get('term', {}), lookups[2])
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _filter_input_values(values: list, key: str): return [value for value in values if value.get(key)]
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _run(cycle: dict):
|
|
76
|
+
inputs = filter_list_term_type(cycle.get('inputs', []), TERM_TYPE)
|
|
77
|
+
input_values = list(map(_input_values, inputs))
|
|
78
|
+
|
|
79
|
+
debugValues(cycle, model=MODEL, term=TERM_ID,
|
|
80
|
+
input_values=log_as_table(input_values))
|
|
81
|
+
|
|
82
|
+
value = list_sum([
|
|
83
|
+
v.get('N', 0) * v.get('value', 0) for v in _filter_input_values(input_values, 'value')
|
|
84
|
+
]) * get_atomic_conversion(Units.KG_NOX, Units.TO_N)
|
|
85
|
+
|
|
86
|
+
min = list_sum([
|
|
87
|
+
v.get('N', 0) * v.get('min', 0) for v in _filter_input_values(input_values, 'min')
|
|
88
|
+
]) * get_atomic_conversion(Units.KG_NOX, Units.TO_N)
|
|
89
|
+
|
|
90
|
+
max = list_sum([
|
|
91
|
+
v.get('N', 0) * v.get('max', 0) for v in _filter_input_values(input_values, 'max')
|
|
92
|
+
]) * get_atomic_conversion(Units.KG_NOX, Units.TO_N)
|
|
93
|
+
|
|
94
|
+
aggregated = list_sum(find_term_match(inputs, UNSPECIFIED_TERM_ID).get('value', [0])) > 0
|
|
95
|
+
|
|
96
|
+
return [_emission(value, min, max, aggregated=aggregated)]
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _should_run(cycle: dict):
|
|
100
|
+
N_inorganic_fertiliser = get_inorganic_fertiliser_N_total(cycle)
|
|
101
|
+
fertiliser_complete = _is_term_type_complete(cycle, 'fertiliser')
|
|
102
|
+
|
|
103
|
+
logRequirements(cycle, model=MODEL, term=TERM_ID,
|
|
104
|
+
N_inorganic_fertiliser=N_inorganic_fertiliser,
|
|
105
|
+
term_type_fertiliser_complete=fertiliser_complete)
|
|
106
|
+
|
|
107
|
+
should_run = all([N_inorganic_fertiliser is not None, fertiliser_complete])
|
|
108
|
+
logShouldRun(cycle, MODEL, TERM_ID, should_run)
|
|
109
|
+
return should_run
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def run(cycle: dict): return _run(cycle) if _should_run(cycle) else []
|
|
@@ -66,6 +66,9 @@ def _input_values(input: dict):
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
|
|
69
|
+
def _filter_input_values(values: list, key: str): return [value for value in values if value.get(key)]
|
|
70
|
+
|
|
71
|
+
|
|
69
72
|
def _run(cycle: dict):
|
|
70
73
|
inputs = filter_list_term_type(cycle.get('inputs', []), TermTermType.ORGANICFERTILISER)
|
|
71
74
|
input_values = list(map(_input_values, inputs))
|
|
@@ -74,15 +77,15 @@ def _run(cycle: dict):
|
|
|
74
77
|
input_values=log_as_table(input_values))
|
|
75
78
|
|
|
76
79
|
value = list_sum([
|
|
77
|
-
v.get('N', 0) * v.get('value', 0) for v in input_values
|
|
80
|
+
v.get('N', 0) * v.get('value', 0) for v in _filter_input_values(input_values, 'value')
|
|
78
81
|
]) * get_atomic_conversion(Units.KG_NOX, Units.TO_N)
|
|
79
82
|
|
|
80
83
|
min = list_sum([
|
|
81
|
-
v.get('N', 0) * v.get('min', 0) for v in input_values
|
|
84
|
+
v.get('N', 0) * v.get('min', 0) for v in _filter_input_values(input_values, 'min')
|
|
82
85
|
]) * get_atomic_conversion(Units.KG_NOX, Units.TO_N)
|
|
83
86
|
|
|
84
87
|
max = list_sum([
|
|
85
|
-
v.get('N', 0) * v.get('max', 0) for v in input_values
|
|
88
|
+
v.get('N', 0) * v.get('max', 0) for v in _filter_input_values(input_values, 'max')
|
|
86
89
|
]) * get_atomic_conversion(Units.KG_NOX, Units.TO_N)
|
|
87
90
|
|
|
88
91
|
return [_emission(value, min, max)]
|
|
@@ -18,15 +18,12 @@ from typing import (
|
|
|
18
18
|
from hestia_earth.schema import (
|
|
19
19
|
CycleFunctionalUnit,
|
|
20
20
|
MeasurementMethodClassification,
|
|
21
|
-
SchemaType,
|
|
22
21
|
SiteSiteType,
|
|
23
22
|
TermTermType,
|
|
24
23
|
)
|
|
25
|
-
from hestia_earth.utils.api import find_related
|
|
26
24
|
from hestia_earth.utils.model import find_term_match, filter_list_term_type
|
|
27
25
|
from hestia_earth.utils.tools import flatten, list_sum, non_empty_list
|
|
28
26
|
|
|
29
|
-
from hestia_earth.models.utils import _load_calculated_node
|
|
30
27
|
from hestia_earth.models.log import log_as_table, logRequirements, logShouldRun
|
|
31
28
|
from hestia_earth.models.utils.blank_node import (
|
|
32
29
|
cumulative_nodes_match,
|
|
@@ -54,7 +51,7 @@ from hestia_earth.models.utils.term import (
|
|
|
54
51
|
get_upland_rice_crop_terms,
|
|
55
52
|
get_upland_rice_land_cover_terms
|
|
56
53
|
)
|
|
57
|
-
|
|
54
|
+
from hestia_earth.models.utils.site import related_cycles
|
|
58
55
|
from .utils import check_consecutive
|
|
59
56
|
from . import MODEL
|
|
60
57
|
|
|
@@ -107,7 +104,14 @@ REQUIREMENTS = {
|
|
|
107
104
|
"value": "",
|
|
108
105
|
"startDate": "",
|
|
109
106
|
"endDate": "",
|
|
110
|
-
"term.@id": "
|
|
107
|
+
"term.@id": "organicFertiliserUsed"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"@type": "Management",
|
|
111
|
+
"value": "",
|
|
112
|
+
"startDate": "",
|
|
113
|
+
"endDate": "",
|
|
114
|
+
"term.@id": "amendmentIncreasingSoilCarbonUsed"
|
|
111
115
|
},
|
|
112
116
|
{"@type": "Management", "value": "", "startDate": "", "endDate": "", "term.@id": "shortBareFallow"}
|
|
113
117
|
]
|
|
@@ -238,7 +242,8 @@ IMPROVED_PASTURE_TERM_ID = "improvedPasture"
|
|
|
238
242
|
SHORT_BARE_FALLOW_TERM_ID = "shortBareFallow"
|
|
239
243
|
ANIMAL_MANURE_USED_TERM_ID = "animalManureUsed"
|
|
240
244
|
INORGANIC_NITROGEN_FERTILISER_USED_TERM_ID = "inorganicNitrogenFertiliserUsed"
|
|
241
|
-
ORGANIC_FERTILISER_USED_TERM_ID = "
|
|
245
|
+
ORGANIC_FERTILISER_USED_TERM_ID = "organicFertiliserUsed"
|
|
246
|
+
SOIL_AMENDMENT_USED_TERM_ID = "amendmentIncreasingSoilCarbonUsed"
|
|
242
247
|
|
|
243
248
|
CLAY_CONTENT_MAX = 8
|
|
244
249
|
SAND_CONTENT_MIN = 70
|
|
@@ -3301,7 +3306,7 @@ def _get_carbon_input_kwargs(
|
|
|
3301
3306
|
|
|
3302
3307
|
has_organic_fertiliser_or_soil_amendment_used = any(
|
|
3303
3308
|
get_node_value(node) for node in land_use_management_nodes
|
|
3304
|
-
if node_term_match(node, ORGANIC_FERTILISER_USED_TERM_ID)
|
|
3309
|
+
if node_term_match(node, [ORGANIC_FERTILISER_USED_TERM_ID, SOIL_AMENDMENT_USED_TERM_ID])
|
|
3305
3310
|
)
|
|
3306
3311
|
|
|
3307
3312
|
has_practice_increasing_c_input = cumulative_nodes_match(
|
|
@@ -3546,7 +3551,7 @@ def _should_run(site: dict) -> tuple[bool, dict]:
|
|
|
3546
3551
|
site_type = site.get("siteType", "")
|
|
3547
3552
|
management_nodes = site.get("management", [])
|
|
3548
3553
|
measurement_nodes = site.get("measurements", [])
|
|
3549
|
-
cycles =
|
|
3554
|
+
cycles = related_cycles(site.get("@id"))
|
|
3550
3555
|
|
|
3551
3556
|
has_management = len(management_nodes) > 0
|
|
3552
3557
|
has_measurements = len(measurement_nodes) > 0
|
|
@@ -3603,26 +3608,6 @@ def _should_run(site: dict) -> tuple[bool, dict]:
|
|
|
3603
3608
|
return should_run_tier_1, should_run_tier_2, inventory, kwargs
|
|
3604
3609
|
|
|
3605
3610
|
|
|
3606
|
-
def _calculated_cycles(site_id: str):
|
|
3607
|
-
"""
|
|
3608
|
-
Get the list of `Cycle`s related to the `Site`. Gets the `recalculated` data if available, else `original`.
|
|
3609
|
-
|
|
3610
|
-
Parameters
|
|
3611
|
-
----------
|
|
3612
|
-
site_id : str
|
|
3613
|
-
The `@id` of the `Site`.
|
|
3614
|
-
|
|
3615
|
-
Returns
|
|
3616
|
-
-------
|
|
3617
|
-
list[dict]
|
|
3618
|
-
The related `Cycle`s as `dict`.
|
|
3619
|
-
"""
|
|
3620
|
-
nodes = find_related(SchemaType.SITE, site_id, SchemaType.CYCLE)
|
|
3621
|
-
return list(
|
|
3622
|
-
map(lambda node: _load_calculated_node(node, SchemaType.CYCLE), nodes or [])
|
|
3623
|
-
)
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
3611
|
def _should_run_tier_1(
|
|
3627
3612
|
inventory: dict,
|
|
3628
3613
|
*,
|
|
@@ -918,11 +918,11 @@
|
|
|
918
918
|
},
|
|
919
919
|
{
|
|
920
920
|
"@type": "Term",
|
|
921
|
-
"@id": "
|
|
921
|
+
"@id": "residueIncorporatedMoreThan30DaysBeforeCultivation"
|
|
922
922
|
},
|
|
923
923
|
{
|
|
924
924
|
"@type": "Term",
|
|
925
|
-
"@id": "
|
|
925
|
+
"@id": "residueIncorporated"
|
|
926
926
|
},
|
|
927
927
|
{
|
|
928
928
|
"@type": "Term",
|
|
@@ -1299,7 +1299,7 @@
|
|
|
1299
1299
|
"@type": "Term",
|
|
1300
1300
|
"name": "Generic crop, seed",
|
|
1301
1301
|
"@id": "genericCropSeed",
|
|
1302
|
-
"_score": 23.
|
|
1302
|
+
"_score": 23.910892
|
|
1303
1303
|
}
|
|
1304
1304
|
]
|
|
1305
1305
|
},
|
|
@@ -1405,11 +1405,11 @@
|
|
|
1405
1405
|
"results": [
|
|
1406
1406
|
{
|
|
1407
1407
|
"@type": "Term",
|
|
1408
|
-
"@id": "
|
|
1408
|
+
"@id": "waterDrainageCanal"
|
|
1409
1409
|
},
|
|
1410
1410
|
{
|
|
1411
1411
|
"@type": "Term",
|
|
1412
|
-
"@id": "
|
|
1412
|
+
"@id": "waterMarine"
|
|
1413
1413
|
},
|
|
1414
1414
|
{
|
|
1415
1415
|
"@type": "Term",
|
|
@@ -1740,15 +1740,15 @@
|
|
|
1740
1740
|
},
|
|
1741
1741
|
{
|
|
1742
1742
|
"@type": "Term",
|
|
1743
|
-
"@id": "
|
|
1743
|
+
"@id": "fullTillage"
|
|
1744
1744
|
},
|
|
1745
1745
|
{
|
|
1746
1746
|
"@type": "Term",
|
|
1747
|
-
"@id": "
|
|
1747
|
+
"@id": "minimumTillage"
|
|
1748
1748
|
},
|
|
1749
1749
|
{
|
|
1750
1750
|
"@type": "Term",
|
|
1751
|
-
"@id": "
|
|
1751
|
+
"@id": "fullInversionTillage"
|
|
1752
1752
|
},
|
|
1753
1753
|
{
|
|
1754
1754
|
"@type": "Term",
|
|
@@ -9,9 +9,9 @@ from hestia_earth.utils.model import filter_list_term_type, linked_node
|
|
|
9
9
|
from hestia_earth.utils.tools import flatten
|
|
10
10
|
|
|
11
11
|
from hestia_earth.models.log import logRequirements, logShouldRun, log_blank_nodes_id
|
|
12
|
-
from hestia_earth.models.utils.site import related_cycles
|
|
13
12
|
from hestia_earth.models.utils.term import get_lookup_value
|
|
14
13
|
from hestia_earth.models.utils.blank_node import get_node_value
|
|
14
|
+
from hestia_earth.models.utils.site import related_cycles
|
|
15
15
|
from . import MODEL
|
|
16
16
|
|
|
17
17
|
REQUIREMENTS = {
|
|
@@ -96,7 +96,7 @@ def _get_items_with_relevant_term_type(cycles: List[dict], item_name: str, relev
|
|
|
96
96
|
)
|
|
97
97
|
|
|
98
98
|
|
|
99
|
-
def
|
|
99
|
+
def _should_run(site: dict):
|
|
100
100
|
# Only get related cycles once.
|
|
101
101
|
cycles = related_cycles(site.get("@id"))
|
|
102
102
|
|
|
@@ -158,11 +158,11 @@ def should_run(site: dict):
|
|
|
158
158
|
practice_ids=log_blank_nodes_id(practices)
|
|
159
159
|
)
|
|
160
160
|
|
|
161
|
-
|
|
161
|
+
should_run = any(products_crop_forage + products_land_cover + practices)
|
|
162
162
|
logShouldRun(site, MODEL, None, should_run=_should_run, model_key=MODEL_KEY)
|
|
163
|
-
return
|
|
163
|
+
return should_run, products_crop_forage + products_land_cover, practices
|
|
164
164
|
|
|
165
165
|
|
|
166
166
|
def run(site: dict):
|
|
167
|
-
|
|
168
|
-
return list(map(management, products + practices)) if
|
|
167
|
+
should_run, products, practices = _should_run(site)
|
|
168
|
+
return list(map(management, products + practices)) if should_run else []
|
|
@@ -4,10 +4,10 @@ Pre Checks Cache Geospatial Database
|
|
|
4
4
|
This model caches results from Geospatial Database.
|
|
5
5
|
"""
|
|
6
6
|
from functools import reduce
|
|
7
|
-
from hestia_earth.utils.tools import flatten
|
|
7
|
+
from hestia_earth.utils.tools import flatten, non_empty_list
|
|
8
8
|
|
|
9
9
|
from hestia_earth.models.log import debugValues
|
|
10
|
-
from hestia_earth.models.utils import CACHE_KEY, cached_value
|
|
10
|
+
from hestia_earth.models.utils import CACHE_KEY, cached_value, first_day_of_month, last_day_of_month
|
|
11
11
|
from hestia_earth.models.utils.site import CACHE_YEARS_KEY
|
|
12
12
|
from hestia_earth.models.geospatialDatabase.utils import (
|
|
13
13
|
MAX_AREA_SIZE, CACHE_VALUE, CACHE_AREA_SIZE,
|
|
@@ -34,7 +34,12 @@ def cache_site_results(results: list, collections: list, area_size: int = None):
|
|
|
34
34
|
collection = collections[index]
|
|
35
35
|
name = collection.get('name')
|
|
36
36
|
value = results[index]
|
|
37
|
-
|
|
37
|
+
cache_sub_key = '-'.join(non_empty_list([
|
|
38
|
+
collection.get('year'),
|
|
39
|
+
collection.get('start_date'),
|
|
40
|
+
collection.get('end_date')
|
|
41
|
+
]))
|
|
42
|
+
data = (group.get(name, {}) | {cache_sub_key: value} if cache_sub_key else value)
|
|
38
43
|
return group | {name: data}
|
|
39
44
|
|
|
40
45
|
return reduce(_combine_result, range(0, len(results)), {}) | (
|
|
@@ -42,13 +47,28 @@ def cache_site_results(results: list, collections: list, area_size: int = None):
|
|
|
42
47
|
)
|
|
43
48
|
|
|
44
49
|
|
|
50
|
+
def _extend_collection_by_month(year: int):
|
|
51
|
+
return [{
|
|
52
|
+
'start_date': first_day_of_month(year, month).strftime('%Y-%m-%d'),
|
|
53
|
+
'end_date': last_day_of_month(year, month).strftime('%Y-%m-%d')
|
|
54
|
+
} for month in range(1, 13)]
|
|
55
|
+
|
|
56
|
+
|
|
45
57
|
def _extend_collection(name: str, collection: dict, years: list = []):
|
|
46
58
|
data = collection | {'name': name, 'collection': _collection_name(collection.get('collection'))}
|
|
59
|
+
|
|
60
|
+
year_params = [{'year': str(year)} for year in years]
|
|
61
|
+
# fetch from first year to last
|
|
62
|
+
month_years = range(years[0], years[-1] + 1) if len(years) > 1 else years
|
|
63
|
+
month_params = flatten(map(_extend_collection_by_month, month_years))
|
|
64
|
+
|
|
47
65
|
return [
|
|
48
|
-
data |
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
] if '
|
|
66
|
+
(data | params) for params in year_params
|
|
67
|
+
] if name.endswith('Annual') else [
|
|
68
|
+
(data | params) for params in month_params
|
|
69
|
+
] if name.endswith('Monthly') else [
|
|
70
|
+
data
|
|
71
|
+
]
|
|
52
72
|
|
|
53
73
|
|
|
54
74
|
def _extend_collections(values: list, years: list = []):
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
from functools import reduce
|
|
2
|
-
import datetime
|
|
3
2
|
from hestia_earth.schema import TermTermType
|
|
4
3
|
from hestia_earth.utils.tools import non_empty_list
|
|
5
4
|
from hestia_earth.utils.date import DAY
|
|
6
5
|
|
|
7
|
-
from hestia_earth.models.utils import _omit
|
|
6
|
+
from hestia_earth.models.utils import _omit, first_day_of_month, last_day_of_month
|
|
8
7
|
from hestia_earth.models.utils.measurement import _new_measurement, measurement_value, has_all_months
|
|
9
8
|
|
|
10
9
|
|
|
@@ -68,10 +67,7 @@ def _group_by_month(term_id: str, dates: list, values: list):
|
|
|
68
67
|
|
|
69
68
|
def map_to_month(data: list, year: int, month: int):
|
|
70
69
|
# make sure we got all the necessary days
|
|
71
|
-
|
|
72
|
-
last_day_of_month = datetime.date(year + int(month / 12), (month % 12) + 1, 1) - datetime.timedelta(days=1)
|
|
73
|
-
|
|
74
|
-
difference = last_day_of_month - first_day_of_month
|
|
70
|
+
difference = last_day_of_month(year, month) - first_day_of_month(year, month)
|
|
75
71
|
days_in_month = round(difference.days + difference.seconds / DAY, 1) + 1
|
|
76
72
|
|
|
77
73
|
return measurement_value({
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from os.path import dirname, abspath
|
|
2
2
|
import sys
|
|
3
|
+
import datetime
|
|
3
4
|
from functools import reduce
|
|
4
5
|
import operator
|
|
5
6
|
from typing import Any
|
|
@@ -126,3 +127,11 @@ def _get_by_key(x, y):
|
|
|
126
127
|
|
|
127
128
|
|
|
128
129
|
def get_dict_key(value: dict, key: str): return reduce(lambda x, y: _get_by_key(x, y), key.split('.'), value)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def first_day_of_month(year: int, month: int):
|
|
133
|
+
return datetime.date(int(year), int(month), 1)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def last_day_of_month(year: int, month: int):
|
|
137
|
+
return datetime.date(int(year) + int(int(month) / 12), (int(month) % 12) + 1, 1) - datetime.timedelta(days=1)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
from hestia_earth.schema import SchemaType, SiteSiteType, TermTermType
|
|
2
|
-
from hestia_earth.utils.api import
|
|
2
|
+
from hestia_earth.utils.api import find_related
|
|
3
3
|
from hestia_earth.utils.lookup import download_lookup, get_table_value, column_name
|
|
4
4
|
from hestia_earth.utils.tools import non_empty_list, safe_parse_date
|
|
5
5
|
|
|
6
6
|
from hestia_earth.models.log import debugMissingLookup
|
|
7
|
-
from . import cached_value
|
|
7
|
+
from . import cached_value, _load_calculated_node
|
|
8
8
|
|
|
9
9
|
CACHE_YEARS_KEY = 'years'
|
|
10
10
|
WATER_TYPES = [
|
|
@@ -47,8 +47,7 @@ def is_site(site: dict): return site.get('@type', site.get('type')) == SchemaTyp
|
|
|
47
47
|
def related_cycles(site_id: str):
|
|
48
48
|
"""
|
|
49
49
|
Get the list of `Cycle` related to the `Site`.
|
|
50
|
-
|
|
51
|
-
In Hestia, a `Cycle` must have a link to a `Site`, therefore a `Site` can be related to many `Cycle`s.
|
|
50
|
+
Gets the `recalculated` data if available, else `original`.
|
|
52
51
|
|
|
53
52
|
Parameters
|
|
54
53
|
----------
|
|
@@ -61,7 +60,7 @@ def related_cycles(site_id: str):
|
|
|
61
60
|
The related `Cycle`s as `dict`.
|
|
62
61
|
"""
|
|
63
62
|
nodes = find_related(SchemaType.SITE, site_id, SchemaType.CYCLE)
|
|
64
|
-
return non_empty_list(map(lambda node:
|
|
63
|
+
return non_empty_list(map(lambda node: _load_calculated_node(node, SchemaType.CYCLE), nodes or []))
|
|
65
64
|
|
|
66
65
|
|
|
67
66
|
def _cycle_end_year(cycle: dict):
|
|
@@ -75,6 +74,10 @@ def related_years(site: dict):
|
|
|
75
74
|
)
|
|
76
75
|
|
|
77
76
|
|
|
77
|
+
def related_months(site: dict):
|
|
78
|
+
return cached_value(site)
|
|
79
|
+
|
|
80
|
+
|
|
78
81
|
def valid_site_type(site: dict, site_types=[SiteSiteType.CROPLAND.value, SiteSiteType.PERMANENT_PASTURE.value]):
|
|
79
82
|
"""
|
|
80
83
|
Check if the site `siteType` is allowed.
|
hestia_earth/models/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
VERSION = '0.59.
|
|
1
|
+
VERSION = '0.59.4'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: hestia-earth-models
|
|
3
|
-
Version: 0.59.
|
|
3
|
+
Version: 0.59.4
|
|
4
4
|
Summary: Hestia's set of modules for filling gaps in the activity data using external datasets (e.g. populating soil properties with a geospatial dataset using provided coordinates) and internal lookups (e.g. populating machinery use from fuel use). Includes rules for when gaps should be filled versus not (e.g. never gap fill yield, gap fill crop residue if yield provided etc.).
|
|
5
5
|
Home-page: https://gitlab.com/hestia-earth/hestia-engine-models
|
|
6
6
|
Author: Hestia Team
|
|
@@ -18,7 +18,7 @@ Requires-Dist: CurrencyConverter ==0.16.8
|
|
|
18
18
|
Requires-Dist: haversine >=2.7.0
|
|
19
19
|
Requires-Dist: pydash
|
|
20
20
|
Provides-Extra: spatial
|
|
21
|
-
Requires-Dist: hestia-earth.earth-engine >=0.4.
|
|
21
|
+
Requires-Dist: hestia-earth.earth-engine >=0.4.7 ; extra == 'spatial'
|
|
22
22
|
|
|
23
23
|
# Hestia Engine Models
|
|
24
24
|
|