hestia-earth-models 0.73.7__py3-none-any.whl → 0.73.8__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 (62) hide show
  1. hestia_earth/models/config/Cycle.json +116 -26
  2. hestia_earth/models/config/ImpactAssessment.json +239 -199
  3. hestia_earth/models/dammgen2009/noxToAirExcreta.py +11 -9
  4. hestia_earth/models/ecoalimV9/cycle.py +29 -39
  5. hestia_earth/models/ecoalimV9/impact_assessment.py +38 -40
  6. hestia_earth/models/ecoalimV9/utils.py +82 -16
  7. hestia_earth/models/ecoinventV3/__init__.py +3 -3
  8. hestia_earth/models/emepEea2019/n2OToAirFuelCombustionDirect.py +2 -2
  9. hestia_earth/models/hestia/default_emissions.py +2 -6
  10. hestia_earth/models/hestia/default_resourceUse.py +2 -5
  11. hestia_earth/models/hestia/seed_emissions.py +7 -3
  12. hestia_earth/models/impact_assessment/emissions.py +3 -5
  13. hestia_earth/models/ipcc2019/biocharOrganicCarbonPerHa.py +9 -3
  14. hestia_earth/models/ipcc2019/co2ToAirAboveGroundBiomassStockChange.py +1 -5
  15. hestia_earth/models/ipcc2019/co2ToAirBelowGroundBiomassStockChange.py +1 -5
  16. hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +1 -33
  17. hestia_earth/models/ipcc2019/co2ToAirSoilOrganicCarbonStockChange.py +1 -5
  18. hestia_earth/models/ipcc2019/n2OToAirAquacultureSystemsIndirect.py +44 -0
  19. hestia_earth/models/ipcc2019/n2OToAirCropResidueBurningIndirect.py +43 -0
  20. hestia_earth/models/ipcc2019/n2OToAirCropResidueDecompositionIndirect.py +13 -70
  21. hestia_earth/models/ipcc2019/n2OToAirExcretaIndirect.py +13 -70
  22. hestia_earth/models/ipcc2019/n2OToAirFuelCombustionIndirect.py +43 -0
  23. hestia_earth/models/ipcc2019/n2OToAirInorganicFertiliserIndirect.py +13 -70
  24. hestia_earth/models/ipcc2019/n2OToAirNaturalVegetationBurningIndirect.py +43 -0
  25. hestia_earth/models/ipcc2019/n2OToAirOrganicFertiliserIndirect.py +13 -70
  26. hestia_earth/models/ipcc2019/n2OToAirOrganicSoilBurningIndirect.py +43 -0
  27. hestia_earth/models/ipcc2019/n2OToAirOrganicSoilCultivationIndirect.py +43 -0
  28. hestia_earth/models/ipcc2019/n2OToAir_indirect_emissions_utils.py +112 -0
  29. hestia_earth/models/ipcc2019/utils.py +0 -25
  30. hestia_earth/models/jarvisAndPain1994/n2ToAirExcreta.py +11 -9
  31. hestia_earth/models/linkedImpactAssessment/emissions.py +24 -15
  32. hestia_earth/models/linkedImpactAssessment/utils.py +5 -1
  33. hestia_earth/models/mocking/search-results.json +354 -354
  34. hestia_earth/models/utils/background_emissions.py +17 -10
  35. hestia_earth/models/utils/emission.py +18 -8
  36. hestia_earth/models/utils/impact_assessment.py +3 -3
  37. hestia_earth/models/utils/indicator.py +8 -1
  38. hestia_earth/models/utils/lookup.py +29 -17
  39. hestia_earth/models/utils/productivity.py +1 -1
  40. hestia_earth/models/version.py +1 -1
  41. hestia_earth/orchestrator/strategies/merge/merge_list.py +41 -54
  42. {hestia_earth_models-0.73.7.dist-info → hestia_earth_models-0.73.8.dist-info}/METADATA +3 -3
  43. {hestia_earth_models-0.73.7.dist-info → hestia_earth_models-0.73.8.dist-info}/RECORD +62 -47
  44. tests/models/dammgen2009/test_noxToAirExcreta.py +2 -2
  45. tests/models/ecoalimV9/test_cycle.py +1 -1
  46. tests/models/ecoalimV9/test_impact_assessment.py +1 -1
  47. tests/models/ecoalimV9/test_utils.py +13 -0
  48. tests/models/ipcc2019/test_biocharOrganicCarbonPerHa.py +2 -1
  49. tests/models/ipcc2019/test_n2OToAirAquacultureSystemsIndirect.py +45 -0
  50. tests/models/ipcc2019/test_n2OToAirCropResidueBurningIndirect.py +45 -0
  51. tests/models/ipcc2019/test_n2OToAirCropResidueDecompositionIndirect.py +6 -32
  52. tests/models/ipcc2019/test_n2OToAirExcretaIndirect.py +6 -32
  53. tests/models/ipcc2019/test_n2OToAirFuelCombustionIndirect.py +45 -0
  54. tests/models/ipcc2019/test_n2OToAirInorganicFertiliserIndirect.py +6 -32
  55. tests/models/ipcc2019/test_n2OToAirNaturalVegetationBurningIndirect.py +45 -0
  56. tests/models/ipcc2019/test_n2OToAirOrganicFertiliserIndirect.py +6 -32
  57. tests/models/ipcc2019/test_n2OToAirOrganicSoilBurningIndirect.py +45 -0
  58. tests/models/ipcc2019/test_n2OToAirOrganicSoilCultivationIndirect.py +45 -0
  59. tests/models/ipcc2019/test_n2OToAir_indirect_emissions_utils.py +19 -0
  60. {hestia_earth_models-0.73.7.dist-info → hestia_earth_models-0.73.8.dist-info}/LICENSE +0 -0
  61. {hestia_earth_models-0.73.7.dist-info → hestia_earth_models-0.73.8.dist-info}/WHEEL +0 -0
  62. {hestia_earth_models-0.73.7.dist-info → hestia_earth_models-0.73.8.dist-info}/top_level.txt +0 -0
@@ -22,7 +22,7 @@ RETURNS = {
22
22
  }
23
23
  TERM_ID = 'noxToAirExcreta'
24
24
  TIER = EmissionMethodTier.TIER_1.value
25
- N2O_TERM_ID = 'n2OToAirExcretaDirect'
25
+ _N2O_TERM_ID = 'n2OToAirExcretaDirect'
26
26
 
27
27
 
28
28
  def _emission(value: float):
@@ -32,22 +32,24 @@ def _emission(value: float):
32
32
  return emission
33
33
 
34
34
 
35
- def _run(n2o: dict):
36
- value = 0.1 * list_sum(n2o.get("value", [])) / get_atomic_conversion(Units.KG_N2O, Units.TO_N)
35
+ def _run(n2o_value: float):
36
+ value = 0.1 * n2o_value / get_atomic_conversion(Units.KG_N2O, Units.TO_N)
37
37
  value = value * get_atomic_conversion(Units.KG_NOX, Units.TO_N)
38
38
  return [_emission(value)]
39
39
 
40
40
 
41
41
  def _should_run(cycle: dict):
42
- n2o = find_term_match(cycle.get('emissions', []), N2O_TERM_ID)
42
+ n2o = find_term_match(cycle.get('emissions', []), _N2O_TERM_ID)
43
+ n2o_value = list_sum(n2o.get("value", []), default=None)
43
44
 
44
- logRequirements(cycle, model=MODEL, term=TERM_ID, has_n2o=n2o is not None)
45
+ logRequirements(cycle, model=MODEL, term=TERM_ID,
46
+ **{_N2O_TERM_ID: n2o_value})
45
47
 
46
- should_run = all([n2o])
48
+ should_run = all([n2o_value is not None])
47
49
  logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
48
- return should_run, n2o
50
+ return should_run, n2o_value
49
51
 
50
52
 
51
53
  def run(cycle: dict):
52
- should_run, n2o = _should_run(cycle)
53
- return _run(n2o) if should_run else []
54
+ should_run, n2o_value = _should_run(cycle)
55
+ return _run(n2o_value) if should_run else []
@@ -1,13 +1,17 @@
1
1
  from functools import reduce
2
2
  from statistics import mean
3
- from hestia_earth.schema import EmissionMethodTier
3
+ from hestia_earth.schema import EmissionMethodTier, TermTermType
4
4
  from hestia_earth.utils.tools import flatten, list_sum
5
5
 
6
- from hestia_earth.models.log import debugValues, logShouldRun, logRequirements
6
+ from hestia_earth.models.log import logShouldRun, logRequirements
7
7
  from hestia_earth.models.utils.emission import _new_emission
8
- from hestia_earth.models.utils.background_emissions import get_background_inputs, no_gap_filled_background_emissions
8
+ from hestia_earth.models.utils.background_emissions import (
9
+ get_background_inputs,
10
+ no_gap_filled_background_emissions,
11
+ log_missing_emissions
12
+ )
9
13
  from hestia_earth.models.utils.blank_node import group_by_keys
10
- from .utils import get_input_mappings, ecoalim_values
14
+ from .utils import get_input_mappings, process_input, parse_term_id
11
15
  from . import MODEL
12
16
 
13
17
  REQUIREMENTS = {
@@ -46,19 +50,19 @@ RETURNS = {
46
50
  }]
47
51
  }
48
52
  LOOKUPS = {
49
- "ecoalim-emissionsResourceUse": "emission-",
50
- "crop": "ecoalimMapping",
51
- "processedFood": "ecoalimMapping",
53
+ "ecoalim-emission": "emission-",
52
54
  "animalProduct": "ecoalimMapping",
55
+ "crop": "ecoalimMapping",
56
+ "feedFoodAdditive": "ecoalimMapping",
53
57
  "forage": "ecoalimMapping",
54
- "feedFoodAdditive": "ecoalimMapping"
58
+ "processedFood": "ecoalimMapping"
55
59
  }
56
60
  MODEL_KEY = 'cycle'
57
61
  TIER = EmissionMethodTier.BACKGROUND.value
58
62
 
59
63
 
60
- def _emission(term_id: str, value: float, input: dict):
61
- emission = _new_emission(term_id, MODEL)
64
+ def _emission(term_id: str, value: float, input: dict, country_id: str = None, key_id: str = None):
65
+ emission = _new_emission(term_id, MODEL, country_id, key_id)
62
66
  emission['value'] = [value]
63
67
  emission['methodTier'] = TIER
64
68
  emission['inputs'] = [input.get('term')]
@@ -69,32 +73,9 @@ def _emission(term_id: str, value: float, input: dict):
69
73
  return emission
70
74
 
71
75
 
72
- def _add_emission(cycle: dict, input: dict):
73
- input_term_id = input.get('term', {}).get('@id')
74
- operation_term_id = input.get('operation', {}).get('@id')
75
- animal_term_id = input.get('animal', {}).get('@id')
76
-
77
- def add(prev: dict, mapping: tuple):
78
- gadm_id, ecoalim_key = mapping
79
- # all countries have the same coefficient
80
- coefficient = 1
81
- emissions = ecoalim_values(ecoalim_key, 'emission')
82
- for emission_term_id, value in emissions:
83
- # log run on each emission so we know it did run
84
- logShouldRun(cycle, MODEL, input_term_id, True, methodTier=TIER, emission_id=emission_term_id)
85
- debugValues(cycle, model=MODEL, term=emission_term_id, model_key=MODEL_KEY,
86
- value=value,
87
- coefficient=coefficient,
88
- input=input_term_id,
89
- operation=operation_term_id,
90
- animal=animal_term_id)
91
- prev[emission_term_id] = prev.get(emission_term_id, []) + [value * coefficient]
92
- return prev
93
- return add
94
-
95
-
96
76
  def _run_input(cycle: dict):
97
77
  no_gap_filled_background_emissions_func = no_gap_filled_background_emissions(cycle)
78
+ log_missing_emissions_func = log_missing_emissions(cycle, model=MODEL, methodTier=TIER)
98
79
 
99
80
  def run(inputs: list):
100
81
  input = inputs[0]
@@ -107,18 +88,27 @@ def _run_input(cycle: dict):
107
88
  has_no_gap_filled_background_emissions = no_gap_filled_background_emissions_func(input)
108
89
 
109
90
  logRequirements(cycle, model=MODEL, term=input_term_id, model_key=MODEL_KEY,
110
- has_ecoalim_mappings=has_mappings,
111
- ecoalim_mappings=';'.join([v[1] for v in mappings]),
91
+ has_mappings=has_mappings,
92
+ mappings=';'.join([v[1] for v in mappings]),
112
93
  has_no_gap_filled_background_emissions=has_no_gap_filled_background_emissions,
113
94
  input_value=input_value)
114
95
 
115
96
  should_run = all([has_mappings, has_no_gap_filled_background_emissions, input_value])
116
97
  logShouldRun(cycle, MODEL, input_term_id, should_run, methodTier=TIER, model_key=MODEL_KEY)
117
98
 
118
- grouped_emissions = reduce(_add_emission(cycle, input), mappings, {}) if should_run else {}
99
+ results = process_input(
100
+ cycle, input, mappings, TermTermType.EMISSION, model_key=MODEL_KEY
101
+ ) if should_run else {}
102
+ log_missing_emissions_func(input_term_id, list(map(parse_term_id, results.keys())))
119
103
  return [
120
- _emission(term_id, mean(value) * input_value, input)
121
- for term_id, value in grouped_emissions.items()
104
+ _emission(
105
+ term_id=parse_term_id(term_id),
106
+ value=mean([v['value'] * v['coefficient'] for v in values]) * input_value,
107
+ input=input,
108
+ country_id=values[0].get('country'),
109
+ key_id=values[0].get('key'),
110
+ )
111
+ for term_id, values in results.items()
122
112
  ]
123
113
  return run
124
114
 
@@ -1,13 +1,13 @@
1
1
  from functools import reduce
2
2
  from statistics import mean
3
- from hestia_earth.schema import IndicatorMethodTier
3
+ from hestia_earth.schema import IndicatorMethodTier, TermTermType
4
4
  from hestia_earth.utils.tools import flatten, list_sum
5
5
 
6
- from hestia_earth.models.log import debugValues, logShouldRun, logRequirements
6
+ from hestia_earth.models.log import logShouldRun, logRequirements
7
7
  from hestia_earth.models.utils.indicator import _new_indicator
8
- from hestia_earth.models.utils.background_emissions import get_background_inputs
8
+ from hestia_earth.models.utils.background_emissions import get_background_inputs, log_missing_emissions
9
9
  from hestia_earth.models.utils.blank_node import group_by_keys
10
- from .utils import get_input_mappings, ecoalim_values
10
+ from .utils import get_input_mappings, process_input, parse_term_id
11
11
  from . import MODEL
12
12
 
13
13
  REQUIREMENTS = {
@@ -48,19 +48,27 @@ RETURNS = {
48
48
  }]
49
49
  }
50
50
  LOOKUPS = {
51
- "ecoalim-emissionsResourceUse": "resourceUse-",
52
- "crop": "ecoalimMapping",
53
- "processedFood": "ecoalimMapping",
51
+ "ecoalim-resourceUse": "resourceUse-",
54
52
  "animalProduct": "ecoalimMapping",
53
+ "crop": "ecoalimMapping",
54
+ "feedFoodAdditive": "ecoalimMapping",
55
55
  "forage": "ecoalimMapping",
56
- "feedFoodAdditive": "ecoalimMapping"
56
+ "processedFood": "ecoalimMapping"
57
57
  }
58
58
  MODEL_KEY = 'impact_assessment'
59
59
  TIER = IndicatorMethodTier.BACKGROUND.value
60
60
 
61
61
 
62
- def _indicator(term_id: str, value: float, input: dict):
63
- indicator = _new_indicator(term_id, MODEL)
62
+ def _indicator(
63
+ term_id: str,
64
+ value: float,
65
+ input: dict,
66
+ country_id: str = None,
67
+ key_id: str = None,
68
+ land_cover_id: str = None,
69
+ previous_land_cover_id: str = None,
70
+ ):
71
+ indicator = _new_indicator(term_id, MODEL, land_cover_id, previous_land_cover_id, country_id, key_id)
64
72
  indicator['value'] = value
65
73
  indicator['methodTier'] = TIER
66
74
  indicator['inputs'] = [input.get('term')]
@@ -69,32 +77,11 @@ def _indicator(term_id: str, value: float, input: dict):
69
77
  return indicator
70
78
 
71
79
 
72
- def _add_indicator(cycle: dict, input: dict):
73
- input_term_id = input.get('term', {}).get('@id')
74
- operation_term_id = input.get('operation', {}).get('@id')
75
- animal_term_id = input.get('animal', {}).get('@id')
76
-
77
- def add(prev: dict, mapping: tuple):
78
- gadm_id, ecoalim_key = mapping
79
- # all countries have the same coefficient
80
- coefficient = 1
81
- indicators = ecoalim_values(ecoalim_key, 'resourceUse')
82
- for indicator_term_id, value in indicators:
83
- # log run on each indicator so we know it did run
84
- logShouldRun(cycle, MODEL, input_term_id, True, methodTier=TIER, emission_id=indicator_term_id)
85
- debugValues(cycle, model=MODEL, term=indicator_term_id, model_key=MODEL_KEY,
86
- value=value,
87
- coefficient=coefficient,
88
- input=input_term_id,
89
- operation=operation_term_id,
90
- animal=animal_term_id)
91
- if value is not None:
92
- prev[indicator_term_id] = prev.get(indicator_term_id, []) + [value * coefficient]
93
- return prev
94
- return add
95
-
96
-
97
80
  def _run_input(impact_assessment: dict):
81
+ log_missing_emissions_func = log_missing_emissions(
82
+ impact_assessment, TermTermType.RESOURCEUSE, model=MODEL, methodTier=TIER
83
+ )
84
+
98
85
  def run(inputs: list):
99
86
  input = inputs[0]
100
87
  input_term_id = input.get('term', {}).get('@id')
@@ -103,8 +90,8 @@ def _run_input(impact_assessment: dict):
103
90
  has_mappings = len(mappings) > 0
104
91
 
105
92
  logRequirements(impact_assessment, model=MODEL, term=input_term_id, model_key=MODEL_KEY,
106
- has_ecoalim_mappings=has_mappings,
107
- ecoalim_mappings=';'.join([v[1] for v in mappings]),
93
+ has_mappings=has_mappings,
94
+ mappings=';'.join([v[1] for v in mappings]),
108
95
  input_value=input_value)
109
96
 
110
97
  should_run = all([has_mappings, input_value])
@@ -112,10 +99,21 @@ def _run_input(impact_assessment: dict):
112
99
  impact_assessment, MODEL, input_term_id, should_run, methodTier=TIER, model_key=MODEL_KEY
113
100
  )
114
101
 
115
- grouped_indicators = reduce(_add_indicator(impact_assessment, input), mappings, {}) if should_run else {}
102
+ results = process_input(
103
+ impact_assessment, input, mappings, TermTermType.RESOURCEUSE, model_key=MODEL_KEY
104
+ ) if should_run else {}
105
+ log_missing_emissions_func(input_term_id, list(map(parse_term_id, results.keys())))
116
106
  return [
117
- _indicator(term_id, mean(value) * input_value, input)
118
- for term_id, value in grouped_indicators.items()
107
+ _indicator(
108
+ term_id=parse_term_id(term_id),
109
+ value=mean([v['value'] * v['coefficient'] for v in values]) * input_value,
110
+ input=input,
111
+ country_id=values[0].get('country'),
112
+ key_id=values[0].get('key'),
113
+ land_cover_id=values[0].get('landCover'),
114
+ previous_land_cover_id=values[0].get('previousLandCover'),
115
+ )
116
+ for term_id, values in results.items()
119
117
  ]
120
118
  return run
121
119
 
@@ -1,10 +1,15 @@
1
- from hestia_earth.utils.lookup import download_lookup, get_table_value, column_name, lookup_columns
2
- from hestia_earth.utils.tools import non_empty_list
1
+ from functools import lru_cache, reduce
2
+ from hestia_earth.schema import EmissionMethodTier, TermTermType
3
+ from hestia_earth.utils.lookup import download_lookup, _is_missing_value, column_name, lookup_columns
4
+ from hestia_earth.utils.tools import non_empty_list, safe_parse_float
3
5
 
6
+ from hestia_earth.models.log import debugValues, logShouldRun
7
+ from hestia_earth.models.utils import _omit
4
8
  from hestia_earth.models.utils.term import get_lookup_value
9
+ from . import MODEL
5
10
 
6
-
7
- _LOOKUP = "ecoalim-emissionsResourceUse.csv"
11
+ _LOOKUP_INDEX_KEY = column_name('ecoalimMappingName')
12
+ _TIER = EmissionMethodTier.BACKGROUND.value
8
13
 
9
14
 
10
15
  def get_input_mappings(model: str, input: dict):
@@ -15,17 +20,78 @@ def get_input_mappings(model: str, input: dict):
15
20
  return [(m.split(':')[0], m.split(':')[1]) for m in mappings]
16
21
 
17
22
 
18
- def ecoalim_values(mapping: str, column_prefix: str):
19
- lookup = download_lookup(_LOOKUP)
20
- col_name = column_name('ecoalimMappingName')
23
+ def parse_term_id(term_id: str): return term_id.split('-')[0]
24
+
25
+
26
+ def _process_mapping(node: dict, input: dict, term_type: TermTermType, **log_args):
27
+ input_term_id = input.get('term', {}).get('@id')
28
+ operation_term_id = input.get('operation', {}).get('@id')
29
+ animal_term_id = input.get('animal', {}).get('@id')
30
+
31
+ def add(prev: dict, mapping: tuple):
32
+ gadm_id, ecoalim_key = mapping
33
+ # all countries have the same coefficient
34
+ coefficient = 1
35
+ values = ecoalim_values(ecoalim_key, term_type)
36
+ for term_id, data in values:
37
+ # log run on each node so we know it did run
38
+ logShouldRun(node, MODEL, input_term_id, True, methodTier=_TIER, emission_id=term_id)
39
+ debugValues(node, model=MODEL, term=term_id,
40
+ value=data.get('value'),
41
+ coefficient=coefficient,
42
+ input=input_term_id,
43
+ operation=operation_term_id,
44
+ animal=animal_term_id,
45
+ **log_args)
46
+ group_id = '-'.join(non_empty_list([term_id] + list(_omit(data, ['value']).values())))
47
+ prev[group_id] = prev.get(group_id, []) + [data | {'coefficient': coefficient}]
48
+ return prev
49
+ return add
50
+
51
+
52
+ def process_input(node: dict, input: dict, mappings: list, term_type: TermTermType, **log_args):
53
+ return reduce(_process_mapping(node, input, term_type, **log_args), mappings, {})
54
+
55
+
56
+ _KEY_TO_FIELD = {
57
+ 'inputs': 'key'
58
+ }
59
+
60
+
61
+ def _key_to_field(key: str): return _KEY_TO_FIELD.get(key) or key
62
+
63
+
64
+ def _values_from_column(column: str, value: str):
65
+ values = column.split('+')
66
+ term_id = values[0]
67
+ value = safe_parse_float(value, default=None)
68
+ return {
69
+ term_id: {
70
+ 'value': value
71
+ } | {
72
+ _key_to_field(v.split('[')[0]): v.split('[')[1][:-1] for v in values[1:]
73
+ }
74
+ } if all([
75
+ column != _LOOKUP_INDEX_KEY,
76
+ not _is_missing_value(value)
77
+ ]) else {}
78
+
79
+
80
+ @lru_cache()
81
+ def _build_lookup(term_type: str):
82
+ lookup = download_lookup(f"ecoalim-{term_type}.csv", keep_in_memory=False)
83
+ columns = lookup_columns(lookup)
84
+ return {
85
+ row[_LOOKUP_INDEX_KEY]: reduce(
86
+ lambda prev, curr: prev | _values_from_column(curr, row[curr]),
87
+ columns,
88
+ {}
89
+ )
90
+ for row in lookup
91
+ }
21
92
 
22
- def emission(column: str):
23
- id = get_table_value(lookup, col_name, mapping, column)
24
- value = get_table_value(lookup, col_name, mapping, column.replace('term', 'value'))
25
- return (id, value) if id else None
26
93
 
27
- columns = [
28
- col for col in lookup_columns(lookup)
29
- if col.startswith(column_name(column_prefix)) and col.endswith(column_name('term'))
30
- ]
31
- return non_empty_list(map(emission, columns))
94
+ @lru_cache()
95
+ def ecoalim_values(mapping: str, term_type: TermTermType):
96
+ data = _build_lookup(term_type.value)
97
+ return list(data[mapping].items())
@@ -129,11 +129,11 @@ def _run_input(cycle: dict):
129
129
  should_run = all([has_mappings, has_no_gap_filled_background_emissions, input_value])
130
130
  logShouldRun(cycle, MODEL, input_term_id, should_run, methodTier=TIER, **extra_logs)
131
131
 
132
- grouped_emissions = reduce(_add_emission(cycle, input, **extra_logs), mappings, {}) if should_run else {}
133
- log_missing_emissions_func(input_term_id, list(grouped_emissions.keys()), **extra_logs)
132
+ results = reduce(_add_emission(cycle, input, **extra_logs), mappings, {}) if should_run else {}
133
+ log_missing_emissions_func(input_term_id, list(results.keys()), **extra_logs)
134
134
  return [
135
135
  _emission(term_id, value * input_value, input)
136
- for term_id, value in grouped_emissions.items()
136
+ for term_id, value in results.items()
137
137
  ]
138
138
  return run
139
139
 
@@ -26,8 +26,8 @@ RETURNS = {
26
26
  }]
27
27
  }
28
28
  LOOKUPS = {
29
- "fuel": "n2OToAirFuelCombustionEmepEea2019",
30
- "operation": "n2OToAirFuelCombustionEmepEea2019"
29
+ "fuel": "n2oToAirFuelCombustionEmepEea2019",
30
+ "operation": "n2oToAirFuelCombustionEmepEea2019"
31
31
  }
32
32
  TERM_ID = 'n2OToAirFuelCombustionDirect'
33
33
  TIER = EmissionMethodTier.TIER_1.value
@@ -1,10 +1,9 @@
1
1
  from hestia_earth.schema import EmissionMethodTier
2
2
  from hestia_earth.utils.tools import flatten, safe_parse_float
3
- from hestia_earth.utils.emission import cycle_emissions_in_system_boundary
4
3
 
5
4
  from hestia_earth.models.log import logRequirements, logShouldRun
6
5
  from hestia_earth.models.utils import _omit
7
- from hestia_earth.models.utils.emission import _new_emission
6
+ from hestia_earth.models.utils.emission import _new_emission, background_emissions_in_system_boundary
8
7
  from hestia_earth.models.utils.background_emissions import no_gap_filled_background_emissions
9
8
  from hestia_earth.models.utils.term import get_lookup_value
10
9
  from hestia_earth.models.utils.input import unique_background_inputs
@@ -51,10 +50,7 @@ def _default_value(input: dict):
51
50
 
52
51
 
53
52
  def _run_input(cycle: dict):
54
- required_emission_term_ids = [
55
- id for id in cycle_emissions_in_system_boundary(cycle)
56
- if id.endswith('InputsProduction')
57
- ]
53
+ required_emission_term_ids = background_emissions_in_system_boundary(cycle)
58
54
 
59
55
  def run(input: dict):
60
56
  input_term = input.get('input').get('term')
@@ -1,9 +1,9 @@
1
1
  from hestia_earth.schema import IndicatorMethodTier, TermTermType
2
2
  from hestia_earth.utils.tools import flatten, safe_parse_float
3
- from hestia_earth.utils.emission import emissions_in_system_boundary
4
3
 
5
4
  from hestia_earth.models.log import logRequirements, logShouldRun
6
5
  from hestia_earth.models.utils import _omit
6
+ from hestia_earth.models.utils.emission import background_emissions_in_system_boundary
7
7
  from hestia_earth.models.utils.indicator import _new_indicator
8
8
  from hestia_earth.models.utils.background_emissions import no_gap_filled_background_emissions
9
9
  from hestia_earth.models.utils.term import get_lookup_value
@@ -54,10 +54,7 @@ def _default_value(input: dict):
54
54
 
55
55
 
56
56
  def _run_input(impact: dict):
57
- required_resourceUse_term_ids = [
58
- id for id in emissions_in_system_boundary(TermTermType.RESOURCEUSE)
59
- if id.endswith('InputsProduction')
60
- ]
57
+ required_resourceUse_term_ids = background_emissions_in_system_boundary(impact, TermTermType.RESOURCEUSE)
61
58
 
62
59
  def run(input: dict):
63
60
  input_term = input.get('input').get('term')
@@ -109,10 +109,11 @@ def _map_group_emissions(group_id: str, required_emission_term_ids: list, emissi
109
109
  missing_emissions = list(filter(lambda v: v not in emission_ids, emissions))
110
110
  return {
111
111
  'group-id': group_id,
112
+ 'is-group-in-system-boundary': group_id in required_emission_term_ids,
112
113
  'total-emissions': len(emissions),
113
114
  'included-emissions': len(included_emissions),
114
115
  'missing-emissions': '-'.join(missing_emissions),
115
- 'is-valid': len(emissions) == len(included_emissions)
116
+ 'has-all-emissions': len(emissions) == len(included_emissions)
116
117
  }
117
118
 
118
119
 
@@ -140,7 +141,10 @@ def _filter_emissions(cycle: dict):
140
141
  for group_id in group_ids
141
142
  ]
142
143
  # only keep groups that have all emissions present in the Cycle
143
- valid_groups = list(filter(lambda group: group.get('is-valid'), emissions_per_group))
144
+ valid_groups = list(filter(lambda group: all([
145
+ group.get('has-all-emissions'),
146
+ group.get('is-group-in-system-boundary')
147
+ ]), emissions_per_group))
144
148
  valid_group_ids = set([v.get('group-id') for v in valid_groups])
145
149
 
146
150
  # finally, only return emissions which groups are valid
@@ -283,7 +287,7 @@ def _should_run(cycle: dict):
283
287
  # log failed emissions to show in the logs
284
288
  for group in emissions_per_group:
285
289
  emission_id = group.get('group-id')
286
- if not group.get('is-valid') or not should_run:
290
+ if not group.get('has-all-emissions') or not should_run:
287
291
  logRequirements(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY, emission_id=emission_id,
288
292
  **group,
289
293
  **_omit(seed_input, 'input'),
@@ -2,6 +2,7 @@ from hestia_earth.utils.tools import list_sum
2
2
  from hestia_earth.utils.emission import cycle_emissions_in_system_boundary
3
3
 
4
4
  from hestia_earth.models.log import logRequirements, logShouldRun
5
+ from hestia_earth.models.utils import _include
5
6
  from hestia_earth.models.utils.impact_assessment import get_product, convert_value_from_cycle
6
7
  from hestia_earth.models.utils.indicator import _new_indicator
7
8
  from . import MODEL
@@ -44,11 +45,8 @@ def _indicator(impact_assessment: dict, product: dict):
44
45
 
45
46
  if len(emission.get('inputs', [])):
46
47
  indicator['inputs'] = emission['inputs']
47
- if emission.get('operation'):
48
- indicator['operation'] = emission.get('operation')
49
- if emission.get('transformation'):
50
- indicator['transformation'] = emission.get('transformation')
51
- return indicator
48
+
49
+ return indicator | _include(emission, ['operation', 'transformation', 'country', 'key'])
52
50
  return run
53
51
 
54
52
 
@@ -57,12 +57,16 @@ RETURNS = {
57
57
  "statsDefinition": "simulated",
58
58
  "observations": "",
59
59
  "dates": "",
60
+ "depthUpper": "",
61
+ "depthLower": "",
60
62
  "methodClassification": "tier 1 model"
61
63
  }]
62
64
  }
63
65
  TERM_ID = 'biocharOrganicCarbonPerHa'
64
66
 
65
67
  _ITERATIONS = 1000
68
+ _DEPTH_UPPER = 0
69
+ _DEPTH_LOWER = 30
66
70
  _METHOD_CLASSIFICATION = MeasurementMethodClassification.TIER_1_MODEL.value
67
71
  _STATS_DEFINITION = MeasurementStatsDefinition.SIMULATED.value
68
72
 
@@ -172,7 +176,7 @@ def _compile_inventory(
172
176
  cycle_data = {
173
177
  cycle.get("@id"): {
174
178
  "biochar_nodes": filter_list_term_type(cycle.get("inputs", []), TermTermType.BIOCHAR),
175
- **{field: cycle.get(field) for field in COPY_FIELDS}
179
+ **{k: v for k in COPY_FIELDS if (v := cycle.get(k)) is not None}
176
180
  } for cycle in cycles
177
181
  }
178
182
 
@@ -201,7 +205,7 @@ def _compile_inventory(
201
205
  [
202
206
  {
203
207
  "total_oc": total_oc.get(id, 0),
204
- **{field: data.get(field) for field in COPY_FIELDS}
208
+ **data
205
209
  } for id, data in cycle_data.items()
206
210
  ],
207
211
  include_spillovers=True
@@ -427,9 +431,11 @@ def _measurement(
427
431
  "statsDefinition": statsDefinition,
428
432
  "observations": observations,
429
433
  "dates": dates,
434
+ "depthUpper": _DEPTH_UPPER,
435
+ "depthLower": _DEPTH_LOWER,
430
436
  "methodClassification": _METHOD_CLASSIFICATION
431
437
  }
432
438
  measurement = _new_measurement(TERM_ID, MODEL) | {
433
- key: value for key, value in update_dict.items() if value
439
+ key: value for key, value in update_dict.items() if value is not None
434
440
  }
435
441
  return measurement
@@ -78,9 +78,7 @@ def _emission(
78
78
  min: list[float] = None,
79
79
  max: list[float] = None,
80
80
  statsDefinition: str = None,
81
- observations: list[int] = None,
82
- start_date: str,
83
- end_date: str
81
+ observations: list[int] = None
84
82
  ) -> dict:
85
83
  """
86
84
  Create an emission node based on the provided value and method tier.
@@ -108,8 +106,6 @@ def _emission(
108
106
  "max": max,
109
107
  "statsDefinition": statsDefinition,
110
108
  "observations": observations,
111
- "startDate": start_date,
112
- "endDate": end_date,
113
109
  "methodTier": method_tier.value,
114
110
  }
115
111
  emission = _new_emission(term_id, MODEL) | {
@@ -69,9 +69,7 @@ def _emission(
69
69
  min: list[float] = None,
70
70
  max: list[float] = None,
71
71
  statsDefinition: str = None,
72
- observations: list[int] = None,
73
- start_date: str,
74
- end_date: str
72
+ observations: list[int] = None
75
73
  ) -> dict:
76
74
  """
77
75
  Create an emission node based on the provided value and method tier.
@@ -99,8 +97,6 @@ def _emission(
99
97
  "max": max,
100
98
  "statsDefinition": statsDefinition,
101
99
  "observations": observations,
102
- "startDate": start_date,
103
- "endDate": end_date,
104
100
  "methodTier": method_tier.value,
105
101
  "depth": _DEPTH_LOWER
106
102
  }
@@ -2,7 +2,7 @@
2
2
  Utilities for calculating CO2 emissions based on changes in carbon stocks (e.g., `organicCarbonPerHa`,
3
3
  `aboveGroundBiomass` and `belowGroundBiomass`).
4
4
  """
5
- from datetime import datetime, timedelta
5
+ from datetime import datetime
6
6
  from enum import Enum
7
7
  from functools import reduce
8
8
  from itertools import product
@@ -1506,8 +1506,6 @@ def create_run_function(
1506
1506
  new_emission_func(
1507
1507
  term_id=emission_term_id,
1508
1508
  method_tier=_get_emission_method(total_emission),
1509
- start_date=_get_emission_start_date(total_emission, cycle_start_date),
1510
- end_date=_get_emission_end_date(total_emission, cycle_end_date),
1511
1509
  **calc_descriptive_stats(
1512
1510
  total_emission.value,
1513
1511
  EmissionStatsDefinition.SIMULATED,
@@ -1532,33 +1530,3 @@ def get_zero_emission(year):
1532
1530
  def _get_emission_method(emission: CarbonStockChangeEmission):
1533
1531
  method = emission.method
1534
1532
  return method if isinstance(method, EmissionMethodTier) else EmissionMethodTier.TIER_1
1535
-
1536
-
1537
- def _get_emission_start_date(emission: CarbonStockChangeEmission, cycle_start_date: str) -> str:
1538
- cycle_datetime = safe_parse_date(_gapfill_datestr(cycle_start_date))
1539
- emission_datetime = safe_parse_date(emission.start_date)
1540
-
1541
- should_run = (
1542
- cycle_datetime and emission_datetime
1543
- and cycle_datetime < emission_datetime # If the cycle starts before the emission, add a `startDate`
1544
- )
1545
-
1546
- return (
1547
- (emission_datetime + timedelta(seconds=1)).strftime(DatestrFormat.YEAR_MONTH_DAY.value) if should_run
1548
- else None
1549
- )
1550
-
1551
-
1552
- def _get_emission_end_date(emission: CarbonStockChangeEmission, cycle_end_date: str) -> str:
1553
- cycle_datetime = safe_parse_date(_gapfill_datestr(cycle_end_date, DatestrGapfillMode.END))
1554
- emission_datetime = safe_parse_date(emission.end_date)
1555
-
1556
- should_run = (
1557
- cycle_datetime and emission_datetime
1558
- and cycle_datetime > emission_datetime # If the cycle ends after the emission, add an `endDate`
1559
- )
1560
-
1561
- return (
1562
- emission_datetime.strftime(DatestrFormat.YEAR_MONTH_DAY.value) if should_run
1563
- else None
1564
- )