hestia-earth-models 0.65.3__py3-none-any.whl → 0.65.5__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/agribalyse2016/fuelElectricity.py +41 -35
- hestia_earth/models/aware/scarcityWeightedWaterUse.py +1 -1
- hestia_earth/models/cache_sites.py +2 -0
- hestia_earth/models/chaudharyBrooks2018/damageToTerrestrialEcosystemsLandOccupation.py +1 -1
- hestia_earth/models/chaudharyBrooks2018/damageToTerrestrialEcosystemsLandTransformation.py +1 -1
- hestia_earth/models/chaudharyBrooks2018/damageToTerrestrialEcosystemsTotalLandUseEffects.py +1 -1
- hestia_earth/models/cycle/completeness/__init__.py +1 -1
- hestia_earth/models/cycle/completeness/electricityFuel.py +4 -2
- hestia_earth/models/emepEea2019/nh3ToAirInorganicFertiliser.py +1 -1
- hestia_earth/models/geospatialDatabase/precipitationAnnual.py +2 -2
- hestia_earth/models/geospatialDatabase/precipitationLongTermAnnualMean.py +2 -2
- hestia_earth/models/geospatialDatabase/precipitationMonthly.py +2 -2
- hestia_earth/models/geospatialDatabase/temperatureAnnual.py +2 -2
- hestia_earth/models/geospatialDatabase/temperatureLongTermAnnualMean.py +2 -2
- hestia_earth/models/geospatialDatabase/temperatureMonthly.py +2 -2
- hestia_earth/models/hestia/landCover.py +31 -46
- hestia_earth/models/hestia/landTransformation100YearAverageDuringCycle.py +49 -0
- hestia_earth/models/hestia/landTransformation20YearAverageDuringCycle.py +49 -0
- hestia_earth/models/hestia/resourceUse_utils.py +200 -0
- hestia_earth/models/hestia/seed_emissions.py +37 -28
- hestia_earth/models/hestia/utils.py +48 -0
- hestia_earth/models/impact_assessment/emissions.py +20 -5
- hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +66 -28
- hestia_earth/models/ipcc2019/croppingDuration.py +5 -0
- hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_1_utils.py +26 -142
- hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_2_utils.py +3 -3
- hestia_earth/models/ipcc2019/organicCarbonPerHa_utils.py +8 -5
- hestia_earth/models/linkedImpactAssessment/freshwaterWithdrawalsInputsProduction.py +2 -1
- hestia_earth/models/linkedImpactAssessment/landOccupationInputsProduction.py +1 -0
- hestia_earth/models/linkedImpactAssessment/landTransformation100YearAverageInputsProduction.py +1 -0
- hestia_earth/models/linkedImpactAssessment/landTransformation20YearAverageInputsProduction.py +1 -0
- hestia_earth/models/linkedImpactAssessment/utils.py +25 -20
- hestia_earth/models/mocking/search-results.json +670 -654
- hestia_earth/models/pooreNemecek2018/freshwaterWithdrawalsDuringCycle.py +4 -1
- hestia_earth/models/schererPfister2015/nErosionSoilFlux.py +23 -14
- hestia_earth/models/schererPfister2015/pErosionSoilFlux.py +23 -15
- hestia_earth/models/schererPfister2015/utils.py +3 -5
- hestia_earth/models/site/management.py +2 -2
- hestia_earth/models/utils/__init__.py +9 -0
- hestia_earth/models/utils/blank_node.py +28 -0
- hestia_earth/models/utils/ecoClimateZone.py +1 -4
- hestia_earth/models/utils/fuel.py +4 -1
- hestia_earth/models/utils/impact_assessment.py +7 -5
- hestia_earth/models/utils/lookup.py +8 -2
- hestia_earth/models/utils/pesticideAI.py +1 -0
- hestia_earth/models/version.py +1 -1
- {hestia_earth_models-0.65.3.dist-info → hestia_earth_models-0.65.5.dist-info}/METADATA +2 -2
- {hestia_earth_models-0.65.3.dist-info → hestia_earth_models-0.65.5.dist-info}/RECORD +59 -53
- tests/models/hestia/test_landTransformation100YearAverageDuringCycle.py +30 -0
- tests/models/hestia/test_landTransformation20YearAverageDuringCycle.py +31 -0
- tests/models/ipcc2019/test_co2ToAirAboveGroundBiomassStockChange.py +3 -1
- tests/models/ipcc2019/test_co2ToAirBelowGroundBiomassStockChange.py +3 -1
- tests/models/ipcc2019/test_co2ToAirSoilOrganicCarbonStockChange.py +3 -1
- tests/models/ipcc2019/test_organicCarbonPerHa.py +3 -2
- tests/models/ipcc2019/test_organicCarbonPerHa_tier_1_utils.py +15 -11
- tests/models/utils/test_blank_node.py +22 -7
- {hestia_earth_models-0.65.3.dist-info → hestia_earth_models-0.65.5.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.65.3.dist-info → hestia_earth_models-0.65.5.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.65.3.dist-info → hestia_earth_models-0.65.5.dist-info}/top_level.txt +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Fuel and Electricity
|
|
3
3
|
|
|
4
|
-
This model calculates fuel and electricity data from the number of hours each machine is
|
|
4
|
+
This model calculates fuel and electricity data from the number of hours each machine is used for.
|
|
5
5
|
"""
|
|
6
|
-
from functools import reduce
|
|
7
6
|
from hestia_earth.schema import TermTermType
|
|
8
7
|
from hestia_earth.utils.model import filter_list_term_type
|
|
9
8
|
from hestia_earth.utils.tools import flatten, list_sum, non_empty_list
|
|
10
9
|
|
|
11
10
|
from hestia_earth.models.log import debugValues, logRequirements, logShouldRun, log_as_table
|
|
11
|
+
from hestia_earth.models.utils import group_by
|
|
12
12
|
from hestia_earth.models.utils.term import get_lookup_value
|
|
13
13
|
from hestia_earth.models.utils.input import _new_input
|
|
14
14
|
from . import MODEL
|
|
@@ -68,57 +68,63 @@ def _run_operation(cycle: dict):
|
|
|
68
68
|
return exec
|
|
69
69
|
|
|
70
70
|
|
|
71
|
-
def
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
group[input_term_id].append(operation)
|
|
76
|
-
return group
|
|
71
|
+
def _operation_data(practice: dict):
|
|
72
|
+
term = practice.get('term', {})
|
|
73
|
+
values = practice.get('value', [])
|
|
74
|
+
value = list_sum(values) if all([not isinstance(v, str) for v in values]) else None # str allowed for Practice
|
|
77
75
|
|
|
78
|
-
|
|
76
|
+
coeffs = get_lookup_value(term, LOOKUPS['operation'], model=MODEL, model_key=MODEL_KEY)
|
|
77
|
+
values = non_empty_list(coeffs.split(';')) if coeffs else []
|
|
78
|
+
inputs = [{'id': c.split(':')[0], 'value': float(c.split(':')[1])} for c in values]
|
|
79
79
|
|
|
80
|
+
return [{
|
|
81
|
+
'term': term,
|
|
82
|
+
'value': value,
|
|
83
|
+
'input': input,
|
|
84
|
+
'dates': ';'.join(practice.get('dates', []))
|
|
85
|
+
} for input in inputs]
|
|
80
86
|
|
|
81
|
-
def _should_run_operation(cycle: dict):
|
|
82
|
-
def exec(practice: dict):
|
|
83
|
-
term = practice.get('term', {})
|
|
84
|
-
term_id = term.get('@id')
|
|
85
|
-
values = practice.get('value', [])
|
|
86
|
-
value = list_sum(values) if all([not isinstance(v, str) for v in values]) else 0 # str allowed for Practice
|
|
87
|
-
has_value = value > 0
|
|
88
87
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
has_lookup_value = len(inputs) > 0
|
|
88
|
+
def _should_run(cycle: dict):
|
|
89
|
+
is_incomplete = not cycle.get('completeness', {}).get('electricityFuel', False)
|
|
90
|
+
operations = filter_list_term_type(cycle.get('practices', []), TermTermType.OPERATION)
|
|
93
91
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
has_fuelUse_lookup_value=has_lookup_value)
|
|
92
|
+
operations = flatten(map(_operation_data, operations))
|
|
93
|
+
term_ids = list(set(non_empty_list(map(lambda v: v.get('term', {}).get('@id'), operations))))
|
|
97
94
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return [{'term': term, 'value': value, 'input': input} for input in inputs] if should_run else []
|
|
101
|
-
return exec
|
|
95
|
+
valid_operations = [v for v in operations if (v.get('value') or 0) > 0]
|
|
96
|
+
has_operations = len(valid_operations) > 0
|
|
102
97
|
|
|
98
|
+
# group operations by term to show in logs
|
|
99
|
+
grouped_operations = group_by(operations, ['term.@id'])
|
|
103
100
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
101
|
+
for term_id, operations in grouped_operations.items():
|
|
102
|
+
logs = [
|
|
103
|
+
{
|
|
104
|
+
'value': operation.get('value'),
|
|
105
|
+
'dates': operation.get('dates'),
|
|
106
|
+
'input-id': operation.get('input', {}).get('@id'),
|
|
107
|
+
}
|
|
108
|
+
for operation in operations
|
|
109
|
+
]
|
|
110
|
+
logRequirements(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
|
|
111
|
+
details=log_as_table(logs))
|
|
112
|
+
|
|
113
|
+
should_run = any([(v.get('value') or 0) > 0 for v in operations])
|
|
114
|
+
logShouldRun(cycle, MODEL, term_id, should_run, model_key=MODEL_KEY)
|
|
109
115
|
|
|
110
116
|
logRequirements(cycle, model=MODEL, model_key=MODEL_KEY,
|
|
111
117
|
is_term_type_electricityFuel_incomplete=is_incomplete,
|
|
112
118
|
has_operations=has_operations,
|
|
113
|
-
operations=';'.join(
|
|
119
|
+
operations=';'.join(term_ids))
|
|
114
120
|
|
|
115
121
|
should_run = all([is_incomplete, has_operations])
|
|
116
122
|
logShouldRun(cycle, MODEL, None, should_run, model_key=MODEL_KEY)
|
|
117
|
-
return should_run,
|
|
123
|
+
return should_run, valid_operations
|
|
118
124
|
|
|
119
125
|
|
|
120
126
|
def run(cycle: dict):
|
|
121
127
|
should_run, operations = _should_run(cycle)
|
|
122
128
|
# group operations by input to show logs as table
|
|
123
|
-
grouped_operations =
|
|
129
|
+
grouped_operations = group_by(operations, ['input.id'])
|
|
124
130
|
return flatten(map(_run_operation(cycle), grouped_operations.values())) if should_run else []
|
|
@@ -89,7 +89,7 @@ def _run(impact_assessment: dict):
|
|
|
89
89
|
_get_factor_from_basinId(site, aware_id) if aware_id else None
|
|
90
90
|
) or _get_factor_from_region(impact_assessment, site)
|
|
91
91
|
inputs_value = convert_value_from_cycle(
|
|
92
|
-
product, sum_input_impacts(cycle.get('inputs', []), TERM_ID), model=MODEL, term_id=TERM_ID
|
|
92
|
+
impact_assessment, product, sum_input_impacts(cycle.get('inputs', []), TERM_ID), model=MODEL, term_id=TERM_ID
|
|
93
93
|
)
|
|
94
94
|
|
|
95
95
|
logRequirements(impact_assessment, model=MODEL, term=TERM_ID,
|
|
@@ -4,6 +4,7 @@ from pydash.objects import merge
|
|
|
4
4
|
from hestia_earth.utils.api import download_hestia
|
|
5
5
|
from hestia_earth.utils.tools import flatten
|
|
6
6
|
|
|
7
|
+
from .log import logger
|
|
7
8
|
from .utils import CACHE_KEY, cached_value
|
|
8
9
|
from .utils.site import CACHE_YEARS_KEY
|
|
9
10
|
from .site.pre_checks.cache_geospatialDatabase import (
|
|
@@ -146,6 +147,7 @@ def run(sites: list, years: list = None, include_region: bool = False):
|
|
|
146
147
|
batches = range(0, len(unique_years), batch_size)
|
|
147
148
|
|
|
148
149
|
for batch_index in batches:
|
|
150
|
+
logger.info(f"Processing sites in batch {batch_index + 1} of {len(batches)}...")
|
|
149
151
|
sub_years = unique_years[batch_index:batch_index + batch_size]
|
|
150
152
|
sites = _run(sites, sub_years, include_region, years_only=True)
|
|
151
153
|
|
|
@@ -73,7 +73,7 @@ def _run(impact_assessment: dict):
|
|
|
73
73
|
land_occupation_m2_kg = land_occupation_per_kg(MODEL, TERM_ID, cycle, site, product)
|
|
74
74
|
factor = get_region_factor(TERM_ID, impact_assessment, LOOKUP_SUFFIX, 'medium_intensity')
|
|
75
75
|
inputs_value = convert_value_from_cycle(
|
|
76
|
-
product, sum_input_impacts(cycle.get('inputs', []), TERM_ID), model=MODEL, term_id=TERM_ID
|
|
76
|
+
impact_assessment, product, sum_input_impacts(cycle.get('inputs', []), TERM_ID), model=MODEL, term_id=TERM_ID
|
|
77
77
|
)
|
|
78
78
|
logRequirements(impact_assessment, model=MODEL, term=TERM_ID,
|
|
79
79
|
landOccupation=land_occupation_m2_kg,
|
|
@@ -68,7 +68,7 @@ def _run(impact_assessment: dict):
|
|
|
68
68
|
landTransformation = _value(impact_assessment, _TRANSFORMATION_TERM_ID)
|
|
69
69
|
region_factor = get_region_factor(TERM_ID, impact_assessment, _LOOKUP_SUFFIX, 'medium_intensity')
|
|
70
70
|
inputs_value = convert_value_from_cycle(
|
|
71
|
-
product, sum_input_impacts(cycle.get('inputs', []), TERM_ID), model=MODEL, term_id=TERM_ID
|
|
71
|
+
impact_assessment, product, sum_input_impacts(cycle.get('inputs', []), TERM_ID), model=MODEL, term_id=TERM_ID
|
|
72
72
|
)
|
|
73
73
|
logRequirements(impact_assessment, model=MODEL, term=TERM_ID,
|
|
74
74
|
landTransformation=landTransformation,
|
|
@@ -57,7 +57,7 @@ def run(impact_assessment: dict):
|
|
|
57
57
|
cycle = impact_assessment.get('cycle', {})
|
|
58
58
|
product = get_product(impact_assessment)
|
|
59
59
|
inputs_value = convert_value_from_cycle(
|
|
60
|
-
product, sum_input_impacts(cycle.get('inputs', []), TERM_ID), model=MODEL, term_id=TERM_ID
|
|
60
|
+
impact_assessment, product, sum_input_impacts(cycle.get('inputs', []), TERM_ID), model=MODEL, term_id=TERM_ID
|
|
61
61
|
)
|
|
62
62
|
value = sum_values([landUseEffects, inputs_value])
|
|
63
63
|
logRequirements(impact_assessment, model=MODEL, term=TERM_ID,
|
|
@@ -31,7 +31,7 @@ def _run_model(model, cycle: dict):
|
|
|
31
31
|
|
|
32
32
|
def _run(cycle: dict):
|
|
33
33
|
values = non_empty_list([_run_model(model, cycle) for model in MODELS])
|
|
34
|
-
value = reduce(lambda prev, curr:
|
|
34
|
+
value = reduce(lambda prev, curr: prev | curr, values, cycle.get('completeness', {}))
|
|
35
35
|
keys = ','.join([next(iter(val)) for val in values])
|
|
36
36
|
debugValues(cycle, model=MODEL, keys=keys)
|
|
37
37
|
return value if len(values) > 0 else None
|
|
@@ -40,7 +40,7 @@ def _lookup_value(practice: dict, lookup_name: str):
|
|
|
40
40
|
def _practice_value(practice: dict):
|
|
41
41
|
term = practice.get('term', {})
|
|
42
42
|
fuel_use = _lookup_value(practice, LOOKUPS['operation'][0])
|
|
43
|
-
return {'id': term.get('@id'), 'fuel_use': fuel_use}
|
|
43
|
+
return {'id': term.get('@id'), 'value': practice.get('value'), 'fuel_use': fuel_use}
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
def run(cycle: dict):
|
|
@@ -55,6 +55,8 @@ def run(cycle: dict):
|
|
|
55
55
|
term_type_operation_complete=operation_complete,
|
|
56
56
|
values=log_as_table(practices_values))
|
|
57
57
|
|
|
58
|
-
is_complete = all([operation_complete] + [
|
|
58
|
+
is_complete = all([operation_complete] + [
|
|
59
|
+
all([p.get('fuel_use'), p.get('value') is not None]) for p in practices_values
|
|
60
|
+
])
|
|
59
61
|
|
|
60
62
|
return is_complete
|
|
@@ -78,7 +78,7 @@ def _get_groupings():
|
|
|
78
78
|
|
|
79
79
|
def get_grouping(groupings: dict, term_id: str):
|
|
80
80
|
grouping = get_term_lookup(term_id, 'fertGroupingNitrogen')
|
|
81
|
-
return
|
|
81
|
+
return groupings | ({grouping: term_id} if len(grouping) > 0 else {})
|
|
82
82
|
|
|
83
83
|
return reduce(get_grouping, term_ids, {})
|
|
84
84
|
|
|
@@ -31,8 +31,8 @@ RETURNS = {
|
|
|
31
31
|
}
|
|
32
32
|
TERM_ID = 'precipitationAnnual'
|
|
33
33
|
EE_PARAMS = {
|
|
34
|
-
'collection': 'ECMWF/
|
|
35
|
-
'band_name': '
|
|
34
|
+
'collection': 'ECMWF/ERA5_LAND/MONTHLY_AGGR',
|
|
35
|
+
'band_name': 'total_precipitation_sum',
|
|
36
36
|
'ee_type': 'raster',
|
|
37
37
|
'reducer': 'mean',
|
|
38
38
|
'reducer_annual': 'sum'
|
|
@@ -27,8 +27,8 @@ TERM_ID = 'precipitationLongTermAnnualMean'
|
|
|
27
27
|
START_DATE = '1979-01-01'
|
|
28
28
|
END_DATE = '2020-12-31'
|
|
29
29
|
EE_PARAMS = {
|
|
30
|
-
'collection': 'ECMWF/
|
|
31
|
-
'band_name': '
|
|
30
|
+
'collection': 'ECMWF/ERA5_LAND/MONTHLY_AGGR',
|
|
31
|
+
'band_name': 'total_precipitation_sum',
|
|
32
32
|
'ee_type': 'raster',
|
|
33
33
|
'reducer': 'mean',
|
|
34
34
|
'reducer_annual': 'sum',
|
|
@@ -31,8 +31,8 @@ RETURNS = {
|
|
|
31
31
|
}
|
|
32
32
|
TERM_ID = 'precipitationMonthly'
|
|
33
33
|
EE_PARAMS = {
|
|
34
|
-
'collection': 'ECMWF/
|
|
35
|
-
'band_name': '
|
|
34
|
+
'collection': 'ECMWF/ERA5_LAND/MONTHLY_AGGR',
|
|
35
|
+
'band_name': 'total_precipitation_sum',
|
|
36
36
|
'ee_type': 'raster',
|
|
37
37
|
'reducer': 'mean',
|
|
38
38
|
'reducer_annual': 'sum'
|
|
@@ -31,8 +31,8 @@ RETURNS = {
|
|
|
31
31
|
}
|
|
32
32
|
TERM_ID = 'temperatureAnnual'
|
|
33
33
|
EE_PARAMS = {
|
|
34
|
-
'collection': 'ECMWF/
|
|
35
|
-
'band_name': '
|
|
34
|
+
'collection': 'ECMWF/ERA5_LAND/MONTHLY_AGGR',
|
|
35
|
+
'band_name': 'temperature_2m',
|
|
36
36
|
'ee_type': 'raster',
|
|
37
37
|
'reducer': 'mean',
|
|
38
38
|
'reducer_annual': 'mean'
|
|
@@ -27,8 +27,8 @@ TERM_ID = 'temperatureLongTermAnnualMean'
|
|
|
27
27
|
START_DATE = '1979-01-01'
|
|
28
28
|
END_DATE = '2020-12-31'
|
|
29
29
|
EE_PARAMS = {
|
|
30
|
-
'collection': 'ECMWF/
|
|
31
|
-
'band_name': '
|
|
30
|
+
'collection': 'ECMWF/ERA5_LAND/MONTHLY_AGGR',
|
|
31
|
+
'band_name': 'temperature_2m',
|
|
32
32
|
'ee_type': 'raster',
|
|
33
33
|
'reducer': 'mean',
|
|
34
34
|
'reducer_annual': 'mean',
|
|
@@ -31,8 +31,8 @@ RETURNS = {
|
|
|
31
31
|
}
|
|
32
32
|
TERM_ID = 'temperatureMonthly'
|
|
33
33
|
EE_PARAMS = {
|
|
34
|
-
'collection': 'ECMWF/
|
|
35
|
-
'band_name': '
|
|
34
|
+
'collection': 'ECMWF/ERA5_LAND/MONTHLY_AGGR',
|
|
35
|
+
'band_name': 'temperature_2m',
|
|
36
36
|
'ee_type': 'raster',
|
|
37
37
|
'reducer': 'mean',
|
|
38
38
|
'reducer_annual': 'mean'
|
|
@@ -17,6 +17,20 @@ from hestia_earth.utils.tools import safe_parse_float, to_precision, non_empty_v
|
|
|
17
17
|
from hestia_earth.models.log import logRequirements, log_as_table, logShouldRun
|
|
18
18
|
from hestia_earth.models.utils.management import _new_management
|
|
19
19
|
from hestia_earth.models.utils.term import get_lookup_value
|
|
20
|
+
from .utils import (
|
|
21
|
+
IPCC_LAND_USE_CATEGORY_ANNUAL,
|
|
22
|
+
IPCC_LAND_USE_CATEGORY_PERENNIAL,
|
|
23
|
+
LAND_USE_TERMS_FOR_TRANSFORMATION,
|
|
24
|
+
ANNUAL_CROPLAND,
|
|
25
|
+
PERMANENT_CROPLAND,
|
|
26
|
+
FOREST_LAND,
|
|
27
|
+
OTHER_LAND,
|
|
28
|
+
PERMANENT_PASTURE,
|
|
29
|
+
TOTAL_CROPLAND,
|
|
30
|
+
TOTAL_AGRICULTURAL_CHANGE,
|
|
31
|
+
ALL_LAND_USE_TERMS,
|
|
32
|
+
crop_ipcc_land_use_category,
|
|
33
|
+
)
|
|
20
34
|
from . import MODEL
|
|
21
35
|
|
|
22
36
|
REQUIREMENTS = {
|
|
@@ -69,30 +83,6 @@ LOOKUPS = {
|
|
|
69
83
|
MODEL_KEY = 'landCover'
|
|
70
84
|
|
|
71
85
|
LAND_AREA = LOOKUPS["region-faostatArea"][3]
|
|
72
|
-
TOTAL_CROPLAND = "Cropland"
|
|
73
|
-
ANNUAL_CROPLAND = "Arable land"
|
|
74
|
-
FOREST_LAND = "Forest land"
|
|
75
|
-
OTHER_LAND = "Other land"
|
|
76
|
-
PERMANENT_CROPLAND = "Permanent crops"
|
|
77
|
-
PERMANENT_PASTURE = "Permanent meadows and pastures"
|
|
78
|
-
TOTAL_AGRICULTURAL_CHANGE = "Total agricultural change"
|
|
79
|
-
ALL_LAND_USE_TERMS = [
|
|
80
|
-
FOREST_LAND,
|
|
81
|
-
TOTAL_CROPLAND,
|
|
82
|
-
ANNUAL_CROPLAND,
|
|
83
|
-
PERMANENT_CROPLAND,
|
|
84
|
-
PERMANENT_PASTURE,
|
|
85
|
-
OTHER_LAND
|
|
86
|
-
]
|
|
87
|
-
# Mapping from Land use terms to Management node terms.
|
|
88
|
-
# land use term: (@id, name)
|
|
89
|
-
LAND_USE_TERMS_FOR_TRANSFORMATION = {
|
|
90
|
-
FOREST_LAND: ("forest", "Forest"),
|
|
91
|
-
ANNUAL_CROPLAND: ("annualCropland", "Annual cropland"),
|
|
92
|
-
PERMANENT_CROPLAND: ("permanentCropland", "Permanent cropland"),
|
|
93
|
-
PERMANENT_PASTURE: ("permanentPasture", "Permanent pasture"),
|
|
94
|
-
OTHER_LAND: ("otherLand", OTHER_LAND) # Not used yet
|
|
95
|
-
}
|
|
96
86
|
SITE_TYPES = {
|
|
97
87
|
SiteSiteType.CROPLAND.value,
|
|
98
88
|
SiteSiteType.FOREST.value,
|
|
@@ -100,8 +90,6 @@ SITE_TYPES = {
|
|
|
100
90
|
SiteSiteType.PERMANENT_PASTURE.value
|
|
101
91
|
}
|
|
102
92
|
DEFAULT_WINDOW_IN_YEARS = 20
|
|
103
|
-
IPCC_LAND_USE_CATEGORY_ANNUAL = "Annual crops"
|
|
104
|
-
IPCC_LAND_USE_CATEGORY_PERENNIAL = "Perennial crops"
|
|
105
93
|
OUTPUT_SIGNIFICANT_DIGITS = 3
|
|
106
94
|
|
|
107
95
|
|
|
@@ -137,22 +125,6 @@ def _lookup_land_use_type(nodes: list) -> str:
|
|
|
137
125
|
)
|
|
138
126
|
|
|
139
127
|
|
|
140
|
-
def _crop_ipcc_land_use_category(
|
|
141
|
-
crop_term_id: str,
|
|
142
|
-
lookup_term_type: str = TermTermType.LANDCOVER.value
|
|
143
|
-
) -> str:
|
|
144
|
-
"""
|
|
145
|
-
Looks up the crop in the lookup.
|
|
146
|
-
Returns the IPCC_LAND_USE_CATEGORY.
|
|
147
|
-
"""
|
|
148
|
-
return get_lookup_value(
|
|
149
|
-
lookup_term={"@id": crop_term_id, "type": "Term", "termType": lookup_term_type},
|
|
150
|
-
column=LOOKUPS.get("crop")[1],
|
|
151
|
-
model=MODEL,
|
|
152
|
-
term={"@id": crop_term_id, "type": "Term", "termType": lookup_term_type}
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
|
|
156
128
|
def get_changes(country_id: str, end_year: int) -> dict:
|
|
157
129
|
"""
|
|
158
130
|
For each entry in ALL_LAND_USE_TERMS, creates a key: value in output dictionary, also TOTAL
|
|
@@ -399,7 +371,7 @@ def _get_complete_faostat_to_crop_mapping() -> dict:
|
|
|
399
371
|
get_table_value(lookup, 'termid', crop_term_id, column_name("cropGroupingFaostatArea"))
|
|
400
372
|
)
|
|
401
373
|
if key:
|
|
402
|
-
mappings[key].append(
|
|
374
|
+
mappings[key].append(crop_ipcc_land_use_category(crop_term_id=crop_term_id, lookup_term_type="crop"))
|
|
403
375
|
return {
|
|
404
376
|
fao_name: max(set(crop_terms), key=crop_terms.count)
|
|
405
377
|
for fao_name, crop_terms in mappings.items()
|
|
@@ -420,6 +392,18 @@ def _get_harvested_area(country_id: str, year: int, faostat_name: str) -> float:
|
|
|
420
392
|
)
|
|
421
393
|
|
|
422
394
|
|
|
395
|
+
def _get_term_id_for_crop(nodes: set, land_type: str) -> str:
|
|
396
|
+
"""Use the original crop term id for permanent/perennial crops and the land use id for other types."""
|
|
397
|
+
result = next(
|
|
398
|
+
(node for node in nodes if crop_ipcc_land_use_category(node[0]) == IPCC_LAND_USE_CATEGORY_PERENNIAL), None
|
|
399
|
+
)
|
|
400
|
+
return (
|
|
401
|
+
# Take first perennial crop - not multi-cropping
|
|
402
|
+
result[0] if land_type == PERMANENT_CROPLAND and result else
|
|
403
|
+
LAND_USE_TERMS_FOR_TRANSFORMATION[land_type][0]
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
|
|
423
407
|
def _run_make_management_nodes(existing_nodes: list, percentage_transformed_from: dict, start_year: int) -> list:
|
|
424
408
|
"""Creates a list of new management nodes, excluding any dates matching existing ones."""
|
|
425
409
|
existing_nodes_set = {
|
|
@@ -435,7 +419,8 @@ def _run_make_management_nodes(existing_nodes: list, percentage_transformed_from
|
|
|
435
419
|
"percentage": 0 if ratio == -0.0 else to_precision(
|
|
436
420
|
number=ratio * 100,
|
|
437
421
|
digits=OUTPUT_SIGNIFICANT_DIGITS
|
|
438
|
-
)
|
|
422
|
+
),
|
|
423
|
+
"term_id": _get_term_id_for_crop(existing_nodes_set, land_type=land_type)
|
|
439
424
|
}
|
|
440
425
|
for land_type, ratio in percentage_transformed_from.items()
|
|
441
426
|
]
|
|
@@ -443,7 +428,7 @@ def _run_make_management_nodes(existing_nodes: list, percentage_transformed_from
|
|
|
443
428
|
|
|
444
429
|
return [
|
|
445
430
|
_management(
|
|
446
|
-
term_id=
|
|
431
|
+
term_id=value.get("term_id"),
|
|
447
432
|
value=value.get("percentage"),
|
|
448
433
|
start_date=value.get("land_management_key")[1],
|
|
449
434
|
end_date=value.get("land_management_key")[2]
|
|
@@ -698,7 +683,7 @@ def _should_run_historical_land_use_change_single_crop(
|
|
|
698
683
|
sum_of_site_areas_is_100
|
|
699
684
|
]
|
|
700
685
|
)
|
|
701
|
-
logShouldRun(site, MODEL, term
|
|
686
|
+
logShouldRun(site, MODEL, term.get("@id"), should_run, model_key=MODEL_KEY)
|
|
702
687
|
|
|
703
688
|
return should_run, site_area
|
|
704
689
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Creates an [emissionsResourceUse](https://hestia.earth/schema/Emission) for every landCover land transformation.
|
|
3
|
+
contained within the [ImpactAssesment.cycle](https://hestia.earth/schema/ImpactAssessment#cycle), averaged over the last
|
|
4
|
+
100 years.
|
|
5
|
+
|
|
6
|
+
It does this by multiplying the land occupation during the cycle by the
|
|
7
|
+
[Site](https://www-staging.hestia.earth/schema/Site) area 100 years ago and dividing by 100.
|
|
8
|
+
|
|
9
|
+
Land transformation from [land type] 100 years =
|
|
10
|
+
(Land occupation, during Cycle * Site Percentage Area 100 years ago [land type] / 100) / 100
|
|
11
|
+
"""
|
|
12
|
+
from .resourceUse_utils import run_resource_use
|
|
13
|
+
|
|
14
|
+
REQUIREMENTS = {
|
|
15
|
+
"ImpactAssessment": {
|
|
16
|
+
"Site": {
|
|
17
|
+
"management": [{"@type": "Management", "value": ">=0", "term.termType": "landCover", "endDate": ""}]
|
|
18
|
+
},
|
|
19
|
+
"emissionsResourceUse": [
|
|
20
|
+
{
|
|
21
|
+
"@type": "Indicator",
|
|
22
|
+
"term.@id": "landOccupationDuringCycle",
|
|
23
|
+
"landCover": {
|
|
24
|
+
"@type": "Term",
|
|
25
|
+
"termType": "landCover"
|
|
26
|
+
},
|
|
27
|
+
"value": ">=0"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"endDate": ""
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
RETURNS = {
|
|
34
|
+
"Indicator": [{
|
|
35
|
+
"value": "",
|
|
36
|
+
"landCover": "",
|
|
37
|
+
"previousLandCover": ""
|
|
38
|
+
}]
|
|
39
|
+
}
|
|
40
|
+
TERM_ID = 'landTransformation100YearAverageDuringCycle'
|
|
41
|
+
_HISTORIC_DATE_OFFSET = 100
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def run(impact_assessment: dict):
|
|
45
|
+
return run_resource_use(
|
|
46
|
+
impact_assessment=impact_assessment,
|
|
47
|
+
historic_date_offset=_HISTORIC_DATE_OFFSET,
|
|
48
|
+
term_id=TERM_ID
|
|
49
|
+
)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Creates an [emissionsResourceUse](https://hestia.earth/schema/Emission) for every landCover land transformation.
|
|
3
|
+
contained within the [ImpactAssesment.cycle](https://hestia.earth/schema/ImpactAssessment#cycle), averaged over the last
|
|
4
|
+
20 years.
|
|
5
|
+
|
|
6
|
+
It does this by multiplying the land occupation during the cycle by the
|
|
7
|
+
[Site](https://www-staging.hestia.earth/schema/Site) area 20 years ago and dividing by 20.
|
|
8
|
+
|
|
9
|
+
Land transformation from [land type] 20 years =
|
|
10
|
+
(Land occupation, during Cycle * Site Percentage Area 20 years ago [land type] / 100) / 20
|
|
11
|
+
"""
|
|
12
|
+
from .resourceUse_utils import run_resource_use
|
|
13
|
+
|
|
14
|
+
REQUIREMENTS = {
|
|
15
|
+
"ImpactAssessment": {
|
|
16
|
+
"Site": {
|
|
17
|
+
"management": [{"@type": "Management", "value": ">=0", "term.termType": "landCover", "endDate": ""}]
|
|
18
|
+
},
|
|
19
|
+
"emissionsResourceUse": [
|
|
20
|
+
{
|
|
21
|
+
"@type": "Indicator",
|
|
22
|
+
"term.@id": "landOccupationDuringCycle",
|
|
23
|
+
"landCover": {
|
|
24
|
+
"@type": "Term",
|
|
25
|
+
"termType": "landCover"
|
|
26
|
+
},
|
|
27
|
+
"value": ">=0"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"endDate": ""
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
RETURNS = {
|
|
34
|
+
"Indicator": [{
|
|
35
|
+
"value": "",
|
|
36
|
+
"landCover": "",
|
|
37
|
+
"previousLandCover": ""
|
|
38
|
+
}]
|
|
39
|
+
}
|
|
40
|
+
TERM_ID = 'landTransformation20YearAverageDuringCycle'
|
|
41
|
+
_HISTORIC_DATE_OFFSET = 20
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def run(impact_assessment: dict):
|
|
45
|
+
return run_resource_use(
|
|
46
|
+
impact_assessment=impact_assessment,
|
|
47
|
+
historic_date_offset=_HISTORIC_DATE_OFFSET,
|
|
48
|
+
term_id=TERM_ID
|
|
49
|
+
)
|