hestia-earth-models 0.70.1__py3-none-any.whl → 0.70.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hestia_earth/models/cml2001Baseline/resourceUseMineralsAndMetalsDuringCycle.py +2 -1
- hestia_earth/models/config/Cycle.json +60 -0
- hestia_earth/models/config/Site.json +8 -0
- hestia_earth/models/hestia/excretaKgMass.py +1 -1
- hestia_earth/models/hestia/management.py +4 -6
- hestia_earth/models/hestia/pToSurfaceWaterAquacultureSystems.py +148 -0
- hestia_earth/models/hestia/soilMeasurement.py +1 -1
- hestia_earth/models/ipcc2019/ch4ToAirFloodedRice.py +8 -6
- hestia_earth/models/ipcc2019/ch4ToAirOrganicSoilCultivation.py +270 -0
- hestia_earth/models/ipcc2019/co2ToAirAboveGroundBiomassStockChange.py +0 -3
- hestia_earth/models/ipcc2019/co2ToAirBelowGroundBiomassStockChange.py +0 -3
- hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +57 -43
- hestia_earth/models/ipcc2019/co2ToAirLimeHydrolysis.py +7 -5
- hestia_earth/models/ipcc2019/co2ToAirOrganicSoilCultivation.py +215 -0
- hestia_earth/models/ipcc2019/co2ToAirSoilOrganicCarbonStockChange.py +0 -3
- hestia_earth/models/ipcc2019/n2OToAirOrganicSoilCultivationDirect.py +161 -0
- hestia_earth/models/ipcc2019/organicSoilCultivation_utils.py +159 -0
- hestia_earth/models/mocking/search-results.json +714 -706
- hestia_earth/models/site/grouped_measurement.py +132 -0
- hestia_earth/models/utils/__init__.py +4 -3
- hestia_earth/models/utils/blank_node.py +38 -9
- hestia_earth/models/utils/constant.py +26 -20
- hestia_earth/models/utils/product.py +39 -1
- hestia_earth/models/utils/property.py +14 -6
- hestia_earth/models/version.py +1 -1
- {hestia_earth_models-0.70.1.dist-info → hestia_earth_models-0.70.2.dist-info}/METADATA +1 -1
- {hestia_earth_models-0.70.1.dist-info → hestia_earth_models-0.70.2.dist-info}/RECORD +42 -31
- tests/models/hestia/test_feedConversionRatio.py +2 -3
- tests/models/hestia/test_pToSurfaceWaterAquacultureSystems.py +56 -0
- tests/models/hestia/test_soilMeasurement.py +11 -19
- tests/models/ipcc2019/test_ch4ToAirEntericFermentation.py +2 -5
- tests/models/ipcc2019/test_ch4ToAirOrganicSoilCultivation.py +61 -0
- tests/models/ipcc2019/test_co2ToAirAboveGroundBiomassStockChange.py +11 -9
- tests/models/ipcc2019/test_co2ToAirBelowGroundBiomassStockChange.py +10 -8
- tests/models/ipcc2019/test_co2ToAirLimeHydrolysis.py +1 -1
- tests/models/ipcc2019/test_co2ToAirOrganicSoilCultivation.py +62 -0
- tests/models/ipcc2019/test_co2ToAirSoilOrganicCarbonStockChange.py +11 -9
- tests/models/ipcc2019/test_n2OToAirOrganicSoilCultivationDirect.py +61 -0
- tests/models/site/test_grouped_measurement.py +20 -0
- {hestia_earth_models-0.70.1.dist-info → hestia_earth_models-0.70.2.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.70.1.dist-info → hestia_earth_models-0.70.2.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.70.1.dist-info → hestia_earth_models-0.70.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,132 @@
|
|
1
|
+
from functools import reduce
|
2
|
+
from hestia_earth.schema import MeasurementMethodClassification
|
3
|
+
from hestia_earth.utils.tools import non_empty_list, flatten, is_number, list_sum
|
4
|
+
|
5
|
+
from hestia_earth.models.log import logRequirements, logShouldRun
|
6
|
+
from hestia_earth.models.utils import _include
|
7
|
+
from hestia_earth.models.utils.measurement import _new_measurement
|
8
|
+
from hestia_earth.models.utils.blank_node import get_lookup_value
|
9
|
+
from . import MODEL
|
10
|
+
|
11
|
+
REQUIREMENTS = {
|
12
|
+
"Site": {
|
13
|
+
"measurements": [
|
14
|
+
{"@type": "Measurement", "depthUpper": "", "depthLower": "", "value": ""}
|
15
|
+
]
|
16
|
+
}
|
17
|
+
}
|
18
|
+
RETURNS = {
|
19
|
+
"Measurement": [{
|
20
|
+
"value": "0",
|
21
|
+
"depthUpper": "",
|
22
|
+
"depthLower": "",
|
23
|
+
"dates": "",
|
24
|
+
"methodClassification": "modelled using other measurements"
|
25
|
+
}]
|
26
|
+
}
|
27
|
+
LOOKUPS = {
|
28
|
+
"measurement": ["sumIs100Group", "sumMax100Group"]
|
29
|
+
}
|
30
|
+
MODEL_KEY = 'grouped_measurement'
|
31
|
+
|
32
|
+
|
33
|
+
def _measurement(term_id: str, measurement: dict):
|
34
|
+
data = _new_measurement(term_id) | _include(measurement, [
|
35
|
+
'depthUpper', 'depthLower', 'startDate', 'endDate', 'dates'
|
36
|
+
])
|
37
|
+
data["value"] = [0]
|
38
|
+
data["methodClassification"] = MeasurementMethodClassification.MODELLED_USING_OTHER_MEASUREMENTS.value
|
39
|
+
return data
|
40
|
+
|
41
|
+
|
42
|
+
def _measurement_term_ids(measurements: list):
|
43
|
+
return list(set([m.get('term', {}).get('@id') for m in measurements]))
|
44
|
+
|
45
|
+
|
46
|
+
def _formatDepth(depth: str):
|
47
|
+
# handle float values
|
48
|
+
return str(int(depth)) if is_number(depth) else ''
|
49
|
+
|
50
|
+
|
51
|
+
def _group_by_depth(measurements: list):
|
52
|
+
def group_by(group: dict, measurement: dict):
|
53
|
+
keys = non_empty_list([
|
54
|
+
_formatDepth(measurement.get('depthUpper')),
|
55
|
+
_formatDepth(measurement.get('depthLower'))
|
56
|
+
])
|
57
|
+
key = '-'.join(keys) if len(keys) > 0 else 'default'
|
58
|
+
group[key] = group.get(key, []) + [measurement]
|
59
|
+
return group
|
60
|
+
|
61
|
+
return reduce(group_by, measurements, {})
|
62
|
+
|
63
|
+
|
64
|
+
def _run_measurements(site: dict, all_term_ids: list, measurements: list):
|
65
|
+
term_ids = _measurement_term_ids(measurements)
|
66
|
+
|
67
|
+
# check the total value is 100%
|
68
|
+
total_value = list_sum([
|
69
|
+
list_sum(m.get('value')) for m in measurements
|
70
|
+
])
|
71
|
+
is_total_100 = 99.5 <= total_value <= 100.5
|
72
|
+
|
73
|
+
should_run = all([is_total_100])
|
74
|
+
|
75
|
+
other_term_ids = [v for v in all_term_ids if v not in term_ids]
|
76
|
+
for term_id in other_term_ids:
|
77
|
+
logRequirements(site, model=MODEL, term=term_id, model_key=MODEL_KEY,
|
78
|
+
total_value=total_value)
|
79
|
+
|
80
|
+
logShouldRun(site, MODEL, term_id, should_run, model_key=MODEL_KEY)
|
81
|
+
|
82
|
+
return [
|
83
|
+
_measurement(term_id=term_id, measurement=measurements[0])
|
84
|
+
for term_id in other_term_ids
|
85
|
+
] if should_run else []
|
86
|
+
|
87
|
+
|
88
|
+
def _run(site: dict, measurements: list):
|
89
|
+
term_ids = _measurement_term_ids(measurements)
|
90
|
+
grouped_measurements = _group_by_depth(measurements)
|
91
|
+
|
92
|
+
return flatten([
|
93
|
+
_run_measurements(site, term_ids, values)
|
94
|
+
for values in grouped_measurements.values()
|
95
|
+
]) if len(grouped_measurements.keys()) > 1 else []
|
96
|
+
|
97
|
+
|
98
|
+
def _group_by_100group(measurements: list):
|
99
|
+
def group_by(group: dict, measurement: dict):
|
100
|
+
term = measurement.get('term', {})
|
101
|
+
sum_group_key = (
|
102
|
+
get_lookup_value(term, 'sumIs100Group', skip_debug=True, model=MODEL) or
|
103
|
+
get_lookup_value(term, 'sumMax100Group', skip_debug=True, model=MODEL)
|
104
|
+
)
|
105
|
+
keys = non_empty_list([
|
106
|
+
sum_group_key,
|
107
|
+
measurement.get('startDate'),
|
108
|
+
measurement.get('endDate'),
|
109
|
+
'-'.join(measurement.get('dates') or []),
|
110
|
+
])
|
111
|
+
key = '-'.join(keys) if len(keys) > 0 else 'default'
|
112
|
+
|
113
|
+
if all([
|
114
|
+
sum_group_key,
|
115
|
+
measurement.get('value', []),
|
116
|
+
measurement.get('depthUpper') is not None,
|
117
|
+
measurement.get('depthLower') is not None
|
118
|
+
]):
|
119
|
+
group[key] = group.get(key, []) + [measurement]
|
120
|
+
|
121
|
+
return group
|
122
|
+
|
123
|
+
return reduce(group_by, measurements, {})
|
124
|
+
|
125
|
+
|
126
|
+
def run(site: dict):
|
127
|
+
grouped_measurements = _group_by_100group(site.get('measurements', []))
|
128
|
+
return flatten([
|
129
|
+
_run(site, values)
|
130
|
+
for values in grouped_measurements.values()
|
131
|
+
if len(values) > 1
|
132
|
+
])
|
@@ -8,7 +8,7 @@ import datetime
|
|
8
8
|
from functools import reduce
|
9
9
|
import operator
|
10
10
|
from pydash.objects import get
|
11
|
-
from typing import
|
11
|
+
from typing import Union, List, Callable
|
12
12
|
from hestia_earth.schema import SchemaType
|
13
13
|
from hestia_earth.utils.api import download_hestia
|
14
14
|
from hestia_earth.utils.tools import flatten, non_empty_list
|
@@ -54,8 +54,9 @@ def _load_calculated_node(node, type: SchemaType, data_state='recalculated'):
|
|
54
54
|
def _unit_str(unit) -> str: return unit if isinstance(unit, str) else unit.value
|
55
55
|
|
56
56
|
|
57
|
-
def _filter_list_term_unit(values: list, unit:
|
58
|
-
units =
|
57
|
+
def _filter_list_term_unit(values: list, unit: Union[str, List[str]]):
|
58
|
+
units = unit if isinstance(unit, list) else[unit]
|
59
|
+
units = list(map(_unit_str, units))
|
59
60
|
return list(filter(lambda i: i.get('term', {}).get('units') in units, values))
|
60
61
|
|
61
62
|
|
@@ -22,7 +22,6 @@ from hestia_earth.utils.tools import (
|
|
22
22
|
list_sum,
|
23
23
|
list_average,
|
24
24
|
safe_parse_date,
|
25
|
-
safe_parse_float,
|
26
25
|
non_empty_list
|
27
26
|
)
|
28
27
|
from hestia_earth.utils.lookup_utils import (
|
@@ -238,16 +237,21 @@ def get_total_value(nodes: list):
|
|
238
237
|
|
239
238
|
def _value_as(term_id: str, convert_to_property=True):
|
240
239
|
def get_value(node: dict):
|
241
|
-
|
240
|
+
factor = get_node_property_value(
|
241
|
+
None, node, term_id, default=0, handle_percents=False
|
242
|
+
) or get_lookup_value(
|
243
|
+
lookup_term=node.get('term', {}),
|
244
|
+
column=term_id
|
245
|
+
) or 0
|
242
246
|
# ignore node value if property is not found
|
243
|
-
factor = safe_parse_float(property.get('value', 0))
|
244
247
|
value = list_sum(node.get('value', []))
|
248
|
+
property = get_node_property(node, term_id, find_default_property=False, download_from_hestia=True)
|
245
249
|
ratio = factor / 100 if property.get('term', {}).get('units', '') == '%' else factor
|
246
250
|
return 0 if ratio == 0 else (value * ratio if convert_to_property else value / ratio)
|
247
251
|
return get_value
|
248
252
|
|
249
253
|
|
250
|
-
def get_total_value_converted(nodes: list, conversion_property, convert_to_property=True):
|
254
|
+
def get_total_value_converted(nodes: list, conversion_property: Union[List[str], str], convert_to_property=True):
|
251
255
|
"""
|
252
256
|
Get the total `value` of a list of Blank Nodes converted using a property of each Blank Node.
|
253
257
|
|
@@ -371,14 +375,39 @@ def get_KG_total(nodes: list) -> list:
|
|
371
375
|
return get_total_value(kg_nodes) + get_total_value_converted(kg_N_nodes, 'nitrogenContent', False)
|
372
376
|
|
373
377
|
|
378
|
+
def get_P_total(nodes: list) -> list:
|
379
|
+
"""
|
380
|
+
Get the total phosphorous content of a list of Blank Node.
|
381
|
+
|
382
|
+
The result contains the values of the following nodes:
|
383
|
+
1. Every blank node specified in `kg P` will be used.
|
384
|
+
1. Every blank node specified in `kg N` will be multiplied by the `phosphateContentAsP` property.
|
385
|
+
2. Every blank node specified in `kg` will be multiplied by the `phosphateContentAsP` property.
|
386
|
+
|
387
|
+
Parameters
|
388
|
+
----------
|
389
|
+
nodes : list
|
390
|
+
A list of Blank Node.
|
391
|
+
|
392
|
+
Returns
|
393
|
+
-------
|
394
|
+
list
|
395
|
+
The phosphorous values as a list of numbers.
|
396
|
+
"""
|
397
|
+
kg_P_nodes = _filter_list_term_unit(nodes, Units.KG_P)
|
398
|
+
kg_N_nodes = _filter_list_term_unit(nodes, Units.KG_N)
|
399
|
+
kg_nodes = _filter_list_term_unit(nodes, Units.KG)
|
400
|
+
return get_total_value(kg_P_nodes) + get_total_value_converted(kg_N_nodes + kg_nodes, 'phosphateContentAsP')
|
401
|
+
|
402
|
+
|
374
403
|
def get_P2O5_total(nodes: list) -> list:
|
375
404
|
"""
|
376
405
|
Get the total phosphate content of a list of Blank Node.
|
377
406
|
|
378
407
|
The result contains the values of the following nodes:
|
379
|
-
1. Every
|
380
|
-
1. Every
|
381
|
-
2. Every
|
408
|
+
1. Every blank node specified in `kg P2O5` will be used.
|
409
|
+
1. Every blank node specified in `kg N` will be multiplied by the `phosphateContentAsP2O5` property.
|
410
|
+
2. Every blank node specified in `kg` will be multiplied by the `phosphateContentAsP2O5` property.
|
382
411
|
|
383
412
|
Parameters
|
384
413
|
----------
|
@@ -390,10 +419,10 @@ def get_P2O5_total(nodes: list) -> list:
|
|
390
419
|
list
|
391
420
|
The phosphate values as a list of numbers.
|
392
421
|
"""
|
393
|
-
|
422
|
+
kg_P2O5_nodes = _filter_list_term_unit(nodes, Units.KG_P2O5)
|
394
423
|
kg_N_nodes = _filter_list_term_unit(nodes, Units.KG_N)
|
395
424
|
kg_nodes = _filter_list_term_unit(nodes, Units.KG)
|
396
|
-
return get_total_value(
|
425
|
+
return get_total_value(kg_P2O5_nodes) + get_total_value_converted(kg_N_nodes + kg_nodes, 'phosphateContentAsP2O5')
|
397
426
|
|
398
427
|
|
399
428
|
def convert_to_nitrogen(node: dict, model: str, blank_nodes: list, **log_args):
|
@@ -19,7 +19,7 @@ class Units(Enum):
|
|
19
19
|
KG_CO2 = 'kg CO2'
|
20
20
|
KG_K = 'kg K'
|
21
21
|
KG_K2O = 'kg K2O'
|
22
|
-
|
22
|
+
KG_CAMGCO32 = 'kg CaMg(CO3)2'
|
23
23
|
KG_N = 'kg N'
|
24
24
|
KG_N2 = 'kg N2'
|
25
25
|
KG_N2O = 'kg N2O'
|
@@ -48,58 +48,62 @@ C = 12.012
|
|
48
48
|
CA = 40.078
|
49
49
|
H = 1.008
|
50
50
|
K = 39.098
|
51
|
+
MG = 24.305
|
51
52
|
N = 14.007
|
52
53
|
_O = 15.999
|
53
54
|
P = 30.974
|
54
55
|
ATOMIC_WEIGHT_CONVERSIONS = {
|
55
56
|
Units.KG_P.value: {
|
56
|
-
Units.KG_P2O5.value: (P*2) / (P*2 + _O*5),
|
57
|
-
Units.KG_PO43.value: P / ((P + _O*4)*3)
|
57
|
+
Units.KG_P2O5.value: (P*2) / (P*2 + _O*5),
|
58
|
+
Units.KG_PO43.value: P / ((P + _O*4)*3)
|
58
59
|
},
|
59
60
|
Units.KG_PO43.value: {
|
60
|
-
Units.KG_P2O5.value: ((P + _O*4)*3) / (P*2 + _O*5)
|
61
|
+
Units.KG_P2O5.value: ((P + _O*4)*3) / (P*2 + _O*5)
|
62
|
+
},
|
63
|
+
Units.KG_P2O5.value: {
|
64
|
+
Units.KG_P.value: (P*2 + _O*5) / (P*2)
|
61
65
|
},
|
62
66
|
Units.KG_K.value: {
|
63
|
-
Units.KG_K2O.value: (K*2) / (K*2 + _O)
|
67
|
+
Units.KG_K2O.value: (K*2) / (K*2 + _O)
|
64
68
|
},
|
65
69
|
Units.KG_CA.value: {
|
66
|
-
Units.KG_CAO.value: CA / (CA + _O)
|
70
|
+
Units.KG_CAO.value: CA / (CA + _O)
|
67
71
|
},
|
68
72
|
Units.KG_CAO.value: {
|
69
|
-
Units.KG_CACO3.value: (CA + _O) / (CA + C + _O*3)
|
73
|
+
Units.KG_CACO3.value: (CA + _O) / (CA + C + _O*3)
|
70
74
|
},
|
71
75
|
Units.KG_CACO3.value: {
|
72
|
-
Units.KG_CO2.value:
|
76
|
+
Units.KG_CO2.value: (CA + C + _O*3) / C
|
73
77
|
},
|
74
|
-
Units.
|
75
|
-
Units.KG_CO2.value:
|
78
|
+
Units.KG_CAMGCO32.value: {
|
79
|
+
Units.KG_CO2.value: (CA + MG + (C + _O*3)*2) / (C*2)
|
76
80
|
},
|
77
81
|
Units.KG_CH4.value: {
|
78
|
-
Units.TO_C.value: (C + H*4) / C
|
82
|
+
Units.TO_C.value: (C + H*4) / C
|
79
83
|
},
|
80
84
|
Units.KG_CO2.value: {
|
81
|
-
Units.TO_C.value: (C + _O*2) / C
|
85
|
+
Units.TO_C.value: (C + _O*2) / C
|
82
86
|
},
|
83
87
|
Units.KG_NOX.value: {
|
84
|
-
Units.TO_N.value: (N + _O) / N
|
88
|
+
Units.TO_N.value: (N + _O) / N
|
85
89
|
},
|
86
90
|
Units.KG_N2.value: {
|
87
91
|
Units.TO_N.value: 1
|
88
92
|
},
|
89
93
|
Units.KG_N2O.value: {
|
90
|
-
Units.TO_N.value: (N*2 + _O) / (N*2)
|
94
|
+
Units.TO_N.value: (N*2 + _O) / (N*2)
|
91
95
|
},
|
92
96
|
Units.KG_NO2.value: {
|
93
|
-
Units.TO_N.value: (N + _O*2) / N
|
97
|
+
Units.TO_N.value: (N + _O*2) / N
|
94
98
|
},
|
95
99
|
Units.KG_NO3.value: {
|
96
|
-
Units.TO_N.value: (N + _O*3) / N
|
100
|
+
Units.TO_N.value: (N + _O*3) / N
|
97
101
|
},
|
98
102
|
Units.KG_NH3.value: {
|
99
|
-
Units.TO_N.value: (N + H*3) / N
|
103
|
+
Units.TO_N.value: (N + H*3) / N
|
100
104
|
},
|
101
105
|
Units.KG_NH4.value: {
|
102
|
-
Units.TO_N.value: (N + H*4) / N
|
106
|
+
Units.TO_N.value: (N + H*4) / N
|
103
107
|
},
|
104
108
|
Units.KW_H.value: {
|
105
109
|
Units.MJ.value: 3.6
|
@@ -113,8 +117,10 @@ def get_atomic_conversion(src_unit: Units, dest_unit: Units, default_value=1):
|
|
113
117
|
return ATOMIC_WEIGHT_CONVERSIONS.get(src_key, {}).get(dest_key, default_value)
|
114
118
|
|
115
119
|
|
116
|
-
def convert_to_unit(node: dict, dest_unit: Units):
|
117
|
-
|
120
|
+
def convert_to_unit(node: dict, dest_unit: Units, default_value=None):
|
121
|
+
value = list_sum(node.get('value', []), default=None)
|
122
|
+
conversion = get_atomic_conversion(node.get('term', {}).get('units'), dest_unit, default_value=None)
|
123
|
+
return value / conversion if all([value is not None, conversion is not None]) else default_value
|
118
124
|
|
119
125
|
|
120
126
|
def convert_to_N(node: dict):
|
@@ -166,6 +166,12 @@ PRODUCT_UNITS_CONVERSIONS = {
|
|
166
166
|
],
|
167
167
|
Units.KG_VS.value: [
|
168
168
|
('volatileSolidsContent', True)
|
169
|
+
],
|
170
|
+
Units.KG_P.value: [
|
171
|
+
('phosphorusContentAsP', True)
|
172
|
+
],
|
173
|
+
Units.KG_P2O5.value: [
|
174
|
+
('phosphateContentAsP2O5', True)
|
169
175
|
]
|
170
176
|
},
|
171
177
|
Units.KG_N.value: {
|
@@ -175,6 +181,14 @@ PRODUCT_UNITS_CONVERSIONS = {
|
|
175
181
|
Units.KG_VS.value: [
|
176
182
|
('nitrogenContent', False),
|
177
183
|
('volatileSolidsContent', True)
|
184
|
+
],
|
185
|
+
Units.KG_P.value: [
|
186
|
+
('nitrogenContent', False),
|
187
|
+
('phosphorusContentAsP', True)
|
188
|
+
],
|
189
|
+
Units.KG_P2O5.value: [
|
190
|
+
('nitrogenContent', False),
|
191
|
+
('phosphateContentAsP2O5', True)
|
178
192
|
]
|
179
193
|
},
|
180
194
|
Units.KG_VS.value: {
|
@@ -215,6 +229,12 @@ PRODUCT_UNITS_CONVERSIONS = {
|
|
215
229
|
],
|
216
230
|
True
|
217
231
|
)
|
232
|
+
],
|
233
|
+
Units.KG_P.value: [
|
234
|
+
('phosphorusContentAsP', True)
|
235
|
+
],
|
236
|
+
Units.KG_P2O5.value: [
|
237
|
+
('phosphateContentAsP2O5', True)
|
218
238
|
]
|
219
239
|
},
|
220
240
|
Units.KG_COLD_CARCASS_WEIGHT.value: {
|
@@ -225,6 +245,12 @@ PRODUCT_UNITS_CONVERSIONS = {
|
|
225
245
|
Units.KG_COLD_CARCASS_WEIGHT.value: [],
|
226
246
|
Units.KG_READY_TO_COOK_WEIGHT.value: [
|
227
247
|
('processingConversionColdCarcassWeightToReadyToCookWeight', True)
|
248
|
+
],
|
249
|
+
Units.KG_P.value: [
|
250
|
+
('phosphorusContentAsP', True)
|
251
|
+
],
|
252
|
+
Units.KG_P2O5.value: [
|
253
|
+
('phosphateContentAsP2O5', True)
|
228
254
|
]
|
229
255
|
},
|
230
256
|
Units.KG_COLD_DRESSED_CARCASS_WEIGHT.value: {
|
@@ -237,6 +263,12 @@ PRODUCT_UNITS_CONVERSIONS = {
|
|
237
263
|
Units.KG_COLD_CARCASS_WEIGHT.value: [],
|
238
264
|
Units.KG_READY_TO_COOK_WEIGHT.value: [
|
239
265
|
('processingConversionColdDressedCarcassWeightToReadyToCookWeight', True)
|
266
|
+
],
|
267
|
+
Units.KG_P.value: [
|
268
|
+
('phosphorusContentAsP', True)
|
269
|
+
],
|
270
|
+
Units.KG_P2O5.value: [
|
271
|
+
('phosphateContentAsP2O5', True)
|
240
272
|
]
|
241
273
|
},
|
242
274
|
Units.KG_READY_TO_COOK_WEIGHT.value: {
|
@@ -262,7 +294,13 @@ PRODUCT_UNITS_CONVERSIONS = {
|
|
262
294
|
Units.KG_COLD_DRESSED_CARCASS_WEIGHT.value: [
|
263
295
|
('processingConversionColdDressedCarcassWeightToReadyToCookWeight', False)
|
264
296
|
],
|
265
|
-
Units.KG_READY_TO_COOK_WEIGHT.value: []
|
297
|
+
Units.KG_READY_TO_COOK_WEIGHT.value: [],
|
298
|
+
Units.KG_P.value: [
|
299
|
+
('phosphorusContentAsP', True)
|
300
|
+
],
|
301
|
+
Units.KG_P2O5.value: [
|
302
|
+
('phosphateContentAsP2O5', True)
|
303
|
+
]
|
266
304
|
},
|
267
305
|
Units.HEAD.value: {
|
268
306
|
Units.KG_LIVEWEIGHT.value: [
|
@@ -50,7 +50,12 @@ def find_term_property(term, property: str, default=None) -> dict:
|
|
50
50
|
return find_term_match(props, property, default)
|
51
51
|
|
52
52
|
|
53
|
-
def get_node_property(
|
53
|
+
def get_node_property(
|
54
|
+
node: dict,
|
55
|
+
property: str,
|
56
|
+
find_default_property: bool = True,
|
57
|
+
download_from_hestia: bool = False
|
58
|
+
) -> dict:
|
54
59
|
"""
|
55
60
|
Get the property by `@id` linked to the Blank Node in the glossary.
|
56
61
|
|
@@ -66,6 +71,8 @@ def get_node_property(node: dict, property: str, find_default_property: bool = T
|
|
66
71
|
The `term.@id` of the property. Example: `nitrogenContent`.
|
67
72
|
find_default_property : bool
|
68
73
|
Default to fetching the property from the `defaultProperties` of the `Term`.
|
74
|
+
download_from_hestia : bool
|
75
|
+
Default to downloading the Term from HESTIA.
|
69
76
|
|
70
77
|
Returns
|
71
78
|
-------
|
@@ -76,7 +83,9 @@ def get_node_property(node: dict, property: str, find_default_property: bool = T
|
|
76
83
|
return find_term_property(node.get('term', {}), property, {}) if all([
|
77
84
|
find_default_property,
|
78
85
|
prop is None
|
79
|
-
]) else (
|
86
|
+
]) else (
|
87
|
+
prop or ({'term': download_term(property, TermTermType.PROPERTY)} if download_from_hestia else {})
|
88
|
+
)
|
80
89
|
|
81
90
|
|
82
91
|
def node_has_no_property(term_id: str):
|
@@ -91,9 +100,8 @@ def node_property_lookup_value(model: str, node_term: dict, prop_id: str, defaul
|
|
91
100
|
# as the lookup table might not exist, we are making sure we return `0` in thise case
|
92
101
|
try:
|
93
102
|
lookup_name = f"{node_term.get('termType')}-property.csv"
|
94
|
-
lookup = download_lookup(lookup_name)
|
95
103
|
term_id = node_term.get('@id')
|
96
|
-
lookup_value = get_table_value(
|
104
|
+
lookup_value = get_table_value(download_lookup(lookup_name), 'termid', term_id, column_name(prop_id))
|
97
105
|
value = extract_grouped_data(lookup_value, 'Avg') if (
|
98
106
|
isinstance(lookup_value, str) and 'Avg' in lookup_value
|
99
107
|
) else lookup_value
|
@@ -104,8 +112,8 @@ def node_property_lookup_value(model: str, node_term: dict, prop_id: str, defaul
|
|
104
112
|
|
105
113
|
|
106
114
|
def get_node_property_value(model: str, node: dict, prop_id: str, default=None, handle_percents=True, **log_args):
|
107
|
-
prop = get_node_property(node, prop_id)
|
108
|
-
term = (prop or {}).get('term')
|
115
|
+
prop = get_node_property(node, prop_id, download_from_hestia=True)
|
116
|
+
term = (prop or {}).get('term')
|
109
117
|
units = (term or {}).get('units')
|
110
118
|
value = prop.get('value') if prop else node_property_lookup_value(model, node.get('term', {}), prop_id, **log_args)
|
111
119
|
return default if value is None else (value / 100 if units == '%' and handle_percents else value)
|
hestia_earth/models/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
VERSION = '0.70.
|
1
|
+
VERSION = '0.70.2'
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: hestia-earth-models
|
3
|
-
Version: 0.70.
|
3
|
+
Version: 0.70.2
|
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
|