hestia-earth-models 0.59.7__py3-none-any.whl → 0.60.1__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 +40 -16
- 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 +16 -4
- 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.1.dist-info}/LICENSE +1 -1
- {hestia_earth_models-0.59.7.dist-info → hestia_earth_models-0.60.1.dist-info}/METADATA +1 -1
- {hestia_earth_models-0.59.7.dist-info → hestia_earth_models-0.60.1.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 +10 -7
- {hestia_earth_models-0.59.7.dist-info → hestia_earth_models-0.60.1.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.59.7.dist-info → hestia_earth_models-0.60.1.dist-info}/top_level.txt +0 -0
|
@@ -5,23 +5,32 @@ This model estimates the energetic requirements of ruminants and can be used to
|
|
|
5
5
|
Source:
|
|
6
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
7
|
"""
|
|
8
|
-
from hestia_earth.schema import TermTermType
|
|
9
|
-
from hestia_earth.utils.api import download_hestia
|
|
10
|
-
from hestia_earth.utils.lookup import download_lookup, get_table_value, column_name, extract_grouped_data
|
|
8
|
+
from hestia_earth.schema import TermTermType
|
|
11
9
|
from hestia_earth.utils.model import filter_list_term_type
|
|
12
|
-
from hestia_earth.utils.tools import list_sum
|
|
10
|
+
from hestia_earth.utils.tools import list_sum
|
|
13
11
|
|
|
14
|
-
from hestia_earth.models.log import
|
|
15
|
-
from hestia_earth.models.utils.input import _new_input
|
|
12
|
+
from hestia_earth.models.log import logRequirements, logShouldRun
|
|
13
|
+
from hestia_earth.models.utils.input import _new_input
|
|
14
|
+
from hestia_earth.models.utils.term import get_wool_terms
|
|
16
15
|
from hestia_earth.models.utils.completeness import _is_term_type_complete, _is_term_type_incomplete
|
|
17
|
-
from hestia_earth.models.utils.term import get_lookup_value, get_wool_terms
|
|
18
|
-
from hestia_earth.models.utils.property import get_node_property, get_node_property_value, node_property_lookup_value
|
|
19
|
-
from .utils import get_milkYield_practice
|
|
20
16
|
from . import MODEL
|
|
17
|
+
from .pastureGrass_utils import (
|
|
18
|
+
practice_input_id,
|
|
19
|
+
should_run_practice,
|
|
20
|
+
calculate_meanDE,
|
|
21
|
+
calculate_meanECHHV,
|
|
22
|
+
calculate_REM,
|
|
23
|
+
calculate_REG,
|
|
24
|
+
calculate_NEfeed,
|
|
25
|
+
product_wool_energy,
|
|
26
|
+
get_animals,
|
|
27
|
+
get_animal_values
|
|
28
|
+
)
|
|
21
29
|
|
|
22
30
|
REQUIREMENTS = {
|
|
23
31
|
"Cycle": {
|
|
24
32
|
"completeness.animalFeed": "True",
|
|
33
|
+
"completeness.animalPopulation": "False",
|
|
25
34
|
"completeness.freshForage": "False",
|
|
26
35
|
"site": {
|
|
27
36
|
"@type": "Site",
|
|
@@ -109,7 +118,7 @@ LOOKUPS = {
|
|
|
109
118
|
"animalManagement": [
|
|
110
119
|
"mjKgEvMilkIpcc2019"
|
|
111
120
|
],
|
|
112
|
-
"animalProduct": "mjKgEvWoolNetEnergyWoolIpcc2019",
|
|
121
|
+
"animalProduct": ["mjKgEvWoolNetEnergyWoolIpcc2019"],
|
|
113
122
|
"liveAnimal": [
|
|
114
123
|
"ipcc2019AnimalTypeGrouping",
|
|
115
124
|
"mjDayKgCfiNetEnergyMaintenanceIpcc2019",
|
|
@@ -130,9 +139,6 @@ RETURNS = {
|
|
|
130
139
|
}]
|
|
131
140
|
}
|
|
132
141
|
MODEL_KEY = 'pastureGrass'
|
|
133
|
-
KEY_TERM_TYPES = [
|
|
134
|
-
TermTermType.LANDCOVER.value
|
|
135
|
-
]
|
|
136
142
|
|
|
137
143
|
|
|
138
144
|
def _input(term_id: str, value: float):
|
|
@@ -141,479 +147,99 @@ def _input(term_id: str, value: float):
|
|
|
141
147
|
return node
|
|
142
148
|
|
|
143
149
|
|
|
144
|
-
def
|
|
150
|
+
def _sum_values(values: list, index=0): return sum([v[index] for v in values])
|
|
145
151
|
|
|
146
152
|
|
|
147
|
-
def
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
def _get_activityCoefficient(cycle: dict, animal: dict, system: dict):
|
|
153
|
-
term = animal.get('term', {})
|
|
154
|
-
term_id = term.get('@id')
|
|
155
|
-
system_id = system.get('term', {}).get('@id')
|
|
156
|
-
lookup = download_lookup('system-liveAnimal-activityCoefficient-ipcc2019.csv')
|
|
157
|
-
activityCoefficient = safe_parse_float(get_table_value(lookup, 'termid', system_id, column_name(term_id)), 0)
|
|
158
|
-
|
|
159
|
-
debugValues(cycle, model=MODEL, term=term_id,
|
|
160
|
-
activityCoefficient=activityCoefficient)
|
|
161
|
-
|
|
162
|
-
return activityCoefficient
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
def _calculate_NEm(cycle: dict, animal: dict):
|
|
166
|
-
term = animal.get('term', {})
|
|
167
|
-
term_id = term.get('@id')
|
|
168
|
-
|
|
169
|
-
mjDayKgCfiNetEnergyMaintenance = safe_parse_float(
|
|
170
|
-
get_lookup_value(term, 'mjDayKgCfiNetEnergyMaintenanceIpcc2019'), 0
|
|
171
|
-
)
|
|
172
|
-
liveweightPerHead = get_node_property(animal, 'liveweightPerHead', False).get('value', 0)
|
|
173
|
-
animal_value = animal.get('value', 0)
|
|
174
|
-
cycleDuration = cycle.get('cycleDuration', 365)
|
|
175
|
-
NEm = mjDayKgCfiNetEnergyMaintenance * pow(liveweightPerHead, 0.75) * animal_value * cycleDuration
|
|
176
|
-
|
|
177
|
-
debugValues(cycle, model=MODEL, term=term_id,
|
|
178
|
-
mjDayKgCfiNetEnergyMaintenance=mjDayKgCfiNetEnergyMaintenance,
|
|
179
|
-
liveweightPerHead=liveweightPerHead,
|
|
180
|
-
NEm=NEm)
|
|
181
|
-
|
|
182
|
-
return NEm
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
def _calculate_NEa_cattleAndBuffalo(cycle: dict, animal: dict, system: dict, NEm: float):
|
|
186
|
-
term = animal.get('term', {})
|
|
187
|
-
term_id = term.get('@id')
|
|
188
|
-
|
|
189
|
-
activityCoefficient = _get_activityCoefficient(cycle, animal, system)
|
|
190
|
-
|
|
191
|
-
NEa = activityCoefficient * NEm
|
|
192
|
-
|
|
193
|
-
debugValues(cycle, model=MODEL, term=term_id,
|
|
194
|
-
NEa=NEa)
|
|
195
|
-
|
|
196
|
-
return term_id, NEa
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
def _calculate_NEa_sheepAndGoat(cycle: dict, animal: dict, system: dict, _NEm: float):
|
|
200
|
-
term = animal.get('term', {})
|
|
201
|
-
term_id = term.get('@id')
|
|
202
|
-
|
|
203
|
-
activityCoefficient = _get_activityCoefficient(cycle, animal, system)
|
|
204
|
-
|
|
205
|
-
liveweightPerHead = get_node_property(animal, 'liveweightPerHead', False).get('value', 0)
|
|
206
|
-
animal_value = animal.get('value', 0)
|
|
207
|
-
cycleDuration = cycle.get('cycleDuration', 365)
|
|
208
|
-
NEa = activityCoefficient * liveweightPerHead * animal_value * cycleDuration
|
|
209
|
-
|
|
210
|
-
debugValues(cycle, model=MODEL, term=term_id,
|
|
211
|
-
liveweightPerHead=liveweightPerHead,
|
|
212
|
-
NEa=NEa)
|
|
213
|
-
|
|
214
|
-
return term_id, NEa
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
_NEa_BY_GROUPING = {
|
|
218
|
-
'cattleAndBuffalo': _calculate_NEa_cattleAndBuffalo,
|
|
219
|
-
'sheepAndGoat': _calculate_NEa_sheepAndGoat
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
def _calculate_NEa(cycle: dict, animal: dict, system: dict, NEm: float):
|
|
224
|
-
grouping = _get_grouping(animal)
|
|
225
|
-
return _NEa_BY_GROUPING.get(grouping, lambda *args: None)(cycle, animal, system, NEm)
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
def _calculate_NEl_cattleAndBuffalo(cycle: dict, animal: dict):
|
|
229
|
-
term = animal.get('term', {})
|
|
230
|
-
term_id = term.get('@id')
|
|
231
|
-
|
|
232
|
-
milkYieldPractice = get_milkYield_practice(animal)
|
|
233
|
-
milkYield = list_sum(milkYieldPractice.get('value', []))
|
|
234
|
-
fatContent = get_node_property(milkYieldPractice, 'fatContent').get('value', 0)
|
|
235
|
-
animal_value = animal.get('value', 0)
|
|
236
|
-
cycleDuration = cycle.get('cycleDuration', 365)
|
|
237
|
-
NEl = milkYield * (1.47 + (0.4 * fatContent)) * animal_value * cycleDuration
|
|
238
|
-
|
|
239
|
-
debugValues(cycle, model=MODEL, term=term_id,
|
|
240
|
-
milkYield=milkYield,
|
|
241
|
-
fatContent=fatContent,
|
|
242
|
-
NEl=NEl)
|
|
243
|
-
|
|
244
|
-
return term_id, NEl
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
def _calculate_NEl_sheepAndGoat(cycle: dict, animal: dict):
|
|
248
|
-
term = animal.get('term', {})
|
|
249
|
-
term_id = term.get('@id')
|
|
250
|
-
|
|
251
|
-
milkYieldPractice = get_milkYield_practice(animal)
|
|
252
|
-
milkYield = list_sum(milkYieldPractice.get('value', []))
|
|
253
|
-
EV_milk = safe_parse_float(get_lookup_value(milkYieldPractice.get('term', {}), 'mjKgEvMilkIpcc2019'), 0)
|
|
254
|
-
default_fatContent = safe_parse_float(
|
|
255
|
-
get_lookup_value(milkYieldPractice.get('term', {}), 'defaultFatContentEvMilkIpcc2019'),
|
|
256
|
-
7
|
|
257
|
-
)
|
|
258
|
-
fatContent = get_node_property(milkYieldPractice, 'fatContent').get('value', 0)
|
|
259
|
-
animal_value = animal.get('value', 0)
|
|
260
|
-
cycleDuration = cycle.get('cycleDuration', 365)
|
|
261
|
-
NEl = milkYield * (EV_milk * fatContent/default_fatContent) * animal_value * cycleDuration
|
|
262
|
-
|
|
263
|
-
debugValues(cycle, model=MODEL, term=term_id,
|
|
264
|
-
milkYield=milkYield,
|
|
265
|
-
EV_milk=EV_milk,
|
|
266
|
-
NEl=NEl)
|
|
267
|
-
|
|
268
|
-
return term_id, NEl
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
_NEl_BY_GROUPING = {
|
|
272
|
-
'cattleAndBuffalo': _calculate_NEl_cattleAndBuffalo,
|
|
273
|
-
'sheepAndGoat': _calculate_NEl_sheepAndGoat
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
def _calculate_NEl(cycle: dict, animal: dict):
|
|
278
|
-
grouping = _get_grouping(animal)
|
|
279
|
-
return _NEl_BY_GROUPING.get(grouping, lambda *args: None)(cycle, animal)
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
def _calculate_NEwork(cycle: dict, animal: dict, NEm: float):
|
|
283
|
-
term = animal.get('term', {})
|
|
284
|
-
term_id = term.get('@id')
|
|
285
|
-
|
|
286
|
-
hoursWorkedPerDay = get_node_property(animal, 'hoursWorkedPerDay').get('value', 0)
|
|
287
|
-
NEwork = 0.1 * NEm * hoursWorkedPerDay
|
|
288
|
-
|
|
289
|
-
debugValues(cycle, model=MODEL, term=term_id,
|
|
290
|
-
hoursWorkedPerDay=hoursWorkedPerDay,
|
|
291
|
-
NEwork=NEwork)
|
|
292
|
-
|
|
293
|
-
return term_id, NEwork
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
def _get_pregnancy_ratio_per_birth(animal: dict, value: str):
|
|
297
|
-
animalsPerBirth = get_node_property(animal, 'animalsPerBirth').get('value', 3)
|
|
298
|
-
single = safe_parse_float(extract_grouped_data(value, 'singleBirth'), 0)
|
|
299
|
-
double = safe_parse_float(extract_grouped_data(value, 'doubleBirth'), 0)
|
|
300
|
-
tripple = safe_parse_float(extract_grouped_data(value, 'tripleBirthOrMore'))
|
|
301
|
-
return (
|
|
302
|
-
single if animalsPerBirth <= 1 else
|
|
303
|
-
((animalsPerBirth-1)/2)*single * (1-((animalsPerBirth-1)/2)*double) if 1 < animalsPerBirth < 2 else
|
|
304
|
-
double if animalsPerBirth == 2 else
|
|
305
|
-
((animalsPerBirth-2)/3)*double * (1-((animalsPerBirth-2)/3)*tripple) if 2 < animalsPerBirth < 3 else
|
|
306
|
-
tripple
|
|
307
|
-
)
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
def _get_pregnancy_ratio(animal: dict):
|
|
311
|
-
term = animal.get('term', {})
|
|
312
|
-
value = get_lookup_value(term, 'ratioCPregnancyNetEnergyPregnancyIpcc2019')
|
|
313
|
-
return _get_pregnancy_ratio_per_birth(animal, value) if ';' in value else safe_parse_float(value, 0)
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
def _calculate_NEp(cycle: dict, animal: dict, NEm: float):
|
|
317
|
-
term = animal.get('term', {})
|
|
318
|
-
term_id = term.get('@id')
|
|
319
|
-
|
|
320
|
-
ratioCPregnancyNetEnergyPregnancy = _get_pregnancy_ratio(animal)
|
|
321
|
-
pregnancyRateTotal = get_node_property(animal, 'pregnancyRateTotal').get('value', 0)
|
|
322
|
-
NEp = ratioCPregnancyNetEnergyPregnancy * pregnancyRateTotal/100 * NEm
|
|
323
|
-
|
|
324
|
-
debugValues(cycle, model=MODEL, term=term_id,
|
|
325
|
-
ratioCPregnancyNetEnergyPregnancy=ratioCPregnancyNetEnergyPregnancy,
|
|
326
|
-
pregnancyRateTotal=pregnancyRateTotal,
|
|
327
|
-
NEp=NEp)
|
|
328
|
-
|
|
329
|
-
return term_id, NEp
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
def _calculate_NEg_cattleAndBuffalo(cycle: dict, animal: dict):
|
|
333
|
-
term = animal.get('term', {})
|
|
334
|
-
term_id = term.get('@id')
|
|
335
|
-
|
|
336
|
-
ratioCNetEnergyGrowthCattleBuffalo = safe_parse_float(
|
|
337
|
-
get_lookup_value(term, 'ratioCNetEnergyGrowthCattleBuffaloIpcc2019'), 0
|
|
338
|
-
)
|
|
339
|
-
liveweightPerHead = get_node_property(animal, 'liveweightPerHead').get('value', 0)
|
|
340
|
-
weightAtMaturity = get_node_property(animal, 'weightAtMaturity').get('value', 0)
|
|
341
|
-
liveweightGain = get_node_property(animal, 'liveweightGain').get('value', 0)
|
|
342
|
-
animal_value = animal.get('value', 0)
|
|
343
|
-
cycleDuration = cycle.get('cycleDuration', 365)
|
|
344
|
-
NEg = 22.02 * \
|
|
345
|
-
pow(liveweightPerHead / (ratioCNetEnergyGrowthCattleBuffalo * weightAtMaturity), 0.75) * \
|
|
346
|
-
pow(liveweightGain, 1.097) * \
|
|
347
|
-
animal_value * cycleDuration if all([
|
|
348
|
-
ratioCNetEnergyGrowthCattleBuffalo * weightAtMaturity > 0
|
|
349
|
-
]) else 0
|
|
350
|
-
|
|
351
|
-
debugValues(cycle, model=MODEL, term=term_id,
|
|
352
|
-
ratioCNetEnergyGrowthCattleBuffalo=ratioCNetEnergyGrowthCattleBuffalo,
|
|
353
|
-
liveweightPerHead=liveweightPerHead,
|
|
354
|
-
weightAtMaturity=weightAtMaturity,
|
|
355
|
-
liveweightGain=liveweightGain,
|
|
356
|
-
NEg=NEg)
|
|
357
|
-
|
|
358
|
-
return term_id, NEg
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
def _calculate_NEg_sheepAndGoat(cycle: dict, animal: dict):
|
|
362
|
-
term = animal.get('term', {})
|
|
363
|
-
term_id = term.get('@id')
|
|
364
|
-
|
|
365
|
-
MjKgABNetEnergyGrowthSheepGoats = get_lookup_value(term, 'MjKgABNetEnergyGrowthSheepGoatsIpcc2019')
|
|
366
|
-
MjKg_a = safe_parse_float(extract_grouped_data(MjKgABNetEnergyGrowthSheepGoats, 'a'), 0)
|
|
367
|
-
MjKg_b = safe_parse_float(extract_grouped_data(MjKgABNetEnergyGrowthSheepGoats, 'b'), 0)
|
|
368
|
-
BWi = get_node_property(animal, 'weightAtWeaning').get('value', 0)
|
|
369
|
-
BWf = get_node_property(animal, 'weightAtOneYear').get('value', 0) or \
|
|
370
|
-
get_node_property(animal, 'weightAtSlaughter').get('value', 0)
|
|
371
|
-
animal_value = animal.get('value', 0)
|
|
372
|
-
cycleDuration = cycle.get('cycleDuration', 365)
|
|
373
|
-
NEg = (BWf - BWi) * (MjKg_a + 0.5 * MjKg_b * (BWi + BWf)) / 365 * animal_value * cycleDuration
|
|
374
|
-
|
|
375
|
-
debugValues(cycle, model=MODEL, term=term_id,
|
|
376
|
-
MjKg_a=MjKg_a,
|
|
377
|
-
MjKg_b=MjKg_b,
|
|
378
|
-
BWi=BWi,
|
|
379
|
-
BWf=BWf,
|
|
380
|
-
NEg=NEg)
|
|
381
|
-
|
|
382
|
-
return term_id, NEg
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
_NEg_BY_GROUPING = {
|
|
386
|
-
'cattleAndBuffalo': _calculate_NEg_cattleAndBuffalo,
|
|
387
|
-
'sheepAndGoat': _calculate_NEg_sheepAndGoat
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
def _calculate_NEg(cycle: dict, animal: dict):
|
|
392
|
-
grouping = _get_grouping(animal)
|
|
393
|
-
return _NEg_BY_GROUPING.get(grouping, lambda *args: None)(cycle, animal)
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
def _calculate_NEwool(cycle: dict):
|
|
397
|
-
terms = get_wool_terms()
|
|
398
|
-
products = [p for p in cycle.get('products', []) if p.get('term', {}).get('@id') in terms]
|
|
153
|
+
def calculate_NEwool(cycle: dict) -> float:
|
|
154
|
+
term_ids = get_wool_terms()
|
|
155
|
+
products = [p for p in cycle.get('products', []) if p.get('term', {}).get('@id') in term_ids]
|
|
399
156
|
product_values = [
|
|
400
|
-
(
|
|
401
|
-
list_sum(p.get('value', [])),
|
|
402
|
-
safe_parse_float(get_lookup_value(p.get('term', {}), LOOKUPS['animalProduct']), 24)
|
|
403
|
-
) for p in products
|
|
157
|
+
(list_sum(p.get('value', [])), product_wool_energy(p)) for p in products
|
|
404
158
|
]
|
|
405
|
-
|
|
406
159
|
return sum([value * lookup_value for (value, lookup_value) in product_values])
|
|
407
160
|
|
|
408
161
|
|
|
409
|
-
def
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
def _calculate_REG(energy: float = 0):
|
|
433
|
-
return 1.164 - (5.16/1000 * energy) + (1.308/100000 * pow(energy, 2)) - (37.4/energy) if energy > 0 else 0
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
def _calculate_feed_meanDE(cycle: dict, input: dict):
|
|
437
|
-
term_id = input.get('term', {}).get('@id')
|
|
438
|
-
|
|
439
|
-
energyContent = get_node_property_value(MODEL, input, 'energyContentHigherHeatingValue')
|
|
440
|
-
energyDigestibility = get_node_property_value(MODEL, input, 'energyDigestibilityRuminants')
|
|
441
|
-
meanDE = energyContent * energyDigestibility if all([energyContent, energyDigestibility]) else 0
|
|
442
|
-
|
|
443
|
-
debugValues(cycle, model=MODEL, term=term_id,
|
|
444
|
-
energyContent=energyContent,
|
|
445
|
-
energyDigestibility=energyDigestibility,
|
|
446
|
-
meanDE=meanDE)
|
|
447
|
-
|
|
448
|
-
return meanDE
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
def _calculate_NEfeed_m(cycle: dict, input: dict, meanDE: float):
|
|
452
|
-
term_id = input.get('term', {}).get('@id')
|
|
453
|
-
|
|
454
|
-
energyDigestibility = get_node_property_value(MODEL, input, 'energyDigestibilityRuminants', default=0)
|
|
455
|
-
REm = _calculate_REM(energyDigestibility * 100)
|
|
456
|
-
|
|
457
|
-
debugValues(cycle, model=MODEL, term=term_id,
|
|
458
|
-
REm=REm)
|
|
459
|
-
|
|
460
|
-
input_value = list_sum(input.get('value'))
|
|
461
|
-
return meanDE * REm * input_value
|
|
162
|
+
def _calculate_GE(
|
|
163
|
+
cycle: dict, animals: list, REM: float, REG: float, NEwool: float, NEm_feed: float, NEg_feed: float, system: dict
|
|
164
|
+
) -> float:
|
|
165
|
+
values = [get_animal_values(cycle, animal, system) for animal in animals]
|
|
166
|
+
NEm = _sum_values(values, 0)
|
|
167
|
+
NEa = _sum_values(values, 1)
|
|
168
|
+
NEl = _sum_values(values, 2)
|
|
169
|
+
NEwork = _sum_values(values, 3)
|
|
170
|
+
NEp = _sum_values(values, 4)
|
|
171
|
+
NEg = _sum_values(values, 5)
|
|
172
|
+
return (NEm + NEa + NEl + NEwork + NEp - NEm_feed)/REM + (NEg + NEwool - NEg_feed)/REG
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _run_practice(cycle: dict, meanDE: float, meanECHHV: float, system: dict):
|
|
176
|
+
animals = get_animals(cycle)
|
|
177
|
+
REM = calculate_REM(meanDE)
|
|
178
|
+
REG = calculate_REG(meanDE)
|
|
179
|
+
NEwool = calculate_NEwool(cycle)
|
|
180
|
+
NEm_feed, NEg_feed = calculate_NEfeed(cycle)
|
|
181
|
+
GE = (
|
|
182
|
+
_calculate_GE(cycle, animals, REM, REG, NEwool, NEm_feed, NEg_feed, system) / (meanDE/100)
|
|
183
|
+
) if all([REM, REG]) else 0
|
|
462
184
|
|
|
463
|
-
|
|
464
|
-
def _calculate_NEfeed_g(cycle: dict, input: dict, meanDE: float):
|
|
465
|
-
term_id = input.get('term', {}).get('@id')
|
|
466
|
-
|
|
467
|
-
energyDigestibility = get_node_property_value(MODEL, input, 'energyDigestibilityRuminants', default=0)
|
|
468
|
-
REg = _calculate_REG(energyDigestibility * 100)
|
|
469
|
-
|
|
470
|
-
debugValues(cycle, model=MODEL, term=term_id,
|
|
471
|
-
REg=REg)
|
|
472
|
-
|
|
473
|
-
input_value = list_sum(input.get('value'))
|
|
474
|
-
return meanDE * REg * input_value
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
def _calculate_NEfeed(cycle: dict):
|
|
478
|
-
inputs = get_feed_inputs(cycle)
|
|
479
|
-
# calculate meanDE for each input first
|
|
480
|
-
inputs = [(input, _calculate_feed_meanDE(cycle, input)) for input in inputs]
|
|
481
|
-
NEfeed_m = sum([
|
|
482
|
-
_calculate_NEfeed_m(cycle, input, meanDE) for (input, meanDE) in inputs
|
|
483
|
-
]) if len(inputs) > 0 else 0
|
|
484
|
-
NEfeed_g = sum([
|
|
485
|
-
_calculate_NEfeed_g(cycle, input, meanDE) for (input, meanDE) in inputs
|
|
486
|
-
]) if len(inputs) > 0 else 0
|
|
487
|
-
|
|
488
|
-
return (NEfeed_m, NEfeed_g)
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
def _group_logs(values: list): return ';'.join([f"id:{term_id}_value:{value}" for term_id, value in values if term_id])
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
def _sum_values(values): return sum([value for term_id, value in values])
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
def _calculate_GE(cycle: dict, meanDE: float, system: dict):
|
|
498
|
-
animals = [
|
|
499
|
-
a for a in cycle.get('animals', []) if all([
|
|
500
|
-
a.get('value'),
|
|
501
|
-
a.get('referencePeriod') == AnimalReferencePeriod.AVERAGE.value
|
|
502
|
-
])
|
|
503
|
-
]
|
|
504
|
-
|
|
505
|
-
# calculate NEm first and re-use in other places
|
|
506
|
-
animals = [(animal, _calculate_NEm(cycle, animal)) for animal in animals]
|
|
507
|
-
|
|
508
|
-
NEm = sum(non_empty_list([NEm for (animal, NEm) in animals]))
|
|
509
|
-
|
|
510
|
-
NEa = non_empty_list([_calculate_NEa(cycle, animal, system, NEm) for (animal, NEm) in animals])
|
|
511
|
-
NEl = non_empty_list([_calculate_NEl(cycle, animal) for (animal, _NEm) in animals])
|
|
512
|
-
NEwork = non_empty_list([_calculate_NEwork(cycle, animal, NEm) for (animal, NEm) in animals])
|
|
513
|
-
NEp = non_empty_list([_calculate_NEp(cycle, animal, NEm) for (animal, NEm) in animals])
|
|
514
|
-
NEg = non_empty_list([_calculate_NEg(cycle, animal) for (animal, _NEm) in animals])
|
|
515
|
-
|
|
516
|
-
NEwool = _calculate_NEwool(cycle)
|
|
517
|
-
REM = _calculate_REM(meanDE) if meanDE > 0 else None
|
|
518
|
-
REG = _calculate_REG(meanDE) if meanDE > 0 else None
|
|
519
|
-
|
|
520
|
-
NEfeed_m, NEfeed_g = _calculate_NEfeed(cycle)
|
|
521
|
-
|
|
522
|
-
logRequirements(cycle, model=MODEL, term=MODEL_KEY,
|
|
523
|
-
NEm=_group_logs([(animal.get('term', {}).get('@id'), NEm) for (animal, NEm) in animals]),
|
|
524
|
-
NEa=_group_logs(NEa),
|
|
525
|
-
NEl=_group_logs(NEl),
|
|
526
|
-
NEwork=_group_logs(NEwork),
|
|
527
|
-
NEp=_group_logs(NEp),
|
|
528
|
-
NEg=_group_logs(NEg),
|
|
529
|
-
NEwool=NEwool,
|
|
530
|
-
REM=REM,
|
|
531
|
-
REG=REG,
|
|
532
|
-
NEfeed_m=NEfeed_m,
|
|
533
|
-
NEfeed_g=NEfeed_g)
|
|
534
|
-
|
|
535
|
-
return (
|
|
536
|
-
(NEm + _sum_values(NEa) + _sum_values(NEl) + _sum_values(NEwork) + _sum_values(NEp) - NEfeed_m)/REM +
|
|
537
|
-
(_sum_values(NEg) + NEwool - NEfeed_g)/REG
|
|
538
|
-
) / (meanDE/100) if all([REM, REG]) else 0
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
def _calculate_meanECHHV(practices: list):
|
|
542
|
-
values = list(map(lambda p: _pastureGrass_key_property_value(p, 'energyContentHigherHeatingValue'), practices))
|
|
543
|
-
total_weight = sum([weight/100 for _value, weight in values])
|
|
544
|
-
return sum([
|
|
545
|
-
(value * weight/100 if all([value, weight]) else 0) for value, weight in values
|
|
546
|
-
]) / total_weight if total_weight > 0 else 0
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
def _run_practice(cycle: dict, GE: float, meanECHHV: float):
|
|
550
185
|
def run(practice: dict):
|
|
551
186
|
key = practice.get('key', {})
|
|
552
187
|
key_id = key.get('@id')
|
|
553
|
-
input_term_id =
|
|
188
|
+
input_term_id = practice_input_id(practice)
|
|
554
189
|
value = (GE / meanECHHV) * (list_sum(practice.get('value', [0])) / 100)
|
|
555
190
|
|
|
556
|
-
logRequirements(cycle, model=MODEL, term=input_term_id,
|
|
191
|
+
logRequirements(cycle, model=MODEL, term=input_term_id, model_key=MODEL_KEY,
|
|
192
|
+
REM=REM,
|
|
193
|
+
REG=REG,
|
|
194
|
+
NEwool=NEwool,
|
|
195
|
+
NEm_feed=NEm_feed,
|
|
196
|
+
NEg_feed=NEg_feed,
|
|
557
197
|
GE=GE,
|
|
558
|
-
meanECHHV=meanECHHV,
|
|
559
198
|
key_id=key_id)
|
|
560
199
|
|
|
561
|
-
logShouldRun(cycle, MODEL, input_term_id, True)
|
|
200
|
+
logShouldRun(cycle, MODEL, input_term_id, True, model_key=MODEL_KEY)
|
|
562
201
|
|
|
563
202
|
return _input(input_term_id, value)
|
|
564
203
|
|
|
565
204
|
return run
|
|
566
205
|
|
|
567
206
|
|
|
568
|
-
def _should_run_practice(cycle: dict):
|
|
569
|
-
def should_run(practice: dict):
|
|
570
|
-
term_id = practice.get('term', {}).get('@id')
|
|
571
|
-
key_term_type = practice.get('key', {}).get('termType')
|
|
572
|
-
value = practice.get('value', [])
|
|
573
|
-
|
|
574
|
-
logRequirements(cycle, model=MODEL, term=term_id,
|
|
575
|
-
practice_value=list_sum(value),
|
|
576
|
-
practice_key_term_type=key_term_type)
|
|
577
|
-
|
|
578
|
-
should_run = all([len(value) > 0, term_id == MODEL_KEY, key_term_type in KEY_TERM_TYPES])
|
|
579
|
-
logShouldRun(cycle, MODEL, term_id, should_run)
|
|
580
|
-
return should_run
|
|
581
|
-
|
|
582
|
-
return should_run
|
|
583
|
-
|
|
584
|
-
|
|
585
207
|
def _should_run(cycle: dict, practices: dict):
|
|
586
208
|
systems = filter_list_term_type(cycle.get('practices', []), TermTermType.SYSTEM)
|
|
587
209
|
animalFeed_complete = _is_term_type_complete(cycle, 'animalFeed')
|
|
210
|
+
animalPopulation_incomplete = _is_term_type_incomplete(cycle, 'animalPopulation')
|
|
588
211
|
freshForage_incomplete = _is_term_type_incomplete(cycle, 'freshForage')
|
|
589
212
|
all_animals_have_value = all([a.get('value', 0) > 0 for a in cycle.get('animals', [])])
|
|
590
213
|
|
|
591
|
-
meanDE =
|
|
592
|
-
meanECHHV =
|
|
593
|
-
GE = _calculate_GE(cycle, meanDE, systems[0]) if all([meanDE > 0, len(systems) > 0]) else 0
|
|
214
|
+
meanDE = calculate_meanDE(practices)
|
|
215
|
+
meanECHHV = calculate_meanECHHV(practices)
|
|
594
216
|
|
|
595
217
|
should_run = all([
|
|
596
|
-
animalFeed_complete,
|
|
218
|
+
animalFeed_complete,
|
|
219
|
+
animalPopulation_incomplete,
|
|
220
|
+
freshForage_incomplete,
|
|
597
221
|
all_animals_have_value,
|
|
598
|
-
len(systems) > 0,
|
|
599
|
-
|
|
222
|
+
len(systems) > 0,
|
|
223
|
+
len(practices) > 0,
|
|
224
|
+
meanDE > 0,
|
|
225
|
+
meanECHHV > 0
|
|
600
226
|
])
|
|
601
227
|
|
|
602
|
-
for term_id in [MODEL_KEY] + [
|
|
603
|
-
logRequirements(cycle, model=MODEL, term=term_id,
|
|
228
|
+
for term_id in [MODEL_KEY] + [practice_input_id(p) for p in practices]:
|
|
229
|
+
logRequirements(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
|
|
604
230
|
term_type_animalFeed_complete=animalFeed_complete,
|
|
231
|
+
term_type_animalPopulation_incomplete=animalPopulation_incomplete,
|
|
605
232
|
term_type_freshForage_incomplete=freshForage_incomplete,
|
|
606
233
|
all_animals_have_value=all_animals_have_value,
|
|
607
234
|
meanDE=meanDE,
|
|
608
|
-
meanECHHV=meanECHHV
|
|
609
|
-
GE=GE)
|
|
235
|
+
meanECHHV=meanECHHV)
|
|
610
236
|
|
|
611
|
-
logShouldRun(cycle, MODEL, term_id, should_run)
|
|
237
|
+
logShouldRun(cycle, MODEL, term_id, should_run, model_key=MODEL_KEY)
|
|
612
238
|
|
|
613
|
-
return should_run,
|
|
239
|
+
return should_run, meanDE, meanECHHV, systems[0] if systems else None
|
|
614
240
|
|
|
615
241
|
|
|
616
242
|
def run(cycle: dict):
|
|
617
|
-
practices = list(filter(
|
|
618
|
-
should_run,
|
|
619
|
-
return list(map(_run_practice(cycle,
|
|
243
|
+
practices = list(filter(should_run_practice(cycle), cycle.get('practices', [])))
|
|
244
|
+
should_run, meanDE, meanECHHV, system = _should_run(cycle, practices)
|
|
245
|
+
return list(map(_run_practice(cycle, meanDE, meanECHHV, system), practices)) if should_run else []
|