hestia-earth-models 0.64.7__py3-none-any.whl → 0.64.9__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 (58) hide show
  1. hestia_earth/models/cycle/animal/milkYield.py +10 -22
  2. hestia_earth/models/cycle/siteArea.py +2 -1
  3. hestia_earth/models/cycle/unknownPreSeasonWaterRegime.py +0 -1
  4. hestia_earth/models/environmentalFootprintV3/soilQualityIndexLandOccupation.py +73 -82
  5. hestia_earth/models/environmentalFootprintV3/soilQualityIndexLandTransformation.py +168 -0
  6. hestia_earth/models/environmentalFootprintV3/soilQualityIndexTotalLandUseEffects.py +77 -0
  7. hestia_earth/models/environmentalFootprintV3/utils.py +1 -1
  8. hestia_earth/models/faostat2018/landTransformationFromCropland100YearAverage.py +3 -2
  9. hestia_earth/models/faostat2018/landTransformationFromCropland20YearAverage.py +3 -2
  10. hestia_earth/models/frischknechtEtAl2000/ionisingRadiationKbqU235Eq.py +69 -37
  11. hestia_earth/models/hyde32/utils.py +4 -0
  12. hestia_earth/models/ipcc2019/animal/fatContent.py +38 -0
  13. hestia_earth/models/ipcc2019/animal/liveweightGain.py +3 -54
  14. hestia_earth/models/ipcc2019/animal/liveweightPerHead.py +3 -54
  15. hestia_earth/models/ipcc2019/animal/pastureGrass.py +3 -1
  16. hestia_earth/models/ipcc2019/animal/pregnancyRateTotal.py +38 -0
  17. hestia_earth/models/ipcc2019/animal/trueProteinContent.py +38 -0
  18. hestia_earth/models/ipcc2019/animal/utils.py +87 -3
  19. hestia_earth/models/ipcc2019/animal/weightAtMaturity.py +4 -10
  20. hestia_earth/models/ipcc2019/co2ToAirAboveGroundBiomassStockChangeLandUseChange.py +191 -0
  21. hestia_earth/models/ipcc2019/co2ToAirBelowGroundBiomassStockChangeLandUseChange.py +204 -0
  22. hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +255 -35
  23. hestia_earth/models/ipcc2019/co2ToAirSoilOrganicCarbonStockChangeManagementChange.py +63 -149
  24. hestia_earth/models/ipcc2019/pastureGrass.py +3 -1
  25. hestia_earth/models/mocking/search-results.json +2026 -26
  26. hestia_earth/models/pooreNemecek2018/landOccupationDuringCycle.py +1 -1
  27. hestia_earth/models/poschEtAl2008/terrestrialAcidificationPotentialAccumulatedExceedance.py +4 -1
  28. hestia_earth/models/poschEtAl2008/terrestrialEutrophicationPotentialAccumulatedExceedance.py +4 -1
  29. hestia_earth/models/site/management.py +3 -5
  30. hestia_earth/models/utils/__init__.py +5 -4
  31. hestia_earth/models/utils/impact_assessment.py +13 -4
  32. hestia_earth/models/utils/input.py +5 -2
  33. hestia_earth/models/utils/site.py +4 -2
  34. hestia_earth/models/version.py +1 -1
  35. {hestia_earth_models-0.64.7.dist-info → hestia_earth_models-0.64.9.dist-info}/METADATA +2 -2
  36. {hestia_earth_models-0.64.7.dist-info → hestia_earth_models-0.64.9.dist-info}/RECORD +58 -44
  37. tests/models/cycle/animal/test_milkYield.py +1 -14
  38. tests/models/environmentalFootprintV3/test_soilQualityIndexLandOccupation.py +97 -66
  39. tests/models/environmentalFootprintV3/test_soilQualityIndexLandTransformation.py +176 -0
  40. tests/models/environmentalFootprintV3/test_soilQualityIndexTotalLandUseEffects.py +55 -0
  41. tests/models/frischknechtEtAl2000/test_ionisingRadiationKbqU235Eq.py +67 -44
  42. tests/models/ipcc2019/animal/test_fatContent.py +22 -0
  43. tests/models/ipcc2019/animal/test_liveweightGain.py +4 -2
  44. tests/models/ipcc2019/animal/test_liveweightPerHead.py +4 -2
  45. tests/models/ipcc2019/animal/test_pregnancyRateTotal.py +22 -0
  46. tests/models/ipcc2019/animal/test_trueProteinContent.py +22 -0
  47. tests/models/ipcc2019/animal/test_weightAtMaturity.py +2 -1
  48. tests/models/ipcc2019/test_co2ToAirAboveGroundBiomassStockChangeLandUseChange.py +83 -0
  49. tests/models/ipcc2019/test_co2ToAirBelowGroundBiomassStockChangeLandUseChange.py +83 -0
  50. tests/models/ipcc2019/test_co2ToAirCarbonStockChange_utils.py +6 -6
  51. tests/models/ipcc2019/test_co2ToAirSoilOrganicCarbonStockChangeManagementChange.py +5 -4
  52. tests/models/poschEtAl2008/test_terrestrialAcidificationPotentialAccumulatedExceedance.py +30 -17
  53. tests/models/poschEtAl2008/test_terrestrialEutrophicationPotentialAccumulatedExceedance.py +28 -14
  54. tests/models/site/test_management.py +4 -1
  55. tests/models/utils/test_input.py +65 -1
  56. {hestia_earth_models-0.64.7.dist-info → hestia_earth_models-0.64.9.dist-info}/LICENSE +0 -0
  57. {hestia_earth_models-0.64.7.dist-info → hestia_earth_models-0.64.9.dist-info}/WHEEL +0 -0
  58. {hestia_earth_models-0.64.7.dist-info → hestia_earth_models-0.64.9.dist-info}/top_level.txt +0 -0
@@ -1,11 +1,11 @@
1
- from functools import reduce
2
1
  from hestia_earth.schema import TermTermType
3
- from hestia_earth.utils.tools import list_sum, flatten, non_empty_list
2
+ from hestia_earth.utils.lookup import get_table_value, download_lookup, column_name
3
+ from hestia_earth.utils.model import filter_list_term_type
4
+ from hestia_earth.utils.tools import flatten
4
5
 
5
- from hestia_earth.models.log import logRequirements, logShouldRun
6
- from hestia_earth.models.utils.emission import filter_emission_inputs
6
+ from hestia_earth.models.log import logRequirements, logShouldRun, log_as_table
7
7
  from hestia_earth.models.utils.indicator import _new_indicator
8
- from hestia_earth.models.utils.lookup import factor_value
8
+ from hestia_earth.models.utils.lookup import _node_value
9
9
  from . import MODEL
10
10
 
11
11
  REQUIREMENTS = {
@@ -18,7 +18,7 @@ REQUIREMENTS = {
18
18
  "ionisingCompoundsToWaterInputsProduction",
19
19
  "ionisingCompoundsToSaltwaterInputsProduction"
20
20
  ],
21
- "inputs": [{"@type": "Input", "term.termType": "waste"}]
21
+ "inputs": {"@type": "Term", "term.termType": "waste", "term.units": "kg"}
22
22
  }]
23
23
  }
24
24
  }
@@ -30,15 +30,23 @@ LOOKUPS = {
30
30
  ]
31
31
  }
32
32
  RETURNS = {
33
- "Indicator": {
33
+ "Indicator": [{
34
34
  "value": "",
35
35
  "inputs": ""
36
- }
36
+ }]
37
37
  }
38
38
 
39
39
  TERM_ID = 'ionisingRadiationKbqU235Eq'
40
40
 
41
41
 
42
+ def _valid_waste(input: dict) -> bool:
43
+ return input.get('units', '').startswith("kg") and input.get('termType', '') == TermTermType.WASTE.value
44
+
45
+
46
+ def _valid_emission(emission: dict) -> bool:
47
+ return len(emission.get('inputs', [])) == 1 and isinstance(_node_value(emission), (int, float))
48
+
49
+
42
50
  def _indicator(value: float, input: dict):
43
51
  indicator = _new_indicator(TERM_ID, MODEL)
44
52
  indicator['value'] = value
@@ -46,45 +54,69 @@ def _indicator(value: float, input: dict):
46
54
  return indicator
47
55
 
48
56
 
49
- def _run(grouped_emissions_inputs: list):
50
- input = grouped_emissions_inputs[0].get('input')
51
- values = [
52
- factor_value(
53
- model=MODEL,
54
- term_id=TERM_ID,
55
- lookup_name=f"{TermTermType.WASTE.value}.csv",
56
- lookup_col=i.get('emission').get('term', {}).get('@id')
57
- )(data=i.get('emission') | {'term': i.get('input')})
58
- for i in grouped_emissions_inputs
57
+ def _run(emissions: list):
58
+ indicators = [
59
+ _indicator(value=emission['value'] * emission['coefficient'], input=emission['input'])
60
+ for emission in emissions
59
61
  ]
60
- value = list_sum(values)
61
- return _indicator(value, input) if value else None
62
+ return indicators
62
63
 
63
64
 
64
65
  def _should_run(impact_assessment: dict):
65
- emissions = flatten([
66
- ([
67
- {'emission': emission, 'input': input}
68
- for input in filter_emission_inputs(emission, TermTermType.WASTE)
66
+ emissions = [emission for emission in filter_list_term_type(impact_assessment.get('emissionsResourceUse', []),
67
+ TermTermType.EMISSION)
68
+ if emission.get('term', {}).get('@id', '') in LOOKUPS[TermTermType.WASTE.value]]
69
+
70
+ has_emissions = bool(emissions)
71
+
72
+ emissions_unpacked = flatten(
73
+ [
74
+ [
75
+ {
76
+ "input-term-id": input.get('@id'),
77
+ "input-term-type": input.get('termType'),
78
+ "indicator-term-id": emission['term']['@id'],
79
+ "indicator-is-valid": _valid_emission(emission),
80
+ "input": input,
81
+ "indicator-input-is-valid": _valid_waste(input),
82
+ "value": _node_value(emission),
83
+ "coefficient": get_table_value(array=download_lookup(filename="waste.csv"),
84
+ col_match='termid',
85
+ col_match_with=input.get('@id'),
86
+ col_val=column_name(emission['term']['@id'])) if input else None
87
+ } for input in emission['inputs'] or [{}]]
88
+ for emission in emissions
89
+ ]
90
+ )
91
+
92
+ valid_emission_with_cf = [em for em in emissions_unpacked if em['coefficient'] is not None
93
+ and em['indicator-is-valid'] is True
94
+ and em['indicator-input-is-valid'] is True]
95
+
96
+ valid_input_requirements = all([
97
+ all([
98
+ em['indicator-is-valid'],
99
+ em['indicator-input-is-valid']
69
100
  ])
70
- for emission in impact_assessment.get('emissionsResourceUse', [])
71
- if emission.get('term', {}).get('@id') in LOOKUPS[TermTermType.WASTE.value]
101
+ for em in emissions_unpacked
72
102
  ])
73
- emissions_per_input = reduce(
74
- lambda p, c: p | {c.get('input').get('@id'): p.get(c.get('input').get('@id'), []) + [c]},
75
- emissions,
76
- {}
77
- )
78
103
 
79
- logRequirements(impact_assessment, model=MODEL,
80
- has_emissions=bool(emissions_per_input))
104
+ all_emissions_have_known_cf = all([em['coefficient'] is not None for em in emissions_unpacked]) and bool(
105
+ emissions_unpacked)
106
+
107
+ logRequirements(impact_assessment, model=MODEL, term=TERM_ID,
108
+ has_emissions=has_emissions,
109
+ valid_input_requirements=valid_input_requirements,
110
+ all_emissions_have_known_CF=all_emissions_have_known_cf,
111
+ emissions=log_as_table(emissions_unpacked)
112
+ )
81
113
 
82
- should_run = all([emissions_per_input])
114
+ should_run = valid_input_requirements
83
115
 
84
116
  logShouldRun(impact_assessment, MODEL, TERM_ID, should_run)
85
- return should_run, emissions_per_input
117
+ return should_run, valid_emission_with_cf
86
118
 
87
119
 
88
120
  def run(impact_assessment: dict):
89
- should_run, emissions_per_input = _should_run(impact_assessment)
90
- return non_empty_list(map(_run, emissions_per_input.values())) if should_run else []
121
+ should_run, emissions = _should_run(impact_assessment)
122
+ return _run(emissions) if should_run else []
@@ -45,6 +45,8 @@ def _run(impact_assessment: dict, term_id: str, land_occupation_m2: float, facto
45
45
 
46
46
 
47
47
  def _should_run(impact_assessment: dict, term_id: str, from_site_type: SiteSiteType, years: int):
48
+ site = get_site(impact_assessment)
49
+ has_site = bool(site)
48
50
  cycle = impact_assessment.get('cycle', {})
49
51
  product = get_product(impact_assessment)
50
52
  site = get_site(impact_assessment)
@@ -52,10 +54,12 @@ def _should_run(impact_assessment: dict, term_id: str, from_site_type: SiteSiteT
52
54
  land_transformation_factor = _get_emission_factor(term_id, impact_assessment, years, from_site_type)
53
55
 
54
56
  logRequirements(impact_assessment, model=MODEL, term=term_id,
57
+ has_site=has_site,
55
58
  land_occupation_m2_kg=land_occupation_m2_kg,
56
59
  land_transformation_factor=land_transformation_factor)
57
60
 
58
61
  should_run = all([
62
+ has_site,
59
63
  land_occupation_m2_kg is not None,
60
64
  land_occupation_m2_kg == 0 or land_transformation_factor is not None
61
65
  ])
@@ -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
+ "practices": {
13
+ "@type": "Practice",
14
+ "term.termType": "animalManagement"
15
+ }
16
+ }]
17
+ }
18
+ }
19
+ LOOKUPS = {
20
+ "region-liveAnimal-milkFatContent": "fat content",
21
+ "liveAnimal": "milkYieldPracticeTermIds"
22
+ }
23
+ RETURNS = {
24
+ "Animal": [{
25
+ "practices": [{
26
+ "@type": "Practice",
27
+ "value": ""
28
+ }]
29
+ }]
30
+ }
31
+ TERM_ID = 'fatContent'
32
+
33
+
34
+ def run(cycle: dict):
35
+ animals = should_run_by_productivity_lookup(
36
+ TERM_ID, cycle, list(LOOKUPS.keys())[0], practice_id=LOOKUPS['liveAnimal']
37
+ )
38
+ return list(map(run_animal_by_productivity(TERM_ID, include_practice=True), animals))
@@ -1,11 +1,4 @@
1
- from hestia_earth.schema import TermTermType
2
- from hestia_earth.utils.model import filter_list_term_type
3
-
4
- from hestia_earth.models.log import logRequirements, logShouldRun
5
- from hestia_earth.models.utils.blank_node import merge_blank_nodes
6
- from hestia_earth.models.utils.property import _new_property, node_has_no_property
7
- from .utils import productivity_lookup_value
8
- from .. import MODEL
1
+ from .utils import should_run_by_productivity_lookup, run_animal_by_productivity
9
2
 
10
3
  REQUIREMENTS = {
11
4
  "Cycle": {
@@ -40,50 +33,6 @@ RETURNS = {
40
33
  TERM_ID = 'liveweightGain'
41
34
 
42
35
 
43
- def _property(value: float):
44
- prop = _new_property(TERM_ID, MODEL)
45
- prop['value'] = value
46
- return prop
47
-
48
-
49
- def _run_animal(data: dict):
50
- animal = data.get('animal')
51
- value = data.get('value')
52
- return animal | {
53
- 'properties': merge_blank_nodes(animal.get('properties', []), [_property(value)])
54
- }
55
-
56
-
57
- def _should_run(cycle: dict):
58
- country = cycle.get('site', {}).get('country', {})
59
- country_id = country.get('@id')
60
- live_animals = filter_list_term_type(cycle.get('animals', []), TermTermType.LIVEANIMAL)
61
- live_animals = list(filter(node_has_no_property(TERM_ID), live_animals))
62
- live_animals_with_value = [{
63
- 'animal': animal,
64
- 'value': productivity_lookup_value(TERM_ID, list(LOOKUPS.keys())[0], country, animal)
65
- } for animal in live_animals]
66
-
67
- def _should_run_animal(value: dict):
68
- animal = value.get('animal')
69
- lookup_value = value.get('value')
70
- term_id = animal.get('term').get('@id')
71
-
72
- logRequirements(cycle, model=MODEL, term=term_id, property=TERM_ID,
73
- country_id=country_id,
74
- liveweightGain=lookup_value)
75
-
76
- should_run = all([
77
- country_id,
78
- lookup_value is not None
79
- ])
80
- logShouldRun(cycle, MODEL, term_id, should_run, property=TERM_ID)
81
-
82
- return should_run
83
-
84
- return list(filter(_should_run_animal, live_animals_with_value))
85
-
86
-
87
36
  def run(cycle: dict):
88
- animals = _should_run(cycle)
89
- return list(map(_run_animal, animals))
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))
@@ -1,11 +1,4 @@
1
- from hestia_earth.schema import TermTermType
2
- from hestia_earth.utils.model import filter_list_term_type
3
-
4
- from hestia_earth.models.log import logRequirements, logShouldRun
5
- from hestia_earth.models.utils.blank_node import merge_blank_nodes
6
- from hestia_earth.models.utils.property import _new_property, node_has_no_property
7
- from .utils import productivity_lookup_value
8
- from .. import MODEL
1
+ from .utils import should_run_by_productivity_lookup, run_animal_by_productivity
9
2
 
10
3
  REQUIREMENTS = {
11
4
  "Cycle": {
@@ -40,50 +33,6 @@ RETURNS = {
40
33
  TERM_ID = 'liveweightPerHead'
41
34
 
42
35
 
43
- def _property(value: float):
44
- prop = _new_property(TERM_ID, MODEL)
45
- prop['value'] = value
46
- return prop
47
-
48
-
49
- def _run_animal(data: dict):
50
- animal = data.get('animal')
51
- value = data.get('value')
52
- return animal | {
53
- 'properties': merge_blank_nodes(animal.get('properties', []), [_property(value)])
54
- }
55
-
56
-
57
- def _should_run(cycle: dict):
58
- country = cycle.get('site', {}).get('country', {})
59
- country_id = country.get('@id')
60
- live_animals = filter_list_term_type(cycle.get('animals', []), TermTermType.LIVEANIMAL)
61
- live_animals = list(filter(node_has_no_property(TERM_ID), live_animals))
62
- live_animals_with_value = [{
63
- 'animal': animal,
64
- 'value': productivity_lookup_value(TERM_ID, list(LOOKUPS.keys())[0], country, animal)
65
- } for animal in live_animals]
66
-
67
- def _should_run_animal(value: dict):
68
- animal = value.get('animal')
69
- lookup_value = value.get('value')
70
- term_id = animal.get('term').get('@id')
71
-
72
- logRequirements(cycle, model=MODEL, term=term_id, property=TERM_ID,
73
- country_id=country_id,
74
- liveweightPerHead=lookup_value)
75
-
76
- should_run = all([
77
- country_id,
78
- lookup_value is not None
79
- ])
80
- logShouldRun(cycle, MODEL, term_id, should_run, property=TERM_ID)
81
-
82
- return should_run
83
-
84
- return list(filter(_should_run_animal, live_animals_with_value))
85
-
86
-
87
36
  def run(cycle: dict):
88
- animals = _should_run(cycle)
89
- return list(map(_run_animal, animals))
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))
@@ -137,10 +137,12 @@ LOOKUPS = {
137
137
  "isWoolProducingAnimal"
138
138
  ],
139
139
  "system-liveAnimal-activityCoefficient-ipcc2019": "using animal term @id",
140
+ "landCover": "grazedPastureGrassInputId",
140
141
  "crop-property": ["energyDigestibilityRuminants", "energyContentHigherHeatingValue"],
141
142
  "crop": "grazedPastureGrassInputId",
142
143
  "forage-property": ["energyDigestibilityRuminants", "energyContentHigherHeatingValue"],
143
- "landCover": "grazedPastureGrassInputId"
144
+ "feedFoodAdditive": "hasEnergyContent",
145
+ "feedFoodAdditive-property": ["energyDigestibilityRuminants", "energyContentHigherHeatingValue"]
144
146
  }
145
147
  RETURNS = {
146
148
  "Animal": [{
@@ -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": "pregnancyRateTotal"
17
+ }]
18
+ }
19
+ }]
20
+ }
21
+ }
22
+ LOOKUPS = {
23
+ "region-liveAnimal-pregnancyRateTotal": "pregnancy rate"
24
+ }
25
+ RETURNS = {
26
+ "Animal": [{
27
+ "properties": [{
28
+ "@type": "Property",
29
+ "value": ""
30
+ }]
31
+ }]
32
+ }
33
+ TERM_ID = 'pregnancyRateTotal'
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))
@@ -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
+ "practices": {
13
+ "@type": "Practice",
14
+ "term.termType": "animalManagement"
15
+ }
16
+ }]
17
+ }
18
+ }
19
+ LOOKUPS = {
20
+ "region-liveAnimal-milkTrueProteinContent": "protein content",
21
+ "liveAnimal": "milkYieldPracticeTermIds"
22
+ }
23
+ RETURNS = {
24
+ "Animal": [{
25
+ "practices": [{
26
+ "@type": "Practice",
27
+ "value": ""
28
+ }]
29
+ }]
30
+ }
31
+ TERM_ID = 'trueProteinContent'
32
+
33
+
34
+ def run(cycle: dict):
35
+ animals = should_run_by_productivity_lookup(
36
+ TERM_ID, cycle, list(LOOKUPS.keys())[0], practice_id=LOOKUPS['liveAnimal']
37
+ )
38
+ return list(map(run_animal_by_productivity(TERM_ID, include_practice=True), animals))
@@ -1,11 +1,26 @@
1
+ from hestia_earth.schema import TermTermType
1
2
  from hestia_earth.utils.lookup import download_lookup, get_table_value, column_name, extract_grouped_data
2
- from hestia_earth.utils.tools import safe_parse_float
3
+ from hestia_earth.utils.model import filter_list_term_type
4
+ from hestia_earth.utils.tools import safe_parse_float, non_empty_list
3
5
 
4
- from hestia_earth.models.log import debugMissingLookup
6
+ from hestia_earth.models.log import logRequirements, logShouldRun, debugMissingLookup
7
+ from hestia_earth.models.utils.blank_node import merge_blank_nodes
8
+ from hestia_earth.models.utils.property import _new_property, node_has_no_property
5
9
  from hestia_earth.models.utils.productivity import PRODUCTIVITY, get_productivity
10
+ from hestia_earth.models.utils.term import get_lookup_value
6
11
  from .. import MODEL
7
12
 
8
13
 
14
+ def _get_practice(term_id: str, animal: dict, practice_id: str):
15
+ term = animal.get('term', {})
16
+ value = get_lookup_value(term, practice_id, model=MODEL, term=term_id)
17
+ practice_ids = non_empty_list((value or '').split(';'))
18
+ return next(
19
+ (p for p in animal.get('practices', []) if p.get('term', {}).get('@id') in practice_ids),
20
+ {}
21
+ )
22
+
23
+
9
24
  def productivity_lookup_value(term_id: str, lookup: str, country: dict, animal: dict):
10
25
  country_id = country.get('@id')
11
26
  productivity_key = get_productivity(country)
@@ -16,5 +31,74 @@ def productivity_lookup_value(term_id: str, lookup: str, country: dict, animal:
16
31
  debugMissingLookup(lookup_name, 'termid', country_id, column, value, model=MODEL, term=term_id)
17
32
  return safe_parse_float(
18
33
  extract_grouped_data(value, productivity_key.value) or
19
- extract_grouped_data(value, PRODUCTIVITY.HIGH.value) # defaults to high if low is not found
34
+ extract_grouped_data(value, PRODUCTIVITY.HIGH.value), # defaults to high if low is not found
35
+ None
20
36
  )
37
+
38
+
39
+ def map_live_animals_by_productivity_lookup(term_id: str, cycle: dict, lookup_col: str, practice_id: str = None):
40
+ country = cycle.get('site', {}).get('country', {})
41
+ live_animals = filter_list_term_type(cycle.get('animals', []), TermTermType.LIVEANIMAL)
42
+ live_animals = list(filter(node_has_no_property(term_id), live_animals))
43
+ return [{
44
+ 'animal': animal,
45
+ 'value': productivity_lookup_value(term_id, lookup_col, country, animal)
46
+ } | ({
47
+ 'practice': _get_practice(term_id, animal, practice_id)
48
+ } if practice_id else {}) for animal in live_animals]
49
+
50
+
51
+ def should_run_by_productivity_lookup(term_id: str, cycle: dict, lookup_col: str, practice_id: str = None):
52
+ country = cycle.get('site', {}).get('country', {})
53
+ country_id = country.get('@id')
54
+ live_animals_with_value = map_live_animals_by_productivity_lookup(term_id, cycle, lookup_col, practice_id)
55
+
56
+ def _should_run_animal(value: dict):
57
+ animal = value.get('animal')
58
+ lookup_value = value.get('value')
59
+ practice = value.get('practice')
60
+ term_id = animal.get('term').get('@id')
61
+
62
+ logRequirements(cycle, model=MODEL, term=term_id, property=term_id,
63
+ country_id=country_id,
64
+ **({
65
+ lookup_col.replace('-', '_'): lookup_value
66
+ } | ({
67
+ 'practice': practice.get('term', {}).get('@id')
68
+ } if practice_id else {})))
69
+
70
+ should_run = all([
71
+ country_id,
72
+ not practice_id or bool(practice),
73
+ lookup_value is not None
74
+ ])
75
+ logShouldRun(cycle, MODEL, term_id, should_run, property=term_id)
76
+
77
+ return should_run
78
+
79
+ return list(filter(_should_run_animal, live_animals_with_value))
80
+
81
+
82
+ def _property(term_id: str, value: float):
83
+ prop = _new_property(term_id, MODEL)
84
+ prop['value'] = value
85
+ return prop
86
+
87
+
88
+ def run_animal_by_productivity(term_id: str, include_practice: bool = False):
89
+ def run(data: dict):
90
+ animal = data.get('animal')
91
+ value = data.get('value')
92
+ practice = data.get('practice')
93
+ return animal | ({
94
+ 'practices': [
95
+ (
96
+ p | ({
97
+ 'properties': merge_blank_nodes(p.get('properties', []), [_property(term_id, value)])
98
+ } if p.get('term', {}).get('@id') == practice.get('term', {}).get('@id') else {})
99
+ ) for p in animal.get('practices', [])
100
+ ]
101
+ } if include_practice else {
102
+ 'properties': merge_blank_nodes(animal.get('properties', []), [_property(term_id, value)])
103
+ })
104
+ return run
@@ -2,13 +2,12 @@
2
2
  Note: when the `liveweightPerHead` property is provided, this model will only work if the returned value is
3
3
  greater than or equal to `liveweightPerHead` value.
4
4
  """
5
- from hestia_earth.schema import TermTermType
6
- from hestia_earth.utils.model import filter_list_term_type, find_term_match
5
+ from hestia_earth.utils.model import find_term_match
7
6
 
8
7
  from hestia_earth.models.log import logRequirements, logShouldRun
9
8
  from hestia_earth.models.utils.blank_node import merge_blank_nodes
10
- from hestia_earth.models.utils.property import _new_property, node_has_no_property
11
- from .utils import productivity_lookup_value
9
+ from hestia_earth.models.utils.property import _new_property
10
+ from .utils import map_live_animals_by_productivity_lookup
12
11
  from .. import MODEL
13
12
 
14
13
  REQUIREMENTS = {
@@ -68,12 +67,7 @@ def _run_animal(data: dict):
68
67
  def _should_run(cycle: dict):
69
68
  country = cycle.get('site', {}).get('country', {})
70
69
  country_id = country.get('@id')
71
- live_animals = filter_list_term_type(cycle.get('animals', []), TermTermType.LIVEANIMAL)
72
- live_animals = list(filter(node_has_no_property(TERM_ID), live_animals))
73
- live_animals_with_value = [{
74
- 'animal': animal,
75
- 'value': productivity_lookup_value(TERM_ID, list(LOOKUPS.keys())[0], country, animal)
76
- } for animal in live_animals]
70
+ live_animals_with_value = map_live_animals_by_productivity_lookup(TERM_ID, cycle, list(LOOKUPS.keys())[0])
77
71
 
78
72
  def _should_run_animal(value: dict):
79
73
  animal = value.get('animal')