hestia-earth-models 0.57.2__py3-none-any.whl → 0.59.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 (109) hide show
  1. hestia_earth/models/cycle/aboveGroundCropResidueTotal.py +17 -12
  2. hestia_earth/models/cycle/excretaKgMass.py +4 -5
  3. hestia_earth/models/cycle/excretaKgN.py +4 -5
  4. hestia_earth/models/cycle/excretaKgVs.py +4 -5
  5. hestia_earth/models/cycle/inorganicFertiliser.py +2 -2
  6. hestia_earth/models/cycle/{irrigated.py → irrigatedTypeUnspecified.py} +4 -4
  7. hestia_earth/models/cycle/liveAnimal.py +9 -11
  8. hestia_earth/models/cycle/milkYield.py +154 -0
  9. hestia_earth/models/cycle/residueIncorporated.py +1 -1
  10. hestia_earth/models/cycle/utils.py +6 -0
  11. hestia_earth/models/emepEea2019/nh3ToAirInorganicFertiliser.py +3 -3
  12. hestia_earth/models/faostat2018/seed.py +2 -3
  13. hestia_earth/models/geospatialDatabase/clayContent.py +17 -4
  14. hestia_earth/models/geospatialDatabase/sandContent.py +17 -4
  15. hestia_earth/models/geospatialDatabase/siltContent.py +2 -2
  16. hestia_earth/models/impact_assessment/irrigated.py +0 -3
  17. hestia_earth/models/ipcc2006/co2ToAirOrganicSoilCultivation.py +2 -2
  18. hestia_earth/models/ipcc2006/n2OToAirCropResidueDecompositionIndirect.py +2 -2
  19. hestia_earth/models/ipcc2006/n2OToAirExcretaDirect.py +1 -1
  20. hestia_earth/models/ipcc2006/n2OToAirExcretaIndirect.py +8 -4
  21. hestia_earth/models/ipcc2006/n2OToAirInorganicFertiliserDirect.py +4 -1
  22. hestia_earth/models/ipcc2006/n2OToAirInorganicFertiliserIndirect.py +1 -1
  23. hestia_earth/models/ipcc2006/n2OToAirOrganicFertiliserDirect.py +1 -1
  24. hestia_earth/models/ipcc2006/n2OToAirOrganicFertiliserIndirect.py +1 -1
  25. hestia_earth/models/ipcc2006/utils.py +11 -8
  26. hestia_earth/models/ipcc2019/ch4ToAirEntericFermentation.py +4 -4
  27. hestia_earth/models/ipcc2019/ch4ToAirFloodedRice.py +16 -7
  28. hestia_earth/models/ipcc2019/co2ToAirSoilCarbonStockChangeManagementChange.py +759 -0
  29. hestia_earth/models/ipcc2019/croppingDuration.py +12 -6
  30. hestia_earth/models/ipcc2019/n2OToAirCropResidueDecompositionDirect.py +5 -52
  31. hestia_earth/models/ipcc2019/n2OToAirInorganicFertiliserDirect.py +104 -0
  32. hestia_earth/models/ipcc2019/n2OToAirInorganicFertiliserIndirect.py +1 -1
  33. hestia_earth/models/ipcc2019/n2OToAirOrganicFertiliserDirect.py +105 -0
  34. hestia_earth/models/ipcc2019/n2OToAirOrganicFertiliserIndirect.py +1 -1
  35. hestia_earth/models/ipcc2019/no3ToGroundwaterCropResidueDecomposition.py +1 -1
  36. hestia_earth/models/ipcc2019/no3ToGroundwaterExcreta.py +1 -1
  37. hestia_earth/models/ipcc2019/no3ToGroundwaterInorganicFertiliser.py +1 -1
  38. hestia_earth/models/ipcc2019/no3ToGroundwaterOrganicFertiliser.py +1 -1
  39. hestia_earth/models/ipcc2019/organicCarbonPerHa.py +1088 -1268
  40. hestia_earth/models/ipcc2019/pastureGrass.py +4 -4
  41. hestia_earth/models/ipcc2019/utils.py +102 -1
  42. hestia_earth/models/koble2014/aboveGroundCropResidue.py +15 -17
  43. hestia_earth/models/koble2014/cropResidueManagement.py +2 -2
  44. hestia_earth/models/koble2014/utils.py +19 -3
  45. hestia_earth/models/linkedImpactAssessment/__init__.py +4 -2
  46. hestia_earth/models/log.py +15 -3
  47. hestia_earth/models/mocking/search-results.json +184 -118
  48. hestia_earth/models/pooreNemecek2018/excretaKgN.py +6 -7
  49. hestia_earth/models/pooreNemecek2018/excretaKgVs.py +7 -6
  50. hestia_earth/models/pooreNemecek2018/no3ToGroundwaterCropResidueDecomposition.py +3 -2
  51. hestia_earth/models/pooreNemecek2018/no3ToGroundwaterExcreta.py +3 -2
  52. hestia_earth/models/pooreNemecek2018/no3ToGroundwaterInorganicFertiliser.py +3 -2
  53. hestia_earth/models/pooreNemecek2018/saplings.py +0 -1
  54. hestia_earth/models/site/management.py +168 -0
  55. hestia_earth/models/site/organicCarbonPerHa.py +251 -89
  56. hestia_earth/models/stehfestBouwman2006/n2OToAirCropResidueDecompositionDirect.py +3 -2
  57. hestia_earth/models/stehfestBouwman2006/n2OToAirExcretaDirect.py +3 -2
  58. hestia_earth/models/stehfestBouwman2006/n2OToAirInorganicFertiliserDirect.py +3 -2
  59. hestia_earth/models/stehfestBouwman2006/n2OToAirOrganicFertiliserDirect.py +3 -2
  60. hestia_earth/models/stehfestBouwman2006/noxToAirCropResidueDecomposition.py +3 -2
  61. hestia_earth/models/stehfestBouwman2006/noxToAirExcreta.py +3 -2
  62. hestia_earth/models/stehfestBouwman2006/noxToAirInorganicFertiliser.py +3 -2
  63. hestia_earth/models/stehfestBouwman2006/noxToAirOrganicFertiliser.py +3 -2
  64. hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirCropResidueDecomposition.py +3 -2
  65. hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirExcreta.py +3 -2
  66. hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirInorganicFertiliser.py +3 -2
  67. hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirOrganicFertiliser.py +3 -2
  68. hestia_earth/models/utils/aggregated.py +1 -0
  69. hestia_earth/models/utils/blank_node.py +394 -72
  70. hestia_earth/models/utils/cropResidue.py +13 -0
  71. hestia_earth/models/utils/cycle.py +18 -9
  72. hestia_earth/models/utils/measurement.py +1 -1
  73. hestia_earth/models/utils/property.py +4 -4
  74. hestia_earth/models/utils/term.py +48 -3
  75. hestia_earth/models/version.py +1 -1
  76. {hestia_earth_models-0.57.2.dist-info → hestia_earth_models-0.59.0.dist-info}/METADATA +5 -9
  77. {hestia_earth_models-0.57.2.dist-info → hestia_earth_models-0.59.0.dist-info}/RECORD +109 -97
  78. {hestia_earth_models-0.57.2.dist-info → hestia_earth_models-0.59.0.dist-info}/WHEEL +1 -1
  79. tests/models/cycle/animal/input/test_hestiaAggregatedData.py +2 -14
  80. tests/models/cycle/input/test_hestiaAggregatedData.py +4 -16
  81. tests/models/cycle/test_coldCarcassWeightPerHead.py +1 -1
  82. tests/models/cycle/test_coldDressedCarcassWeightPerHead.py +1 -1
  83. tests/models/cycle/{test_irrigated.py → test_irrigatedTypeUnspecified.py} +1 -1
  84. tests/models/cycle/test_milkYield.py +58 -0
  85. tests/models/cycle/test_readyToCookWeightPerHead.py +1 -1
  86. tests/models/emepEea2019/test_nh3ToAirInorganicFertiliser.py +1 -1
  87. tests/models/geospatialDatabase/test_clayContent.py +9 -3
  88. tests/models/geospatialDatabase/test_sandContent.py +9 -3
  89. tests/models/ipcc2006/test_n2OToAirExcretaDirect.py +7 -2
  90. tests/models/ipcc2006/test_n2OToAirExcretaIndirect.py +1 -1
  91. tests/models/ipcc2006/test_n2OToAirInorganicFertiliserDirect.py +7 -2
  92. tests/models/ipcc2006/test_n2OToAirInorganicFertiliserIndirect.py +7 -2
  93. tests/models/ipcc2006/test_n2OToAirOrganicFertiliserDirect.py +7 -2
  94. tests/models/ipcc2006/test_n2OToAirOrganicFertiliserIndirect.py +7 -2
  95. tests/models/ipcc2019/test_ch4ToAirEntericFermentation.py +1 -1
  96. tests/models/ipcc2019/test_co2ToAirSoilCarbonStockChangeManagementChange.py +228 -0
  97. tests/models/ipcc2019/test_n2OToAirInorganicFertiliserDirect.py +74 -0
  98. tests/models/ipcc2019/test_n2OToAirOrganicFertiliserDirect.py +74 -0
  99. tests/models/ipcc2019/test_organicCarbonPerHa.py +303 -1044
  100. tests/models/koble2014/test_residueBurnt.py +1 -2
  101. tests/models/koble2014/test_residueLeftOnField.py +1 -2
  102. tests/models/koble2014/test_residueRemoved.py +1 -2
  103. tests/models/koble2014/test_utils.py +52 -0
  104. tests/models/site/test_management.py +117 -0
  105. tests/models/site/test_organicCarbonPerHa.py +51 -5
  106. tests/models/utils/test_blank_node.py +230 -34
  107. tests/models/utils/test_term.py +17 -3
  108. {hestia_earth_models-0.57.2.dist-info → hestia_earth_models-0.59.0.dist-info}/LICENSE +0 -0
  109. {hestia_earth_models-0.57.2.dist-info → hestia_earth_models-0.59.0.dist-info}/top_level.txt +0 -0
@@ -22,7 +22,7 @@ from . import MODEL
22
22
  REQUIREMENTS = {
23
23
  "Cycle": {
24
24
  "completeness.animalFeed": "True",
25
- "completeness.grazedForage": "False",
25
+ "completeness.freshForage": "False",
26
26
  "site": {
27
27
  "@type": "Site",
28
28
  "siteType": "permanent pasture"
@@ -584,7 +584,7 @@ def _should_run_practice(cycle: dict):
584
584
  def _should_run(cycle: dict, practices: dict):
585
585
  systems = filter_list_term_type(cycle.get('practices', []), TermTermType.SYSTEM)
586
586
  animalFeed_complete = _is_term_type_complete(cycle, 'animalFeed')
587
- grazedForage_incomplete = _is_term_type_incomplete(cycle, 'grazedForage')
587
+ freshForage_incomplete = _is_term_type_incomplete(cycle, 'freshForage')
588
588
  all_animals_have_value = all([a.get('value', 0) > 0 for a in cycle.get('animals', [])])
589
589
 
590
590
  meanDE = _calculate_meanDE(practices)
@@ -592,7 +592,7 @@ def _should_run(cycle: dict, practices: dict):
592
592
  GE = _calculate_GE(cycle, meanDE, systems[0]) if all([meanDE > 0, len(systems) > 0]) else 0
593
593
 
594
594
  should_run = all([
595
- animalFeed_complete, grazedForage_incomplete,
595
+ animalFeed_complete, freshForage_incomplete,
596
596
  all_animals_have_value,
597
597
  len(systems) > 0, len(practices) > 0,
598
598
  GE > 0, meanECHHV > 0
@@ -601,7 +601,7 @@ def _should_run(cycle: dict, practices: dict):
601
601
  for term_id in [MODEL_KEY] + [_practice_input_id(p) for p in practices]:
602
602
  logRequirements(cycle, model=MODEL, term=term_id,
603
603
  term_type_animalFeed_complete=animalFeed_complete,
604
- term_type_grazedForage_incomplete=grazedForage_incomplete,
604
+ term_type_freshForage_incomplete=freshForage_incomplete,
605
605
  all_animals_have_value=all_animals_have_value,
606
606
  meanDE=meanDE,
607
607
  meanECHHV=meanECHHV,
@@ -1,4 +1,5 @@
1
- from hestia_earth.utils.model import find_term_match
1
+ from hestia_earth.schema import TermTermType
2
+ from hestia_earth.utils.model import find_term_match, filter_list_term_type
2
3
  from hestia_earth.utils.tools import safe_parse_float
3
4
 
4
5
  from hestia_earth.models.log import debugValues
@@ -7,6 +8,7 @@ from hestia_earth.models.utils.cycle import get_ecoClimateZone
7
8
  from hestia_earth.models.utils.constant import Units, get_atomic_conversion
8
9
  from hestia_earth.models.utils.blank_node import find_terms_value
9
10
  from hestia_earth.models.utils.term import get_lookup_value, get_milkYield_terms
11
+ from hestia_earth.models.utils.ecoClimateZone import get_ecoClimateZone_lookup_value
10
12
  from . import MODEL
11
13
 
12
14
  # From IPCC2019 Indirect N2O emission factor, in N [avg, min, max, std]
@@ -69,3 +71,102 @@ def get_yield_dm(term_id: str, term: dict):
69
71
  def get_milkYield_practice(node: dict):
70
72
  terms = get_milkYield_terms()
71
73
  return next((p for p in node.get('practices', []) if p.get('term', {}).get('@id') in terms), {})
74
+
75
+
76
+ def check_consecutive(ints: list[int]) -> bool:
77
+ """
78
+ Checks whether a list of integers are consecutive.
79
+
80
+ Used to determine whether annualised data is complete from every year from beggining to end.
81
+
82
+ Parameters
83
+ ----------
84
+ ints : list[int]
85
+ A list of integer values.
86
+
87
+ Returns
88
+ -------
89
+ bool
90
+ Whether or not the list of integers is consecutive.
91
+ """
92
+ range_list = list(range(min(ints), max(ints)+1)) if ints else []
93
+ return all(a == b for a, b in zip(ints, range_list))
94
+
95
+
96
+ N2O_FACTORS = {
97
+ # All N inputs in dry climate
98
+ 'dry': {
99
+ 'value': 0.005,
100
+ 'min': 0,
101
+ 'max': 0.011
102
+ },
103
+ 'wet': {
104
+ # Synthetic fertiliser inputs in wet climate
105
+ TermTermType.INORGANICFERTILISER: {
106
+ 'value': 0.016,
107
+ 'min': 0.013,
108
+ 'max': 0.019
109
+ },
110
+ # Other N inputs in wet climate
111
+ TermTermType.ORGANICFERTILISER: {
112
+ 'value': 0.006,
113
+ 'min': 0.001,
114
+ 'max': 0.011
115
+ },
116
+ TermTermType.CROPRESIDUE: {
117
+ 'value': 0.006,
118
+ 'min': 0.001,
119
+ 'max': 0.011
120
+ }
121
+ },
122
+ 'default': {
123
+ 'value': 0.01,
124
+ 'min': 0.001,
125
+ 'max': 0.018
126
+ },
127
+ 'flooded_rice': {
128
+ 'value': 0.004,
129
+ 'min': 0,
130
+ 'max': 0.029
131
+ }
132
+ }
133
+
134
+
135
+ def _get_waterRegime_lookup(model_term_id: str, practice: dict, col: str):
136
+ return safe_parse_float(get_lookup_value(practice.get('term', {}), col, model=MODEL, term=model_term_id), None)
137
+
138
+
139
+ def _is_wet(ecoClimateZone: str = None):
140
+ return get_ecoClimateZone_lookup_value(ecoClimateZone, 'wet') == 1 if ecoClimateZone else None
141
+
142
+
143
+ def _ecoClimate_factors(input_term_type: TermTermType, ecoClimateZone: str = None):
144
+ is_wet = _is_wet(ecoClimateZone)
145
+ factors_key = 'default' if is_wet is None else 'wet' if is_wet else 'dry'
146
+ factors = N2O_FACTORS[factors_key]
147
+ return (factors.get(input_term_type) if factors_key == 'wet' else factors, is_wet is None)
148
+
149
+
150
+ def _flooded_rice_factors(model_term_id: str, cycle: dict):
151
+ lookup_name = 'IPCC_2019_N2O_rice'
152
+ practices = filter_list_term_type(cycle.get('practices', []), TermTermType.WATERREGIME)
153
+ practice = next((p for p in practices if _get_waterRegime_lookup(model_term_id, p, lookup_name) is not None), None)
154
+
155
+ factors = {
156
+ 'value': _get_waterRegime_lookup(model_term_id, practice, lookup_name),
157
+ 'min': _get_waterRegime_lookup(model_term_id, practice, lookup_name + '-min'),
158
+ 'max': _get_waterRegime_lookup(model_term_id, practice, lookup_name + '-max')
159
+ } if practice else N2O_FACTORS['flooded_rice']
160
+
161
+ return (factors, practice is None)
162
+
163
+
164
+ def get_N2O_factors(
165
+ model_term_id: str,
166
+ cycle: dict,
167
+ input_term_type: TermTermType,
168
+ ecoClimateZone: str = None,
169
+ flooded_rice: bool = False
170
+ ):
171
+ return _flooded_rice_factors(model_term_id, cycle) if flooded_rice \
172
+ else _ecoClimate_factors(input_term_type, ecoClimateZone)
@@ -12,6 +12,7 @@ from hestia_earth.utils.model import find_term_match
12
12
  from hestia_earth.utils.tools import flatten, list_sum, list_average
13
13
 
14
14
  from hestia_earth.models.log import logRequirements, logShouldRun, debugValues
15
+ from hestia_earth.models.utils.cropResidue import PRODUCT_ID_TO_PRACTICES_ID
15
16
  from hestia_earth.models.utils.product import _new_product
16
17
  from hestia_earth.models.utils.completeness import _is_term_type_incomplete
17
18
  from . import MODEL
@@ -38,20 +39,16 @@ RETURNS = {
38
39
  }
39
40
  TERM_ID = 'aboveGroundCropResidueLeftOnField,aboveGroundCropResidueBurnt,aboveGroundCropResidueIncorporated,aboveGroundCropResidueRemoved' # noqa: E501
40
41
  TOTAL_TERM_ID = 'aboveGroundCropResidueTotal'
41
- MODELS = [
42
- {'term': 'aboveGroundCropResidueRemoved', 'practices': ['residueRemoved']},
43
- {'term': 'aboveGroundCropResidueIncorporated', 'practices': [
44
- 'residueIncorporated',
45
- 'residueIncorporatedLessThan30DaysBeforeCultivation',
46
- 'residueIncorporatedMoreThan30DaysBeforeCultivation'
47
- ]},
48
- {'term': 'aboveGroundCropResidueBurnt', 'practices': ['residueBurnt']}
49
- ]
50
- REMAINING_MODEL = 'aboveGroundCropResidueLeftOnField'
42
+ REMAINING_MODEL = PRODUCT_ID_TO_PRACTICES_ID[-1]['product']
51
43
 
52
44
 
53
45
  def _get_practices(term_id: str):
54
- return flatten([model.get('practices', []) for model in MODELS if model.get('term') == term_id])
46
+ return flatten([
47
+ model.get('practices', []) for model in PRODUCT_ID_TO_PRACTICES_ID if all([
48
+ model.get('product') == term_id,
49
+ model.get('product') != REMAINING_MODEL
50
+ ])
51
+ ])
55
52
 
56
53
 
57
54
  def _get_practice_value(term_ids: list, cycle: dict) -> float:
@@ -63,12 +60,12 @@ def _get_practice_value(term_ids: list, cycle: dict) -> float:
63
60
 
64
61
 
65
62
  def _product(term_id: str, value: float):
66
- product = _new_product(term_id, value, MODEL)
63
+ product = _new_product(term_id, round(value, 2), MODEL)
67
64
  return product
68
65
 
69
66
 
70
67
  def _should_run_model(model, cycle: dict, total_value: float):
71
- term_id = model.get('term')
68
+ term_id = model.get('product')
72
69
  practice_value = _get_practice_value(model.get('practices'), cycle)
73
70
  has_product = find_term_match(cycle.get('products', []), term_id, None) is not None
74
71
 
@@ -102,15 +99,16 @@ def _run(cycle: dict, total_values: list):
102
99
  total_value = list_average(total_values)
103
100
  # first, calculate the remaining value available after applying all user-uploaded data
104
101
  remaining_value = reduce(
105
- lambda prev, model: prev - _model_value(model.get('term'), products),
106
- MODELS + [{'term': REMAINING_MODEL}],
102
+ lambda prev, model: prev - _model_value(model.get('product'), products),
103
+ PRODUCT_ID_TO_PRACTICES_ID,
107
104
  total_value
108
105
  )
109
106
 
110
107
  values = []
111
108
  # then run every model in order up to the remaining value
112
- for model in MODELS:
113
- term_id = model.get('term')
109
+ models = [model for model in PRODUCT_ID_TO_PRACTICES_ID if model.get('product') != REMAINING_MODEL]
110
+ for model in models:
111
+ term_id = model.get('product')
114
112
  value = _run_model(model, cycle, total_value)
115
113
  debugValues(cycle, model=MODEL, term=term_id,
116
114
  total_value=total_value,
@@ -8,7 +8,7 @@ from hestia_earth.schema import TermTermType
8
8
  from hestia_earth.utils.model import filter_list_term_type
9
9
  from hestia_earth.utils.tools import list_sum
10
10
 
11
- from hestia_earth.models.log import logRequirements, logShouldRun
11
+ from hestia_earth.models.log import logRequirements, logShouldRun, log_blank_nodes_id
12
12
  from hestia_earth.models.utils import is_from_model
13
13
  from hestia_earth.models.utils.blank_node import get_total_value
14
14
  from .utils import _practice
@@ -66,7 +66,7 @@ def _should_run(cycle: dict):
66
66
  logRequirements(cycle, model=MODEL_LOG,
67
67
  total_value=total_value,
68
68
  recalculated_total_value=recalculated_total_value,
69
- recalculated_practices=';'.join([p.get('term', {}).get('@id') for p in recalculated_practices]))
69
+ recalculated_practice_ids=log_blank_nodes_id(recalculated_practices))
70
70
 
71
71
  should_run = all([total_value > 0, total_value != 100, recalculated_total_value > 0])
72
72
  logShouldRun(cycle, MODEL_LOG, None, should_run)
@@ -3,10 +3,12 @@ from hestia_earth.schema import TermTermType
3
3
  from hestia_earth.utils.model import find_primary_product, find_term_match
4
4
  from hestia_earth.utils.tools import list_sum
5
5
 
6
- from hestia_earth.models.log import logRequirements, logShouldRun, log_as_table
6
+ from hestia_earth.models.log import logRequirements, logShouldRun, log_as_table, log_blank_nodes_id
7
+ from hestia_earth.models.utils import is_from_model
7
8
  from hestia_earth.models.utils.completeness import _is_term_type_incomplete
8
9
  from hestia_earth.models.utils.practice import _new_practice
9
10
  from hestia_earth.models.utils.term import get_crop_residue_management_terms
11
+ from hestia_earth.models.utils.cropResidue import crop_residue_product_ids
10
12
  from . import MODEL
11
13
 
12
14
 
@@ -23,6 +25,7 @@ def _model_value(term_id: str, practices: list):
23
25
  def _should_run(term_id: str, cycle: dict, require_country: bool = False):
24
26
  primary_product = find_primary_product(cycle)
25
27
  has_primary_product = primary_product is not None
28
+
26
29
  crop_residue_incomplete = _is_term_type_incomplete(cycle, TermTermType.CROPRESIDUE)
27
30
  practices = cycle.get('practices', [])
28
31
  residue_terms = get_crop_residue_management_terms()
@@ -32,6 +35,16 @@ def _should_run(term_id: str, cycle: dict, require_country: bool = False):
32
35
  ])
33
36
  has_remaining_value = remaining_value > 0
34
37
 
38
+ # make sure no above ground residue product has been added by the user, or values will be off
39
+ provided_cropResidue_products = [
40
+ p for p in cycle.get('products', []) if all([
41
+ p.get('term', {}).get('@id') in crop_residue_product_ids(),
42
+ p.get('value', []),
43
+ not is_from_model(p)
44
+ ])
45
+ ]
46
+ has_provided_cropResidue_products = len(provided_cropResidue_products) > 0
47
+
35
48
  country_id = cycle.get('site', {}).get('country', {}).get('@id')
36
49
 
37
50
  logRequirements(cycle, model=MODEL, term=term_id,
@@ -39,11 +52,14 @@ def _should_run(term_id: str, cycle: dict, require_country: bool = False):
39
52
  term_type_cropResidue_incomplete=crop_residue_incomplete,
40
53
  has_remaining_value=has_remaining_value,
41
54
  crop_residue_values=residue_values,
42
- country_id=country_id)
55
+ country_id=country_id,
56
+ has_provided_cropResidue_products=has_provided_cropResidue_products,
57
+ provided_cropResidue_product_ids=log_blank_nodes_id(provided_cropResidue_products))
43
58
 
44
59
  should_run = all([
45
60
  has_primary_product, crop_residue_incomplete, has_remaining_value,
46
- not require_country or country_id
61
+ not require_country or country_id,
62
+ not has_provided_cropResidue_products
47
63
  ])
48
64
  logShouldRun(cycle, MODEL, term_id, should_run)
49
65
  return should_run, remaining_value, primary_product, country_id
@@ -83,8 +83,9 @@ def _group_emissions(impact: dict):
83
83
  def _group_by(prev: dict, emission: dict):
84
84
  term_id = emission.get('term', {}).get('@id')
85
85
  grouping = _emission_group(term_id)
86
+ value = emission.get('value') or 0
86
87
  if grouping:
87
- prev[grouping] = prev.get(grouping, 0) + (emission.get('value', 0) or 0)
88
+ prev[grouping] = prev.get(grouping, 0) + value
88
89
  return prev
89
90
 
90
91
  emissions = impact.get('emissionsResourceUse', [])
@@ -101,7 +102,8 @@ def _run_input(cycle: dict):
101
102
  emissions = _group_emissions(impact)
102
103
 
103
104
  logRequirements(cycle, model=model, term=term_id,
104
- impact_assessment_id=input.get('impactAssessment', {}).get('@id'))
105
+ impact_assessment_id=input.get('impactAssessment', {}).get('@id'),
106
+ input_value=input_value)
105
107
  logShouldRun(cycle, model, term_id, True, methodTier=TIER)
106
108
 
107
109
  return [
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  import sys
3
3
  import logging
4
- from typing import Union
4
+ from typing import Union, List
5
5
 
6
6
  LOG_LEVEL = os.getenv('LOG_LEVEL', 'INFO')
7
7
 
@@ -57,7 +57,7 @@ def logRequirements(log_node: dict, **kwargs):
57
57
  logger.info(_log_node_suffix(log_node) + 'requirements=true, ' + _join_args(**kwargs))
58
58
 
59
59
 
60
- def logShouldRun(log_node: dict, model: str, term: str, should_run: bool, **kwargs):
60
+ def logShouldRun(log_node: dict, model: str, term: Union[str, None], should_run: bool, **kwargs):
61
61
  extra = (', ' + _join_args(**kwargs)) if len(kwargs.keys()) > 0 else ''
62
62
  logger.info(_log_node_suffix(log_node) + 'should_run=%s, model=%s, term=%s' + extra, should_run, model, term)
63
63
 
@@ -89,4 +89,16 @@ def log_as_table(values: Union[list, dict]):
89
89
  (
90
90
  '_'.join([f"{k}:{v}" for k, v in value.items()]) if isinstance(value, dict) else str(value)
91
91
  ) for value in values
92
- ])
92
+ ]) or 'None'
93
+
94
+
95
+ def log_blank_nodes_id(blank_nodes: List[dict]):
96
+ """
97
+ Log a list of blank node ids to display as a table.
98
+
99
+ Parameters
100
+ ----------
101
+ values : list
102
+ List of blank nodes, like Product, Input, Measurement, etc.
103
+ """
104
+ return ';'.join([p.get('term', {}).get('@id') for p in blank_nodes if p.get('term', {}).get('@id')]) or 'None'