hestia-earth-models 0.65.4__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 +40 -24
- hestia_earth/models/aware/scarcityWeightedWaterUse.py +1 -1
- 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/electricityFuel.py +4 -2
- 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 +35 -21
- 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/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/utils.py +3 -1
- hestia_earth/models/mocking/search-results.json +779 -763
- 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/utils/blank_node.py +28 -0
- hestia_earth/models/utils/fuel.py +4 -1
- hestia_earth/models/utils/impact_assessment.py +7 -5
- hestia_earth/models/utils/pesticideAI.py +1 -0
- hestia_earth/models/version.py +1 -1
- {hestia_earth_models-0.65.4.dist-info → hestia_earth_models-0.65.5.dist-info}/METADATA +2 -2
- {hestia_earth_models-0.65.4.dist-info → hestia_earth_models-0.65.5.dist-info}/RECORD +47 -41
- 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.4.dist-info → hestia_earth_models-0.65.5.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.65.4.dist-info → hestia_earth_models-0.65.5.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.65.4.dist-info → hestia_earth_models-0.65.5.dist-info}/top_level.txt +0 -0
|
@@ -18,7 +18,7 @@ from hestia_earth.utils.model import filter_list_term_type
|
|
|
18
18
|
from hestia_earth.utils.tools import non_empty_list, flatten, list_sum, safe_parse_float
|
|
19
19
|
from hestia_earth.utils.emission import cycle_emissions_in_system_boundary
|
|
20
20
|
|
|
21
|
-
from hestia_earth.models.log import logRequirements, logShouldRun, log_as_table
|
|
21
|
+
from hestia_earth.models.log import logRequirements, logShouldRun, log_as_table, debugValues
|
|
22
22
|
from hestia_earth.models.utils import _omit, group_by
|
|
23
23
|
from hestia_earth.models.utils.emission import _new_emission
|
|
24
24
|
from hestia_earth.models.utils.site import valid_site_type
|
|
@@ -54,7 +54,7 @@ REQUIREMENTS = {
|
|
|
54
54
|
"siteType": ["cropland", "glass or high accessible cover"],
|
|
55
55
|
"country": {"@type": "Term", "termType": "region"}
|
|
56
56
|
},
|
|
57
|
-
"emissions": [{"@type": "Emission"}]
|
|
57
|
+
"emissions": [{"@type": "Emission", "value": ""}]
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
RETURNS = {
|
|
@@ -86,11 +86,24 @@ def _emission(term_id: str, value: float, input: dict):
|
|
|
86
86
|
return emission
|
|
87
87
|
|
|
88
88
|
|
|
89
|
-
def
|
|
90
|
-
|
|
89
|
+
def _run_emission(
|
|
90
|
+
cycle: dict, economicValueShare: float, total_yield: float, seed_input: dict, term_id: str, emission_value: float
|
|
91
|
+
):
|
|
92
|
+
input_term = seed_input.get('term', {})
|
|
93
|
+
input_term_id = input_term.get('@id')
|
|
91
94
|
seed_value = list_sum(seed_input.get('value'))
|
|
95
|
+
value = emission_value * economicValueShare / 100 / total_yield * seed_value
|
|
96
|
+
debugValues(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
|
|
97
|
+
value=value,
|
|
98
|
+
coefficient=1,
|
|
99
|
+
input=input_term_id)
|
|
100
|
+
|
|
101
|
+
return _emission(term_id, value, input_term)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _run(cycle: dict, economicValueShare: float, total_yield: float, seed_input: dict, grouped_emissions: dict):
|
|
92
105
|
return [
|
|
93
|
-
|
|
106
|
+
_run_emission(cycle, economicValueShare, total_yield, seed_input, term_id, emission_value)
|
|
94
107
|
for term_id, emission_value in grouped_emissions.items()
|
|
95
108
|
]
|
|
96
109
|
|
|
@@ -102,12 +115,12 @@ def _filter_emissions(cycle: dict):
|
|
|
102
115
|
{
|
|
103
116
|
'id': i.get('term', {}).get('@id'),
|
|
104
117
|
'group-id': get_lookup_value(i.get('term', {}), LOOKUPS['emission'], model=MODEL, model_key=MODEL_KEY),
|
|
105
|
-
'value': list_sum(i.get('value')
|
|
118
|
+
'value': list_sum(i.get('value'))
|
|
106
119
|
}
|
|
107
120
|
for i in cycle.get('emissions', [])
|
|
108
121
|
if all([
|
|
109
122
|
i.get('term', {}).get('@id') in required_emission_term_ids,
|
|
110
|
-
|
|
123
|
+
len(i.get('value', [])) > 0
|
|
111
124
|
])
|
|
112
125
|
]
|
|
113
126
|
emission_ids = set([v.get('id') for v in emissions])
|
|
@@ -120,7 +133,7 @@ def _filter_emissions(cycle: dict):
|
|
|
120
133
|
'id': group_id,
|
|
121
134
|
'emissions': list(filter(
|
|
122
135
|
lambda id: id in required_emission_term_ids,
|
|
123
|
-
list(lookup[lookup[column_name('inputProductionGroupId')] == group_id].termid)
|
|
136
|
+
set(list(lookup[lookup[column_name('inputProductionGroupId')] == group_id].termid))
|
|
124
137
|
))
|
|
125
138
|
}
|
|
126
139
|
for group_id in group_ids
|
|
@@ -129,8 +142,8 @@ def _filter_emissions(cycle: dict):
|
|
|
129
142
|
{
|
|
130
143
|
'id': group.get('id'),
|
|
131
144
|
'total-emissions': len(group.get('emissions', [])),
|
|
132
|
-
'included-emissions': len(
|
|
133
|
-
'missing-emissions': '-'.join(
|
|
145
|
+
'included-emissions': len(list(filter(lambda v: v in emission_ids, group.get('emissions', [])))),
|
|
146
|
+
'missing-emissions': '-'.join(list(filter(lambda v: v not in emission_ids, group.get('emissions', []))))
|
|
134
147
|
}
|
|
135
148
|
for group in emissions_per_group
|
|
136
149
|
]
|
|
@@ -154,14 +167,14 @@ def _evs(product: dict):
|
|
|
154
167
|
) or product.get('economicValueShare')
|
|
155
168
|
|
|
156
169
|
|
|
157
|
-
def
|
|
170
|
+
def _faostat_yield(country_id: str, end_year: int, product: dict):
|
|
158
171
|
grouping = get_crop_grouping_faostat_production(MODEL, product.get('term', {}))
|
|
159
172
|
return safe_parse_float(extract_grouped_data_closest_date(get_table_value(
|
|
160
173
|
download_lookup('region-crop-cropGroupingFaostatProduction-yield.csv'),
|
|
161
174
|
'termid',
|
|
162
175
|
country_id,
|
|
163
176
|
column_name(grouping)
|
|
164
|
-
), end_year))
|
|
177
|
+
), end_year))
|
|
165
178
|
|
|
166
179
|
|
|
167
180
|
def _group_seed_inputs(inputs: list):
|
|
@@ -186,10 +199,11 @@ def _should_run(cycle: dict):
|
|
|
186
199
|
{
|
|
187
200
|
'product': product.get('term', {}).get('@id'),
|
|
188
201
|
'seed-id': get_lookup_value(
|
|
189
|
-
product.get('term', {}), 'correspondingSeedTermIds', model=MODEL,
|
|
202
|
+
product.get('term', {}), 'correspondingSeedTermIds', model=MODEL, model_key=MODEL_KEY) or None,
|
|
190
203
|
'economicValueShare': _evs(product),
|
|
191
|
-
'yield':
|
|
192
|
-
'
|
|
204
|
+
'FAOSTAT-yield': _faostat_yield(country_id, end_year, product),
|
|
205
|
+
'product-yield': list_sum(product.get('value')),
|
|
206
|
+
'landCover-id': get_landCover_term_id(product.get('term', {}), model=MODEL, model_key=MODEL_KEY)
|
|
193
207
|
}
|
|
194
208
|
for product in crop_products
|
|
195
209
|
]
|
|
@@ -197,7 +211,7 @@ def _should_run(cycle: dict):
|
|
|
197
211
|
value for value in crop_products if all([
|
|
198
212
|
value.get('seed-id'),
|
|
199
213
|
value.get('economicValueShare'),
|
|
200
|
-
value.get('yield'),
|
|
214
|
+
value.get('FAOSTAT-yield') or value.get('product-yield'),
|
|
201
215
|
value.get('landCover-id'),
|
|
202
216
|
])
|
|
203
217
|
]
|
|
@@ -209,7 +223,7 @@ def _should_run(cycle: dict):
|
|
|
209
223
|
{
|
|
210
224
|
'input': i,
|
|
211
225
|
'is-corresponding-seed': i.get('term', {}).get('@id') in seed_term_ids,
|
|
212
|
-
'input-value': i.get('value'),
|
|
226
|
+
'input-value': list_sum(i.get('value'), default=None),
|
|
213
227
|
'has-linked-impact-assessment': bool(i.get('impactAssessment')),
|
|
214
228
|
'is-fromCycle': i.get('fromCycle', False),
|
|
215
229
|
'is-producedInCycle': i.get('producedInCycle', False),
|
|
@@ -221,7 +235,7 @@ def _should_run(cycle: dict):
|
|
|
221
235
|
v.get('input') for v in seed_inputs
|
|
222
236
|
if all([
|
|
223
237
|
v.get('is-corresponding-seed', False),
|
|
224
|
-
|
|
238
|
+
v.get('input-value') or -1 > 0,
|
|
225
239
|
not v.get('has-linked-impact-assessment'),
|
|
226
240
|
not v.get('is-fromCycle'),
|
|
227
241
|
not v.get('is-producedInCycle'),
|
|
@@ -230,12 +244,12 @@ def _should_run(cycle: dict):
|
|
|
230
244
|
|
|
231
245
|
crop_land_cover_ids = list(set([p.get('landCover-id') for p in valid_crop_products]))
|
|
232
246
|
total_economicValueShare = list_sum([p.get('economicValueShare') for p in valid_crop_products])
|
|
233
|
-
total_yield = list_sum([p.get('yield') for p in valid_crop_products])
|
|
247
|
+
total_yield = list_sum([p.get('FAOSTAT-yield') or p.get('product-yield') for p in valid_crop_products])
|
|
234
248
|
|
|
235
249
|
emissions, emissions_per_group = _filter_emissions(cycle)
|
|
236
250
|
# group emissions with the same group-id
|
|
237
251
|
grouped_emissions = reduce(
|
|
238
|
-
lambda p, c: p | {c.get('group-id'): p.get(c.get('group-id'), 0) + c.get('value'
|
|
252
|
+
lambda p, c: p | {c.get('group-id'): p.get(c.get('group-id'), 0) + (c.get('value') or 0)},
|
|
239
253
|
emissions,
|
|
240
254
|
{}
|
|
241
255
|
)
|
|
@@ -266,7 +280,7 @@ def _should_run(cycle: dict):
|
|
|
266
280
|
emissions_per_group=log_as_table(emissions_per_group),
|
|
267
281
|
**_omit(seed_input, 'input'))
|
|
268
282
|
|
|
269
|
-
logShouldRun(cycle, MODEL, term_id, should_run,
|
|
283
|
+
logShouldRun(cycle, MODEL, term_id, should_run, methodTier=TIER, model_key=MODEL_KEY)
|
|
270
284
|
|
|
271
285
|
return should_run, total_economicValueShare, total_yield, grouped_seed_inputs, grouped_emissions
|
|
272
286
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from hestia_earth.schema import TermTermType
|
|
2
|
+
|
|
3
|
+
from hestia_earth.models.utils.term import get_lookup_value
|
|
4
|
+
from . import MODEL
|
|
5
|
+
|
|
6
|
+
IPCC_LAND_USE_CATEGORY_ANNUAL = "Annual crops"
|
|
7
|
+
IPCC_LAND_USE_CATEGORY_PERENNIAL = "Perennial crops"
|
|
8
|
+
TOTAL_CROPLAND = "Cropland"
|
|
9
|
+
ANNUAL_CROPLAND = "Arable land"
|
|
10
|
+
FOREST_LAND = "Forest land"
|
|
11
|
+
OTHER_LAND = "Other land"
|
|
12
|
+
PERMANENT_CROPLAND = "Permanent crops"
|
|
13
|
+
PERMANENT_PASTURE = "Permanent meadows and pastures"
|
|
14
|
+
TOTAL_AGRICULTURAL_CHANGE = "Total agricultural change"
|
|
15
|
+
ALL_LAND_USE_TERMS = [
|
|
16
|
+
FOREST_LAND,
|
|
17
|
+
TOTAL_CROPLAND,
|
|
18
|
+
ANNUAL_CROPLAND,
|
|
19
|
+
PERMANENT_CROPLAND,
|
|
20
|
+
PERMANENT_PASTURE,
|
|
21
|
+
OTHER_LAND
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
# Mapping from Land use terms to Management node terms.
|
|
25
|
+
# land use term: (@id, name)
|
|
26
|
+
LAND_USE_TERMS_FOR_TRANSFORMATION = {
|
|
27
|
+
FOREST_LAND: ("forest", "Forest"),
|
|
28
|
+
ANNUAL_CROPLAND: ("annualCropland", "Annual cropland"),
|
|
29
|
+
PERMANENT_CROPLAND: ("permanentCropland", "Permanent cropland"),
|
|
30
|
+
PERMANENT_PASTURE: ("permanentPasture", "Permanent pasture"),
|
|
31
|
+
OTHER_LAND: ("otherLand", OTHER_LAND) # Not used yet
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def crop_ipcc_land_use_category(
|
|
36
|
+
crop_term_id: str,
|
|
37
|
+
lookup_term_type: str = TermTermType.LANDCOVER.value
|
|
38
|
+
) -> str:
|
|
39
|
+
"""
|
|
40
|
+
Looks up the crop in the lookup.
|
|
41
|
+
Returns the IPCC_LAND_USE_CATEGORY.
|
|
42
|
+
"""
|
|
43
|
+
return get_lookup_value(
|
|
44
|
+
lookup_term={"@id": crop_term_id, "type": "Term", "termType": lookup_term_type},
|
|
45
|
+
column='IPCC_LAND_USE_CATEGORY',
|
|
46
|
+
model=MODEL,
|
|
47
|
+
term={"@id": crop_term_id, "type": "Term", "termType": lookup_term_type}
|
|
48
|
+
)
|
|
@@ -4,9 +4,11 @@ Emissions
|
|
|
4
4
|
Creates an [Indicator](https://hestia.earth/schema/Indicator) for every [Emission](https://hestia.earth/schema/Emission)
|
|
5
5
|
contained within the [ImpactAssesment.cycle](https://hestia.earth/schema/ImpactAssessment#cycle).
|
|
6
6
|
It does this by dividing the Emission amount by the Product amount, and applying an allocation between co-products.
|
|
7
|
+
Note: for any Emission in the system boundary that does not exist in the Cycle, it will log the model as failed,
|
|
8
|
+
so that we know the Emission is missing.
|
|
7
9
|
"""
|
|
8
|
-
|
|
9
10
|
from hestia_earth.utils.tools import list_sum
|
|
11
|
+
from hestia_earth.utils.emission import cycle_emissions_in_system_boundary
|
|
10
12
|
|
|
11
13
|
from hestia_earth.models.log import logRequirements, logShouldRun
|
|
12
14
|
from hestia_earth.models.utils.impact_assessment import get_product, convert_value_from_cycle
|
|
@@ -38,10 +40,12 @@ RETURNS = {
|
|
|
38
40
|
MODEL_KEY = 'emissions'
|
|
39
41
|
|
|
40
42
|
|
|
41
|
-
def _indicator(product: dict):
|
|
43
|
+
def _indicator(impact_assessment: dict, product: dict):
|
|
42
44
|
def run(emission: dict):
|
|
43
45
|
term_id = emission.get('term', {}).get('@id')
|
|
44
|
-
value = convert_value_from_cycle(
|
|
46
|
+
value = convert_value_from_cycle(
|
|
47
|
+
impact_assessment, product, list_sum(emission.get('value', [0])), model=MODEL, term_id=term_id
|
|
48
|
+
)
|
|
45
49
|
|
|
46
50
|
indicator = _new_indicator(emission.get('term', {}), emission.get('methodModel'))
|
|
47
51
|
indicator['value'] = value
|
|
@@ -57,13 +61,23 @@ def _indicator(product: dict):
|
|
|
57
61
|
return run
|
|
58
62
|
|
|
59
63
|
|
|
64
|
+
def _log_missing_emissions(impact_assessment: dict, emissions: list):
|
|
65
|
+
term_ids = cycle_emissions_in_system_boundary(cycle=impact_assessment.get('cycle', {}))
|
|
66
|
+
emission_ids = list(map(lambda e: e.get('term', {}).get('@id'), emissions))
|
|
67
|
+
missing_term_ids = [term_id for term_id in term_ids if term_id not in emission_ids]
|
|
68
|
+
for term_id in missing_term_ids:
|
|
69
|
+
logRequirements(impact_assessment, model=MODEL, term=term_id,
|
|
70
|
+
present_in_cycle=False)
|
|
71
|
+
logShouldRun(impact_assessment, MODEL, term_id, should_run=False)
|
|
72
|
+
|
|
73
|
+
|
|
60
74
|
def _should_run_emission(impact_assessment: dict):
|
|
61
75
|
product = get_product(impact_assessment)
|
|
62
76
|
|
|
63
77
|
def exec(emission: dict):
|
|
64
78
|
term_id = emission.get('term', {}).get('@id')
|
|
65
79
|
has_value = convert_value_from_cycle(
|
|
66
|
-
product, list_sum(emission.get('value', [0])), model=MODEL, term_id=term_id
|
|
80
|
+
impact_assessment, product, list_sum(emission.get('value', [0])), model=MODEL, term_id=term_id
|
|
67
81
|
) is not None
|
|
68
82
|
not_deleted = emission.get('deleted', False) is not True
|
|
69
83
|
|
|
@@ -91,4 +105,5 @@ def run(impact_assessment: dict):
|
|
|
91
105
|
should_run, product = _should_run(impact_assessment)
|
|
92
106
|
emissions = impact_assessment.get('cycle', {}).get(MODEL_KEY, []) if should_run else []
|
|
93
107
|
emissions = list(filter(_should_run_emission(impact_assessment), emissions))
|
|
94
|
-
|
|
108
|
+
_log_missing_emissions(impact_assessment, emissions)
|
|
109
|
+
return list(map(_indicator(impact_assessment, product), emissions))
|
|
@@ -47,7 +47,6 @@ _NOMINAL_ERROR = 75
|
|
|
47
47
|
Carbon stock measurements without an associated `sd` should be assigned a nominal error of 75% (2*sd as a percentage of
|
|
48
48
|
the mean).
|
|
49
49
|
"""
|
|
50
|
-
_DEFAULT_YEARS_SINCE_LUC_EVENT = 999
|
|
51
50
|
_TRANSITION_PERIOD_YEARS = 20
|
|
52
51
|
_TRANSITION_PERIOD_DAYS = 20 * YEAR # 20 years in days
|
|
53
52
|
_VALID_DATE_FORMATS = {
|
|
@@ -96,6 +95,7 @@ class _InventoryKey(Enum):
|
|
|
96
95
|
LAND_USE_SUMMARY = "land-use-summary"
|
|
97
96
|
LAND_USE_CHANGE_EVENT = "luc-event"
|
|
98
97
|
YEARS_SINCE_LUC_EVENT = "years-since-luc-event"
|
|
98
|
+
YEARS_SINCE_INVENTORY_START = "years-since-inventory-start"
|
|
99
99
|
|
|
100
100
|
|
|
101
101
|
CarbonStock = NamedTuple("CarbonStock", [
|
|
@@ -611,7 +611,6 @@ def _create_compile_inventory_function(
|
|
|
611
611
|
)
|
|
612
612
|
|
|
613
613
|
inventory = _squash_inventory(
|
|
614
|
-
cycle_id,
|
|
615
614
|
cycle_inventory,
|
|
616
615
|
carbon_stock_inventory,
|
|
617
616
|
land_use_inventory,
|
|
@@ -1008,14 +1007,20 @@ def _compile_land_use_inventory(
|
|
|
1008
1007
|
is_luc_event = detect_land_use_change_func(land_use_summary, prev_land_use_summary)
|
|
1009
1008
|
|
|
1010
1009
|
time_delta = current_year - prev_year
|
|
1011
|
-
prev_years_since_luc_event =
|
|
1010
|
+
prev_years_since_luc_event = (
|
|
1011
|
+
result.get(prev_year, {}).get(_InventoryKey.YEARS_SINCE_LUC_EVENT, _TRANSITION_PERIOD_YEARS)
|
|
1012
|
+
)
|
|
1013
|
+
prev_years_since_inventory_start = result.get(prev_year, {}).get(_InventoryKey.YEARS_SINCE_INVENTORY_START, 0)
|
|
1014
|
+
|
|
1012
1015
|
years_since_luc_event = time_delta if is_luc_event else prev_years_since_luc_event + time_delta
|
|
1016
|
+
years_since_inventory_start = prev_years_since_inventory_start + time_delta
|
|
1013
1017
|
|
|
1014
1018
|
update_dict = {
|
|
1015
1019
|
current_year: {
|
|
1016
1020
|
_InventoryKey.LAND_USE_SUMMARY: land_use_summary,
|
|
1017
1021
|
_InventoryKey.LAND_USE_CHANGE_EVENT: is_luc_event,
|
|
1018
1022
|
_InventoryKey.YEARS_SINCE_LUC_EVENT: years_since_luc_event,
|
|
1023
|
+
_InventoryKey.YEARS_SINCE_INVENTORY_START: years_since_inventory_start
|
|
1019
1024
|
}
|
|
1020
1025
|
}
|
|
1021
1026
|
return result | update_dict
|
|
@@ -1030,9 +1035,7 @@ def _compile_land_use_inventory(
|
|
|
1030
1035
|
start_year: {
|
|
1031
1036
|
_InventoryKey.LAND_USE_SUMMARY: summarise_land_use_func(
|
|
1032
1037
|
land_cover_nodes_by_year.get(start_year, [])
|
|
1033
|
-
)
|
|
1034
|
-
_InventoryKey.LAND_USE_CHANGE_EVENT: False,
|
|
1035
|
-
_InventoryKey.YEARS_SINCE_LUC_EVENT: _DEFAULT_YEARS_SINCE_LUC_EVENT
|
|
1038
|
+
)
|
|
1036
1039
|
}
|
|
1037
1040
|
}
|
|
1038
1041
|
) if should_run else {}
|
|
@@ -1062,7 +1065,6 @@ def _sorted_merge(*sources: Union[dict, list[dict]]) -> dict:
|
|
|
1062
1065
|
|
|
1063
1066
|
|
|
1064
1067
|
def _squash_inventory(
|
|
1065
|
-
cycle_id: str,
|
|
1066
1068
|
cycle_inventory: dict,
|
|
1067
1069
|
carbon_stock_inventory: dict,
|
|
1068
1070
|
land_use_inventory: dict,
|
|
@@ -1075,8 +1077,6 @@ def _squash_inventory(
|
|
|
1075
1077
|
|
|
1076
1078
|
Parameters
|
|
1077
1079
|
----------
|
|
1078
|
-
cycle_id : str
|
|
1079
|
-
The unique identifier of the cycle being processed.
|
|
1080
1080
|
|
|
1081
1081
|
cycle_inventory : dict
|
|
1082
1082
|
A dictionary representing the share of emissions for each cycle, grouped by year.
|
|
@@ -1162,12 +1162,7 @@ def _squash_inventory(
|
|
|
1162
1162
|
)))
|
|
1163
1163
|
|
|
1164
1164
|
def should_run_group(method: MeasurementMethodClassification, year: int) -> bool:
|
|
1165
|
-
|
|
1166
|
-
share_of_emissions_group = cycle_inventory.get(year, {})
|
|
1167
|
-
|
|
1168
|
-
has_emission = _InventoryKey.CO2_EMISSION in carbon_stock_inventory_group.keys()
|
|
1169
|
-
is_relevant_for_cycle = cycle_id in share_of_emissions_group.get(_InventoryKey.SHARE_OF_EMISSION, {}).keys()
|
|
1170
|
-
return all([has_emission, is_relevant_for_cycle])
|
|
1165
|
+
return _InventoryKey.CO2_EMISSION in carbon_stock_inventory.get(method, {}).get(year, {}).keys()
|
|
1171
1166
|
|
|
1172
1167
|
def squash(result: dict, year: int) -> dict:
|
|
1173
1168
|
update_dict = next(
|
|
@@ -1175,7 +1170,10 @@ def _squash_inventory(
|
|
|
1175
1170
|
{
|
|
1176
1171
|
year: {
|
|
1177
1172
|
**_get_land_use_change_data(year, land_use_inventory),
|
|
1178
|
-
**reduce(merge, [
|
|
1173
|
+
**reduce(merge, [
|
|
1174
|
+
carbon_stock_inventory.get(method, {}).get(year, {}),
|
|
1175
|
+
cycle_inventory.get(year, {})
|
|
1176
|
+
], dict())
|
|
1179
1177
|
}
|
|
1180
1178
|
} for method in measurement_method_ranking if should_run_group(method, year)
|
|
1181
1179
|
),
|
|
@@ -1205,15 +1203,22 @@ def _get_land_use_change_data(
|
|
|
1205
1203
|
)
|
|
1206
1204
|
)
|
|
1207
1205
|
|
|
1208
|
-
|
|
1209
|
-
|
|
1206
|
+
time_delta = closest_inventory_year - year if closest_inventory_year else 0
|
|
1207
|
+
prev_years_since_luc_event = (
|
|
1208
|
+
land_use_inventory.get(closest_inventory_year, {}).get(_InventoryKey.YEARS_SINCE_LUC_EVENT)
|
|
1209
|
+
)
|
|
1210
|
+
prev_years_since_inventory_start = (
|
|
1211
|
+
land_use_inventory.get(closest_inventory_year, {}).get(_InventoryKey.YEARS_SINCE_INVENTORY_START)
|
|
1212
|
+
)
|
|
1210
1213
|
|
|
1211
|
-
years_since_luc_event =
|
|
1212
|
-
|
|
1214
|
+
years_since_luc_event = prev_years_since_luc_event - time_delta if prev_years_since_luc_event else None
|
|
1215
|
+
years_since_inventory_start = (
|
|
1216
|
+
prev_years_since_inventory_start - time_delta if prev_years_since_inventory_start else None
|
|
1213
1217
|
)
|
|
1214
1218
|
|
|
1215
1219
|
return {
|
|
1216
|
-
_InventoryKey.YEARS_SINCE_LUC_EVENT: years_since_luc_event
|
|
1220
|
+
_InventoryKey.YEARS_SINCE_LUC_EVENT: years_since_luc_event,
|
|
1221
|
+
_InventoryKey.YEARS_SINCE_INVENTORY_START: years_since_inventory_start
|
|
1217
1222
|
}
|
|
1218
1223
|
|
|
1219
1224
|
|
|
@@ -1408,25 +1413,54 @@ def create_run_function(
|
|
|
1408
1413
|
"""
|
|
1409
1414
|
data = inventory[year]
|
|
1410
1415
|
years_since_luc_event = data[_InventoryKey.YEARS_SINCE_LUC_EVENT]
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
)
|
|
1416
|
+
years_since_inventory_start = data[_InventoryKey.YEARS_SINCE_INVENTORY_START]
|
|
1417
|
+
|
|
1418
|
+
is_luc_emission = bool(years_since_luc_event) and years_since_luc_event <= _TRANSITION_PERIOD_YEARS
|
|
1419
|
+
is_data_complete = bool(years_since_inventory_start) and years_since_inventory_start > _TRANSITION_PERIOD_YEARS
|
|
1420
|
+
|
|
1421
|
+
if is_luc_emission:
|
|
1422
|
+
# If LUC emission allocate emissions to land use change AND add corresponding zero emission to management
|
|
1423
|
+
emission_term_id = land_use_change_emission_term_id
|
|
1424
|
+
zero_emission_term_id = management_change_emission_term_id
|
|
1425
|
+
elif is_data_complete:
|
|
1426
|
+
# If management emission && data complete allocate emissions to management change AND add corresponding
|
|
1427
|
+
# zero emission to management
|
|
1428
|
+
emission_term_id = management_change_emission_term_id
|
|
1429
|
+
zero_emission_term_id = land_use_change_emission_term_id
|
|
1430
|
+
else:
|
|
1431
|
+
# If management emission, but not data complete allocate emissions to management change only
|
|
1432
|
+
emission_term_id = management_change_emission_term_id
|
|
1433
|
+
zero_emission_term_id = None
|
|
1415
1434
|
|
|
1416
1435
|
rescaled_emission = _rescale_carbon_stock_change_emission(
|
|
1417
1436
|
data[_InventoryKey.CO2_EMISSION], data[_InventoryKey.SHARE_OF_EMISSION][cycle_id]
|
|
1418
1437
|
)
|
|
1419
1438
|
|
|
1439
|
+
zero_emission = CarbonStockChangeEmission(
|
|
1440
|
+
value=array(0),
|
|
1441
|
+
start_date=rescaled_emission.start_date,
|
|
1442
|
+
end_date=rescaled_emission.end_date,
|
|
1443
|
+
method=rescaled_emission.method
|
|
1444
|
+
) if zero_emission_term_id else None
|
|
1445
|
+
|
|
1420
1446
|
previous_emission = result.get(emission_term_id)
|
|
1447
|
+
previous_zero_emission = result.get(zero_emission_term_id)
|
|
1421
1448
|
|
|
1422
|
-
|
|
1449
|
+
emission_dict = {
|
|
1423
1450
|
emission_term_id: (
|
|
1424
1451
|
_add_carbon_stock_change_emissions(previous_emission, rescaled_emission) if previous_emission
|
|
1425
1452
|
else rescaled_emission
|
|
1426
1453
|
)
|
|
1427
1454
|
}
|
|
1428
1455
|
|
|
1429
|
-
|
|
1456
|
+
zero_emission_dict = {
|
|
1457
|
+
zero_emission_term_id: (
|
|
1458
|
+
_add_carbon_stock_change_emissions(previous_zero_emission, zero_emission) if previous_zero_emission
|
|
1459
|
+
else zero_emission
|
|
1460
|
+
)
|
|
1461
|
+
} if zero_emission_term_id else {}
|
|
1462
|
+
|
|
1463
|
+
return result | emission_dict | zero_emission_dict
|
|
1430
1464
|
|
|
1431
1465
|
def run(cycle_id: str, cycle_start_date: str, cycle_end_date: str, inventory: dict) -> list[dict]:
|
|
1432
1466
|
"""
|
|
@@ -1447,9 +1481,13 @@ def create_run_function(
|
|
|
1447
1481
|
list[dict]
|
|
1448
1482
|
A list of [Emission](https://www.hestia.earth/schema/Emission) nodes containing model results.
|
|
1449
1483
|
"""
|
|
1484
|
+
|
|
1485
|
+
def should_run_year(year: int) -> bool:
|
|
1486
|
+
return cycle_id in inventory.get(year, {}).get(_InventoryKey.SHARE_OF_EMISSION, {}).keys()
|
|
1487
|
+
|
|
1450
1488
|
assigned_emissions = reduce(
|
|
1451
1489
|
lambda result, year: reduce_emissions(result, year, cycle_id, inventory),
|
|
1452
|
-
inventory.keys(),
|
|
1490
|
+
(year for year in inventory.keys() if should_run_year(year)),
|
|
1453
1491
|
{}
|
|
1454
1492
|
)
|
|
1455
1493
|
|