hestia-earth-models 0.65.6__py3-none-any.whl → 0.65.7__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.
Files changed (51) hide show
  1. hestia_earth/models/config/Cycle.json +2193 -0
  2. hestia_earth/models/config/ImpactAssessment.json +2041 -0
  3. hestia_earth/models/config/Site.json +471 -0
  4. hestia_earth/models/config/__init__.py +71 -0
  5. hestia_earth/models/config/run-calculations.json +42 -0
  6. hestia_earth/models/config/trigger-calculations.json +43 -0
  7. hestia_earth/models/ipcc2019/animal/hoursWorkedPerDay.py +38 -0
  8. hestia_earth/models/mocking/search-results.json +4524 -27
  9. hestia_earth/models/version.py +1 -1
  10. hestia_earth/orchestrator/__init__.py +40 -0
  11. hestia_earth/orchestrator/log.py +62 -0
  12. hestia_earth/orchestrator/models/__init__.py +118 -0
  13. hestia_earth/orchestrator/models/emissions/__init__.py +0 -0
  14. hestia_earth/orchestrator/models/emissions/deleted.py +15 -0
  15. hestia_earth/orchestrator/models/transformations.py +103 -0
  16. hestia_earth/orchestrator/strategies/__init__.py +0 -0
  17. hestia_earth/orchestrator/strategies/merge/__init__.py +42 -0
  18. hestia_earth/orchestrator/strategies/merge/merge_append.py +29 -0
  19. hestia_earth/orchestrator/strategies/merge/merge_default.py +1 -0
  20. hestia_earth/orchestrator/strategies/merge/merge_list.py +103 -0
  21. hestia_earth/orchestrator/strategies/merge/merge_node.py +59 -0
  22. hestia_earth/orchestrator/strategies/run/__init__.py +8 -0
  23. hestia_earth/orchestrator/strategies/run/add_blank_node_if_missing.py +85 -0
  24. hestia_earth/orchestrator/strategies/run/add_key_if_missing.py +9 -0
  25. hestia_earth/orchestrator/strategies/run/always.py +6 -0
  26. hestia_earth/orchestrator/utils.py +116 -0
  27. {hestia_earth_models-0.65.6.dist-info → hestia_earth_models-0.65.7.dist-info}/METADATA +27 -5
  28. {hestia_earth_models-0.65.6.dist-info → hestia_earth_models-0.65.7.dist-info}/RECORD +51 -7
  29. tests/models/ipcc2019/animal/test_hoursWorkedPerDay.py +22 -0
  30. tests/models/test_config.py +115 -0
  31. tests/orchestrator/__init__.py +0 -0
  32. tests/orchestrator/models/__init__.py +0 -0
  33. tests/orchestrator/models/emissions/__init__.py +0 -0
  34. tests/orchestrator/models/emissions/test_deleted.py +21 -0
  35. tests/orchestrator/models/test_transformations.py +29 -0
  36. tests/orchestrator/strategies/__init__.py +0 -0
  37. tests/orchestrator/strategies/merge/__init__.py +0 -0
  38. tests/orchestrator/strategies/merge/test_merge_append.py +33 -0
  39. tests/orchestrator/strategies/merge/test_merge_default.py +7 -0
  40. tests/orchestrator/strategies/merge/test_merge_list.py +327 -0
  41. tests/orchestrator/strategies/merge/test_merge_node.py +95 -0
  42. tests/orchestrator/strategies/run/__init__.py +0 -0
  43. tests/orchestrator/strategies/run/test_add_blank_node_if_missing.py +114 -0
  44. tests/orchestrator/strategies/run/test_add_key_if_missing.py +14 -0
  45. tests/orchestrator/strategies/run/test_always.py +5 -0
  46. tests/orchestrator/test_models.py +69 -0
  47. tests/orchestrator/test_orchestrator.py +27 -0
  48. tests/orchestrator/test_utils.py +109 -0
  49. {hestia_earth_models-0.65.6.dist-info → hestia_earth_models-0.65.7.dist-info}/LICENSE +0 -0
  50. {hestia_earth_models-0.65.6.dist-info → hestia_earth_models-0.65.7.dist-info}/WHEEL +0 -0
  51. {hestia_earth_models-0.65.6.dist-info → hestia_earth_models-0.65.7.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,471 @@
1
+ {
2
+ "models": [
3
+ [
4
+ {
5
+ "key": "measurements",
6
+ "model": "site",
7
+ "value": "organicCarbonPerKgSoil",
8
+ "runStrategy": "add_blank_node_if_missing",
9
+ "mergeStrategy": "list",
10
+ "stage": 1
11
+ },
12
+ {
13
+ "key": "measurements",
14
+ "model": "site",
15
+ "value": "organicCarbonPerM3Soil",
16
+ "runStrategy": "add_blank_node_if_missing",
17
+ "mergeStrategy": "list",
18
+ "stage": 1
19
+ },
20
+ {
21
+ "key": "measurements",
22
+ "model": "site",
23
+ "value": "organicMatterPerKgSoil",
24
+ "runStrategy": "add_blank_node_if_missing",
25
+ "mergeStrategy": "list",
26
+ "stage": 1
27
+ },
28
+ {
29
+ "key": "measurements",
30
+ "model": "site",
31
+ "value": "organicMatterPerM3Soil",
32
+ "runStrategy": "add_blank_node_if_missing",
33
+ "mergeStrategy": "list",
34
+ "stage": 1
35
+ },
36
+ {
37
+ "key": "measurements",
38
+ "model": "site",
39
+ "value": "potentialEvapotranspirationMonthly",
40
+ "runStrategy": "add_blank_node_if_missing",
41
+ "mergeStrategy": "list",
42
+ "stage": 1
43
+ },
44
+ {
45
+ "key": "measurements",
46
+ "model": "site",
47
+ "value": "precipitationMonthly",
48
+ "runStrategy": "add_blank_node_if_missing",
49
+ "mergeStrategy": "list",
50
+ "stage": 1
51
+ },
52
+ {
53
+ "key": "measurements",
54
+ "model": "site",
55
+ "value": "rainfallMonthly",
56
+ "runStrategy": "add_blank_node_if_missing",
57
+ "mergeStrategy": "list",
58
+ "stage": 1
59
+ },
60
+ {
61
+ "key": "measurements",
62
+ "model": "site",
63
+ "value": "temperatureMonthly",
64
+ "runStrategy": "add_blank_node_if_missing",
65
+ "mergeStrategy": "list",
66
+ "stage": 1
67
+ },
68
+ {
69
+ "key": "measurements",
70
+ "model": "site",
71
+ "value": "brackishWater",
72
+ "runStrategy": "add_blank_node_if_missing",
73
+ "mergeStrategy": "list",
74
+ "stage": 1
75
+ },
76
+ {
77
+ "key": "measurements",
78
+ "model": "site",
79
+ "value": "freshWater",
80
+ "runStrategy": "add_blank_node_if_missing",
81
+ "mergeStrategy": "list",
82
+ "stage": 1
83
+ },
84
+ {
85
+ "key": "measurements",
86
+ "model": "site",
87
+ "value": "salineWater",
88
+ "runStrategy": "add_blank_node_if_missing",
89
+ "mergeStrategy": "list",
90
+ "stage": 1
91
+ }
92
+ ],
93
+ [
94
+ {
95
+ "key": "measurements",
96
+ "model": "site",
97
+ "value": "potentialEvapotranspirationAnnual",
98
+ "runStrategy": "add_blank_node_if_missing",
99
+ "mergeStrategy": "list",
100
+ "stage": 1
101
+ },
102
+ {
103
+ "key": "measurements",
104
+ "model": "site",
105
+ "value": "precipitationAnnual",
106
+ "runStrategy": "add_blank_node_if_missing",
107
+ "mergeStrategy": "list",
108
+ "stage": 1
109
+ },
110
+ {
111
+ "key": "measurements",
112
+ "model": "site",
113
+ "value": "rainfallAnnual",
114
+ "runStrategy": "add_blank_node_if_missing",
115
+ "mergeStrategy": "list",
116
+ "stage": 1
117
+ },
118
+ {
119
+ "key": "measurements",
120
+ "model": "site",
121
+ "value": "temperatureAnnual",
122
+ "runStrategy": "add_blank_node_if_missing",
123
+ "mergeStrategy": "list",
124
+ "stage": 1
125
+ }
126
+ ],
127
+ [
128
+ {
129
+ "key": "awareWaterBasinId",
130
+ "model": "geospatialDatabase",
131
+ "value": "aware",
132
+ "runStrategy": "add_key_if_missing",
133
+ "mergeStrategy": "default",
134
+ "stage": 1
135
+ },
136
+ {
137
+ "key": "measurements",
138
+ "model": "geospatialDatabase",
139
+ "value": "ecoClimateZone",
140
+ "runStrategy": "add_blank_node_if_missing",
141
+ "mergeStrategy": "list",
142
+ "stage": 1
143
+ },
144
+ {
145
+ "key": "measurements",
146
+ "model": "geospatialDatabase",
147
+ "value": "drainageClass",
148
+ "runStrategy": "add_blank_node_if_missing",
149
+ "mergeStrategy": "list",
150
+ "stage": 1
151
+ },
152
+ {
153
+ "key": "ecoregion",
154
+ "model": "geospatialDatabase",
155
+ "value": "ecoregion",
156
+ "runStrategy": "add_key_if_missing",
157
+ "mergeStrategy": "default",
158
+ "stage": 1
159
+ },
160
+ {
161
+ "key": "measurements",
162
+ "model": "geospatialDatabase",
163
+ "value": "erodibility",
164
+ "runStrategy": "add_blank_node_if_missing",
165
+ "mergeStrategy": "list",
166
+ "stage": 1
167
+ },
168
+ {
169
+ "key": "measurements",
170
+ "model": "geospatialDatabase",
171
+ "value": "histosol",
172
+ "runStrategy": "add_blank_node_if_missing",
173
+ "mergeStrategy": "list",
174
+ "stage": 1
175
+ },
176
+ {
177
+ "key": "measurements",
178
+ "model": "geospatialDatabase",
179
+ "value": "nutrientLossToAquaticEnvironment",
180
+ "runStrategy": "add_blank_node_if_missing",
181
+ "mergeStrategy": "list",
182
+ "stage": 1
183
+ },
184
+ {
185
+ "key": "measurements",
186
+ "model": "geospatialDatabase",
187
+ "value": "precipitationMonthly",
188
+ "runStrategy": "add_blank_node_if_missing",
189
+ "mergeStrategy": "list",
190
+ "stage": 1
191
+ },
192
+ {
193
+ "key": "measurements",
194
+ "model": "geospatialDatabase",
195
+ "value": "precipitationAnnual",
196
+ "runStrategy": "add_blank_node_if_missing",
197
+ "mergeStrategy": "list",
198
+ "stage": 1
199
+ },
200
+ {
201
+ "key": "measurements",
202
+ "model": "geospatialDatabase",
203
+ "value": "precipitationLongTermAnnualMean",
204
+ "runStrategy": "add_blank_node_if_missing",
205
+ "mergeStrategy": "list",
206
+ "stage": 1
207
+ },
208
+ {
209
+ "key": "region",
210
+ "model": "geospatialDatabase",
211
+ "value": "region",
212
+ "runStrategy": "add_key_if_missing",
213
+ "mergeStrategy": "node",
214
+ "stage": 1
215
+ },
216
+ {
217
+ "key": "measurements",
218
+ "model": "geospatialDatabase",
219
+ "value": "slopeLength",
220
+ "runStrategy": "add_blank_node_if_missing",
221
+ "mergeStrategy": "list",
222
+ "stage": 1
223
+ },
224
+ {
225
+ "key": "measurements",
226
+ "model": "geospatialDatabase",
227
+ "value": "slope",
228
+ "runStrategy": "add_blank_node_if_missing",
229
+ "mergeStrategy": "list",
230
+ "stage": 1
231
+ },
232
+ {
233
+ "key": "measurements",
234
+ "model": "geospatialDatabase",
235
+ "value": "totalNitrogenPerKgSoil",
236
+ "runStrategy": "add_blank_node_if_missing",
237
+ "mergeStrategy": "list",
238
+ "stage": 1
239
+ },
240
+ {
241
+ "key": "measurements",
242
+ "model": "geospatialDatabase",
243
+ "value": "organicCarbonPerKgSoil",
244
+ "runStrategy": "add_blank_node_if_missing",
245
+ "mergeStrategy": "list",
246
+ "stage": 1
247
+ },
248
+ {
249
+ "key": "measurements",
250
+ "model": "geospatialDatabase",
251
+ "value": "soilPh",
252
+ "runStrategy": "add_blank_node_if_missing",
253
+ "mergeStrategy": "list",
254
+ "stage": 1
255
+ },
256
+ {
257
+ "key": "measurements",
258
+ "model": "geospatialDatabase",
259
+ "value": "totalPhosphorusPerKgSoil",
260
+ "runStrategy": "add_blank_node_if_missing",
261
+ "mergeStrategy": "list",
262
+ "stage": 1
263
+ },
264
+ {
265
+ "key": "measurements",
266
+ "model": "geospatialDatabase",
267
+ "value": "temperatureMonthly",
268
+ "runStrategy": "add_blank_node_if_missing",
269
+ "mergeStrategy": "list",
270
+ "stage": 1
271
+ },
272
+ {
273
+ "key": "measurements",
274
+ "model": "geospatialDatabase",
275
+ "value": "temperatureAnnual",
276
+ "runStrategy": "add_blank_node_if_missing",
277
+ "mergeStrategy": "list",
278
+ "stage": 1
279
+ },
280
+ {
281
+ "key": "measurements",
282
+ "model": "geospatialDatabase",
283
+ "value": "temperatureLongTermAnnualMean",
284
+ "runStrategy": "add_blank_node_if_missing",
285
+ "mergeStrategy": "list",
286
+ "stage": 1
287
+ },
288
+ {
289
+ "key": "measurements",
290
+ "model": "geospatialDatabase",
291
+ "value": "heavyWinterPrecipitation",
292
+ "runStrategy": "add_blank_node_if_missing",
293
+ "mergeStrategy": "list",
294
+ "stage": 1
295
+ },
296
+ {
297
+ "key": "measurements",
298
+ "model": "geospatialDatabase",
299
+ "value": "potentialEvapotranspirationMonthly",
300
+ "runStrategy": "add_blank_node_if_missing",
301
+ "mergeStrategy": "list",
302
+ "stage": 1
303
+ },
304
+ {
305
+ "key": "measurements",
306
+ "model": "geospatialDatabase",
307
+ "value": "potentialEvapotranspirationAnnual",
308
+ "runStrategy": "add_blank_node_if_missing",
309
+ "mergeStrategy": "list",
310
+ "stage": 1
311
+ },
312
+ {
313
+ "key": "measurements",
314
+ "model": "geospatialDatabase",
315
+ "value": "potentialEvapotranspirationLongTermAnnualMean",
316
+ "runStrategy": "add_blank_node_if_missing",
317
+ "mergeStrategy": "list",
318
+ "stage": 1
319
+ },
320
+ {
321
+ "key": "measurements",
322
+ "model": "geospatialDatabase",
323
+ "value": "waterDepth",
324
+ "runStrategy": "add_blank_node_if_missing",
325
+ "mergeStrategy": "list",
326
+ "stage": 1
327
+ },
328
+ {
329
+ "key": "measurements",
330
+ "model": "geospatialDatabase",
331
+ "value": "clayContent",
332
+ "runStrategy": "add_blank_node_if_missing",
333
+ "mergeStrategy": "list",
334
+ "stage": 1
335
+ },
336
+ {
337
+ "key": "measurements",
338
+ "model": "geospatialDatabase",
339
+ "value": "sandContent",
340
+ "runStrategy": "add_blank_node_if_missing",
341
+ "mergeStrategy": "list",
342
+ "stage": 1
343
+ }
344
+ ],
345
+ [
346
+ {
347
+ "key": "measurements",
348
+ "model": "geospatialDatabase",
349
+ "value": "siltContent",
350
+ "runStrategy": "add_blank_node_if_missing",
351
+ "mergeStrategy": "list",
352
+ "stage": 1
353
+ },
354
+ {
355
+ "key": "measurements",
356
+ "model": "site",
357
+ "value": "totalNitrogenPerKgSoil",
358
+ "runStrategy": "add_blank_node_if_missing",
359
+ "mergeStrategy": "list",
360
+ "stage": 1
361
+ },
362
+ {
363
+ "key": "measurements",
364
+ "model": "site",
365
+ "value": "netPrimaryProduction",
366
+ "runStrategy": "add_blank_node_if_missing",
367
+ "mergeStrategy": "list",
368
+ "stage": 1
369
+ },
370
+ {
371
+ "key": "measurements",
372
+ "model": "site",
373
+ "value": "waterDepth",
374
+ "runStrategy": "add_blank_node_if_missing",
375
+ "mergeStrategy": "list",
376
+ "stage": 1
377
+ },
378
+ {
379
+ "key": "measurements",
380
+ "model": "site",
381
+ "value": "cationExchangeCapacityPerKgSoil",
382
+ "runStrategy": "add_blank_node_if_missing",
383
+ "mergeStrategy": "list",
384
+ "stage": 1
385
+ }
386
+ ],
387
+ {
388
+ "key": "measurements",
389
+ "model": "site",
390
+ "value": "measurement.value",
391
+ "runStrategy": "always",
392
+ "mergeStrategy": "list",
393
+ "stage": 1
394
+ },
395
+ {
396
+ "key": "measurements",
397
+ "model": "site",
398
+ "value": "soilMeasurement",
399
+ "runStrategy": "always",
400
+ "mergeStrategy": "list",
401
+ "stage": 1
402
+ },
403
+ {
404
+ "key": "management",
405
+ "model": "site",
406
+ "value": "management",
407
+ "runStrategy": "always",
408
+ "mergeStrategy": "list",
409
+ "stage": 2
410
+ },
411
+ [
412
+ {
413
+ "key": "measurements",
414
+ "model": "site",
415
+ "value": "organicCarbonPerHa",
416
+ "runStrategy": "always",
417
+ "mergeStrategy": "list",
418
+ "mergeArgs": {
419
+ "replaceThreshold": ["value", 0.01]
420
+ },
421
+ "stage": 2
422
+ },
423
+ {
424
+ "key": "management",
425
+ "model": "hestia",
426
+ "value": "landCover",
427
+ "runStrategy": "always",
428
+ "mergeStrategy": "list",
429
+ "mergeArgs": {
430
+ "replaceThreshold": ["value", 0.01]
431
+ },
432
+ "stage": 2
433
+ }
434
+ ],
435
+ [
436
+ {
437
+ "key": "measurements",
438
+ "model": "ipcc2019",
439
+ "value": "organicCarbonPerHa",
440
+ "runStrategy": "always",
441
+ "mergeStrategy": "list",
442
+ "mergeArgs": {
443
+ "replaceThreshold": ["value", 0.01]
444
+ },
445
+ "stage": 2
446
+ },
447
+ {
448
+ "key": "measurements",
449
+ "model": "ipcc2019",
450
+ "value": "aboveGroundBiomass",
451
+ "runStrategy": "always",
452
+ "mergeStrategy": "list",
453
+ "mergeArgs": {
454
+ "replaceThreshold": ["value", 0.01]
455
+ },
456
+ "stage": 2
457
+ },
458
+ {
459
+ "key": "measurements",
460
+ "model": "ipcc2019",
461
+ "value": "belowGroundBiomass",
462
+ "runStrategy": "always",
463
+ "mergeStrategy": "list",
464
+ "mergeArgs": {
465
+ "replaceThreshold": ["value", 0.01]
466
+ },
467
+ "stage": 2
468
+ }
469
+ ]
470
+ ]
471
+ }
@@ -0,0 +1,71 @@
1
+ import os
2
+ import json
3
+ from hestia_earth.utils.tools import flatten
4
+
5
+ CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
6
+
7
+
8
+ def _is_aggregated_model(model: dict):
9
+ return isinstance(model, dict) and 'aggregated' in model.get('value', '').lower()
10
+
11
+
12
+ def _remove_aggregated(models: list):
13
+ values = [
14
+ _remove_aggregated(m) if isinstance(m, list) else m if not _is_aggregated_model(m) else None
15
+ for m in models
16
+ ]
17
+ return list(filter(lambda v: v is not None, values))
18
+
19
+
20
+ def _load_config(filename: str) -> dict:
21
+ with open(os.path.join(CURRENT_DIR, f"{filename}.json"), 'r') as f:
22
+ return json.load(f)
23
+
24
+
25
+ def load_config(node_type: str, skip_aggregated_models: bool = False) -> dict:
26
+ """
27
+ Load the configuration associated with the Node Type.
28
+
29
+ Parameters
30
+ ----------
31
+ node_type : str
32
+ The Node Type to load configuration. Can be: `Cycle`, `Site`, `ImpactAssessment`.
33
+ skip_aggregated_models : bool
34
+ Include models using aggregated data. Included by default.
35
+ """
36
+ try:
37
+ config = _load_config(node_type)
38
+ models = config.get('models')
39
+ return config | {'models': _remove_aggregated(models) if skip_aggregated_models else models}
40
+ except FileNotFoundError:
41
+ raise Exception(f"Invalid type {node_type}.")
42
+
43
+
44
+ def config_max_stage(config: dict):
45
+ """
46
+ Get maximum `stage` value from a configuration.
47
+
48
+ Parameters
49
+ ----------
50
+ config : dict
51
+ The Node configuration.
52
+ """
53
+ models = config.get('models', [])
54
+ return max([m.get('stage', 1) for m in flatten(models)])
55
+
56
+
57
+ def _load_stage_config(filename: str, node_type: str, stage: int):
58
+ config = _load_config(filename).get(node_type, {})
59
+
60
+ if f"stage-{stage}" not in config:
61
+ raise Exception(f"Invalid stage configuration for {node_type}: {stage}")
62
+
63
+ return config.get(f"stage-{stage}", [])
64
+
65
+
66
+ def load_run_config(node_type: str, stage: int):
67
+ return _load_stage_config('run-calculations', node_type, stage)
68
+
69
+
70
+ def load_trigger_config(node_type: str, stage: int):
71
+ return _load_stage_config('trigger-calculations', node_type, stage)
@@ -0,0 +1,42 @@
1
+ {
2
+ "Site": {
3
+ "stage-1": [],
4
+ "stage-2": [
5
+ {
6
+ "key": "related",
7
+ "type": "Cycle",
8
+ "stage": 1
9
+ }
10
+ ]
11
+ },
12
+ "Cycle": {
13
+ "stage-1": [
14
+ {
15
+ "key": "nested",
16
+ "type": "Site",
17
+ "stage": 1
18
+ },
19
+ {
20
+ "key": "nested",
21
+ "type": "ImpactAssessment",
22
+ "stage": 1
23
+ }
24
+ ],
25
+ "stage-2": [
26
+ {
27
+ "key": "nested",
28
+ "type": "Site",
29
+ "stage": 2
30
+ }
31
+ ]
32
+ },
33
+ "ImpactAssessment": {
34
+ "stage-1": [
35
+ {
36
+ "key": "nested",
37
+ "type": "Cycle",
38
+ "stage": 2
39
+ }
40
+ ]
41
+ }
42
+ }
@@ -0,0 +1,43 @@
1
+ {
2
+ "Site": {
3
+ "stage-1": [
4
+ {
5
+ "key": "related",
6
+ "type": "Cycle",
7
+ "stage": 1
8
+ }
9
+ ],
10
+ "stage-2": [
11
+ {
12
+ "key": "related",
13
+ "type": "Cycle",
14
+ "stage": 2
15
+ }
16
+ ]
17
+ },
18
+ "Cycle": {
19
+ "stage-1": [
20
+ {
21
+ "key": "nested",
22
+ "type": "Site",
23
+ "stage": 2
24
+ }
25
+ ],
26
+ "stage-2": [
27
+ {
28
+ "key": "related",
29
+ "type": "ImpactAssessment",
30
+ "stage": 1
31
+ }
32
+ ]
33
+ },
34
+ "ImpactAssessment": {
35
+ "stage-1": [
36
+ {
37
+ "key": "related",
38
+ "type": "Cycle",
39
+ "stage": 1
40
+ }
41
+ ]
42
+ }
43
+ }
@@ -0,0 +1,38 @@
1
+ from .utils import should_run_by_productivity_lookup, run_animal_by_productivity
2
+
3
+ REQUIREMENTS = {
4
+ "Cycle": {
5
+ "site": {
6
+ "@type": "Site",
7
+ "country": {"@type": "Term", "termType": "region"}
8
+ },
9
+ "animals": [{
10
+ "@type": "Animal",
11
+ "term.termType": "liveAnimal",
12
+ "none": {
13
+ "properties": [{
14
+ "@type": "Property",
15
+ "value": "",
16
+ "term.@id": "hoursWorkedPerDay"
17
+ }]
18
+ }
19
+ }]
20
+ }
21
+ }
22
+ LOOKUPS = {
23
+ "region-liveAnimal-hoursWorkedPerDay": "hours worked per day"
24
+ }
25
+ RETURNS = {
26
+ "Animal": [{
27
+ "properties": [{
28
+ "@type": "Property",
29
+ "value": ""
30
+ }]
31
+ }]
32
+ }
33
+ TERM_ID = 'hoursWorkedPerDay'
34
+
35
+
36
+ def run(cycle: dict):
37
+ animals = should_run_by_productivity_lookup(TERM_ID, cycle, list(LOOKUPS.keys())[0])
38
+ return list(map(run_animal_by_productivity(TERM_ID), animals))