hestia-earth-models 0.61.7__py3-none-any.whl → 0.62.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 (51) hide show
  1. hestia_earth/models/cycle/completeness/electricityFuel.py +60 -0
  2. hestia_earth/models/cycle/product/economicValueShare.py +47 -31
  3. hestia_earth/models/emepEea2019/nh3ToAirInorganicFertiliser.py +44 -59
  4. hestia_earth/models/geospatialDatabase/histosol.py +4 -0
  5. hestia_earth/models/ipcc2006/co2ToAirOrganicSoilCultivation.py +4 -2
  6. hestia_earth/models/ipcc2006/n2OToAirOrganicSoilCultivationDirect.py +1 -1
  7. hestia_earth/models/ipcc2019/aboveGroundCropResidueTotal.py +1 -1
  8. hestia_earth/models/ipcc2019/animal/pastureGrass.py +30 -24
  9. hestia_earth/models/ipcc2019/belowGroundCropResidue.py +1 -1
  10. hestia_earth/models/ipcc2019/ch4ToAirExcreta.py +1 -1
  11. hestia_earth/models/ipcc2019/co2ToAirSoilOrganicCarbonStockChangeManagementChange.py +511 -458
  12. hestia_earth/models/ipcc2019/co2ToAirUreaHydrolysis.py +5 -1
  13. hestia_earth/models/ipcc2019/organicCarbonPerHa.py +116 -3882
  14. hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_1_utils.py +2060 -0
  15. hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_2_utils.py +1630 -0
  16. hestia_earth/models/ipcc2019/organicCarbonPerHa_utils.py +324 -0
  17. hestia_earth/models/ipcc2019/pastureGrass.py +37 -19
  18. hestia_earth/models/ipcc2019/pastureGrass_utils.py +4 -21
  19. hestia_earth/models/mocking/search-results.json +293 -289
  20. hestia_earth/models/site/organicCarbonPerHa.py +58 -44
  21. hestia_earth/models/site/soilMeasurement.py +18 -13
  22. hestia_earth/models/utils/__init__.py +28 -0
  23. hestia_earth/models/utils/array_builders.py +578 -0
  24. hestia_earth/models/utils/blank_node.py +55 -39
  25. hestia_earth/models/utils/descriptive_stats.py +285 -0
  26. hestia_earth/models/utils/emission.py +73 -2
  27. hestia_earth/models/utils/inorganicFertiliser.py +2 -2
  28. hestia_earth/models/utils/measurement.py +118 -4
  29. hestia_earth/models/version.py +1 -1
  30. {hestia_earth_models-0.61.7.dist-info → hestia_earth_models-0.62.0.dist-info}/METADATA +2 -2
  31. {hestia_earth_models-0.61.7.dist-info → hestia_earth_models-0.62.0.dist-info}/RECORD +51 -39
  32. tests/models/cycle/completeness/test_electricityFuel.py +21 -0
  33. tests/models/cycle/product/test_economicValueShare.py +8 -0
  34. tests/models/emepEea2019/test_nh3ToAirInorganicFertiliser.py +2 -2
  35. tests/models/ipcc2019/animal/test_pastureGrass.py +2 -2
  36. tests/models/ipcc2019/test_co2ToAirSoilOrganicCarbonStockChangeManagementChange.py +55 -165
  37. tests/models/ipcc2019/test_organicCarbonPerHa.py +219 -460
  38. tests/models/ipcc2019/test_organicCarbonPerHa_tier_1_utils.py +471 -0
  39. tests/models/ipcc2019/test_organicCarbonPerHa_tier_2_utils.py +208 -0
  40. tests/models/ipcc2019/test_organicCarbonPerHa_utils.py +75 -0
  41. tests/models/ipcc2019/test_pastureGrass.py +0 -16
  42. tests/models/site/test_organicCarbonPerHa.py +3 -12
  43. tests/models/site/test_soilMeasurement.py +3 -18
  44. tests/models/utils/test_array_builders.py +253 -0
  45. tests/models/utils/test_blank_node.py +154 -15
  46. tests/models/utils/test_descriptive_stats.py +134 -0
  47. tests/models/utils/test_emission.py +51 -1
  48. tests/models/utils/test_measurement.py +54 -2
  49. {hestia_earth_models-0.61.7.dist-info → hestia_earth_models-0.62.0.dist-info}/LICENSE +0 -0
  50. {hestia_earth_models-0.61.7.dist-info → hestia_earth_models-0.62.0.dist-info}/WHEEL +0 -0
  51. {hestia_earth_models-0.61.7.dist-info → hestia_earth_models-0.62.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,324 @@
1
+ from enum import Enum
2
+ from functools import lru_cache
3
+ from numpy.typing import NDArray
4
+ from typing import NamedTuple, Optional
5
+
6
+ from hestia_earth.schema import MeasurementStatsDefinition, SiteSiteType
7
+
8
+ from hestia_earth.models.utils.array_builders import (
9
+ repeat_single, plus_minus_uncertainty_to_normal_1d, truncated_normal_1d
10
+ )
11
+ from hestia_earth.models.utils.blank_node import cumulative_nodes_term_match
12
+ from hestia_earth.models.utils.term import (
13
+ get_cover_crop_property_terms, get_crop_residue_incorporated_or_left_on_field_terms, get_irrigated_terms,
14
+ get_residue_removed_or_burnt_terms, get_upland_rice_crop_terms, get_upland_rice_land_cover_terms
15
+ )
16
+
17
+ STATS_DEFINITION = MeasurementStatsDefinition.SIMULATED.value
18
+ DEPTH_UPPER = 0
19
+ DEPTH_LOWER = 30
20
+
21
+ MIN_AREA_THRESHOLD = 30 # 30% as per IPCC guidelines
22
+ SUPER_MAJORITY_AREA_THRESHOLD = 100 - MIN_AREA_THRESHOLD
23
+ MIN_YIELD_THRESHOLD = 1
24
+
25
+
26
+ def get_cover_crop_property_terms_with_cache():
27
+ return lru_cache()(get_cover_crop_property_terms)()
28
+
29
+
30
+ def get_crop_residue_inc_or_left_terms_with_cache():
31
+ return lru_cache()(get_crop_residue_incorporated_or_left_on_field_terms)()
32
+
33
+
34
+ def get_irrigated_terms_with_cache():
35
+ return lru_cache()(get_irrigated_terms)()
36
+
37
+
38
+ def get_residue_removed_or_burnt_terms_with_cache():
39
+ return lru_cache()(get_residue_removed_or_burnt_terms)()
40
+
41
+
42
+ def get_upland_rice_crop_terms_with_cache():
43
+ return lru_cache()(get_upland_rice_crop_terms)()
44
+
45
+
46
+ def get_upland_rice_land_cover_terms_with_cache():
47
+ return lru_cache()(get_upland_rice_land_cover_terms)()
48
+
49
+
50
+ class EcoClimateZone(Enum):
51
+ """
52
+ Enum representing eco-climate zones. The value of each member of the Enum correctly corresponds with the values of
53
+ `ecoClimateZone` term and the `ecoClimateZone-lookup.csv`.
54
+ """
55
+ WARM_TEMPERATE_MOIST = 1
56
+ WARM_TEMPERATE_DRY = 2
57
+ COOL_TEMPERATE_MOIST = 3
58
+ COOL_TEMPERATE_DRY = 4
59
+ POLAR_MOIST = 5
60
+ POLAR_DRY = 6
61
+ BOREAL_MOIST = 7
62
+ BOREAL_DRY = 8
63
+ TROPICAL_MONTANE = 9
64
+ TROPICAL_WET = 10
65
+ TROPICAL_MOIST = 11
66
+ TROPICAL_DRY = 12
67
+
68
+
69
+ class IpccSoilCategory(Enum):
70
+ """
71
+ Enum representing IPCC Soil Categories.
72
+
73
+ See [IPCC (2019) Vol 4, Ch. 2 and 3](https://www.ipcc-nggip.iges.or.jp/public/2019rf/vol4.html) for more
74
+ information.
75
+ """
76
+ ORGANIC_SOILS = "organic soils"
77
+ SANDY_SOILS = "sandy soils"
78
+ WETLAND_SOILS = "wetland soils"
79
+ VOLCANIC_SOILS = "volcanic soils"
80
+ SPODIC_SOILS = "spodic soils"
81
+ HIGH_ACTIVITY_CLAY_SOILS = "high-activity clay soils"
82
+ LOW_ACTIVITY_CLAY_SOILS = "low-activity clay soils"
83
+
84
+
85
+ IPCC_SOIL_CATEGORY_TO_SOIL_TYPE_LOOKUP_VALUE = {
86
+ IpccSoilCategory.ORGANIC_SOILS: "Organic soils",
87
+ IpccSoilCategory.SANDY_SOILS: "Sandy soils",
88
+ IpccSoilCategory.WETLAND_SOILS: "Wetland soils",
89
+ IpccSoilCategory.VOLCANIC_SOILS: "Volcanic soils",
90
+ IpccSoilCategory.SPODIC_SOILS: "Spodic soils",
91
+ IpccSoilCategory.HIGH_ACTIVITY_CLAY_SOILS: "High-activity clay soils",
92
+ IpccSoilCategory.LOW_ACTIVITY_CLAY_SOILS: "Low-activity clay soils",
93
+ }
94
+ """
95
+ A dictionary mapping IPCC soil categories to corresponding soil type and USDA soil type lookup values in the
96
+ `"IPCC_SOIL_CATEGORY"` column.
97
+ """
98
+
99
+
100
+ class IpccLandUseCategory(Enum):
101
+ """
102
+ Enum representing IPCC Land Use Categories.
103
+
104
+ See [IPCC (2019) Vol 4](https://www.ipcc-nggip.iges.or.jp/public/2019rf/vol4.html) for more information.
105
+ """
106
+ GRASSLAND = "grassland"
107
+ PERENNIAL_CROPS = "perennial crops"
108
+ PADDY_RICE_CULTIVATION = "paddy rice cultivation"
109
+ ANNUAL_CROPS_WET = "annual crops (wet)"
110
+ ANNUAL_CROPS = "annual crops"
111
+ SET_ASIDE = "set aside"
112
+ FOREST = "forest"
113
+ NATIVE = "native"
114
+ OTHER = "other"
115
+
116
+
117
+ SITE_TYPE_TO_IPCC_LAND_USE_CATEGORY = {
118
+ SiteSiteType.PERMANENT_PASTURE.value: IpccLandUseCategory.GRASSLAND,
119
+ SiteSiteType.FOREST.value: IpccLandUseCategory.FOREST,
120
+ SiteSiteType.OTHER_NATURAL_VEGETATION.value: IpccLandUseCategory.NATIVE
121
+ }
122
+ """
123
+ A dictionary mapping site types to corresponding IPCC land use categories.
124
+ """
125
+
126
+ IPCC_LAND_USE_CATEGORY_TO_LAND_COVER_LOOKUP_VALUE = {
127
+ IpccLandUseCategory.GRASSLAND: "Grassland",
128
+ IpccLandUseCategory.PERENNIAL_CROPS: "Perennial crops",
129
+ IpccLandUseCategory.PADDY_RICE_CULTIVATION: "Paddy rice cultivation",
130
+ IpccLandUseCategory.ANNUAL_CROPS_WET: "Annual crops",
131
+ IpccLandUseCategory.ANNUAL_CROPS: "Annual crops",
132
+ IpccLandUseCategory.SET_ASIDE: [
133
+ "Annual crops", "Paddy rice cultivation", "Perennial crops", "Set aside"
134
+ ],
135
+ IpccLandUseCategory.FOREST: "Forest",
136
+ IpccLandUseCategory.NATIVE: "Native"
137
+ }
138
+ """
139
+ A dictionary mapping IPCC land use categories to corresponding land cover lookup values in the
140
+ `"IPCC_LAND_USE_CATEGORY"` column.
141
+ """
142
+
143
+
144
+ class IpccManagementCategory(Enum):
145
+ """
146
+ Enum representing IPCC Management Categories for grasslands and annual croplands.
147
+
148
+ See [IPCC (2019) Vol. 4, Ch. 5 and 6](https://www.ipcc-nggip.iges.or.jp/public/2019rf/vol4.html) for more
149
+ information.
150
+ """
151
+ SEVERELY_DEGRADED = "severely degraded"
152
+ IMPROVED_GRASSLAND = "improved grassland"
153
+ HIGH_INTENSITY_GRAZING = "high-intensity grazing"
154
+ NOMINALLY_MANAGED = "nominally managed"
155
+ FULL_TILLAGE = "full tillage"
156
+ REDUCED_TILLAGE = "reduced tillage"
157
+ NO_TILLAGE = "no tillage"
158
+ OTHER = "other"
159
+
160
+
161
+ IPCC_MANAGEMENT_CATEGORY_TO_GRASSLAND_MANAGEMENT_TERM_ID = {
162
+ IpccManagementCategory.SEVERELY_DEGRADED: "severelyDegradedPasture",
163
+ IpccManagementCategory.IMPROVED_GRASSLAND: "improvedPasture",
164
+ IpccManagementCategory.HIGH_INTENSITY_GRAZING: "highIntensityGrazingPasture",
165
+ IpccManagementCategory.NOMINALLY_MANAGED: "nominallyManagedPasture",
166
+ IpccManagementCategory.OTHER: "nativePasture"
167
+ }
168
+ """
169
+ A dictionary mapping IPCC management categories to corresponding grassland management term IDs from the land cover
170
+ glossary.
171
+ """
172
+
173
+
174
+ IPCC_MANAGEMENT_CATEGORY_TO_TILLAGE_MANAGEMENT_LOOKUP_VALUE = {
175
+ IpccManagementCategory.FULL_TILLAGE: "Full tillage",
176
+ IpccManagementCategory.REDUCED_TILLAGE: "Reduced tillage",
177
+ IpccManagementCategory.NO_TILLAGE: "No tillage"
178
+ }
179
+ """
180
+ A dictionary mapping IPCC management categories to corresponding tillage lookup values in the
181
+ `"IPCC_TILLAGE_MANAGEMENT_CATEGORY" column`.
182
+ """
183
+
184
+
185
+ class IpccCarbonInputCategory(Enum):
186
+ """
187
+ Enum representing IPCC Carbon Input Categories for improved grasslands and annual croplands.
188
+
189
+ See [IPCC (2019) Vol. 4, Ch. 4, 5 and 6](https://www.ipcc-nggip.iges.or.jp/public/2019rf/vol4.html) for more
190
+ information.
191
+ """
192
+ GRASSLAND_HIGH = "grassland high"
193
+ GRASSLAND_MEDIUM = "grassland medium"
194
+ CROPLAND_HIGH_WITH_MANURE = "cropland high (with manure)"
195
+ CROPLAND_HIGH_WITHOUT_MANURE = "cropland high (without manure)"
196
+ CROPLAND_MEDIUM = "cropland medium"
197
+ CROPLAND_LOW = "cropland low"
198
+ OTHER = "other"
199
+
200
+
201
+ CarbonSource = NamedTuple(
202
+ "CarbonSource",
203
+ [
204
+ ("mass", float),
205
+ ("carbon_content", float),
206
+ ("nitrogen_content", float),
207
+ ("lignin_content", float),
208
+ ]
209
+ )
210
+ """
211
+ A single carbon source (e.g. crop residues or organic amendment).
212
+
213
+ Attributes
214
+ -----------
215
+ mass : float
216
+ The dry-matter mass of the carbon source, kg ha-1
217
+ carbon_content : float
218
+ The carbon content of the carbon source, decimal proportion, kg C (kg d.m.)-1.
219
+ nitrogen_content : float
220
+ The nitrogen content of the carbon source, decimal_proportion, kg N (kg d.m.)-1.
221
+ lignin_content : float
222
+ The lignin content of the carbon source, decimal_proportion, kg lignin (kg d.m.)-1.
223
+ """
224
+
225
+
226
+ def check_consecutive(ints: list[int]) -> bool:
227
+ """
228
+ Checks whether a list of integers are consecutive.
229
+
230
+ Used to determine whether annualised data is complete from every year from beggining to end.
231
+
232
+ Parameters
233
+ ----------
234
+ ints : list[int]
235
+ A list of integer values.
236
+
237
+ Returns
238
+ -------
239
+ bool
240
+ Whether or not the list of integers is consecutive.
241
+ """
242
+ range_list = list(range(min(ints), max(ints)+1)) if ints else []
243
+ return all(a == b for a, b in zip(ints, range_list))
244
+
245
+
246
+ def check_irrigation(water_regime_nodes: list[dict]) -> bool:
247
+ """
248
+ Check if irrigation is present in the water regime nodes.
249
+
250
+ Parameters
251
+ ----------
252
+ water_regime_nodes : list[dict]
253
+ List of water regime nodes to be checked.
254
+
255
+ Returns
256
+ -------
257
+ bool
258
+ `True` if irrigation is present, `False` otherwise.
259
+ """
260
+ return cumulative_nodes_term_match(
261
+ water_regime_nodes,
262
+ target_term_ids=get_irrigated_terms_with_cache(),
263
+ cumulative_threshold=MIN_AREA_THRESHOLD
264
+ )
265
+
266
+
267
+ def sample_truncated_normal(
268
+ *, iterations: int, value: float, sd: float, min: float, max: float, seed: Optional[int] = None, **_
269
+ ) -> NDArray:
270
+ """Randomly sample a model parameter with a truncated normal distribution."""
271
+ return truncated_normal_1d(shape=(1, iterations), mu=value, sigma=sd, low=min, high=max, seed=seed)
272
+
273
+
274
+ def sample_plus_minus_uncertainty(
275
+ *, iterations: int, value: float, uncertainty: float, seed: Optional[int] = None, **_
276
+ ) -> NDArray:
277
+ """Randomly sample a model parameter with a plus/minus uncertainty distribution."""
278
+ return plus_minus_uncertainty_to_normal_1d(shape=(1, iterations), value=value, uncertainty=uncertainty, seed=seed)
279
+
280
+
281
+ def sample_plus_minus_error(
282
+ *, iterations: int, value: float, error: float, seed: Optional[int] = None, **_
283
+ ) -> NDArray:
284
+ """Randomly sample a model parameter with a truncated normal distribution described using plus/minus error."""
285
+ sd = value * (error / 200)
286
+ low = value - (value * (error / 100))
287
+ high = value + (value * (error / 100))
288
+ return truncated_normal_1d(shape=(1, iterations), mu=value, sigma=sd, low=low, high=high, seed=seed)
289
+
290
+
291
+ def sample_constant(*, iterations: int, value: float, **_) -> NDArray:
292
+ """Sample a constant model parameter."""
293
+ return repeat_single(shape=(1, iterations), value=value)
294
+
295
+
296
+ def format_bool(value: Optional[bool]) -> str:
297
+ """Format a bool for logging in a table."""
298
+ return str(bool(value))
299
+
300
+
301
+ def format_number(value: Optional[float]) -> str:
302
+ """Format a float for logging in a table."""
303
+ return f"{value:.1f}" if isinstance(value, (float, int)) else "None"
304
+
305
+
306
+ def format_enum(value: Optional[Enum]) -> str:
307
+ """Format an enum for logging in a table."""
308
+ return value.value if isinstance(value, Enum) else "None"
309
+
310
+
311
+ def format_bool_list(values: Optional[list[bool]]) -> str:
312
+ """Format a list of bools for logging in a table."""
313
+ return (
314
+ " ".join(format_bool(value) for value in values) or "None" if isinstance(values, list)
315
+ else "None"
316
+ )
317
+
318
+
319
+ def format_number_list(values: Optional[list[float]]) -> str:
320
+ """Format a list of floats for logging in a table."""
321
+ return (
322
+ " ".join(format_number(value) for value in values) or "None"if isinstance(values, list)
323
+ else "None"
324
+ )
@@ -1,15 +1,18 @@
1
1
  """
2
- Full Grass Consumption
2
+ Cycle Pasture Grass
3
3
 
4
4
  This model estimates the energetic requirements of ruminants and can be used to estimate the amount of grass they graze.
5
5
  Source:
6
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
+ This version of the model will run at the Cycle level, if at least one Cycle Input is given as feed
9
+ (see https://www.hestia.earth/schema/Input#isAnimalFeed).
7
10
  """
8
11
  from hestia_earth.schema import TermTermType
9
12
  from hestia_earth.utils.model import filter_list_term_type
10
13
  from hestia_earth.utils.tools import list_sum
11
14
 
12
- from hestia_earth.models.log import logRequirements, logShouldRun
15
+ from hestia_earth.models.log import logRequirements, logShouldRun, debugValues
13
16
  from hestia_earth.models.utils.input import _new_input
14
17
  from hestia_earth.models.utils.term import get_wool_terms
15
18
  from hestia_earth.models.utils.completeness import _is_term_type_complete, _is_term_type_incomplete
@@ -30,7 +33,7 @@ from .pastureGrass_utils import (
30
33
  REQUIREMENTS = {
31
34
  "Cycle": {
32
35
  "completeness.animalFeed": "True",
33
- "completeness.animalPopulation": "False",
36
+ "completeness.animalPopulation": "True",
34
37
  "completeness.freshForage": "False",
35
38
  "site": {
36
39
  "@type": "Site",
@@ -45,6 +48,19 @@ REQUIREMENTS = {
45
48
  "term.termType": "landCover"
46
49
  }
47
50
  }],
51
+ "inputs": [{
52
+ "@type": "Input",
53
+ "term.units": "kg",
54
+ "value": "> 0",
55
+ "isAnimalFeed": "True",
56
+ "optional": {
57
+ "properties": [{
58
+ "@type": "Property",
59
+ "value": "",
60
+ "term.@id": ["neutralDetergentFibreContent", "energyContentHigherHeatingValue"]
61
+ }]
62
+ }
63
+ }],
48
64
  "animals": [{
49
65
  "@type": "Animal",
50
66
  "value": "> 0",
@@ -93,19 +109,6 @@ REQUIREMENTS = {
93
109
  }
94
110
  }],
95
111
  "optional": {
96
- "inputs": [{
97
- "@type": "Input",
98
- "term.units": "kg",
99
- "value": "> 0",
100
- "isAnimalFeed": "True",
101
- "optional": {
102
- "properties": [{
103
- "@type": "Property",
104
- "value": "",
105
- "term.@id": ["neutralDetergentFibreContent", "energyContentHigherHeatingValue"]
106
- }]
107
- }
108
- }],
109
112
  "products": [{
110
113
  "@type": "Product",
111
114
  "value": "",
@@ -169,6 +172,17 @@ def _calculate_GE(
169
172
  NEwork = _sum_values(values, 3)
170
173
  NEp = _sum_values(values, 4)
171
174
  NEg = _sum_values(values, 5)
175
+
176
+ debugValues(cycle, model=MODEL, term=MODEL_KEY, model_key=MODEL_KEY,
177
+ NEm=NEm,
178
+ NEa=NEa,
179
+ NEl=NEl,
180
+ NEwork=NEwork,
181
+ NEp=NEp,
182
+ NEg=NEg,
183
+ NEm_feed=NEm_feed,
184
+ NEg_feed=NEg_feed)
185
+
172
186
  return (NEm + NEa + NEl + NEwork + NEp - NEm_feed)/REM + (NEg + NEwool - NEg_feed)/REG
173
187
 
174
188
 
@@ -207,17 +221,20 @@ def _run_practice(cycle: dict, meanDE: float, meanECHHV: float, system: dict):
207
221
  def _should_run(cycle: dict, practices: dict):
208
222
  systems = filter_list_term_type(cycle.get('practices', []), TermTermType.SYSTEM)
209
223
  animalFeed_complete = _is_term_type_complete(cycle, 'animalFeed')
210
- animalPopulation_incomplete = _is_term_type_incomplete(cycle, 'animalPopulation')
224
+ animalPopulation_complete = _is_term_type_complete(cycle, 'animalPopulation')
211
225
  freshForage_incomplete = _is_term_type_incomplete(cycle, 'freshForage')
212
226
  all_animals_have_value = all([a.get('value', 0) > 0 for a in cycle.get('animals', [])])
213
227
 
228
+ has_cycle_inputs_feed = any([i.get('isAnimalFeed', False) for i in cycle.get('inputs', [])])
229
+
214
230
  meanDE = calculate_meanDE(practices)
215
231
  meanECHHV = calculate_meanECHHV(practices)
216
232
 
217
233
  should_run = all([
218
234
  animalFeed_complete,
219
- animalPopulation_incomplete,
235
+ animalPopulation_complete,
220
236
  freshForage_incomplete,
237
+ has_cycle_inputs_feed,
221
238
  all_animals_have_value,
222
239
  len(systems) > 0,
223
240
  len(practices) > 0,
@@ -228,8 +245,9 @@ def _should_run(cycle: dict, practices: dict):
228
245
  for term_id in [MODEL_KEY] + [practice_input_id(p) for p in practices]:
229
246
  logRequirements(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
230
247
  term_type_animalFeed_complete=animalFeed_complete,
231
- term_type_animalPopulation_incomplete=animalPopulation_incomplete,
248
+ term_type_animalPopulation_complete=animalPopulation_complete,
232
249
  term_type_freshForage_incomplete=freshForage_incomplete,
250
+ has_cycle_inputs_feed=has_cycle_inputs_feed,
233
251
  all_animals_have_value=all_animals_have_value,
234
252
  meanDE=meanDE,
235
253
  meanECHHV=meanECHHV)
@@ -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
4
4
  from hestia_earth.utils.tools import list_sum, safe_parse_float
5
5
 
6
- from hestia_earth.models.log import debugValues, logRequirements, logShouldRun
6
+ from hestia_earth.models.log import debugValues
7
7
  from hestia_earth.models.utils.input import get_feed_inputs
8
8
  from hestia_earth.models.utils.term import get_lookup_value
9
9
  from hestia_earth.models.utils.property import get_node_property, get_node_property_value, node_property_lookup_value
@@ -98,7 +98,7 @@ _NEa_BY_GROUPING = {
98
98
 
99
99
  def _calculate_NEa(cycle: dict, animal: dict, system: dict, NEm: float) -> float:
100
100
  grouping = _get_grouping(animal)
101
- return _NEa_BY_GROUPING.get(grouping, lambda *args: None)(cycle, animal, system, NEm)
101
+ return _NEa_BY_GROUPING.get(grouping, lambda *args: 0)(cycle, animal, system, NEm)
102
102
 
103
103
 
104
104
  def _calculate_NEl_cattleAndBuffalo(cycle: dict, animal: dict) -> float:
@@ -156,7 +156,7 @@ _NEl_BY_GROUPING = {
156
156
 
157
157
  def _calculate_NEl(cycle: dict, animal: dict) -> float:
158
158
  grouping = _get_grouping(animal)
159
- return _NEl_BY_GROUPING.get(grouping, lambda *args: None)(cycle, animal)
159
+ return _NEl_BY_GROUPING.get(grouping, lambda *args: 0)(cycle, animal)
160
160
 
161
161
 
162
162
  def _calculate_NEwork(cycle: dict, animal: dict, NEm: float) -> float:
@@ -347,8 +347,6 @@ def calculate_NEfeed(node: dict) -> tuple:
347
347
 
348
348
 
349
349
  def get_animal_values(cycle: dict, animal: dict, system: dict):
350
- term_id = animal.get('term', {}).get('@id')
351
-
352
350
  NEm = _calculate_NEm(cycle, animal)
353
351
  NEa = _calculate_NEa(cycle, animal, system, NEm)
354
352
  NEl = _calculate_NEl(cycle, animal)
@@ -356,14 +354,6 @@ def get_animal_values(cycle: dict, animal: dict, system: dict):
356
354
  NEp = _calculate_NEp(cycle, animal, NEm)
357
355
  NEg = _calculate_NEg(cycle, animal)
358
356
 
359
- logRequirements(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
360
- NEm=NEm,
361
- NEa=NEa,
362
- NEl=NEl,
363
- NEwork=NEwork,
364
- NEp=NEp,
365
- NEg=NEg)
366
-
367
357
  return (NEm, NEa, NEl, NEwork, NEp, NEg)
368
358
 
369
359
 
@@ -394,14 +384,7 @@ def should_run_practice(cycle: dict):
394
384
  term_id = practice.get('term', {}).get('@id')
395
385
  key_term_type = practice.get('key', {}).get('termType')
396
386
  value = practice.get('value', [])
397
-
398
- logRequirements(cycle, model=MODEL, term=term_id,
399
- practice_value=list_sum(value),
400
- practice_key_term_type=key_term_type)
401
-
402
- should_run = all([len(value) > 0, term_id == MODEL_KEY, key_term_type in KEY_TERM_TYPES])
403
- logShouldRun(cycle, MODEL, term_id, should_run)
404
- return should_run
387
+ return all([len(value) > 0, term_id == MODEL_KEY, key_term_type in KEY_TERM_TYPES])
405
388
 
406
389
  return should_run
407
390