hestia-earth-models 0.64.9__py3-none-any.whl → 0.64.11__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 (125) hide show
  1. hestia_earth/models/cml2001Baseline/abioticResourceDepletionFossilFuels.py +175 -0
  2. hestia_earth/models/cml2001Baseline/abioticResourceDepletionMineralsAndMetals.py +136 -0
  3. hestia_earth/models/cml2001Baseline/eutrophicationPotentialExcludingFate.py +2 -2
  4. hestia_earth/models/cml2001Baseline/terrestrialAcidificationPotentialIncludingFateAverageEurope.py +2 -2
  5. hestia_earth/models/cml2001NonBaseline/eutrophicationPotentialIncludingFateAverageEurope.py +2 -2
  6. hestia_earth/models/cml2001NonBaseline/terrestrialAcidificationPotentialExcludingFate.py +2 -2
  7. hestia_earth/models/cycle/completeness/cropResidue.py +15 -10
  8. hestia_earth/models/cycle/completeness/freshForage.py +60 -0
  9. hestia_earth/models/edip2003/ozoneDepletionPotential.py +2 -2
  10. hestia_earth/models/environmentalFootprintV3/soilQualityIndexLandTransformation.py +2 -2
  11. hestia_earth/models/fantkeEtAl2016/damageToHumanHealthParticulateMatterFormation.py +7 -17
  12. hestia_earth/models/ipcc2013ExcludingFeedbacks/gwp100.py +2 -2
  13. hestia_earth/models/ipcc2013IncludingFeedbacks/gwp100.py +2 -2
  14. hestia_earth/models/ipcc2019/aboveGroundBiomass.py +31 -243
  15. hestia_earth/models/ipcc2019/belowGroundBiomass.py +529 -0
  16. hestia_earth/models/ipcc2019/biomass_utils.py +406 -0
  17. hestia_earth/models/ipcc2019/{co2ToAirAboveGroundBiomassStockChangeLandUseChange.py → co2ToAirAboveGroundBiomassStockChange.py} +19 -7
  18. hestia_earth/models/ipcc2019/{co2ToAirBelowGroundBiomassStockChangeLandUseChange.py → co2ToAirBelowGroundBiomassStockChange.py} +19 -7
  19. hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +402 -73
  20. hestia_earth/models/ipcc2019/{co2ToAirSoilOrganicCarbonStockChangeManagementChange.py → co2ToAirSoilOrganicCarbonStockChange.py} +20 -8
  21. hestia_earth/models/ipcc2019/organicCarbonPerHa.py +3 -1
  22. hestia_earth/models/ipcc2019/pastureGrass_utils.py +6 -7
  23. hestia_earth/models/ipcc2021/gwp100.py +2 -2
  24. hestia_earth/models/lcImpactAllEffects100Years/damageToFreshwaterEcosystemsClimateChange.py +2 -2
  25. hestia_earth/models/lcImpactAllEffects100Years/damageToFreshwaterEcosystemsFreshwaterEutrophication.py +2 -2
  26. hestia_earth/models/lcImpactAllEffects100Years/damageToFreshwaterEcosystemsWaterStress.py +2 -2
  27. hestia_earth/models/lcImpactAllEffects100Years/damageToHumanHealthClimateChange.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/damageToHumanHealthStratosphericOzoneDepletion.py +2 -2
  31. hestia_earth/models/lcImpactAllEffects100Years/damageToHumanHealthWaterStress.py +2 -2
  32. hestia_earth/models/lcImpactAllEffects100Years/damageToMarineEcosystemsMarineEutrophication.py +2 -2
  33. hestia_earth/models/lcImpactAllEffects100Years/damageToTerrestrialEcosystemsClimateChange.py +2 -2
  34. hestia_earth/models/lcImpactAllEffects100Years/damageToTerrestrialEcosystemsPhotochemicalOzoneFormation.py +2 -2
  35. hestia_earth/models/lcImpactAllEffects100Years/damageToTerrestrialEcosystemsTerrestrialAcidification.py +2 -2
  36. hestia_earth/models/lcImpactAllEffectsInfinite/damageToFreshwaterEcosystemsClimateChange.py +2 -2
  37. hestia_earth/models/lcImpactAllEffectsInfinite/damageToFreshwaterEcosystemsFreshwaterEutrophication.py +2 -2
  38. hestia_earth/models/lcImpactAllEffectsInfinite/damageToFreshwaterEcosystemsWaterStress.py +2 -2
  39. hestia_earth/models/lcImpactAllEffectsInfinite/damageToHumanHealthClimateChange.py +2 -2
  40. hestia_earth/models/lcImpactAllEffectsInfinite/damageToHumanHealthParticulateMatterFormation.py +2 -2
  41. hestia_earth/models/lcImpactAllEffectsInfinite/damageToHumanHealthPhotochemicalOzoneFormation.py +2 -2
  42. hestia_earth/models/lcImpactAllEffectsInfinite/damageToHumanHealthStratosphericOzoneDepletion.py +2 -2
  43. hestia_earth/models/lcImpactAllEffectsInfinite/damageToHumanHealthWaterStress.py +2 -2
  44. hestia_earth/models/lcImpactAllEffectsInfinite/damageToMarineEcosystemsMarineEutrophication.py +2 -2
  45. hestia_earth/models/lcImpactAllEffectsInfinite/damageToTerrestrialEcosystemsClimateChange.py +2 -2
  46. hestia_earth/models/lcImpactAllEffectsInfinite/damageToTerrestrialEcosystemsPhotochemicalOzoneFormation.py +2 -2
  47. hestia_earth/models/lcImpactAllEffectsInfinite/damageToTerrestrialEcosystemsTerrestrialAcidification.py +2 -2
  48. hestia_earth/models/lcImpactCertainEffects100Years/damageToFreshwaterEcosystemsFreshwaterEutrophication.py +2 -2
  49. hestia_earth/models/lcImpactCertainEffects100Years/damageToFreshwaterEcosystemsWaterStress.py +2 -2
  50. hestia_earth/models/lcImpactCertainEffects100Years/damageToHumanHealthClimateChange.py +2 -2
  51. hestia_earth/models/lcImpactCertainEffects100Years/damageToHumanHealthParticulateMatterFormation.py +2 -2
  52. hestia_earth/models/lcImpactCertainEffects100Years/damageToHumanHealthPhotochemicalOzoneFormation.py +2 -2
  53. hestia_earth/models/lcImpactCertainEffects100Years/damageToHumanHealthStratosphericOzoneDepletion.py +2 -2
  54. hestia_earth/models/lcImpactCertainEffects100Years/damageToHumanHealthWaterStress.py +2 -2
  55. hestia_earth/models/lcImpactCertainEffects100Years/damageToMarineEcosystemsMarineEutrophication.py +2 -2
  56. hestia_earth/models/lcImpactCertainEffects100Years/damageToTerrestrialEcosystemsClimateChange.py +2 -2
  57. hestia_earth/models/lcImpactCertainEffects100Years/damageToTerrestrialEcosystemsPhotochemicalOzoneFormation.py +2 -2
  58. hestia_earth/models/lcImpactCertainEffects100Years/damageToTerrestrialEcosystemsTerrestrialAcidification.py +2 -2
  59. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToFreshwaterEcosystemsFreshwaterEutrophication.py +2 -2
  60. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToFreshwaterEcosystemsWaterStress.py +2 -2
  61. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToHumanHealthClimateChange.py +2 -2
  62. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToHumanHealthParticulateMatterFormation.py +2 -2
  63. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToHumanHealthPhotochemicalOzoneFormation.py +2 -2
  64. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToHumanHealthStratosphericOzoneDepletion.py +2 -2
  65. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToHumanHealthWaterStress.py +2 -2
  66. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToMarineEcosystemsMarineEutrophication.py +2 -2
  67. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToTerrestrialEcosystemsClimateChange.py +2 -2
  68. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToTerrestrialEcosystemsPhotochemicalOzoneFormation.py +2 -2
  69. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToTerrestrialEcosystemsTerrestrialAcidification.py +2 -2
  70. hestia_earth/models/mocking/build_mock_search.py +44 -0
  71. hestia_earth/models/mocking/mock_search.py +8 -49
  72. hestia_earth/models/mocking/search-results.json +3055 -558
  73. hestia_earth/models/poschEtAl2008/terrestrialAcidificationPotentialAccumulatedExceedance.py +3 -3
  74. hestia_earth/models/poschEtAl2008/terrestrialEutrophicationPotentialAccumulatedExceedance.py +3 -3
  75. hestia_earth/models/preload_requests.py +1 -1
  76. hestia_earth/models/recipe2016Egalitarian/ecosystemDamageOzoneFormation.py +2 -2
  77. hestia_earth/models/recipe2016Egalitarian/freshwaterEutrophicationPotential.py +2 -2
  78. hestia_earth/models/recipe2016Egalitarian/humanDamageOzoneFormation.py +2 -2
  79. hestia_earth/models/recipe2016Egalitarian/marineEutrophicationPotential.py +2 -2
  80. hestia_earth/models/recipe2016Egalitarian/ozoneDepletionPotential.py +2 -2
  81. hestia_earth/models/recipe2016Egalitarian/terrestrialAcidificationPotential.py +2 -2
  82. hestia_earth/models/recipe2016Hierarchist/ecosystemDamageOzoneFormation.py +2 -2
  83. hestia_earth/models/recipe2016Hierarchist/freshwaterEutrophicationPotential.py +2 -2
  84. hestia_earth/models/recipe2016Hierarchist/humanDamageOzoneFormation.py +2 -2
  85. hestia_earth/models/recipe2016Hierarchist/marineEutrophicationPotential.py +2 -2
  86. hestia_earth/models/recipe2016Hierarchist/ozoneDepletionPotential.py +2 -2
  87. hestia_earth/models/recipe2016Hierarchist/terrestrialAcidificationPotential.py +2 -2
  88. hestia_earth/models/recipe2016Individualist/ecosystemDamageOzoneFormation.py +2 -2
  89. hestia_earth/models/recipe2016Individualist/freshwaterEutrophicationPotential.py +2 -2
  90. hestia_earth/models/recipe2016Individualist/humanDamageOzoneFormation.py +2 -2
  91. hestia_earth/models/recipe2016Individualist/marineEutrophicationPotential.py +2 -2
  92. hestia_earth/models/recipe2016Individualist/ozoneDepletionPotential.py +2 -2
  93. hestia_earth/models/recipe2016Individualist/terrestrialAcidificationPotential.py +2 -2
  94. hestia_earth/models/schmidt2007/utils.py +13 -4
  95. hestia_earth/models/utils/blank_node.py +73 -3
  96. hestia_earth/models/utils/constant.py +8 -1
  97. hestia_earth/models/utils/cycle.py +10 -13
  98. hestia_earth/models/utils/fuel.py +1 -1
  99. hestia_earth/models/utils/impact_assessment.py +49 -24
  100. hestia_earth/models/utils/lookup.py +36 -7
  101. hestia_earth/models/utils/pesticideAI.py +1 -1
  102. hestia_earth/models/utils/property.py +11 -4
  103. hestia_earth/models/utils/term.py +15 -8
  104. hestia_earth/models/version.py +1 -1
  105. {hestia_earth_models-0.64.9.dist-info → hestia_earth_models-0.64.11.dist-info}/METADATA +2 -2
  106. {hestia_earth_models-0.64.9.dist-info → hestia_earth_models-0.64.11.dist-info}/RECORD +123 -114
  107. {hestia_earth_models-0.64.9.dist-info → hestia_earth_models-0.64.11.dist-info}/WHEEL +1 -1
  108. tests/models/cml2001Baseline/test_abioticResourceDepletionFossilFuels.py +196 -0
  109. tests/models/cml2001Baseline/test_abioticResourceDepletionMineralsAndMetals.py +124 -0
  110. tests/models/cycle/completeness/test_freshForage.py +21 -0
  111. tests/models/edip2003/test_ozoneDepletionPotential.py +1 -13
  112. tests/models/environmentalFootprintV3/test_soilQualityIndexLandTransformation.py +1 -2
  113. tests/models/impact_assessment/test_emissions.py +1 -0
  114. tests/models/ipcc2019/test_aboveGroundBiomass.py +27 -63
  115. tests/models/ipcc2019/test_belowGroundBiomass.py +146 -0
  116. tests/models/ipcc2019/test_biomass_utils.py +115 -0
  117. tests/models/ipcc2019/{test_co2ToAirAboveGroundBiomassStockChangeLandUseChange.py → test_co2ToAirAboveGroundBiomassStockChange.py} +5 -5
  118. tests/models/ipcc2019/{test_co2ToAirBelowGroundBiomassStockChangeLandUseChange.py → test_co2ToAirBelowGroundBiomassStockChange.py} +5 -5
  119. tests/models/ipcc2019/{test_co2ToAirSoilOrganicCarbonStockChangeManagementChange.py → test_co2ToAirSoilOrganicCarbonStockChange.py} +5 -5
  120. tests/models/ipcc2021/test_gwp100.py +2 -2
  121. tests/models/utils/test_impact_assessment.py +3 -3
  122. hestia_earth/models/ipcc2019/aboveGroundBiomass_utils.py +0 -180
  123. tests/models/ipcc2019/test_aboveGroundBiomass_utils.py +0 -92
  124. {hestia_earth_models-0.64.9.dist-info → hestia_earth_models-0.64.11.dist-info}/LICENSE +0 -0
  125. {hestia_earth_models-0.64.9.dist-info → hestia_earth_models-0.64.11.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,175 @@
1
+ """
2
+ This model calculates the abiotic resource depletion, fossil fuels. Based on the models CML 2002 (Guinée et al., 2002) and van Oers et al. 2002 (method, v.4.8)
3
+
4
+ >The earth contains a finite amount of non-renewable resources, such as fossil fuels like coal, oil and gas. The basic idea behind this impact category is that extracting resources today will force future generations to extract less or different resources. For example, the depletion of V2.0 – 25th August 2023 28 fossil fuels may lead to the non-availability of fossil fuels for future generations. The amount of materials contributing to resource use, fossils, are converted into MJ.
5
+
6
+ Source : [Life Cycle Assessment & the EF methods - Comprehensive coverage of impacts](https://green-business.ec.europa.eu/environmental-footprint-methods/life-cycle-assessment-ef-methods_en)
7
+
8
+ The model accepts any non-renewable energy term that can be expressed in, or converted to, MegaJoules.
9
+
10
+ Source: [JRC Technical reports Suggestions for updating the Product Environmental Footprint (PEF) method](https://eplca.jrc.ec.europa.eu/permalink/PEF_method.pdf#%5B%7B%22num%22%3A80%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C68%2C363%2C0%5D)
11
+
12
+ Source: [Differences between EF model versions](https://eplca.jrc.ec.europa.eu/EFVersioning.html)
13
+ """ # noqa: E501
14
+ from itertools import chain
15
+ from typing import Optional
16
+
17
+ from hestia_earth.schema import TermTermType
18
+ from hestia_earth.utils.lookup import download_lookup, column_name
19
+ from hestia_earth.utils.model import filter_list_term_type
20
+ from hestia_earth.utils.tools import list_sum, flatten
21
+
22
+ from hestia_earth.models.log import logShouldRun, logRequirements, log_as_table
23
+ from . import MODEL
24
+ from ..utils.blank_node import convert_unit
25
+ from ..utils.constant import Units
26
+ from ..utils.indicator import _new_indicator
27
+ from ..utils.lookup import _node_value
28
+
29
+ REQUIREMENTS = {
30
+ "ImpactAssessment": {
31
+ "emissionsResourceUse": [
32
+ {
33
+ "@type": "Indicator",
34
+ "term.termType": "resourceUse",
35
+ "term.@id": ["resourceUseEnergyDepletionInputsProduction", "resourceUseEnergyDepletionDuringCycle"],
36
+ "value": "> 0",
37
+ "inputs":
38
+ {
39
+ "@type": "Input",
40
+ "term.name": "non-renewable\" energy terms only,\"",
41
+ "term.units": ["kg", "m3", "kWh", "MJ"],
42
+ "term.termType": ["fuel", "electricity"],
43
+ "optional": {
44
+ "defaultProperties": [
45
+ {
46
+ "@type": "Property",
47
+ "value": "",
48
+ "term.@id": "energyContentHigherHeatingValue",
49
+ "term.units": "MJ / kg"
50
+ },
51
+ {
52
+ "@type": "Property",
53
+ "value": "",
54
+ "term.@id": "density",
55
+ "term.units": "kg / m3"
56
+ }
57
+ ]
58
+ }
59
+ }
60
+ }
61
+ ]
62
+ }
63
+ }
64
+
65
+ LOOKUPS = {
66
+ "fuel": ["energyContentHigherHeatingValue", "density", "abioticResourceDepletionFossilFuelsCml2001Baseline"],
67
+ "electricity": ["abioticResourceDepletionFossilFuelsCml2001Baseline"]
68
+ }
69
+
70
+ RETURNS = {
71
+ "Indicator": {
72
+ "value": ""
73
+ }
74
+ }
75
+ TERM_ID = 'abioticResourceDepletionFossilFuels'
76
+
77
+ ENERGY_CARRIERS_TERMIDS = REQUIREMENTS['ImpactAssessment']['emissionsResourceUse'][0]['term.@id']
78
+
79
+ INPUTS_TYPES_UNITS = {
80
+ TermTermType.FUEL.value: [Units.KG.value, Units.M3.value, Units.MJ.value],
81
+ TermTermType.ELECTRICITY.value: [Units.KW_H.value, Units.MJ.value]
82
+ }
83
+
84
+
85
+ def download_all_non_renewable_terms(lookup_file_name: str) -> list:
86
+ """
87
+ returns all non renewable term ids in lookup files like `electricity.csv` or `fuel.csv`
88
+ """
89
+ lookup = download_lookup(lookup_file_name)
90
+ results = lookup[
91
+ lookup[column_name("abioticResourceDepletionFossilFuelsCml2001Baseline")] == True # noqa: E712
92
+ ]["termid"]
93
+ terms_ids: list[str] = [str(entry) for entry in results]
94
+ return terms_ids
95
+
96
+
97
+ def _valid_resource_indicator(resource: dict) -> bool:
98
+ return len(resource.get('inputs', [])) == 1 and \
99
+ isinstance(_node_value(resource), (int, float)) and \
100
+ _node_value(resource) > 0
101
+
102
+
103
+ def _valid_input(input: dict) -> bool:
104
+ return input.get("@id") in list(chain.from_iterable([
105
+ download_all_non_renewable_terms(f"{termType}.csv") for termType in LOOKUPS.keys()
106
+ ])) and input.get("units", "") in INPUTS_TYPES_UNITS.get(input.get("termType", ""))
107
+
108
+
109
+ def _get_value_in_mj(input: dict, indicator: dict) -> Optional[float]:
110
+ return convert_unit(input, dest_unit=Units.MJ, node_value=_node_value(indicator)) if _valid_input(input) else None
111
+
112
+
113
+ def _indicator(value: float):
114
+ indicator = _new_indicator(TERM_ID, MODEL)
115
+ indicator["value"] = value
116
+ return indicator
117
+
118
+
119
+ def _run(energy_resources_in_mj: list):
120
+ return _indicator(list_sum(energy_resources_in_mj))
121
+
122
+
123
+ def _should_run(impact_assessment: dict) -> tuple[bool, list]:
124
+ emissions_resource_use = [
125
+ resource for resource in
126
+ filter_list_term_type(impact_assessment.get('emissionsResourceUse', []), TermTermType.RESOURCEUSE) if
127
+ resource.get('term', {}).get('@id', '') in ENERGY_CARRIERS_TERMIDS]
128
+
129
+ has_resource_use_entries = bool(emissions_resource_use)
130
+
131
+ resource_uses_unpacked = flatten(
132
+ [
133
+ [
134
+ {
135
+ "input-term-id": input.get('@id'),
136
+ "input-term-type": input.get('termType'),
137
+ "indicator-term-id": resource_indicator['term']['@id'],
138
+ "indicator-is-valid": _valid_resource_indicator(resource_indicator),
139
+ "input": input,
140
+ "indicator-input-is-valid": _valid_input(input),
141
+ "value": _node_value(resource_indicator),
142
+ "input-unit": input.get('units'),
143
+ "value-in-MJ": _get_value_in_mj(input, resource_indicator)
144
+ } for input in resource_indicator['inputs'] or [{}]]
145
+ for resource_indicator in emissions_resource_use
146
+ ]
147
+ )
148
+
149
+ has_valid_input_requirements = all([
150
+ all([energy_input['indicator-is-valid'], energy_input['indicator-input-is-valid']])
151
+ for energy_input in resource_uses_unpacked
152
+ ])
153
+
154
+ energy_resources_in_mj = [energy_input['value-in-MJ'] for energy_input in resource_uses_unpacked]
155
+ valid_energy_resources_in_mj = [value for value in energy_resources_in_mj if value is not None]
156
+ all_inputs_have_valid_mj_value = all([energy is not None for energy in energy_resources_in_mj]
157
+ ) and bool(energy_resources_in_mj)
158
+
159
+ logRequirements(impact_assessment, model=MODEL, term=TERM_ID,
160
+ has_resource_use_entries=has_resource_use_entries,
161
+ has_valid_input_requirements=has_valid_input_requirements,
162
+ all_inputs_have_valid_mj_value=all_inputs_have_valid_mj_value,
163
+ energy_resources_used=log_as_table(resource_uses_unpacked))
164
+
165
+ should_run = has_resource_use_entries is False or all([has_resource_use_entries,
166
+ has_valid_input_requirements,
167
+ all_inputs_have_valid_mj_value])
168
+
169
+ logShouldRun(impact_assessment, MODEL, TERM_ID, should_run)
170
+ return should_run, valid_energy_resources_in_mj
171
+
172
+
173
+ def run(impact_assessment: dict):
174
+ should_run, resources = _should_run(impact_assessment)
175
+ return _run(resources) if should_run else None
@@ -0,0 +1,136 @@
1
+ """
2
+ Calculates the EU PEF Abiotic resource depletion, for minerals and metals Indicator
3
+
4
+ Uses lookup factors from [eplca.jrc.ec.europa.eu](https://eplca.jrc.ec.europa.eu/permalink/EF3_1/EF-LCIAMethod_CF(EF-v3.1).xlsx), Accessed 2024-09-05.
5
+
6
+ > The results of this impact category shall be interpreted with caution, because the results of ADP after
7
+ > normalization may be overestimated. The European Commission intends to develop a new method moving
8
+ > from depletion to dissipation model to better quantify the potential for conservation of resources
9
+
10
+ Source: [JRC Technical reports Suggestions for updating the Product Environmental Footprint (PEF) method](https://eplca.jrc.ec.europa.eu/permalink/PEF_method.pdf#%5B%7B%22num%22%3A80%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C68%2C363%2C0%5D)
11
+ """ # noqa: E501
12
+
13
+ from hestia_earth.schema import TermTermType
14
+ from hestia_earth.utils.lookup import get_table_value, download_lookup, column_name
15
+ from hestia_earth.utils.model import filter_list_term_type
16
+ from hestia_earth.utils.tools import list_sum, flatten
17
+
18
+ from hestia_earth.models.log import logRequirements, logShouldRun, log_as_table
19
+ from . import MODEL
20
+ from ..utils.indicator import _new_indicator
21
+ from ..utils.lookup import _node_value
22
+
23
+ REQUIREMENTS = {
24
+ "ImpactAssessment": {
25
+ "emissionsResourceUse": [
26
+ {
27
+ "@type": "Indicator", "value": "", "term.termType": "resourceUse",
28
+ "term.@id": ["resourceUseMineralsAndMetalsInputsProduction", "resourceUseMineralsAndMetalsDuringCycle"],
29
+ "inputs": {
30
+ "@type": "Term",
31
+ "term.units": "kg",
32
+ "term.termType": ["material", "soilAmendment", "otherInorganicChemical"]}
33
+ }]
34
+ }
35
+ }
36
+
37
+ LOOKUPS = {
38
+ "@doc": "Different lookup files are used depending on the input material",
39
+ "soilAmendment": "abioticResourceDepletionMineralsAndMetalsCml2001Baseline",
40
+ "material": "abioticResourceDepletionMineralsAndMetalsCml2001Baseline",
41
+ "otherInorganicChemical": "abioticResourceDepletionMineralsAndMetalsCml2001Baseline"
42
+ }
43
+
44
+ RETURNS = {
45
+ "Indicator": {
46
+ "value": ""
47
+ }
48
+ }
49
+
50
+ TERM_ID = 'abioticResourceDepletionMineralsAndMetals'
51
+
52
+ authorised_resource_use_term_types = [TermTermType.MATERIAL.value,
53
+ TermTermType.SOILAMENDMENT.value,
54
+ TermTermType.OTHERINORGANICCHEMICAL.value]
55
+ authorised_resource_use_term_ids = ['resourceUseMineralsAndMetalsInputsProduction',
56
+ 'resourceUseMineralsAndMetalsDuringCycle']
57
+
58
+
59
+ def _valid_input(input: dict) -> bool:
60
+ return input.get('units', '').startswith("kg") and input.get('termType', '') in authorised_resource_use_term_types
61
+
62
+
63
+ def _valid_resource_indicator(resource: dict) -> bool:
64
+ return len(resource.get('inputs', [])) == 1 and isinstance(_node_value(resource), (int, float))
65
+
66
+
67
+ def _indicator(value: float):
68
+ indicator = _new_indicator(TERM_ID, MODEL)
69
+ indicator['value'] = value
70
+ return indicator
71
+
72
+
73
+ def _run(resources: list):
74
+ result = list_sum([indicator_input['value'] * indicator_input['coefficient'] for indicator_input in resources])
75
+ return _indicator(result)
76
+
77
+
78
+ def _should_run(impact_assessment: dict) -> tuple[bool, list]:
79
+ emissions_resource_use = [
80
+ resource for resource in
81
+ filter_list_term_type(impact_assessment.get('emissionsResourceUse', []), TermTermType.RESOURCEUSE) if
82
+ resource.get('term', {}).get('@id', '') in authorised_resource_use_term_ids]
83
+
84
+ has_resource_use_entries = bool(emissions_resource_use)
85
+
86
+ resource_uses_unpacked = flatten(
87
+ [
88
+ [
89
+ {
90
+ "input-term-id": input.get('@id'),
91
+ "input-term-type": input.get('termType'),
92
+ "indicator-term-id": resource_indicator['term']['@id'],
93
+ "indicator-is-valid": _valid_resource_indicator(resource_indicator),
94
+ "input": input,
95
+ "indicator-input-is-valid": _valid_input(input),
96
+ "value": _node_value(resource_indicator),
97
+ "coefficient": get_table_value(
98
+ array=download_lookup(filename=f"{input.get('termType')}.csv"),
99
+ col_match='termid',
100
+ col_match_with=input.get('@id'),
101
+ col_val=column_name(LOOKUPS.get(input.get('termType'), ''))) if input else None
102
+ } for input in resource_indicator['inputs'] or [{}]]
103
+ for resource_indicator in emissions_resource_use
104
+ ]
105
+ )
106
+ valid_resources_with_cf = [em for em in resource_uses_unpacked if em['coefficient'] is not None
107
+ and em['indicator-is-valid'] is True
108
+ and em['indicator-input-is-valid'] is True]
109
+
110
+ has_valid_input_requirements = all([
111
+ all([
112
+ em['indicator-is-valid'],
113
+ em['indicator-input-is-valid']
114
+ ])
115
+ for em in resource_uses_unpacked
116
+ ])
117
+
118
+ all_resources_have_cf = all([em['coefficient'] is not None for em in resource_uses_unpacked]
119
+ ) and bool(resource_uses_unpacked)
120
+
121
+ logRequirements(impact_assessment, model=MODEL, term=TERM_ID,
122
+ has_resource_use_entries=has_resource_use_entries,
123
+ has_valid_input_requirements=has_valid_input_requirements,
124
+ all_resources_have_cf=all_resources_have_cf,
125
+ resource_uses=log_as_table(resource_uses_unpacked)
126
+ )
127
+
128
+ should_run = has_valid_input_requirements
129
+
130
+ logShouldRun(impact_assessment, MODEL, TERM_ID, should_run)
131
+ return should_run, valid_resources_with_cf
132
+
133
+
134
+ def run(impact_assessment: dict):
135
+ should_run, resources = _should_run(impact_assessment)
136
+ return _run(resources) if should_run else None
@@ -1,6 +1,6 @@
1
1
  from hestia_earth.models.log import logRequirements, logShouldRun
2
2
  from hestia_earth.models.utils.indicator import _new_indicator
3
- from hestia_earth.models.utils.impact_assessment import impact_lookup_value
3
+ from hestia_earth.models.utils.impact_assessment import impact_emission_lookup_value
4
4
  from . import MODEL
5
5
 
6
6
  REQUIREMENTS = {
@@ -26,7 +26,7 @@ def _indicator(value: float):
26
26
 
27
27
 
28
28
  def run(impact_assessment: dict):
29
- value = impact_lookup_value(MODEL, TERM_ID, impact_assessment, LOOKUPS['emission'])
29
+ value = impact_emission_lookup_value(MODEL, TERM_ID, impact_assessment, LOOKUPS['emission'])
30
30
  logRequirements(impact_assessment, model=MODEL, term=TERM_ID,
31
31
  value=value)
32
32
  logShouldRun(impact_assessment, MODEL, TERM_ID, True)
@@ -1,6 +1,6 @@
1
1
  from hestia_earth.models.log import logRequirements, logShouldRun
2
2
  from hestia_earth.models.utils.indicator import _new_indicator
3
- from hestia_earth.models.utils.impact_assessment import impact_lookup_value
3
+ from hestia_earth.models.utils.impact_assessment import impact_emission_lookup_value
4
4
  from . import MODEL
5
5
 
6
6
  REQUIREMENTS = {
@@ -26,7 +26,7 @@ def _indicator(value: float):
26
26
 
27
27
 
28
28
  def run(impact_assessment: dict):
29
- value = impact_lookup_value(MODEL, TERM_ID, impact_assessment, LOOKUPS['emission'])
29
+ value = impact_emission_lookup_value(MODEL, TERM_ID, impact_assessment, LOOKUPS['emission'])
30
30
  logRequirements(impact_assessment, model=MODEL, term=TERM_ID,
31
31
  value=value)
32
32
  logShouldRun(impact_assessment, MODEL, TERM_ID, True)
@@ -1,6 +1,6 @@
1
1
  from hestia_earth.models.log import logRequirements, logShouldRun
2
2
  from hestia_earth.models.utils.indicator import _new_indicator
3
- from hestia_earth.models.utils.impact_assessment import impact_lookup_value
3
+ from hestia_earth.models.utils.impact_assessment import impact_emission_lookup_value
4
4
  from . import MODEL
5
5
 
6
6
  REQUIREMENTS = {
@@ -26,7 +26,7 @@ def _indicator(value: float):
26
26
 
27
27
 
28
28
  def run(impact_assessment: dict):
29
- value = impact_lookup_value(MODEL, TERM_ID, impact_assessment, LOOKUPS['emission'])
29
+ value = impact_emission_lookup_value(MODEL, TERM_ID, impact_assessment, LOOKUPS['emission'])
30
30
  logRequirements(impact_assessment, model=MODEL, term=TERM_ID,
31
31
  value=value)
32
32
  logShouldRun(impact_assessment, MODEL, TERM_ID, True)
@@ -1,6 +1,6 @@
1
1
  from hestia_earth.models.log import logRequirements, logShouldRun
2
2
  from hestia_earth.models.utils.indicator import _new_indicator
3
- from hestia_earth.models.utils.impact_assessment import impact_lookup_value
3
+ from hestia_earth.models.utils.impact_assessment import impact_emission_lookup_value
4
4
  from . import MODEL
5
5
 
6
6
  REQUIREMENTS = {
@@ -26,7 +26,7 @@ def _indicator(value: float):
26
26
 
27
27
 
28
28
  def run(impact_assessment: dict):
29
- value = impact_lookup_value(MODEL, TERM_ID, impact_assessment, LOOKUPS['emission'])
29
+ value = impact_emission_lookup_value(MODEL, TERM_ID, impact_assessment, LOOKUPS['emission'])
30
30
  logRequirements(impact_assessment, model=MODEL, term=TERM_ID,
31
31
  value=value)
32
32
  logShouldRun(impact_assessment, MODEL, TERM_ID, True)
@@ -5,6 +5,7 @@ This model checks if we have the requirements below and updates the
5
5
  [Data Completeness](https://hestia.earth/schema/Completeness#cropResidue) value.
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
10
11
  from hestia_earth.models.utils.term import get_crop_residue_terms
@@ -14,15 +15,15 @@ REQUIREMENTS = {
14
15
  "Cycle": {
15
16
  "completeness.cropResidue": "False",
16
17
  "products": [
17
- {"@type": "Product", "value": "", "term.@id": "belowGroundCropResidue"},
18
- {"@type": "Product", "value": "", "term.@id": "aboveGroundCropResidueTotal"}
18
+ {"@type": "Product", "value": ">= 0", "term.@id": "belowGroundCropResidue"},
19
+ {"@type": "Product", "value": "> 0", "term.@id": "aboveGroundCropResidueTotal"}
19
20
  ],
20
21
  "optional": {
21
22
  "products": [
22
- {"@type": "Product", "value": "", "term.@id": "aboveGroundCropResidueRemoved"},
23
- {"@type": "Product", "value": "", "term.@id": "aboveGroundCropResidueIncorporated"},
24
- {"@type": "Product", "value": "", "term.@id": "aboveGroundCropResidueBurnt"},
25
- {"@type": "Product", "value": "", "term.@id": "aboveGroundCropResidueLeftOnField"}
23
+ {"@type": "Product", "value": "> 0", "term.@id": "aboveGroundCropResidueRemoved"},
24
+ {"@type": "Product", "value": "> 0", "term.@id": "aboveGroundCropResidueIncorporated"},
25
+ {"@type": "Product", "value": "> 0", "term.@id": "aboveGroundCropResidueBurnt"},
26
+ {"@type": "Product", "value": "> 0", "term.@id": "aboveGroundCropResidueLeftOnField"}
26
27
  ]
27
28
  }
28
29
  }
@@ -44,17 +45,21 @@ def _optional_term_ids():
44
45
  return [term for term in terms if term not in REQUIRED_TERM_IDS]
45
46
 
46
47
 
47
- def _has_product(products):
48
+ def _has_product(products, zero_allowed=True):
48
49
  def has_product(term_id: str):
49
- return (term_id, find_term_match(products, term_id, None) is not None)
50
+ value = list_sum(find_term_match(products, term_id).get('value', [-1]))
51
+ return (term_id, value >= 0 if zero_allowed else value > 0)
50
52
  return has_product
51
53
 
52
54
 
53
55
  def run(cycle: dict):
54
56
  products = cycle.get('products', [])
55
57
  # all required terms + at least one of the optional terms must be present
56
- required_products_map = list(map(_has_product(products), REQUIRED_TERM_IDS))
57
- optional_products_map = list(map(_has_product(products), _optional_term_ids()))
58
+ required_products_map = [
59
+ _has_product(products, zero_allowed=True)('belowGroundCropResidue'),
60
+ _has_product(products, zero_allowed=False)('aboveGroundCropResidueTotal'),
61
+ ]
62
+ optional_products_map = list(map(_has_product(products, zero_allowed=False), _optional_term_ids()))
58
63
 
59
64
  has_required_products = all([has_product for _term_id, has_product in required_products_map])
60
65
  has_optional_product = any([has_product for _term_id, has_product in optional_products_map])
@@ -0,0 +1,60 @@
1
+ """
2
+ Completeness Fresh Forage
3
+
4
+ This model checks if we have the requirements below and updates the
5
+ [Data Completeness](https://hestia.earth/schema/Completeness#cropResidue) value.
6
+ """
7
+ from hestia_earth.schema import SiteSiteType
8
+ from hestia_earth.utils.tools import list_sum
9
+
10
+ from hestia_earth.models.log import logRequirements
11
+ from hestia_earth.models.utils import is_from_model
12
+ from . import MODEL
13
+
14
+ REQUIREMENTS = {
15
+ "Cycle": {
16
+ "completeness.freshForage": "False",
17
+ "site": {
18
+ "@type": "Site",
19
+ "siteType": "permanent pasture"
20
+ },
21
+ "or": {
22
+ "inputs": [{"@type": "Input", "termType": "forage", "value": "> 0", "added": ["value"]}],
23
+ "animals": [{
24
+ "@type": "Animal",
25
+ "inputs": [{"@type": "Input", "termType": "forage", "value": "> 0", "added": ["value"]}]
26
+ }]
27
+ }
28
+ }
29
+ }
30
+ RETURNS = {
31
+ "Completeness": {
32
+ "freshForage": ""
33
+ }
34
+ }
35
+ MODEL_KEY = 'freshForage'
36
+ ALLOWED_SITE_TYPES = [
37
+ SiteSiteType.PERMANENT_PASTURE.value
38
+ ]
39
+
40
+
41
+ def _valid_input(input: dict): return is_from_model(input) and list_sum(input.get('value', [-1])) > 0
42
+
43
+
44
+ def run(cycle: dict):
45
+ site_type = cycle.get('site', {}).get('siteType')
46
+ site_type_allowed = site_type in ALLOWED_SITE_TYPES
47
+
48
+ cycle_has_added_forage_input = any(map(_valid_input, cycle.get('inputs', [])))
49
+
50
+ animals = cycle.get('animals', [])
51
+ all_animals_have_added_forage_input = bool(animals) and all([
52
+ any(map(_valid_input, animal.get('inputs', []))) for animal in animals
53
+ ])
54
+
55
+ logRequirements(cycle, model=MODEL, term=None, key=MODEL_KEY,
56
+ site_type_allowed=site_type_allowed,
57
+ cycle_has_added_forage_input=cycle_has_added_forage_input,
58
+ all_animals_have_added_forage_input=all_animals_have_added_forage_input)
59
+
60
+ return all([site_type_allowed, cycle_has_added_forage_input or all_animals_have_added_forage_input])
@@ -1,6 +1,6 @@
1
1
  from hestia_earth.models.log import logRequirements, logShouldRun
2
2
  from hestia_earth.models.utils.indicator import _new_indicator
3
- from hestia_earth.models.utils.impact_assessment import impact_lookup_value
3
+ from hestia_earth.models.utils.impact_assessment import impact_emission_lookup_value
4
4
  from . import MODEL
5
5
 
6
6
  REQUIREMENTS = {
@@ -27,7 +27,7 @@ def _indicator(value: float):
27
27
 
28
28
 
29
29
  def run(impact_assessment: dict):
30
- value = impact_lookup_value(MODEL, TERM_ID, impact_assessment, LOOKUPS['emission'])
30
+ value = impact_emission_lookup_value(MODEL, TERM_ID, impact_assessment, LOOKUPS['emission'])
31
31
  logRequirements(impact_assessment, model=MODEL, term=TERM_ID,
32
32
  value=value)
33
33
  logShouldRun(impact_assessment, MODEL, TERM_ID, True)
@@ -18,7 +18,7 @@ from ..utils.impact_assessment import get_country_id
18
18
  from ..utils.indicator import _new_indicator
19
19
  from ..utils.landCover import get_pef_grouping
20
20
  from ..utils.lookup import fallback_country, _node_value
21
- from ..utils.term import download_all_land_cover_terms
21
+ from ..utils.term import get_land_cover_terms
22
22
 
23
23
  REQUIREMENTS = {
24
24
  "ImpactAssessment": {
@@ -92,7 +92,7 @@ def _is_valid_indicator(indicator: dict, land_cover_term_ids: list[str]) -> bool
92
92
 
93
93
  def _should_run(impact_assessment: dict) -> Tuple[bool, list]:
94
94
  resource_uses = filter_list_term_type(impact_assessment.get('emissionsResourceUse', []), TermTermType.RESOURCEUSE)
95
- land_cover_term_ids = [term.get("@id") for term in download_all_land_cover_terms()] if resource_uses else []
95
+ land_cover_term_ids = get_land_cover_terms() if resource_uses else []
96
96
 
97
97
  land_transformation_indicators = [i for i in resource_uses if _is_valid_indicator(i, land_cover_term_ids)]
98
98
 
@@ -1,33 +1,23 @@
1
- from hestia_earth.utils.lookup import column_name
2
-
3
1
  from hestia_earth.models.log import logRequirements, logShouldRun
2
+ from hestia_earth.models.utils.impact_assessment import impact_emission_lookup_value
3
+ from hestia_earth.models.utils.indicator import _new_indicator
4
4
  from . import MODEL
5
- from ..utils.impact_assessment import impact_lookup_value
6
- from ..utils.indicator import _new_indicator
7
5
 
8
6
  REQUIREMENTS = {
9
7
  "ImpactAssessment": {
10
- "emissionsResourceUse": [
11
- {
12
- "@type": "Indicator", "value": "", "term.termType": "emission"
13
- }
14
- ]
8
+ "emissionsResourceUse": [{"@type": "Indicator", "value": "", "term.termType": "emission"}]
15
9
  }
16
10
  }
17
-
18
- TERM_ID = 'damageToHumanHealthParticulateMatterFormation'
19
-
20
11
  LOOKUPS = {
21
12
  "emission": "damageToHumanHealthParticulateMatterFormationFantkeEtAl2016"
22
13
  }
23
-
24
14
  RETURNS = {
25
15
  "Indicator": {
26
16
  "value": ""
27
17
  }
28
18
  }
29
19
 
30
- default_group_key = 'default'
20
+ TERM_ID = 'damageToHumanHealthParticulateMatterFormation'
31
21
 
32
22
 
33
23
  def _indicator(value: float):
@@ -37,9 +27,9 @@ def _indicator(value: float):
37
27
 
38
28
 
39
29
  def run(impact_assessment: dict):
40
- value = impact_lookup_value(model=MODEL, term_id=TERM_ID, impact=impact_assessment,
41
- lookup_col=column_name(LOOKUPS['emission']),
42
- grouped_key=default_group_key)
30
+ value = impact_emission_lookup_value(
31
+ model=MODEL, term_id=TERM_ID, impact=impact_assessment, lookup_col=LOOKUPS['emission'], grouped_key='default'
32
+ )
43
33
  logRequirements(impact_assessment, model=MODEL, term=TERM_ID,
44
34
  value=value)
45
35
 
@@ -1,6 +1,6 @@
1
1
  from hestia_earth.models.log import logRequirements, logShouldRun
2
2
  from hestia_earth.models.utils.indicator import _new_indicator
3
- from hestia_earth.models.utils.impact_assessment import impact_lookup_value
3
+ from hestia_earth.models.utils.impact_assessment import impact_emission_lookup_value
4
4
  from . import MODEL
5
5
 
6
6
  REQUIREMENTS = {
@@ -26,7 +26,7 @@ def _indicator(value: float):
26
26
 
27
27
 
28
28
  def run(impact_assessment: dict):
29
- value = impact_lookup_value(MODEL, TERM_ID, impact_assessment, LOOKUPS['emission'])
29
+ value = impact_emission_lookup_value(MODEL, TERM_ID, impact_assessment, LOOKUPS['emission'])
30
30
  logRequirements(impact_assessment, model=MODEL, term=TERM_ID,
31
31
  value=value)
32
32
  logShouldRun(impact_assessment, MODEL, TERM_ID, True)
@@ -1,6 +1,6 @@
1
1
  from hestia_earth.models.log import logRequirements, logShouldRun
2
2
  from hestia_earth.models.utils.indicator import _new_indicator
3
- from hestia_earth.models.utils.impact_assessment import impact_lookup_value
3
+ from hestia_earth.models.utils.impact_assessment import impact_emission_lookup_value
4
4
  from . import MODEL
5
5
 
6
6
  REQUIREMENTS = {
@@ -26,7 +26,7 @@ def _indicator(value: float):
26
26
 
27
27
 
28
28
  def run(impact_assessment: dict):
29
- value = impact_lookup_value(MODEL, TERM_ID, impact_assessment, LOOKUPS['emission'])
29
+ value = impact_emission_lookup_value(MODEL, TERM_ID, impact_assessment, LOOKUPS['emission'])
30
30
  logRequirements(impact_assessment, model=MODEL, term=TERM_ID,
31
31
  value=value)
32
32
  logShouldRun(impact_assessment, MODEL, TERM_ID, True)