hestia-earth-models 0.64.8__py3-none-any.whl → 0.64.10__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 (105) hide show
  1. hestia_earth/models/cml2001Baseline/abioticResourceDepletionFossilFuels.py +175 -0
  2. hestia_earth/models/cml2001Baseline/abioticResourceDepletionMineralsAndMetals.py +136 -0
  3. hestia_earth/models/cycle/siteArea.py +2 -1
  4. hestia_earth/models/environmentalFootprintV3/soilQualityIndexLandOccupation.py +73 -82
  5. hestia_earth/models/environmentalFootprintV3/soilQualityIndexLandTransformation.py +102 -116
  6. hestia_earth/models/environmentalFootprintV3/soilQualityIndexTotalLandUseEffects.py +27 -16
  7. hestia_earth/models/faostat2018/landTransformationFromCropland100YearAverage.py +3 -2
  8. hestia_earth/models/faostat2018/landTransformationFromCropland20YearAverage.py +3 -2
  9. hestia_earth/models/frischknechtEtAl2000/ionisingRadiationKbqU235Eq.py +69 -37
  10. hestia_earth/models/ipcc2019/aboveGroundBiomass.py +31 -243
  11. hestia_earth/models/ipcc2019/animal/fatContent.py +38 -0
  12. hestia_earth/models/ipcc2019/animal/liveweightGain.py +3 -54
  13. hestia_earth/models/ipcc2019/animal/liveweightPerHead.py +3 -54
  14. hestia_earth/models/ipcc2019/animal/pregnancyRateTotal.py +38 -0
  15. hestia_earth/models/ipcc2019/animal/trueProteinContent.py +38 -0
  16. hestia_earth/models/ipcc2019/animal/utils.py +87 -3
  17. hestia_earth/models/ipcc2019/animal/weightAtMaturity.py +4 -10
  18. hestia_earth/models/ipcc2019/belowGroundBiomass.py +529 -0
  19. hestia_earth/models/ipcc2019/biomass_utils.py +406 -0
  20. hestia_earth/models/ipcc2019/{co2ToAirAboveGroundBiomassStockChangeLandUseChange.py → co2ToAirAboveGroundBiomassStockChange.py} +19 -7
  21. hestia_earth/models/ipcc2019/{co2ToAirBelowGroundBiomassStockChangeLandUseChange.py → co2ToAirBelowGroundBiomassStockChange.py} +19 -7
  22. hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +402 -73
  23. hestia_earth/models/ipcc2019/{co2ToAirSoilOrganicCarbonStockChangeManagementChange.py → co2ToAirSoilOrganicCarbonStockChange.py} +20 -8
  24. hestia_earth/models/ipcc2019/organicCarbonPerHa.py +3 -1
  25. hestia_earth/models/ipcc2019/pastureGrass_utils.py +6 -7
  26. hestia_earth/models/lcImpactAllEffects100Years/damageToFreshwaterEcosystemsFreshwaterEutrophication.py +2 -2
  27. hestia_earth/models/lcImpactAllEffects100Years/damageToFreshwaterEcosystemsWaterStress.py +2 -2
  28. hestia_earth/models/lcImpactAllEffects100Years/damageToHumanHealthParticulateMatterFormation.py +2 -2
  29. hestia_earth/models/lcImpactAllEffects100Years/damageToHumanHealthPhotochemicalOzoneFormation.py +2 -2
  30. hestia_earth/models/lcImpactAllEffects100Years/damageToHumanHealthWaterStress.py +2 -2
  31. hestia_earth/models/lcImpactAllEffects100Years/damageToMarineEcosystemsMarineEutrophication.py +2 -2
  32. hestia_earth/models/lcImpactAllEffects100Years/damageToTerrestrialEcosystemsPhotochemicalOzoneFormation.py +2 -2
  33. hestia_earth/models/lcImpactAllEffects100Years/damageToTerrestrialEcosystemsTerrestrialAcidification.py +2 -2
  34. hestia_earth/models/lcImpactAllEffectsInfinite/damageToFreshwaterEcosystemsFreshwaterEutrophication.py +2 -2
  35. hestia_earth/models/lcImpactAllEffectsInfinite/damageToFreshwaterEcosystemsWaterStress.py +2 -2
  36. hestia_earth/models/lcImpactAllEffectsInfinite/damageToHumanHealthParticulateMatterFormation.py +2 -2
  37. hestia_earth/models/lcImpactAllEffectsInfinite/damageToHumanHealthPhotochemicalOzoneFormation.py +2 -2
  38. hestia_earth/models/lcImpactAllEffectsInfinite/damageToHumanHealthWaterStress.py +2 -2
  39. hestia_earth/models/lcImpactAllEffectsInfinite/damageToMarineEcosystemsMarineEutrophication.py +2 -2
  40. hestia_earth/models/lcImpactAllEffectsInfinite/damageToTerrestrialEcosystemsPhotochemicalOzoneFormation.py +2 -2
  41. hestia_earth/models/lcImpactAllEffectsInfinite/damageToTerrestrialEcosystemsTerrestrialAcidification.py +2 -2
  42. hestia_earth/models/lcImpactCertainEffects100Years/damageToFreshwaterEcosystemsFreshwaterEutrophication.py +2 -2
  43. hestia_earth/models/lcImpactCertainEffects100Years/damageToFreshwaterEcosystemsWaterStress.py +2 -2
  44. hestia_earth/models/lcImpactCertainEffects100Years/damageToHumanHealthParticulateMatterFormation.py +2 -2
  45. hestia_earth/models/lcImpactCertainEffects100Years/damageToHumanHealthPhotochemicalOzoneFormation.py +2 -2
  46. hestia_earth/models/lcImpactCertainEffects100Years/damageToHumanHealthWaterStress.py +2 -2
  47. hestia_earth/models/lcImpactCertainEffects100Years/damageToMarineEcosystemsMarineEutrophication.py +2 -2
  48. hestia_earth/models/lcImpactCertainEffects100Years/damageToTerrestrialEcosystemsPhotochemicalOzoneFormation.py +2 -2
  49. hestia_earth/models/lcImpactCertainEffects100Years/damageToTerrestrialEcosystemsTerrestrialAcidification.py +2 -2
  50. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToFreshwaterEcosystemsFreshwaterEutrophication.py +2 -2
  51. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToFreshwaterEcosystemsWaterStress.py +2 -2
  52. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToHumanHealthParticulateMatterFormation.py +2 -2
  53. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToHumanHealthPhotochemicalOzoneFormation.py +2 -2
  54. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToHumanHealthWaterStress.py +2 -2
  55. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToMarineEcosystemsMarineEutrophication.py +2 -2
  56. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToTerrestrialEcosystemsPhotochemicalOzoneFormation.py +2 -2
  57. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToTerrestrialEcosystemsTerrestrialAcidification.py +2 -2
  58. hestia_earth/models/mocking/build_mock_search.py +44 -0
  59. hestia_earth/models/mocking/mock_search.py +8 -49
  60. hestia_earth/models/mocking/search-results.json +3078 -575
  61. hestia_earth/models/poschEtAl2008/terrestrialAcidificationPotentialAccumulatedExceedance.py +6 -3
  62. hestia_earth/models/poschEtAl2008/terrestrialEutrophicationPotentialAccumulatedExceedance.py +6 -3
  63. hestia_earth/models/preload_requests.py +1 -1
  64. hestia_earth/models/schmidt2007/utils.py +13 -4
  65. hestia_earth/models/utils/__init__.py +5 -4
  66. hestia_earth/models/utils/blank_node.py +73 -3
  67. hestia_earth/models/utils/constant.py +8 -1
  68. hestia_earth/models/utils/cycle.py +10 -13
  69. hestia_earth/models/utils/fuel.py +1 -1
  70. hestia_earth/models/utils/impact_assessment.py +39 -15
  71. hestia_earth/models/utils/lookup.py +36 -7
  72. hestia_earth/models/utils/pesticideAI.py +1 -1
  73. hestia_earth/models/utils/property.py +11 -4
  74. hestia_earth/models/utils/term.py +15 -8
  75. hestia_earth/models/version.py +1 -1
  76. {hestia_earth_models-0.64.8.dist-info → hestia_earth_models-0.64.10.dist-info}/METADATA +2 -2
  77. {hestia_earth_models-0.64.8.dist-info → hestia_earth_models-0.64.10.dist-info}/RECORD +103 -90
  78. {hestia_earth_models-0.64.8.dist-info → hestia_earth_models-0.64.10.dist-info}/WHEEL +1 -1
  79. tests/models/cml2001Baseline/test_abioticResourceDepletionFossilFuels.py +196 -0
  80. tests/models/cml2001Baseline/test_abioticResourceDepletionMineralsAndMetals.py +124 -0
  81. tests/models/edip2003/test_ozoneDepletionPotential.py +1 -13
  82. tests/models/environmentalFootprintV3/test_soilQualityIndexLandOccupation.py +97 -66
  83. tests/models/environmentalFootprintV3/test_soilQualityIndexLandTransformation.py +136 -74
  84. tests/models/environmentalFootprintV3/test_soilQualityIndexTotalLandUseEffects.py +15 -10
  85. tests/models/frischknechtEtAl2000/test_ionisingRadiationKbqU235Eq.py +67 -44
  86. tests/models/impact_assessment/test_emissions.py +1 -0
  87. tests/models/ipcc2019/animal/test_fatContent.py +22 -0
  88. tests/models/ipcc2019/animal/test_liveweightGain.py +4 -2
  89. tests/models/ipcc2019/animal/test_liveweightPerHead.py +4 -2
  90. tests/models/ipcc2019/animal/test_pregnancyRateTotal.py +22 -0
  91. tests/models/ipcc2019/animal/test_trueProteinContent.py +22 -0
  92. tests/models/ipcc2019/animal/test_weightAtMaturity.py +2 -1
  93. tests/models/ipcc2019/test_aboveGroundBiomass.py +27 -63
  94. tests/models/ipcc2019/test_belowGroundBiomass.py +146 -0
  95. tests/models/ipcc2019/test_biomass_utils.py +115 -0
  96. tests/models/ipcc2019/{test_co2ToAirAboveGroundBiomassStockChangeLandUseChange.py → test_co2ToAirAboveGroundBiomassStockChange.py} +5 -5
  97. tests/models/ipcc2019/{test_co2ToAirBelowGroundBiomassStockChangeLandUseChange.py → test_co2ToAirBelowGroundBiomassStockChange.py} +5 -5
  98. tests/models/ipcc2019/{test_co2ToAirSoilOrganicCarbonStockChangeManagementChange.py → test_co2ToAirSoilOrganicCarbonStockChange.py} +5 -5
  99. tests/models/ipcc2021/test_gwp100.py +2 -2
  100. tests/models/poschEtAl2008/test_terrestrialAcidificationPotentialAccumulatedExceedance.py +30 -17
  101. tests/models/poschEtAl2008/test_terrestrialEutrophicationPotentialAccumulatedExceedance.py +28 -14
  102. hestia_earth/models/ipcc2019/aboveGroundBiomass_utils.py +0 -180
  103. tests/models/ipcc2019/test_aboveGroundBiomass_utils.py +0 -92
  104. {hestia_earth_models-0.64.8.dist-info → hestia_earth_models-0.64.10.dist-info}/LICENSE +0 -0
  105. {hestia_earth_models-0.64.8.dist-info → hestia_earth_models-0.64.10.dist-info}/top_level.txt +0 -0
@@ -4,53 +4,53 @@ based on an updated [LANCA model (De Laurentiis et al. 2019)](
4
4
  http://publications.jrc.ec.europa.eu/repository/handle/JRC113865) and on the LANCA (Regionalised) Characterisation
5
5
  Factors version 2.5 (Horn and Meier, 2018).
6
6
  """
7
- from typing import List
7
+ from typing import List, Tuple, Optional
8
8
 
9
9
  from hestia_earth.schema import TermTermType
10
10
  from hestia_earth.utils.lookup import download_lookup
11
11
  from hestia_earth.utils.model import filter_list_term_type
12
- from hestia_earth.utils.tools import list_sum, safe_parse_date, non_empty_list
12
+ from hestia_earth.utils.tools import list_sum
13
13
 
14
14
  from hestia_earth.models.log import logRequirements, logShouldRun, log_as_table
15
- from hestia_earth.models.utils import hectar_to_square_meter
16
- from hestia_earth.models.utils import pairwise
17
15
  from . import MODEL
18
16
  from .utils import get_coefficient_factor
17
+ from ..utils.impact_assessment import get_country_id
19
18
  from ..utils.indicator import _new_indicator
20
19
  from ..utils.landCover import get_pef_grouping
21
- from ..utils.lookup import fallback_country
20
+ from ..utils.lookup import fallback_country, _node_value
21
+ from ..utils.term import get_land_cover_terms
22
22
 
23
23
  REQUIREMENTS = {
24
24
  "ImpactAssessment": {
25
- "cycle": {
26
- "@type": "Cycle",
27
- "site": {
28
- "area": "> 0",
29
- "@type": "Site",
30
- "management": [{"@type": "Management", "term.termType": "landCover"}],
31
- "optional": {"country": {"@type": "Term", "termType": "region"}}
32
- },
33
- "optional": {
34
- "otherSitesArea": "> 0",
35
- "otherSites": [{
36
- "@type": "Site",
37
- "management": [{"@type": "Management", "term.termType": "landCover"}],
38
- "optional": {"country": {"@type": "Term", "termType": "region"}}
39
- }]
25
+ "emissionsResourceUse": [
26
+ {
27
+ "@type": "Indicator",
28
+ "term.units": "m2 / year",
29
+ "term.termType": "resourceUse",
30
+ "term.name": "Land transformation from",
31
+ "value": "> 0",
32
+ "landCover": {"@type": "Term", "term.termType": "landCover"}
40
33
  }
41
- }
34
+ ],
35
+ "optional": {"country": {"@type": "Term", "termType": "region"}}
42
36
  }
43
37
  }
44
38
 
39
+ # Note: CFs in `region-pefTermGrouping-landTransformation-from.csv` appear to be the opposite values as those in
40
+ # `region-pefTermGrouping-landTransformation-to.csv` but can be different in some cases.
45
41
  LOOKUPS = {
46
- "@doc": "Uses `landCover.csv` for column headers and region-pefTermGrouping-landTransformation-X.csv for to/from CFs. (CFs in `region-pefTermGrouping-landTransformation-from.csv` appear to be the opposite values as those in `region-pefTermGrouping-landTransformation-to.csv` but can be different in some cases)", # noqa: E501
47
- "region-pefTermGrouping-landTransformation-from": "",
48
- "region-pefTermGrouping-landTransformation-to": "",
42
+ "region-pefTermGrouping-landTransformation-from": "using country and `pefTermGrouping` from `landCover`",
43
+ "region-pefTermGrouping-landTransformation-to": "using country and `pefTermGrouping` from `landCover`",
49
44
  "landCover": "pefTermGrouping"
50
45
  }
51
46
 
52
- from_lookup_file = f"{list(LOOKUPS.keys())[1]}.csv"
53
- to_lookup_file = f"{list(LOOKUPS.keys())[2]}.csv"
47
+ from_lookup_file = f"{list(LOOKUPS.keys())[0]}.csv"
48
+ to_lookup_file = f"{list(LOOKUPS.keys())[1]}.csv"
49
+
50
+ LOOKUP = {
51
+ "from": from_lookup_file,
52
+ "to": to_lookup_file
53
+ }
54
54
 
55
55
  RETURNS = {
56
56
  "Indicator": {
@@ -67,116 +67,102 @@ def _indicator(value: float):
67
67
  return indicator
68
68
 
69
69
 
70
- def _run(sites: List[dict]):
71
- result = []
72
- for site in sites:
73
- values = [(transformation_from_factor + transformation_to_factor) * hectar_to_square_meter(site['area'])
74
- for transformation_from_factor, transformation_to_factor in site['transformation_factors']]
75
- result.append(list_sum(values))
76
- return _indicator(list_sum(result)) if result else None
70
+ def _run(transformations: List[dict]):
71
+ values = [(transformation['factor-from'] + transformation['factor-to']) * transformation['area'] for transformation
72
+ in transformations]
73
+ return _indicator(list_sum(values))
77
74
 
78
75
 
79
- def _should_run(impact_assessment: dict):
80
- cycle = impact_assessment.get('cycle', {})
76
+ def _extract_land_cover_from_indicator_id(indicator: dict) -> Optional[str]:
77
+ """
78
+ Given a indicator with term type `resourceUse` return the equivalent `landCover` term
79
+ """
80
+ term_in_id = indicator.get('term', {}).get('@id', '') \
81
+ .removeprefix("landTransformationFrom") \
82
+ .removesuffix("20YearAverageInputsProduction") \
83
+ .removesuffix("20YearAverageDuringCycle")
84
+ term_in_id = term_in_id[0].lower() + term_in_id[1:] if term_in_id else None
85
+ return term_in_id
81
86
 
82
- has_site = bool(cycle.get('site', {}))
83
- site_area = cycle.get('site', {}).get("area", False)
84
- has_area = site_area > 0
85
87
 
86
- has_other_sites = bool(cycle.get('otherSites', []))
88
+ def _is_valid_indicator(indicator: dict, land_cover_term_ids: list[str]) -> bool:
89
+ term_id = _extract_land_cover_from_indicator_id(indicator)
90
+ return term_id in land_cover_term_ids
87
91
 
88
- all_sites = non_empty_list([cycle.get('site')] + cycle.get('otherSites', []))
89
- site_areas = [cycle.get('site', {}).get('area')] + cycle.get('otherSitesArea', [])
90
92
 
91
- sites = [
92
- {
93
- 'site_id': site.get('@id', site.get('id')),
94
- 'transformation_pairs': list(pairwise(
95
- sorted(filter_list_term_type(site.get("management", []), TermTermType.LANDCOVER.value),
96
- key=lambda d: safe_parse_date(d['endDate'])))),
97
- 'country_id_str': site.get('country', {}).get('@id', ''),
98
- 'area': site_areas[index] if len(site_areas) >= index + 1 else None,
99
- }
100
- for index, site in enumerate(all_sites)
101
- ]
93
+ def _should_run(impact_assessment: dict) -> Tuple[bool, list]:
94
+ resource_uses = filter_list_term_type(impact_assessment.get('emissionsResourceUse', []), TermTermType.RESOURCEUSE)
95
+ land_cover_term_ids = get_land_cover_terms() if resource_uses else []
102
96
 
103
- sites = [
104
- site for site in sites
105
- if all([
106
- (site.get('area') or 0) > 0,
107
- site.get('transformation_pairs', [])
108
- ])
109
- ]
97
+ land_transformation_indicators = [i for i in resource_uses if _is_valid_indicator(i, land_cover_term_ids)]
110
98
 
111
- sites = [
112
- site |
99
+ found_transformations = [
113
100
  {
114
- 'column_names': [(get_pef_grouping(from_transformation['term']['@id']),
115
- get_pef_grouping(to_transformation['term']['@id']))
116
- for from_transformation, to_transformation in site['transformation_pairs']],
117
- } for site in sites
101
+ 'area': _node_value(transformation_indicator) * 20,
102
+ 'area-unit': transformation_indicator.get('term', {}).get("units"),
103
+ 'land-cover-id-from': _extract_land_cover_from_indicator_id(transformation_indicator),
104
+ 'land-cover-id-to': transformation_indicator.get('landCover', {}).get("@id"),
105
+ 'indicator-id': transformation_indicator.get('term', {}).get('@id', ''),
106
+ 'good-land-cover-term': transformation_indicator.get('landCover', {}).get('termType') == 'landCover',
107
+ 'country-id': get_country_id(impact_assessment),
108
+ 'area-is-valid': _node_value(transformation_indicator) is not None and _node_value(
109
+ transformation_indicator) > 0,
110
+ 'area-unit-is-valid': transformation_indicator.get('term', {}).get("units") == "m2 / year",
111
+ 'lookup-country': fallback_country(get_country_id(impact_assessment),
112
+ [download_lookup(from_lookup_file), download_lookup(to_lookup_file)]),
113
+ } for transformation_indicator in land_transformation_indicators
118
114
  ]
119
115
 
120
- has_lookup_column = lambda s: s['column_names'] and all([all(pair) for pair in s['column_names']]) # noqa: E731
121
- valid_sites = [site for site in sites if has_lookup_column(site)]
122
-
123
- has_valid_sites = bool(valid_sites)
124
-
125
- valid_sites = [
126
- site |
127
- {
128
- 'country_id': fallback_country(site['country_id_str'],
129
- [download_lookup(from_lookup_file), download_lookup(to_lookup_file)]
130
- )
131
- } for site in valid_sites
116
+ found_transformations_with_coefficient = [
117
+ transformation | {
118
+ "using-fallback-country-region-world-CFs": transformation['lookup-country'] != transformation['country-id'],
119
+ 'factor-from': get_coefficient_factor(
120
+ lookup_name=from_lookup_file,
121
+ country_id=transformation['lookup-country'],
122
+ term_id=TERM_ID,
123
+ occupation_type=get_pef_grouping(transformation['land-cover-id-from'])) if
124
+ transformation['land-cover-id-from'] else None,
125
+ 'factor-to': get_coefficient_factor(
126
+ lookup_name=to_lookup_file,
127
+ country_id=transformation['lookup-country'],
128
+ term_id=TERM_ID,
129
+ occupation_type=get_pef_grouping(transformation['land-cover-id-to'])) if
130
+ transformation['land-cover-id-to'] else None
131
+ } for transformation in found_transformations
132
132
  ]
133
133
 
134
- valid_sites = [
135
- site |
136
- {
137
- 'transformation_factors': [(get_coefficient_factor(lookup_name=from_lookup_file,
138
- country_id=site['country_id'], term_id=TERM_ID,
139
- occupation_type=from_transformation_header),
140
- get_coefficient_factor(lookup_name=to_lookup_file,
141
- country_id=site['country_id'], term_id=TERM_ID,
142
- occupation_type=to_transformation_header))
143
- for from_transformation_header, to_transformation_header in site['column_names']]
144
- } for site in valid_sites
134
+ valid_transformations_with_coef = [
135
+ t for t in found_transformations_with_coefficient if all([
136
+ t['area-is-valid'],
137
+ t['area-unit-is-valid'],
138
+ t['factor-from'] is not None,
139
+ t['factor-to'] is not None
140
+ ])
145
141
  ]
146
142
 
147
- log_equivalent_eu_pef_land_use_names = [
148
- [{
149
- 'site-id': site['site_id'],
150
- 'hestia-term': hestia_term,
151
- 'corine-term': corine_term,
152
- } for hestia_term, corine_term in site['column_names']
153
- ] for site in valid_sites]
154
-
155
- log_transformation_factors = [
156
- [{
157
- 'site-id': site['site_id'],
158
- 'country-id-used-for-factors': site['country_id'],
159
- 'country-id-in-input': site['country_id_str'],
160
- 'factor-from': from_transformation_header,
161
- 'factor-to': to_transformation_header,
162
- } for from_transformation_header, to_transformation_header in site['transformation_factors']
163
- ] for site in valid_sites]
143
+ has_land_transformation_indicators = bool(land_transformation_indicators)
144
+
145
+ all_transformations_are_valid = all(
146
+ [
147
+ all([t['area-is-valid'], t['area-unit-is-valid'], t['good-land-cover-term']])
148
+ for t in found_transformations_with_coefficient
149
+ ]
150
+ ) if found_transformations_with_coefficient else False
164
151
 
165
152
  logRequirements(impact_assessment, model=MODEL, term=TERM_ID,
166
- has_site=has_site,
167
- has_area=has_area,
168
- has_other_sites=has_other_sites,
169
- has_valid_sites=has_valid_sites,
170
- equivalent_EU_PEF_landUse_names=log_as_table(log_equivalent_eu_pef_land_use_names),
171
- transformation_factors=log_as_table(log_transformation_factors)
153
+ has_land_occupation_indicators=has_land_transformation_indicators,
154
+ all_transformations_are_valid=all_transformations_are_valid,
155
+ has_valid_transformations_with_coef=bool(valid_transformations_with_coef),
156
+ found_transformations=log_as_table(found_transformations_with_coefficient)
172
157
  )
173
- should_run = has_valid_sites
174
158
 
175
- logShouldRun(impact_assessment, MODEL, TERM_ID, should_run)
159
+ should_run = has_land_transformation_indicators is False or all([has_land_transformation_indicators,
160
+ all_transformations_are_valid])
176
161
 
177
- return should_run, valid_sites
162
+ logShouldRun(impact_assessment, MODEL, TERM_ID, should_run)
163
+ return should_run, valid_transformations_with_coef
178
164
 
179
165
 
180
166
  def run(impact_assessment: dict):
181
- should_run, sites = _should_run(impact_assessment)
182
- return _run(sites) if should_run else None
167
+ should_run, transformations = _should_run(impact_assessment)
168
+ return _run(transformations) if should_run else None
@@ -5,6 +5,7 @@ http://publications.jrc.ec.europa.eu/repository/handle/JRC113865) and on the LAN
5
5
  Factors version 2.5 (Horn and Meier, 2018).
6
6
  """
7
7
  from hestia_earth.utils.model import find_term_match
8
+ from hestia_earth.utils.tools import list_sum
8
9
 
9
10
  from hestia_earth.models.log import logRequirements, logShouldRun
10
11
  from . import MODEL
@@ -35,32 +36,42 @@ def _indicator(value: float):
35
36
  return indicator
36
37
 
37
38
 
38
- def _run(land_occupation_indicator, transformation_indicator):
39
- value = land_occupation_indicator['value'] + transformation_indicator['value']
40
- return _indicator(value) if value else None
39
+ def _run(indicators: list):
40
+ values = [indicator['value'] for indicator in indicators]
41
+ return _indicator(list_sum(values))
41
42
 
42
43
 
43
- def _should_run(impactassessment: dict):
44
- land_occupation_indicator = find_term_match(impactassessment.get('emissionsResourceUse', []),
45
- "soilQualityIndexLandOccupation")
46
- transformation_indicator = find_term_match(impactassessment.get('emissionsResourceUse', []),
47
- "soilQualityIndexLandTransformation")
44
+ def _should_run(impactassessment: dict) -> tuple[bool, list]:
45
+ land_indicators = [
46
+ i for i in impactassessment.get('emissionsResourceUse', []) if
47
+ i.get('term', {}).get('@id', '') in ['soilQualityIndexLandOccupation', 'soilQualityIndexLandTransformation']
48
+ ]
49
+ has_indicators = bool(land_indicators)
48
50
 
49
- has_valid_values = all([isinstance(land_occupation_indicator.get('value', None), (int, float)),
50
- isinstance(transformation_indicator.get('value', None), (int, float))])
51
+ land_occupation_indicator = find_term_match(land_indicators, "soilQualityIndexLandOccupation",
52
+ default_val=None)
53
+ has_land_occupation_indicator = bool(land_occupation_indicator)
54
+
55
+ land_transformation_indicator = find_term_match(land_indicators, "soilQualityIndexLandTransformation",
56
+ default_val=None)
57
+ has_land_transformation_indicator = bool(land_transformation_indicator)
58
+
59
+ has_valid_values = all([isinstance(indicator.get('value', None), (int, float)) for indicator in land_indicators])
51
60
 
52
61
  logRequirements(impactassessment, model=MODEL, term=TERM_ID,
53
- transformation_indicator=transformation_indicator,
54
- land_occupation_indicator=land_occupation_indicator,
62
+ has_indicators=has_indicators,
63
+ has_land_occupation_indicator=has_land_occupation_indicator,
64
+ has_land_transformation_indicator=has_land_transformation_indicator,
55
65
  has_valid_values=has_valid_values
56
66
  )
57
67
 
58
- should_run = all([transformation_indicator, land_occupation_indicator, has_valid_values])
68
+ should_run = all([has_indicators, has_valid_values,
69
+ has_land_occupation_indicator, has_land_transformation_indicator])
59
70
 
60
71
  logShouldRun(impactassessment, MODEL, TERM_ID, should_run)
61
- return should_run, land_occupation_indicator, transformation_indicator
72
+ return should_run, land_indicators
62
73
 
63
74
 
64
75
  def run(impactassessment: dict):
65
- should_run, land_occupation_indicator, transformation_indicator = _should_run(impactassessment)
66
- return _run(land_occupation_indicator, transformation_indicator) if should_run else None
76
+ should_run, indicators = _should_run(impactassessment)
77
+ return _run(indicators) if should_run else None
@@ -20,7 +20,8 @@ LOOKUPS = {
20
20
  }
21
21
  RETURNS = {
22
22
  "Indicator": [{
23
- "value": ""
23
+ "value": "",
24
+ "landCover": ""
24
25
  }]
25
26
  }
26
27
  TERM_ID = 'landTransformationFromTemporaryCropland100YearAverageDuringCycle,landTransformationFromPermanentCropland100YearAverageDuringCycle' # noqa: E501
@@ -30,7 +31,7 @@ PERMANENT_TERM_ID = 'landTransformationFromPermanentCropland100YearAverageDuring
30
31
 
31
32
 
32
33
  def _indicator(term_id: str, value: float):
33
- indicator = _new_indicator(term_id, MODEL)
34
+ indicator = _new_indicator(term_id, MODEL, 'cropland')
34
35
  indicator['value'] = value
35
36
  return indicator
36
37
 
@@ -20,7 +20,8 @@ LOOKUPS = {
20
20
  }
21
21
  RETURNS = {
22
22
  "Indicator": [{
23
- "value": ""
23
+ "value": "",
24
+ "landCover": ""
24
25
  }]
25
26
  }
26
27
  TERM_ID = 'landTransformationFromTemporaryCropland20YearAverageDuringCycle,landTransformationFromPermanentCropland20YearAverageDuringCycle' # noqa: E501
@@ -30,7 +31,7 @@ PERMANENT_TERM_ID = 'landTransformationFromPermanentCropland20YearAverageDuringC
30
31
 
31
32
 
32
33
  def _indicator(term_id: str, value: float):
33
- indicator = _new_indicator(term_id, MODEL)
34
+ indicator = _new_indicator(term_id, MODEL, 'cropland')
34
35
  indicator['value'] = value
35
36
  return indicator
36
37
 
@@ -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 []