hestia-earth-models 0.70.1__py3-none-any.whl → 0.70.3__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.
- hestia_earth/models/cml2001Baseline/resourceUseMineralsAndMetalsDuringCycle.py +2 -1
- hestia_earth/models/config/Cycle.json +68 -0
- hestia_earth/models/config/Site.json +8 -0
- hestia_earth/models/cycle/practice/landCover.py +181 -0
- hestia_earth/models/emepEea2019/nh3ToAirExcreta.py +1 -1
- hestia_earth/models/hestia/excretaKgMass.py +1 -1
- hestia_earth/models/hestia/management.py +15 -113
- hestia_earth/models/hestia/pToSurfaceWaterAquacultureSystems.py +148 -0
- hestia_earth/models/hestia/soilMeasurement.py +1 -1
- hestia_earth/models/ipcc2019/ch4ToAirFloodedRice.py +8 -6
- hestia_earth/models/ipcc2019/ch4ToAirOrganicSoilCultivation.py +270 -0
- hestia_earth/models/ipcc2019/co2ToAirAboveGroundBiomassStockChange.py +0 -3
- hestia_earth/models/ipcc2019/co2ToAirBelowGroundBiomassStockChange.py +0 -3
- hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +57 -43
- hestia_earth/models/ipcc2019/co2ToAirLimeHydrolysis.py +7 -5
- hestia_earth/models/ipcc2019/co2ToAirOrganicSoilCultivation.py +215 -0
- hestia_earth/models/ipcc2019/co2ToAirSoilOrganicCarbonStockChange.py +0 -3
- hestia_earth/models/ipcc2019/n2OToAirOrganicSoilCultivationDirect.py +161 -0
- hestia_earth/models/ipcc2019/no3ToGroundwaterExcreta.py +1 -1
- hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_2.py +15 -4
- hestia_earth/models/ipcc2019/organicSoilCultivation_utils.py +159 -0
- hestia_earth/models/mocking/search-results.json +713 -705
- hestia_earth/models/pooreNemecek2018/excretaKgN.py +3 -1
- hestia_earth/models/site/grouped_measurement.py +132 -0
- hestia_earth/models/utils/__init__.py +4 -3
- hestia_earth/models/utils/blank_node.py +40 -11
- hestia_earth/models/utils/constant.py +26 -20
- hestia_earth/models/utils/excretaManagement.py +2 -2
- hestia_earth/models/utils/product.py +39 -1
- hestia_earth/models/utils/property.py +25 -12
- hestia_earth/models/version.py +1 -1
- {hestia_earth_models-0.70.1.dist-info → hestia_earth_models-0.70.3.dist-info}/METADATA +2 -2
- {hestia_earth_models-0.70.1.dist-info → hestia_earth_models-0.70.3.dist-info}/RECORD +49 -36
- tests/models/cycle/practice/test_landCover.py +27 -0
- tests/models/hestia/test_feedConversionRatio.py +2 -3
- tests/models/hestia/test_pToSurfaceWaterAquacultureSystems.py +56 -0
- tests/models/hestia/test_soilMeasurement.py +11 -19
- tests/models/ipcc2019/test_ch4ToAirEntericFermentation.py +4 -7
- tests/models/ipcc2019/test_ch4ToAirOrganicSoilCultivation.py +61 -0
- tests/models/ipcc2019/test_co2ToAirAboveGroundBiomassStockChange.py +11 -9
- tests/models/ipcc2019/test_co2ToAirBelowGroundBiomassStockChange.py +10 -8
- tests/models/ipcc2019/test_co2ToAirLimeHydrolysis.py +1 -1
- tests/models/ipcc2019/test_co2ToAirOrganicSoilCultivation.py +62 -0
- tests/models/ipcc2019/test_co2ToAirSoilOrganicCarbonStockChange.py +11 -9
- tests/models/ipcc2019/test_n2OToAirOrganicSoilCultivationDirect.py +61 -0
- tests/models/site/test_grouped_measurement.py +20 -0
- {hestia_earth_models-0.70.1.dist-info → hestia_earth_models-0.70.3.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.70.1.dist-info → hestia_earth_models-0.70.3.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.70.1.dist-info → hestia_earth_models-0.70.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,148 @@
|
|
1
|
+
from hestia_earth.schema import EmissionMethodTier, EmissionStatsDefinition, TermTermType
|
2
|
+
from hestia_earth.utils.model import filter_list_term_type
|
3
|
+
from hestia_earth.utils.tools import list_sum, non_empty_list
|
4
|
+
|
5
|
+
from hestia_earth.models.log import logRequirements, logShouldRun, debugValues, log_as_table
|
6
|
+
from hestia_earth.models.utils import _filter_list_term_unit
|
7
|
+
from hestia_earth.models.utils.emission import _new_emission
|
8
|
+
from hestia_earth.models.utils.constant import Units, convert_to_unit, get_atomic_conversion
|
9
|
+
from hestia_earth.models.utils.product import convert_product_to_unit
|
10
|
+
from hestia_earth.models.utils.completeness import _is_term_type_complete
|
11
|
+
from . import MODEL
|
12
|
+
|
13
|
+
REQUIREMENTS = {
|
14
|
+
"Cycle": {
|
15
|
+
"completeness.animalFeed": "True",
|
16
|
+
"completeness.product": "True",
|
17
|
+
"completeness.fertiliser": "True",
|
18
|
+
"completeness.liveAnimalInput": "True",
|
19
|
+
"inputs": [
|
20
|
+
{
|
21
|
+
"@type": "Input",
|
22
|
+
"term.termType": [
|
23
|
+
"crop",
|
24
|
+
"liveAnimal",
|
25
|
+
"liveAquaticSpecies",
|
26
|
+
"animalProduct",
|
27
|
+
"processedFood",
|
28
|
+
"feedFoodAdditive",
|
29
|
+
"organicFertiliser",
|
30
|
+
"forage",
|
31
|
+
"excreta",
|
32
|
+
"waste"
|
33
|
+
],
|
34
|
+
"optional": {
|
35
|
+
"properties": [
|
36
|
+
{"@type": "Property", "value": "", "term.@id": "phosphorusContentAsP"},
|
37
|
+
{"@type": "Property", "value": "", "term.@id": "phosphateContentAsP2O5"}
|
38
|
+
]
|
39
|
+
}
|
40
|
+
},
|
41
|
+
{
|
42
|
+
"@type": "Input",
|
43
|
+
"term.termType": "inorganicFertiliser",
|
44
|
+
"term.units": "kg P2O5"
|
45
|
+
}
|
46
|
+
],
|
47
|
+
"products": [{
|
48
|
+
"@type": "Product",
|
49
|
+
"term.termType": ["liveAquaticSpecies", "liveAnimal", "animalProduct", "crop"],
|
50
|
+
"optional": {
|
51
|
+
"properties": [
|
52
|
+
{"@type": "Property", "value": "", "term.@id": "phosphorusContentAsP"},
|
53
|
+
{"@type": "Property", "value": "", "term.@id": "phosphateContentAsP2O5"}
|
54
|
+
]
|
55
|
+
}
|
56
|
+
}]
|
57
|
+
}
|
58
|
+
}
|
59
|
+
RETURNS = {
|
60
|
+
"Emission": [{
|
61
|
+
"value": "",
|
62
|
+
"min": "",
|
63
|
+
"max": "",
|
64
|
+
"methodTier": "tier 1",
|
65
|
+
"statsDefinition": "modelled"
|
66
|
+
}]
|
67
|
+
}
|
68
|
+
TERM_ID = 'pToSurfaceWaterAquacultureSystems'
|
69
|
+
TIER = EmissionMethodTier.TIER_1.value
|
70
|
+
|
71
|
+
|
72
|
+
def _emission(value: float):
|
73
|
+
emission = _new_emission(TERM_ID, MODEL)
|
74
|
+
emission['value'] = [value]
|
75
|
+
emission['statsDefinition'] = EmissionStatsDefinition.MODELLED.value
|
76
|
+
emission['methodTier'] = TIER
|
77
|
+
return emission
|
78
|
+
|
79
|
+
|
80
|
+
def _convert_to_P(blank_node: dict):
|
81
|
+
return {
|
82
|
+
'id': blank_node.get('term', {}).get('@id'),
|
83
|
+
'value': list_sum(blank_node.get('value'), default=None),
|
84
|
+
'value-converted': (
|
85
|
+
convert_product_to_unit(blank_node, Units.KG_P) or
|
86
|
+
convert_product_to_unit(blank_node, Units.KG_P2O5) / get_atomic_conversion(Units.KG_P2O5, Units.KG_P) or
|
87
|
+
convert_to_unit(blank_node, Units.KG_P)
|
88
|
+
)
|
89
|
+
}
|
90
|
+
|
91
|
+
|
92
|
+
def _run(cycle: dict):
|
93
|
+
inputs = filter_list_term_type(cycle.get('inputs', []), [
|
94
|
+
TermTermType.CROP,
|
95
|
+
TermTermType.LIVEANIMAL,
|
96
|
+
TermTermType.LIVEAQUATICSPECIES,
|
97
|
+
TermTermType.ANIMALPRODUCT,
|
98
|
+
TermTermType.PROCESSEDFOOD,
|
99
|
+
TermTermType.FEEDFOODADDITIVE,
|
100
|
+
TermTermType.ORGANICFERTILISER,
|
101
|
+
TermTermType.FORAGE,
|
102
|
+
TermTermType.EXCRETA,
|
103
|
+
TermTermType.WASTE,
|
104
|
+
]) + _filter_list_term_unit(filter_list_term_type(cycle.get('inputs', []), [
|
105
|
+
TermTermType.INORGANICFERTILISER
|
106
|
+
]), Units.KG_P2O5)
|
107
|
+
inputs_P = list(map(_convert_to_P, inputs))
|
108
|
+
total_inputs_P = list_sum(non_empty_list([i.get('value-converted', 0) for i in inputs_P]))
|
109
|
+
|
110
|
+
products = filter_list_term_type(cycle.get('products', []), [
|
111
|
+
TermTermType.CROP,
|
112
|
+
TermTermType.LIVEANIMAL,
|
113
|
+
TermTermType.LIVEAQUATICSPECIES,
|
114
|
+
TermTermType.ANIMALPRODUCT
|
115
|
+
])
|
116
|
+
products_P = list(map(_convert_to_P, products))
|
117
|
+
total_products_P = list_sum(non_empty_list([i.get('value-converted', 0) for i in products_P]))
|
118
|
+
|
119
|
+
debugValues(cycle, model=MODEL, term=TERM_ID,
|
120
|
+
inputs_P=log_as_table(inputs_P),
|
121
|
+
products_P=log_as_table(products_P))
|
122
|
+
|
123
|
+
return [_emission(total_inputs_P - total_products_P)]
|
124
|
+
|
125
|
+
|
126
|
+
def _should_run(cycle: dict):
|
127
|
+
is_animalFeed_complete = _is_term_type_complete(cycle, 'animalFeed')
|
128
|
+
is_product_complete = _is_term_type_complete(cycle, 'product')
|
129
|
+
is_fertiliser_complete = _is_term_type_complete(cycle, 'fertiliser')
|
130
|
+
is_liveAnimalInput_complete = _is_term_type_complete(cycle, 'liveAnimalInput')
|
131
|
+
|
132
|
+
logRequirements(cycle, model=MODEL, term=TERM_ID,
|
133
|
+
is_term_type_animalFeed_complete=is_animalFeed_complete,
|
134
|
+
is_term_type_product_complete=is_product_complete,
|
135
|
+
is_term_type_fertiliser_complete=is_fertiliser_complete,
|
136
|
+
is_term_type_liveAnimalInput_complete=is_liveAnimalInput_complete)
|
137
|
+
|
138
|
+
should_run = all([
|
139
|
+
is_animalFeed_complete,
|
140
|
+
is_product_complete,
|
141
|
+
is_fertiliser_complete,
|
142
|
+
is_liveAnimalInput_complete
|
143
|
+
])
|
144
|
+
logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
|
145
|
+
return should_run
|
146
|
+
|
147
|
+
|
148
|
+
def run(cycle: dict): return _run(cycle) if _should_run(cycle) else []
|
@@ -32,7 +32,7 @@ STANDARD_DEPTHS = {(0, 30), (0, 50)}
|
|
32
32
|
|
33
33
|
|
34
34
|
def _measurement(value: float, date: str, term_id: str, standard_fields: dict):
|
35
|
-
data = _new_measurement(term_id)
|
35
|
+
data = _new_measurement(term_id, MODEL)
|
36
36
|
data["value"] = [value]
|
37
37
|
data["depthUpper"] = standard_fields["depthUpper"]
|
38
38
|
data["depthLower"] = standard_fields["depthLower"]
|
@@ -16,8 +16,10 @@ REQUIREMENTS = {
|
|
16
16
|
"Cycle": {
|
17
17
|
"practices": [
|
18
18
|
{"@type": "Practice", "value": "", "term.@id": "croppingDuration"},
|
19
|
-
{"@type": "Practice", "value": "", "term.termType": ["landUseManagement", "waterRegime"]}
|
19
|
+
{"@type": "Practice", "value": "", "term.termType": ["landUseManagement", "waterRegime"]},
|
20
|
+
{"@type": "Practice", "value": "", "term.termType": "cropResidueManagement"}
|
20
21
|
],
|
22
|
+
"products": [{"@type": "Product", "value": "", "term.@id": "aboveGroundCropResidueIncorporated"}],
|
21
23
|
"site": {
|
22
24
|
"@type": "Site",
|
23
25
|
"country": {"@type": "Term", "termType": "region"}
|
@@ -31,9 +33,7 @@ REQUIREMENTS = {
|
|
31
33
|
"term.termType": "fertiliserBrandName",
|
32
34
|
"properties": [{"@type": "Property", "value": "", "key.termType": "organicFertiliser"}]
|
33
35
|
}
|
34
|
-
]
|
35
|
-
"products": [{"@type": "Product", "value": "", "term.@id": "aboveGroundCropResidueIncorporated"}],
|
36
|
-
"practices": [{"@type": "Practice", "value": "", "term.termType": "cropResidueManagement"}]
|
36
|
+
]
|
37
37
|
}
|
38
38
|
}
|
39
39
|
}
|
@@ -160,8 +160,10 @@ def _get_fertiliser_value(cycle: dict, suffix: str = 'value'):
|
|
160
160
|
def _calculate_SFo(cycle: dict, suffix: str = 'value'):
|
161
161
|
cropResidue = _get_cropResidue_value(cycle, suffix)
|
162
162
|
fertiliser = _get_fertiliser_value(cycle, suffix)
|
163
|
-
|
164
|
-
|
163
|
+
return (1 + (fertiliser/1000) + (cropResidue/1000)) ** 0.59 if all([
|
164
|
+
fertiliser is not None,
|
165
|
+
cropResidue is not None
|
166
|
+
]) else None
|
165
167
|
|
166
168
|
|
167
169
|
def _get_practice_values(practice: dict, col: str, default=None):
|
@@ -0,0 +1,270 @@
|
|
1
|
+
import numpy as np
|
2
|
+
import numpy.typing as npt
|
3
|
+
from typing import Callable, Union
|
4
|
+
|
5
|
+
from hestia_earth.schema import EmissionMethodTier, EmissionStatsDefinition
|
6
|
+
|
7
|
+
from hestia_earth.models.log import logRequirements, logShouldRun
|
8
|
+
from hestia_earth.models.utils.array_builders import (
|
9
|
+
discrete_uniform_1d, gen_seed, normal_1d, repeat_single, triangular_1d
|
10
|
+
)
|
11
|
+
from hestia_earth.models.utils.cycle import land_occupation_per_ha
|
12
|
+
from hestia_earth.models.utils.descriptive_stats import calc_descriptive_stats
|
13
|
+
from hestia_earth.models.utils.ecoClimateZone import EcoClimateZone, get_eco_climate_zone_value
|
14
|
+
from hestia_earth.models.utils.emission import _new_emission
|
15
|
+
from hestia_earth.models.utils.measurement import most_relevant_measurement_value
|
16
|
+
from hestia_earth.models.utils.site import valid_site_type
|
17
|
+
|
18
|
+
from .organicSoilCultivation_utils import (
|
19
|
+
assign_ditch_category, assign_organic_soil_category, calc_emission, DitchCategory, get_ditch_frac,
|
20
|
+
get_emission_factor, OrganicSoilCategory, remap_categories, valid_eco_climate_zone
|
21
|
+
)
|
22
|
+
from . import MODEL
|
23
|
+
|
24
|
+
REQUIREMENTS = {
|
25
|
+
"Cycle": {
|
26
|
+
"or": [
|
27
|
+
{
|
28
|
+
"cycleDuration": "",
|
29
|
+
"practices": [{"@type": "Practice", "value": "", "term.@id": "longFallowRatio"}]
|
30
|
+
},
|
31
|
+
{
|
32
|
+
"@doc": "for plantations, additional properties are required",
|
33
|
+
"practices": [
|
34
|
+
{"@type": "Practice", "value": "", "term.@id": "nurseryDensity"},
|
35
|
+
{"@type": "Practice", "value": "", "term.@id": "nurseryDuration"},
|
36
|
+
{"@type": "Practice", "value": "", "term.@id": "plantationProductiveLifespan"},
|
37
|
+
{"@type": "Practice", "value": "", "term.@id": "plantationDensity"},
|
38
|
+
{"@type": "Practice", "value": "", "term.@id": "plantationLifespan"},
|
39
|
+
{"@type": "Practice", "value": "", "term.@id": "rotationDuration"}
|
40
|
+
]
|
41
|
+
}
|
42
|
+
],
|
43
|
+
"site": {
|
44
|
+
"@type": "Site",
|
45
|
+
"measurements": [
|
46
|
+
{"@type": "Measurement", "value": "", "term.@id": "histosol"},
|
47
|
+
{"@type": "Measurement", "value": "", "term.@id": "ecoClimateZone"}
|
48
|
+
]
|
49
|
+
},
|
50
|
+
"optional": {
|
51
|
+
"cycleDuration": ""
|
52
|
+
}
|
53
|
+
}
|
54
|
+
}
|
55
|
+
LOOKUPS = {
|
56
|
+
"crop": [
|
57
|
+
"isPlantation",
|
58
|
+
"IPCC_2013_ORGANIC_SOIL_CULTIVATION_CATEGORY"
|
59
|
+
],
|
60
|
+
"forage": [
|
61
|
+
"isPlantation",
|
62
|
+
"IPCC_2013_ORGANIC_SOIL_CULTIVATION_CATEGORY"
|
63
|
+
],
|
64
|
+
"ecoClimateZone": [
|
65
|
+
"IPCC_2013_ORGANIC_SOILS_TONNES_CH4_HECTARE_ANNUAL_CROPS",
|
66
|
+
"IPCC_2013_ORGANIC_SOILS_TONNES_CH4_HECTARE_PERENNIAL_CROPS",
|
67
|
+
"IPCC_2013_ORGANIC_SOILS_TONNES_CH4_HECTARE_ACACIA",
|
68
|
+
"IPCC_2013_ORGANIC_SOILS_TONNES_CH4_HECTARE_OIL_PALM",
|
69
|
+
"IPCC_2013_ORGANIC_SOILS_TONNES_CH4_HECTARE_SAGO_PALM",
|
70
|
+
"IPCC_2013_ORGANIC_SOILS_TONNES_CH4_HECTARE_PADDY_RICE_CULTIVATION",
|
71
|
+
"IPCC_2013_ORGANIC_SOILS_TONNES_CH4_HECTARE_GRASSLAND",
|
72
|
+
"IPCC_2013_ORGANIC_SOILS_TONNES_CH4_HECTARE_DITCH",
|
73
|
+
"IPCC_2013_ORGANIC_SOILS_TONNES_CH4_HECTARE_OTHER",
|
74
|
+
"IPCC_2013_DRAINED_ORGANIC_SOILS_DITCH_FRAC_AGRICULTURAL_LAND",
|
75
|
+
"IPCC_2013_DRAINED_ORGANIC_SOILS_DITCH_FRAC_NETHERLANDS"
|
76
|
+
]
|
77
|
+
}
|
78
|
+
RETURNS = {
|
79
|
+
"Emission": [{
|
80
|
+
"value": "",
|
81
|
+
"sd": "",
|
82
|
+
"min": "",
|
83
|
+
"max": "",
|
84
|
+
"observations": "",
|
85
|
+
"statsDefinition": "simulated",
|
86
|
+
"methodTier": "tier 1"
|
87
|
+
}]
|
88
|
+
}
|
89
|
+
TERM_ID = 'ch4ToAirOrganicSoilCultivation'
|
90
|
+
TIER = EmissionMethodTier.TIER_1.value
|
91
|
+
|
92
|
+
_STATS_DEFINITION = EmissionStatsDefinition.SIMULATED.value
|
93
|
+
_ITERATIONS = 100000
|
94
|
+
|
95
|
+
_CATEGORY_REMAPPER = {
|
96
|
+
OrganicSoilCategory.ACACIA: OrganicSoilCategory.PERENNIAL_CROPS
|
97
|
+
}
|
98
|
+
|
99
|
+
|
100
|
+
def _emission(descriptive_stats: dict):
|
101
|
+
emission = _new_emission(TERM_ID, MODEL) | descriptive_stats
|
102
|
+
emission['methodTier'] = TIER
|
103
|
+
return emission
|
104
|
+
|
105
|
+
|
106
|
+
def sample_emission_factor(
|
107
|
+
eco_climate_zone: EcoClimateZone,
|
108
|
+
organic_soil_category: OrganicSoilCategory,
|
109
|
+
seed: Union[int, np.random.Generator, None] = None,
|
110
|
+
) -> npt.NDArray:
|
111
|
+
category = remap_categories(organic_soil_category, _CATEGORY_REMAPPER) # fewer categories than CO2 model
|
112
|
+
factor_data = get_emission_factor(TERM_ID, eco_climate_zone, category)
|
113
|
+
sample_func = _get_sample_func(factor_data)
|
114
|
+
return sample_func(iterations=_ITERATIONS, seed=seed, **factor_data)
|
115
|
+
|
116
|
+
|
117
|
+
def sample_ditch_frac(
|
118
|
+
eco_climate_zone: EcoClimateZone,
|
119
|
+
ditch_category: DitchCategory,
|
120
|
+
seed: Union[int, np.random.Generator, None] = None,
|
121
|
+
) -> npt.NDArray:
|
122
|
+
factor_data = get_ditch_frac(eco_climate_zone, ditch_category, term=TERM_ID)
|
123
|
+
sample_func = _get_sample_func(factor_data)
|
124
|
+
return sample_func(iterations=_ITERATIONS, seed=seed, **factor_data)
|
125
|
+
|
126
|
+
|
127
|
+
def _sample_normal(
|
128
|
+
*, iterations: int, value: float, sd: float, seed: Union[int, np.random.Generator, None] = None, **_
|
129
|
+
) -> npt.NDArray:
|
130
|
+
return normal_1d(shape=(1, iterations), mu=value, sigma=sd, seed=seed)
|
131
|
+
|
132
|
+
|
133
|
+
def _sample_uniform(
|
134
|
+
*, iterations: int, min: float, max: float, seed: Union[int, np.random.Generator, None] = None, **_
|
135
|
+
) -> npt.NDArray:
|
136
|
+
return discrete_uniform_1d(shape=(1, iterations), low=min, high=max, seed=seed)
|
137
|
+
|
138
|
+
|
139
|
+
def _sample_triangular(
|
140
|
+
*, iterations: int, value: float, min: float, max: float, seed: Union[int, np.random.Generator, None] = None, **_
|
141
|
+
) -> npt.NDArray:
|
142
|
+
return triangular_1d(shape=(1, iterations), mode=value, low=min, high=max, seed=seed)
|
143
|
+
|
144
|
+
|
145
|
+
def _sample_constant(*, value: float, **_) -> npt.NDArray:
|
146
|
+
"""Sample a constant model parameter."""
|
147
|
+
return repeat_single(shape=(1, 1), value=value)
|
148
|
+
|
149
|
+
|
150
|
+
_KWARGS_TO_SAMPLE_FUNC = {
|
151
|
+
("value", "sd"): _sample_normal,
|
152
|
+
("value", "min", "max"): _sample_triangular,
|
153
|
+
("min", "max"): _sample_uniform,
|
154
|
+
("value",): _sample_constant
|
155
|
+
}
|
156
|
+
"""
|
157
|
+
Mapping from available distribution data to sample function.
|
158
|
+
"""
|
159
|
+
|
160
|
+
|
161
|
+
def _get_sample_func(kwargs: dict) -> Callable:
|
162
|
+
"""
|
163
|
+
Select the correct sample function for a parameter based on the distribution data available. All possible
|
164
|
+
parameters for the model should have, at a minimum, a `value`, meaning that no default function needs to be
|
165
|
+
specified.
|
166
|
+
|
167
|
+
This function has been extracted into it's own method to allow for mocking of sample function.
|
168
|
+
|
169
|
+
Keyword Args
|
170
|
+
------------
|
171
|
+
value : float
|
172
|
+
The distribution mean.
|
173
|
+
sd : float
|
174
|
+
The standard deviation of the distribution.
|
175
|
+
se : float
|
176
|
+
The standard error of the distribution.
|
177
|
+
n : float
|
178
|
+
Sample size.
|
179
|
+
|
180
|
+
Returns
|
181
|
+
-------
|
182
|
+
Callable
|
183
|
+
The sample function for the distribution.
|
184
|
+
"""
|
185
|
+
return next(
|
186
|
+
sample_func for required_kwargs, sample_func in _KWARGS_TO_SAMPLE_FUNC.items()
|
187
|
+
if all(kwarg in kwargs.keys() for kwarg in required_kwargs)
|
188
|
+
)
|
189
|
+
|
190
|
+
|
191
|
+
def _should_run(cycle: dict):
|
192
|
+
end_date = cycle.get('endDate')
|
193
|
+
site = cycle.get('site', {})
|
194
|
+
measurements = site.get('measurements', [])
|
195
|
+
|
196
|
+
seed = gen_seed(cycle, MODEL, TERM_ID)
|
197
|
+
rng = np.random.default_rng(seed)
|
198
|
+
|
199
|
+
def _get_measurement_content(term_id: str):
|
200
|
+
return most_relevant_measurement_value(measurements, term_id, end_date)
|
201
|
+
|
202
|
+
histosol = _get_measurement_content('histosol')
|
203
|
+
eco_climate_zone = get_eco_climate_zone_value(cycle, as_enum=True)
|
204
|
+
organic_soil_category = assign_organic_soil_category(cycle, log_id=TERM_ID)
|
205
|
+
ditch_category = assign_ditch_category(cycle)
|
206
|
+
|
207
|
+
emission_factor = (
|
208
|
+
sample_emission_factor(eco_climate_zone, organic_soil_category, seed=rng) if eco_climate_zone
|
209
|
+
else None
|
210
|
+
)
|
211
|
+
ditch_factor = (
|
212
|
+
sample_emission_factor(eco_climate_zone, OrganicSoilCategory.DITCH, seed=rng) if eco_climate_zone
|
213
|
+
else None
|
214
|
+
)
|
215
|
+
ditch_frac = (
|
216
|
+
sample_ditch_frac(eco_climate_zone, ditch_category, seed=rng) if eco_climate_zone
|
217
|
+
else None
|
218
|
+
)
|
219
|
+
|
220
|
+
land_occupation = land_occupation_per_ha(MODEL, TERM_ID, cycle)
|
221
|
+
|
222
|
+
logRequirements(
|
223
|
+
cycle, model=MODEL, term=TERM_ID,
|
224
|
+
eco_climate_zone=eco_climate_zone,
|
225
|
+
organic_soil_category=organic_soil_category,
|
226
|
+
ditch_category=ditch_category,
|
227
|
+
emission_factor=f"{np.mean(emission_factor):.3f}",
|
228
|
+
ditch_factor=f"{np.mean(ditch_factor):.3f}",
|
229
|
+
ditch_frac=f"{np.mean(ditch_frac):.3f}",
|
230
|
+
land_occupation=land_occupation,
|
231
|
+
histosol=histosol
|
232
|
+
)
|
233
|
+
|
234
|
+
should_run = all([
|
235
|
+
valid_site_type(site),
|
236
|
+
valid_eco_climate_zone(eco_climate_zone),
|
237
|
+
all(
|
238
|
+
var is not None for var in [
|
239
|
+
emission_factor,
|
240
|
+
ditch_factor,
|
241
|
+
ditch_frac,
|
242
|
+
land_occupation,
|
243
|
+
histosol
|
244
|
+
]
|
245
|
+
)
|
246
|
+
])
|
247
|
+
|
248
|
+
logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
|
249
|
+
|
250
|
+
return should_run, emission_factor, ditch_factor, ditch_frac, histosol, land_occupation
|
251
|
+
|
252
|
+
|
253
|
+
def _run(
|
254
|
+
emission_factor: npt.NDArray,
|
255
|
+
ditch_factor: npt.NDArray,
|
256
|
+
ditch_frac: npt.NDArray,
|
257
|
+
histosol: float,
|
258
|
+
land_occupation: float
|
259
|
+
):
|
260
|
+
land_emission = calc_emission(TERM_ID, emission_factor, histosol, land_occupation)
|
261
|
+
ditch_emission = calc_emission(TERM_ID, ditch_factor, histosol, land_occupation)
|
262
|
+
|
263
|
+
result = (ditch_emission * ditch_frac) + (land_emission * (1 - ditch_frac))
|
264
|
+
descriptive_stats = calc_descriptive_stats(result, _STATS_DEFINITION)
|
265
|
+
return [_emission(descriptive_stats)]
|
266
|
+
|
267
|
+
|
268
|
+
def run(cycle: dict):
|
269
|
+
should_run, *args = _should_run(cycle)
|
270
|
+
return _run(*args) if should_run else []
|
@@ -186,13 +186,11 @@ def _should_compile_inventory_func(
|
|
186
186
|
) for cycle in cycles
|
187
187
|
)
|
188
188
|
|
189
|
-
has_stock_measurements = len(carbon_stock_measurements) > 0
|
190
189
|
has_cycles = len(cycles) > 0
|
191
190
|
has_functional_unit_1_ha = all(cycle.get('functionalUnit') == CycleFunctionalUnit._1_HA.value for cycle in cycles)
|
192
191
|
|
193
192
|
should_run = all([
|
194
193
|
has_soil,
|
195
|
-
has_stock_measurements,
|
196
194
|
has_cycles,
|
197
195
|
has_functional_unit_1_ha
|
198
196
|
])
|
@@ -201,7 +199,6 @@ def _should_compile_inventory_func(
|
|
201
199
|
"site_type": site_type,
|
202
200
|
"has_soil": has_soil,
|
203
201
|
"carbon_stock_term": _CARBON_STOCK_TERM_ID,
|
204
|
-
"has_stock_measurements": has_stock_measurements,
|
205
202
|
"has_cycles": has_cycles,
|
206
203
|
"has_functional_unit_1_ha": has_functional_unit_1_ha,
|
207
204
|
}
|
@@ -199,13 +199,11 @@ def _should_compile_inventory_func(
|
|
199
199
|
) for cycle in cycles
|
200
200
|
)
|
201
201
|
|
202
|
-
has_stock_measurements = len(carbon_stock_measurements) > 0
|
203
202
|
has_cycles = len(cycles) > 0
|
204
203
|
has_functional_unit_1_ha = all(cycle.get('functionalUnit') == CycleFunctionalUnit._1_HA.value for cycle in cycles)
|
205
204
|
|
206
205
|
should_run = all([
|
207
206
|
has_soil,
|
208
|
-
has_stock_measurements,
|
209
207
|
has_cycles,
|
210
208
|
has_functional_unit_1_ha
|
211
209
|
])
|
@@ -214,7 +212,6 @@ def _should_compile_inventory_func(
|
|
214
212
|
"site_type": site_type,
|
215
213
|
"has_soil": has_soil,
|
216
214
|
"carbon_stock_term": _CARBON_STOCK_TERM_ID,
|
217
|
-
"has_stock_measurements": has_stock_measurements,
|
218
215
|
"has_cycles": has_cycles,
|
219
216
|
"has_functional_unit_1_ha": has_functional_unit_1_ha,
|
220
217
|
}
|