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
@@ -2,7 +2,7 @@ from enum import Enum
2
2
  from functools import reduce
3
3
  from numpy import average, copy, random, vstack
4
4
  from numpy.typing import NDArray
5
- from typing import Optional, Union
5
+ from typing import Union
6
6
  from hestia_earth.schema import (
7
7
  MeasurementMethodClassification,
8
8
  MeasurementStatsDefinition,
@@ -12,7 +12,7 @@ from hestia_earth.utils.tools import non_empty_list
12
12
  from hestia_earth.utils.stats import gen_seed
13
13
  from hestia_earth.utils.descriptive_stats import calc_descriptive_stats
14
14
 
15
- from hestia_earth.models.log import log_as_table, logRequirements, logShouldRun
15
+ from hestia_earth.models.log import format_bool, format_float, log_as_table, logRequirements, logShouldRun
16
16
  from hestia_earth.models.utils import pairwise
17
17
  from hestia_earth.models.utils.blank_node import group_nodes_by_year
18
18
  from hestia_earth.models.utils.ecoClimateZone import EcoClimateZone, get_eco_climate_zone_value
@@ -338,7 +338,7 @@ def _format_inventory(inventory: dict) -> str:
338
338
  {
339
339
  "year": year,
340
340
  **{
341
- _format_column_header(category): _format_number(
341
+ _format_column_header(category): format_float(
342
342
  inventory.get(year, {}).get(_InventoryKey.LAND_COVER_SUMMARY, {}).get(category, 0)
343
343
  ) for category in land_covers
344
344
  },
@@ -384,16 +384,6 @@ def _get_loggable_inventory_keys(inventory: dict) -> list:
384
384
  return sorted(unique_keys, key=lambda key_: key_order[key_])
385
385
 
386
386
 
387
- def _format_bool(value: Optional[bool]) -> str:
388
- """Format a bool for logging in a table."""
389
- return str(bool(value))
390
-
391
-
392
- def _format_number(value: Optional[float]) -> str:
393
- """Format a float for logging in a table."""
394
- return f"{value:.1f}" if isinstance(value, (float, int)) else "None"
395
-
396
-
397
387
  def _format_column_header(value: Union[_InventoryKey, BiomassCategory, str]):
398
388
  """Format an enum or str for logging as a table column header."""
399
389
  as_string = value.value if isinstance(value, Enum) else str(value)
@@ -401,8 +391,8 @@ def _format_column_header(value: Union[_InventoryKey, BiomassCategory, str]):
401
391
 
402
392
 
403
393
  _INVENTORY_KEY_TO_FORMAT_FUNC = {
404
- _InventoryKey.LAND_COVER_CHANGE_EVENT: _format_bool,
405
- _InventoryKey.YEARS_SINCE_LCC_EVENT: _format_number
394
+ _InventoryKey.LAND_COVER_CHANGE_EVENT: format_bool,
395
+ _InventoryKey.YEARS_SINCE_LCC_EVENT: format_float
406
396
  }
407
397
  """
408
398
  Map inventory keys to format functions. The columns in inventory logged as a table will also be sorted in the order of
@@ -2,7 +2,7 @@ from enum import Enum
2
2
  from functools import reduce
3
3
  from numpy import average, copy, random, vstack
4
4
  from numpy.typing import NDArray
5
- from typing import Optional, Union
5
+ from typing import Union
6
6
  from hestia_earth.schema import (
7
7
  MeasurementMethodClassification,
8
8
  MeasurementStatsDefinition,
@@ -12,7 +12,7 @@ from hestia_earth.utils.tools import non_empty_list
12
12
  from hestia_earth.utils.stats import gen_seed
13
13
  from hestia_earth.utils.descriptive_stats import calc_descriptive_stats
14
14
 
15
- from hestia_earth.models.log import log_as_table, logRequirements, logShouldRun
15
+ from hestia_earth.models.log import format_bool, format_float, log_as_table, logRequirements, logShouldRun
16
16
  from hestia_earth.models.utils import pairwise
17
17
  from hestia_earth.models.utils.blank_node import group_nodes_by_year
18
18
  from hestia_earth.models.utils.ecoClimateZone import EcoClimateZone, get_eco_climate_zone_value
@@ -325,7 +325,7 @@ def _format_inventory(inventory: dict) -> str:
325
325
  {
326
326
  "year": year,
327
327
  **{
328
- _format_column_header(category): _format_number(
328
+ _format_column_header(category): format_float(
329
329
  inventory.get(year, {}).get(_InventoryKey.BIOMASS_CATEGORY_SUMMARY, {}).get(category, 0)
330
330
  ) for category in land_covers
331
331
  },
@@ -371,16 +371,6 @@ def _get_loggable_inventory_keys(inventory: dict) -> list:
371
371
  return sorted(unique_keys, key=lambda key_: key_order[key_])
372
372
 
373
373
 
374
- def _format_bool(value: Optional[bool]) -> str:
375
- """Format a bool for logging in a table."""
376
- return str(bool(value))
377
-
378
-
379
- def _format_number(value: Optional[float]) -> str:
380
- """Format a float for logging in a table."""
381
- return f"{value:.1f}" if isinstance(value, (float, int)) else "None"
382
-
383
-
384
374
  def _format_column_header(value: Union[_InventoryKey, BiomassCategory, str]):
385
375
  """Format an enum or str for logging as a table column header."""
386
376
  as_string = value.value if isinstance(value, Enum) else str(value)
@@ -388,8 +378,8 @@ def _format_column_header(value: Union[_InventoryKey, BiomassCategory, str]):
388
378
 
389
379
 
390
380
  _INVENTORY_KEY_TO_FORMAT_FUNC = {
391
- _InventoryKey.LAND_COVER_CHANGE_EVENT: _format_bool,
392
- _InventoryKey.YEARS_SINCE_LCC_EVENT: _format_number
381
+ _InventoryKey.LAND_COVER_CHANGE_EVENT: format_bool,
382
+ _InventoryKey.YEARS_SINCE_LCC_EVENT: format_float
393
383
  }
394
384
  """
395
385
  Map inventory keys to format functions. The columns in inventory logged as a table will also be sorted in the order of
@@ -11,7 +11,7 @@ from hestia_earth.utils.descriptive_stats import calc_descriptive_stats
11
11
  from hestia_earth.utils.stats import gen_seed, truncated_normal_1d
12
12
  from hestia_earth.utils.tools import non_empty_list
13
13
 
14
- from hestia_earth.models.log import log_as_table, logRequirements, logShouldRun
14
+ from hestia_earth.models.log import format_nd_array, format_str, log_as_table, logRequirements, logShouldRun
15
15
  from hestia_earth.models.utils.blank_node import group_nodes_by_year, filter_list_term_type
16
16
  from hestia_earth.models.utils.measurement import _new_measurement
17
17
  from hestia_earth.models.utils.property import get_node_property
@@ -280,17 +280,17 @@ def _format_inventory(inventory: dict) -> str:
280
280
  return log_as_table(
281
281
  {
282
282
  "year": year,
283
- "stable-oc-from-biochar": _format_factor(inventory.get(year))
283
+ "stable-oc-from-biochar": format_nd_array(inventory.get(year))
284
284
  } for year in inventory_years
285
285
  ) if should_run else "None"
286
286
 
287
287
 
288
288
  def _format_logs(logs: dict):
289
289
  """
290
- Format model logs. Format method selected based on dict key, with `_format_str` as fallback.
290
+ Format model logs. Format method selected based on dict key, with `format_str` as fallback.
291
291
  """
292
292
  return {
293
- _format_str(key): _LOG_KEY_TO_FORMAT_FUNC.get(key, _format_str)(value) for key, value in logs.items()
293
+ format_str(key): _LOG_KEY_TO_FORMAT_FUNC.get(key, format_str)(value) for key, value in logs.items()
294
294
  }
295
295
 
296
296
 
@@ -303,45 +303,11 @@ def _format_factor_cache(factor_cache: dict) -> str:
303
303
  return log_as_table(
304
304
  {
305
305
  "term-id": term_id,
306
- **{_format_str(key): _format_factor(value) for key, value in factor_dict.items()}
306
+ **{format_str(key): format_nd_array(value) for key, value in factor_dict.items()}
307
307
  } for term_id, factor_dict in factor_cache.items()
308
308
  ) if should_run else "None"
309
309
 
310
310
 
311
- def _format_factor(value) -> str:
312
- """
313
- Format a model factor. Method selected based on factor type (ndarray, int or float).
314
- """
315
- format_func = next(
316
- (func for type, func in _TYPE_TO_FORMAT_FUNC.items() if isinstance(value, type)),
317
- None
318
- )
319
- return format_func(value) if format_func else "None"
320
-
321
-
322
- def _format_nd_array(value) -> str:
323
- return f"{np.mean(value):.3g} ± {np.std(value):.3g}"
324
-
325
-
326
- def _format_number(value) -> str:
327
- return f"{value:.3g}"
328
-
329
-
330
- _INVALID_CHARS = {"_", ":", ",", "="}
331
- _REPLACEMENT_CHAR = "-"
332
-
333
-
334
- def _format_str(value: str, *_) -> str:
335
- """Format a string for logging in a table. Remove all characters used to render the table on the front end."""
336
- return reduce(lambda x, char: x.replace(char, _REPLACEMENT_CHAR), _INVALID_CHARS, str(value))
337
-
338
-
339
- _TYPE_TO_FORMAT_FUNC = {
340
- np.ndarray: _format_nd_array,
341
- (float, int): _format_number
342
- }
343
-
344
-
345
311
  _LOG_KEY_TO_FORMAT_FUNC = {
346
312
  "factor_cache": _format_factor_cache
347
313
  }
@@ -2,7 +2,7 @@ import numpy as np
2
2
  import numpy.typing as npt
3
3
  from typing import Callable, Union
4
4
  from hestia_earth.schema import EmissionMethodTier, EmissionStatsDefinition
5
- from hestia_earth.models.log import logRequirements, logShouldRun
5
+ from hestia_earth.models.log import format_nd_array, format_float, logRequirements, logShouldRun
6
6
  from hestia_earth.utils.stats import (
7
7
  discrete_uniform_1d, gen_seed, normal_1d, repeat_single, triangular_1d
8
8
  )
@@ -15,8 +15,8 @@ from hestia_earth.models.utils.measurement import most_relevant_measurement_valu
15
15
  from hestia_earth.models.utils.site import valid_site_type
16
16
 
17
17
  from .organicSoilCultivation_utils import (
18
- assign_ditch_category, assign_organic_soil_category, calc_emission, DitchCategory, format_nd_array, format_number,
19
- get_ditch_frac, get_emission_factor, OrganicSoilCategory, remap_categories, valid_eco_climate_zone
18
+ assign_ditch_category, assign_organic_soil_category, calc_emission, DitchCategory, get_ditch_frac,
19
+ get_emission_factor, OrganicSoilCategory, remap_categories, valid_eco_climate_zone
20
20
  )
21
21
  from . import MODEL
22
22
 
@@ -226,8 +226,8 @@ def _should_run(cycle: dict):
226
226
  emission_factor=format_nd_array(emission_factor),
227
227
  ditch_factor=format_nd_array(ditch_factor),
228
228
  ditch_frac=format_nd_array(ditch_frac),
229
- land_occupation=format_number(land_occupation),
230
- histosol=format_number(histosol)
229
+ land_occupation=format_float(land_occupation),
230
+ histosol=format_float(histosol)
231
231
  )
232
232
 
233
233
  should_run = all([
@@ -1,6 +1,5 @@
1
1
  from hestia_earth.schema import EmissionMethodTier, MeasurementMethodClassification
2
2
 
3
- from hestia_earth.models.log import logRequirements, logShouldRun
4
3
  from hestia_earth.models.utils.emission import _new_emission
5
4
 
6
5
  from .biomass_utils import detect_land_cover_change, get_valid_management_nodes, summarise_land_cover_nodes
@@ -42,8 +41,10 @@ RETURNS = {
42
41
  }
43
42
  TERM_ID = 'co2ToAirAboveGroundBiomassStockChangeLandUseChange,co2ToAirAboveGroundBiomassStockChangeManagementChange'
44
43
 
45
- _LU_EMISSION_TERM_ID = "co2ToAirAboveGroundBiomassStockChangeLandUseChange"
46
- _MG_EMISSION_TERM_ID = "co2ToAirAboveGroundBiomassStockChangeManagementChange"
44
+ _TERM_IDS = TERM_ID.split(",")
45
+
46
+ _LU_EMISSION_TERM_ID = _TERM_IDS[0]
47
+ _MG_EMISSION_TERM_ID = _TERM_IDS[1]
47
48
 
48
49
  _CARBON_STOCK_TERM_ID = 'aboveGroundBiomass'
49
50
 
@@ -122,23 +123,17 @@ def run(cycle: dict) -> list[dict]:
122
123
  """
123
124
  should_run_exec = create_should_run_function(
124
125
  _CARBON_STOCK_TERM_ID,
125
- measurements_mandatory=False, # Model can allocate zero emissions to LUC with enough landCover data
126
+ _LU_EMISSION_TERM_ID,
127
+ _MG_EMISSION_TERM_ID,
128
+ measurements_required=False, # Model can allocate zero emissions to LUC with enough landCover data
126
129
  measurement_method_ranking=_MEASUREMENT_METHOD_RANKING,
127
130
  get_valid_management_nodes_func=get_valid_management_nodes,
128
131
  summarise_land_use_func=summarise_land_cover_nodes,
129
132
  detect_land_use_change_func=detect_land_cover_change,
130
133
  )
131
134
 
132
- run_exec = create_run_function(
133
- new_emission_func=_emission,
134
- land_use_change_emission_term_id=_LU_EMISSION_TERM_ID,
135
- management_change_emission_term_id=_MG_EMISSION_TERM_ID
136
- )
137
-
138
- should_run, cycle_id, inventory, logs = should_run_exec(cycle)
135
+ run_exec = create_run_function(new_emission_func=_emission)
139
136
 
140
- for term_id in [_LU_EMISSION_TERM_ID, _MG_EMISSION_TERM_ID]:
141
- logRequirements(cycle, model=MODEL, term=term_id, **logs)
142
- logShouldRun(cycle, MODEL, term_id, should_run)
137
+ should_run, assigned_emissions = should_run_exec(cycle)
143
138
 
144
- return run_exec(cycle_id, inventory) if should_run else []
139
+ return run_exec(assigned_emissions) if should_run else []
@@ -1,6 +1,5 @@
1
1
  from hestia_earth.schema import EmissionMethodTier
2
2
 
3
- from hestia_earth.models.log import logRequirements, logShouldRun
4
3
  from hestia_earth.models.utils.emission import _new_emission
5
4
 
6
5
  from .biomass_utils import detect_land_cover_change, get_valid_management_nodes, summarise_land_cover_nodes
@@ -43,8 +42,10 @@ RETURNS = {
43
42
  }
44
43
  TERM_ID = 'co2ToAirBelowGroundBiomassStockChangeLandUseChange,co2ToAirBelowGroundBiomassStockChangeManagementChange'
45
44
 
46
- _LU_EMISSION_TERM_ID = "co2ToAirBelowGroundBiomassStockChangeLandUseChange"
47
- _MG_EMISSION_TERM_ID = "co2ToAirBelowGroundBiomassStockChangeManagementChange"
45
+ _TERM_IDS = TERM_ID.split(",")
46
+
47
+ _LU_EMISSION_TERM_ID = _TERM_IDS[0]
48
+ _MG_EMISSION_TERM_ID = _TERM_IDS[1]
48
49
 
49
50
  _DEPTH_UPPER = 0
50
51
  _DEPTH_LOWER = 30
@@ -114,24 +115,18 @@ def run(cycle: dict) -> list[dict]:
114
115
  """
115
116
  should_run_exec = create_should_run_function(
116
117
  _CARBON_STOCK_TERM_ID,
118
+ _LU_EMISSION_TERM_ID,
119
+ _MG_EMISSION_TERM_ID,
117
120
  depth_upper=_DEPTH_UPPER,
118
121
  depth_lower=_DEPTH_LOWER,
119
- measurements_mandatory=False, # Model can allocate zero emissions to LUC with enough landCover data
122
+ measurements_required=False, # Model can allocate zero emissions to LUC with enough landCover data
120
123
  get_valid_management_nodes_func=get_valid_management_nodes,
121
124
  summarise_land_use_func=summarise_land_cover_nodes,
122
- detect_land_use_change_func=detect_land_cover_change
123
- )
124
-
125
- run_exec = create_run_function(
126
- new_emission_func=_emission,
127
- land_use_change_emission_term_id=_LU_EMISSION_TERM_ID,
128
- management_change_emission_term_id=_MG_EMISSION_TERM_ID
125
+ detect_land_use_change_func=detect_land_cover_change,
129
126
  )
130
127
 
131
- should_run, cycle_id, inventory, logs = should_run_exec(cycle)
128
+ run_exec = create_run_function(new_emission_func=_emission)
132
129
 
133
- for term_id in [_LU_EMISSION_TERM_ID, _MG_EMISSION_TERM_ID]:
134
- logRequirements(cycle, model=MODEL, term=term_id, **logs)
135
- logShouldRun(cycle, MODEL, term_id, should_run)
130
+ should_run, assigned_emissions = should_run_exec(cycle)
136
131
 
137
- return run_exec(cycle_id, inventory) if should_run else []
132
+ return run_exec(assigned_emissions) if should_run else []
@@ -1,7 +1,6 @@
1
1
  from hestia_earth.schema import EmissionMethodTier
2
2
  from hestia_earth.utils.date import YEAR
3
3
 
4
- from hestia_earth.models.log import logRequirements, logShouldRun
5
4
  from hestia_earth.models.utils.emission import _new_emission
6
5
 
7
6
  from .co2ToAirCarbonStockChange_utils import create_run_function, create_should_run_function
@@ -116,25 +115,16 @@ def run(cycle: dict) -> list[dict]:
116
115
  """
117
116
  should_run_exec = create_should_run_function(
118
117
  _CARBON_STOCK_TERM_ID,
118
+ land_use_change_emission_term_id=None, # All emissions allocated to management change
119
+ management_change_emission_term_id=TERM_ID,
119
120
  depth_upper=_DEPTH_UPPER,
120
121
  depth_lower=_DEPTH_LOWER,
121
- transition_period=_TRANSITION_PERIOD_DAYS
122
+ transition_period=_TRANSITION_PERIOD_DAYS,
123
+ exclude_from_logs=_EXCLUDE_FROM_LOGS
122
124
  )
123
125
 
124
- run_exec = create_run_function(
125
- new_emission_func=_emission,
126
- land_use_change_emission_term_id=None, # All emissions allocated to management change
127
- management_change_emission_term_id=TERM_ID
128
- )
126
+ run_exec = create_run_function(new_emission_func=_emission)
129
127
 
130
- should_run, cycle_id, inventory, logs = should_run_exec(cycle)
131
-
132
- logRequirements(
133
- cycle,
134
- model=MODEL,
135
- term=TERM_ID,
136
- **{k: v for k, v in logs.items() if k not in _EXCLUDE_FROM_LOGS}
137
- )
138
- logShouldRun(cycle, MODEL, TERM_ID, should_run)
128
+ should_run, assigned_emissions = should_run_exec(cycle)
139
129
 
140
- return run_exec(cycle_id, inventory) if should_run else []
130
+ return run_exec(assigned_emissions) if should_run else []