hestia-earth-models 0.59.5__py3-none-any.whl → 0.59.7__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 (46) hide show
  1. hestia_earth/models/cache_sites.py +6 -8
  2. hestia_earth/models/cycle/animal/milkYield.py +86 -0
  3. hestia_earth/models/cycle/endDate.py +50 -0
  4. hestia_earth/models/cycle/inorganicFertiliser.py +3 -2
  5. hestia_earth/models/cycle/milkYield.py +8 -3
  6. hestia_earth/models/cycle/pre_checks/__init__.py +1 -2
  7. hestia_earth/models/cycle/siteDuration.py +1 -1
  8. hestia_earth/models/cycle/startDate.py +42 -0
  9. hestia_earth/models/emepEea2019/nh3ToAirInorganicFertiliser.py +9 -6
  10. hestia_earth/models/faostat2018/liveweightPerHead.py +77 -41
  11. hestia_earth/models/faostat2018/product/price.py +43 -57
  12. hestia_earth/models/faostat2018/utils.py +10 -2
  13. hestia_earth/models/geospatialDatabase/utils.py +0 -1
  14. hestia_earth/models/haversineFormula/transport/distance.py +6 -3
  15. hestia_earth/models/ipcc2006/n2OToAirInorganicFertiliserIndirect.py +1 -1
  16. hestia_earth/models/ipcc2019/co2ToAirLimeHydrolysis.py +1 -1
  17. hestia_earth/models/ipcc2019/co2ToAirUreaHydrolysis.py +2 -7
  18. hestia_earth/models/ipcc2019/organicCarbonPerHa.py +26 -6
  19. hestia_earth/models/ipcc2019/pastureGrass.py +2 -1
  20. hestia_earth/models/linkedImpactAssessment/__init__.py +3 -3
  21. hestia_earth/models/mocking/search-results.json +244 -232
  22. hestia_earth/models/schmidt2007/h2SToAirWasteTreatment.py +58 -0
  23. hestia_earth/models/site/management.py +3 -1
  24. hestia_earth/models/site/pre_checks/cache_geospatialDatabase.py +2 -2
  25. hestia_earth/models/utils/__init__.py +4 -1
  26. hestia_earth/models/utils/animalProduct.py +6 -4
  27. hestia_earth/models/utils/blank_node.py +3 -2
  28. hestia_earth/models/utils/product.py +9 -1
  29. hestia_earth/models/utils/property.py +2 -1
  30. hestia_earth/models/utils/site.py +7 -4
  31. hestia_earth/models/version.py +1 -1
  32. {hestia_earth_models-0.59.5.dist-info → hestia_earth_models-0.59.7.dist-info}/METADATA +1 -1
  33. {hestia_earth_models-0.59.5.dist-info → hestia_earth_models-0.59.7.dist-info}/RECORD +44 -38
  34. tests/models/cycle/animal/test_milkYield.py +43 -0
  35. tests/models/cycle/test_endDate.py +24 -0
  36. tests/models/cycle/test_startDate.py +22 -0
  37. tests/models/faostat2018/product/test_price.py +40 -48
  38. tests/models/faostat2018/test_liveweightPerHead.py +106 -42
  39. tests/models/ipcc2019/test_organicCarbonPerHa.py +102 -39
  40. tests/models/schmidt2007/test_h2SToAirWasteTreatment.py +45 -0
  41. tests/models/utils/test_blank_node.py +71 -3
  42. hestia_earth/models/cycle/pre_checks/startDate.py +0 -52
  43. tests/models/cycle/pre_checks/test_startDate.py +0 -44
  44. {hestia_earth_models-0.59.5.dist-info → hestia_earth_models-0.59.7.dist-info}/LICENSE +0 -0
  45. {hestia_earth_models-0.59.5.dist-info → hestia_earth_models-0.59.7.dist-info}/WHEEL +0 -0
  46. {hestia_earth_models-0.59.5.dist-info → hestia_earth_models-0.59.7.dist-info}/top_level.txt +0 -0
@@ -12,10 +12,9 @@ from hestia_earth.models.log import debugMissingLookup, debugValues, logRequirem
12
12
  from hestia_earth.models.utils.constant import Units
13
13
  from hestia_earth.models.utils.currency import DEFAULT_CURRENCY
14
14
  from hestia_earth.models.utils.crop import FAOSTAT_PRODUCTION_LOOKUP_COLUMN, get_crop_grouping_faostat_production
15
- from hestia_earth.models.utils.animalProduct import (
16
- FAO_LOOKUP_COLUMN, get_animalProduct_grouping_fao, get_animalProduct_lookup_value
17
- )
15
+ from hestia_earth.models.utils.animalProduct import FAO_LOOKUP_COLUMN, get_animalProduct_grouping_fao
18
16
  from hestia_earth.models.utils.product import convert_product_to_unit
17
+ from ..utils import get_liveAnimal_to_animalProduct_id
19
18
  from .. import MODEL
20
19
 
21
20
  REQUIREMENTS = {
@@ -39,10 +38,11 @@ LOOKUPS = {
39
38
  "@doc": "Depending on the primary product [termType](https://hestia.earth/schema/Product#term)",
40
39
  "crop": "cropGroupingFaostatProduction",
41
40
  "region-crop-cropGroupingFaostatProduction-price": "use value from above",
42
- "liveAnimal": "primaryMeatProductFAO",
43
- "animalProduct": ["animalProductGroupingFAOEquivalent", "animalProductGroupingFAO", "liveAnimal"],
41
+ "liveAnimal": ["primaryMeatProductFaoPriceTermId"],
42
+ "animalProduct": ["animalProductGroupingFAOEquivalent", "animalProductGroupingFAO"],
44
43
  "region-animalProduct-animalProductGroupingFAO-price": "use value from above",
45
- "region-animalProduct-animalProductGroupingFAO-averageColdCarcassWeight": "use value from above"
44
+ "region-animalProduct-animalProductGroupingFAO-averageColdCarcassWeight": "use value from above",
45
+ "region-animalProduct-animalProductGroupingFAO-weightPerItem": "use value from above"
46
46
  }
47
47
  MODEL_KEY = 'price'
48
48
  LOOKUP_NAME = {
@@ -53,7 +53,9 @@ LOOKUP_GROUPING = {
53
53
  TermTermType.CROP.value: get_crop_grouping_faostat_production,
54
54
  TermTermType.ANIMALPRODUCT.value: get_animalProduct_grouping_fao
55
55
  }
56
- LOOKUP_WEIGHT = 'region-animalProduct-animalProductGroupingFAO-averageColdCarcassWeight.csv'
56
+ LOOKUP_UNITS_NUMBER = {
57
+ TermTermType.ANIMALPRODUCT.value: f"region-{TermTermType.ANIMALPRODUCT.value}-{FAO_LOOKUP_COLUMN}-weightPerItem.csv"
58
+ }
57
59
 
58
60
 
59
61
  def _term_grouping(term: dict): return LOOKUP_GROUPING.get(term.get('termType'), lambda *_: None)(MODEL, term)
@@ -65,8 +67,7 @@ def _lookup_data(
65
67
  lookup_name = lookup_name or LOOKUP_NAME.get(term_type)
66
68
  lookup = download_lookup(lookup_name)
67
69
  data = get_table_value(lookup, 'termid', country_id, column_name(grouping))
68
- debugMissingLookup(lookup_name, 'termid', country_id, grouping, data,
69
- model=MODEL, term=term_id, key=MODEL_KEY)
70
+ debugMissingLookup(lookup_name, 'termid', country_id, grouping, data, model=MODEL, term=term_id, key=MODEL_KEY)
70
71
  price = extract_grouped_data(data, str(year)) or extract_grouped_data(data, 'Average_price_per_tonne')
71
72
  return safe_parse_float(price, None)
72
73
 
@@ -76,58 +77,46 @@ def _product(product: dict, value: float):
76
77
  return product | {'currency': DEFAULT_CURRENCY, MODEL_KEY: round(value, 4)}
77
78
 
78
79
 
79
- def _get_animalProductId(term_id: str):
80
- lookup_name = 'liveAnimal.csv'
81
- lookup = download_lookup(lookup_name)
82
- value = get_table_value(lookup, 'termid', term_id, column_name(LOOKUPS.get('liveAnimal')))
83
- debugMissingLookup(lookup_name, 'termid', term_id, LOOKUPS.get('liveAnimal'), value,
84
- model=MODEL, term=term_id, key=MODEL_KEY)
85
- return value
86
-
87
-
88
80
  def _get_liveAnimal_lookup_values(cycle: dict, product: dict, country_id: str, year: int = None):
89
81
  term_id = product.get('term', {}).get('@id')
90
- animal_product = _get_animalProductId(term_id)
91
- groupingFAO = get_animalProduct_lookup_value(MODEL, animal_product, FAO_LOOKUP_COLUMN) if animal_product else None
82
+ animal_product = get_liveAnimal_to_animalProduct_id(term_id, LOOKUPS['liveAnimal'][0], key=MODEL_KEY)
83
+ groupingFAO = _term_grouping({'termType': TermTermType.ANIMALPRODUCT.value, '@id': animal_product})
92
84
 
93
85
  # one live animal can be linked to many animal product, hence go one by one until we have a match
94
86
  if groupingFAO:
95
- average_carcass_weight = _lookup_data(animal_product, groupingFAO, country_id, year, lookup_name=LOOKUP_WEIGHT)
96
- price = _lookup_data(term_id, groupingFAO, country_id, year, term_type=TermTermType.ANIMALPRODUCT.value)
87
+ price_per_ton_liveweight = _lookup_data(
88
+ term_id, groupingFAO, country_id, year, term_type=TermTermType.ANIMALPRODUCT.value
89
+ )
97
90
  debugValues(cycle, model=MODEL, term=term_id, key=MODEL_KEY, by='liveAnimal',
98
91
  animal_product=animal_product,
99
- groupingFAO=f"'{groupingFAO}'",
100
- average_carcass_weight_hg=average_carcass_weight,
101
- price_per_ton=price)
102
- if price and average_carcass_weight:
92
+ price_per_ton_liveweight=price_per_ton_liveweight,
93
+ groupingFAO=f"'{groupingFAO}'")
94
+ if price_per_ton_liveweight:
103
95
  # price is per 1000kg, divide by 1000 to go back to USD/kg
104
- # average_carcass_weight is in hg, divide by 10 to go back to kg
105
- return (animal_product, price / 1000, average_carcass_weight / 10)
106
- return (None, None, None)
96
+ return (animal_product, price_per_ton_liveweight / 1000)
97
+ return (None, None)
107
98
 
108
99
 
109
100
  def _run_by_liveAnimal(cycle: dict, product: dict, country_id: str, year: int = None):
110
101
  term_id = product.get('term', {}).get('@id')
111
- animal_product, price, carcass_weight = _get_liveAnimal_lookup_values(cycle, product, country_id, year)
102
+ animal_product_id, price_per_kg_liveweight = _get_liveAnimal_lookup_values(cycle, product, country_id, year)
112
103
 
113
- animal_product = download_hestia(animal_product)
114
- price_per_carcass_weight = convert_product_to_unit({
104
+ animal_product = download_hestia(animal_product_id)
105
+ price_per_head = convert_product_to_unit({
106
+ **product,
115
107
  'term': animal_product,
116
- 'value': [price]
117
- }, Units.KG_COLD_CARCASS_WEIGHT) if price else None
118
- should_run = all([price_per_carcass_weight, carcass_weight])
119
- value = price_per_carcass_weight * carcass_weight if should_run else None
108
+ 'value': [price_per_kg_liveweight]
109
+ }, Units.HEAD) if price_per_kg_liveweight else None
120
110
 
121
111
  logRequirements(cycle, model=MODEL, term=term_id, key=MODEL_KEY, by='liveAnimal',
122
- price_from_lookup=price,
123
- carcass_weight_kg=carcass_weight,
124
- price_per_carcass_weight=price_per_carcass_weight,
125
112
  year=year,
126
- price=value)
113
+ price_per_kg_liveweight=price_per_kg_liveweight,
114
+ price_per_head=price_per_head)
127
115
 
116
+ should_run = all([animal_product, price_per_head])
128
117
  logShouldRun(cycle, MODEL, term_id, should_run, key=MODEL_KEY, by='liveAnimal')
129
118
 
130
- return _product(product, value) if value is not None else None
119
+ return _product(product, price_per_head) if price_per_head is not None else None
131
120
 
132
121
 
133
122
  def _should_run_liveAnimal(product: dict):
@@ -138,6 +127,7 @@ def _run_by_country(cycle: dict, product: dict, country_id: str, year: int = Non
138
127
  product_term = product.get('term', {})
139
128
  term_id = product_term.get('@id')
140
129
  term_type = product_term.get('termType')
130
+ term_units = product_term.get('units')
141
131
 
142
132
  has_yield = len(product.get('value', [])) > 0
143
133
  not_already_set = MODEL_KEY not in product.keys()
@@ -148,44 +138,40 @@ def _run_by_country(cycle: dict, product: dict, country_id: str, year: int = Non
148
138
  should_run = all([not_already_set, has_yield, grouping])
149
139
  value = _lookup_data(term_id, grouping, country_id, year, term_type=term_type) if should_run else None
150
140
 
141
+ # if units is number instead of kg, need to convert to number first
142
+ conversion_to_number = safe_parse_float(get_table_value(
143
+ download_lookup(LOOKUP_UNITS_NUMBER.get(term_type)), 'termid', country_id, column_name(grouping)
144
+ ), 1) if term_units == Units.NUMBER.value else 1
145
+
151
146
  logRequirements(cycle, model=MODEL, term=term_id, key=MODEL_KEY, by='country',
152
147
  has_yield=has_yield,
153
148
  not_already_set=not_already_set,
154
- groupingFAO=f"'{grouping}'",
155
149
  year=year,
156
- price_per_ton=value)
150
+ price_per_ton=value,
151
+ groupingFAO=f"'{grouping}'",
152
+ conversion_to_number=conversion_to_number)
157
153
 
158
154
  logShouldRun(cycle, MODEL, term_id, should_run, key=MODEL_KEY, by='country')
159
155
 
160
156
  # divide by 1000 to convert price per tonne to kg
161
- return _product(product, value / 1000) if value is not None else None
157
+ return _product(product, value / 1000 * conversion_to_number) if value is not None else None
162
158
 
163
159
 
164
160
  def _should_run_product(product: dict):
165
161
  return product.get(MODEL_KEY) is None
166
162
 
167
163
 
168
- def _should_run(cycle: dict):
169
- country_id = cycle.get('site', {}).get('country', {}).get('@id')
170
-
171
- logRequirements(cycle, model=MODEL, key=MODEL_KEY,
172
- country_id=country_id)
173
-
174
- should_run = all([country_id])
175
- logShouldRun(cycle, MODEL, None, should_run, key=MODEL_KEY)
176
- return should_run, country_id
177
-
178
-
179
164
  def run(cycle: dict):
180
- should_run_by_country, country_id = _should_run(cycle)
165
+ country_id = cycle.get('site', {}).get('country', {}).get('@id')
181
166
  end_date = safe_parse_date(cycle.get('endDate'))
182
167
  year = end_date.year if end_date else None
168
+
183
169
  products = list(filter(_should_run_product, cycle.get('products', [])))
184
170
  return non_empty_list([
185
171
  (
186
172
  (
187
173
  (_run_by_liveAnimal(cycle, p, country_id, year) if _should_run_liveAnimal(p) else None)
188
174
  or _run_by_country(cycle, p, country_id, year)
189
- ) if should_run_by_country else None
175
+ ) if country_id else None
190
176
  ) for p in products
191
177
  ])
@@ -3,7 +3,7 @@ from hestia_earth.utils.api import download_hestia
3
3
  from hestia_earth.utils.lookup import download_lookup, get_table_value, column_name, extract_grouped_data_closest_date
4
4
  from hestia_earth.utils.tools import safe_parse_float
5
5
 
6
- from hestia_earth.models.log import logger
6
+ from hestia_earth.models.log import logger, debugMissingLookup
7
7
  from hestia_earth.models.utils.animalProduct import (
8
8
  FAO_LOOKUP_COLUMN, FAO_EQUIVALENT_LOOKUP_COLUMN, get_animalProduct_lookup_value
9
9
  )
@@ -13,9 +13,17 @@ from . import MODEL
13
13
  LOOKUP_PREFIX = f"{TermTermType.REGION.value}-{TermTermType.ANIMALPRODUCT.value}-{FAO_LOOKUP_COLUMN}"
14
14
 
15
15
 
16
+ def get_liveAnimal_to_animalProduct_id(product_term_id: str, column: str, **log_args):
17
+ lookup_name = 'liveAnimal.csv'
18
+ lookup = download_lookup(lookup_name)
19
+ value = get_table_value(lookup, 'termid', product_term_id, column_name(column))
20
+ debugMissingLookup(lookup_name, 'termid', product_term_id, column, value, model=MODEL, **log_args)
21
+ return value
22
+
23
+
16
24
  def product_equivalent_value(product: dict, year: int, country: str):
17
25
  term_id = product.get('term', {}).get('@id')
18
- fao_product_id = get_animalProduct_lookup_value(MODEL, term_id, FAO_EQUIVALENT_LOOKUP_COLUMN)
26
+ fao_product_id = get_animalProduct_lookup_value(MODEL, term_id, FAO_EQUIVALENT_LOOKUP_COLUMN) or term_id
19
27
  grouping = get_animalProduct_lookup_value(MODEL, fao_product_id, FAO_LOOKUP_COLUMN)
20
28
 
21
29
  if not grouping or not fao_product_id:
@@ -175,7 +175,6 @@ def download(term: str, site: dict, data: dict, only_coordinates=False) -> dict:
175
175
  }
176
176
  ]
177
177
  }
178
- print(query)
179
178
  value = _parse_run_query(term, query)
180
179
 
181
180
  if value is None:
@@ -27,8 +27,11 @@ REQUIREMENTS = {
27
27
  }
28
28
  }
29
29
  RETURNS = {
30
- "Transport": [{
31
- "distance": ""
30
+ "Input": [{
31
+ "transport": [{
32
+ "@type": "Transport",
33
+ "distance": ""
34
+ }]
32
35
  }]
33
36
  }
34
37
  MODEL_KEY = 'distance'
@@ -98,7 +101,7 @@ def _should_run(cycle: dict):
98
101
  # can only run if the site country has centroid coordinates
99
102
  logRequirements(cycle, model=MODEL, term=None, key=MODEL_KEY,
100
103
  latitude=country.get('latitude'),
101
- longitude=country.get('latitude'),
104
+ longitude=country.get('longitude'),
102
105
  has_inputs_transport=len(inputs) > 0)
103
106
  should_run = all([country.get('latitude'), country.get('latitude'), len(inputs) > 0])
104
107
  logShouldRun(cycle, MODEL, None, should_run, key=MODEL_KEY)
@@ -55,7 +55,7 @@ def _run(cycle: dict, N_total: float):
55
55
  nh3_n=nh3_n,
56
56
  nox_n=nox_n)
57
57
  value = COEFF_NH3NOX_N2O * (
58
- sum_values([nh3_n, nox_n]) or N_total * 0.2
58
+ sum_values([nh3_n, nox_n]) or N_total * 0.1
59
59
  ) + COEFF_NO3_N2O * (
60
60
  no3_n or N_total * 0.3
61
61
  )
@@ -11,7 +11,7 @@ from . import MODEL
11
11
 
12
12
  REQUIREMENTS = {
13
13
  "Cycle": {
14
- "completeness.soilAmendments": "",
14
+ "completeness.soilAmendment": "",
15
15
  "inputs": [{
16
16
  "@type": "Input",
17
17
  "value": "",
@@ -11,13 +11,8 @@ from . import MODEL
11
11
 
12
12
  REQUIREMENTS = {
13
13
  "Cycle": {
14
- "or": {
15
- "completeness.fertiliser": "",
16
- "inputs": [{"@type": "Input", "value": "", "term.termType": "inorganicFertiliser"}]
17
- },
18
- "optional": {
19
- "inputs": [{"@type": "Input", "value": "", "term.@id": "inorganicNitrogenFertiliserUnspecifiedKgN"}]
20
- }
14
+ "completeness.fertiliser": "",
15
+ "inputs": [{"@type": "Input", "value": "", "term.termType": "inorganicFertiliser"}]
21
16
  }
22
17
  }
23
18
  RETURNS = {
@@ -2,7 +2,13 @@
2
2
  The IPCC model for estimating soil organic carbon stock changes in the 0 - 30cm depth interval due to management
3
3
  changes. This model combines the Tier 1 & Tier 2 methodologies. It first tries to run Tier 2 (only on croplands
4
4
  remaining croplands). If Tier 2 cannot run, it will try to run Tier 1 (for croplands remaining croplands and for
5
- grasslands remaining grasslands). Source:
5
+ grasslands remaining grasslands).
6
+
7
+ More information on this model, including data requirements **and** recommendations, tier methodologies, and examples,
8
+ can be found in the
9
+ [Hestia SOC wiki](https://gitlab.com/hestia-earth/hestia-engine-models/-/wikis/Soil-organic-carbon-modelling).
10
+
11
+ Source:
6
12
  [IPCC 2019, Vol. 4, Chapter 10](https://www.ipcc-nggip.iges.or.jp/public/2019rf/pdf/4_Volume4/19R_V4_Ch05_Cropland.pdf).
7
13
  """
8
14
  from enum import Enum
@@ -253,6 +259,11 @@ The number of years required for soil organic carbon to reach equilibrium after
253
259
  a change in land use, management regime or carbon input regime.
254
260
  """
255
261
 
262
+ EXCLUDED_ECO_CLIMATE_ZONES_TIER_1 = {
263
+ 5, # Polar Moist
264
+ 6 # Polar Dry
265
+ }
266
+
256
267
  VALID_SITE_TYPES_TIER_1 = [
257
268
  SiteSiteType.CROPLAND.value,
258
269
  SiteSiteType.FOREST.value,
@@ -281,7 +292,7 @@ def _measurement(year: int, value: float, method_classification: str) -> dict:
281
292
  dict
282
293
  A valid Hestia `Measurement` node, see: https://www.hestia.earth/schema/Measurement.
283
294
  """
284
- measurement = _new_measurement(TERM_ID, MODEL)
295
+ measurement = _new_measurement(TERM_ID)
285
296
  measurement["value"] = [value]
286
297
  measurement["dates"] = [f"{year}-12-31"]
287
298
  measurement["depthUpper"] = DEPTH_UPPER
@@ -846,7 +857,7 @@ def _calc_water_factor(
846
857
  float
847
858
  The water effect on decomposition for a given month, dimensionless, between `0.2129` and `1.5`.
848
859
  """
849
- mappet = min(1.25, precipitation / pet)
860
+ mappet = min(1.25, precipitation / pet) if pet else 1.25
850
861
  return 0.775 if is_irrigated else 0.2129 + (water_factor_slope * (mappet)) - (0.2413 * pow(mappet, 2))
851
862
 
852
863
 
@@ -937,7 +948,8 @@ def _calc_average_nitrogen_content_of_organic_carbon_sources(
937
948
  weighted_values = [
938
949
  c.mass * (c.nitrogen_content if c.nitrogen_content else default_nitrogen_content) for c in carbon_sources
939
950
  ]
940
- return sum(weighted_values) / total_weight if total_weight > 0 else default_nitrogen_content
951
+ should_run = total_weight > 0
952
+ return sum(weighted_values) / total_weight if should_run else 0
941
953
 
942
954
 
943
955
  def _calc_average_lignin_content_of_organic_carbon_sources(
@@ -963,7 +975,8 @@ def _calc_average_lignin_content_of_organic_carbon_sources(
963
975
  weighted_values = [
964
976
  c.mass * (c.lignin_content if c.lignin_content else default_lignin_content) for c in carbon_sources
965
977
  ]
966
- return sum(weighted_values) / total_weight if total_weight > 0 else default_lignin_content
978
+ should_run = total_weight > 0
979
+ return sum(weighted_values) / total_weight if should_run else 0
967
980
 
968
981
 
969
982
  # --- TIER 2 FUNCTIONS: ACTIVE SUB-POOL SOC STOCK ---
@@ -3570,7 +3583,7 @@ def _should_run_tier_1(
3570
3583
  Determines whether there is sufficient data in the inventory and keyword args to run the tier 1 model.
3571
3584
  """
3572
3585
  return all([
3573
- eco_climate_zone and eco_climate_zone > 0,
3586
+ eco_climate_zone and eco_climate_zone not in EXCLUDED_ECO_CLIMATE_ZONES_TIER_1,
3574
3587
  soc_ref and soc_ref > 0,
3575
3588
  any(year for year, group in inventory.items() if group.get(_InventoryKey.SHOULD_RUN_TIER_1))
3576
3589
  ])
@@ -3724,9 +3737,16 @@ def _should_run_inventory_year_tier_2(group: dict) -> bool:
3724
3737
  }
3725
3738
  )
3726
3739
 
3740
+ carbon_input_data_complete = all([
3741
+ group.get(_InventoryKey.CARBON_INPUT, 0) > 0,
3742
+ group.get(_InventoryKey.N_CONTENT, 0) > 0,
3743
+ group.get(_InventoryKey.LIGNIN_CONTENT, 0) > 0,
3744
+ ])
3745
+
3727
3746
  return all([
3728
3747
  not group.get(_InventoryKey.IS_PADDY_RICE),
3729
3748
  monthly_data_complete,
3749
+ carbon_input_data_complete,
3730
3750
  all(key in group.keys() for key in REQUIRED_KEYS_TIER_2),
3731
3751
  ])
3732
3752
 
@@ -497,7 +497,8 @@ def _sum_values(values): return sum([value for term_id, value in values])
497
497
  def _calculate_GE(cycle: dict, meanDE: float, system: dict):
498
498
  animals = [
499
499
  a for a in cycle.get('animals', []) if all([
500
- a.get('value') and a.get('referencePeriod') == AnimalReferencePeriod.AVERAGE.value
500
+ a.get('value'),
501
+ a.get('referencePeriod') == AnimalReferencePeriod.AVERAGE.value
501
502
  ])
502
503
  ]
503
504
 
@@ -75,7 +75,7 @@ def _run_emission(cycle: dict, term_id: str, data: dict):
75
75
 
76
76
  details = values.get('details', {})
77
77
  logRequirements(cycle, model=model, term=term_id,
78
- values=log_as_table([{'impact_assessment_id': key} | value for key, value in details.items()]))
78
+ values=log_as_table([{'impact-assessment-id': key} | value for key, value in details.items()]))
79
79
 
80
80
  logShouldRun(cycle, model, term_id, True, methodTier=TIER,
81
81
  input=term.get('@id'),
@@ -138,8 +138,8 @@ def _group_inputs(group: dict, values: tuple):
138
138
  grouped_inputs['value'] = grouped_inputs['value'] + (emission_value * input_value)
139
139
  # for logging
140
140
  grouped_inputs['details'][input.get('impactAssessment', {}).get('@id')] = {
141
- 'emission_value': emission_value,
142
- 'input_value': input_value
141
+ 'emission-value': emission_value,
142
+ 'input-value': input_value
143
143
  }
144
144
  group[emission_term_id][input_group_key] = grouped_inputs
145
145
  return group