hestia-earth-models 0.62.0__py3-none-any.whl → 0.62.2__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 (68) hide show
  1. hestia_earth/models/blonkConsultants2016/utils.py +3 -2
  2. hestia_earth/models/cycle/coldCarcassWeightPerHead.py +4 -2
  3. hestia_earth/models/cycle/coldDressedCarcassWeightPerHead.py +2 -2
  4. hestia_earth/models/cycle/concentrateFeed.py +3 -3
  5. hestia_earth/models/cycle/feedConversionRatio/feedConversionRatioNitrogen.py +2 -1
  6. hestia_earth/models/cycle/post_checks/__init__.py +3 -2
  7. hestia_earth/models/cycle/post_checks/otherSites.py +40 -0
  8. hestia_earth/models/cycle/pre_checks/__init__.py +2 -1
  9. hestia_earth/models/cycle/pre_checks/otherSites.py +42 -0
  10. hestia_earth/models/cycle/pre_checks/site.py +1 -1
  11. hestia_earth/models/cycle/readyToCookWeightPerHead.py +2 -2
  12. hestia_earth/models/ecoinventV3AndEmberClimate/utils.py +1 -1
  13. hestia_earth/models/emepEea2019/utils.py +4 -3
  14. hestia_earth/models/geospatialDatabase/heavyWinterPrecipitation.py +1 -1
  15. hestia_earth/models/ipcc2019/animal/pastureGrass.py +53 -43
  16. hestia_earth/models/ipcc2019/co2ToAirSoilOrganicCarbonStockChangeManagementChange.py +30 -4
  17. hestia_earth/models/ipcc2019/n2OToAirExcretaDirect.py +6 -2
  18. hestia_earth/models/ipcc2019/n2OToAirExcretaIndirect.py +1 -1
  19. hestia_earth/models/ipcc2019/n2OToAirInorganicFertiliserDirect.py +1 -1
  20. hestia_earth/models/ipcc2019/n2OToAirInorganicFertiliserIndirect.py +1 -1
  21. hestia_earth/models/ipcc2019/n2OToAirOrganicFertiliserIndirect.py +1 -1
  22. hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_1_utils.py +4 -2
  23. hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_2_utils.py +210 -40
  24. hestia_earth/models/ipcc2019/organicCarbonPerHa_utils.py +2 -6
  25. hestia_earth/models/ipcc2019/pastureGrass.py +44 -42
  26. hestia_earth/models/ipcc2019/pastureGrass_utils.py +46 -92
  27. hestia_earth/models/mocking/search-results.json +378 -234
  28. hestia_earth/models/schererPfister2015/utils.py +2 -2
  29. hestia_earth/models/site/brackishWater.py +1 -1
  30. hestia_earth/models/site/flowingWater.py +1 -1
  31. hestia_earth/models/site/freshWater.py +1 -1
  32. hestia_earth/models/site/management.py +79 -38
  33. hestia_earth/models/site/pre_checks/cache_sources.py +9 -13
  34. hestia_earth/models/site/salineWater.py +1 -1
  35. hestia_earth/models/stehfestBouwman2006/n2OToAirCropResidueDecompositionDirect.py +12 -2
  36. hestia_earth/models/stehfestBouwman2006/n2OToAirExcretaDirect.py +12 -2
  37. hestia_earth/models/stehfestBouwman2006/n2OToAirInorganicFertiliserDirect.py +11 -1
  38. hestia_earth/models/stehfestBouwman2006/n2OToAirOrganicFertiliserDirect.py +11 -1
  39. hestia_earth/models/stehfestBouwman2006/noxToAirCropResidueDecomposition.py +12 -2
  40. hestia_earth/models/stehfestBouwman2006/noxToAirExcreta.py +12 -2
  41. hestia_earth/models/stehfestBouwman2006/noxToAirInorganicFertiliser.py +11 -1
  42. hestia_earth/models/stehfestBouwman2006/noxToAirOrganicFertiliser.py +11 -1
  43. hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirCropResidueDecomposition.py +12 -2
  44. hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirExcreta.py +12 -2
  45. hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirInorganicFertiliser.py +11 -1
  46. hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirOrganicFertiliser.py +11 -1
  47. hestia_earth/models/utils/blank_node.py +144 -110
  48. hestia_earth/models/utils/constant.py +2 -0
  49. hestia_earth/models/utils/lookup.py +19 -6
  50. hestia_earth/models/utils/property.py +6 -6
  51. hestia_earth/models/utils/site.py +7 -0
  52. hestia_earth/models/utils/source.py +1 -1
  53. hestia_earth/models/utils/term.py +21 -1
  54. hestia_earth/models/version.py +1 -1
  55. {hestia_earth_models-0.62.0.dist-info → hestia_earth_models-0.62.2.dist-info}/METADATA +2 -2
  56. {hestia_earth_models-0.62.0.dist-info → hestia_earth_models-0.62.2.dist-info}/RECORD +68 -63
  57. tests/models/cycle/post_checks/test_otherSites.py +15 -0
  58. tests/models/cycle/pre_checks/test_otherSites.py +21 -0
  59. tests/models/ipcc2019/test_co2ToAirSoilOrganicCarbonStockChangeManagementChange.py +5 -3
  60. tests/models/ipcc2019/test_organicCarbonPerHa.py +10 -20
  61. tests/models/ipcc2019/test_organicCarbonPerHa_tier_2_utils.py +0 -8
  62. tests/models/site/pre_checks/test_cache_sources.py +6 -10
  63. tests/models/site/test_management.py +192 -4
  64. tests/models/utils/test_blank_node.py +0 -281
  65. tests/models/utils/test_lookup.py +10 -0
  66. {hestia_earth_models-0.62.0.dist-info → hestia_earth_models-0.62.2.dist-info}/LICENSE +0 -0
  67. {hestia_earth_models-0.62.0.dist-info → hestia_earth_models-0.62.2.dist-info}/WHEEL +0 -0
  68. {hestia_earth_models-0.62.0.dist-info → hestia_earth_models-0.62.2.dist-info}/top_level.txt +0 -0
@@ -25,5 +25,6 @@ def get_emission_factor(term_id: str, cycle: dict, factor: str):
25
25
  data = safe_parse_float(value, None)
26
26
  # fallback to site.siteType data if possible
27
27
  return data if data is not None else safe_parse_float(
28
- extract_grouped_data(
29
- get_table_value(lookup, 'termid', country_id, column_name('NONE')), site.get('siteType')), None)
28
+ extract_grouped_data(get_table_value(lookup, 'termid', country_id, column_name('NONE')), site.get('siteType')),
29
+ None
30
+ )
@@ -42,8 +42,10 @@ def _property(value: float):
42
42
 
43
43
 
44
44
  def _run(product: dict):
45
- liveweightPerHead = get_node_property_value(MODEL, product, 'liveweightPerHead')
46
- processingConversion = get_node_property_value(MODEL, product, 'processingConversionLiveweightToColdCarcassWeight')
45
+ liveweightPerHead = get_node_property_value(MODEL, product, 'liveweightPerHead', term=TERM_ID)
46
+ processingConversion = get_node_property_value(
47
+ MODEL, product, 'processingConversionLiveweightToColdCarcassWeight', term=TERM_ID
48
+ )
47
49
  value = liveweightPerHead * processingConversion if all([liveweightPerHead, processingConversion]) else None
48
50
  prop = _property(value) if value else None
49
51
  return {**product, 'properties': product.get('properties', []) + [prop]} if prop else None
@@ -46,9 +46,9 @@ def _property(value: float):
46
46
 
47
47
 
48
48
  def _run(product: dict):
49
- liveweightPerHead = get_node_property_value(MODEL, product, 'liveweightPerHead')
49
+ liveweightPerHead = get_node_property_value(MODEL, product, 'liveweightPerHead', term=TERM_ID)
50
50
  processingConversion = get_node_property_value(
51
- MODEL, product, 'processingConversionLiveweightToColdDressedCarcassWeight'
51
+ MODEL, product, 'processingConversionLiveweightToColdDressedCarcassWeight', term=TERM_ID
52
52
  )
53
53
  value = liveweightPerHead * processingConversion if all([liveweightPerHead, processingConversion]) else None
54
54
  prop = _property(value) if value else None
@@ -79,7 +79,7 @@ def _calculate_value(cycle: dict, product: dict, inputs: list, property_id: str,
79
79
  def _calculate_default_value(cycle: dict, product: dict, inputs: list, property_id: str):
80
80
  values = [(
81
81
  i.get('term', {}).get('@id'),
82
- get_node_property_value(MODEL, i, property_id),
82
+ get_node_property_value(MODEL, i, property_id, term=TERM_ID),
83
83
  list_sum(i.get('value', []))
84
84
  ) for i in inputs]
85
85
  return _calculate_value(cycle, product, inputs, property_id, values)
@@ -88,8 +88,8 @@ def _calculate_default_value(cycle: dict, product: dict, inputs: list, property_
88
88
  def _calculate_N_value(cycle: dict, product: dict, inputs: list, property_id: str):
89
89
  values = [(
90
90
  i.get('term', {}).get('@id'),
91
- get_node_property_value(MODEL, i, property_id) or
92
- get_node_property_value(MODEL, i, 'crudeProteinContent', default=0) * 0.16,
91
+ get_node_property_value(MODEL, i, property_id, term=TERM_ID) or
92
+ get_node_property_value(MODEL, i, 'crudeProteinContent', default=0, term=TERM_ID) * 0.16,
93
93
  list_sum(i.get('value', []))
94
94
  ) for i in inputs]
95
95
  return _calculate_value(cycle, product, inputs, property_id, values)
@@ -72,5 +72,6 @@ TERM_ID = 'feedConversionRatioNitrogen'
72
72
  def run(cycle: dict, feed: float):
73
73
  inputs = get_feed_inputs(cycle)
74
74
  return list_sum(non_empty_list([
75
- get_node_property_value_converted(MODEL, input, 'crudeProteinContent', default=0) / 6.25 for input in inputs
75
+ get_node_property_value_converted(MODEL, input, 'crudeProteinContent', default=0, term=TERM_ID) / 6.25
76
+ for input in inputs
76
77
  ]))
@@ -2,14 +2,15 @@ from os.path import dirname, abspath
2
2
  import sys
3
3
 
4
4
  from hestia_earth.models.utils import _run_in_serie
5
- from . import cache, site
5
+ from . import cache, site, otherSites
6
6
 
7
7
  CURRENT_DIR = dirname(abspath(__file__)) + '/'
8
8
  sys.path.append(CURRENT_DIR)
9
9
 
10
10
  MODELS = [
11
11
  cache.run,
12
- site.run
12
+ site.run,
13
+ otherSites.run
13
14
  ]
14
15
 
15
16
 
@@ -0,0 +1,40 @@
1
+ """
2
+ Post Checks Other Sites
3
+
4
+ This model is run only if the [pre model](../pre_checks/cycle.md) has been run before.
5
+ This model will restore the `cycle.otherSites` as a list of "linked node"
6
+ (i.e. it will be set with only `@type`, `@id` and `name` keys).
7
+ """
8
+ from hestia_earth.utils.model import linked_node
9
+
10
+ REQUIREMENTS = {
11
+ "Cycle": {
12
+ "otherSites": [{
13
+ "@type": "Site",
14
+ "@id": ""
15
+ }]
16
+ }
17
+ }
18
+ RETURNS = {
19
+ "Cycle": {
20
+ "otherSites": [{"@type": "Site"}]
21
+ }
22
+ }
23
+ MODEL_KEY = 'otherSites'
24
+
25
+
26
+ def _run_site(site: dict): return linked_node(site)
27
+
28
+
29
+ def _should_run_site(site: dict): return site.get('@id') is not None
30
+
31
+
32
+ def _should_run(cycle: dict): return len(cycle.get(MODEL_KEY, [])) > 0
33
+
34
+
35
+ def run(cycle: dict):
36
+ return cycle | (
37
+ ({
38
+ MODEL_KEY: [_run_site(site) if _should_run_site(site) else site for site in cycle.get(MODEL_KEY, [])]
39
+ }) if _should_run(cycle) else {}
40
+ )
@@ -2,12 +2,13 @@ from os.path import dirname, abspath
2
2
  import sys
3
3
 
4
4
  from hestia_earth.models.utils import _run_in_serie
5
- from . import site, cache_sources
5
+ from . import site, cache_sources, otherSites
6
6
 
7
7
  CURRENT_DIR = dirname(abspath(__file__)) + '/'
8
8
  sys.path.append(CURRENT_DIR)
9
9
 
10
10
  MODELS = [
11
+ otherSites.run,
11
12
  site.run,
12
13
  cache_sources.run
13
14
  ]
@@ -0,0 +1,42 @@
1
+ """
2
+ Pre Checks Other Sites
3
+
4
+ Some Cycle models need a full version of the linked [Site](https://hestia.earth/schema/Site) to run.
5
+ This model will fetch the complete version of the [Cycle Sites](https://hestia.earth/schema/Cycle#otherSites)
6
+ and include them.
7
+ """
8
+ from hestia_earth.schema import SchemaType
9
+
10
+ from hestia_earth.models.utils import _load_calculated_node
11
+
12
+ REQUIREMENTS = {
13
+ "Cycle": {
14
+ "otherSites": [{
15
+ "@type": "Site",
16
+ "@id": ""
17
+ }]
18
+ }
19
+ }
20
+ RETURNS = {
21
+ "Cycle": {
22
+ "otherSites": [{"@type": "Site"}]
23
+ }
24
+ }
25
+ MODEL_KEY = 'otherSites'
26
+
27
+
28
+ def _run_site(site: dict): return _load_calculated_node(site, SchemaType.SITE)
29
+
30
+
31
+ def _should_run_site(site: dict): return site.get('@id') is not None
32
+
33
+
34
+ def _should_run(cycle: dict): return len(cycle.get(MODEL_KEY, [])) > 0
35
+
36
+
37
+ def run(cycle: dict):
38
+ return cycle | (
39
+ ({
40
+ MODEL_KEY: [_run_site(site) if _should_run_site(site) else site for site in cycle.get(MODEL_KEY, [])]
41
+ }) if _should_run(cycle) else {}
42
+ )
@@ -2,7 +2,7 @@
2
2
  Pre Checks Site
3
3
 
4
4
  Some Cycle models need a full version of the linked [Site](https://hestia.earth/schema/Site) to run.
5
- This model will fetch the complete version of the [Site](https://hestia.earth/schema/Site) and include it.
5
+ This model will fetch the complete version of the [Cycle Site](https://hestia.earth/schema/Cycle#site) and include it.
6
6
  """
7
7
  from hestia_earth.schema import SchemaType
8
8
 
@@ -42,9 +42,9 @@ def _property(value: float):
42
42
 
43
43
 
44
44
  def _run(product: dict):
45
- liveweightPerHead = get_node_property_value(MODEL, product, 'liveweightPerHead')
45
+ liveweightPerHead = get_node_property_value(MODEL, product, 'liveweightPerHead', term=TERM_ID)
46
46
  processingConversion = get_node_property_value(
47
- MODEL, product, 'processingConversionLiveweightToReadyToCookWeight'
47
+ MODEL, product, 'processingConversionLiveweightToReadyToCookWeight', term=TERM_ID
48
48
  )
49
49
  value = liveweightPerHead * processingConversion if all([liveweightPerHead, processingConversion]) else None
50
50
  prop = _property(value) if value else None
@@ -33,7 +33,7 @@ def _extract_emission_value(value_iter: Any) -> Union[float, None]:
33
33
  value_list = list(value_iter)
34
34
  try:
35
35
  if len(list(value_list)) > 0 and len(list(value_list)[0]) > 1:
36
- return safe_parse_float(list(value_list)[0][1])
36
+ return safe_parse_float(list(value_list)[0][1], None)
37
37
  except ValueError:
38
38
  return None
39
39
 
@@ -1,7 +1,7 @@
1
1
  from hestia_earth.schema import TermTermType
2
2
  from hestia_earth.utils.model import filter_list_term_type
3
3
  from hestia_earth.utils.lookup import extract_grouped_data
4
- from hestia_earth.utils.tools import list_sum, safe_parse_float
4
+ from hestia_earth.utils.tools import list_sum, safe_parse_float, non_empty_list
5
5
 
6
6
  from hestia_earth.models.utils.completeness import _is_term_type_complete
7
7
  from hestia_earth.models.utils.term import get_lookup_value
@@ -19,14 +19,15 @@ def _get_fuel_input_value(term_id: str, lookup_col: str):
19
19
  get_lookup_value(operation_term, lookup_col, model=MODEL, term=term_id), input_term_id
20
20
  ) if operation_term else None
21
21
  input_factor = operation_factor or get_lookup_value(input_term, lookup_col, model=MODEL, term=term_id)
22
+ factor = safe_parse_float(input_factor, None)
22
23
 
23
- return input_value * safe_parse_float(input_factor)
24
+ return input_value * factor if factor is not None else None
24
25
  return get_value
25
26
 
26
27
 
27
28
  def get_fuel_values(term_id: str, cycle: dict, lookup_col: str):
28
29
  inputs = filter_list_term_type(cycle.get('inputs', []), TermTermType.FUEL)
29
- values = list(map(_get_fuel_input_value(term_id, lookup_col), inputs))
30
+ values = non_empty_list(map(_get_fuel_input_value(term_id, lookup_col), inputs))
30
31
 
31
32
  return [0] if all([
32
33
  len(values) == 0,
@@ -39,7 +39,7 @@ def _measurement(site: dict, value: float):
39
39
 
40
40
  def _download(site: dict):
41
41
  value = download(TERM_ID, site, EE_PARAMS)
42
- return 1 if value == 1 else (0 if value == 0.1 else None)
42
+ return value == 1
43
43
 
44
44
 
45
45
  def _run(site: dict):
@@ -12,7 +12,8 @@ from hestia_earth.schema import TermTermType
12
12
  from hestia_earth.utils.model import filter_list_term_type
13
13
  from hestia_earth.utils.tools import list_sum
14
14
 
15
- from hestia_earth.models.log import logRequirements, logShouldRun, debugValues
15
+ from hestia_earth.models.log import logRequirements, logShouldRun, debugValues, log_as_table
16
+ from hestia_earth.models.utils.blank_node import lookups_logs, properties_logs
16
17
  from hestia_earth.models.utils.input import _new_input
17
18
  from hestia_earth.models.utils.term import get_wool_terms, get_lookup_value
18
19
  from hestia_earth.models.utils.completeness import _is_term_type_complete, _is_term_type_incomplete
@@ -26,6 +27,7 @@ from ..pastureGrass_utils import (
26
27
  calculate_REM,
27
28
  calculate_REG,
28
29
  calculate_NEfeed,
30
+ calculate_GE,
29
31
  product_wool_energy,
30
32
  get_animals,
31
33
  get_animal_values
@@ -115,7 +117,8 @@ REQUIREMENTS = {
115
117
  }
116
118
  LOOKUPS = {
117
119
  "animalManagement": [
118
- "mjKgEvMilkIpcc2019"
120
+ "mjKgEvMilkIpcc2019",
121
+ "defaultFatContentEvMilkIpcc2019"
119
122
  ],
120
123
  "animalProduct": ["mjKgEvWoolNetEnergyWoolIpcc2019", "allowedLiveAnimalTermIds"],
121
124
  "liveAnimal": [
@@ -184,40 +187,52 @@ def calculate_NEwool(cycle: dict, animal: dict, products: list, total_weight: fl
184
187
  return total_energy * animal_weight/total_weight
185
188
 
186
189
 
187
- def _calculate_GE(
188
- cycle: dict, animal: dict, REM: float, REG: float, NEwool: float, system: dict
189
- ) -> float:
190
- term_id = animal.get('term', {}).get('@id')
191
-
192
- NEm, NEa, NEl, NEwork, NEp, NEg = get_animal_values(cycle, animal, system)
193
-
194
- NEm_feed, NEg_feed = calculate_NEfeed(animal)
195
- debugValues(animal, model=MODEL, term=term_id, model_key=MODEL_KEY,
196
- NEm=NEm,
197
- NEa=NEa,
198
- NEl=NEl,
199
- NEwork=NEwork,
200
- NEp=NEp,
201
- NEg=NEg,
202
- NEm_feed=NEm_feed,
203
- NEg_feed=NEg_feed)
204
-
205
- return (NEm + NEa + NEl + NEwork + NEp - NEm_feed)/REM + (NEg + NEwool - NEg_feed)/REG
206
-
207
-
208
- def _run_practice(cycle: dict, GE: float, meanECHHV: float):
190
+ def _run_practice(
191
+ animal: dict, values: dict, meanDE: float, meanECHHV: float, REM: float, REG: float,
192
+ NEwool: float, NEm_feed: float, NEg_feed: float
193
+ ):
209
194
  def run(practice: dict):
210
195
  key = practice.get('key', {})
211
196
  key_id = key.get('@id')
212
197
  input_term_id = practice_input_id(practice)
213
- value = (GE / meanECHHV) * (list_sum(practice.get('value', [0])) / 100)
214
198
 
215
- logRequirements(cycle, model=MODEL, term=input_term_id, model_key=MODEL_KEY,
216
- GE=GE,
217
- meanECHHV=meanECHHV,
218
- key_id=key_id)
199
+ GE = (
200
+ calculate_GE([values], REM, REG, NEwool, NEm_feed, NEg_feed) / (meanDE/100)
201
+ ) if meanDE else 0
202
+
203
+ value = (GE / meanECHHV) * (list_sum(practice.get('value', [0])) / 100)
219
204
 
220
- logShouldRun(cycle, MODEL, input_term_id, True, model_key=MODEL_KEY)
205
+ logs = log_as_table(values | {
206
+ 'animalId': animal.get('term', {}).get('@id'),
207
+ 'practiceKeyId': key_id,
208
+ 'GE': GE,
209
+ 'NEmFeed': NEm_feed,
210
+ 'NEgFeed': NEg_feed,
211
+ 'REM': REM,
212
+ 'REG': REG,
213
+ 'NEwool': NEwool,
214
+ 'meanECHHV': meanECHHV,
215
+ 'meanDE': meanDE
216
+ })
217
+ animal_lookups = lookups_logs(MODEL, [animal], LOOKUPS, model_key=MODEL_KEY, term=input_term_id)
218
+ animal_properties = properties_logs([animal], properties=[
219
+ 'liveweightPerHead',
220
+ 'hoursWorkedPerDay',
221
+ 'animalsPerBirth',
222
+ 'pregnancyRateTotal',
223
+ 'weightAtMaturity',
224
+ 'liveweightGain',
225
+ 'weightAtWeaning',
226
+ 'weightAtOneYear',
227
+ 'weightAtSlaughter'
228
+ ])
229
+
230
+ logRequirements(animal, model=MODEL, term=input_term_id, model_key=MODEL_KEY,
231
+ animal_logs=logs,
232
+ animal_lookups=animal_lookups,
233
+ animal_properties=animal_properties)
234
+
235
+ logShouldRun(animal, MODEL, input_term_id, True, model_key=MODEL_KEY)
221
236
 
222
237
  return _input(input_term_id, value)
223
238
 
@@ -235,21 +250,16 @@ def _run_animal(cycle: dict, meanDE: float, meanECHHV: float, system: dict, prac
235
250
  total_liveWeightPerHead = _sum_liveWeightPerHead(animals)
236
251
 
237
252
  def run(animal: dict):
238
- term_id = animal.get('term', {}).get('@id')
239
-
240
253
  NEwool = calculate_NEwool(cycle, animal, wool_products, total_liveWeightPerHead) if (
241
254
  total_liveWeightPerHead > 0
242
255
  ) else 0
243
- GE = (_calculate_GE(cycle, animal, REM, REG, NEwool, system) / (meanDE/100)) if all([REM, REG]) else 0
244
-
245
- debugValues(animal, model=MODEL, term=term_id, model_key=MODEL_KEY,
246
- REM=REM,
247
- REG=REG,
248
- NEwool=NEwool,
249
- GE=GE,
250
- meanDE=meanDE)
256
+ NEm_feed, NEg_feed = calculate_NEfeed(animal)
257
+ animal_values = get_animal_values(cycle, animal, system)
251
258
 
252
- inputs = list(map(_run_practice(cycle, GE, meanECHHV), practices))
259
+ inputs = list(map(
260
+ _run_practice(animal, animal_values, meanDE, meanECHHV, REM, REG, NEwool, NEm_feed, NEg_feed),
261
+ practices
262
+ ))
253
263
  return animal | {
254
264
  'inputs': animal.get('inputs', []) + inputs
255
265
  }
@@ -289,8 +299,8 @@ def _should_run(cycle: dict, animals: list, practices: dict):
289
299
  term_type_freshForage_incomplete=freshForage_incomplete,
290
300
  no_cycle_inputs_feed=no_cycle_inputs_feed,
291
301
  all_animals_have_value=all_animals_have_value,
292
- meanDE=meanDE,
293
- meanECHHV=meanECHHV)
302
+ meanDE=calculate_meanDE(practices, term=term_id),
303
+ meanECHHV=calculate_meanECHHV(practices, term=term_id))
294
304
 
295
305
  logShouldRun(animal, MODEL, term_id, should_run, model_key=MODEL_KEY)
296
306
 
@@ -7,7 +7,7 @@ from pydash.objects import merge
7
7
  from typing import NamedTuple, Optional, Union
8
8
 
9
9
  from hestia_earth.schema import (
10
- CycleFunctionalUnit, EmissionMethodTier, MeasurementMethodClassification
10
+ CycleFunctionalUnit, EmissionMethodTier, MeasurementMethodClassification, SiteSiteType
11
11
  )
12
12
  from hestia_earth.utils.date import diff_in_days
13
13
  from hestia_earth.utils.tools import flatten, non_empty_list, safe_parse_date
@@ -15,7 +15,8 @@ from hestia_earth.utils.tools import flatten, non_empty_list, safe_parse_date
15
15
  from hestia_earth.models.log import log_as_table, logRequirements, logShouldRun
16
16
  from hestia_earth.models.utils import pairwise
17
17
  from hestia_earth.models.utils.blank_node import (
18
- _get_datestr_format, _gapfill_datestr, DatestrGapfillMode, DatestrFormat, group_nodes_by_year, node_term_match
18
+ _get_datestr_format, _gapfill_datestr, DatestrGapfillMode, DatestrFormat, group_nodes_by_year, node_term_match,
19
+ cumulative_nodes_term_match
19
20
  )
20
21
  from hestia_earth.models.utils.constant import Units, get_atomic_conversion
21
22
  from hestia_earth.models.utils.emission import _new_emission, min_emission_method_tier
@@ -82,6 +83,13 @@ The list of `MeasurementMethodClassification`s that can be used to calculate SOC
82
83
  order from strongest to weakest.
83
84
  """
84
85
 
86
+ _SITE_TYPE_SYSTEMS_MAPPING = {
87
+ SiteSiteType.GLASS_OR_HIGH_ACCESSIBLE_COVER.value: [
88
+ "protectedCroppingSystemSoilBased",
89
+ "protectedCroppingSystemSoilAndSubstrateBased"
90
+ ]
91
+ }
92
+
85
93
 
86
94
  class _InventoryKey(Enum):
87
95
  """
@@ -207,19 +215,37 @@ def _should_run(cycle: dict) -> tuple[bool, str, dict]:
207
215
  soc_measurements = [node for node in site.get("measurements", []) if _validate_soc_measurement(node)]
208
216
  cycles = related_cycles(site)
209
217
 
218
+ site_type = site.get("siteType")
219
+ has_soil = site_type not in _SITE_TYPE_SYSTEMS_MAPPING or all(
220
+ cumulative_nodes_term_match(
221
+ cycle.get("practices", []),
222
+ target_term_ids=_SITE_TYPE_SYSTEMS_MAPPING[site_type],
223
+ cumulative_threshold=0
224
+ ) for cycle in cycles
225
+ )
226
+
210
227
  has_soc_measurements = len(soc_measurements) > 0
211
228
  has_cycles = len(cycles) > 0
212
229
  has_functional_unit_1_ha = all(cycle.get('functionalUnit') == CycleFunctionalUnit._1_HA.value for cycle in cycles)
213
230
 
214
- should_compile_inventory = all([has_cycles, has_functional_unit_1_ha, has_soc_measurements])
231
+ should_compile_inventory = all([
232
+ has_soil,
233
+ has_cycles,
234
+ has_functional_unit_1_ha,
235
+ has_soc_measurements,
236
+ ])
215
237
 
216
- inventory, logs = _compile_inventory(cycle_id, cycles, soc_measurements) if should_compile_inventory else ({}, {})
238
+ inventory, logs = (
239
+ _compile_inventory(cycle_id, cycles, soc_measurements) if should_compile_inventory else ({}, {})
240
+ )
217
241
 
218
242
  has_valid_inventory = len(inventory) > 0
219
243
  has_consecutive_years = check_consecutive(inventory.keys())
220
244
 
221
245
  logRequirements(
222
246
  cycle, model=MODEL, term=TERM_ID,
247
+ site_type=site_type,
248
+ has_soil=has_soil,
223
249
  has_soc_measurements=has_soc_measurements,
224
250
  has_cycles=has_cycles,
225
251
  has_functional_unit_1_ha=has_functional_unit_1_ha,
@@ -1,7 +1,8 @@
1
- from hestia_earth.schema import EmissionMethodTier
1
+ from hestia_earth.schema import EmissionMethodTier, TermTermType
2
2
 
3
3
  from hestia_earth.models.log import logRequirements, logShouldRun
4
4
  from hestia_earth.models.utils.constant import Units, get_atomic_conversion
5
+ from hestia_earth.models.utils.completeness import _is_term_type_complete
5
6
  from hestia_earth.models.utils.emission import _new_emission
6
7
  from hestia_earth.models.utils.input import total_excreta
7
8
  from hestia_earth.models.utils.excretaManagement import get_lookup_factor
@@ -9,6 +10,7 @@ from . import MODEL
9
10
 
10
11
  REQUIREMENTS = {
11
12
  "Cycle": {
13
+ "completeness.excreta": "True",
12
14
  "practices": [
13
15
  {"@type": "Practice", "value": "", "term.termType": "excretaManagement"}
14
16
  ]
@@ -42,10 +44,12 @@ def _run(excretaKgN: float, N2O_N_EF: float):
42
44
  def _should_run(cycle: dict):
43
45
  excretaKgN = total_excreta(cycle.get('inputs', []))
44
46
  N2O_N_EF = get_lookup_factor(cycle.get('practices', []), LOOKUPS['excretaManagement'])
47
+ term_type_complete = _is_term_type_complete(cycle, TermTermType.EXCRETA)
45
48
 
46
49
  logRequirements(cycle, model=MODEL, term=TERM_ID,
47
50
  excretaKgN=excretaKgN,
48
- N2O_N_EF=N2O_N_EF)
51
+ N2O_N_EF=N2O_N_EF,
52
+ term_type_excreta_complete=term_type_complete)
49
53
 
50
54
  should_run = all([excretaKgN, N2O_N_EF])
51
55
  logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
@@ -88,7 +88,7 @@ def _should_run(cycle: dict):
88
88
  no3_n=no3_n,
89
89
  nh3_n=nh3_n,
90
90
  nox_n=nox_n,
91
- term_type_cropResidue_complete=term_type_complete)
91
+ term_type_excreta_complete=term_type_complete)
92
92
 
93
93
  should_run = all([no3_n is not None, nh3_n is not None, nox_n is not None, term_type_complete])
94
94
  logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
@@ -97,7 +97,7 @@ def _should_run(cycle: dict):
97
97
  flooded_rice = has_flooded_rice(cycle.get('products', []))
98
98
 
99
99
  logRequirements(cycle, model=MODEL, term=TERM_ID,
100
- term_type_cropResidue_complete=term_type_complete,
100
+ term_type_fertiliser_complete=term_type_complete,
101
101
  N_total=N_total,
102
102
  has_flooded_rice=flooded_rice,
103
103
  ecoClimateZone=ecoClimateZone)
@@ -88,7 +88,7 @@ def _should_run(cycle: dict):
88
88
  no3_n=no3_n,
89
89
  nh3_n=nh3_n,
90
90
  nox_n=nox_n,
91
- term_type_cropResidue_complete=term_type_complete)
91
+ term_type_fertiliser_complete=term_type_complete)
92
92
 
93
93
  should_run = all([no3_n is not None, nh3_n is not None, nox_n is not None, term_type_complete])
94
94
  logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
@@ -88,7 +88,7 @@ def _should_run(cycle: dict):
88
88
  no3_n=no3_n,
89
89
  nh3_n=nh3_n,
90
90
  nox_n=nox_n,
91
- term_type_cropResidue_complete=term_type_complete)
91
+ term_type_fertiliser_complete=term_type_complete)
92
92
 
93
93
  should_run = all([no3_n is not None, nh3_n is not None, nox_n is not None, term_type_complete])
94
94
  logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
@@ -19,10 +19,11 @@ from typing import Callable, Optional, Union
19
19
 
20
20
  from hestia_earth.schema import MeasurementMethodClassification, SiteSiteType, TermTermType
21
21
  from hestia_earth.utils.model import find_term_match, filter_list_term_type
22
+ from hestia_earth.utils.blank_node import get_node_value
22
23
 
23
24
  from hestia_earth.models.utils.array_builders import gen_seed
24
25
  from hestia_earth.models.utils.blank_node import (
25
- cumulative_nodes_match, cumulative_nodes_lookup_match, cumulative_nodes_term_match, get_node_value,
26
+ cumulative_nodes_match, cumulative_nodes_lookup_match, cumulative_nodes_term_match,
26
27
  node_lookup_match, node_term_match, group_nodes_by_year
27
28
  )
28
29
  from hestia_earth.models.utils.descriptive_stats import calc_descriptive_stats
@@ -1952,6 +1953,7 @@ def _get_carbon_input_kwargs(
1952
1953
  crop_residue_management_nodes = filter_list_term_type(management_nodes, [TermTermType.CROPRESIDUEMANAGEMENT])
1953
1954
  land_cover_nodes = filter_list_term_type(management_nodes, [TermTermType.LANDCOVER])
1954
1955
  land_use_management_nodes = filter_list_term_type(management_nodes, [TermTermType.LANDUSEMANAGEMENT])
1956
+ system_nodes = filter_list_term_type(management_nodes, [TermTermType.SYSTEM])
1955
1957
  water_regime_nodes = filter_list_term_type(management_nodes, [TermTermType.WATERREGIME])
1956
1958
 
1957
1959
  has_animal_manure_used = any(
@@ -2006,7 +2008,7 @@ def _get_carbon_input_kwargs(
2006
2008
  node_lookup_match(node, PRACTICE_INCREASING_C_INPUT_LOOKUP, True)
2007
2009
  and not node_term_match(node, EXCLUDED_PRACTICE_TERM_IDS)
2008
2010
  ),
2009
- land_use_management_nodes,
2011
+ land_use_management_nodes + system_nodes,
2010
2012
  cumulative_threshold=MIN_AREA_THRESHOLD
2011
2013
  )
2012
2014