hestia-earth-models 0.74.13__py3-none-any.whl → 0.74.15__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/config/ImpactAssessment.json +4 -2
- hestia_earth/models/config/Site.json +11 -3
- hestia_earth/models/ecoalimV9/cycle.py +20 -5
- hestia_earth/models/ecoalimV9/utils.py +52 -2
- hestia_earth/models/emepEea2019/fuelCombustion_utils.py +21 -21
- hestia_earth/models/environmentalFootprintV3_1/environmentalFootprintSingleOverallScore.py +27 -18
- hestia_earth/models/hestia/landCover.py +27 -41
- hestia_earth/models/hestia/landCover_utils.py +40 -45
- hestia_earth/models/hestia/landOccupationDuringCycle.py +9 -27
- hestia_earth/models/hestia/soilClassification.py +314 -0
- hestia_earth/models/ipcc2019/aboveGroundBiomass.py +5 -15
- hestia_earth/models/ipcc2019/belowGroundBiomass.py +5 -15
- hestia_earth/models/ipcc2019/biocharOrganicCarbonPerHa.py +5 -39
- hestia_earth/models/ipcc2019/ch4ToAirEntericFermentation.py +2 -1
- hestia_earth/models/ipcc2019/ch4ToAirOrganicSoilCultivation.py +5 -5
- hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +6 -21
- hestia_earth/models/ipcc2019/co2ToAirOrganicSoilCultivation.py +4 -5
- hestia_earth/models/ipcc2019/n2OToAirOrganicSoilCultivationDirect.py +5 -5
- hestia_earth/models/ipcc2019/nonCo2EmissionsToAirNaturalVegetationBurning.py +17 -46
- hestia_earth/models/ipcc2019/organicCarbonPerHa.py +10 -10
- hestia_earth/models/ipcc2019/organicCarbonPerHa_utils.py +4 -19
- hestia_earth/models/ipcc2019/organicSoilCultivation_utils.py +0 -9
- hestia_earth/models/log.py +71 -1
- hestia_earth/models/mocking/search-results.json +1 -1
- hestia_earth/models/utils/__init__.py +2 -2
- hestia_earth/models/utils/aggregated.py +3 -3
- hestia_earth/models/utils/blank_node.py +12 -4
- hestia_earth/models/utils/lookup.py +9 -10
- hestia_earth/models/version.py +1 -1
- {hestia_earth_models-0.74.13.dist-info → hestia_earth_models-0.74.15.dist-info}/METADATA +2 -2
- {hestia_earth_models-0.74.13.dist-info → hestia_earth_models-0.74.15.dist-info}/RECORD +39 -36
- tests/models/ecoalimV9/test_cycle.py +3 -2
- tests/models/hestia/test_landCover.py +1 -1
- tests/models/hestia/test_soilClassification.py +72 -0
- tests/models/ipcc2019/test_organicCarbonPerHa_utils.py +4 -48
- tests/models/test_log.py +128 -0
- {hestia_earth_models-0.74.13.dist-info → hestia_earth_models-0.74.15.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.74.13.dist-info → hestia_earth_models-0.74.15.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.74.13.dist-info → hestia_earth_models-0.74.15.dist-info}/top_level.txt +0 -0
|
@@ -10,7 +10,10 @@ from hestia_earth.utils.tools import safe_parse_float
|
|
|
10
10
|
from hestia_earth.utils.stats import gen_seed, repeat_single, truncated_normal_1d
|
|
11
11
|
from hestia_earth.utils.descriptive_stats import calc_descriptive_stats
|
|
12
12
|
|
|
13
|
-
from hestia_earth.models.log import
|
|
13
|
+
from hestia_earth.models.log import (
|
|
14
|
+
debugMissingLookup, format_bool, format_decimal_percentage, format_float, format_nd_array, format_str, log_as_table,
|
|
15
|
+
logRequirements, logShouldRun
|
|
16
|
+
)
|
|
14
17
|
from hestia_earth.models.utils.blank_node import group_nodes_by_year
|
|
15
18
|
from hestia_earth.models.utils.ecoClimateZone import EcoClimateZone, get_eco_climate_zone_value
|
|
16
19
|
from hestia_earth.models.utils.emission import _new_emission
|
|
@@ -670,60 +673,28 @@ def _compile_inventory(
|
|
|
670
673
|
return should_run, inventory, logs
|
|
671
674
|
|
|
672
675
|
|
|
673
|
-
def _format_bool(value: Optional[bool]) -> str:
|
|
674
|
-
"""Format a bool for logging in a table."""
|
|
675
|
-
return str(bool(value))
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
def _format_number(value: Optional[float], unit: Optional[str] = None) -> str:
|
|
679
|
-
"""Format a float for logging in a table."""
|
|
680
|
-
return f"{value:.1f}{f' {unit}' if unit else ''}" if isinstance(value, (float, int)) else "None"
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
def _format_nd_array(value: Optional[npt.NDArray], unit: Optional[str] = None) -> str:
|
|
684
|
-
"""Format a numpy array for logging in a table."""
|
|
685
|
-
return (
|
|
686
|
-
f"{_format_number(value.mean())} ± {_format_number(value.std())}" + f"{f' {unit}' if unit else ''}"
|
|
687
|
-
if isinstance(value, np.ndarray) else "None"
|
|
688
|
-
)
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
def _format_decimal_percentage(value: Optional[float], unit: Optional[str] = "pct") -> str:
|
|
692
|
-
"""Format a decimal percentage (0-1) as a percentage (0-100%) for logging in a table."""
|
|
693
|
-
return _format_number(value * 100, unit) if isinstance(value, (float, int)) else "None"
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
_INVALID_CHARS = {"_", ":", ",", "="}
|
|
697
|
-
_REPLACEMENT_CHAR = "-"
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
def _format_str(value: str, *_) -> str:
|
|
701
|
-
"""Format a string for logging in a table. Remove all characters used to render the table on the front end."""
|
|
702
|
-
return reduce(lambda x, char: x.replace(char, _REPLACEMENT_CHAR), _INVALID_CHARS, str(value))
|
|
703
|
-
|
|
704
|
-
|
|
705
676
|
def _format_column_header(*keys: tuple[Union[Enum, str], ...]) -> str:
|
|
706
677
|
"""Format a variable number of enums and strings for logging as a table column header."""
|
|
707
|
-
return " ".join(
|
|
678
|
+
return " ".join(format_str(k.value if isinstance(k, Enum) else format_str(k)) for k in keys)
|
|
708
679
|
|
|
709
680
|
|
|
710
681
|
def _format_eco_climate_zone(value: EcoClimateZone) -> str:
|
|
711
682
|
"""Format an eco-climate zone for logging."""
|
|
712
683
|
return (
|
|
713
|
-
|
|
684
|
+
format_str(str(value.name).lower().replace("_", " ").capitalize()) if isinstance(value, EcoClimateZone)
|
|
714
685
|
else "None"
|
|
715
686
|
)
|
|
716
687
|
|
|
717
688
|
|
|
718
689
|
_LOGS_FORMAT_DATA: dict[str, Callable] = {
|
|
719
|
-
"has_valid_site_type":
|
|
690
|
+
"has_valid_site_type": format_bool,
|
|
720
691
|
"eco_climate_zone": _format_eco_climate_zone,
|
|
721
|
-
"has_valid_eco_climate_zone":
|
|
722
|
-
"has_land_cover_nodes":
|
|
723
|
-
"should_compile_inventory":
|
|
724
|
-
"percent_burned": lambda x:
|
|
692
|
+
"has_valid_eco_climate_zone": format_bool,
|
|
693
|
+
"has_land_cover_nodes": format_bool,
|
|
694
|
+
"should_compile_inventory": format_bool,
|
|
695
|
+
"percent_burned": lambda x: format_float(x, "pct"),
|
|
725
696
|
}
|
|
726
|
-
_DEFAULT_FORMAT_FUNC =
|
|
697
|
+
_DEFAULT_FORMAT_FUNC = format_str
|
|
727
698
|
|
|
728
699
|
|
|
729
700
|
def _format_logs(logs: dict) -> dict[str, str]:
|
|
@@ -735,23 +706,23 @@ def _format_logs(logs: dict) -> dict[str, str]:
|
|
|
735
706
|
|
|
736
707
|
_INVENTORY_FORMAT_DATA: dict[_InventoryKey, dict[Literal["filter_by", "format_func"], Any]] = {
|
|
737
708
|
"fuel_burnt_per_category": {
|
|
738
|
-
"format_func": lambda x:
|
|
709
|
+
"format_func": lambda x: format_nd_array(x, "kg")
|
|
739
710
|
},
|
|
740
711
|
"annual_emissions": {
|
|
741
712
|
"filter_by": ("term_id", ),
|
|
742
|
-
"format_func": lambda x:
|
|
713
|
+
"format_func": lambda x: format_nd_array(x, "kg")
|
|
743
714
|
},
|
|
744
715
|
"amortised_emissions": {
|
|
745
716
|
"filter_by": ("term_id", ),
|
|
746
|
-
"format_func": lambda x:
|
|
717
|
+
"format_func": lambda x: format_nd_array(x, "kg")
|
|
747
718
|
},
|
|
748
719
|
"share_of_emissions": {
|
|
749
720
|
"filter_by": ("cycle_id", ),
|
|
750
|
-
"format_func":
|
|
721
|
+
"format_func": format_decimal_percentage
|
|
751
722
|
},
|
|
752
723
|
"allocated_emissions": {
|
|
753
724
|
"filter_by": ("term_id", "cycle_id"),
|
|
754
|
-
"format_func": lambda x:
|
|
725
|
+
"format_func": lambda x: format_nd_array(x, "kg")
|
|
755
726
|
}
|
|
756
727
|
}
|
|
757
728
|
"""
|
|
@@ -2,9 +2,9 @@ from functools import reduce
|
|
|
2
2
|
from pydash.objects import merge
|
|
3
3
|
from types import ModuleType
|
|
4
4
|
|
|
5
|
-
from hestia_earth.models.log import log_as_table, logRequirements, logShouldRun
|
|
5
|
+
from hestia_earth.models.log import format_bool, format_enum, format_float, log_as_table, logRequirements, logShouldRun
|
|
6
6
|
|
|
7
|
-
from .organicCarbonPerHa_utils import
|
|
7
|
+
from .organicCarbonPerHa_utils import format_bool_list, format_float_list
|
|
8
8
|
from . import organicCarbonPerHa_tier_1 as tier_1
|
|
9
9
|
from . import organicCarbonPerHa_tier_2 as tier_2
|
|
10
10
|
from . import MODEL # noqa
|
|
@@ -204,20 +204,20 @@ def _get_unique_inventory_keys(inventory: dict) -> list:
|
|
|
204
204
|
|
|
205
205
|
_INVENTORY_KEY_TO_FORMAT_FUNC = {
|
|
206
206
|
tier_2._InventoryKey.SHOULD_RUN: format_bool,
|
|
207
|
-
tier_2._InventoryKey.TEMP_MONTHLY:
|
|
208
|
-
tier_2._InventoryKey.PRECIP_MONTHLY:
|
|
209
|
-
tier_2._InventoryKey.PET_MONTHLY:
|
|
207
|
+
tier_2._InventoryKey.TEMP_MONTHLY: format_float_list,
|
|
208
|
+
tier_2._InventoryKey.PRECIP_MONTHLY: format_float_list,
|
|
209
|
+
tier_2._InventoryKey.PET_MONTHLY: format_float_list,
|
|
210
210
|
tier_2._InventoryKey.IRRIGATED_MONTHLY: format_bool_list,
|
|
211
|
-
tier_2._InventoryKey.SAND_CONTENT:
|
|
212
|
-
tier_2._InventoryKey.CARBON_INPUT:
|
|
213
|
-
tier_2._InventoryKey.N_CONTENT:
|
|
214
|
-
tier_2._InventoryKey.LIGNIN_CONTENT:
|
|
211
|
+
tier_2._InventoryKey.SAND_CONTENT: format_float,
|
|
212
|
+
tier_2._InventoryKey.CARBON_INPUT: format_float,
|
|
213
|
+
tier_2._InventoryKey.N_CONTENT: format_float,
|
|
214
|
+
tier_2._InventoryKey.LIGNIN_CONTENT: format_float,
|
|
215
215
|
tier_2._InventoryKey.TILLAGE_CATEGORY: format_enum,
|
|
216
216
|
tier_2._InventoryKey.IS_PADDY_RICE: format_bool,
|
|
217
217
|
tier_1._InventoryKey.SHOULD_RUN: format_bool,
|
|
218
218
|
tier_1._InventoryKey.LU_CATEGORY: format_enum,
|
|
219
219
|
tier_1._InventoryKey.MG_CATEGORY: format_enum,
|
|
220
|
-
tier_1._InventoryKey.CI_CATEGORY: format_enum
|
|
220
|
+
tier_1._InventoryKey.CI_CATEGORY: format_enum
|
|
221
221
|
}
|
|
222
222
|
"""
|
|
223
223
|
Map inventory keys to format functions. The columns in inventory logged as a table will also be sorted in the order of
|
|
@@ -8,7 +8,7 @@ from hestia_earth.utils.stats import calc_z_critical
|
|
|
8
8
|
from hestia_earth.utils.stats import (
|
|
9
9
|
repeat_single, truncated_normal_1d
|
|
10
10
|
)
|
|
11
|
-
from hestia_earth.models.log import log_as_table
|
|
11
|
+
from hestia_earth.models.log import format_bool, format_enum, format_float, log_as_table
|
|
12
12
|
from hestia_earth.models.utils.blank_node import cumulative_nodes_term_match, node_term_match
|
|
13
13
|
from hestia_earth.models.utils.term import get_cover_crop_property_terms, get_irrigated_terms
|
|
14
14
|
|
|
@@ -268,21 +268,6 @@ def sample_constant(*, iterations: int, value: float, **_) -> NDArray:
|
|
|
268
268
|
return repeat_single(shape=(1, iterations), value=value)
|
|
269
269
|
|
|
270
270
|
|
|
271
|
-
def format_bool(value: Optional[bool]) -> str:
|
|
272
|
-
"""Format a bool for logging in a table."""
|
|
273
|
-
return str(bool(value))
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
def format_number(value: Optional[float]) -> str:
|
|
277
|
-
"""Format a float for logging in a table."""
|
|
278
|
-
return f"{value:.1f}" if isinstance(value, (float, int)) else "None"
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
def format_enum(value: Optional[Enum]) -> str:
|
|
282
|
-
"""Format an enum for logging in a table."""
|
|
283
|
-
return value.value if isinstance(value, Enum) else "None"
|
|
284
|
-
|
|
285
|
-
|
|
286
271
|
def format_bool_list(values: Optional[list[bool]]) -> str:
|
|
287
272
|
"""Format a list of bools for logging in a table."""
|
|
288
273
|
return (
|
|
@@ -291,10 +276,10 @@ def format_bool_list(values: Optional[list[bool]]) -> str:
|
|
|
291
276
|
)
|
|
292
277
|
|
|
293
278
|
|
|
294
|
-
def
|
|
279
|
+
def format_float_list(values: Optional[list[float]]) -> str:
|
|
295
280
|
"""Format a list of floats for logging in a table."""
|
|
296
281
|
return (
|
|
297
|
-
" ".join(
|
|
282
|
+
" ".join(format_float(value, ndigits=1) for value in values) or "None"if isinstance(values, list)
|
|
298
283
|
else "None"
|
|
299
284
|
)
|
|
300
285
|
|
|
@@ -303,7 +288,7 @@ def format_soil_inventory(inventory: list[SoilData]) -> str:
|
|
|
303
288
|
return log_as_table(
|
|
304
289
|
{
|
|
305
290
|
"term-id": data.term_id,
|
|
306
|
-
"value":
|
|
291
|
+
"value": format_float(data.value),
|
|
307
292
|
"category": format_enum(data.category)
|
|
308
293
|
} for data in inventory
|
|
309
294
|
) if inventory else "None"
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
2
|
from typing import Literal
|
|
3
|
-
import numpy as np
|
|
4
3
|
|
|
5
4
|
from hestia_earth.schema import SiteSiteType
|
|
6
5
|
from hestia_earth.utils.model import find_primary_product
|
|
@@ -157,11 +156,3 @@ def valid_eco_climate_zone(
|
|
|
157
156
|
Validate that the model should run for a specific eco-climate zone.
|
|
158
157
|
"""
|
|
159
158
|
return isinstance(eco_climate_zone, EcoClimateZone) and eco_climate_zone not in _EXCLUDED_ECO_CLIMATE_ZONES
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
def format_number(value) -> str:
|
|
163
|
-
return f"{value:.3g}" if isinstance(value, (float, int)) else "None"
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
def format_nd_array(value) -> str:
|
|
167
|
-
return f"{np.mean(value):.3g} ± {np.std(value):.3g}" if isinstance(value, np.ndarray) else "None"
|
hestia_earth/models/log.py
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from functools import reduce
|
|
1
3
|
import os
|
|
2
4
|
import sys
|
|
3
5
|
import logging
|
|
4
|
-
from typing import
|
|
6
|
+
from typing import List, Optional, Union
|
|
7
|
+
from numpy.typing import NDArray
|
|
8
|
+
from numpy import ndarray
|
|
5
9
|
|
|
6
10
|
LOG_LEVEL = os.getenv('LOG_LEVEL', 'INFO')
|
|
7
11
|
_EXTENDED_LOGS = os.getenv('LOG_EXTENDED', 'true') == 'true'
|
|
@@ -108,3 +112,69 @@ def log_blank_nodes_id(blank_nodes: List[dict]):
|
|
|
108
112
|
List of blank nodes, like Product, Input, Measurement, etc.
|
|
109
113
|
"""
|
|
110
114
|
return ';'.join([p.get('term', {}).get('@id') for p in blank_nodes if p.get('term', {}).get('@id')]) or 'None'
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
_INVALID_CHARS = {"_", ":", ",", "="}
|
|
118
|
+
_REPLACEMENT_CHAR = "-"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def format_str(value: Optional[str], default: str = "None") -> str:
|
|
122
|
+
"""Format a string for logging in a table. Remove all characters used to render the table on the front end."""
|
|
123
|
+
return (
|
|
124
|
+
reduce(lambda x, char: x.replace(char, _REPLACEMENT_CHAR), _INVALID_CHARS, str(value))
|
|
125
|
+
if value else default
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def format_bool(value: Optional[bool], default: str = "None") -> str:
|
|
130
|
+
return str(value) if isinstance(value, bool) else default
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def format_float(value: Union[int, float, None], unit: str = "", default: str = "None", ndigits: int = 3) -> str:
|
|
134
|
+
return " ".join(
|
|
135
|
+
string for string in [f"{round(value, ndigits)}", format_str(unit, "")] if string
|
|
136
|
+
) if isinstance(value, (float, int)) else default
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def format_int(value: Union[int, float, None], unit: str = "", default: str = "None") -> str:
|
|
140
|
+
return format_float(value, unit=unit, default=default, ndigits=None)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _format_nd_array(value: Optional[NDArray], unit: str = "", default: str = "None", ndigits: int = 3) -> str:
|
|
144
|
+
return " ".join(
|
|
145
|
+
string for string in [
|
|
146
|
+
f"{format_float(value.mean(), ndigits=ndigits)} ± {format_float(value.std(), ndigits=ndigits)}",
|
|
147
|
+
format_str(unit, "")
|
|
148
|
+
] if string
|
|
149
|
+
) if isinstance(value, ndarray) else default
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
TYPE_TO_FORMAT_FUNC = {
|
|
153
|
+
ndarray: _format_nd_array,
|
|
154
|
+
(float, int): format_float
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def format_nd_array(value: Optional[NDArray], unit: str = "", default: str = "None", ndigits: int = 3) -> str:
|
|
159
|
+
"""
|
|
160
|
+
Format a numpy array for logging in a table.
|
|
161
|
+
|
|
162
|
+
Values that are floats and ints are logged using `format_float`.
|
|
163
|
+
"""
|
|
164
|
+
format_func = next(
|
|
165
|
+
(func for type_, func in TYPE_TO_FORMAT_FUNC.items() if isinstance(value, type_)),
|
|
166
|
+
None
|
|
167
|
+
)
|
|
168
|
+
return format_func(value, unit=unit, default=default, ndigits=ndigits) if format_func else default
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def format_decimal_percentage(
|
|
172
|
+
value: Optional[float], unit: str = "pct", default: str = "None", ndigits: int = 3
|
|
173
|
+
) -> str:
|
|
174
|
+
"""Format a decimal percentage (0-1) as a percentage (0-100%) for logging in a table."""
|
|
175
|
+
return format_float(value * 100, unit=unit, ndigits=ndigits) if isinstance(value, (float, int)) else default
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def format_enum(value: Optional[Enum], default: str = "None") -> str:
|
|
179
|
+
"""Format an enum for logging in a table."""
|
|
180
|
+
return format_str(value.value) if isinstance(value, Enum) else default
|