hestia-earth-models 0.61.8__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.

@@ -9,10 +9,12 @@ from hestia_earth.utils.model import filter_list_term_type
9
9
 
10
10
  from hestia_earth.models.log import logRequirements, log_as_table
11
11
  from hestia_earth.models.utils.blank_node import get_lookup_value
12
+ from hestia_earth.models.utils.completeness import _is_term_type_complete
12
13
  from . import MODEL
13
14
 
14
15
  REQUIREMENTS = {
15
16
  "Cycle": {
17
+ "completeness.operation": "True",
16
18
  "completeness.electricityFuel": "False",
17
19
  "practices": [
18
20
  {"@type": "Practice", "value": "", "term.termType": "operation"}
@@ -42,6 +44,7 @@ def _practice_value(practice: dict):
42
44
 
43
45
 
44
46
  def run(cycle: dict):
47
+ operation_complete = _is_term_type_complete(cycle, TermTermType.OPERATION)
45
48
  practices = filter_list_term_type(cycle.get('practices', []), TermTermType.OPERATION)
46
49
  combustion_practices = [
47
50
  p for p in practices if _lookup_value(p, LOOKUPS['operation'][1]) in _VALID_COMBUSTION_TYPES
@@ -49,8 +52,9 @@ def run(cycle: dict):
49
52
  practices_values = list(map(_practice_value, combustion_practices))
50
53
 
51
54
  logRequirements(cycle, model=MODEL, term=None, key=MODEL_KEY,
55
+ term_type_operation_complete=operation_complete,
52
56
  values=log_as_table(practices_values))
53
57
 
54
- is_complete = all([p.get('fuel_use') for p in practices_values])
58
+ is_complete = all([operation_complete] + [p.get('fuel_use') for p in practices_values])
55
59
 
56
60
  return is_complete
@@ -2,20 +2,21 @@
2
2
  Product Economic Value Share
3
3
 
4
4
  This model quantifies the relative economic value share of each marketable Product in a Cycle.
5
- Marketable Products are all Products in the Glossary with the exception of crop residue not sold.
5
+ Marketable Products are all Products identified with the lookup "generateImpactAssessment = TRUE".
6
6
 
7
7
  It works in the following order:
8
- 1. If revenue data are provided for all marketable products,
8
+ 1. For every product with no `value`, the `economicValueShare` is set to `0`.
9
+ 2. If revenue data are provided for all marketable products,
9
10
  the `economicValueShare` is directly calculated as the share of revenue of each Product;
10
- 2. If the primary product is a crop and it is the only crop Product,
11
- `economicValueShare` is assigned based on a lookup table containing typical global average economic value shares
12
- drawn from [Poore & Nemecek (2018)](https://science.sciencemag.org/content/360/6392/987).
11
+ 3. Based on a lookup table containing typical global average economic value shares
12
+ drawn from [Poore & Nemecek (2018)](https://science.sciencemag.org/content/360/6392/987), if all products have a
13
+ corresponding value, the `economicValueShare` will be proportionally distributed among the products.
13
14
  """
14
- from hestia_earth.schema import TermTermType
15
15
  from hestia_earth.utils.model import find_term_match
16
16
  from hestia_earth.utils.tools import list_sum
17
17
 
18
18
  from hestia_earth.models.log import logRequirements, logShouldRun
19
+ from hestia_earth.models.utils.blank_node import get_lookup_value
19
20
  from hestia_earth.models.utils.cycle import unique_currencies
20
21
  from .utils import lookup_share
21
22
  from .. import MODEL
@@ -25,9 +26,11 @@ REQUIREMENTS = {
25
26
  "products": [{
26
27
  "@type": "Product",
27
28
  "value": "",
28
- "economicValueShare": "",
29
- "revenue": "",
30
- "currency": ""
29
+ "optional": {
30
+ "economicValueShare": "",
31
+ "revenue": "",
32
+ "currency": ""
33
+ }
31
34
  }],
32
35
  "optional": {
33
36
  "completeness.product": ""
@@ -42,7 +45,8 @@ RETURNS = {
42
45
  LOOKUPS = {
43
46
  "@doc": "Depending on the primary product [termType](https://hestia.earth/schema/Product#term)",
44
47
  "crop": "global_economic_value_share",
45
- "excreta": "global_economic_value_share"
48
+ "excreta": "global_economic_value_share",
49
+ "animalProduct": "global_economic_value_share"
46
50
  }
47
51
  MODEL_KEY = 'economicValueShare'
48
52
  MAX_VALUE = 100.5
@@ -60,7 +64,7 @@ def _is_complete(cycle: dict): return cycle.get('completeness', {}).get('product
60
64
  def _no_yield(product): return list_sum(product.get('value', [-1]), -1) == 0
61
65
 
62
66
 
63
- def _total_revenue(products: list): return sum([p.get(MODEL_KEY, 0) for p in products])
67
+ def _total_evs(products: list): return sum([p.get(MODEL_KEY, 0) for p in products])
64
68
 
65
69
 
66
70
  def _product_with_value(product: dict):
@@ -72,18 +76,33 @@ def _rescale_value(products: list, total: float):
72
76
  return list(map(lambda p: {**p, MODEL_KEY: p.get(MODEL_KEY) * 100 / total}, products))
73
77
 
74
78
 
79
+ def _should_run_by_default(cycle: dict, products: list):
80
+ run_by = 'default'
81
+ # only run if all products have the lookup data or value will be incorrect
82
+ products = list(map(_product_with_value, products))
83
+ all_with_economicValueShare = all([p.get(MODEL_KEY) is not None for p in products])
84
+
85
+ should_run = all([all_with_economicValueShare])
86
+
87
+ for p in products:
88
+ term_id = p.get('term', {}).get('@id')
89
+ logRequirements(cycle, model=MODEL, term=term_id, key=MODEL_KEY, by=run_by,
90
+ all_with_economicValueShare=all_with_economicValueShare)
91
+ logShouldRun(cycle, MODEL, term_id, should_run, key=MODEL_KEY, by=run_by)
92
+
93
+ return should_run
94
+
95
+
75
96
  def _run_by_default(cycle: dict, products: list):
76
97
  run_by = 'default'
77
98
  is_complete = _is_complete(cycle)
78
99
  products = list(map(_product_with_value, products))
79
- # remove results where lookup share was not found
80
- results = list(filter(lambda p: p.get(MODEL_KEY) is not None, products))
81
100
  # only return list if the new total of evs is not above threshold
82
- total_revenue = _total_revenue(results)
83
- below_max_threshold = total_revenue <= MAX_VALUE
84
- should_rescale = is_complete and MIN_COMPLETE_VALUE <= total_revenue <= MAX_VALUE
85
- above_min_threshold = True if should_rescale else total_revenue >= MIN_VALUE if is_complete else True
86
- results = _rescale_value(results, total_revenue) if should_rescale else results
101
+ total_economicValueShare = _total_evs(products)
102
+ below_max_threshold = total_economicValueShare <= MAX_VALUE
103
+ should_rescale = is_complete and MIN_COMPLETE_VALUE <= total_economicValueShare <= MAX_VALUE
104
+ above_min_threshold = True if should_rescale else total_economicValueShare >= MIN_VALUE if is_complete else True
105
+ results = _rescale_value(products, total_economicValueShare) if should_rescale else products
87
106
 
88
107
  should_run = all([below_max_threshold, above_min_threshold])
89
108
 
@@ -93,7 +112,7 @@ def _run_by_default(cycle: dict, products: list):
93
112
  logRequirements(cycle, model=MODEL, term=term_id, key=MODEL_KEY, by=run_by,
94
113
  below_max_threshold=below_max_threshold,
95
114
  above_min_threshold=above_min_threshold,
96
- total_revenue=total_revenue)
115
+ total_economicValueShare=total_economicValueShare)
97
116
  logShouldRun(cycle, MODEL, term_id, p_should_run, key=MODEL_KEY, by=run_by)
98
117
 
99
118
  return results if should_run else []
@@ -109,8 +128,8 @@ def _run_by_revenue(products: list):
109
128
  def _should_run_by_revenue(cycle: dict, products: list):
110
129
  run_by = 'revenue'
111
130
  is_complete = _is_complete(cycle)
112
- total_value = _total_revenue(products)
113
- below_threshold = total_value < MAX_VALUE
131
+ total_economicValueShare = _total_evs(products)
132
+ below_threshold = total_economicValueShare < MAX_VALUE
114
133
  # ignore products with no yield
115
134
  products = list(filter(lambda p: not _no_yield(p), products))
116
135
  currencies = unique_currencies(cycle)
@@ -122,7 +141,7 @@ def _should_run_by_revenue(cycle: dict, products: list):
122
141
  term_id = p.get('term', {}).get('@id')
123
142
  logRequirements(cycle, model=MODEL, term=term_id, key=MODEL_KEY, by=run_by,
124
143
  is_complete=is_complete,
125
- total_value=total_value,
144
+ total_economicValueShare=total_economicValueShare,
126
145
  below_threshold=below_threshold,
127
146
  all_with_revenue=all_with_revenue,
128
147
  currencies=';'.join(currencies),
@@ -133,14 +152,14 @@ def _should_run_by_revenue(cycle: dict, products: list):
133
152
 
134
153
 
135
154
  def _run_single_missing_evs(products: list):
136
- total_value = _total_revenue(products)
155
+ total_value = _total_evs(products)
137
156
  return list(map(lambda p: _product(p, 100 - total_value) if p.get(MODEL_KEY) is None else p, products))
138
157
 
139
158
 
140
159
  def _should_run_single_missing_evs(cycle: dict, products: list):
141
160
  run_by = '1-missing-evs'
142
161
  is_complete = _is_complete(cycle)
143
- total_value = _total_revenue(products)
162
+ total_value = _total_evs(products)
144
163
  # ignore products with no yield
145
164
  products = list(filter(lambda p: not _no_yield(p), products))
146
165
  missing_values = [p for p in products if p.get(MODEL_KEY) is None]
@@ -175,20 +194,17 @@ def _should_run_no_value(cycle: dict, product: dict):
175
194
 
176
195
 
177
196
  def _should_have_evs(product: dict):
178
- term_type = product.get('term', {}).get('termType')
179
- return term_type not in [
180
- TermTermType.CROPRESIDUE.value,
181
- TermTermType.EXCRETA.value
182
- ]
197
+ should_generate_ia = get_lookup_value(product.get('term', {}), 'generateImpactAssessment')
198
+ return str(should_generate_ia).lower() != 'false'
183
199
 
184
200
 
185
201
  def run(cycle: dict):
186
202
  products = cycle.get('products', [])
187
- # skip any product that will never has value
203
+ # skip any product that is not marketable
188
204
  products = list(filter(_should_have_evs, products))
189
205
  products = list(map(lambda p: _product(p, 0) if _should_run_no_value(cycle, p) else p, products))
190
206
  return (
191
207
  _run_single_missing_evs(products) if _should_run_single_missing_evs(cycle, products) else
192
208
  _run_by_revenue(products) if _should_run_by_revenue(cycle, products) else
193
- _run_by_default(cycle, products)
209
+ _run_by_default(cycle, products) if _should_run_by_default(cycle, products) else []
194
210
  )
@@ -1,9 +1,12 @@
1
1
  """
2
- Full Grass Consumption
2
+ Animal 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 Animal Blank Node level, if none of the Cycle Input are 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
@@ -138,7 +141,7 @@ RETURNS = {
138
141
  }]
139
142
  }]
140
143
  }
141
- MODEL_KEY = 'animal/pastureGrass'
144
+ MODEL_KEY = 'pastureGrass'
142
145
 
143
146
 
144
147
  def _input(term_id: str, value: float):
@@ -173,7 +176,7 @@ def calculate_NEwool(cycle: dict, animal: dict, products: list, total_weight: fl
173
176
  ])
174
177
  animal_weight = _sum_liveWeightPerHead([animal])
175
178
 
176
- debugValues(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
179
+ debugValues(animal, model=MODEL, term=term_id, model_key=MODEL_KEY,
177
180
  total_energy=total_energy,
178
181
  animal_liveWeightPerHead=animal_weight,
179
182
  total_liveWeightPerHead=total_weight)
@@ -189,7 +192,13 @@ def _calculate_GE(
189
192
  NEm, NEa, NEl, NEwork, NEp, NEg = get_animal_values(cycle, animal, system)
190
193
 
191
194
  NEm_feed, NEg_feed = calculate_NEfeed(animal)
192
- debugValues(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
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,
193
202
  NEm_feed=NEm_feed,
194
203
  NEg_feed=NEg_feed)
195
204
 
@@ -233,7 +242,7 @@ def _run_animal(cycle: dict, meanDE: float, meanECHHV: float, system: dict, prac
233
242
  ) else 0
234
243
  GE = (_calculate_GE(cycle, animal, REM, REG, NEwool, system) / (meanDE/100)) if all([REM, REG]) else 0
235
244
 
236
- debugValues(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
245
+ debugValues(animal, model=MODEL, term=term_id, model_key=MODEL_KEY,
237
246
  REM=REM,
238
247
  REG=REG,
239
248
  NEwool=NEwool,
@@ -248,17 +257,12 @@ def _run_animal(cycle: dict, meanDE: float, meanECHHV: float, system: dict, prac
248
257
  return run
249
258
 
250
259
 
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):
260
+ def _should_run(cycle: dict, animals: list, practices: dict):
257
261
  systems = filter_list_term_type(cycle.get('practices', []), TermTermType.SYSTEM)
258
262
  animalFeed_complete = _is_term_type_complete(cycle, 'animalFeed')
259
263
  animalPopulation_complete = _is_term_type_complete(cycle, 'animalPopulation')
260
264
  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', [])])
265
+ all_animals_have_value = all([a.get('value', 0) > 0 for a in animals])
262
266
 
263
267
  no_cycle_inputs_feed = all([not input.get('isAnimalFeed', False) for input in cycle.get('inputs', [])])
264
268
 
@@ -278,21 +282,23 @@ def _should_run(cycle: dict, practices: dict):
278
282
  ])
279
283
 
280
284
  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)
285
+ for animal in animals:
286
+ logRequirements(animal, model=MODEL, term=term_id, model_key=MODEL_KEY,
287
+ term_type_animalFeed_complete=animalFeed_complete,
288
+ term_type_animalPopulation_complete=animalPopulation_complete,
289
+ term_type_freshForage_incomplete=freshForage_incomplete,
290
+ no_cycle_inputs_feed=no_cycle_inputs_feed,
291
+ all_animals_have_value=all_animals_have_value,
292
+ meanDE=meanDE,
293
+ meanECHHV=meanECHHV)
294
+
295
+ logShouldRun(animal, MODEL, term_id, should_run, model_key=MODEL_KEY)
291
296
 
292
297
  return should_run, meanDE, meanECHHV, systems[0] if systems else None
293
298
 
294
299
 
295
300
  def run(cycle: dict):
301
+ animals = get_animals(cycle)
296
302
  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 []
303
+ should_run, meanDE, meanECHHV, system = _should_run(cycle, animals, practices)
304
+ return list(map(_run_animal(cycle, meanDE, meanECHHV, system, practices), animals)) if should_run else []
@@ -139,13 +139,11 @@ def run(site: dict) -> list[dict]:
139
139
  """
140
140
  should_run, run_data = _should_run(site)
141
141
  _log_data(site, should_run, run_data)
142
- return next(
143
- (
144
- _run_method(method, **run_data[method]) for method in run_data.keys()
145
- if run_data[method]["should_run"]
146
- ),
142
+ return reduce(
143
+ lambda result, method: result + _run_method(method, **run_data[method]),
144
+ run_data,
147
145
  list()
148
- ) if should_run else []
146
+ )
149
147
 
150
148
 
151
149
  def _should_run(site: dict) -> tuple[bool, dict[ModuleType, dict]]:
@@ -25,7 +25,7 @@ from hestia_earth.models.utils.array_builders import (
25
25
  )
26
26
  from hestia_earth.models.utils.blank_node import (
27
27
  cumulative_nodes_lookup_match, cumulative_nodes_term_match, get_node_value, group_nodes_by_year,
28
- group_nodes_by_year_and_month, GroupNodesByYearMode
28
+ group_nodes_by_year_and_month, GroupNodesByYearMode, node_term_match
29
29
  )
30
30
  from hestia_earth.models.utils.cycle import check_cycle_site_ids_identical
31
31
  from hestia_earth.models.utils.descriptive_stats import calc_descriptive_stats
@@ -1227,15 +1227,15 @@ def _check_12_months(inner_dict: dict, keys: set[Any]):
1227
1227
  def _get_grouped_climate_measurements(grouped_measurements: dict) -> dict:
1228
1228
  return {
1229
1229
  year: {
1230
- _InventoryKey.TEMP_MONTHLY: non_empty_list(
1231
- find_term_match(measurements, _TEMPERATURE_MONTHLY_TERM_ID, {}).get("value", [])
1232
- ),
1233
- _InventoryKey.PRECIP_MONTHLY: non_empty_list(
1234
- find_term_match(measurements, _PRECIPITATION_MONTHLY_TERM_ID, {}).get("value", [])
1235
- ),
1236
- _InventoryKey.PET_MONTHLY: non_empty_list(
1237
- find_term_match(measurements, _PET_MONTHLY_TERM_ID, {}).get("value", [])
1238
- )
1230
+ _InventoryKey.TEMP_MONTHLY: non_empty_list(flatten(
1231
+ node.get("value", []) for node in measurements if node_term_match(node, _TEMPERATURE_MONTHLY_TERM_ID)
1232
+ )),
1233
+ _InventoryKey.PRECIP_MONTHLY: non_empty_list(flatten(
1234
+ node.get("value", []) for node in measurements if node_term_match(node, _PRECIPITATION_MONTHLY_TERM_ID)
1235
+ )),
1236
+ _InventoryKey.PET_MONTHLY: non_empty_list(flatten(
1237
+ node.get("value", []) for node in measurements if node_term_match(node, _PET_MONTHLY_TERM_ID)
1238
+ ))
1239
1239
  } for year, measurements in grouped_measurements.items()
1240
1240
  }
1241
1241
 
@@ -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