hestia-earth-models 0.64.13__py3-none-any.whl → 0.64.14__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/materialAndSubstrate.py +158 -0
- hestia_earth/models/ipcc2019/ch4ToAirEntericFermentation.py +2 -2
- hestia_earth/models/ipcc2019/ch4ToAirExcreta.py +1 -2
- hestia_earth/models/mocking/__init__.py +1 -1
- hestia_earth/models/mocking/search-results.json +1031 -1031
- hestia_earth/models/preload_requests.py +24 -4
- hestia_earth/models/utils/constant.py +3 -0
- hestia_earth/models/version.py +1 -1
- {hestia_earth_models-0.64.13.dist-info → hestia_earth_models-0.64.14.dist-info}/METADATA +1 -1
- {hestia_earth_models-0.64.13.dist-info → hestia_earth_models-0.64.14.dist-info}/RECORD +14 -12
- tests/models/cycle/test_materialsAndSubstrate.py +49 -0
- {hestia_earth_models-0.64.13.dist-info → hestia_earth_models-0.64.14.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.64.13.dist-info → hestia_earth_models-0.64.14.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.64.13.dist-info → hestia_earth_models-0.64.14.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Material and Substrate
|
|
3
|
+
|
|
4
|
+
This model gap-fills depreciated amount per Cycle from Site Infrastructure node.
|
|
5
|
+
"""
|
|
6
|
+
from typing import Union
|
|
7
|
+
from hestia_earth.schema import TermTermType
|
|
8
|
+
from hestia_earth.utils.lookup import download_lookup
|
|
9
|
+
from hestia_earth.utils.tools import to_precision, flatten, list_sum
|
|
10
|
+
from hestia_earth.utils.model import filter_list_term_type
|
|
11
|
+
|
|
12
|
+
from hestia_earth.models.log import logShouldRun, logRequirements
|
|
13
|
+
from hestia_earth.models.utils.constant import DAYS_IN_YEAR
|
|
14
|
+
from hestia_earth.models.utils.input import _new_input
|
|
15
|
+
from hestia_earth.models.utils.completeness import _is_term_type_incomplete
|
|
16
|
+
from .import MODEL
|
|
17
|
+
|
|
18
|
+
REQUIREMENTS = {
|
|
19
|
+
"Cycle": {
|
|
20
|
+
"completeness.material": "False",
|
|
21
|
+
"cycleDuration": "",
|
|
22
|
+
"site": {
|
|
23
|
+
"@type": "Site",
|
|
24
|
+
"infrastructure": [
|
|
25
|
+
{
|
|
26
|
+
"@type": "Infrastructure",
|
|
27
|
+
"defaultLifespan": "",
|
|
28
|
+
"inputs": [
|
|
29
|
+
{
|
|
30
|
+
"@type": "Input",
|
|
31
|
+
"term.termType": ["material", "substrate"],
|
|
32
|
+
"value": "",
|
|
33
|
+
"lifespan": ""
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
RETURNS = {
|
|
42
|
+
"Input": [{
|
|
43
|
+
"value": "",
|
|
44
|
+
"min": "",
|
|
45
|
+
"max": "",
|
|
46
|
+
"sd": "",
|
|
47
|
+
"statsDefinition": ""
|
|
48
|
+
}]
|
|
49
|
+
}
|
|
50
|
+
LOOKUPS = {
|
|
51
|
+
"material": ""
|
|
52
|
+
}
|
|
53
|
+
MODEL_KEY = 'materialAndSubstrate'
|
|
54
|
+
|
|
55
|
+
_ID_SUFFIX = "DepreciatedAmountPerCycle"
|
|
56
|
+
_OPTIONAL_VALUES = ["min", "max", "sd"]
|
|
57
|
+
_SIGNIFICANT_DIGITS = 5
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _input(term_id: str, value: float, stats: dict) -> dict:
|
|
61
|
+
node = _new_input(term_id + _ID_SUFFIX)
|
|
62
|
+
node['value'] = [value]
|
|
63
|
+
return node | stats
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _get_value(node: dict, field_name: str) -> float:
|
|
67
|
+
value = node.get(field_name)
|
|
68
|
+
return list_sum(value) if isinstance(value, list) else value
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def calculate_value(input_node: dict, field_name: str, cycle_duration: float) -> Union[float, None]:
|
|
72
|
+
lifespan = input_node.get("lifespan")
|
|
73
|
+
value = _get_value(node=input_node, field_name=field_name)
|
|
74
|
+
return (
|
|
75
|
+
to_precision(number=(value / (lifespan * DAYS_IN_YEAR)) * cycle_duration, digits=_SIGNIFICANT_DIGITS)
|
|
76
|
+
if value else None
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _run_input(cycle: dict, input_node: dict) -> dict:
|
|
81
|
+
cycle_duration = cycle.get("cycleDuration")
|
|
82
|
+
|
|
83
|
+
value = calculate_value(
|
|
84
|
+
input_node=input_node,
|
|
85
|
+
field_name="value",
|
|
86
|
+
cycle_duration=cycle_duration
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
optional_gap_filled_values = {
|
|
90
|
+
field_name: [
|
|
91
|
+
calculate_value(input_node=input_node, field_name=field_name, cycle_duration=cycle_duration)
|
|
92
|
+
]
|
|
93
|
+
for field_name in _OPTIONAL_VALUES if field_name in input_node
|
|
94
|
+
}
|
|
95
|
+
if "statsDefinition" in input_node:
|
|
96
|
+
optional_gap_filled_values["statsDefinition"] = input_node["statsDefinition"]
|
|
97
|
+
|
|
98
|
+
return _input(input_node.get('term', {}).get('@id'), value, optional_gap_filled_values)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _has_depreciated_term(term: dict):
|
|
102
|
+
lookup = download_lookup(f"{term.get('termType')}.csv")
|
|
103
|
+
return term.get('@id') + _ID_SUFFIX in list(lookup.termid)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _should_run_input(cycle: dict, input_node: dict) -> bool:
|
|
107
|
+
term = input_node.get('term', {})
|
|
108
|
+
term_id = term.get('@id')
|
|
109
|
+
has_lifespan = input_node.get('lifespan', 0) > 0
|
|
110
|
+
has_valid_value = _get_value(input_node, 'value') > 0
|
|
111
|
+
has_depreciated_term = _has_depreciated_term(term)
|
|
112
|
+
|
|
113
|
+
should_run = all([
|
|
114
|
+
has_depreciated_term,
|
|
115
|
+
has_valid_value,
|
|
116
|
+
has_lifespan
|
|
117
|
+
])
|
|
118
|
+
|
|
119
|
+
logRequirements(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
|
|
120
|
+
has_valid_value=has_valid_value,
|
|
121
|
+
has_lifespan=has_lifespan,
|
|
122
|
+
has_depreciated_term=has_depreciated_term)
|
|
123
|
+
logShouldRun(input_node, MODEL, term_id, should_run, model_key=MODEL_KEY)
|
|
124
|
+
return should_run
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _should_run_infrastructure(cycle: dict, infra_node: dict) -> tuple[bool, list]:
|
|
128
|
+
inputs = filter_list_term_type(infra_node.get('inputs', []), [TermTermType.MATERIAL, TermTermType.SUBSTRATE])
|
|
129
|
+
inputs = [
|
|
130
|
+
i | {
|
|
131
|
+
'lifespan': i.get('lifespan') or infra_node.get('defaultLifespan')
|
|
132
|
+
}
|
|
133
|
+
for i in inputs
|
|
134
|
+
]
|
|
135
|
+
return [i for i in inputs if _should_run_input(cycle, i)]
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _should_run(cycle: dict) -> tuple[bool, list]:
|
|
139
|
+
inputs = flatten([
|
|
140
|
+
_should_run_infrastructure(cycle, i)
|
|
141
|
+
for i in cycle.get('site', {}).get('infrastructure', [])
|
|
142
|
+
])
|
|
143
|
+
has_material_inputs = len(inputs) > 0
|
|
144
|
+
cycle_duration = cycle.get('cycleDuration')
|
|
145
|
+
is_incomplete = _is_term_type_incomplete(cycle, TermTermType.MATERIAL)
|
|
146
|
+
|
|
147
|
+
logRequirements(cycle, model=MODEL, term=None, model_key=MODEL_KEY,
|
|
148
|
+
term_type_material_incomplete=is_incomplete,
|
|
149
|
+
has_material_inputs=has_material_inputs)
|
|
150
|
+
|
|
151
|
+
should_run = all([is_incomplete, has_material_inputs, cycle_duration])
|
|
152
|
+
logShouldRun(cycle, MODEL, None, should_run, model_key=MODEL_KEY)
|
|
153
|
+
return should_run, inputs
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def run(cycle: dict):
|
|
157
|
+
should_run, inputs = _should_run(cycle)
|
|
158
|
+
return [_run_input(cycle, i) for i in inputs] if should_run else []
|
|
@@ -141,10 +141,10 @@ DE_MAPPING = {
|
|
|
141
141
|
def _get_grouped_data_key(keys: list, DE: float, NDF: float, ionophore: bool, milk_yield: float):
|
|
142
142
|
# test conditions one by one and return the key associated for the first one that passes
|
|
143
143
|
return (
|
|
144
|
-
next(
|
|
144
|
+
(next(
|
|
145
145
|
(key for key in keys if key in DE_NDF_MAPPING and DE_NDF_MAPPING[key](DE, NDF)),
|
|
146
146
|
None
|
|
147
|
-
) or next(
|
|
147
|
+
) if all([DE is not None, NDF is not None]) else None) or next(
|
|
148
148
|
(key for key in keys if key in DE_MAPPING and DE_MAPPING[key](DE, ionophore)),
|
|
149
149
|
None
|
|
150
150
|
) if DE else None
|
|
@@ -6,7 +6,7 @@ from hestia_earth.utils.tools import safe_parse_float, list_sum
|
|
|
6
6
|
|
|
7
7
|
from hestia_earth.models.log import debugValues, logRequirements, debugMissingLookup, logShouldRun, log_as_table
|
|
8
8
|
from hestia_earth.models.utils import _filter_list_term_unit
|
|
9
|
-
from hestia_earth.models.utils.constant import Units
|
|
9
|
+
from hestia_earth.models.utils.constant import Units, DAYS_PER_MONTH
|
|
10
10
|
from hestia_earth.models.utils.completeness import _is_term_type_complete
|
|
11
11
|
from hestia_earth.models.utils.productivity import PRODUCTIVITY, get_productivity
|
|
12
12
|
from hestia_earth.models.utils.emission import _new_emission
|
|
@@ -40,7 +40,6 @@ RETURNS = {
|
|
|
40
40
|
}
|
|
41
41
|
TERM_ID = 'ch4ToAirExcreta'
|
|
42
42
|
TIER = EmissionMethodTier.TIER_2.value
|
|
43
|
-
DAYS_PER_MONTH = 365.25/12
|
|
44
43
|
|
|
45
44
|
|
|
46
45
|
class DURATION(Enum):
|