hestia-earth-models 0.59.6__py3-none-any.whl → 0.60.0__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 (49) hide show
  1. hestia_earth/models/cache_sites.py +8 -8
  2. hestia_earth/models/cycle/siteDuration.py +1 -1
  3. hestia_earth/models/emepEea2019/nh3ToAirInorganicFertiliser.py +9 -6
  4. hestia_earth/models/faostat2018/product/price.py +14 -3
  5. hestia_earth/models/geospatialDatabase/utils.py +0 -1
  6. hestia_earth/models/ipcc2019/animal/__init__.py +0 -0
  7. hestia_earth/models/ipcc2019/animal/pastureGrass.py +298 -0
  8. hestia_earth/models/ipcc2019/co2ToAirLimeHydrolysis.py +1 -1
  9. hestia_earth/models/ipcc2019/{co2ToAirSoilCarbonStockChangeManagementChange.py → co2ToAirSoilOrganicCarbonStockChangeManagementChange.py} +2 -2
  10. hestia_earth/models/ipcc2019/co2ToAirUreaHydrolysis.py +2 -7
  11. hestia_earth/models/ipcc2019/organicCarbonPerHa.py +7 -2
  12. hestia_earth/models/ipcc2019/pastureGrass.py +73 -447
  13. hestia_earth/models/ipcc2019/pastureGrass_utils.py +415 -0
  14. hestia_earth/models/mocking/search-results.json +215 -207
  15. hestia_earth/models/site/pre_checks/cache_geospatialDatabase.py +14 -2
  16. hestia_earth/models/utils/completeness.py +17 -14
  17. hestia_earth/models/utils/feedipedia.py +23 -23
  18. hestia_earth/models/utils/property.py +4 -1
  19. hestia_earth/models/utils/site.py +7 -4
  20. hestia_earth/models/version.py +1 -1
  21. {hestia_earth_models-0.59.6.dist-info → hestia_earth_models-0.60.0.dist-info}/LICENSE +1 -1
  22. {hestia_earth_models-0.59.6.dist-info → hestia_earth_models-0.60.0.dist-info}/METADATA +1 -1
  23. {hestia_earth_models-0.59.6.dist-info → hestia_earth_models-0.60.0.dist-info}/RECORD +49 -44
  24. tests/models/cycle/animal/input/test_properties.py +3 -1
  25. tests/models/cycle/animal/test_properties.py +4 -2
  26. tests/models/cycle/input/test_properties.py +3 -1
  27. tests/models/cycle/product/test_properties.py +2 -1
  28. tests/models/cycle/test_coldCarcassWeightPerHead.py +1 -0
  29. tests/models/cycle/test_coldDressedCarcassWeightPerHead.py +1 -0
  30. tests/models/cycle/test_energyContentLowerHeatingValue.py +1 -0
  31. tests/models/cycle/test_feedConversionRatio.py +10 -0
  32. tests/models/cycle/test_readyToCookWeightPerHead.py +1 -0
  33. tests/models/faostat2018/product/test_price.py +15 -3
  34. tests/models/ipcc2006/test_n2OToAirCropResidueDecompositionDirect.py +4 -1
  35. tests/models/ipcc2019/animal/__init__.py +0 -0
  36. tests/models/ipcc2019/animal/test_pastureGrass.py +45 -0
  37. tests/models/ipcc2019/test_ch4ToAirEntericFermentation.py +32 -8
  38. tests/models/ipcc2019/{test_co2ToAirSoilCarbonStockChangeManagementChange.py → test_co2ToAirSoilOrganicCarbonStockChangeManagementChange.py} +1 -1
  39. tests/models/ipcc2019/test_n2OToAirCropResidueDecompositionDirect.py +6 -1
  40. tests/models/ipcc2019/test_n2OToAirInorganicFertiliserDirect.py +6 -1
  41. tests/models/ipcc2019/test_n2OToAirOrganicFertiliserDirect.py +6 -1
  42. tests/models/ipcc2019/test_organicCarbonPerHa.py +95 -40
  43. tests/models/ipcc2019/test_pastureGrass.py +32 -8
  44. tests/models/pooreNemecek2018/test_excretaKgN.py +5 -0
  45. tests/models/pooreNemecek2018/test_excretaKgVs.py +5 -0
  46. tests/models/pooreNemecek2018/test_no3ToGroundwaterSoilFlux.py +1 -0
  47. tests/models/test_cache_sites.py +22 -7
  48. {hestia_earth_models-0.59.6.dist-info → hestia_earth_models-0.60.0.dist-info}/WHEEL +0 -0
  49. {hestia_earth_models-0.59.6.dist-info → hestia_earth_models-0.60.0.dist-info}/top_level.txt +0 -0
@@ -34,7 +34,7 @@ def _cache_results(results: list, collections: list, index: int):
34
34
  return cache_site_results(results[start:end], collections)
35
35
 
36
36
 
37
- def _run_values(sites: list, param_type: ParamType, rasters: list = [], vectors: list = [], years: list = []):
37
+ def _run_values(sites: list, param_type: ParamType, rasters: list = [], vectors: list = [], years: list = None):
38
38
  param_values = list(map(_VALUE_AS_PARAM.get(param_type), sites))
39
39
  # unique list
40
40
  param_values = list(set(param_values)) if param_type == ParamType.GADM_IDS else list({
@@ -66,11 +66,9 @@ def _run_values(sites: list, param_type: ParamType, rasters: list = [], vectors:
66
66
  } | ({CACHE_AREA_SIZE: area_size} if area_size is not None else {})
67
67
  return {
68
68
  **site,
69
- CACHE_KEY: {
70
- **cached_value(site),
71
- CACHE_YEARS_KEY: years,
72
- CACHE_GEOSPATIAL_KEY: cached_data
73
- }
69
+ CACHE_KEY: (
70
+ cached_value(site) | {CACHE_GEOSPATIAL_KEY: cached_data}
71
+ ) | ({CACHE_YEARS_KEY: years} if years else {})
74
72
  }
75
73
 
76
74
  return reduce(lambda prev, curr: prev + [_process_site(curr)], sites, [])
@@ -114,7 +112,7 @@ def _group_sites(sites: dict):
114
112
  }
115
113
 
116
114
 
117
- def run(sites: list, years: list, include_region: bool = False):
115
+ def run(sites: list, years: list = None, include_region: bool = False, years_only: bool = False):
118
116
  """
119
117
  Run all queries at once for the list of provided Sites.
120
118
  Note: Earth Engine needs to be initiliased with `init_gee()` before running this function.
@@ -128,8 +126,10 @@ def run(sites: list, years: list, include_region: bool = False):
128
126
  include_region : bool
129
127
  Prefecth region IDs.
130
128
  This will cache region-level data and will make the request slower. Only use if needed.
129
+ years_only : bool
130
+ Run only the collections that depend on the years (if provided).
131
131
  """
132
- rasters, vectors = list_collections(years, include_region=include_region)
132
+ rasters, vectors = list_collections(years, include_region, years_only)
133
133
 
134
134
  filtered_data = _group_sites(sites)
135
135
 
@@ -9,7 +9,7 @@ from . import MODEL
9
9
 
10
10
  REQUIREMENTS = {
11
11
  "Cycle": {
12
- "cycleDuration": "365",
12
+ "cycleDuration": "> 0",
13
13
  "none": {
14
14
  "otherSites": ""
15
15
  }
@@ -17,14 +17,17 @@ from . import MODEL
17
17
 
18
18
  REQUIREMENTS = {
19
19
  "Cycle": {
20
- "or": {
21
- "inputs": [{
20
+ "completeness.fertiliser": "True",
21
+ "inputs": [
22
+ {
22
23
  "@type": "Input",
23
24
  "value": "",
24
- "term.termType": ["inorganicFertiliser", "inorganicNitrogenFertiliserUnspecifiedKgN"]
25
- }],
26
- "completeness.fertiliser": "True"
27
- },
25
+ "term.termType": "inorganicFertiliser",
26
+ "optional": {
27
+ "properties": [{"@type": "Property", "value": "", "term.@id": "nitrogenContent"}]
28
+ }
29
+ }
30
+ ],
28
31
  "site": {
29
32
  "@type": "Site",
30
33
  "country": {"@type": "Term", "termType": "region"},
@@ -41,7 +41,8 @@ LOOKUPS = {
41
41
  "liveAnimal": ["primaryMeatProductFaoPriceTermId"],
42
42
  "animalProduct": ["animalProductGroupingFAOEquivalent", "animalProductGroupingFAO"],
43
43
  "region-animalProduct-animalProductGroupingFAO-price": "use value from above",
44
- "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"
45
46
  }
46
47
  MODEL_KEY = 'price'
47
48
  LOOKUP_NAME = {
@@ -52,6 +53,9 @@ LOOKUP_GROUPING = {
52
53
  TermTermType.CROP.value: get_crop_grouping_faostat_production,
53
54
  TermTermType.ANIMALPRODUCT.value: get_animalProduct_grouping_fao
54
55
  }
56
+ LOOKUP_UNITS_NUMBER = {
57
+ TermTermType.ANIMALPRODUCT.value: f"region-{TermTermType.ANIMALPRODUCT.value}-{FAO_LOOKUP_COLUMN}-weightPerItem.csv"
58
+ }
55
59
 
56
60
 
57
61
  def _term_grouping(term: dict): return LOOKUP_GROUPING.get(term.get('termType'), lambda *_: None)(MODEL, term)
@@ -123,6 +127,7 @@ def _run_by_country(cycle: dict, product: dict, country_id: str, year: int = Non
123
127
  product_term = product.get('term', {})
124
128
  term_id = product_term.get('@id')
125
129
  term_type = product_term.get('termType')
130
+ term_units = product_term.get('units')
126
131
 
127
132
  has_yield = len(product.get('value', [])) > 0
128
133
  not_already_set = MODEL_KEY not in product.keys()
@@ -133,17 +138,23 @@ def _run_by_country(cycle: dict, product: dict, country_id: str, year: int = Non
133
138
  should_run = all([not_already_set, has_yield, grouping])
134
139
  value = _lookup_data(term_id, grouping, country_id, year, term_type=term_type) if should_run else None
135
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
+
136
146
  logRequirements(cycle, model=MODEL, term=term_id, key=MODEL_KEY, by='country',
137
147
  has_yield=has_yield,
138
148
  not_already_set=not_already_set,
139
149
  year=year,
140
150
  price_per_ton=value,
141
- groupingFAO=f"'{grouping}'")
151
+ groupingFAO=f"'{grouping}'",
152
+ conversion_to_number=conversion_to_number)
142
153
 
143
154
  logShouldRun(cycle, MODEL, term_id, should_run, key=MODEL_KEY, by='country')
144
155
 
145
156
  # divide by 1000 to convert price per tonne to kg
146
- 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
147
158
 
148
159
 
149
160
  def _should_run_product(product: dict):
@@ -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:
File without changes
@@ -0,0 +1,298 @@
1
+ """
2
+ Full Grass Consumption
3
+
4
+ This model estimates the energetic requirements of ruminants and can be used to estimate the amount of grass they graze.
5
+ Source:
6
+ [IPCC 2019, Vol.4, Chapter 10](https://www.ipcc-nggip.iges.or.jp/public/2019rf/pdf/4_Volume4/19R_V4_Ch10_Livestock.pdf).
7
+ """
8
+ from hestia_earth.schema import TermTermType
9
+ from hestia_earth.utils.model import filter_list_term_type
10
+ from hestia_earth.utils.tools import list_sum
11
+
12
+ from hestia_earth.models.log import logRequirements, logShouldRun, debugValues
13
+ from hestia_earth.models.utils.input import _new_input
14
+ from hestia_earth.models.utils.term import get_wool_terms, get_lookup_value
15
+ from hestia_earth.models.utils.completeness import _is_term_type_complete, _is_term_type_incomplete
16
+ from hestia_earth.models.utils.property import get_node_property
17
+ from .. import MODEL
18
+ from ..pastureGrass_utils import (
19
+ practice_input_id,
20
+ should_run_practice,
21
+ calculate_meanDE,
22
+ calculate_meanECHHV,
23
+ calculate_REM,
24
+ calculate_REG,
25
+ calculate_NEfeed,
26
+ product_wool_energy,
27
+ get_animals,
28
+ get_animal_values
29
+ )
30
+
31
+ REQUIREMENTS = {
32
+ "Cycle": {
33
+ "completeness.animalFeed": "True",
34
+ "completeness.animalPopulation": "True",
35
+ "completeness.freshForage": "False",
36
+ "site": {
37
+ "@type": "Site",
38
+ "siteType": "permanent pasture"
39
+ },
40
+ "practices": [{
41
+ "@type": "Practice",
42
+ "value": "",
43
+ "term.@id": "pastureGrass",
44
+ "key": {
45
+ "@type": "Term",
46
+ "term.termType": "landCover"
47
+ }
48
+ }],
49
+ "animals": [{
50
+ "@type": "Animal",
51
+ "value": "> 0",
52
+ "term.termType": "liveAnimal",
53
+ "referencePeriod": "average",
54
+ "properties": [{
55
+ "@type": "Property",
56
+ "value": "",
57
+ "term.@id": [
58
+ "liveweightPerHead",
59
+ "weightAtMaturity"
60
+ ]
61
+ }],
62
+ "optional": {
63
+ "properties": [{
64
+ "@type": "Property",
65
+ "value": "",
66
+ "term.@id": [
67
+ "hoursWorkedPerDay",
68
+ "pregnancyRateTotal",
69
+ "animalsPerBirth"
70
+ ]
71
+ }],
72
+ "inputs": [{
73
+ "@type": "Input",
74
+ "term.units": "kg",
75
+ "value": "> 0",
76
+ "optional": {
77
+ "properties": [{
78
+ "@type": "Property",
79
+ "value": "",
80
+ "term.@id": ["neutralDetergentFibreContent", "energyContentHigherHeatingValue"]
81
+ }]
82
+ }
83
+ }],
84
+ "practices": [{
85
+ "@type": "Practice",
86
+ "value": "",
87
+ "term.termType": "animalManagement",
88
+ "properties": [{
89
+ "@type": "Property",
90
+ "value": "",
91
+ "term.@id": "fatContent"
92
+ }]
93
+ }]
94
+ }
95
+ }],
96
+ "none": {
97
+ "inputs": [{
98
+ "@type": "Input",
99
+ "term.units": "kg",
100
+ "value": "> 0",
101
+ "isAnimalFeed": "True"
102
+ }]
103
+ },
104
+ "optional": {
105
+ "products": [{
106
+ "@type": "Product",
107
+ "value": "",
108
+ "term.@id": "animalProduct"
109
+ }]
110
+ }
111
+ }
112
+ }
113
+ LOOKUPS = {
114
+ "animalManagement": [
115
+ "mjKgEvMilkIpcc2019"
116
+ ],
117
+ "animalProduct": ["mjKgEvWoolNetEnergyWoolIpcc2019", "allowedLiveAnimalTermIds"],
118
+ "liveAnimal": [
119
+ "ipcc2019AnimalTypeGrouping",
120
+ "mjDayKgCfiNetEnergyMaintenanceIpcc2019",
121
+ "ratioCPregnancyNetEnergyPregnancyIpcc2019",
122
+ "ratioCNetEnergyGrowthCattleBuffaloIpcc2019",
123
+ "mjKgABNetEnergyGrowthSheepGoatsIpcc2019",
124
+ "isWoolProducingAnimal"
125
+ ],
126
+ "system-liveAnimal-activityCoefficient-ipcc2019": "using animal term @id",
127
+ "crop-property": ["energyDigestibilityRuminants", "energyContentHigherHeatingValue"],
128
+ "crop": "grazedPastureGrassInputId",
129
+ "forage-property": ["energyDigestibilityRuminants", "energyContentHigherHeatingValue"],
130
+ "landCover": "grazedPastureGrassInputId"
131
+ }
132
+ RETURNS = {
133
+ "Animal": [{
134
+ "Input": [{
135
+ "@type": "Input",
136
+ "term.termType": ["crop", "forage"],
137
+ "value": ""
138
+ }]
139
+ }]
140
+ }
141
+ MODEL_KEY = 'animal/pastureGrass'
142
+
143
+
144
+ def _input(term_id: str, value: float):
145
+ node = _new_input(term_id, MODEL)
146
+ node['value'] = [value]
147
+ return node
148
+
149
+
150
+ def _sum_liveWeightPerHead(animals: list):
151
+ return list_sum([
152
+ animal.get('value', 0) * get_node_property(animal, 'liveweightPerHead', False).get('value', 0)
153
+ for animal in animals
154
+ ])
155
+
156
+
157
+ def _isNEwool_animal(animal: dict):
158
+ value = get_lookup_value(animal.get('term', {}), 'isWoolProducingAnimal', model=MODEL, model_key=MODEL_KEY)
159
+ return not (not value)
160
+
161
+
162
+ def _is_NEwool_product(product: dict, animal: dict):
163
+ animal_term_ids = get_lookup_value(product, 'allowedLiveAnimalTermIds', model=MODEL, model_key=MODEL_KEY).split(';')
164
+ return animal.get('term', {}).get('@id') in animal_term_ids
165
+
166
+
167
+ def calculate_NEwool(cycle: dict, animal: dict, products: list, total_weight: float) -> float:
168
+ term_id = animal.get('term', {}).get('@id')
169
+
170
+ wool_products = [p for p in products if _is_NEwool_product(p.get('term', {}), animal)]
171
+ total_energy = list_sum([
172
+ list_sum(product.get('value', [])) * product_wool_energy(product) for product in wool_products
173
+ ])
174
+ animal_weight = _sum_liveWeightPerHead([animal])
175
+
176
+ debugValues(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
177
+ total_energy=total_energy,
178
+ animal_liveWeightPerHead=animal_weight,
179
+ total_liveWeightPerHead=total_weight)
180
+
181
+ return total_energy * animal_weight/total_weight
182
+
183
+
184
+ def _calculate_GE(
185
+ cycle: dict, animal: dict, REM: float, REG: float, NEwool: float, system: dict
186
+ ) -> float:
187
+ term_id = animal.get('term', {}).get('@id')
188
+
189
+ NEm, NEa, NEl, NEwork, NEp, NEg = get_animal_values(cycle, animal, system)
190
+
191
+ NEm_feed, NEg_feed = calculate_NEfeed(animal)
192
+ debugValues(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
193
+ NEm_feed=NEm_feed,
194
+ NEg_feed=NEg_feed)
195
+
196
+ return (NEm + NEa + NEl + NEwork + NEp - NEm_feed)/REM + (NEg + NEwool - NEg_feed)/REG
197
+
198
+
199
+ def _run_practice(cycle: dict, GE: float, meanECHHV: float):
200
+ def run(practice: dict):
201
+ key = practice.get('key', {})
202
+ key_id = key.get('@id')
203
+ input_term_id = practice_input_id(practice)
204
+ value = (GE / meanECHHV) * (list_sum(practice.get('value', [0])) / 100)
205
+
206
+ logRequirements(cycle, model=MODEL, term=input_term_id, model_key=MODEL_KEY,
207
+ GE=GE,
208
+ meanECHHV=meanECHHV,
209
+ key_id=key_id)
210
+
211
+ logShouldRun(cycle, MODEL, input_term_id, True, model_key=MODEL_KEY)
212
+
213
+ return _input(input_term_id, value)
214
+
215
+ return run
216
+
217
+
218
+ def _run_animal(cycle: dict, meanDE: float, meanECHHV: float, system: dict, practices: list):
219
+ REM = calculate_REM(meanDE)
220
+ REG = calculate_REG(meanDE)
221
+
222
+ wool_term_ids = get_wool_terms()
223
+ # list of animal product
224
+ wool_products = [p for p in cycle.get('products', []) if p.get('term', {}).get('@id') in wool_term_ids]
225
+ animals = list(filter(_isNEwool_animal, cycle.get('animals', [])))
226
+ total_liveWeightPerHead = _sum_liveWeightPerHead(animals)
227
+
228
+ def run(animal: dict):
229
+ term_id = animal.get('term', {}).get('@id')
230
+
231
+ NEwool = calculate_NEwool(cycle, animal, wool_products, total_liveWeightPerHead) if (
232
+ total_liveWeightPerHead > 0
233
+ ) else 0
234
+ GE = (_calculate_GE(cycle, animal, REM, REG, NEwool, system) / (meanDE/100)) if all([REM, REG]) else 0
235
+
236
+ debugValues(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
237
+ REM=REM,
238
+ REG=REG,
239
+ NEwool=NEwool,
240
+ GE=GE,
241
+ meanDE=meanDE)
242
+
243
+ inputs = list(map(_run_practice(cycle, GE, meanECHHV), practices))
244
+ return animal | {
245
+ 'inputs': animal.get('inputs', []) + inputs
246
+ }
247
+
248
+ return run
249
+
250
+
251
+ def _run(cycle: dict, meanDE: float, meanECHHV: float, system: dict, practices: list):
252
+ animals = get_animals(cycle)
253
+ return list(map(_run_animal(cycle, meanDE, meanECHHV, system, practices), animals))
254
+
255
+
256
+ def _should_run(cycle: dict, practices: dict):
257
+ systems = filter_list_term_type(cycle.get('practices', []), TermTermType.SYSTEM)
258
+ animalFeed_complete = _is_term_type_complete(cycle, 'animalFeed')
259
+ animalPopulation_complete = _is_term_type_complete(cycle, 'animalPopulation')
260
+ freshForage_incomplete = _is_term_type_incomplete(cycle, 'freshForage')
261
+ all_animals_have_value = all([a.get('value', 0) > 0 for a in cycle.get('animals', [])])
262
+
263
+ no_cycle_inputs_feed = all([not input.get('isAnimalFeed', False) for input in cycle.get('inputs', [])])
264
+
265
+ meanDE = calculate_meanDE(practices)
266
+ meanECHHV = calculate_meanECHHV(practices)
267
+
268
+ should_run = all([
269
+ animalFeed_complete,
270
+ animalPopulation_complete,
271
+ freshForage_incomplete,
272
+ no_cycle_inputs_feed,
273
+ all_animals_have_value,
274
+ len(systems) > 0,
275
+ len(practices) > 0,
276
+ meanDE > 0,
277
+ meanECHHV > 0
278
+ ])
279
+
280
+ for term_id in [MODEL_KEY] + [practice_input_id(p) for p in practices]:
281
+ logRequirements(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
282
+ term_type_animalFeed_complete=animalFeed_complete,
283
+ term_type_animalPopulation_complete=animalPopulation_complete,
284
+ term_type_freshForage_incomplete=freshForage_incomplete,
285
+ no_cycle_inputs_feed=no_cycle_inputs_feed,
286
+ all_animals_have_value=all_animals_have_value,
287
+ meanDE=meanDE,
288
+ meanECHHV=meanECHHV)
289
+
290
+ logShouldRun(cycle, MODEL, term_id, should_run, model_key=MODEL_KEY)
291
+
292
+ return should_run, meanDE, meanECHHV, systems[0] if systems else None
293
+
294
+
295
+ def run(cycle: dict):
296
+ practices = list(filter(should_run_practice(cycle), cycle.get('practices', [])))
297
+ should_run, meanDE, meanECHHV, system = _should_run(cycle, practices)
298
+ return _run(cycle, meanDE, meanECHHV, system, practices) if should_run else []
@@ -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": "",
@@ -50,7 +50,7 @@ RETURNS = {
50
50
  "depth": "30"
51
51
  }]
52
52
  }
53
- TERM_ID = 'co2ToAirSoilCarbonStockChangeManagementChange'
53
+ TERM_ID = 'co2ToAirSoilOrganicCarbonStockChangeManagementChange'
54
54
 
55
55
  DEPTH_UPPER = 0
56
56
  DEPTH_LOWER = 30
@@ -101,7 +101,7 @@ MEASUREMENT_METHOD_RANKING = [
101
101
  ]
102
102
  """
103
103
  A ranking of `MeasurementMethodClassification`s from weakest to strongest used to determine the `EmissionMethodTier` of
104
- the `co2ToAirSoilCarbonStockChangeManagementChange` output.
104
+ the `co2ToAirSoilOrganicCarbonStockChangeManagementChange` output.
105
105
 
106
106
  The `EmissionMethodTier` should be based on the weakest `MeasurementMethodClassification` between the current SOC and
107
107
  previous SOC.
@@ -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 = {
@@ -259,6 +259,11 @@ The number of years required for soil organic carbon to reach equilibrium after
259
259
  a change in land use, management regime or carbon input regime.
260
260
  """
261
261
 
262
+ EXCLUDED_ECO_CLIMATE_ZONES_TIER_1 = {
263
+ 5, # Polar Moist
264
+ 6 # Polar Dry
265
+ }
266
+
262
267
  VALID_SITE_TYPES_TIER_1 = [
263
268
  SiteSiteType.CROPLAND.value,
264
269
  SiteSiteType.FOREST.value,
@@ -287,7 +292,7 @@ def _measurement(year: int, value: float, method_classification: str) -> dict:
287
292
  dict
288
293
  A valid Hestia `Measurement` node, see: https://www.hestia.earth/schema/Measurement.
289
294
  """
290
- measurement = _new_measurement(TERM_ID, MODEL)
295
+ measurement = _new_measurement(TERM_ID)
291
296
  measurement["value"] = [value]
292
297
  measurement["dates"] = [f"{year}-12-31"]
293
298
  measurement["depthUpper"] = DEPTH_UPPER
@@ -3578,7 +3583,7 @@ def _should_run_tier_1(
3578
3583
  Determines whether there is sufficient data in the inventory and keyword args to run the tier 1 model.
3579
3584
  """
3580
3585
  return all([
3581
- eco_climate_zone and eco_climate_zone > 0,
3586
+ eco_climate_zone and eco_climate_zone not in EXCLUDED_ECO_CLIMATE_ZONES_TIER_1,
3582
3587
  soc_ref and soc_ref > 0,
3583
3588
  any(year for year, group in inventory.items() if group.get(_InventoryKey.SHOULD_RUN_TIER_1))
3584
3589
  ])