hestia-earth-models 0.59.7__py3-none-any.whl → 0.60.0__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/cache_sites.py +4 -2
- hestia_earth/models/ipcc2019/animal/__init__.py +0 -0
- hestia_earth/models/ipcc2019/animal/pastureGrass.py +298 -0
- hestia_earth/models/ipcc2019/{co2ToAirSoilCarbonStockChangeManagementChange.py → co2ToAirSoilOrganicCarbonStockChangeManagementChange.py} +2 -2
- hestia_earth/models/ipcc2019/pastureGrass.py +73 -447
- hestia_earth/models/ipcc2019/pastureGrass_utils.py +415 -0
- hestia_earth/models/mocking/search-results.json +215 -207
- hestia_earth/models/site/pre_checks/cache_geospatialDatabase.py +14 -2
- hestia_earth/models/utils/completeness.py +17 -14
- hestia_earth/models/utils/feedipedia.py +23 -23
- hestia_earth/models/utils/property.py +3 -1
- hestia_earth/models/version.py +1 -1
- {hestia_earth_models-0.59.7.dist-info → hestia_earth_models-0.60.0.dist-info}/LICENSE +1 -1
- {hestia_earth_models-0.59.7.dist-info → hestia_earth_models-0.60.0.dist-info}/METADATA +1 -1
- {hestia_earth_models-0.59.7.dist-info → hestia_earth_models-0.60.0.dist-info}/RECORD +39 -34
- tests/models/cycle/animal/input/test_properties.py +3 -1
- tests/models/cycle/animal/test_properties.py +4 -2
- tests/models/cycle/input/test_properties.py +3 -1
- tests/models/cycle/product/test_properties.py +2 -1
- tests/models/cycle/test_coldCarcassWeightPerHead.py +1 -0
- tests/models/cycle/test_coldDressedCarcassWeightPerHead.py +1 -0
- tests/models/cycle/test_energyContentLowerHeatingValue.py +1 -0
- tests/models/cycle/test_feedConversionRatio.py +10 -0
- tests/models/cycle/test_readyToCookWeightPerHead.py +1 -0
- tests/models/ipcc2006/test_n2OToAirCropResidueDecompositionDirect.py +4 -1
- tests/models/ipcc2019/animal/__init__.py +0 -0
- tests/models/ipcc2019/animal/test_pastureGrass.py +45 -0
- tests/models/ipcc2019/test_ch4ToAirEntericFermentation.py +32 -8
- tests/models/ipcc2019/{test_co2ToAirSoilCarbonStockChangeManagementChange.py → test_co2ToAirSoilOrganicCarbonStockChangeManagementChange.py} +1 -1
- tests/models/ipcc2019/test_n2OToAirCropResidueDecompositionDirect.py +6 -1
- tests/models/ipcc2019/test_n2OToAirInorganicFertiliserDirect.py +6 -1
- tests/models/ipcc2019/test_n2OToAirOrganicFertiliserDirect.py +6 -1
- tests/models/ipcc2019/test_pastureGrass.py +32 -8
- tests/models/pooreNemecek2018/test_excretaKgN.py +5 -0
- tests/models/pooreNemecek2018/test_excretaKgVs.py +5 -0
- tests/models/pooreNemecek2018/test_no3ToGroundwaterSoilFlux.py +1 -0
- tests/models/test_cache_sites.py +22 -7
- {hestia_earth_models-0.59.7.dist-info → hestia_earth_models-0.60.0.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.59.7.dist-info → hestia_earth_models-0.60.0.dist-info}/top_level.txt +0 -0
|
@@ -112,7 +112,7 @@ def _group_sites(sites: dict):
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
|
|
115
|
-
def run(sites: list, years: list = None, include_region: bool = False):
|
|
115
|
+
def run(sites: list, years: list = None, include_region: bool = False, years_only: bool = False):
|
|
116
116
|
"""
|
|
117
117
|
Run all queries at once for the list of provided Sites.
|
|
118
118
|
Note: Earth Engine needs to be initiliased with `init_gee()` before running this function.
|
|
@@ -126,8 +126,10 @@ def run(sites: list, years: list = None, include_region: bool = False):
|
|
|
126
126
|
include_region : bool
|
|
127
127
|
Prefecth region IDs.
|
|
128
128
|
This will cache region-level data and will make the request slower. Only use if needed.
|
|
129
|
+
years_only : bool
|
|
130
|
+
Run only the collections that depend on the years (if provided).
|
|
129
131
|
"""
|
|
130
|
-
rasters, vectors = list_collections(years, include_region)
|
|
132
|
+
rasters, vectors = list_collections(years, include_region, years_only)
|
|
131
133
|
|
|
132
134
|
filtered_data = _group_sites(sites)
|
|
133
135
|
|
|
File without changes
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Full Grass Consumption
|
|
3
|
+
|
|
4
|
+
This model estimates the energetic requirements of ruminants and can be used to estimate the amount of grass they graze.
|
|
5
|
+
Source:
|
|
6
|
+
[IPCC 2019, Vol.4, Chapter 10](https://www.ipcc-nggip.iges.or.jp/public/2019rf/pdf/4_Volume4/19R_V4_Ch10_Livestock.pdf).
|
|
7
|
+
"""
|
|
8
|
+
from hestia_earth.schema import TermTermType
|
|
9
|
+
from hestia_earth.utils.model import filter_list_term_type
|
|
10
|
+
from hestia_earth.utils.tools import list_sum
|
|
11
|
+
|
|
12
|
+
from hestia_earth.models.log import logRequirements, logShouldRun, debugValues
|
|
13
|
+
from hestia_earth.models.utils.input import _new_input
|
|
14
|
+
from hestia_earth.models.utils.term import get_wool_terms, get_lookup_value
|
|
15
|
+
from hestia_earth.models.utils.completeness import _is_term_type_complete, _is_term_type_incomplete
|
|
16
|
+
from hestia_earth.models.utils.property import get_node_property
|
|
17
|
+
from .. import MODEL
|
|
18
|
+
from ..pastureGrass_utils import (
|
|
19
|
+
practice_input_id,
|
|
20
|
+
should_run_practice,
|
|
21
|
+
calculate_meanDE,
|
|
22
|
+
calculate_meanECHHV,
|
|
23
|
+
calculate_REM,
|
|
24
|
+
calculate_REG,
|
|
25
|
+
calculate_NEfeed,
|
|
26
|
+
product_wool_energy,
|
|
27
|
+
get_animals,
|
|
28
|
+
get_animal_values
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
REQUIREMENTS = {
|
|
32
|
+
"Cycle": {
|
|
33
|
+
"completeness.animalFeed": "True",
|
|
34
|
+
"completeness.animalPopulation": "True",
|
|
35
|
+
"completeness.freshForage": "False",
|
|
36
|
+
"site": {
|
|
37
|
+
"@type": "Site",
|
|
38
|
+
"siteType": "permanent pasture"
|
|
39
|
+
},
|
|
40
|
+
"practices": [{
|
|
41
|
+
"@type": "Practice",
|
|
42
|
+
"value": "",
|
|
43
|
+
"term.@id": "pastureGrass",
|
|
44
|
+
"key": {
|
|
45
|
+
"@type": "Term",
|
|
46
|
+
"term.termType": "landCover"
|
|
47
|
+
}
|
|
48
|
+
}],
|
|
49
|
+
"animals": [{
|
|
50
|
+
"@type": "Animal",
|
|
51
|
+
"value": "> 0",
|
|
52
|
+
"term.termType": "liveAnimal",
|
|
53
|
+
"referencePeriod": "average",
|
|
54
|
+
"properties": [{
|
|
55
|
+
"@type": "Property",
|
|
56
|
+
"value": "",
|
|
57
|
+
"term.@id": [
|
|
58
|
+
"liveweightPerHead",
|
|
59
|
+
"weightAtMaturity"
|
|
60
|
+
]
|
|
61
|
+
}],
|
|
62
|
+
"optional": {
|
|
63
|
+
"properties": [{
|
|
64
|
+
"@type": "Property",
|
|
65
|
+
"value": "",
|
|
66
|
+
"term.@id": [
|
|
67
|
+
"hoursWorkedPerDay",
|
|
68
|
+
"pregnancyRateTotal",
|
|
69
|
+
"animalsPerBirth"
|
|
70
|
+
]
|
|
71
|
+
}],
|
|
72
|
+
"inputs": [{
|
|
73
|
+
"@type": "Input",
|
|
74
|
+
"term.units": "kg",
|
|
75
|
+
"value": "> 0",
|
|
76
|
+
"optional": {
|
|
77
|
+
"properties": [{
|
|
78
|
+
"@type": "Property",
|
|
79
|
+
"value": "",
|
|
80
|
+
"term.@id": ["neutralDetergentFibreContent", "energyContentHigherHeatingValue"]
|
|
81
|
+
}]
|
|
82
|
+
}
|
|
83
|
+
}],
|
|
84
|
+
"practices": [{
|
|
85
|
+
"@type": "Practice",
|
|
86
|
+
"value": "",
|
|
87
|
+
"term.termType": "animalManagement",
|
|
88
|
+
"properties": [{
|
|
89
|
+
"@type": "Property",
|
|
90
|
+
"value": "",
|
|
91
|
+
"term.@id": "fatContent"
|
|
92
|
+
}]
|
|
93
|
+
}]
|
|
94
|
+
}
|
|
95
|
+
}],
|
|
96
|
+
"none": {
|
|
97
|
+
"inputs": [{
|
|
98
|
+
"@type": "Input",
|
|
99
|
+
"term.units": "kg",
|
|
100
|
+
"value": "> 0",
|
|
101
|
+
"isAnimalFeed": "True"
|
|
102
|
+
}]
|
|
103
|
+
},
|
|
104
|
+
"optional": {
|
|
105
|
+
"products": [{
|
|
106
|
+
"@type": "Product",
|
|
107
|
+
"value": "",
|
|
108
|
+
"term.@id": "animalProduct"
|
|
109
|
+
}]
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
LOOKUPS = {
|
|
114
|
+
"animalManagement": [
|
|
115
|
+
"mjKgEvMilkIpcc2019"
|
|
116
|
+
],
|
|
117
|
+
"animalProduct": ["mjKgEvWoolNetEnergyWoolIpcc2019", "allowedLiveAnimalTermIds"],
|
|
118
|
+
"liveAnimal": [
|
|
119
|
+
"ipcc2019AnimalTypeGrouping",
|
|
120
|
+
"mjDayKgCfiNetEnergyMaintenanceIpcc2019",
|
|
121
|
+
"ratioCPregnancyNetEnergyPregnancyIpcc2019",
|
|
122
|
+
"ratioCNetEnergyGrowthCattleBuffaloIpcc2019",
|
|
123
|
+
"mjKgABNetEnergyGrowthSheepGoatsIpcc2019",
|
|
124
|
+
"isWoolProducingAnimal"
|
|
125
|
+
],
|
|
126
|
+
"system-liveAnimal-activityCoefficient-ipcc2019": "using animal term @id",
|
|
127
|
+
"crop-property": ["energyDigestibilityRuminants", "energyContentHigherHeatingValue"],
|
|
128
|
+
"crop": "grazedPastureGrassInputId",
|
|
129
|
+
"forage-property": ["energyDigestibilityRuminants", "energyContentHigherHeatingValue"],
|
|
130
|
+
"landCover": "grazedPastureGrassInputId"
|
|
131
|
+
}
|
|
132
|
+
RETURNS = {
|
|
133
|
+
"Animal": [{
|
|
134
|
+
"Input": [{
|
|
135
|
+
"@type": "Input",
|
|
136
|
+
"term.termType": ["crop", "forage"],
|
|
137
|
+
"value": ""
|
|
138
|
+
}]
|
|
139
|
+
}]
|
|
140
|
+
}
|
|
141
|
+
MODEL_KEY = 'animal/pastureGrass'
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _input(term_id: str, value: float):
|
|
145
|
+
node = _new_input(term_id, MODEL)
|
|
146
|
+
node['value'] = [value]
|
|
147
|
+
return node
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _sum_liveWeightPerHead(animals: list):
|
|
151
|
+
return list_sum([
|
|
152
|
+
animal.get('value', 0) * get_node_property(animal, 'liveweightPerHead', False).get('value', 0)
|
|
153
|
+
for animal in animals
|
|
154
|
+
])
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _isNEwool_animal(animal: dict):
|
|
158
|
+
value = get_lookup_value(animal.get('term', {}), 'isWoolProducingAnimal', model=MODEL, model_key=MODEL_KEY)
|
|
159
|
+
return not (not value)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _is_NEwool_product(product: dict, animal: dict):
|
|
163
|
+
animal_term_ids = get_lookup_value(product, 'allowedLiveAnimalTermIds', model=MODEL, model_key=MODEL_KEY).split(';')
|
|
164
|
+
return animal.get('term', {}).get('@id') in animal_term_ids
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def calculate_NEwool(cycle: dict, animal: dict, products: list, total_weight: float) -> float:
|
|
168
|
+
term_id = animal.get('term', {}).get('@id')
|
|
169
|
+
|
|
170
|
+
wool_products = [p for p in products if _is_NEwool_product(p.get('term', {}), animal)]
|
|
171
|
+
total_energy = list_sum([
|
|
172
|
+
list_sum(product.get('value', [])) * product_wool_energy(product) for product in wool_products
|
|
173
|
+
])
|
|
174
|
+
animal_weight = _sum_liveWeightPerHead([animal])
|
|
175
|
+
|
|
176
|
+
debugValues(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
|
|
177
|
+
total_energy=total_energy,
|
|
178
|
+
animal_liveWeightPerHead=animal_weight,
|
|
179
|
+
total_liveWeightPerHead=total_weight)
|
|
180
|
+
|
|
181
|
+
return total_energy * animal_weight/total_weight
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _calculate_GE(
|
|
185
|
+
cycle: dict, animal: dict, REM: float, REG: float, NEwool: float, system: dict
|
|
186
|
+
) -> float:
|
|
187
|
+
term_id = animal.get('term', {}).get('@id')
|
|
188
|
+
|
|
189
|
+
NEm, NEa, NEl, NEwork, NEp, NEg = get_animal_values(cycle, animal, system)
|
|
190
|
+
|
|
191
|
+
NEm_feed, NEg_feed = calculate_NEfeed(animal)
|
|
192
|
+
debugValues(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
|
|
193
|
+
NEm_feed=NEm_feed,
|
|
194
|
+
NEg_feed=NEg_feed)
|
|
195
|
+
|
|
196
|
+
return (NEm + NEa + NEl + NEwork + NEp - NEm_feed)/REM + (NEg + NEwool - NEg_feed)/REG
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def _run_practice(cycle: dict, GE: float, meanECHHV: float):
|
|
200
|
+
def run(practice: dict):
|
|
201
|
+
key = practice.get('key', {})
|
|
202
|
+
key_id = key.get('@id')
|
|
203
|
+
input_term_id = practice_input_id(practice)
|
|
204
|
+
value = (GE / meanECHHV) * (list_sum(practice.get('value', [0])) / 100)
|
|
205
|
+
|
|
206
|
+
logRequirements(cycle, model=MODEL, term=input_term_id, model_key=MODEL_KEY,
|
|
207
|
+
GE=GE,
|
|
208
|
+
meanECHHV=meanECHHV,
|
|
209
|
+
key_id=key_id)
|
|
210
|
+
|
|
211
|
+
logShouldRun(cycle, MODEL, input_term_id, True, model_key=MODEL_KEY)
|
|
212
|
+
|
|
213
|
+
return _input(input_term_id, value)
|
|
214
|
+
|
|
215
|
+
return run
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def _run_animal(cycle: dict, meanDE: float, meanECHHV: float, system: dict, practices: list):
|
|
219
|
+
REM = calculate_REM(meanDE)
|
|
220
|
+
REG = calculate_REG(meanDE)
|
|
221
|
+
|
|
222
|
+
wool_term_ids = get_wool_terms()
|
|
223
|
+
# list of animal product
|
|
224
|
+
wool_products = [p for p in cycle.get('products', []) if p.get('term', {}).get('@id') in wool_term_ids]
|
|
225
|
+
animals = list(filter(_isNEwool_animal, cycle.get('animals', [])))
|
|
226
|
+
total_liveWeightPerHead = _sum_liveWeightPerHead(animals)
|
|
227
|
+
|
|
228
|
+
def run(animal: dict):
|
|
229
|
+
term_id = animal.get('term', {}).get('@id')
|
|
230
|
+
|
|
231
|
+
NEwool = calculate_NEwool(cycle, animal, wool_products, total_liveWeightPerHead) if (
|
|
232
|
+
total_liveWeightPerHead > 0
|
|
233
|
+
) else 0
|
|
234
|
+
GE = (_calculate_GE(cycle, animal, REM, REG, NEwool, system) / (meanDE/100)) if all([REM, REG]) else 0
|
|
235
|
+
|
|
236
|
+
debugValues(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
|
|
237
|
+
REM=REM,
|
|
238
|
+
REG=REG,
|
|
239
|
+
NEwool=NEwool,
|
|
240
|
+
GE=GE,
|
|
241
|
+
meanDE=meanDE)
|
|
242
|
+
|
|
243
|
+
inputs = list(map(_run_practice(cycle, GE, meanECHHV), practices))
|
|
244
|
+
return animal | {
|
|
245
|
+
'inputs': animal.get('inputs', []) + inputs
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return run
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def _run(cycle: dict, meanDE: float, meanECHHV: float, system: dict, practices: list):
|
|
252
|
+
animals = get_animals(cycle)
|
|
253
|
+
return list(map(_run_animal(cycle, meanDE, meanECHHV, system, practices), animals))
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def _should_run(cycle: dict, practices: dict):
|
|
257
|
+
systems = filter_list_term_type(cycle.get('practices', []), TermTermType.SYSTEM)
|
|
258
|
+
animalFeed_complete = _is_term_type_complete(cycle, 'animalFeed')
|
|
259
|
+
animalPopulation_complete = _is_term_type_complete(cycle, 'animalPopulation')
|
|
260
|
+
freshForage_incomplete = _is_term_type_incomplete(cycle, 'freshForage')
|
|
261
|
+
all_animals_have_value = all([a.get('value', 0) > 0 for a in cycle.get('animals', [])])
|
|
262
|
+
|
|
263
|
+
no_cycle_inputs_feed = all([not input.get('isAnimalFeed', False) for input in cycle.get('inputs', [])])
|
|
264
|
+
|
|
265
|
+
meanDE = calculate_meanDE(practices)
|
|
266
|
+
meanECHHV = calculate_meanECHHV(practices)
|
|
267
|
+
|
|
268
|
+
should_run = all([
|
|
269
|
+
animalFeed_complete,
|
|
270
|
+
animalPopulation_complete,
|
|
271
|
+
freshForage_incomplete,
|
|
272
|
+
no_cycle_inputs_feed,
|
|
273
|
+
all_animals_have_value,
|
|
274
|
+
len(systems) > 0,
|
|
275
|
+
len(practices) > 0,
|
|
276
|
+
meanDE > 0,
|
|
277
|
+
meanECHHV > 0
|
|
278
|
+
])
|
|
279
|
+
|
|
280
|
+
for term_id in [MODEL_KEY] + [practice_input_id(p) for p in practices]:
|
|
281
|
+
logRequirements(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
|
|
282
|
+
term_type_animalFeed_complete=animalFeed_complete,
|
|
283
|
+
term_type_animalPopulation_complete=animalPopulation_complete,
|
|
284
|
+
term_type_freshForage_incomplete=freshForage_incomplete,
|
|
285
|
+
no_cycle_inputs_feed=no_cycle_inputs_feed,
|
|
286
|
+
all_animals_have_value=all_animals_have_value,
|
|
287
|
+
meanDE=meanDE,
|
|
288
|
+
meanECHHV=meanECHHV)
|
|
289
|
+
|
|
290
|
+
logShouldRun(cycle, MODEL, term_id, should_run, model_key=MODEL_KEY)
|
|
291
|
+
|
|
292
|
+
return should_run, meanDE, meanECHHV, systems[0] if systems else None
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def run(cycle: dict):
|
|
296
|
+
practices = list(filter(should_run_practice(cycle), cycle.get('practices', [])))
|
|
297
|
+
should_run, meanDE, meanECHHV, system = _should_run(cycle, practices)
|
|
298
|
+
return _run(cycle, meanDE, meanECHHV, system, practices) if should_run else []
|
|
@@ -50,7 +50,7 @@ RETURNS = {
|
|
|
50
50
|
"depth": "30"
|
|
51
51
|
}]
|
|
52
52
|
}
|
|
53
|
-
TERM_ID = '
|
|
53
|
+
TERM_ID = 'co2ToAirSoilOrganicCarbonStockChangeManagementChange'
|
|
54
54
|
|
|
55
55
|
DEPTH_UPPER = 0
|
|
56
56
|
DEPTH_LOWER = 30
|
|
@@ -101,7 +101,7 @@ MEASUREMENT_METHOD_RANKING = [
|
|
|
101
101
|
]
|
|
102
102
|
"""
|
|
103
103
|
A ranking of `MeasurementMethodClassification`s from weakest to strongest used to determine the `EmissionMethodTier` of
|
|
104
|
-
the `
|
|
104
|
+
the `co2ToAirSoilOrganicCarbonStockChangeManagementChange` output.
|
|
105
105
|
|
|
106
106
|
The `EmissionMethodTier` should be based on the weakest `MeasurementMethodClassification` between the current SOC and
|
|
107
107
|
previous SOC.
|