hestia-earth-models 0.59.4__py3-none-any.whl → 0.59.5__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/liveAnimal.py +3 -0
- hestia_earth/models/cycle/milkYield.py +1 -1
- hestia_earth/models/cycle/utils.py +1 -1
- hestia_earth/models/geospatialDatabase/potentialEvapotranspirationLongTermAnnualMean.py +2 -2
- hestia_earth/models/geospatialDatabase/potentialEvapotranspirationMonthly.py +9 -8
- hestia_earth/models/geospatialDatabase/precipitationMonthly.py +10 -8
- hestia_earth/models/geospatialDatabase/temperatureAnnual.py +2 -5
- hestia_earth/models/geospatialDatabase/temperatureLongTermAnnualMean.py +2 -3
- hestia_earth/models/geospatialDatabase/temperatureMonthly.py +8 -8
- hestia_earth/models/geospatialDatabase/utils.py +6 -1
- hestia_earth/models/ipcc2019/organicCarbonPerHa.py +70 -110
- hestia_earth/models/linkedImpactAssessment/__init__.py +78 -43
- hestia_earth/models/mocking/search-results.json +0 -39
- hestia_earth/models/schmidt2007/n2OToAirWasteTreatmentDirect.py +58 -0
- hestia_earth/models/schmidt2007/nh3ToAirWasteTreatment.py +58 -0
- hestia_earth/models/site/management.py +104 -11
- hestia_earth/models/site/soilMeasurement.py +9 -9
- hestia_earth/models/utils/blank_node.py +3 -3
- hestia_earth/models/utils/term.py +0 -23
- hestia_earth/models/version.py +1 -1
- {hestia_earth_models-0.59.4.dist-info → hestia_earth_models-0.59.5.dist-info}/METADATA +1 -1
- {hestia_earth_models-0.59.4.dist-info → hestia_earth_models-0.59.5.dist-info}/RECORD +31 -27
- tests/models/ipcc2019/test_organicCarbonPerHa.py +4 -18
- tests/models/schmidt2007/test_n2OToAirWasteTreatmentDirect.py +45 -0
- tests/models/schmidt2007/test_nh3ToAirWasteTreatment.py +45 -0
- tests/models/site/test_management.py +24 -3
- tests/models/site/test_soilMeasurement.py +40 -21
- tests/models/utils/test_term.py +1 -8
- {hestia_earth_models-0.59.4.dist-info → hestia_earth_models-0.59.5.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.59.4.dist-info → hestia_earth_models-0.59.5.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.59.4.dist-info → hestia_earth_models-0.59.5.dist-info}/top_level.txt +0 -0
|
@@ -8,7 +8,7 @@ from hestia_earth.schema import EmissionMethodTier
|
|
|
8
8
|
from hestia_earth.utils.lookup import download_lookup, get_table_value, column_name
|
|
9
9
|
from hestia_earth.utils.tools import flatten, list_sum
|
|
10
10
|
|
|
11
|
-
from hestia_earth.models.log import debugValues, logRequirements, logShouldRun
|
|
11
|
+
from hestia_earth.models.log import debugValues, logRequirements, logShouldRun, log_as_table
|
|
12
12
|
from hestia_earth.models.utils.emission import _new_emission
|
|
13
13
|
from hestia_earth.models.utils.input import load_impacts
|
|
14
14
|
from hestia_earth.models.utils.blank_node import group_by_keys
|
|
@@ -52,71 +52,99 @@ MODEL_AGGREGATED = 'hestiaAggregatedData'
|
|
|
52
52
|
TIER = EmissionMethodTier.BACKGROUND.value
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
def _emission(
|
|
56
|
-
# log run on each emission so we know it did run
|
|
57
|
-
input_term_id = input.get('term', {}).get('@id')
|
|
58
|
-
operation_term_id = input.get('operation', {}).get('@id')
|
|
59
|
-
animal_term_id = input.get('animal', {}).get('@id')
|
|
60
|
-
|
|
61
|
-
logShouldRun(cycle, model, term_id, True, methodTier=TIER,
|
|
62
|
-
input=input_term_id,
|
|
63
|
-
operation=operation_term_id,
|
|
64
|
-
animal=animal_term_id)
|
|
65
|
-
|
|
55
|
+
def _emission(model: str, term_id: str, value: float, input: dict, operation={}, animal={}):
|
|
66
56
|
emission = _new_emission(term_id, model)
|
|
67
57
|
emission['value'] = [value]
|
|
68
58
|
emission['methodTier'] = TIER
|
|
69
|
-
emission['inputs'] = [input
|
|
70
|
-
if
|
|
71
|
-
emission['operation'] =
|
|
72
|
-
if
|
|
73
|
-
emission['animals'] = [
|
|
59
|
+
emission['inputs'] = [input]
|
|
60
|
+
if operation:
|
|
61
|
+
emission['operation'] = operation
|
|
62
|
+
if animal:
|
|
63
|
+
emission['animals'] = [animal]
|
|
74
64
|
return emission
|
|
75
65
|
|
|
76
66
|
|
|
67
|
+
def _run_emission(cycle: dict, term_id: str, data: dict):
|
|
68
|
+
def run_input(values: dict):
|
|
69
|
+
value = values.get('value', 0)
|
|
70
|
+
term = values.get('term', {})
|
|
71
|
+
operation = values.get('operation', {})
|
|
72
|
+
animal = values.get('animal', {})
|
|
73
|
+
is_aggregated = any(values.get('aggregated', []))
|
|
74
|
+
model = MODEL_AGGREGATED if is_aggregated else MODEL
|
|
75
|
+
|
|
76
|
+
details = values.get('details', {})
|
|
77
|
+
logRequirements(cycle, model=model, term=term_id,
|
|
78
|
+
values=log_as_table([{'impact_assessment_id': key} | value for key, value in details.items()]))
|
|
79
|
+
|
|
80
|
+
logShouldRun(cycle, model, term_id, True, methodTier=TIER,
|
|
81
|
+
input=term.get('@id'),
|
|
82
|
+
operation=operation.get('@id'),
|
|
83
|
+
animal=animal.get('@id'))
|
|
84
|
+
|
|
85
|
+
return _emission(model, term_id, value, input=term, operation=operation, animal=animal)
|
|
86
|
+
|
|
87
|
+
return list(map(run_input, data.values()))
|
|
88
|
+
|
|
89
|
+
|
|
77
90
|
def _emission_group(term_id: str):
|
|
78
91
|
lookup = download_lookup('emission.csv', True)
|
|
79
92
|
return get_table_value(lookup, 'termid', term_id, column_name('inputProductionGroupId'))
|
|
80
93
|
|
|
81
94
|
|
|
82
95
|
def _group_emissions(impact: dict):
|
|
83
|
-
def _group_by(
|
|
96
|
+
def _group_by(group: dict, emission: dict):
|
|
84
97
|
term_id = emission.get('term', {}).get('@id')
|
|
85
98
|
grouping = _emission_group(term_id)
|
|
86
99
|
value = emission.get('value') or 0
|
|
87
100
|
if grouping:
|
|
88
|
-
|
|
89
|
-
return
|
|
101
|
+
group[grouping] = group.get(grouping, 0) + value
|
|
102
|
+
return group
|
|
90
103
|
|
|
91
104
|
emissions = impact.get('emissionsResourceUse', [])
|
|
92
105
|
return reduce(_group_by, emissions, {})
|
|
93
106
|
|
|
94
107
|
|
|
95
|
-
def _run_input(cycle: dict):
|
|
96
|
-
def run(inputs: list):
|
|
97
|
-
input = inputs[0]
|
|
98
|
-
input_value = list_sum(flatten(input.get('value', []) for input in inputs))
|
|
99
|
-
term_id = input.get('term', {}).get('@id')
|
|
100
|
-
impact = input.get('impactAssessment')
|
|
101
|
-
model = MODEL_AGGREGATED if impact.get('aggregated', False) else MODEL
|
|
102
|
-
emissions = _group_emissions(impact)
|
|
103
|
-
|
|
104
|
-
logRequirements(cycle, model=model, term=term_id,
|
|
105
|
-
impact_assessment_id=input.get('impactAssessment', {}).get('@id'),
|
|
106
|
-
input_value=input_value)
|
|
107
|
-
logShouldRun(cycle, model, term_id, True, methodTier=TIER)
|
|
108
|
-
|
|
109
|
-
return [
|
|
110
|
-
_emission(cycle, id, input_value * value, input, model) for id, value in emissions.items()
|
|
111
|
-
]
|
|
112
|
-
return run
|
|
113
|
-
|
|
114
|
-
|
|
115
108
|
def _animal_inputs(animal: dict):
|
|
116
109
|
inputs = load_impacts(animal.get('inputs', []))
|
|
117
110
|
return [(input | {'animal': animal.get('term', {})}) for input in inputs]
|
|
118
111
|
|
|
119
112
|
|
|
113
|
+
def _group_input_emissions(input: dict):
|
|
114
|
+
impact = input.get('impactAssessment')
|
|
115
|
+
emissions = _group_emissions(impact)
|
|
116
|
+
return input | {'emissions': emissions}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _group_inputs(group: dict, values: tuple):
|
|
120
|
+
# input_group_key = 'group-id'
|
|
121
|
+
# inputs = [{'term': {}, 'value':[], 'impactAssessment': {}, 'emissions': {'co2ToAirInputsProduction': 10}}]
|
|
122
|
+
input_group_key, inputs = values
|
|
123
|
+
for input in inputs:
|
|
124
|
+
input_value = list_sum(input.get('value'))
|
|
125
|
+
emissions = input.get('emissions', {})
|
|
126
|
+
for emission_term_id, emission_value in emissions.items():
|
|
127
|
+
group[emission_term_id] = group.get(emission_term_id, {})
|
|
128
|
+
|
|
129
|
+
grouped_inputs = group[emission_term_id].get(input_group_key, {
|
|
130
|
+
'term': input.get('term', {}),
|
|
131
|
+
'operation': input.get('operation', {}),
|
|
132
|
+
'animal': input.get('animal', {}),
|
|
133
|
+
'value': 0,
|
|
134
|
+
'aggregated': [],
|
|
135
|
+
'details': {}
|
|
136
|
+
})
|
|
137
|
+
grouped_inputs['aggregated'].append(input.get('impactAssessment', {}).get('agregated', False))
|
|
138
|
+
grouped_inputs['value'] = grouped_inputs['value'] + (emission_value * input_value)
|
|
139
|
+
# for logging
|
|
140
|
+
grouped_inputs['details'][input.get('impactAssessment', {}).get('@id')] = {
|
|
141
|
+
'emission_value': emission_value,
|
|
142
|
+
'input_value': input_value
|
|
143
|
+
}
|
|
144
|
+
group[emission_term_id][input_group_key] = grouped_inputs
|
|
145
|
+
return group
|
|
146
|
+
|
|
147
|
+
|
|
120
148
|
def run(_, cycle: dict):
|
|
121
149
|
inputs = flatten(
|
|
122
150
|
load_impacts(cycle.get('inputs', [])) +
|
|
@@ -124,9 +152,16 @@ def run(_, cycle: dict):
|
|
|
124
152
|
)
|
|
125
153
|
inputs = [i for i in inputs if list_sum(i.get('value', [])) > 0]
|
|
126
154
|
|
|
155
|
+
# group inputs with same term/operation/animal to avoid adding emissions twice
|
|
156
|
+
# inputs = {'group-id': [{'term': {},'value':[10],'impactAssessment': {}}]}
|
|
157
|
+
inputs = reduce(group_by_keys(['term', 'operation', 'animal']), inputs, {})
|
|
158
|
+
inputs = {key: list(map(_group_input_emissions, value)) for key, value in inputs.items()}
|
|
159
|
+
|
|
127
160
|
debugValues(cycle, model=MODEL,
|
|
128
161
|
nb_inputs=len(inputs))
|
|
129
162
|
|
|
130
|
-
# group
|
|
131
|
-
|
|
132
|
-
|
|
163
|
+
# finally group everything by emission so we can log inputs together
|
|
164
|
+
# emissions = {'co2ToAirInputsProduct': {'group-id':{'term':{},'value':10,'details':{}}}}
|
|
165
|
+
emissions = reduce(_group_inputs, inputs.items(), {})
|
|
166
|
+
|
|
167
|
+
return flatten([_run_emission(cycle, term_id, data) for term_id, data in emissions.items()])
|
|
@@ -1532,45 +1532,6 @@
|
|
|
1532
1532
|
}
|
|
1533
1533
|
]
|
|
1534
1534
|
},
|
|
1535
|
-
{
|
|
1536
|
-
"name": "get_long_fallow_land_cover_terms",
|
|
1537
|
-
"query": {
|
|
1538
|
-
"bool": {
|
|
1539
|
-
"must": [
|
|
1540
|
-
{
|
|
1541
|
-
"match": {
|
|
1542
|
-
"@type": "Term"
|
|
1543
|
-
}
|
|
1544
|
-
},
|
|
1545
|
-
{
|
|
1546
|
-
"match": {
|
|
1547
|
-
"termType.keyword": "landCover"
|
|
1548
|
-
}
|
|
1549
|
-
},
|
|
1550
|
-
{
|
|
1551
|
-
"match_phrase_prefix": {
|
|
1552
|
-
"name": "long"
|
|
1553
|
-
}
|
|
1554
|
-
},
|
|
1555
|
-
{
|
|
1556
|
-
"match": {
|
|
1557
|
-
"name": "fallow"
|
|
1558
|
-
}
|
|
1559
|
-
}
|
|
1560
|
-
]
|
|
1561
|
-
}
|
|
1562
|
-
},
|
|
1563
|
-
"results": [
|
|
1564
|
-
{
|
|
1565
|
-
"@type": "Term",
|
|
1566
|
-
"@id": "longFallow"
|
|
1567
|
-
},
|
|
1568
|
-
{
|
|
1569
|
-
"@type": "Term",
|
|
1570
|
-
"@id": "longBareFallow"
|
|
1571
|
-
}
|
|
1572
|
-
]
|
|
1573
|
-
},
|
|
1574
1535
|
{
|
|
1575
1536
|
"name": "get_milkYield_terms",
|
|
1576
1537
|
"query": {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from hestia_earth.schema import EmissionMethodTier
|
|
2
|
+
from hestia_earth.utils.tools import list_sum
|
|
3
|
+
|
|
4
|
+
from hestia_earth.models.log import logRequirements, logShouldRun
|
|
5
|
+
from hestia_earth.models.utils.emission import _new_emission
|
|
6
|
+
from .utils import get_waste_values
|
|
7
|
+
from . import MODEL
|
|
8
|
+
|
|
9
|
+
REQUIREMENTS = {
|
|
10
|
+
"Cycle": {
|
|
11
|
+
"or": {
|
|
12
|
+
"product": [
|
|
13
|
+
{"@type": "Product", "value": "", "term.termType": "waste"}
|
|
14
|
+
],
|
|
15
|
+
"completeness.waste": ""
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
RETURNS = {
|
|
20
|
+
"Emission": [{
|
|
21
|
+
"value": "",
|
|
22
|
+
"methodTier": "tier 1"
|
|
23
|
+
}]
|
|
24
|
+
}
|
|
25
|
+
LOOKUPS = {
|
|
26
|
+
"waste": "n2oEfSchmidt2007"
|
|
27
|
+
}
|
|
28
|
+
TERM_ID = 'n2OToAirWasteTreatmentDirect'
|
|
29
|
+
TIER = EmissionMethodTier.TIER_1.value
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _emission(value: float):
|
|
33
|
+
emission = _new_emission(TERM_ID, MODEL)
|
|
34
|
+
emission['value'] = [value]
|
|
35
|
+
emission['methodTier'] = TIER
|
|
36
|
+
return emission
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _run(waste_values: list):
|
|
40
|
+
value = list_sum(waste_values)
|
|
41
|
+
return [_emission(value)]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _should_run(cycle: dict):
|
|
45
|
+
waste_values = get_waste_values(TERM_ID, cycle, LOOKUPS['waste'])
|
|
46
|
+
has_waste = len(waste_values) > 0
|
|
47
|
+
|
|
48
|
+
logRequirements(cycle, model=MODEL, term=TERM_ID,
|
|
49
|
+
has_waste=has_waste)
|
|
50
|
+
|
|
51
|
+
should_run = any([has_waste])
|
|
52
|
+
logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
|
|
53
|
+
return should_run, waste_values
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def run(cycle: dict):
|
|
57
|
+
should_run, waste_values = _should_run(cycle)
|
|
58
|
+
return _run(waste_values) if should_run else []
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from hestia_earth.schema import EmissionMethodTier
|
|
2
|
+
from hestia_earth.utils.tools import list_sum
|
|
3
|
+
|
|
4
|
+
from hestia_earth.models.log import logRequirements, logShouldRun
|
|
5
|
+
from hestia_earth.models.utils.emission import _new_emission
|
|
6
|
+
from .utils import get_waste_values
|
|
7
|
+
from . import MODEL
|
|
8
|
+
|
|
9
|
+
REQUIREMENTS = {
|
|
10
|
+
"Cycle": {
|
|
11
|
+
"or": {
|
|
12
|
+
"product": [
|
|
13
|
+
{"@type": "Product", "value": "", "term.termType": "waste"}
|
|
14
|
+
],
|
|
15
|
+
"completeness.waste": ""
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
RETURNS = {
|
|
20
|
+
"Emission": [{
|
|
21
|
+
"value": "",
|
|
22
|
+
"methodTier": "tier 1"
|
|
23
|
+
}]
|
|
24
|
+
}
|
|
25
|
+
LOOKUPS = {
|
|
26
|
+
"waste": "nh3EfSchmidt2007"
|
|
27
|
+
}
|
|
28
|
+
TERM_ID = 'nh3ToAirWasteTreatment'
|
|
29
|
+
TIER = EmissionMethodTier.TIER_1.value
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _emission(value: float):
|
|
33
|
+
emission = _new_emission(TERM_ID, MODEL)
|
|
34
|
+
emission['value'] = [value]
|
|
35
|
+
emission['methodTier'] = TIER
|
|
36
|
+
return emission
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _run(waste_values: list):
|
|
40
|
+
value = list_sum(waste_values)
|
|
41
|
+
return [_emission(value)]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _should_run(cycle: dict):
|
|
45
|
+
waste_values = get_waste_values(TERM_ID, cycle, LOOKUPS['waste'])
|
|
46
|
+
has_waste = len(waste_values) > 0
|
|
47
|
+
|
|
48
|
+
logRequirements(cycle, model=MODEL, term=TERM_ID,
|
|
49
|
+
has_waste=has_waste)
|
|
50
|
+
|
|
51
|
+
should_run = any([has_waste])
|
|
52
|
+
logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
|
|
53
|
+
return should_run, waste_values
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def run(cycle: dict):
|
|
57
|
+
should_run, waste_values = _should_run(cycle)
|
|
58
|
+
return _run(waste_values) if should_run else []
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Management node with data gap-filled data from cycles.
|
|
3
3
|
"""
|
|
4
|
-
from typing import List
|
|
4
|
+
from typing import List, Any
|
|
5
5
|
from functools import reduce
|
|
6
6
|
from hestia_earth.schema import SchemaType, TermTermType
|
|
7
7
|
from hestia_earth.utils.api import download_hestia
|
|
8
8
|
from hestia_earth.utils.model import filter_list_term_type, linked_node
|
|
9
|
-
from hestia_earth.utils.tools import flatten
|
|
9
|
+
from hestia_earth.utils.tools import flatten, safe_parse_float
|
|
10
10
|
|
|
11
11
|
from hestia_earth.models.log import logRequirements, logShouldRun, log_blank_nodes_id
|
|
12
12
|
from hestia_earth.models.utils.term import get_lookup_value
|
|
@@ -37,6 +37,16 @@ REQUIREMENTS = {
|
|
|
37
37
|
],
|
|
38
38
|
"value": ""
|
|
39
39
|
}
|
|
40
|
+
],
|
|
41
|
+
"inputs": [
|
|
42
|
+
{
|
|
43
|
+
"@type": "Input",
|
|
44
|
+
"term.termType": [
|
|
45
|
+
"inorganicFertiliser",
|
|
46
|
+
"organicFertiliser",
|
|
47
|
+
"soilAmendment"
|
|
48
|
+
]
|
|
49
|
+
}
|
|
40
50
|
]
|
|
41
51
|
}]
|
|
42
52
|
}
|
|
@@ -53,9 +63,45 @@ RETURNS = {
|
|
|
53
63
|
"startDate": ""
|
|
54
64
|
}]
|
|
55
65
|
}
|
|
56
|
-
|
|
66
|
+
LOOKUPS = {
|
|
67
|
+
"inorganicFertiliser": "nitrogenContent",
|
|
68
|
+
"organicFertiliser": "ANIMAL_MANURE",
|
|
69
|
+
"soilAmendment": "PRACTICE_INCREASING_C_INPUT"
|
|
70
|
+
}
|
|
57
71
|
MODEL_KEY = 'management'
|
|
58
72
|
LAND_COVER_KEY = 'landCoverId'
|
|
73
|
+
ANIMAL_MANURE_USED_TERM_ID = "animalManureUsed"
|
|
74
|
+
INORGANIC_NITROGEN_FERTILISER_USED_TERM_ID = "inorganicNitrogenFertiliserUsed"
|
|
75
|
+
ORGANIC_FERTILISER_USED_TERM_ID = "organicFertiliserUsed"
|
|
76
|
+
AMENDMENT_INCREASING_C_USED_TERM_ID = "amendmentIncreasingSoilCarbonUsed"
|
|
77
|
+
INPUT_RULES = {
|
|
78
|
+
TermTermType.INORGANICFERTILISER.value: (
|
|
79
|
+
(
|
|
80
|
+
TermTermType.INORGANICFERTILISER.value, # Lookup column
|
|
81
|
+
lambda x: safe_parse_float(x) > 0, # Condition
|
|
82
|
+
INORGANIC_NITROGEN_FERTILISER_USED_TERM_ID # New term.
|
|
83
|
+
),
|
|
84
|
+
),
|
|
85
|
+
TermTermType.SOILAMENDMENT.value: (
|
|
86
|
+
(
|
|
87
|
+
TermTermType.SOILAMENDMENT.value,
|
|
88
|
+
lambda x: x is True,
|
|
89
|
+
AMENDMENT_INCREASING_C_USED_TERM_ID
|
|
90
|
+
),
|
|
91
|
+
),
|
|
92
|
+
TermTermType.ORGANICFERTILISER.value: (
|
|
93
|
+
(
|
|
94
|
+
TermTermType.SOILAMENDMENT.value,
|
|
95
|
+
lambda x: x is True,
|
|
96
|
+
ORGANIC_FERTILISER_USED_TERM_ID
|
|
97
|
+
),
|
|
98
|
+
(
|
|
99
|
+
TermTermType.ORGANICFERTILISER.value,
|
|
100
|
+
lambda x: x is True,
|
|
101
|
+
ANIMAL_MANURE_USED_TERM_ID
|
|
102
|
+
)
|
|
103
|
+
)
|
|
104
|
+
}
|
|
59
105
|
|
|
60
106
|
|
|
61
107
|
def management(data: dict):
|
|
@@ -74,7 +120,9 @@ def _include_start_end(cycle: dict, values: list):
|
|
|
74
120
|
return [(_include(cycle, ['startDate', 'endDate']) | v) for v in values]
|
|
75
121
|
|
|
76
122
|
|
|
77
|
-
def _copy_item_if_exists(source: dict, keys: List[str] =
|
|
123
|
+
def _copy_item_if_exists(source: dict, keys: List[str] = None, dest: dict = None) -> dict:
|
|
124
|
+
keys = keys or []
|
|
125
|
+
dest = dest or {}
|
|
78
126
|
return reduce(lambda p, c: p | ({c: source[c]} if c in source else {}), keys, dest)
|
|
79
127
|
|
|
80
128
|
|
|
@@ -96,6 +144,50 @@ def _get_items_with_relevant_term_type(cycles: List[dict], item_name: str, relev
|
|
|
96
144
|
)
|
|
97
145
|
|
|
98
146
|
|
|
147
|
+
def _get_lookup_with_debug(term: dict, column: str) -> Any:
|
|
148
|
+
get_lookup_value(term, column, model_key=MODEL_KEY, land_cover_key=LAND_COVER_KEY)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _data_from_input(cycle: dict, term_id: str) -> dict:
|
|
152
|
+
return {
|
|
153
|
+
"term": {
|
|
154
|
+
"@type": "Term",
|
|
155
|
+
"@id": term_id,
|
|
156
|
+
"termType": "landUseManagement"
|
|
157
|
+
},
|
|
158
|
+
"value": True,
|
|
159
|
+
"startDate": cycle["startDate"],
|
|
160
|
+
"endDate": cycle["endDate"]
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _process_rule(cycle, term, term_type) -> List:
|
|
165
|
+
relevant_terms = []
|
|
166
|
+
for column, condition, new_term in INPUT_RULES[term_type]:
|
|
167
|
+
lookup_result = _get_lookup_with_debug(term, LOOKUPS[column])
|
|
168
|
+
|
|
169
|
+
if condition(lookup_result):
|
|
170
|
+
relevant_terms.append(_data_from_input(cycle=cycle, term_id=new_term))
|
|
171
|
+
|
|
172
|
+
return relevant_terms
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _get_relevant_inputs(cycles: List[dict]) -> List:
|
|
176
|
+
relevant_inputs = []
|
|
177
|
+
for cycle in [c for c in cycles if "inputs" in c]:
|
|
178
|
+
for i in cycle["inputs"]:
|
|
179
|
+
if i.get("term", {}).get("termType", "") in INPUT_RULES:
|
|
180
|
+
relevant_inputs.extend(
|
|
181
|
+
_process_rule(
|
|
182
|
+
cycle=cycle,
|
|
183
|
+
term=i.get("term", {}),
|
|
184
|
+
term_type=i.get("term", {}).get("termType", "")
|
|
185
|
+
)
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
return relevant_inputs
|
|
189
|
+
|
|
190
|
+
|
|
99
191
|
def _should_run(site: dict):
|
|
100
192
|
# Only get related cycles once.
|
|
101
193
|
cycles = related_cycles(site.get("@id"))
|
|
@@ -148,6 +240,7 @@ def _should_run(site: dict):
|
|
|
148
240
|
)
|
|
149
241
|
]
|
|
150
242
|
|
|
243
|
+
relevant_inputs = _get_relevant_inputs(cycles)
|
|
151
244
|
logRequirements(
|
|
152
245
|
site,
|
|
153
246
|
model=MODEL,
|
|
@@ -155,14 +248,14 @@ def _should_run(site: dict):
|
|
|
155
248
|
model_key=MODEL_KEY,
|
|
156
249
|
products_crop_forage_ids=log_blank_nodes_id(products_crop_forage),
|
|
157
250
|
products_land_cover_ids=log_blank_nodes_id(products_land_cover),
|
|
158
|
-
practice_ids=log_blank_nodes_id(practices)
|
|
251
|
+
practice_ids=log_blank_nodes_id(practices),
|
|
252
|
+
inputs=log_blank_nodes_id(relevant_inputs)
|
|
159
253
|
)
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
return should_run, products_crop_forage + products_land_cover, practices
|
|
254
|
+
should_run = any(products_crop_forage + products_land_cover + practices + relevant_inputs)
|
|
255
|
+
logShouldRun(site, MODEL, None, should_run=should_run, model_key=MODEL_KEY)
|
|
256
|
+
return should_run, products_crop_forage + products_land_cover, practices, relevant_inputs
|
|
164
257
|
|
|
165
258
|
|
|
166
259
|
def run(site: dict):
|
|
167
|
-
should_run, products, practices = _should_run(site)
|
|
168
|
-
return list(map(management, products + practices)) if should_run else []
|
|
260
|
+
should_run, products, practices, inputs = _should_run(site)
|
|
261
|
+
return list(map(management, products + practices + inputs)) if should_run else []
|
|
@@ -16,7 +16,7 @@ from . import MODEL
|
|
|
16
16
|
REQUIREMENTS = {
|
|
17
17
|
"Site": {
|
|
18
18
|
"measurements": [
|
|
19
|
-
{"@type": "Measurement", "depthUpper": "", "depthLower": ""}
|
|
19
|
+
{"@type": "Measurement", "depthUpper": "", "depthLower": "", "value": ""}
|
|
20
20
|
]
|
|
21
21
|
}
|
|
22
22
|
}
|
|
@@ -159,21 +159,21 @@ def _get_needed_depths(site: dict) -> list:
|
|
|
159
159
|
|
|
160
160
|
def _should_run(site: dict, model_key: str):
|
|
161
161
|
# we only work with measurements with depths
|
|
162
|
-
measurements = [
|
|
163
|
-
m
|
|
164
|
-
|
|
165
|
-
]
|
|
162
|
+
measurements = [m for m in site.get("measurements", []) if all([
|
|
163
|
+
get_lookup_value(m.get("term", {}), LOOKUPS["measurement"][0], model=MODEL, model_key=model_key),
|
|
164
|
+
m.get('value', [])
|
|
165
|
+
])]
|
|
166
166
|
|
|
167
167
|
measurements_with_depths = [m for m in measurements if all([
|
|
168
|
-
"depthUpper" in m
|
|
169
|
-
"depthLower" in m
|
|
168
|
+
"depthUpper" in m,
|
|
169
|
+
"depthLower" in m,
|
|
170
170
|
(int(m.get("depthUpper", 0)), int(m.get("depthLower", 0))) not in STANDARD_DEPTHS
|
|
171
171
|
])]
|
|
172
172
|
has_measurements_with_depths = len(measurements_with_depths) > 0
|
|
173
173
|
|
|
174
174
|
measurements_missing_depth_recommended = [m for m in measurements if all([
|
|
175
|
-
"depthUpper" not in m
|
|
176
|
-
"depthLower" not in m
|
|
175
|
+
"depthUpper" not in m,
|
|
176
|
+
"depthLower" not in m,
|
|
177
177
|
not get_lookup_value(m.get("term", {}), LOOKUPS["measurement"][1], model=MODEL, model_key=model_key)
|
|
178
178
|
])]
|
|
179
179
|
|
|
@@ -37,9 +37,9 @@ from .term import get_lookup_value
|
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
def group_by_keys(group_keys: list = ['term']):
|
|
40
|
-
def run(group: dict,
|
|
41
|
-
group_key = '-'.join(non_empty_list(map(lambda v:
|
|
42
|
-
group[group_key] = group.get(group_key, []) + [
|
|
40
|
+
def run(group: dict, node: dict):
|
|
41
|
+
group_key = '-'.join(non_empty_list(map(lambda v: node.get(v, {}).get('@id'), group_keys)))
|
|
42
|
+
group[group_key] = group.get(group_key, []) + [node]
|
|
43
43
|
return group
|
|
44
44
|
return run
|
|
45
45
|
|
|
@@ -603,26 +603,3 @@ def get_pasture_system_terms():
|
|
|
603
603
|
'name': 'pasture'
|
|
604
604
|
}, limit=LIMIT)
|
|
605
605
|
return list(map(lambda n: n["@id"], terms))
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
def get_long_fallow_land_cover_terms():
|
|
609
|
-
"""
|
|
610
|
-
Find all `landCover` terms with the name `long fallow`:
|
|
611
|
-
https://hestia.earth/glossary?termType=landCover&query=long%fallow
|
|
612
|
-
|
|
613
|
-
Returns
|
|
614
|
-
-------
|
|
615
|
-
list
|
|
616
|
-
List of matching term `@id` as `str`.
|
|
617
|
-
"""
|
|
618
|
-
terms = search({
|
|
619
|
-
"bool": {
|
|
620
|
-
"must": [
|
|
621
|
-
{"match": {"@type": SchemaType.TERM.value}},
|
|
622
|
-
{"match": {"termType.keyword": TermTermType.LANDCOVER.value}},
|
|
623
|
-
{"match_phrase_prefix": {"name": "long"}},
|
|
624
|
-
{"match": {"name": "fallow"}}
|
|
625
|
-
],
|
|
626
|
-
}
|
|
627
|
-
}, limit=LIMIT)
|
|
628
|
-
return list(map(lambda n: n["@id"], terms))
|
hestia_earth/models/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
VERSION = '0.59.
|
|
1
|
+
VERSION = '0.59.5'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: hestia-earth-models
|
|
3
|
-
Version: 0.59.
|
|
3
|
+
Version: 0.59.5
|
|
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
|