hestia-earth-models 0.64.14__py3-none-any.whl → 0.65.1__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 +1 -1
- hestia_earth/models/cache_sites.py +15 -24
- hestia_earth/models/chaudharyBrooks2018/damageToTerrestrialEcosystemsLandTransformation.py +6 -9
- hestia_earth/models/cycle/input/hestiaAggregatedData.py +46 -22
- hestia_earth/models/cycle/pre_checks/cache_sources.py +3 -25
- hestia_earth/models/cycle/product/economicValueShare.py +2 -2
- hestia_earth/models/ecoinventV3/__init__.py +3 -2
- hestia_earth/models/ecoinventV3/utils.py +1 -2
- hestia_earth/models/ecoinventV3AndEmberClimate/__init__.py +3 -2
- hestia_earth/models/environmentalFootprintV3/soilQualityIndexLandTransformation.py +17 -37
- hestia_earth/models/faostat2018/landTransformation100YearAverageDuringCycle.py +34 -0
- hestia_earth/models/faostat2018/landTransformation20YearAverageDuringCycle.py +34 -0
- hestia_earth/models/faostat2018/utils.py +47 -3
- hestia_earth/models/hestia/landCover.py +5 -5
- hestia_earth/models/hestia/seed_emissions.py +284 -0
- hestia_earth/models/ipcc2019/aboveGroundBiomass.py +2 -2
- hestia_earth/models/ipcc2019/belowGroundBiomass.py +8 -2
- hestia_earth/models/ipcc2019/biomass_utils.py +11 -4
- hestia_earth/models/ipcc2019/ch4ToAirEntericFermentation.py +19 -10
- hestia_earth/models/ipcc2019/co2ToAirAboveGroundBiomassStockChange.py +2 -1
- hestia_earth/models/ipcc2019/co2ToAirBelowGroundBiomassStockChange.py +2 -1
- hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +8 -7
- hestia_earth/models/ipcc2019/co2ToAirSoilOrganicCarbonStockChange.py +2 -1
- hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_1_utils.py +28 -34
- hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_2_utils.py +8 -12
- hestia_earth/models/ipcc2019/organicCarbonPerHa_utils.py +13 -30
- hestia_earth/models/linkedImpactAssessment/freshwaterWithdrawalsInputsProduction.py +4 -1
- hestia_earth/models/linkedImpactAssessment/landOccupationInputsProduction.py +16 -1
- hestia_earth/models/linkedImpactAssessment/{landTransformationFromForest100YearAverageInputsProduction.py → landTransformation100YearAverageInputsProduction.py} +8 -3
- hestia_earth/models/linkedImpactAssessment/{landTransformationFromCropland100YearAverageInputsProduction.py → landTransformation20YearAverageInputsProduction.py} +8 -3
- hestia_earth/models/linkedImpactAssessment/utils.py +80 -16
- hestia_earth/models/mocking/search-results.json +448 -448
- hestia_earth/models/pooreNemecek2018/excretaKgN.py +45 -41
- hestia_earth/models/pooreNemecek2018/excretaKgVs.py +89 -63
- hestia_earth/models/pooreNemecek2018/saplingsDepreciatedAmountPerCycle.py +8 -8
- hestia_earth/models/pooreNemecek2018/utils.py +60 -19
- hestia_earth/models/schererPfister2015/nErosionSoilFlux.py +4 -3
- hestia_earth/models/schererPfister2015/pErosionSoilFlux.py +4 -3
- hestia_earth/models/schererPfister2015/utils.py +12 -9
- hestia_earth/models/site/management.py +70 -55
- hestia_earth/models/site/pre_checks/cache_sources.py +2 -20
- hestia_earth/models/utils/__init__.py +12 -1
- hestia_earth/models/utils/aggregated.py +1 -1
- hestia_earth/models/utils/blank_node.py +20 -12
- hestia_earth/models/utils/cache_sources.py +15 -0
- hestia_earth/models/utils/crop.py +5 -0
- hestia_earth/models/utils/indicator.py +3 -1
- hestia_earth/models/version.py +1 -1
- {hestia_earth_models-0.64.14.dist-info → hestia_earth_models-0.65.1.dist-info}/LICENSE +1 -1
- {hestia_earth_models-0.64.14.dist-info → hestia_earth_models-0.65.1.dist-info}/METADATA +3 -3
- {hestia_earth_models-0.64.14.dist-info → hestia_earth_models-0.65.1.dist-info}/RECORD +80 -109
- tests/models/cml2001Baseline/test_abioticResourceDepletionMineralsAndMetals.py +1 -1
- tests/models/cycle/input/test_hestiaAggregatedData.py +5 -2
- tests/models/environmentalFootprintV3/test_soilQualityIndexLandTransformation.py +39 -28
- tests/models/{hyde32/test_landTransformationFromForest20YearAverageDuringCycle.py → faostat2018/test_landTransformation100YearAverageDuringCycle.py} +5 -5
- tests/models/{hyde32/test_landTransformationFromForest100YearAverageDuringCycle.py → faostat2018/test_landTransformation20YearAverageDuringCycle.py} +5 -5
- tests/models/faostat2018/test_utils.py +28 -0
- tests/models/hestia/test_landCover.py +2 -1
- tests/models/hestia/test_seed_emissions.py +27 -0
- tests/models/ipcc2019/test_aboveGroundBiomass.py +40 -4
- tests/models/ipcc2019/test_belowGroundBiomass.py +40 -4
- tests/models/ipcc2019/test_co2ToAirAboveGroundBiomassStockChange.py +52 -15
- tests/models/ipcc2019/test_co2ToAirBelowGroundBiomassStockChange.py +50 -14
- tests/models/ipcc2019/test_co2ToAirSoilOrganicCarbonStockChange.py +53 -32
- tests/models/ipcc2019/test_organicCarbonPerHa.py +91 -108
- tests/models/ipcc2019/test_organicCarbonPerHa_tier_1_utils.py +33 -50
- tests/models/ipcc2019/test_organicCarbonPerHa_tier_2_utils.py +0 -52
- tests/models/linkedImpactAssessment/test_freshwaterWithdrawalsInputsProduction.py +6 -4
- tests/models/linkedImpactAssessment/test_landOccupationInputsProduction.py +6 -4
- tests/models/linkedImpactAssessment/{test_landTransformationFromForest100YearAverageInputsProduction.py → test_landTransformation100YearAverageInputsProduction.py} +7 -5
- tests/models/linkedImpactAssessment/{test_landTransformationFromForest20YearAverageInputsProduction.py → test_landTransformation20YearAverageInputsProduction.py} +7 -5
- tests/models/pooreNemecek2018/test_excretaKgN.py +2 -2
- tests/models/pooreNemecek2018/test_excretaKgVs.py +1 -1
- tests/models/pooreNemecek2018/test_utils.py +26 -0
- tests/models/site/test_management.py +10 -27
- tests/models/test_cache_sites.py +40 -12
- tests/models/utils/test_blank_node.py +0 -8
- tests/models/utils/test_cache_sources.py +21 -0
- hestia_earth/models/blonkConsultants2016/landTransformationFromForest20YearAverageDuringCycle.py +0 -90
- hestia_earth/models/faostat2018/landTransformationFromCropland100YearAverage.py +0 -74
- hestia_earth/models/faostat2018/landTransformationFromCropland20YearAverage.py +0 -74
- hestia_earth/models/hyde32/__init__.py +0 -13
- hestia_earth/models/hyde32/landTransformationFromCropland100YearAverageDuringCycle.py +0 -60
- hestia_earth/models/hyde32/landTransformationFromCropland20YearAverageDuringCycle.py +0 -60
- hestia_earth/models/hyde32/landTransformationFromForest100YearAverageDuringCycle.py +0 -60
- hestia_earth/models/hyde32/landTransformationFromForest20YearAverageDuringCycle.py +0 -60
- hestia_earth/models/hyde32/landTransformationFromOtherNaturalVegetation100YearAverageDuringCycle.py +0 -61
- hestia_earth/models/hyde32/landTransformationFromOtherNaturalVegetation20YearAverageDuringCycle.py +0 -61
- hestia_earth/models/hyde32/landTransformationFromPermanentPasture100YearAverageDuringCycle.py +0 -61
- hestia_earth/models/hyde32/landTransformationFromPermanentPasture20YearAverageDuringCycle.py +0 -61
- hestia_earth/models/hyde32/utils.py +0 -72
- hestia_earth/models/linkedImpactAssessment/landTransformationFromCropland20YearAverageInputsProduction.py +0 -36
- hestia_earth/models/linkedImpactAssessment/landTransformationFromForest20YearAverageInputsProduction.py +0 -36
- hestia_earth/models/linkedImpactAssessment/landTransformationFromOtherNaturalVegetation100YearAverageInputsProduction.py +0 -36
- hestia_earth/models/linkedImpactAssessment/landTransformationFromOtherNaturalVegetation20YearAverageInputsProduction.py +0 -36
- hestia_earth/models/linkedImpactAssessment/landTransformationFromPermanentPasture100YearAverageInputsProduction.py +0 -36
- hestia_earth/models/linkedImpactAssessment/landTransformationFromPermanentPasture20YearAverageInputsProduction.py +0 -36
- tests/models/blonkConsultants2016/test_landTransformationFromForest20YearAverageDuringCycle.py +0 -36
- tests/models/cycle/pre_checks/test_cache_sources.py +0 -25
- tests/models/faostat2018/test_landTransformationFromCropland100YearAverage.py +0 -40
- tests/models/faostat2018/test_landTransformationFromCropland20YearAverage.py +0 -40
- tests/models/hyde32/__init__.py +0 -0
- tests/models/hyde32/test_landTransformationFromCropland100YearAverageDuringCycle.py +0 -21
- tests/models/hyde32/test_landTransformationFromCropland20YearAverageDuringCycle.py +0 -21
- tests/models/hyde32/test_landTransformationFromOtherNaturalVegetation100YearAverageDuringCycle.py +0 -23
- tests/models/hyde32/test_landTransformationFromOtherNaturalVegetation20YearAverageDuringCycle.py +0 -21
- tests/models/hyde32/test_landTransformationFromPermanentPasture100YearAverageDuringCycle.py +0 -21
- tests/models/hyde32/test_landTransformationFromPermanentPasture20YearAverageDuringCycle.py +0 -21
- tests/models/linkedImpactAssessment/test_landTransformationFromCropland100YearAverageInputsProduction.py +0 -23
- tests/models/linkedImpactAssessment/test_landTransformationFromCropland20YearAverageInputsProduction.py +0 -23
- tests/models/linkedImpactAssessment/test_landTransformationFromOtherNaturalVegetation100YearAverageInputsProduction.py +0 -23
- tests/models/linkedImpactAssessment/test_landTransformationFromOtherNaturalVegetation20YearAverageInputsProduction.py +0 -23
- tests/models/linkedImpactAssessment/test_landTransformationFromPermanentPasture100YearAverageInputsProduction.py +0 -24
- tests/models/linkedImpactAssessment/test_landTransformationFromPermanentPasture20YearAverageInputsProduction.py +0 -24
- tests/models/site/pre_checks/test_cache_sources.py +0 -21
- {hestia_earth_models-0.64.14.dist-info → hestia_earth_models-0.65.1.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.64.14.dist-info → hestia_earth_models-0.65.1.dist-info}/top_level.txt +0 -0
|
@@ -20,10 +20,11 @@ from hestia_earth.utils.tools import safe_parse_float, flatten
|
|
|
20
20
|
from hestia_earth.utils.blank_node import get_node_value
|
|
21
21
|
|
|
22
22
|
from hestia_earth.models.log import logRequirements, logShouldRun, log_as_table
|
|
23
|
-
from hestia_earth.models.utils import _include
|
|
23
|
+
from hestia_earth.models.utils import _include, _omit
|
|
24
24
|
from hestia_earth.models.utils.management import _new_management
|
|
25
25
|
from hestia_earth.models.utils.term import get_lookup_value
|
|
26
26
|
from hestia_earth.models.utils.blank_node import condense_nodes
|
|
27
|
+
from hestia_earth.models.utils.crop import get_landCover_term_id
|
|
27
28
|
from hestia_earth.models.utils.site import (
|
|
28
29
|
related_cycles, get_land_cover_term_id as get_landCover_term_id_from_site_type
|
|
29
30
|
)
|
|
@@ -39,8 +40,7 @@ REQUIREMENTS = {
|
|
|
39
40
|
"products": [
|
|
40
41
|
{
|
|
41
42
|
"@type": "Product",
|
|
42
|
-
"term.termType": ["crop", "forage", "landCover"]
|
|
43
|
-
"units": ["% area", "boolean"]
|
|
43
|
+
"term.termType": ["crop", "forage", "landCover"]
|
|
44
44
|
}
|
|
45
45
|
],
|
|
46
46
|
"practices": [
|
|
@@ -52,7 +52,6 @@ REQUIREMENTS = {
|
|
|
52
52
|
"landUseManagement",
|
|
53
53
|
"system"
|
|
54
54
|
],
|
|
55
|
-
"units": ["% area", "boolean"],
|
|
56
55
|
"value": ""
|
|
57
56
|
}
|
|
58
57
|
],
|
|
@@ -87,11 +86,11 @@ LOOKUPS = {
|
|
|
87
86
|
"inorganicFertiliser": "nitrogenContent",
|
|
88
87
|
"organicFertiliser": "ANIMAL_MANURE",
|
|
89
88
|
"soilAmendment": "PRACTICE_INCREASING_C_INPUT",
|
|
90
|
-
"landUseManagement": "GAP_FILL_TO_MANAGEMENT"
|
|
89
|
+
"landUseManagement": "GAP_FILL_TO_MANAGEMENT",
|
|
90
|
+
"property": "GAP_FILL_TO_MANAGEMENT"
|
|
91
91
|
}
|
|
92
92
|
MODEL_KEY = 'management'
|
|
93
93
|
|
|
94
|
-
_LAND_COVER_KEY = LOOKUPS['crop'][0]
|
|
95
94
|
_ANIMAL_MANURE_USED_TERM_ID = "animalManureUsed"
|
|
96
95
|
_INORGANIC_NITROGEN_FERTILISER_USED_TERM_ID = "inorganicNitrogenFertiliserUsed"
|
|
97
96
|
_ORGANIC_FERTILISER_USED_TERM_ID = "organicFertiliserUsed"
|
|
@@ -140,6 +139,16 @@ def management(data: dict):
|
|
|
140
139
|
return node
|
|
141
140
|
|
|
142
141
|
|
|
142
|
+
def _should_gap_fill(term: dict):
|
|
143
|
+
value = get_lookup_value(lookup_term=term, column='GAP_FILL_TO_MANAGEMENT')
|
|
144
|
+
return bool(value)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _filter_properties(blank_node: dict):
|
|
148
|
+
properties = list(filter(lambda p: _should_gap_fill(p.get('term', {})), blank_node.get('properties', [])))
|
|
149
|
+
return _omit(blank_node, ['properties']) | ({'properties': properties} if properties else {})
|
|
150
|
+
|
|
151
|
+
|
|
143
152
|
def _map_to_value(value: dict):
|
|
144
153
|
return {
|
|
145
154
|
'id': value.get('term', {}).get('@id'),
|
|
@@ -154,37 +163,23 @@ def _extract_node_value(node: dict) -> dict:
|
|
|
154
163
|
return node | {'value': get_node_value(node)}
|
|
155
164
|
|
|
156
165
|
|
|
157
|
-
def _default_dates(cycle: dict, values: list):
|
|
158
|
-
return [(_include(cycle, ["startDate", "endDate"]) | v) for v in values]
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
def _dates_from_current_cycle(cycle: dict, values: list) -> list:
|
|
162
|
-
"""Always uses the dates from the cycle."""
|
|
163
|
-
return [v | _include(cycle, ["startDate", "endDate"]) for v in values]
|
|
164
|
-
|
|
165
|
-
|
|
166
166
|
def _copy_item_if_exists(source: dict, keys: list[str] = None, dest: dict = None) -> dict:
|
|
167
|
-
|
|
168
|
-
dest = dest or {}
|
|
169
|
-
return reduce(lambda p, c: p | ({c: source[c]} if c in source else {}), keys, dest)
|
|
167
|
+
return reduce(lambda p, c: p | ({c: source[c]} if source.get(c) else {}), keys or [], dest or {})
|
|
170
168
|
|
|
171
169
|
|
|
172
170
|
def _get_landCover_term_id(product: dict) -> str:
|
|
173
171
|
term = product.get('term', {})
|
|
174
|
-
|
|
175
|
-
return value.split(';')[0] if value else None
|
|
172
|
+
return get_landCover_term_id(term, model=MODEL, term=term.get('@id'), model_key=MODEL_KEY)
|
|
176
173
|
|
|
177
174
|
|
|
178
|
-
def _get_relevant_items(
|
|
179
|
-
cycle: dict, item_name: str, relevant_terms: list, date_fill: callable = _default_dates
|
|
180
|
-
):
|
|
175
|
+
def _get_relevant_items(cycle: dict, item_name: str, relevant_terms: list):
|
|
181
176
|
"""
|
|
182
177
|
Get items from the list of cycles with any of the relevant terms.
|
|
183
|
-
Also adds dates
|
|
178
|
+
Also adds dates from Cycle.
|
|
184
179
|
"""
|
|
185
180
|
return [
|
|
186
|
-
item
|
|
187
|
-
for item in
|
|
181
|
+
_include(cycle, ["startDate", "endDate"]) | item
|
|
182
|
+
for item in filter_list_term_type(cycle.get(item_name, []), relevant_terms)
|
|
188
183
|
]
|
|
189
184
|
|
|
190
185
|
|
|
@@ -226,54 +221,74 @@ def _run_from_siteType(site: dict, cycle: dict):
|
|
|
226
221
|
}] if should_run else []
|
|
227
222
|
|
|
228
223
|
|
|
229
|
-
def
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
224
|
+
def _run_products(cycle: dict, products: list, total_products: int = None, use_cycle_dates: bool = False):
|
|
225
|
+
default_dates = _include(cycle, ["startDate", "endDate"])
|
|
226
|
+
return [
|
|
227
|
+
_map_to_value(default_dates | _copy_item_if_exists(
|
|
228
|
+
source=product,
|
|
229
|
+
keys=['properties', 'startDate', 'endDate'],
|
|
230
|
+
dest={
|
|
231
|
+
"term": {'@id': _get_landCover_term_id(product)},
|
|
232
|
+
"value": round(100 / (total_products or len(products)), 2)
|
|
233
|
+
}
|
|
234
|
+
) | (
|
|
235
|
+
default_dates if use_cycle_dates else {}
|
|
236
|
+
))
|
|
237
|
+
for product in products
|
|
238
|
+
]
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def _run_from_landCover(cycle: dict, crop_forage_products: list):
|
|
242
|
+
"""
|
|
243
|
+
Copy landCover items, and include crop/forage landCover items with properties to count in ratio.
|
|
244
|
+
"""
|
|
235
245
|
products = [
|
|
236
246
|
_map_to_value(_extract_node_value(
|
|
237
247
|
_include(
|
|
238
248
|
value=product,
|
|
239
249
|
keys=["term", "value", "startDate", "endDate", "properties"]
|
|
240
250
|
)
|
|
241
|
-
)) for product in
|
|
251
|
+
)) for product in _get_relevant_items(
|
|
252
|
+
cycle=cycle,
|
|
253
|
+
item_name="products",
|
|
254
|
+
relevant_terms=[TermTermType.LANDCOVER]
|
|
255
|
+
)
|
|
242
256
|
]
|
|
243
|
-
return products
|
|
257
|
+
return products + _run_products(
|
|
258
|
+
cycle,
|
|
259
|
+
crop_forage_products,
|
|
260
|
+
total_products=len(crop_forage_products) + len(products),
|
|
261
|
+
use_cycle_dates=True
|
|
262
|
+
)
|
|
244
263
|
|
|
245
264
|
|
|
246
265
|
def _run_from_crop_forage(cycle: dict):
|
|
247
266
|
products = _get_relevant_items(
|
|
248
267
|
cycle=cycle,
|
|
249
268
|
item_name="products",
|
|
250
|
-
relevant_terms=[TermTermType.CROP, TermTermType.FORAGE]
|
|
251
|
-
date_fill=_dates_from_current_cycle
|
|
269
|
+
relevant_terms=[TermTermType.CROP, TermTermType.FORAGE]
|
|
252
270
|
)
|
|
271
|
+
# only take products with a matching landCover term
|
|
253
272
|
products = list(filter(_get_landCover_term_id, products))
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
source=product,
|
|
257
|
-
keys=["startDate", "endDate", "properties"],
|
|
258
|
-
dest={
|
|
259
|
-
"term": {'@id': _get_landCover_term_id(product)},
|
|
260
|
-
"value": round(100 / len(products), 2)
|
|
261
|
-
}
|
|
262
|
-
))
|
|
263
|
-
for product in products
|
|
264
|
-
]
|
|
265
|
-
return products
|
|
273
|
+
# remove any properties that should not get gap-filled
|
|
274
|
+
products = list(map(_filter_properties, products))
|
|
266
275
|
|
|
276
|
+
# split products with properties and those without
|
|
277
|
+
products_with_gap_filled_props = [p for p in products if p.get('properties')]
|
|
278
|
+
products_without_gap_filled_props = [p for p in products if not p.get('properties')]
|
|
267
279
|
|
|
268
|
-
|
|
280
|
+
return _run_from_landCover(
|
|
281
|
+
cycle=cycle,
|
|
282
|
+
crop_forage_products=products_with_gap_filled_props
|
|
283
|
+
) + _run_products(cycle, products_without_gap_filled_props, use_cycle_dates=False)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def _should_run_practice(practice: dict):
|
|
269
287
|
"""
|
|
270
288
|
Include only landUseManagement practices where GAP_FILL_TO_MANAGEMENT = True
|
|
271
289
|
"""
|
|
272
290
|
term = practice.get('term', {})
|
|
273
|
-
return (
|
|
274
|
-
term.get('termType') != TermTermType.LANDUSEMANAGEMENT.value or
|
|
275
|
-
get_lookup_value(lookup_term=term, column=LOOKUPS["landUseManagement"])
|
|
276
|
-
)
|
|
291
|
+
return term.get('termType') != TermTermType.LANDUSEMANAGEMENT.value or _should_gap_fill(term)
|
|
277
292
|
|
|
278
293
|
|
|
279
294
|
def _run_from_practices(cycle: dict):
|
|
@@ -295,13 +310,13 @@ def _run_from_practices(cycle: dict):
|
|
|
295
310
|
]
|
|
296
311
|
)
|
|
297
312
|
]
|
|
298
|
-
practices = list(map(_map_to_value, filter(
|
|
313
|
+
practices = list(map(_map_to_value, filter(_should_run_practice, practices)))
|
|
299
314
|
return practices
|
|
300
315
|
|
|
301
316
|
|
|
302
317
|
def _run_cycle(site: dict, cycle: dict):
|
|
303
318
|
inputs = _run_from_inputs(site, cycle)
|
|
304
|
-
products =
|
|
319
|
+
products = _run_from_crop_forage(cycle)
|
|
305
320
|
site_types = _run_from_siteType(site, cycle)
|
|
306
321
|
practices = _run_from_practices(cycle)
|
|
307
322
|
return [
|
|
@@ -3,9 +3,7 @@ Pre Checks Cache Sources
|
|
|
3
3
|
|
|
4
4
|
This model caches the sources of all Site models.
|
|
5
5
|
"""
|
|
6
|
-
from hestia_earth.models.
|
|
7
|
-
from hestia_earth.models.utils import CACHE_KEY, cached_value
|
|
8
|
-
from hestia_earth.models.utils.source import CACHE_SOURCES_KEY, find_sources
|
|
6
|
+
from hestia_earth.models.utils.cache_sources import cache_sources
|
|
9
7
|
|
|
10
8
|
REQUIREMENTS = {
|
|
11
9
|
"Site": {}
|
|
@@ -15,20 +13,4 @@ RETURNS = {
|
|
|
15
13
|
}
|
|
16
14
|
|
|
17
15
|
|
|
18
|
-
def
|
|
19
|
-
sources = find_sources()
|
|
20
|
-
debugValues(site, sources=';'.join([str(title) for title in sources.keys()]))
|
|
21
|
-
return sources
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def _should_run(site: dict):
|
|
25
|
-
has_cache = cached_value(site, CACHE_SOURCES_KEY)
|
|
26
|
-
return not bool(has_cache)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def run(site: dict):
|
|
30
|
-
should_run = _should_run(site)
|
|
31
|
-
return {
|
|
32
|
-
**site,
|
|
33
|
-
CACHE_KEY: cached_value(site) | {CACHE_SOURCES_KEY: _run(site)}
|
|
34
|
-
} if should_run else site
|
|
16
|
+
def run(site: dict): return cache_sources(site)
|
|
@@ -7,7 +7,7 @@ import sys
|
|
|
7
7
|
import datetime
|
|
8
8
|
from functools import reduce
|
|
9
9
|
import operator
|
|
10
|
-
from typing import Any, Union
|
|
10
|
+
from typing import Any, Callable, Union
|
|
11
11
|
from hestia_earth.schema import SchemaType
|
|
12
12
|
from hestia_earth.utils.api import download_hestia
|
|
13
13
|
from hestia_earth.utils.model import linked_node
|
|
@@ -198,3 +198,14 @@ def hectar_to_square_meter(value): return value * 10000
|
|
|
198
198
|
|
|
199
199
|
|
|
200
200
|
def square_meter_to_hectare(value): return value / 10000
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def split_on_condition(iterable: Iterable, condition: Callable):
|
|
204
|
+
"""
|
|
205
|
+
Split an iterable into two iterables of the same type based on whether or not each item satisfies a condition.
|
|
206
|
+
"""
|
|
207
|
+
def construct(iterator: Generator) -> Iterable:
|
|
208
|
+
return ''.join(iterable) if isinstance(iterable, str) else type(iterable)(iterator)
|
|
209
|
+
|
|
210
|
+
cond_true, cond_false = tee((condition(item), item) for item in iterable)
|
|
211
|
+
return construct(i for p, i in cond_true if p), construct(i for p, i in cond_false if not p)
|
|
@@ -107,10 +107,10 @@ def should_link_input_to_impact(cycle: dict):
|
|
|
107
107
|
def should_run(input: dict):
|
|
108
108
|
term = input.get('term', {})
|
|
109
109
|
return all([
|
|
110
|
-
not input.get('impactAssessment'),
|
|
111
110
|
_should_aggregate_input(term),
|
|
112
111
|
# make sure Input is not a Product as well or we might double-count emissions
|
|
113
112
|
find_term_match(cycle.get('products', []), term.get('@id'), None) is None,
|
|
113
|
+
not input.get('impactAssessment'),
|
|
114
114
|
# ignore inputs which are flagged as Product of the Cycle
|
|
115
115
|
not input.get('fromCycle', False),
|
|
116
116
|
not input.get('producedInCycle', False)
|
|
@@ -377,7 +377,7 @@ def get_P2O5_total(nodes: list) -> list:
|
|
|
377
377
|
return get_total_value(kg_P_nodes) + get_total_value_converted(kg_N_nodes + kg_nodes, 'phosphateContentAsP2O5')
|
|
378
378
|
|
|
379
379
|
|
|
380
|
-
def convert_to_nitrogen(node: dict, model: str,
|
|
380
|
+
def convert_to_nitrogen(node: dict, model: str, blank_nodes: list, **log_args):
|
|
381
381
|
def prop_value(input: dict):
|
|
382
382
|
value = get_node_property_value(model, input, 'nitrogenContent', default=None, **log_args)
|
|
383
383
|
return value or get_node_property_value(model, input, 'crudeProteinContent', default=0, **log_args) / 6.25
|
|
@@ -385,7 +385,7 @@ def convert_to_nitrogen(node: dict, model: str, term_id: str, blank_nodes: list,
|
|
|
385
385
|
values = [(i, prop_value(i)) for i in blank_nodes]
|
|
386
386
|
missing_nitrogen_property = [i.get('term', {}).get('@id') for i, p_value in values if not p_value]
|
|
387
387
|
|
|
388
|
-
debugValues(node, model=model,
|
|
388
|
+
debugValues(node, model=model,
|
|
389
389
|
missing_nitrogen_property=';'.join(set(missing_nitrogen_property)),
|
|
390
390
|
**log_args)
|
|
391
391
|
|
|
@@ -394,7 +394,7 @@ def convert_to_nitrogen(node: dict, model: str, term_id: str, blank_nodes: list,
|
|
|
394
394
|
]) if len(missing_nitrogen_property) == 0 else None
|
|
395
395
|
|
|
396
396
|
|
|
397
|
-
def convert_to_carbon(node: dict, model: str,
|
|
397
|
+
def convert_to_carbon(node: dict, model: str, blank_nodes: list, **log_args):
|
|
398
398
|
def prop_value(input: dict):
|
|
399
399
|
value = get_node_property_value(model, input, 'carbonContent', default=None, **log_args)
|
|
400
400
|
return value or \
|
|
@@ -403,7 +403,7 @@ def convert_to_carbon(node: dict, model: str, term_id: str, blank_nodes: list, *
|
|
|
403
403
|
values = [(i, prop_value(i)) for i in blank_nodes]
|
|
404
404
|
missing_carbon_property = [i.get('term', {}).get('@id') for i, p_value in values if not p_value]
|
|
405
405
|
|
|
406
|
-
debugValues(node, model=model,
|
|
406
|
+
debugValues(node, model=model,
|
|
407
407
|
missing_carbon_property=';'.join(missing_carbon_property),
|
|
408
408
|
**log_args)
|
|
409
409
|
|
|
@@ -1248,6 +1248,12 @@ def get_inputs_from_properties(input: dict, term_types: Union[TermTermType, List
|
|
|
1248
1248
|
return filter_list_term_type(inputs, term_types)
|
|
1249
1249
|
|
|
1250
1250
|
|
|
1251
|
+
def _has_unique_key(nodes: list, key: str): return len(set([n.get(key) for n in nodes])) == 1
|
|
1252
|
+
|
|
1253
|
+
|
|
1254
|
+
def _same_dates(nodes: list): return all([_has_unique_key(nodes, 'startDate'), _has_unique_key(nodes, 'endDate')])
|
|
1255
|
+
|
|
1256
|
+
|
|
1251
1257
|
def _should_group_node(node: dict): return node.get('startDate') and node.get('endDate')
|
|
1252
1258
|
|
|
1253
1259
|
|
|
@@ -1281,19 +1287,21 @@ def _group_nodes_by_consecutive_dates(nodes: list):
|
|
|
1281
1287
|
if group:
|
|
1282
1288
|
groups.append(group)
|
|
1283
1289
|
|
|
1284
|
-
|
|
1290
|
+
# if all nodes have a single startDate and endDate, then they are all the same
|
|
1291
|
+
return [nodes] if _same_dates(nodes) else groups
|
|
1292
|
+
|
|
1293
|
+
|
|
1294
|
+
def _sum_nodes_value(nodes: list):
|
|
1295
|
+
values = flatten([n.get('value', []) for n in nodes])
|
|
1296
|
+
is_boolean = all([isinstance(v, bool) for v in values])
|
|
1297
|
+
return values[0] if is_boolean else [list_sum(values)] if isinstance(nodes[0]['value'], list) else list_sum(values)
|
|
1285
1298
|
|
|
1286
1299
|
|
|
1287
1300
|
def _node_from_group(nodes: list):
|
|
1288
1301
|
# `nodes` contain list with consecutive dates
|
|
1289
|
-
# if all nodes have the same dates, sum up the values
|
|
1290
|
-
same_startDate = len(set([n.get('startDate') for n in nodes])) == 1
|
|
1291
|
-
same_endDate = len(set([n.get('endDate') for n in nodes])) == 1
|
|
1292
|
-
total_value = list_sum(flatten([n.get('value', []) for n in nodes]))
|
|
1293
1302
|
return nodes[0] if len(nodes) == 1 else (
|
|
1294
|
-
nodes
|
|
1295
|
-
|
|
1296
|
-
} if all([same_startDate, same_endDate])
|
|
1303
|
+
# if all nodes have the same dates, sum up the values
|
|
1304
|
+
nodes[0] | {'value': _sum_nodes_value(nodes)} if _same_dates(nodes)
|
|
1297
1305
|
else nodes[0] | {
|
|
1298
1306
|
'startDate': min(n.get('startDate') for n in nodes),
|
|
1299
1307
|
'endDate': max(n.get('endDate') for n in nodes)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from . import CACHE_KEY, cached_value
|
|
2
|
+
from .source import CACHE_SOURCES_KEY, find_sources
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def _run(): return {CACHE_SOURCES_KEY: find_sources()}
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _has_value(node: dict): return bool(cached_value(node, CACHE_SOURCES_KEY))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def cache_sources(node: dict):
|
|
12
|
+
return {
|
|
13
|
+
**node,
|
|
14
|
+
CACHE_KEY: cached_value(node) | _run()
|
|
15
|
+
} if not _has_value(node) else node
|
|
@@ -61,3 +61,8 @@ def valid_site_type(cycle: dict, include_permanent_pasture=False):
|
|
|
61
61
|
[SiteSiteType.PERMANENT_PASTURE.value] if include_permanent_pasture else []
|
|
62
62
|
)
|
|
63
63
|
return site_valid_site_type(cycle.get('site', {}), site_types)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def get_landCover_term_id(lookup_term: dict, **log_args) -> str:
|
|
67
|
+
value = get_lookup_value(lookup_term, 'landCoverTermId', **log_args)
|
|
68
|
+
return value.split(';')[0] if value else None
|
|
@@ -5,9 +5,11 @@ from hestia_earth.utils.model import linked_node
|
|
|
5
5
|
from . import _term_id, _include_methodModel
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
def _new_indicator(term, model=None, land_cover_id=None):
|
|
8
|
+
def _new_indicator(term, model=None, land_cover_id: str = None, previous_land_cover_id: str = None):
|
|
9
9
|
node = {'@type': SchemaType.INDICATOR.value}
|
|
10
10
|
node['term'] = linked_node(term if isinstance(term, dict) else download_hestia(_term_id(term)))
|
|
11
11
|
if land_cover_id:
|
|
12
12
|
node['landCover'] = linked_node(download_hestia(land_cover_id))
|
|
13
|
+
if previous_land_cover_id:
|
|
14
|
+
node['previousLandCover'] = linked_node(download_hestia(previous_land_cover_id))
|
|
13
15
|
return _include_methodModel(node, model)
|
hestia_earth/models/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
VERSION = '0.
|
|
1
|
+
VERSION = '0.65.1'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2019-
|
|
3
|
+
Copyright (c) 2019-2025 Harmonised Environmental Storage and Tracking of the Impacts of Agriculture (HESTIA) Project
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: hestia-earth-models
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.65.1
|
|
4
4
|
Summary: HESTIA's set of modules for filling gaps in the activity data using external datasets (e.g. populating soil properties with a geospatial dataset using provided coordinates) and internal lookups (e.g. populating machinery use from fuel use). Includes rules for when gaps should be filled versus not (e.g. never gap fill yield, gap fill crop residue if yield provided etc.).
|
|
5
5
|
Home-page: https://gitlab.com/hestia-earth/hestia-engine-models
|
|
6
6
|
Author: HESTIA Team
|
|
7
7
|
Author-email: guillaumeroyer.mail@gmail.com
|
|
8
|
-
License:
|
|
8
|
+
License: MIT
|
|
9
9
|
Platform: UNKNOWN
|
|
10
10
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.6
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
14
|
Requires-Dist: hestia-earth-schema==30.*
|
|
15
|
-
Requires-Dist: hestia-earth-utils>=0.13.
|
|
15
|
+
Requires-Dist: hestia-earth-utils>=0.13.12
|
|
16
16
|
Requires-Dist: python-dateutil>=2.8.1
|
|
17
17
|
Requires-Dist: CurrencyConverter==0.16.8
|
|
18
18
|
Requires-Dist: haversine>=2.7.0
|