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.
- hestia_earth/models/cml2001Baseline/abioticResourceDepletionFossilFuels.py +175 -0
- hestia_earth/models/cml2001Baseline/abioticResourceDepletionMineralsAndMetals.py +136 -0
- hestia_earth/models/cycle/siteArea.py +2 -1
- hestia_earth/models/environmentalFootprintV3/soilQualityIndexLandOccupation.py +73 -82
- hestia_earth/models/environmentalFootprintV3/soilQualityIndexLandTransformation.py +102 -116
- hestia_earth/models/environmentalFootprintV3/soilQualityIndexTotalLandUseEffects.py +27 -16
- hestia_earth/models/faostat2018/landTransformationFromCropland100YearAverage.py +3 -2
- hestia_earth/models/faostat2018/landTransformationFromCropland20YearAverage.py +3 -2
- hestia_earth/models/frischknechtEtAl2000/ionisingRadiationKbqU235Eq.py +69 -37
- hestia_earth/models/ipcc2019/aboveGroundBiomass.py +31 -243
- hestia_earth/models/ipcc2019/animal/fatContent.py +38 -0
- hestia_earth/models/ipcc2019/animal/liveweightGain.py +3 -54
- hestia_earth/models/ipcc2019/animal/liveweightPerHead.py +3 -54
- hestia_earth/models/ipcc2019/animal/pregnancyRateTotal.py +38 -0
- hestia_earth/models/ipcc2019/animal/trueProteinContent.py +38 -0
- hestia_earth/models/ipcc2019/animal/utils.py +87 -3
- hestia_earth/models/ipcc2019/animal/weightAtMaturity.py +4 -10
- hestia_earth/models/ipcc2019/belowGroundBiomass.py +529 -0
- hestia_earth/models/ipcc2019/biomass_utils.py +406 -0
- hestia_earth/models/ipcc2019/{co2ToAirAboveGroundBiomassStockChangeLandUseChange.py → co2ToAirAboveGroundBiomassStockChange.py} +19 -7
- hestia_earth/models/ipcc2019/{co2ToAirBelowGroundBiomassStockChangeLandUseChange.py → co2ToAirBelowGroundBiomassStockChange.py} +19 -7
- hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +402 -73
- hestia_earth/models/ipcc2019/{co2ToAirSoilOrganicCarbonStockChangeManagementChange.py → co2ToAirSoilOrganicCarbonStockChange.py} +20 -8
- hestia_earth/models/ipcc2019/organicCarbonPerHa.py +3 -1
- hestia_earth/models/ipcc2019/pastureGrass_utils.py +6 -7
- hestia_earth/models/lcImpactAllEffects100Years/damageToFreshwaterEcosystemsFreshwaterEutrophication.py +2 -2
- hestia_earth/models/lcImpactAllEffects100Years/damageToFreshwaterEcosystemsWaterStress.py +2 -2
- hestia_earth/models/lcImpactAllEffects100Years/damageToHumanHealthParticulateMatterFormation.py +2 -2
- hestia_earth/models/lcImpactAllEffects100Years/damageToHumanHealthPhotochemicalOzoneFormation.py +2 -2
- hestia_earth/models/lcImpactAllEffects100Years/damageToHumanHealthWaterStress.py +2 -2
- hestia_earth/models/lcImpactAllEffects100Years/damageToMarineEcosystemsMarineEutrophication.py +2 -2
- hestia_earth/models/lcImpactAllEffects100Years/damageToTerrestrialEcosystemsPhotochemicalOzoneFormation.py +2 -2
- hestia_earth/models/lcImpactAllEffects100Years/damageToTerrestrialEcosystemsTerrestrialAcidification.py +2 -2
- hestia_earth/models/lcImpactAllEffectsInfinite/damageToFreshwaterEcosystemsFreshwaterEutrophication.py +2 -2
- hestia_earth/models/lcImpactAllEffectsInfinite/damageToFreshwaterEcosystemsWaterStress.py +2 -2
- hestia_earth/models/lcImpactAllEffectsInfinite/damageToHumanHealthParticulateMatterFormation.py +2 -2
- hestia_earth/models/lcImpactAllEffectsInfinite/damageToHumanHealthPhotochemicalOzoneFormation.py +2 -2
- hestia_earth/models/lcImpactAllEffectsInfinite/damageToHumanHealthWaterStress.py +2 -2
- hestia_earth/models/lcImpactAllEffectsInfinite/damageToMarineEcosystemsMarineEutrophication.py +2 -2
- hestia_earth/models/lcImpactAllEffectsInfinite/damageToTerrestrialEcosystemsPhotochemicalOzoneFormation.py +2 -2
- hestia_earth/models/lcImpactAllEffectsInfinite/damageToTerrestrialEcosystemsTerrestrialAcidification.py +2 -2
- hestia_earth/models/lcImpactCertainEffects100Years/damageToFreshwaterEcosystemsFreshwaterEutrophication.py +2 -2
- hestia_earth/models/lcImpactCertainEffects100Years/damageToFreshwaterEcosystemsWaterStress.py +2 -2
- hestia_earth/models/lcImpactCertainEffects100Years/damageToHumanHealthParticulateMatterFormation.py +2 -2
- hestia_earth/models/lcImpactCertainEffects100Years/damageToHumanHealthPhotochemicalOzoneFormation.py +2 -2
- hestia_earth/models/lcImpactCertainEffects100Years/damageToHumanHealthWaterStress.py +2 -2
- hestia_earth/models/lcImpactCertainEffects100Years/damageToMarineEcosystemsMarineEutrophication.py +2 -2
- hestia_earth/models/lcImpactCertainEffects100Years/damageToTerrestrialEcosystemsPhotochemicalOzoneFormation.py +2 -2
- hestia_earth/models/lcImpactCertainEffects100Years/damageToTerrestrialEcosystemsTerrestrialAcidification.py +2 -2
- hestia_earth/models/lcImpactCertainEffectsInfinite/damageToFreshwaterEcosystemsFreshwaterEutrophication.py +2 -2
- hestia_earth/models/lcImpactCertainEffectsInfinite/damageToFreshwaterEcosystemsWaterStress.py +2 -2
- hestia_earth/models/lcImpactCertainEffectsInfinite/damageToHumanHealthParticulateMatterFormation.py +2 -2
- hestia_earth/models/lcImpactCertainEffectsInfinite/damageToHumanHealthPhotochemicalOzoneFormation.py +2 -2
- hestia_earth/models/lcImpactCertainEffectsInfinite/damageToHumanHealthWaterStress.py +2 -2
- hestia_earth/models/lcImpactCertainEffectsInfinite/damageToMarineEcosystemsMarineEutrophication.py +2 -2
- hestia_earth/models/lcImpactCertainEffectsInfinite/damageToTerrestrialEcosystemsPhotochemicalOzoneFormation.py +2 -2
- hestia_earth/models/lcImpactCertainEffectsInfinite/damageToTerrestrialEcosystemsTerrestrialAcidification.py +2 -2
- hestia_earth/models/mocking/build_mock_search.py +44 -0
- hestia_earth/models/mocking/mock_search.py +8 -49
- hestia_earth/models/mocking/search-results.json +3078 -575
- hestia_earth/models/poschEtAl2008/terrestrialAcidificationPotentialAccumulatedExceedance.py +6 -3
- hestia_earth/models/poschEtAl2008/terrestrialEutrophicationPotentialAccumulatedExceedance.py +6 -3
- hestia_earth/models/preload_requests.py +1 -1
- hestia_earth/models/schmidt2007/utils.py +13 -4
- hestia_earth/models/utils/__init__.py +5 -4
- hestia_earth/models/utils/blank_node.py +73 -3
- hestia_earth/models/utils/constant.py +8 -1
- hestia_earth/models/utils/cycle.py +10 -13
- hestia_earth/models/utils/fuel.py +1 -1
- hestia_earth/models/utils/impact_assessment.py +39 -15
- hestia_earth/models/utils/lookup.py +36 -7
- hestia_earth/models/utils/pesticideAI.py +1 -1
- hestia_earth/models/utils/property.py +11 -4
- hestia_earth/models/utils/term.py +15 -8
- hestia_earth/models/version.py +1 -1
- {hestia_earth_models-0.64.8.dist-info → hestia_earth_models-0.64.10.dist-info}/METADATA +2 -2
- {hestia_earth_models-0.64.8.dist-info → hestia_earth_models-0.64.10.dist-info}/RECORD +103 -90
- {hestia_earth_models-0.64.8.dist-info → hestia_earth_models-0.64.10.dist-info}/WHEEL +1 -1
- tests/models/cml2001Baseline/test_abioticResourceDepletionFossilFuels.py +196 -0
- tests/models/cml2001Baseline/test_abioticResourceDepletionMineralsAndMetals.py +124 -0
- tests/models/edip2003/test_ozoneDepletionPotential.py +1 -13
- tests/models/environmentalFootprintV3/test_soilQualityIndexLandOccupation.py +97 -66
- tests/models/environmentalFootprintV3/test_soilQualityIndexLandTransformation.py +136 -74
- tests/models/environmentalFootprintV3/test_soilQualityIndexTotalLandUseEffects.py +15 -10
- tests/models/frischknechtEtAl2000/test_ionisingRadiationKbqU235Eq.py +67 -44
- tests/models/impact_assessment/test_emissions.py +1 -0
- tests/models/ipcc2019/animal/test_fatContent.py +22 -0
- tests/models/ipcc2019/animal/test_liveweightGain.py +4 -2
- tests/models/ipcc2019/animal/test_liveweightPerHead.py +4 -2
- tests/models/ipcc2019/animal/test_pregnancyRateTotal.py +22 -0
- tests/models/ipcc2019/animal/test_trueProteinContent.py +22 -0
- tests/models/ipcc2019/animal/test_weightAtMaturity.py +2 -1
- tests/models/ipcc2019/test_aboveGroundBiomass.py +27 -63
- tests/models/ipcc2019/test_belowGroundBiomass.py +146 -0
- tests/models/ipcc2019/test_biomass_utils.py +115 -0
- tests/models/ipcc2019/{test_co2ToAirAboveGroundBiomassStockChangeLandUseChange.py → test_co2ToAirAboveGroundBiomassStockChange.py} +5 -5
- tests/models/ipcc2019/{test_co2ToAirBelowGroundBiomassStockChangeLandUseChange.py → test_co2ToAirBelowGroundBiomassStockChange.py} +5 -5
- tests/models/ipcc2019/{test_co2ToAirSoilOrganicCarbonStockChangeManagementChange.py → test_co2ToAirSoilOrganicCarbonStockChange.py} +5 -5
- tests/models/ipcc2021/test_gwp100.py +2 -2
- tests/models/poschEtAl2008/test_terrestrialAcidificationPotentialAccumulatedExceedance.py +30 -17
- tests/models/poschEtAl2008/test_terrestrialEutrophicationPotentialAccumulatedExceedance.py +28 -14
- hestia_earth/models/ipcc2019/aboveGroundBiomass_utils.py +0 -180
- tests/models/ipcc2019/test_aboveGroundBiomass_utils.py +0 -92
- {hestia_earth_models-0.64.8.dist-info → hestia_earth_models-0.64.10.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.64.8.dist-info → hestia_earth_models-0.64.10.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
|
|
@@ -9,6 +9,7 @@ from hestia_earth.utils.model import filter_list_term_type, find_term_match
|
|
|
9
9
|
from hestia_earth.utils.tools import list_sum
|
|
10
10
|
|
|
11
11
|
from hestia_earth.models.log import logRequirements, logShouldRun, log_as_table
|
|
12
|
+
from hestia_earth.models.utils import square_meter_to_hectare
|
|
12
13
|
from . import MODEL
|
|
13
14
|
|
|
14
15
|
REQUIREMENTS = {
|
|
@@ -48,7 +49,7 @@ def _run(cycle: dict):
|
|
|
48
49
|
animals = filter_list_term_type(cycle.get('animals', []), TermTermType.LIVEANIMAL)
|
|
49
50
|
stocking_density = find_term_match(
|
|
50
51
|
cycle.get('practices', []), 'stockingDensityAnimalHousingAverage', {}).get('value', [])
|
|
51
|
-
return round(list_sum([a.get('value') for a in animals]) / list_sum(stocking_density), 7)
|
|
52
|
+
return square_meter_to_hectare(round(list_sum([a.get('value') for a in animals]) / list_sum(stocking_density), 7))
|
|
52
53
|
|
|
53
54
|
|
|
54
55
|
def _should_run(cycle: dict, site: dict, key=MODEL_KEY):
|
|
@@ -1,41 +1,37 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Characterises [soilQualityIndexLandOccupation](https://hestia.earth/term/soilQualityIndexLandOccupation)
|
|
3
|
+
based on an updated [LANCA model (De Laurentiis et al. 2019)](
|
|
4
|
+
http://publications.jrc.ec.europa.eu/repository/handle/JRC113865) and on the LANCA (Regionalised) Characterisation
|
|
5
|
+
Factors version 2.5 (Horn and Meier, 2018).
|
|
6
|
+
"""
|
|
7
|
+
from typing import Tuple
|
|
8
|
+
|
|
1
9
|
from hestia_earth.schema import TermTermType
|
|
2
10
|
from hestia_earth.utils.lookup import download_lookup
|
|
3
|
-
from hestia_earth.utils.
|
|
11
|
+
from hestia_earth.utils.model import filter_list_term_type
|
|
12
|
+
from hestia_earth.utils.tools import list_sum
|
|
4
13
|
|
|
5
14
|
from hestia_earth.models.log import logRequirements, logShouldRun, log_as_table
|
|
6
|
-
from hestia_earth.models.utils import hectar_to_square_meter, days_to_years
|
|
7
|
-
from hestia_earth.models.utils.blank_node import most_relevant_blank_node_by_type
|
|
8
15
|
from hestia_earth.models.utils.indicator import _new_indicator
|
|
9
16
|
from hestia_earth.models.utils.landCover import get_pef_grouping
|
|
10
|
-
from hestia_earth.models.utils.lookup import fallback_country
|
|
17
|
+
from hestia_earth.models.utils.lookup import fallback_country, _node_value
|
|
11
18
|
from . import MODEL
|
|
12
19
|
from .utils import get_coefficient_factor
|
|
20
|
+
from ..utils.impact_assessment import get_country_id
|
|
13
21
|
|
|
14
22
|
REQUIREMENTS = {
|
|
15
23
|
"ImpactAssessment": {
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"country": {"@type": "Term", "termType": "region"}
|
|
25
|
-
},
|
|
26
|
-
"optional": {
|
|
27
|
-
"otherSitesDuration": "> 0",
|
|
28
|
-
"otherSitesArea": "> 0",
|
|
29
|
-
"otherSites": [{
|
|
30
|
-
"@type": "Site",
|
|
31
|
-
"siteType": "",
|
|
32
|
-
"management": [{"@type": "Management", "value": "", "term.termType": "landCover"}],
|
|
33
|
-
"country": {"@type": "Term", "termType": "region"}
|
|
34
|
-
}]
|
|
35
|
-
}
|
|
36
|
-
}
|
|
24
|
+
"optional": {"country": {"@type": "Term", "termType": "region"}},
|
|
25
|
+
"emissionsResourceUse": [{
|
|
26
|
+
"@type": "Indicator",
|
|
27
|
+
"value": ">0",
|
|
28
|
+
"term.@id": ["landOccupationInputsProduction", "landOccupationDuringCycle"],
|
|
29
|
+
"term.units": "m2*year",
|
|
30
|
+
"landCover": {"@type": "Term", "term.termType": "landCover"}
|
|
31
|
+
}]
|
|
37
32
|
}
|
|
38
33
|
}
|
|
34
|
+
|
|
39
35
|
LOOKUPS = {
|
|
40
36
|
"@doc": "Performs lookup on landCover.csv for column headers and region-pefTermGrouping-landOccupation.csv for CFs",
|
|
41
37
|
"region-pefTermGrouping-landOccupation": "",
|
|
@@ -50,6 +46,8 @@ RETURNS = {
|
|
|
50
46
|
TERM_ID = 'soilQualityIndexLandOccupation'
|
|
51
47
|
LOOKUP = f"{list(LOOKUPS.keys())[1]}.csv"
|
|
52
48
|
|
|
49
|
+
authorised_indicators = ["landOccupationInputsProduction", "landOccupationDuringCycle"]
|
|
50
|
+
|
|
53
51
|
|
|
54
52
|
def _indicator(value: float):
|
|
55
53
|
indicator = _new_indicator(TERM_ID, MODEL)
|
|
@@ -57,73 +55,66 @@ def _indicator(value: float):
|
|
|
57
55
|
return indicator
|
|
58
56
|
|
|
59
57
|
|
|
60
|
-
def _run(
|
|
61
|
-
values = [
|
|
62
|
-
return _indicator(list_sum(values))
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def _should_run(impact_assessment: dict):
|
|
66
|
-
cycle = impact_assessment.get('cycle', {})
|
|
67
|
-
end_date = cycle.get('endDate')
|
|
68
|
-
|
|
69
|
-
has_site = bool(cycle.get('site', False))
|
|
70
|
-
has_other_sites = bool(cycle.get('otherSites', []))
|
|
58
|
+
def _run(land_occupation_indicators: list):
|
|
59
|
+
values = [indicator['coefficient'] * indicator['area-by-year'] for indicator in land_occupation_indicators]
|
|
60
|
+
return _indicator(list_sum(values))
|
|
71
61
|
|
|
72
|
-
all_sites = non_empty_list([cycle.get('site')] + cycle.get('otherSites', []))
|
|
73
|
-
site_areas = [cycle.get('siteArea')] + cycle.get('otherSitesArea', [])
|
|
74
|
-
site_durations = [cycle.get('siteDuration')] + cycle.get('otherSitesDuration', [])
|
|
75
62
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
'duration': site_durations[index] if len(site_durations) >= index + 1 else None,
|
|
82
|
-
'landCover-id': (most_relevant_blank_node_by_type(
|
|
83
|
-
site.get("management", []),
|
|
84
|
-
term_type=TermTermType.LANDCOVER.value,
|
|
85
|
-
date=end_date
|
|
86
|
-
) or {}).get('term', {}).get('@id'),
|
|
87
|
-
}
|
|
88
|
-
for index, site in enumerate(all_sites)
|
|
63
|
+
def _should_run(impact_assessment: dict) -> Tuple[bool, list]:
|
|
64
|
+
land_occupation_indicators = [
|
|
65
|
+
i for i in filter_list_term_type(impact_assessment.get('emissionsResourceUse', []), TermTermType.RESOURCEUSE) if
|
|
66
|
+
i.get('landCover', {}).get('termType') == TermTermType.LANDCOVER.value and
|
|
67
|
+
i.get('term', {}).get('@id', '') in authorised_indicators
|
|
89
68
|
]
|
|
90
69
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
70
|
+
found_land_occupation_indicators = [{
|
|
71
|
+
'area-by-year': _node_value(land_occupation_indicator),
|
|
72
|
+
'area-unit': land_occupation_indicator.get('term', {}).get("units"),
|
|
73
|
+
'land-cover-id': land_occupation_indicator.get('landCover', {}).get("@id"),
|
|
74
|
+
'country-id': get_country_id(impact_assessment),
|
|
75
|
+
'area-by-year-is-valid': _node_value(land_occupation_indicator) is not None and _node_value(
|
|
76
|
+
land_occupation_indicator) > 0,
|
|
77
|
+
'area-unit-is-valid': land_occupation_indicator.get('term', {}).get("units") == "m2*year",
|
|
78
|
+
'used-country': fallback_country(get_country_id(impact_assessment), [download_lookup(LOOKUP)]),
|
|
79
|
+
|
|
80
|
+
} for land_occupation_indicator in land_occupation_indicators]
|
|
81
|
+
|
|
82
|
+
found_indicators_with_coefficient = [
|
|
83
|
+
indicator | {
|
|
84
|
+
'coefficient': get_coefficient_factor(
|
|
85
|
+
LOOKUP, indicator['used-country'],
|
|
86
|
+
get_pef_grouping(indicator['land-cover-id']),
|
|
107
87
|
term_id=TERM_ID
|
|
108
|
-
)
|
|
109
|
-
|
|
88
|
+
),
|
|
89
|
+
"using-fallback-country-region-world-CFs": indicator['used-country'] != indicator['country-id']
|
|
90
|
+
} for indicator in found_land_occupation_indicators
|
|
110
91
|
]
|
|
111
|
-
valid_sites = [site for site in sites if site.get('coeff') is not None]
|
|
112
92
|
|
|
113
|
-
|
|
93
|
+
has_valid_land_occupations = all(
|
|
94
|
+
[
|
|
95
|
+
indicator['area-by-year-is-valid'] and indicator['area-unit-is-valid']
|
|
96
|
+
for indicator in found_land_occupation_indicators
|
|
97
|
+
]) if found_land_occupation_indicators else False
|
|
98
|
+
|
|
99
|
+
valid_indicator_with_coef = [indicator for indicator in found_indicators_with_coefficient if
|
|
100
|
+
indicator['coefficient'] is not None and
|
|
101
|
+
indicator['area-by-year-is-valid'] and
|
|
102
|
+
indicator['area-unit-is-valid']]
|
|
114
103
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
104
|
+
has_land_occupation_indicators = bool(land_occupation_indicators)
|
|
105
|
+
|
|
106
|
+
logRequirements(impact_assessment, model=MODEL, term=TERM_ID,
|
|
107
|
+
has_land_occupation_indicators=has_land_occupation_indicators,
|
|
108
|
+
has_valid_land_occupations=has_valid_land_occupations,
|
|
109
|
+
land_occupation_indicators=log_as_table(found_indicators_with_coefficient)
|
|
120
110
|
)
|
|
121
111
|
|
|
122
|
-
should_run =
|
|
123
|
-
|
|
124
|
-
|
|
112
|
+
should_run = has_land_occupation_indicators and has_valid_land_occupations
|
|
113
|
+
|
|
114
|
+
logShouldRun(impact_assessment, MODEL, TERM_ID, should_run)
|
|
115
|
+
return should_run, valid_indicator_with_coef
|
|
125
116
|
|
|
126
117
|
|
|
127
118
|
def run(impact_assessment: dict):
|
|
128
|
-
should_run,
|
|
129
|
-
return _run(
|
|
119
|
+
should_run, land_occupation_indicators = _should_run(impact_assessment)
|
|
120
|
+
return _run(land_occupation_indicators) if should_run else None
|