hestia-earth-models 0.74.14__py3-none-any.whl → 0.74.16__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.

Files changed (37) hide show
  1. hestia_earth/models/cache_nodes.py +9 -6
  2. hestia_earth/models/config/ImpactAssessment.json +0 -22
  3. hestia_earth/models/config/Site.json +11 -3
  4. hestia_earth/models/cycle/completeness/material.py +2 -3
  5. hestia_earth/models/emepEea2019/fuelCombustion_utils.py +21 -21
  6. hestia_earth/models/hestia/landOccupationDuringCycle.py +9 -27
  7. hestia_earth/models/hestia/resourceUse_utils.py +49 -20
  8. hestia_earth/models/hestia/soilClassification.py +314 -0
  9. hestia_earth/models/ipcc2019/aboveGroundBiomass.py +5 -15
  10. hestia_earth/models/ipcc2019/belowGroundBiomass.py +5 -15
  11. hestia_earth/models/ipcc2019/biocharOrganicCarbonPerHa.py +5 -39
  12. hestia_earth/models/ipcc2019/ch4ToAirOrganicSoilCultivation.py +5 -5
  13. hestia_earth/models/ipcc2019/co2ToAirAboveGroundBiomassStockChange.py +10 -15
  14. hestia_earth/models/ipcc2019/co2ToAirBelowGroundBiomassStockChange.py +11 -16
  15. hestia_earth/models/ipcc2019/co2ToAirBiocharStockChange.py +7 -17
  16. hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +123 -74
  17. hestia_earth/models/ipcc2019/co2ToAirOrganicSoilCultivation.py +4 -5
  18. hestia_earth/models/ipcc2019/co2ToAirSoilOrganicCarbonStockChange.py +10 -15
  19. hestia_earth/models/ipcc2019/n2OToAirOrganicSoilCultivationDirect.py +5 -5
  20. hestia_earth/models/ipcc2019/nonCo2EmissionsToAirNaturalVegetationBurning.py +18 -47
  21. hestia_earth/models/ipcc2019/organicCarbonPerHa.py +10 -10
  22. hestia_earth/models/ipcc2019/organicCarbonPerHa_utils.py +4 -19
  23. hestia_earth/models/ipcc2019/organicSoilCultivation_utils.py +0 -9
  24. hestia_earth/models/log.py +75 -1
  25. hestia_earth/models/mocking/search-results.json +1 -1
  26. hestia_earth/models/utils/blank_node.py +12 -4
  27. hestia_earth/models/version.py +1 -1
  28. {hestia_earth_models-0.74.14.dist-info → hestia_earth_models-0.74.16.dist-info}/METADATA +15 -7
  29. {hestia_earth_models-0.74.14.dist-info → hestia_earth_models-0.74.16.dist-info}/RECORD +37 -34
  30. {hestia_earth_models-0.74.14.dist-info → hestia_earth_models-0.74.16.dist-info}/WHEEL +1 -1
  31. tests/models/ecoalimV9/test_cycle.py +2 -2
  32. tests/models/hestia/test_landTransformation20YearAverageDuringCycle.py +4 -8
  33. tests/models/hestia/test_soilClassification.py +72 -0
  34. tests/models/ipcc2019/test_organicCarbonPerHa_utils.py +4 -48
  35. tests/models/test_log.py +128 -0
  36. {hestia_earth_models-0.74.14.dist-info → hestia_earth_models-0.74.16.dist-info/licenses}/LICENSE +0 -0
  37. {hestia_earth_models-0.74.14.dist-info → hestia_earth_models-0.74.16.dist-info}/top_level.txt +0 -0
@@ -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 format_number_list(values: Optional[list[float]]) -> str:
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(format_number(value) for value in values) or "None"if isinstance(values, list)
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": format_number(data.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"
@@ -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 Union, List
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,73 @@ 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
181
+
182
+
183
+ def format_conditional_message(value: bool, on_true: str = "True", on_false: str = "False") -> str:
184
+ return format_str(on_true if bool(value) else on_false)