hestia-earth-models 0.64.13__py3-none-any.whl → 0.65.0__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/materialAndSubstrate.py +158 -0
- hestia_earth/models/cycle/pre_checks/cache_sources.py +3 -25
- hestia_earth/models/cycle/product/economicValueShare.py +2 -2
- hestia_earth/models/environmentalFootprintV3/soilQualityIndexLandTransformation.py +11 -33
- 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 +275 -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 +21 -12
- hestia_earth/models/ipcc2019/ch4ToAirExcreta.py +1 -2
- 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/{landTransformationFromCropland20YearAverageInputsProduction.py → landTransformation100YearAverageInputsProduction.py} +5 -2
- hestia_earth/models/linkedImpactAssessment/{landTransformationFromCropland100YearAverageInputsProduction.py → landTransformation20YearAverageInputsProduction.py} +5 -2
- hestia_earth/models/linkedImpactAssessment/utils.py +69 -12
- hestia_earth/models/mocking/__init__.py +1 -1
- hestia_earth/models/mocking/search-results.json +1026 -1026
- 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/preload_requests.py +24 -4
- 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/constant.py +3 -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.13.dist-info → hestia_earth_models-0.65.0.dist-info}/METADATA +2 -2
- {hestia_earth_models-0.64.13.dist-info → hestia_earth_models-0.65.0.dist-info}/RECORD +81 -108
- tests/models/cml2001Baseline/test_abioticResourceDepletionMineralsAndMetals.py +1 -1
- tests/models/cycle/input/test_hestiaAggregatedData.py +5 -2
- tests/models/cycle/test_materialsAndSubstrate.py +49 -0
- 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/landTransformationFromForest100YearAverageInputsProduction.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.13.dist-info → hestia_earth_models-0.65.0.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.64.13.dist-info → hestia_earth_models-0.65.0.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.64.13.dist-info → hestia_earth_models-0.65.0.dist-info}/top_level.txt +0 -0
|
@@ -1,14 +1,16 @@
|
|
|
1
|
+
from numpy import recarray
|
|
1
2
|
from hestia_earth.schema import TermTermType
|
|
2
3
|
from hestia_earth.utils.api import download_hestia
|
|
3
4
|
from hestia_earth.utils.lookup import download_lookup, get_table_value, column_name, extract_grouped_data_closest_date
|
|
4
|
-
from hestia_earth.utils.tools import safe_parse_float
|
|
5
|
-
from numpy import recarray
|
|
5
|
+
from hestia_earth.utils.tools import safe_parse_float, flatten
|
|
6
6
|
|
|
7
|
-
from hestia_earth.models.log import logger, debugMissingLookup
|
|
7
|
+
from hestia_earth.models.log import logger, debugMissingLookup, logRequirements, logShouldRun, debugValues
|
|
8
8
|
from hestia_earth.models.utils.animalProduct import (
|
|
9
9
|
FAO_LOOKUP_COLUMN, FAO_EQUIVALENT_LOOKUP_COLUMN, get_animalProduct_lookup_value
|
|
10
10
|
)
|
|
11
11
|
from hestia_earth.models.utils.product import convert_product_to_unit
|
|
12
|
+
from hestia_earth.models.utils.impact_assessment import get_country_id, impact_end_year
|
|
13
|
+
from hestia_earth.models.utils.indicator import _new_indicator
|
|
12
14
|
from . import MODEL
|
|
13
15
|
|
|
14
16
|
LOOKUP_PREFIX = f"{TermTermType.REGION.value}-{TermTermType.ANIMALPRODUCT.value}-{FAO_LOOKUP_COLUMN}"
|
|
@@ -140,3 +142,45 @@ def get_change_in_harvested_area_for_crop(country_id: str, crop_name: str, start
|
|
|
140
142
|
return _split_delta(
|
|
141
143
|
get_table_value(lookup, 'termid', country_id, column_name(crop_name)), start_year, end_year
|
|
142
144
|
)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def should_run_landTransformationFromCropland(term_id: str, impact: dict):
|
|
148
|
+
indicators = [
|
|
149
|
+
i for i in impact.get('emissionsResourceUse', [])
|
|
150
|
+
if all([
|
|
151
|
+
i.get('term', {}).get('@id') == term_id,
|
|
152
|
+
i.get('previousLandCover', {}).get('@id') == 'cropland',
|
|
153
|
+
i.get('value', -1) > 0
|
|
154
|
+
])
|
|
155
|
+
]
|
|
156
|
+
has_cropland = bool(indicators)
|
|
157
|
+
|
|
158
|
+
should_run = all([has_cropland])
|
|
159
|
+
logRequirements(impact, model=MODEL, term=term_id,
|
|
160
|
+
has_cropland_indicators=has_cropland)
|
|
161
|
+
logShouldRun(impact, MODEL, term_id, should_run)
|
|
162
|
+
|
|
163
|
+
return should_run, indicators
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def run_landTransformationFromCropland(term_id: str, impact: dict, indicators: list, years: int):
|
|
167
|
+
country_id = get_country_id(impact)
|
|
168
|
+
end_year = impact_end_year(impact)
|
|
169
|
+
total, permanent, temporary = get_cropland_ratio(country_id, end_year - years, end_year)
|
|
170
|
+
|
|
171
|
+
debugValues(impact, model=MODEL, term_id=term_id,
|
|
172
|
+
diff_temporary_area=temporary,
|
|
173
|
+
diff_permanent_area=permanent,
|
|
174
|
+
diff_total_area=total)
|
|
175
|
+
|
|
176
|
+
return flatten([
|
|
177
|
+
[
|
|
178
|
+
_new_indicator(term_id, MODEL, indicator.get('landCover', {}).get('@id'), 'annualCropland') | {
|
|
179
|
+
'value': indicator.get('value') * temporary / total
|
|
180
|
+
},
|
|
181
|
+
_new_indicator(term_id, MODEL, indicator.get('landCover', {}).get('@id'), 'permanentCropland') | {
|
|
182
|
+
'value': indicator.get('value') * permanent / total
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
for indicator in indicators
|
|
186
|
+
]) if total is not None else []
|
|
@@ -198,14 +198,14 @@ def _estimate_maximum_forest_change(
|
|
|
198
198
|
pasture_change=pasture_change,
|
|
199
199
|
total_cropland_change=total_cropland_change
|
|
200
200
|
) if not positive_change else (
|
|
201
|
-
total_agricultural_change
|
|
201
|
+
-total_agricultural_change
|
|
202
202
|
if -min(forest_change, 0) > total_agricultural_change else
|
|
203
203
|
min(forest_change, 0)
|
|
204
204
|
)
|
|
205
205
|
|
|
206
206
|
|
|
207
207
|
def _negative_agricultural_land_change(forest_change, pasture_change, total_cropland_change):
|
|
208
|
-
return pasture_change if 0 < pasture_change < -min(forest_change, 0) \
|
|
208
|
+
return -pasture_change if 0 < pasture_change < -min(forest_change, 0) \
|
|
209
209
|
else min(forest_change, 0) if pasture_change > 0 \
|
|
210
210
|
else -total_cropland_change if 0 < total_cropland_change < -min(forest_change, 0) \
|
|
211
211
|
else min(forest_change, 0) if 0 < total_cropland_change \
|
|
@@ -432,7 +432,7 @@ def _run_make_management_nodes(existing_nodes: list, percentage_transformed_from
|
|
|
432
432
|
LAND_USE_TERMS_FOR_TRANSFORMATION[land_type], f"{start_year}-01-01", f"{start_year}-12-31"
|
|
433
433
|
),
|
|
434
434
|
"land_type": land_type,
|
|
435
|
-
"percentage": 0
|
|
435
|
+
"percentage": 0 if ratio == -0.0 else to_precision(
|
|
436
436
|
number=ratio * 100,
|
|
437
437
|
digits=OUTPUT_SIGNIFICANT_DIGITS
|
|
438
438
|
)
|
|
@@ -462,7 +462,7 @@ def get_ratio_of_expanded_area(country_id: str, fao_name: str, end_year: int) ->
|
|
|
462
462
|
faostat_name=fao_name
|
|
463
463
|
)
|
|
464
464
|
return 0.0 if any([expansion is None, end_value is None]) else max(
|
|
465
|
-
0.0, _safe_divide(numerator=expansion, denominator=
|
|
465
|
+
0.0, _safe_divide(numerator=expansion, denominator=end_value)
|
|
466
466
|
)
|
|
467
467
|
|
|
468
468
|
|
|
@@ -619,7 +619,7 @@ def _should_run_historical_land_use_change_single_crop(
|
|
|
619
619
|
other_land_loss_to_pasture=other_land_loss_to[PERMANENT_PASTURE]
|
|
620
620
|
)
|
|
621
621
|
|
|
622
|
-
#
|
|
622
|
+
# C14-G14
|
|
623
623
|
shares_of_expansion = _get_shares_of_expansion(
|
|
624
624
|
land_use_type=land_use_type,
|
|
625
625
|
percent_annual_cropland_was=percent_annual_cropland_was,
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Seed Emissions
|
|
3
|
+
|
|
4
|
+
This model uses the `emissions` recalculated from the current `Cycle` to estimate the `emissions` associated with
|
|
5
|
+
producing the `Input` with `termType` = `seed`.
|
|
6
|
+
|
|
7
|
+
These are the steps:
|
|
8
|
+
|
|
9
|
+
1. Recalculate all emissions for the Cycle of interest;
|
|
10
|
+
2. Group Cycle emissions based on their `inputProductionGroupId` lookup value and sum them up;
|
|
11
|
+
3. Divide the sum of each emission group by the average crop yield (from FAOSTAT) to get emissions per kg of product;
|
|
12
|
+
4. Multiply by `seed.value` to get total background `emissions` from seed production per ha.
|
|
13
|
+
"""
|
|
14
|
+
from functools import reduce
|
|
15
|
+
from hestia_earth.schema import TermTermType, EmissionMethodTier, SiteSiteType
|
|
16
|
+
from hestia_earth.utils.lookup import download_lookup, column_name, get_table_value, extract_grouped_data_closest_date
|
|
17
|
+
from hestia_earth.utils.model import filter_list_term_type
|
|
18
|
+
from hestia_earth.utils.tools import non_empty_list, flatten, list_sum, safe_parse_float
|
|
19
|
+
from hestia_earth.utils.emission import cycle_emissions_in_system_boundary
|
|
20
|
+
|
|
21
|
+
from hestia_earth.models.log import logRequirements, logShouldRun, log_as_table
|
|
22
|
+
from hestia_earth.models.utils.emission import _new_emission
|
|
23
|
+
from hestia_earth.models.utils.site import valid_site_type
|
|
24
|
+
from hestia_earth.models.utils.cycle import cycle_end_year
|
|
25
|
+
from hestia_earth.models.utils.crop import get_crop_grouping_faostat_production, get_landCover_term_id
|
|
26
|
+
from hestia_earth.models.utils.completeness import _is_term_type_complete
|
|
27
|
+
from hestia_earth.models.utils.blank_node import get_lookup_value
|
|
28
|
+
from . import MODEL
|
|
29
|
+
|
|
30
|
+
REQUIREMENTS = {
|
|
31
|
+
"Cycle": {
|
|
32
|
+
"completeness.product": "True",
|
|
33
|
+
"endDate": "",
|
|
34
|
+
"inputs": [{
|
|
35
|
+
"@type": "Input",
|
|
36
|
+
"term.termType": "seed",
|
|
37
|
+
"value": "> 0",
|
|
38
|
+
"none": {
|
|
39
|
+
"impactAssessment": "",
|
|
40
|
+
"fromCycle": "True",
|
|
41
|
+
"producedInCycle": "True"
|
|
42
|
+
}
|
|
43
|
+
}],
|
|
44
|
+
"products": [{
|
|
45
|
+
"@type": "Product",
|
|
46
|
+
"term.termType": "crop",
|
|
47
|
+
"optional": {
|
|
48
|
+
"economicValueShare": "> 0"
|
|
49
|
+
}
|
|
50
|
+
}],
|
|
51
|
+
"site": {
|
|
52
|
+
"@type": "Site",
|
|
53
|
+
"siteType": ["cropland", "glass or high accessible cover"],
|
|
54
|
+
"country": {"@type": "Term", "termType": "region"}
|
|
55
|
+
},
|
|
56
|
+
"emissions": [{"@type": "Emission"}]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
RETURNS = {
|
|
60
|
+
"Emission": [{
|
|
61
|
+
"value": "",
|
|
62
|
+
"inputs": "",
|
|
63
|
+
"methodTier": "background"
|
|
64
|
+
}]
|
|
65
|
+
}
|
|
66
|
+
LOOKUPS = {
|
|
67
|
+
"region-crop-cropGroupingFaostatProduction-yield": "value from cropGroupingFaostatProduction and country",
|
|
68
|
+
"crop": [
|
|
69
|
+
"correspondingSeedTermIds",
|
|
70
|
+
"cropGroupingFaostatProduction",
|
|
71
|
+
"global_economic_value_share",
|
|
72
|
+
"landCoverTermId"
|
|
73
|
+
],
|
|
74
|
+
"emission": "inputProductionGroupId"
|
|
75
|
+
}
|
|
76
|
+
MODEL_KEY = 'seed_emissions'
|
|
77
|
+
TIER = EmissionMethodTier.BACKGROUND.value
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _emission(term_id: str, value: float, input: dict):
|
|
81
|
+
emission = _new_emission(term_id, MODEL)
|
|
82
|
+
emission['value'] = [round(value, 7)]
|
|
83
|
+
emission['inputs'] = [input]
|
|
84
|
+
emission['methodTier'] = TIER
|
|
85
|
+
return emission
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _run(cycle: dict, economicValueShare: float, total_yield: float, seed_input: dict, grouped_emissions: dict):
|
|
89
|
+
term = seed_input.get('term', {})
|
|
90
|
+
seed_value = list_sum(seed_input.get('value'))
|
|
91
|
+
return [
|
|
92
|
+
_emission(term_id, emission_value * economicValueShare / 100 / total_yield * seed_value, term)
|
|
93
|
+
for term_id, emission_value in grouped_emissions.items()
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _filter_emissions(cycle: dict):
|
|
98
|
+
required_emission_term_ids = cycle_emissions_in_system_boundary(cycle)
|
|
99
|
+
|
|
100
|
+
emissions = [
|
|
101
|
+
{
|
|
102
|
+
'id': i.get('term', {}).get('@id'),
|
|
103
|
+
'group-id': get_lookup_value(i.get('term', {}), LOOKUPS['emission'], model=MODEL, model_key=MODEL_KEY),
|
|
104
|
+
'value': list_sum(i.get('value'), 0)
|
|
105
|
+
}
|
|
106
|
+
for i in cycle.get('emissions', [])
|
|
107
|
+
if all([
|
|
108
|
+
i.get('term', {}).get('@id') in required_emission_term_ids,
|
|
109
|
+
list_sum(i.get('value'), 0) > 0
|
|
110
|
+
])
|
|
111
|
+
]
|
|
112
|
+
emission_ids = set([v.get('id') for v in emissions])
|
|
113
|
+
group_ids = set([v.get('group-id') for v in emissions if v.get('group-id')])
|
|
114
|
+
|
|
115
|
+
# for each group, get the list of all required emissions
|
|
116
|
+
lookup = download_lookup('emission.csv')
|
|
117
|
+
emissions_per_group = [
|
|
118
|
+
{
|
|
119
|
+
'id': group_id,
|
|
120
|
+
'emissions': list(filter(
|
|
121
|
+
lambda id: id in required_emission_term_ids,
|
|
122
|
+
list(lookup[lookup[column_name('inputProductionGroupId')] == group_id].termid)
|
|
123
|
+
))
|
|
124
|
+
}
|
|
125
|
+
for group_id in group_ids
|
|
126
|
+
]
|
|
127
|
+
emissions_per_group = [
|
|
128
|
+
{
|
|
129
|
+
'id': group.get('id'),
|
|
130
|
+
'total-emissions': len(group.get('emissions', [])),
|
|
131
|
+
'included-emissions': len([v in emission_ids for v in group.get('emissions', [])]),
|
|
132
|
+
'missing-emissions': '-'.join([v for v in group.get('emissions', []) if v not in emission_ids])
|
|
133
|
+
}
|
|
134
|
+
for group in emissions_per_group
|
|
135
|
+
]
|
|
136
|
+
# only keep groups that have all emissions present in the Cycle
|
|
137
|
+
valid_groups = list(filter(
|
|
138
|
+
lambda group: group.get('total-emissions') == group.get('included-emissions'),
|
|
139
|
+
emissions_per_group
|
|
140
|
+
))
|
|
141
|
+
valid_group_ids = set([v.get('id') for v in valid_groups])
|
|
142
|
+
|
|
143
|
+
# finally, only return emissions which groups are valid
|
|
144
|
+
return list(filter(
|
|
145
|
+
lambda emission: emission.get('group-id') in valid_group_ids,
|
|
146
|
+
emissions
|
|
147
|
+
)), emissions_per_group
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _evs(product: dict):
|
|
151
|
+
return safe_parse_float(
|
|
152
|
+
get_lookup_value(product.get('term', {}), 'global_economic_value_share', model=MODEL, model_key=MODEL_KEY)
|
|
153
|
+
) or product.get('economicValueShare')
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _yield(country_id: str, end_year: int, product: dict):
|
|
157
|
+
grouping = get_crop_grouping_faostat_production(MODEL, product.get('term', {}))
|
|
158
|
+
return safe_parse_float(extract_grouped_data_closest_date(get_table_value(
|
|
159
|
+
download_lookup('region-crop-cropGroupingFaostatProduction-yield.csv'),
|
|
160
|
+
'termid',
|
|
161
|
+
country_id,
|
|
162
|
+
column_name(grouping)
|
|
163
|
+
), end_year)) or list_sum(product.get('value'))
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _group_seed_inputs(inputs: list):
|
|
167
|
+
def _group_by(group: dict, input: dict):
|
|
168
|
+
term_id = input.get('term', {}).get('@id')
|
|
169
|
+
group[term_id] = group.get(term_id, []) + [input]
|
|
170
|
+
return group
|
|
171
|
+
|
|
172
|
+
grouped_inputs = reduce(_group_by, inputs, {})
|
|
173
|
+
return [
|
|
174
|
+
inputs[0] | {'value': flatten([v.get('value') for v in inputs])}
|
|
175
|
+
for inputs in grouped_inputs.values()
|
|
176
|
+
]
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _should_run(cycle: dict):
|
|
180
|
+
crop_products = filter_list_term_type(cycle.get('products', []), TermTermType.CROP)
|
|
181
|
+
site_type_valid = valid_site_type(cycle.get('site', {}), [
|
|
182
|
+
SiteSiteType.CROPLAND.value, SiteSiteType.GLASS_OR_HIGH_ACCESSIBLE_COVER.value
|
|
183
|
+
])
|
|
184
|
+
is_product_complete = _is_term_type_complete(cycle, 'product')
|
|
185
|
+
end_year = cycle_end_year(cycle)
|
|
186
|
+
country_id = cycle.get('site', {}).get('country', {}).get('@id')
|
|
187
|
+
|
|
188
|
+
# only keep the crop products that map to a seed
|
|
189
|
+
crop_products = [
|
|
190
|
+
{
|
|
191
|
+
'product': product.get('term', {}).get('@id'),
|
|
192
|
+
'seed-id': get_lookup_value(
|
|
193
|
+
product.get('term', {}), 'correspondingSeedTermIds', model=MODEL, key=MODEL_KEY),
|
|
194
|
+
'economicValueShare': _evs(product),
|
|
195
|
+
'yield': _yield(country_id, end_year, product),
|
|
196
|
+
'landCover-id': get_landCover_term_id(product.get('term', {}), model=MODEL, key=MODEL_KEY)
|
|
197
|
+
}
|
|
198
|
+
for product in crop_products
|
|
199
|
+
]
|
|
200
|
+
valid_crop_products = [
|
|
201
|
+
value for value in crop_products if all([
|
|
202
|
+
value.get('seed-id'),
|
|
203
|
+
value.get('economicValueShare'),
|
|
204
|
+
value.get('yield'),
|
|
205
|
+
value.get('landCover-id'),
|
|
206
|
+
])
|
|
207
|
+
]
|
|
208
|
+
|
|
209
|
+
# array of ; delimited values
|
|
210
|
+
seed_term_ids = list(set(flatten([v.get('seed-id').split(';') for v in valid_crop_products if v.get('seed-id')])))
|
|
211
|
+
|
|
212
|
+
seed_inputs = [
|
|
213
|
+
i
|
|
214
|
+
for i in cycle.get('inputs', [])
|
|
215
|
+
if all([
|
|
216
|
+
i.get('term', {}).get('termType') == TermTermType.SEED.value,
|
|
217
|
+
i.get('term', {}).get('@id') in seed_term_ids,
|
|
218
|
+
list_sum(i.get('value'), 0) > 0,
|
|
219
|
+
not i.get('impactAssessment'),
|
|
220
|
+
# ignore inputs which are flagged as Product of the Cycle
|
|
221
|
+
not i.get('fromCycle', False),
|
|
222
|
+
not i.get('producedInCycle', False)
|
|
223
|
+
])
|
|
224
|
+
]
|
|
225
|
+
# sum up seed inputs with the same id
|
|
226
|
+
seed_inputs = _group_seed_inputs(seed_inputs)
|
|
227
|
+
|
|
228
|
+
crop_land_cover_ids = list(set([p.get('landCover-id') for p in valid_crop_products]))
|
|
229
|
+
total_economicValueShare = list_sum([p.get('economicValueShare') for p in valid_crop_products])
|
|
230
|
+
total_yield = list_sum([p.get('yield') for p in valid_crop_products])
|
|
231
|
+
|
|
232
|
+
emissions, emissions_per_group = _filter_emissions(cycle)
|
|
233
|
+
# group emissions with the same group-id
|
|
234
|
+
grouped_emissions = reduce(
|
|
235
|
+
lambda p, c: p | {c.get('group-id'): p.get(c.get('group-id'), 0) + c.get('value', 0)},
|
|
236
|
+
emissions,
|
|
237
|
+
{}
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
should_run = all([
|
|
241
|
+
site_type_valid,
|
|
242
|
+
len(crop_land_cover_ids) <= 1,
|
|
243
|
+
is_product_complete,
|
|
244
|
+
total_economicValueShare,
|
|
245
|
+
total_yield,
|
|
246
|
+
bool(seed_inputs),
|
|
247
|
+
bool(emissions)
|
|
248
|
+
])
|
|
249
|
+
|
|
250
|
+
for seed_input in seed_inputs:
|
|
251
|
+
term_id = seed_input.get('term', {}).get('@id')
|
|
252
|
+
|
|
253
|
+
logRequirements(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
|
|
254
|
+
site_type_valid=site_type_valid,
|
|
255
|
+
crop_products=log_as_table(crop_products),
|
|
256
|
+
crop_land_cover_ids=';'.join(crop_land_cover_ids),
|
|
257
|
+
is_term_type_product_complete=is_product_complete,
|
|
258
|
+
total_economicValueShare=total_economicValueShare,
|
|
259
|
+
total_yield=total_yield,
|
|
260
|
+
end_year=end_year,
|
|
261
|
+
country_id=country_id,
|
|
262
|
+
emissions=log_as_table(emissions),
|
|
263
|
+
emissions_per_group=log_as_table(emissions_per_group))
|
|
264
|
+
|
|
265
|
+
logShouldRun(cycle, MODEL, term_id, should_run, key=MODEL_KEY)
|
|
266
|
+
|
|
267
|
+
return should_run, total_economicValueShare, total_yield, seed_inputs, grouped_emissions
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def run(cycle: dict):
|
|
271
|
+
should_run, economicValueShare, total_yield, seed_inputs, grouped_emissions = _should_run(cycle)
|
|
272
|
+
return flatten(non_empty_list([
|
|
273
|
+
_run(cycle, economicValueShare, total_yield, seed_input, grouped_emissions)
|
|
274
|
+
for seed_input in seed_inputs
|
|
275
|
+
])) if should_run else []
|
|
@@ -22,7 +22,7 @@ from hestia_earth.models.utils.measurement import _new_measurement
|
|
|
22
22
|
|
|
23
23
|
from . import MODEL
|
|
24
24
|
from .biomass_utils import (
|
|
25
|
-
BiomassCategory,
|
|
25
|
+
BiomassCategory, get_valid_management_nodes, detect_land_cover_change, group_by_biomass_category, group_by_term_id,
|
|
26
26
|
sample_biomass_equilibrium, summarise_land_cover_nodes
|
|
27
27
|
)
|
|
28
28
|
|
|
@@ -152,7 +152,7 @@ def _should_run(site: dict) -> tuple[bool, dict, dict]:
|
|
|
152
152
|
site_type = site.get("siteType")
|
|
153
153
|
eco_climate_zone = get_eco_climate_zone_value(site, as_enum=True)
|
|
154
154
|
|
|
155
|
-
land_cover =
|
|
155
|
+
land_cover = get_valid_management_nodes(site)
|
|
156
156
|
|
|
157
157
|
has_valid_site_type = site_type not in _EXCLUDED_SITE_TYPES
|
|
158
158
|
has_valid_eco_climate_zone = all([
|
|
@@ -22,7 +22,7 @@ from hestia_earth.models.utils.measurement import _new_measurement
|
|
|
22
22
|
|
|
23
23
|
from . import MODEL
|
|
24
24
|
from .biomass_utils import (
|
|
25
|
-
BiomassCategory,
|
|
25
|
+
BiomassCategory, get_valid_management_nodes, detect_land_cover_change, group_by_biomass_category,
|
|
26
26
|
sample_biomass_equilibrium, summarise_land_cover_nodes
|
|
27
27
|
)
|
|
28
28
|
|
|
@@ -70,12 +70,16 @@ RETURNS = {
|
|
|
70
70
|
"statsDefinition": "simulated",
|
|
71
71
|
"observations": "",
|
|
72
72
|
"dates": "",
|
|
73
|
+
"depthUpper": "0",
|
|
74
|
+
"depthLower": "30",
|
|
73
75
|
"methodClassification": "tier 1 model"
|
|
74
76
|
}]
|
|
75
77
|
}
|
|
76
78
|
TERM_ID = 'belowGroundBiomass'
|
|
77
79
|
|
|
78
80
|
_ITERATIONS = 10000
|
|
81
|
+
_DEPTH_UPPER = 0
|
|
82
|
+
_DEPTH_LOWER = 30
|
|
79
83
|
_METHOD_CLASSIFICATION = MeasurementMethodClassification.TIER_1_MODEL.value
|
|
80
84
|
_STATS_DEFINITION = MeasurementStatsDefinition.SIMULATED.value
|
|
81
85
|
|
|
@@ -145,7 +149,7 @@ def _should_run(site: dict) -> tuple[bool, dict, dict]:
|
|
|
145
149
|
site_type = site.get("siteType")
|
|
146
150
|
eco_climate_zone = get_eco_climate_zone_value(site, as_enum=True)
|
|
147
151
|
|
|
148
|
-
land_cover =
|
|
152
|
+
land_cover = get_valid_management_nodes(site)
|
|
149
153
|
|
|
150
154
|
has_valid_site_type = site_type not in _EXCLUDED_SITE_TYPES
|
|
151
155
|
has_valid_eco_climate_zone = all([
|
|
@@ -522,4 +526,6 @@ def _measurement(
|
|
|
522
526
|
measurement = _new_measurement(TERM_ID) | {
|
|
523
527
|
key: value for key, value in update_dict.items() if value
|
|
524
528
|
}
|
|
529
|
+
measurement["depthUpper"] = _DEPTH_UPPER
|
|
530
|
+
measurement["depthLower"] = _DEPTH_LOWER
|
|
525
531
|
return measurement
|
|
@@ -10,9 +10,9 @@ from hestia_earth.utils.blank_node import get_node_value
|
|
|
10
10
|
from hestia_earth.utils.model import filter_list_term_type
|
|
11
11
|
|
|
12
12
|
from hestia_earth.models.utils.array_builders import repeat_single, truncated_normal_1d
|
|
13
|
-
from hestia_earth.models.utils.blank_node import validate_start_date_end_date
|
|
13
|
+
from hestia_earth.models.utils.blank_node import node_term_match, validate_start_date_end_date
|
|
14
14
|
from hestia_earth.models.utils.ecoClimateZone import EcoClimateZone, get_ecoClimateZone_lookup_grouped_value
|
|
15
|
-
from hestia_earth.models.utils.term import get_lookup_value
|
|
15
|
+
from hestia_earth.models.utils.term import get_cover_crop_property_terms, get_lookup_value
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
LOOKUPS = {
|
|
@@ -409,9 +409,16 @@ _KWARGS_TO_SAMPLE_FUNC = {
|
|
|
409
409
|
}
|
|
410
410
|
|
|
411
411
|
|
|
412
|
-
def
|
|
412
|
+
def get_valid_management_nodes(site: dict) -> list[dict]:
|
|
413
413
|
"""Retrieve valid `landCover` nodes from a site's management."""
|
|
414
|
+
COVER_CROP_TERM_IDS = get_cover_crop_property_terms()
|
|
414
415
|
return [
|
|
415
416
|
node for node in filter_list_term_type(site.get("management", []), TermTermType.LANDCOVER)
|
|
416
|
-
if
|
|
417
|
+
if (
|
|
418
|
+
validate_start_date_end_date(node)
|
|
419
|
+
and not any(
|
|
420
|
+
prop.get("value", False) for prop in node.get("properties", [])
|
|
421
|
+
if node_term_match(prop, COVER_CROP_TERM_IDS)
|
|
422
|
+
)
|
|
423
|
+
)
|
|
417
424
|
]
|
|
@@ -3,7 +3,7 @@ from hestia_earth.utils.lookup import column_name, download_lookup, get_table_va
|
|
|
3
3
|
from hestia_earth.utils.model import find_primary_product, find_term_match
|
|
4
4
|
from hestia_earth.utils.tools import list_sum, safe_parse_float
|
|
5
5
|
|
|
6
|
-
from hestia_earth.models.log import debugMissingLookup, debugValues, logRequirements, logShouldRun
|
|
6
|
+
from hestia_earth.models.log import debugMissingLookup, debugValues, logRequirements, logShouldRun, log_as_table
|
|
7
7
|
from hestia_earth.models.utils.blank_node import get_total_value_converted_with_min_ratio
|
|
8
8
|
from hestia_earth.models.utils.input import get_feed_inputs
|
|
9
9
|
from hestia_earth.models.utils.emission import _new_emission
|
|
@@ -103,13 +103,18 @@ def _emission(value: float, sd: float = None, min: float = None, max: float = No
|
|
|
103
103
|
return emission
|
|
104
104
|
|
|
105
105
|
|
|
106
|
-
def _run(feed: float, enteric_factor: float = None, enteric_sd: float = None, default_values=
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
106
|
+
def _run(feed: float, enteric_factor: float = None, enteric_sd: float = None, default_values: dict = {}):
|
|
107
|
+
default_value = default_values.get('value')
|
|
108
|
+
value = (feed * ((enteric_factor or default_value) / 100)) / METHANE_EC
|
|
109
|
+
min = (feed * (default_values.get('min') / 100)) / METHANE_EC if all([
|
|
110
|
+
enteric_factor is None, default_values.get('min')
|
|
111
|
+
]) else None
|
|
112
|
+
max = (feed * (default_values.get('max') / 100)) / METHANE_EC if all([
|
|
113
|
+
enteric_factor is None, default_values.get('max')
|
|
114
|
+
]) else None
|
|
115
|
+
description = f"Average Ym factor of {default_value}% used as data missing to differentiate Ym." if all([
|
|
111
116
|
enteric_factor is None,
|
|
112
|
-
|
|
117
|
+
default_value is not None
|
|
113
118
|
]) else None
|
|
114
119
|
return [
|
|
115
120
|
_emission(value, enteric_sd, min, max, description)
|
|
@@ -141,10 +146,10 @@ DE_MAPPING = {
|
|
|
141
146
|
def _get_grouped_data_key(keys: list, DE: float, NDF: float, ionophore: bool, milk_yield: float):
|
|
142
147
|
# test conditions one by one and return the key associated for the first one that passes
|
|
143
148
|
return (
|
|
144
|
-
next(
|
|
149
|
+
(next(
|
|
145
150
|
(key for key in keys if key in DE_NDF_MAPPING and DE_NDF_MAPPING[key](DE, NDF)),
|
|
146
151
|
None
|
|
147
|
-
) or next(
|
|
152
|
+
) if all([DE is not None, NDF is not None]) else None) or next(
|
|
148
153
|
(key for key in keys if key in DE_MAPPING and DE_MAPPING[key](DE, ionophore)),
|
|
149
154
|
None
|
|
150
155
|
) if DE else None
|
|
@@ -204,7 +209,11 @@ def _get_default_values(lookup, term: dict):
|
|
|
204
209
|
value = get_table_value(lookup, 'termid', term_id, column_name(LOOKUPS['liveAnimal'][3])) if term_id else None
|
|
205
210
|
min = get_table_value(lookup, 'termid', term_id, column_name(LOOKUPS['liveAnimal'][4])) if term_id else None
|
|
206
211
|
max = get_table_value(lookup, 'termid', term_id, column_name(LOOKUPS['liveAnimal'][5])) if term_id else None
|
|
207
|
-
return
|
|
212
|
+
return {
|
|
213
|
+
'value': safe_parse_float(value, None),
|
|
214
|
+
'min': safe_parse_float(min, None),
|
|
215
|
+
'max': safe_parse_float(max, None)
|
|
216
|
+
}
|
|
208
217
|
|
|
209
218
|
|
|
210
219
|
def _should_run(cycle: dict):
|
|
@@ -250,7 +259,7 @@ def _should_run(cycle: dict):
|
|
|
250
259
|
milk_yield=milk_yield,
|
|
251
260
|
enteric_factor=enteric_factor,
|
|
252
261
|
enteric_sd=enteric_sd,
|
|
253
|
-
default_values=
|
|
262
|
+
default_values=log_as_table(default_values))
|
|
254
263
|
|
|
255
264
|
logRequirements(cycle, model=MODEL, term=TERM_ID,
|
|
256
265
|
term_type_animalFeed_complete=is_animalFeed_complete,
|
|
@@ -259,7 +268,7 @@ def _should_run(cycle: dict):
|
|
|
259
268
|
|
|
260
269
|
should_run = all([
|
|
261
270
|
is_animalFeed_complete, is_freshForage_complete, total_feed,
|
|
262
|
-
enteric_factor or default_values
|
|
271
|
+
enteric_factor or default_values.get('value')
|
|
263
272
|
])
|
|
264
273
|
logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
|
|
265
274
|
return should_run, total_feed, enteric_factor, enteric_sd, default_values
|
|
@@ -6,7 +6,7 @@ from hestia_earth.utils.tools import safe_parse_float, list_sum
|
|
|
6
6
|
|
|
7
7
|
from hestia_earth.models.log import debugValues, logRequirements, debugMissingLookup, logShouldRun, log_as_table
|
|
8
8
|
from hestia_earth.models.utils import _filter_list_term_unit
|
|
9
|
-
from hestia_earth.models.utils.constant import Units
|
|
9
|
+
from hestia_earth.models.utils.constant import Units, DAYS_PER_MONTH
|
|
10
10
|
from hestia_earth.models.utils.completeness import _is_term_type_complete
|
|
11
11
|
from hestia_earth.models.utils.productivity import PRODUCTIVITY, get_productivity
|
|
12
12
|
from hestia_earth.models.utils.emission import _new_emission
|
|
@@ -40,7 +40,6 @@ RETURNS = {
|
|
|
40
40
|
}
|
|
41
41
|
TERM_ID = 'ch4ToAirExcreta'
|
|
42
42
|
TIER = EmissionMethodTier.TIER_2.value
|
|
43
|
-
DAYS_PER_MONTH = 365.25/12
|
|
44
43
|
|
|
45
44
|
|
|
46
45
|
class DURATION(Enum):
|
|
@@ -4,7 +4,7 @@ from hestia_earth.models.log import logRequirements, logShouldRun
|
|
|
4
4
|
from hestia_earth.models.utils.blank_node import cumulative_nodes_term_match
|
|
5
5
|
from hestia_earth.models.utils.emission import _new_emission
|
|
6
6
|
|
|
7
|
-
from .biomass_utils import detect_land_cover_change, summarise_land_cover_nodes
|
|
7
|
+
from .biomass_utils import detect_land_cover_change, get_valid_management_nodes, summarise_land_cover_nodes
|
|
8
8
|
from .co2ToAirCarbonStockChange_utils import create_run_function, create_should_run_function
|
|
9
9
|
from . import MODEL
|
|
10
10
|
|
|
@@ -133,6 +133,7 @@ def run(cycle: dict) -> list[dict]:
|
|
|
133
133
|
"""
|
|
134
134
|
should_run_exec = create_should_run_function(
|
|
135
135
|
carbon_stock_term_id=_CARBON_STOCK_TERM_ID,
|
|
136
|
+
get_valid_management_nodes_func=get_valid_management_nodes,
|
|
136
137
|
should_compile_inventory_func=_should_compile_inventory_func,
|
|
137
138
|
summarise_land_use_func=summarise_land_cover_nodes,
|
|
138
139
|
detect_land_use_change_func=detect_land_cover_change,
|
|
@@ -4,7 +4,7 @@ from hestia_earth.models.log import logRequirements, logShouldRun
|
|
|
4
4
|
from hestia_earth.models.utils.blank_node import cumulative_nodes_term_match
|
|
5
5
|
from hestia_earth.models.utils.emission import _new_emission
|
|
6
6
|
|
|
7
|
-
from .biomass_utils import detect_land_cover_change, summarise_land_cover_nodes
|
|
7
|
+
from .biomass_utils import detect_land_cover_change, get_valid_management_nodes, summarise_land_cover_nodes
|
|
8
8
|
from .co2ToAirCarbonStockChange_utils import create_run_function, create_should_run_function
|
|
9
9
|
from . import MODEL
|
|
10
10
|
|
|
@@ -125,6 +125,7 @@ def run(cycle: dict) -> list[dict]:
|
|
|
125
125
|
"""
|
|
126
126
|
should_run_exec = create_should_run_function(
|
|
127
127
|
carbon_stock_term_id=_CARBON_STOCK_TERM_ID,
|
|
128
|
+
get_valid_management_nodes_func=get_valid_management_nodes,
|
|
128
129
|
should_compile_inventory_func=_should_compile_inventory_func,
|
|
129
130
|
summarise_land_use_func=summarise_land_cover_nodes,
|
|
130
131
|
detect_land_use_change_func=detect_land_cover_change,
|
|
@@ -13,10 +13,9 @@ from pydash.objects import merge
|
|
|
13
13
|
from typing import Any, Callable, NamedTuple, Optional, Union
|
|
14
14
|
|
|
15
15
|
from hestia_earth.schema import (
|
|
16
|
-
EmissionMethodTier, EmissionStatsDefinition, MeasurementMethodClassification
|
|
16
|
+
EmissionMethodTier, EmissionStatsDefinition, MeasurementMethodClassification
|
|
17
17
|
)
|
|
18
18
|
from hestia_earth.utils.date import diff_in_days, YEAR
|
|
19
|
-
from hestia_earth.utils.model import filter_list_term_type
|
|
20
19
|
from hestia_earth.utils.tools import flatten, non_empty_list, safe_parse_date
|
|
21
20
|
|
|
22
21
|
from hestia_earth.models.log import log_as_table
|
|
@@ -24,7 +23,7 @@ from hestia_earth.models.utils import pairwise
|
|
|
24
23
|
from hestia_earth.models.utils.array_builders import correlated_normal_2d, gen_seed
|
|
25
24
|
from hestia_earth.models.utils.blank_node import (
|
|
26
25
|
_gapfill_datestr, _get_datestr_format, DatestrGapfillMode, DatestrFormat, group_nodes_by_year, node_term_match,
|
|
27
|
-
split_node_by_dates
|
|
26
|
+
split_node_by_dates
|
|
28
27
|
)
|
|
29
28
|
from hestia_earth.models.utils.constant import Units, get_atomic_conversion
|
|
30
29
|
from hestia_earth.models.utils.descriptive_stats import calc_descriptive_stats
|
|
@@ -327,6 +326,7 @@ def _add_carbon_stock_change_emissions(
|
|
|
327
326
|
def create_should_run_function(
|
|
328
327
|
*,
|
|
329
328
|
carbon_stock_term_id: str,
|
|
329
|
+
get_valid_management_nodes_func: Callable[[dict], list[dict]],
|
|
330
330
|
should_compile_inventory_func: Callable[[dict, list[dict], list[dict]], tuple[bool, dict]],
|
|
331
331
|
summarise_land_use_func: Callable[[list[dict]], Any],
|
|
332
332
|
detect_land_use_change_func: Callable[[Any, Any], bool],
|
|
@@ -351,6 +351,10 @@ def create_should_run_function(
|
|
|
351
351
|
`(site: dict, cycles: list[dict], carbon_stock_measurements: list[dict]) -> (should_run: bool, logs: dict)`, to
|
|
352
352
|
determine whether there is enough site and cycles data available to compile the carbon stock change inventory.
|
|
353
353
|
|
|
354
|
+
get_valid_management_nodes_func : Callable[[dict], list[dict]]
|
|
355
|
+
A function, with the signature... `(site: dict) -> management_nodes: list[dict]` to extract valid management
|
|
356
|
+
nodes from the site for building the land use inventory.
|
|
357
|
+
|
|
354
358
|
summarise_land_use_func: Callable[[list[dict]], Any]
|
|
355
359
|
A function with the signature `(nodes: list[dict]) -> Any`, to reduce a list of `landCover`
|
|
356
360
|
[Management](https://www.hestia.earth/schema/Management) nodes into a land use summary that can be compared
|
|
@@ -418,10 +422,7 @@ def create_should_run_function(
|
|
|
418
422
|
])
|
|
419
423
|
]
|
|
420
424
|
|
|
421
|
-
land_cover_nodes =
|
|
422
|
-
node for node in filter_list_term_type(site.get("management", []), TermTermType.LANDCOVER)
|
|
423
|
-
if validate_start_date_end_date(node)
|
|
424
|
-
]
|
|
425
|
+
land_cover_nodes = get_valid_management_nodes_func(site)
|
|
425
426
|
|
|
426
427
|
seed = gen_seed(site) # All cycles linked to the same site should be consistent
|
|
427
428
|
rng = random.default_rng(seed)
|