hestia-earth-models 0.59.4__py3-none-any.whl → 0.59.6__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/cycle/animal/milkYield.py +86 -0
- hestia_earth/models/cycle/endDate.py +50 -0
- hestia_earth/models/cycle/inorganicFertiliser.py +3 -2
- hestia_earth/models/cycle/liveAnimal.py +3 -0
- hestia_earth/models/cycle/milkYield.py +8 -3
- hestia_earth/models/cycle/pre_checks/__init__.py +1 -2
- hestia_earth/models/cycle/startDate.py +42 -0
- hestia_earth/models/cycle/utils.py +1 -1
- hestia_earth/models/faostat2018/liveweightPerHead.py +77 -41
- hestia_earth/models/faostat2018/product/price.py +30 -55
- hestia_earth/models/faostat2018/utils.py +10 -2
- hestia_earth/models/geospatialDatabase/potentialEvapotranspirationLongTermAnnualMean.py +2 -2
- hestia_earth/models/geospatialDatabase/potentialEvapotranspirationMonthly.py +9 -8
- hestia_earth/models/geospatialDatabase/precipitationMonthly.py +10 -8
- hestia_earth/models/geospatialDatabase/temperatureAnnual.py +2 -5
- hestia_earth/models/geospatialDatabase/temperatureLongTermAnnualMean.py +2 -3
- hestia_earth/models/geospatialDatabase/temperatureMonthly.py +8 -8
- hestia_earth/models/geospatialDatabase/utils.py +6 -1
- hestia_earth/models/haversineFormula/transport/distance.py +6 -3
- hestia_earth/models/ipcc2006/n2OToAirInorganicFertiliserIndirect.py +1 -1
- hestia_earth/models/ipcc2019/organicCarbonPerHa.py +89 -114
- hestia_earth/models/ipcc2019/pastureGrass.py +2 -1
- hestia_earth/models/linkedImpactAssessment/__init__.py +78 -43
- hestia_earth/models/mocking/search-results.json +244 -271
- hestia_earth/models/schmidt2007/h2SToAirWasteTreatment.py +58 -0
- hestia_earth/models/schmidt2007/n2OToAirWasteTreatmentDirect.py +58 -0
- hestia_earth/models/schmidt2007/nh3ToAirWasteTreatment.py +58 -0
- hestia_earth/models/site/management.py +107 -12
- hestia_earth/models/site/soilMeasurement.py +9 -9
- hestia_earth/models/utils/__init__.py +4 -1
- hestia_earth/models/utils/animalProduct.py +6 -4
- hestia_earth/models/utils/blank_node.py +6 -5
- hestia_earth/models/utils/product.py +9 -1
- hestia_earth/models/utils/term.py +0 -23
- hestia_earth/models/version.py +1 -1
- {hestia_earth_models-0.59.4.dist-info → hestia_earth_models-0.59.6.dist-info}/METADATA +1 -1
- {hestia_earth_models-0.59.4.dist-info → hestia_earth_models-0.59.6.dist-info}/RECORD +53 -43
- tests/models/cycle/animal/test_milkYield.py +43 -0
- tests/models/cycle/test_endDate.py +24 -0
- tests/models/cycle/test_startDate.py +22 -0
- tests/models/faostat2018/product/test_price.py +25 -45
- tests/models/faostat2018/test_liveweightPerHead.py +106 -42
- tests/models/ipcc2019/test_organicCarbonPerHa.py +12 -18
- tests/models/schmidt2007/test_h2SToAirWasteTreatment.py +45 -0
- tests/models/schmidt2007/test_n2OToAirWasteTreatmentDirect.py +45 -0
- tests/models/schmidt2007/test_nh3ToAirWasteTreatment.py +45 -0
- tests/models/site/test_management.py +24 -3
- tests/models/site/test_soilMeasurement.py +40 -21
- tests/models/utils/test_blank_node.py +71 -3
- tests/models/utils/test_term.py +1 -8
- hestia_earth/models/cycle/pre_checks/startDate.py +0 -52
- tests/models/cycle/pre_checks/test_startDate.py +0 -44
- {hestia_earth_models-0.59.4.dist-info → hestia_earth_models-0.59.6.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.59.4.dist-info → hestia_earth_models-0.59.6.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.59.4.dist-info → hestia_earth_models-0.59.6.dist-info}/top_level.txt +0 -0
|
@@ -10,7 +10,7 @@ from hestia_earth.models.utils import first_day_of_month, last_day_of_month
|
|
|
10
10
|
from hestia_earth.models.utils.measurement import _new_measurement
|
|
11
11
|
from hestia_earth.models.utils.source import get_source
|
|
12
12
|
from hestia_earth.models.utils.site import related_years
|
|
13
|
-
from .utils import
|
|
13
|
+
from .utils import download, has_geospatial_data, should_download
|
|
14
14
|
from . import MODEL
|
|
15
15
|
|
|
16
16
|
REQUIREMENTS = {
|
|
@@ -48,9 +48,6 @@ def _measurement(site: dict, value: list, dates: list):
|
|
|
48
48
|
return measurement | get_source(site, BIBLIO_TITLE)
|
|
49
49
|
|
|
50
50
|
|
|
51
|
-
def _to_celcius(kelvin_value: int): return kelvin_value - KELVIN_0 if kelvin_value else None
|
|
52
|
-
|
|
53
|
-
|
|
54
51
|
def _download(site: dict, start_date: str, end_date: str):
|
|
55
52
|
return download(
|
|
56
53
|
TERM_ID,
|
|
@@ -63,6 +60,12 @@ def _download(site: dict, start_date: str, end_date: str):
|
|
|
63
60
|
)
|
|
64
61
|
|
|
65
62
|
|
|
63
|
+
def _value_at(site: dict, start_date: str, end_date: str):
|
|
64
|
+
factor = 0.1
|
|
65
|
+
value = _download(site, start_date, end_date)
|
|
66
|
+
return (value * factor, start_date[0:7]) if value is not None else None
|
|
67
|
+
|
|
68
|
+
|
|
66
69
|
def _run(site: dict, years: list):
|
|
67
70
|
# fetch from first year to last
|
|
68
71
|
years = range(years[0], years[-1] + 1) if len(years) > 1 else years
|
|
@@ -73,10 +76,8 @@ def _run(site: dict, years: list):
|
|
|
73
76
|
for month in range(1, 13)
|
|
74
77
|
] for year in years
|
|
75
78
|
])
|
|
76
|
-
values = non_empty_list([
|
|
77
|
-
|
|
78
|
-
])
|
|
79
|
-
return _measurement(site, [v for v, d in values], [d for v, d in values])
|
|
79
|
+
values = non_empty_list([_value_at(site, start_date, end_date) for start_date, end_date in dates])
|
|
80
|
+
return [_measurement(site, [v for v, d in values], [d for v, d in values])] if values else []
|
|
80
81
|
|
|
81
82
|
|
|
82
83
|
def run(site: dict):
|
|
@@ -10,7 +10,7 @@ from hestia_earth.models.utils import first_day_of_month, last_day_of_month
|
|
|
10
10
|
from hestia_earth.models.utils.measurement import _new_measurement
|
|
11
11
|
from hestia_earth.models.utils.source import get_source
|
|
12
12
|
from hestia_earth.models.utils.site import related_years
|
|
13
|
-
from .utils import
|
|
13
|
+
from .utils import download, has_geospatial_data, should_download
|
|
14
14
|
from . import MODEL
|
|
15
15
|
|
|
16
16
|
REQUIREMENTS = {
|
|
@@ -48,9 +48,6 @@ def _measurement(site: dict, value: list, dates: list):
|
|
|
48
48
|
return measurement | get_source(site, BIBLIO_TITLE)
|
|
49
49
|
|
|
50
50
|
|
|
51
|
-
def _to_celcius(kelvin_value: int): return kelvin_value - KELVIN_0 if kelvin_value else None
|
|
52
|
-
|
|
53
|
-
|
|
54
51
|
def _download(site: dict, start_date: str, end_date: str):
|
|
55
52
|
return download(
|
|
56
53
|
TERM_ID,
|
|
@@ -63,6 +60,13 @@ def _download(site: dict, start_date: str, end_date: str):
|
|
|
63
60
|
)
|
|
64
61
|
|
|
65
62
|
|
|
63
|
+
def _value_at(site: dict, start_date: str, end_date: str):
|
|
64
|
+
# collection is in meters, convert to millimeters
|
|
65
|
+
factor = 1000
|
|
66
|
+
value = _download(site, start_date, end_date)
|
|
67
|
+
return (value * factor, start_date[0:7]) if value is not None else None
|
|
68
|
+
|
|
69
|
+
|
|
66
70
|
def _run(site: dict, years: list):
|
|
67
71
|
# fetch from first year to last
|
|
68
72
|
years = range(years[0], years[-1] + 1) if len(years) > 1 else years
|
|
@@ -73,10 +77,8 @@ def _run(site: dict, years: list):
|
|
|
73
77
|
for month in range(1, 13)
|
|
74
78
|
] for year in years
|
|
75
79
|
])
|
|
76
|
-
values = non_empty_list([
|
|
77
|
-
|
|
78
|
-
])
|
|
79
|
-
return _measurement(site, [v for v, d in values], [d for v, d in values])
|
|
80
|
+
values = non_empty_list([_value_at(site, start_date, end_date) for start_date, end_date in dates])
|
|
81
|
+
return [_measurement(site, [v for v, d in values], [d for v, d in values])] if values else []
|
|
80
82
|
|
|
81
83
|
|
|
82
84
|
def run(site: dict):
|
|
@@ -9,7 +9,7 @@ from hestia_earth.models.log import logRequirements, logShouldRun
|
|
|
9
9
|
from hestia_earth.models.utils.measurement import _new_measurement
|
|
10
10
|
from hestia_earth.models.utils.source import get_source
|
|
11
11
|
from hestia_earth.models.utils.site import related_years
|
|
12
|
-
from .utils import
|
|
12
|
+
from .utils import to_celcius, download, has_geospatial_data, should_download
|
|
13
13
|
from . import MODEL
|
|
14
14
|
|
|
15
15
|
REQUIREMENTS = {
|
|
@@ -49,9 +49,6 @@ def _measurement(site: dict, value: float, year: int):
|
|
|
49
49
|
return measurement | get_source(site, BIBLIO_TITLE)
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
def _to_celcius(kelvin_value: int): return kelvin_value - KELVIN_0 if kelvin_value else None
|
|
53
|
-
|
|
54
|
-
|
|
55
52
|
def _download(site: dict, year: int):
|
|
56
53
|
return download(
|
|
57
54
|
TERM_ID,
|
|
@@ -64,7 +61,7 @@ def _download(site: dict, year: int):
|
|
|
64
61
|
|
|
65
62
|
|
|
66
63
|
def _run(site: dict, year: int):
|
|
67
|
-
value =
|
|
64
|
+
value = to_celcius(_download(site, year))
|
|
68
65
|
return _measurement(site, value, year) if value else None
|
|
69
66
|
|
|
70
67
|
|
|
@@ -3,9 +3,8 @@ from hestia_earth.schema import MeasurementMethodClassification
|
|
|
3
3
|
from hestia_earth.models.log import logRequirements, logShouldRun
|
|
4
4
|
from hestia_earth.models.utils.measurement import _new_measurement
|
|
5
5
|
from hestia_earth.models.utils.source import get_source
|
|
6
|
-
from .utils import download, has_geospatial_data, should_download
|
|
6
|
+
from .utils import to_celcius, download, has_geospatial_data, should_download
|
|
7
7
|
from . import MODEL
|
|
8
|
-
from .temperatureAnnual import _to_celcius
|
|
9
8
|
|
|
10
9
|
REQUIREMENTS = {
|
|
11
10
|
"Site": {
|
|
@@ -50,7 +49,7 @@ def _measurement(site: dict, value: float):
|
|
|
50
49
|
|
|
51
50
|
|
|
52
51
|
def _run(site: dict):
|
|
53
|
-
value =
|
|
52
|
+
value = to_celcius(download(TERM_ID, site, EE_PARAMS))
|
|
54
53
|
return [_measurement(site, value)] if value is not None else []
|
|
55
54
|
|
|
56
55
|
|
|
@@ -10,7 +10,7 @@ from hestia_earth.models.utils import first_day_of_month, last_day_of_month
|
|
|
10
10
|
from hestia_earth.models.utils.measurement import _new_measurement
|
|
11
11
|
from hestia_earth.models.utils.source import get_source
|
|
12
12
|
from hestia_earth.models.utils.site import related_years
|
|
13
|
-
from .utils import
|
|
13
|
+
from .utils import to_celcius, download, has_geospatial_data, should_download
|
|
14
14
|
from . import MODEL
|
|
15
15
|
|
|
16
16
|
REQUIREMENTS = {
|
|
@@ -48,9 +48,6 @@ def _measurement(site: dict, value: list, dates: list):
|
|
|
48
48
|
return measurement | get_source(site, BIBLIO_TITLE)
|
|
49
49
|
|
|
50
50
|
|
|
51
|
-
def _to_celcius(kelvin_value: int): return kelvin_value - KELVIN_0 if kelvin_value else None
|
|
52
|
-
|
|
53
|
-
|
|
54
51
|
def _download(site: dict, start_date: str, end_date: str):
|
|
55
52
|
return download(
|
|
56
53
|
TERM_ID,
|
|
@@ -63,6 +60,11 @@ def _download(site: dict, start_date: str, end_date: str):
|
|
|
63
60
|
)
|
|
64
61
|
|
|
65
62
|
|
|
63
|
+
def _value_at(site: dict, start_date: str, end_date: str):
|
|
64
|
+
value = _download(site, start_date, end_date)
|
|
65
|
+
return (to_celcius(value), start_date[0:7]) if value is not None else None
|
|
66
|
+
|
|
67
|
+
|
|
66
68
|
def _run(site: dict, years: list):
|
|
67
69
|
# fetch from first year to last
|
|
68
70
|
years = range(years[0], years[-1] + 1) if len(years) > 1 else years
|
|
@@ -73,10 +75,8 @@ def _run(site: dict, years: list):
|
|
|
73
75
|
for month in range(1, 13)
|
|
74
76
|
] for year in years
|
|
75
77
|
])
|
|
76
|
-
values = non_empty_list([
|
|
77
|
-
|
|
78
|
-
])
|
|
79
|
-
return _measurement(site, [v for v, d in values], [d for v, d in values])
|
|
78
|
+
values = non_empty_list([_value_at(site, start_date, end_date) for start_date, end_date in dates])
|
|
79
|
+
return [_measurement(site, [v for v, d in values], [d for v, d in values])] if values else []
|
|
80
80
|
|
|
81
81
|
|
|
82
82
|
def run(site: dict):
|
|
@@ -23,6 +23,9 @@ GEOPANDAS_COLLECTION_NAME = {
|
|
|
23
23
|
KELVIN_0 = 273.15
|
|
24
24
|
|
|
25
25
|
|
|
26
|
+
def to_celcius(kelvin_value: int): return kelvin_value - KELVIN_0 if kelvin_value else None
|
|
27
|
+
|
|
28
|
+
|
|
26
29
|
def use_geopandas(): return os.getenv('HEE_USE_GEOPANDAS', 'false') == 'true'
|
|
27
30
|
|
|
28
31
|
|
|
@@ -139,7 +142,9 @@ def _get_cached_data(term: str, site: dict, data: dict):
|
|
|
139
142
|
data.get('end_date')
|
|
140
143
|
]))
|
|
141
144
|
# data can be grouped by year when required
|
|
142
|
-
value = cache.get(cache_sub_key) if
|
|
145
|
+
value = cache.get(cache_sub_key) if (
|
|
146
|
+
isinstance(cache, dict) and cache_sub_key in cache and cache is not None
|
|
147
|
+
) else cache
|
|
143
148
|
if value is not None:
|
|
144
149
|
debugValues(site, model=MODEL, term=term, value_from_cache=value)
|
|
145
150
|
return value
|
|
@@ -27,8 +27,11 @@ REQUIREMENTS = {
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
RETURNS = {
|
|
30
|
-
"
|
|
31
|
-
"
|
|
30
|
+
"Input": [{
|
|
31
|
+
"transport": [{
|
|
32
|
+
"@type": "Transport",
|
|
33
|
+
"distance": ""
|
|
34
|
+
}]
|
|
32
35
|
}]
|
|
33
36
|
}
|
|
34
37
|
MODEL_KEY = 'distance'
|
|
@@ -98,7 +101,7 @@ def _should_run(cycle: dict):
|
|
|
98
101
|
# can only run if the site country has centroid coordinates
|
|
99
102
|
logRequirements(cycle, model=MODEL, term=None, key=MODEL_KEY,
|
|
100
103
|
latitude=country.get('latitude'),
|
|
101
|
-
longitude=country.get('
|
|
104
|
+
longitude=country.get('longitude'),
|
|
102
105
|
has_inputs_transport=len(inputs) > 0)
|
|
103
106
|
should_run = all([country.get('latitude'), country.get('latitude'), len(inputs) > 0])
|
|
104
107
|
logShouldRun(cycle, MODEL, None, should_run, key=MODEL_KEY)
|
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
The IPCC model for estimating soil organic carbon stock changes in the 0 - 30cm depth interval due to management
|
|
3
3
|
changes. This model combines the Tier 1 & Tier 2 methodologies. It first tries to run Tier 2 (only on croplands
|
|
4
4
|
remaining croplands). If Tier 2 cannot run, it will try to run Tier 1 (for croplands remaining croplands and for
|
|
5
|
-
grasslands remaining grasslands).
|
|
5
|
+
grasslands remaining grasslands).
|
|
6
|
+
|
|
7
|
+
More information on this model, including data requirements **and** recommendations, tier methodologies, and examples,
|
|
8
|
+
can be found in the
|
|
9
|
+
[Hestia SOC wiki](https://gitlab.com/hestia-earth/hestia-engine-models/-/wikis/Soil-organic-carbon-modelling).
|
|
10
|
+
|
|
11
|
+
Source:
|
|
6
12
|
[IPCC 2019, Vol. 4, Chapter 10](https://www.ipcc-nggip.iges.or.jp/public/2019rf/pdf/4_Volume4/19R_V4_Ch05_Cropland.pdf).
|
|
7
13
|
"""
|
|
8
14
|
from enum import Enum
|
|
@@ -46,7 +52,6 @@ from hestia_earth.models.utils.term import (
|
|
|
46
52
|
get_cover_crop_property_terms,
|
|
47
53
|
get_crop_residue_incorporated_or_left_on_field_terms,
|
|
48
54
|
get_irrigated_terms,
|
|
49
|
-
get_long_fallow_land_cover_terms,
|
|
50
55
|
get_residue_removed_or_burnt_terms,
|
|
51
56
|
get_upland_rice_crop_terms,
|
|
52
57
|
get_upland_rice_land_cover_terms
|
|
@@ -610,25 +615,26 @@ A dictionary mapping IPCC soil categories to corresponding soil type and USDA so
|
|
|
610
615
|
`"IPCC_SOIL_CATEGORY"` column.
|
|
611
616
|
"""
|
|
612
617
|
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
IpccLandUseCategory.ANNUAL_CROPS_WET: SiteSiteType.CROPLAND.value,
|
|
618
|
-
IpccLandUseCategory.ANNUAL_CROPS: SiteSiteType.CROPLAND.value,
|
|
619
|
-
IpccLandUseCategory.SET_ASIDE: SiteSiteType.CROPLAND.value,
|
|
620
|
-
IpccLandUseCategory.FOREST: SiteSiteType.FOREST.value,
|
|
621
|
-
IpccLandUseCategory.NATIVE: SiteSiteType.OTHER_NATURAL_VEGETATION.value
|
|
618
|
+
SITE_TYPE_TO_IPCC_LAND_USE_CATEGORY = {
|
|
619
|
+
SiteSiteType.PERMANENT_PASTURE.value: IpccLandUseCategory.GRASSLAND,
|
|
620
|
+
SiteSiteType.FOREST.value: IpccLandUseCategory.FOREST,
|
|
621
|
+
SiteSiteType.OTHER_NATURAL_VEGETATION.value: IpccLandUseCategory.NATIVE
|
|
622
622
|
}
|
|
623
623
|
"""
|
|
624
|
-
A dictionary mapping IPCC land use categories
|
|
624
|
+
A dictionary mapping site types to corresponding IPCC land use categories.
|
|
625
625
|
"""
|
|
626
626
|
|
|
627
627
|
IPCC_LAND_USE_CATEGORY_TO_LAND_COVER_LOOKUP_VALUE = {
|
|
628
|
+
IpccLandUseCategory.GRASSLAND: "Grassland",
|
|
628
629
|
IpccLandUseCategory.PERENNIAL_CROPS: "Perennial crops",
|
|
629
630
|
IpccLandUseCategory.PADDY_RICE_CULTIVATION: "Paddy rice cultivation",
|
|
630
631
|
IpccLandUseCategory.ANNUAL_CROPS_WET: "Annual crops",
|
|
631
|
-
IpccLandUseCategory.ANNUAL_CROPS: "Annual crops"
|
|
632
|
+
IpccLandUseCategory.ANNUAL_CROPS: "Annual crops",
|
|
633
|
+
IpccLandUseCategory.SET_ASIDE: [
|
|
634
|
+
"Annual crops", "Paddy rice cultivation", "Perennial crops", "Set aside"
|
|
635
|
+
],
|
|
636
|
+
IpccLandUseCategory.FOREST: "Forest",
|
|
637
|
+
IpccLandUseCategory.NATIVE: "Native"
|
|
632
638
|
}
|
|
633
639
|
"""
|
|
634
640
|
A dictionary mapping IPCC land use categories to corresponding land cover lookup values in the
|
|
@@ -846,7 +852,7 @@ def _calc_water_factor(
|
|
|
846
852
|
float
|
|
847
853
|
The water effect on decomposition for a given month, dimensionless, between `0.2129` and `1.5`.
|
|
848
854
|
"""
|
|
849
|
-
mappet = min(1.25, precipitation / pet)
|
|
855
|
+
mappet = min(1.25, precipitation / pet) if pet else 1.25
|
|
850
856
|
return 0.775 if is_irrigated else 0.2129 + (water_factor_slope * (mappet)) - (0.2413 * pow(mappet, 2))
|
|
851
857
|
|
|
852
858
|
|
|
@@ -937,7 +943,8 @@ def _calc_average_nitrogen_content_of_organic_carbon_sources(
|
|
|
937
943
|
weighted_values = [
|
|
938
944
|
c.mass * (c.nitrogen_content if c.nitrogen_content else default_nitrogen_content) for c in carbon_sources
|
|
939
945
|
]
|
|
940
|
-
|
|
946
|
+
should_run = total_weight > 0
|
|
947
|
+
return sum(weighted_values) / total_weight if should_run else 0
|
|
941
948
|
|
|
942
949
|
|
|
943
950
|
def _calc_average_lignin_content_of_organic_carbon_sources(
|
|
@@ -963,7 +970,8 @@ def _calc_average_lignin_content_of_organic_carbon_sources(
|
|
|
963
970
|
weighted_values = [
|
|
964
971
|
c.mass * (c.lignin_content if c.lignin_content else default_lignin_content) for c in carbon_sources
|
|
965
972
|
]
|
|
966
|
-
|
|
973
|
+
should_run = total_weight > 0
|
|
974
|
+
return sum(weighted_values) / total_weight if should_run else 0
|
|
967
975
|
|
|
968
976
|
|
|
969
977
|
# --- TIER 2 FUNCTIONS: ACTIVE SUB-POOL SOC STOCK ---
|
|
@@ -2525,7 +2533,7 @@ def _has_irrigation(water_regime_nodes: list[dict]) -> bool:
|
|
|
2525
2533
|
|
|
2526
2534
|
Parameters
|
|
2527
2535
|
----------
|
|
2528
|
-
water_regime_nodes :
|
|
2536
|
+
water_regime_nodes : list[dict]
|
|
2529
2537
|
List of water regime nodes to be checked.
|
|
2530
2538
|
|
|
2531
2539
|
Returns
|
|
@@ -2542,13 +2550,13 @@ def _has_irrigation(water_regime_nodes: list[dict]) -> bool:
|
|
|
2542
2550
|
|
|
2543
2551
|
def _has_long_fallow(land_cover_nodes: list[dict]) -> bool:
|
|
2544
2552
|
"""
|
|
2545
|
-
Check if long fallow terms
|
|
2553
|
+
Check if long fallow terms are present in the land cover nodes.
|
|
2546
2554
|
|
|
2547
2555
|
n.b., a super majority of the site area must be under long fallow for it to be classified as set aside.
|
|
2548
2556
|
|
|
2549
2557
|
Parameters
|
|
2550
2558
|
----------
|
|
2551
|
-
land_cover_nodes :
|
|
2559
|
+
land_cover_nodes : list[dict]
|
|
2552
2560
|
List of land cover nodes to be checked.
|
|
2553
2561
|
|
|
2554
2562
|
Returns
|
|
@@ -2556,9 +2564,12 @@ def _has_long_fallow(land_cover_nodes: list[dict]) -> bool:
|
|
|
2556
2564
|
bool
|
|
2557
2565
|
`True` if long fallow is present, `False` otherwise.
|
|
2558
2566
|
"""
|
|
2559
|
-
|
|
2567
|
+
LOOKUP = LOOKUPS["landCover"][0]
|
|
2568
|
+
TARGET_LOOKUP_VALUE = "Set aside"
|
|
2569
|
+
return cumulative_nodes_lookup_match(
|
|
2560
2570
|
land_cover_nodes,
|
|
2561
|
-
|
|
2571
|
+
lookup=LOOKUP,
|
|
2572
|
+
target_lookup_values=TARGET_LOOKUP_VALUE,
|
|
2562
2573
|
cumulative_threshold=SUPER_MAJORITY_AREA_THRESHOLD
|
|
2563
2574
|
) or cumulative_nodes_match(
|
|
2564
2575
|
lambda node: get_node_property(node, LONG_FALLOW_CROP_TERM_ID, False).get("value", 0),
|
|
@@ -2573,7 +2584,7 @@ def _has_upland_rice(land_cover_nodes: list[dict]) -> bool:
|
|
|
2573
2584
|
|
|
2574
2585
|
Parameters
|
|
2575
2586
|
----------
|
|
2576
|
-
land_cover_nodes :
|
|
2587
|
+
land_cover_nodes : list[dict]
|
|
2577
2588
|
List of land cover nodes to be checked.
|
|
2578
2589
|
|
|
2579
2590
|
Returns
|
|
@@ -2589,63 +2600,39 @@ def _has_upland_rice(land_cover_nodes: list[dict]) -> bool:
|
|
|
2589
2600
|
|
|
2590
2601
|
|
|
2591
2602
|
IPCC_LAND_USE_CATEGORY_TO_VALIDATION_KWARGS = {
|
|
2603
|
+
IpccLandUseCategory.ANNUAL_CROPS_WET: {"has_wetland_soils"},
|
|
2592
2604
|
IpccLandUseCategory.SET_ASIDE: {"has_long_fallow"},
|
|
2593
|
-
IpccLandUseCategory.ANNUAL_CROPS_WET: {"has_wetland_soils"}
|
|
2594
2605
|
}
|
|
2595
2606
|
"""
|
|
2596
|
-
Keyword arguments that need to be
|
|
2607
|
+
Keyword arguments that need to be validated in addition to the `landCover` lookup match for specific
|
|
2608
|
+
`IpccLandUseCategory`s.
|
|
2597
2609
|
"""
|
|
2598
2610
|
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
----------
|
|
2606
|
-
key : IpccLandUseCategory
|
|
2607
|
-
The IPCC land use category to check.
|
|
2608
|
-
site_type : str
|
|
2609
|
-
The site type to check.
|
|
2610
|
-
|
|
2611
|
-
Keyword Args
|
|
2612
|
-
------------
|
|
2613
|
-
has_long_fallow : bool
|
|
2614
|
-
Indicates whether long fallow is present on more than 30% of the site.
|
|
2615
|
-
has_wetland_soils : bool
|
|
2616
|
-
Indicates whether wetland soils are present to more than 30% of the site.
|
|
2617
|
-
|
|
2618
|
-
Returns
|
|
2619
|
-
-------
|
|
2620
|
-
bool
|
|
2621
|
-
`True` if the conditions match the specified land use category, `False` otherwise.
|
|
2622
|
-
|
|
2623
|
-
"""
|
|
2624
|
-
target_site_type = IPCC_LAND_USE_CATEGORY_TO_SITE_TYPE.get(key, None)
|
|
2625
|
-
validation_kwargs = IPCC_LAND_USE_CATEGORY_TO_VALIDATION_KWARGS.get(key, set())
|
|
2626
|
-
valid_kwargs = all(v for k, v in kwargs.items() if k in validation_kwargs)
|
|
2627
|
-
return site_type == target_site_type and valid_kwargs
|
|
2611
|
+
IPCC_LAND_USE_CATEGORY_TO_OVERRIDE_KWARGS = {
|
|
2612
|
+
IpccLandUseCategory.PADDY_RICE_CULTIVATION: {"has_irrigated_upland_rice"}
|
|
2613
|
+
}
|
|
2614
|
+
"""
|
|
2615
|
+
Keyword arguments that can override the `landCover` lookup match for specific `IpccLandUseCategory`s.
|
|
2616
|
+
"""
|
|
2628
2617
|
|
|
2629
2618
|
|
|
2630
|
-
def
|
|
2631
|
-
*, key: IpccLandUseCategory, site_type: str, land_cover_nodes: list[dict], **kwargs
|
|
2632
|
-
) -> bool:
|
|
2619
|
+
def _check_ipcc_land_use_category(*, key: IpccLandUseCategory, land_cover_nodes: list[dict], **kwargs) -> bool:
|
|
2633
2620
|
"""
|
|
2634
|
-
Check if the
|
|
2635
|
-
|
|
2636
|
-
This function is special case of `_check_ipcc_land_use_category`.
|
|
2621
|
+
Check if the land cover nodes and keyword args satisfy the requirements for the given key.
|
|
2637
2622
|
|
|
2638
2623
|
Parameters
|
|
2639
2624
|
----------
|
|
2640
2625
|
key : IpccLandUseCategory
|
|
2641
2626
|
The IPCC land use category to check.
|
|
2642
|
-
|
|
2643
|
-
|
|
2627
|
+
land_cover_nodes : list[dict]
|
|
2628
|
+
List of land cover nodes to be checked.
|
|
2644
2629
|
|
|
2645
2630
|
Keyword Args
|
|
2646
2631
|
------------
|
|
2632
|
+
has_irrigated_upland_rice : bool
|
|
2633
|
+
Indicates whether irrigated upland rice is present on more than 30% of the site.
|
|
2647
2634
|
has_long_fallow : bool
|
|
2648
|
-
Indicates whether long fallow is present on more than
|
|
2635
|
+
Indicates whether long fallow is present on more than 70% of the site.
|
|
2649
2636
|
has_wetland_soils : bool
|
|
2650
2637
|
Indicates whether wetland soils are present to more than 30% of the site.
|
|
2651
2638
|
|
|
@@ -2662,48 +2649,23 @@ def _check_cropland_land_use_category(
|
|
|
2662
2649
|
target_lookup_values=target_lookup_values,
|
|
2663
2650
|
cumulative_threshold=MIN_AREA_THRESHOLD
|
|
2664
2651
|
)
|
|
2665
|
-
return _check_ipcc_land_use_category(key=key, site_type=site_type, **kwargs) and valid_lookup
|
|
2666
2652
|
|
|
2653
|
+
validation_kwargs = IPCC_LAND_USE_CATEGORY_TO_VALIDATION_KWARGS.get(key, set())
|
|
2654
|
+
valid_kwargs = all(v for k, v in kwargs.items() if k in validation_kwargs)
|
|
2667
2655
|
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
) -> bool:
|
|
2671
|
-
"""
|
|
2672
|
-
Check if the site type and land cover nodes match the target conditions for a cropland IpccLandUseCategory.
|
|
2656
|
+
override_kwargs = IPCC_LAND_USE_CATEGORY_TO_OVERRIDE_KWARGS.get(key, set())
|
|
2657
|
+
valid_override = any(v for k, v in kwargs.items() if k in override_kwargs)
|
|
2673
2658
|
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
Parameters
|
|
2677
|
-
----------
|
|
2678
|
-
key : IpccLandUseCategory
|
|
2679
|
-
The IPCC land use category to check.
|
|
2680
|
-
site_type : str
|
|
2681
|
-
The site type to check.
|
|
2682
|
-
|
|
2683
|
-
Keyword Args
|
|
2684
|
-
------------
|
|
2685
|
-
has_irrigated_upland_rice : bool
|
|
2686
|
-
Indicates whether irrigated upland rice is present on more than 30% of the site.
|
|
2687
|
-
has_long_fallow : bool
|
|
2688
|
-
Indicates whether long fallow is present on more than 30% of the site.
|
|
2689
|
-
has_wetland_soils : bool
|
|
2690
|
-
Indicates whether wetland soils are present to more than 30% of the site.
|
|
2691
|
-
|
|
2692
|
-
Returns
|
|
2693
|
-
-------
|
|
2694
|
-
bool
|
|
2695
|
-
`True` if the conditions match the specified land use category, `False` otherwise.
|
|
2696
|
-
"""
|
|
2697
|
-
return _check_cropland_land_use_category(key=key, site_type=site_type, **kwargs) or has_irrigated_upland_rice
|
|
2659
|
+
return (valid_lookup and valid_kwargs) or valid_override
|
|
2698
2660
|
|
|
2699
2661
|
|
|
2700
2662
|
LAND_USE_CATEGORY_DECISION_TREE = {
|
|
2701
2663
|
IpccLandUseCategory.GRASSLAND: _check_ipcc_land_use_category,
|
|
2702
2664
|
IpccLandUseCategory.SET_ASIDE: _check_ipcc_land_use_category,
|
|
2703
|
-
IpccLandUseCategory.PERENNIAL_CROPS:
|
|
2704
|
-
IpccLandUseCategory.PADDY_RICE_CULTIVATION:
|
|
2705
|
-
IpccLandUseCategory.ANNUAL_CROPS_WET:
|
|
2706
|
-
IpccLandUseCategory.ANNUAL_CROPS:
|
|
2665
|
+
IpccLandUseCategory.PERENNIAL_CROPS: _check_ipcc_land_use_category,
|
|
2666
|
+
IpccLandUseCategory.PADDY_RICE_CULTIVATION: _check_ipcc_land_use_category,
|
|
2667
|
+
IpccLandUseCategory.ANNUAL_CROPS_WET: _check_ipcc_land_use_category,
|
|
2668
|
+
IpccLandUseCategory.ANNUAL_CROPS: _check_ipcc_land_use_category,
|
|
2707
2669
|
IpccLandUseCategory.FOREST: _check_ipcc_land_use_category,
|
|
2708
2670
|
IpccLandUseCategory.NATIVE: _check_ipcc_land_use_category,
|
|
2709
2671
|
IpccLandUseCategory.OTHER: _check_ipcc_land_use_category
|
|
@@ -2712,21 +2674,19 @@ LAND_USE_CATEGORY_DECISION_TREE = {
|
|
|
2712
2674
|
A decision tree mapping IPCC soil categories to corresponding check functions.
|
|
2713
2675
|
|
|
2714
2676
|
Key: IpccLandUseCategory
|
|
2715
|
-
Value: Corresponding function for checking the match of the given land use category based on
|
|
2716
|
-
and
|
|
2677
|
+
Value: Corresponding function for checking the match of the given land use category based on land cover nodes
|
|
2678
|
+
and additional kwargs.
|
|
2717
2679
|
"""
|
|
2718
2680
|
|
|
2719
2681
|
|
|
2720
2682
|
def _assign_ipcc_land_use_category(
|
|
2721
|
-
|
|
2683
|
+
management_nodes: list[dict], ipcc_soil_category: IpccSoilCategory,
|
|
2722
2684
|
) -> IpccLandUseCategory:
|
|
2723
2685
|
"""
|
|
2724
|
-
Assigns IPCC land use category based on
|
|
2686
|
+
Assigns IPCC land use category based on management nodes and soil category.
|
|
2725
2687
|
|
|
2726
2688
|
Parameters
|
|
2727
2689
|
----------
|
|
2728
|
-
site_type : str
|
|
2729
|
-
The type of the site.
|
|
2730
2690
|
management_nodes : list[dict]
|
|
2731
2691
|
List of management nodes.
|
|
2732
2692
|
ipcc_soil_category : IpccSoilCategory
|
|
@@ -2749,14 +2709,13 @@ def _assign_ipcc_land_use_category(
|
|
|
2749
2709
|
has_long_fallow = _has_long_fallow(land_cover_nodes)
|
|
2750
2710
|
has_wetland_soils = ipcc_soil_category is IpccSoilCategory.WETLAND_SOILS
|
|
2751
2711
|
|
|
2752
|
-
should_run = bool(
|
|
2712
|
+
should_run = bool(land_cover_nodes)
|
|
2753
2713
|
|
|
2754
2714
|
return next(
|
|
2755
2715
|
(
|
|
2756
2716
|
key for key in DECISION_TREE
|
|
2757
2717
|
if DECISION_TREE[key](
|
|
2758
2718
|
key=key,
|
|
2759
|
-
site_type=site_type,
|
|
2760
2719
|
land_cover_nodes=land_cover_nodes,
|
|
2761
2720
|
has_long_fallow=has_long_fallow,
|
|
2762
2721
|
has_irrigated_upland_rice=has_irrigated_upland_rice,
|
|
@@ -2780,7 +2739,7 @@ def _check_grassland_ipcc_management_category(
|
|
|
2780
2739
|
----------
|
|
2781
2740
|
key : IpccManagementCategory
|
|
2782
2741
|
The IPCC management category to check.
|
|
2783
|
-
land_cover_nodes :
|
|
2742
|
+
land_cover_nodes : list[dict]
|
|
2784
2743
|
List of land cover nodes to be checked.
|
|
2785
2744
|
|
|
2786
2745
|
Returns
|
|
@@ -2806,7 +2765,7 @@ def _check_tillage_ipcc_management_category(
|
|
|
2806
2765
|
----------
|
|
2807
2766
|
key : IpccManagementCategory
|
|
2808
2767
|
The IPCC management category to check.
|
|
2809
|
-
tillage_nodes :
|
|
2768
|
+
tillage_nodes : list[dict]
|
|
2810
2769
|
List of tillage nodes to be checked.
|
|
2811
2770
|
|
|
2812
2771
|
Returns
|
|
@@ -3773,9 +3732,16 @@ def _should_run_inventory_year_tier_2(group: dict) -> bool:
|
|
|
3773
3732
|
}
|
|
3774
3733
|
)
|
|
3775
3734
|
|
|
3735
|
+
carbon_input_data_complete = all([
|
|
3736
|
+
group.get(_InventoryKey.CARBON_INPUT, 0) > 0,
|
|
3737
|
+
group.get(_InventoryKey.N_CONTENT, 0) > 0,
|
|
3738
|
+
group.get(_InventoryKey.LIGNIN_CONTENT, 0) > 0,
|
|
3739
|
+
])
|
|
3740
|
+
|
|
3776
3741
|
return all([
|
|
3777
3742
|
not group.get(_InventoryKey.IS_PADDY_RICE),
|
|
3778
3743
|
monthly_data_complete,
|
|
3744
|
+
carbon_input_data_complete,
|
|
3779
3745
|
all(key in group.keys() for key in REQUIRED_KEYS_TIER_2),
|
|
3780
3746
|
])
|
|
3781
3747
|
|
|
@@ -3783,11 +3749,15 @@ def _should_run_inventory_year_tier_2(group: dict) -> bool:
|
|
|
3783
3749
|
def _get_grouped_climate_measurements(grouped_measurements: dict) -> dict:
|
|
3784
3750
|
return {
|
|
3785
3751
|
year: {
|
|
3786
|
-
_InventoryKey.TEMP_MONTHLY:
|
|
3787
|
-
|
|
3752
|
+
_InventoryKey.TEMP_MONTHLY: non_empty_list(
|
|
3753
|
+
find_term_match(measurements, TEMPERATURE_MONTHLY_TERM_ID, {}).get("value", [])
|
|
3754
|
+
),
|
|
3755
|
+
_InventoryKey.PRECIP_MONTHLY: non_empty_list(
|
|
3788
3756
|
find_term_match(measurements, PRECIPITATION_MONTHLY_TERM_ID, {}).get("value", [])
|
|
3789
3757
|
),
|
|
3790
|
-
_InventoryKey.PET_MONTHLY:
|
|
3758
|
+
_InventoryKey.PET_MONTHLY: non_empty_list(
|
|
3759
|
+
find_term_match(measurements, PET_MONTHLY_TERM_ID, {}).get("value", [])
|
|
3760
|
+
)
|
|
3791
3761
|
} for year, measurements in grouped_measurements.items()
|
|
3792
3762
|
}
|
|
3793
3763
|
|
|
@@ -3917,15 +3887,19 @@ def _build_inventory_tier_1(
|
|
|
3917
3887
|
eco_climate_zone = _get_eco_climate_zone(measurement_nodes)
|
|
3918
3888
|
ipcc_soil_category = _assign_ipcc_soil_category(measurement_nodes)
|
|
3919
3889
|
soc_ref = _retrieve_soc_ref(eco_climate_zone, ipcc_soil_category)
|
|
3890
|
+
grouped_management = group_nodes_by_year(management_nodes)
|
|
3891
|
+
|
|
3892
|
+
# If no `landCover` nodes in `site.management` use `site.siteType` to assign static `IpccLandUseCategory`
|
|
3893
|
+
run_with_site_type = len(filter_list_term_type(management_nodes, [TermTermType.LANDCOVER])) == 0
|
|
3894
|
+
site_type_ipcc_land_use_category = SITE_TYPE_TO_IPCC_LAND_USE_CATEGORY.get(site_type, IpccLandUseCategory.OTHER)
|
|
3920
3895
|
|
|
3921
3896
|
grouped_management = group_nodes_by_year(management_nodes)
|
|
3922
3897
|
|
|
3923
3898
|
grouped_land_use_categories = {
|
|
3924
3899
|
year: {
|
|
3925
|
-
_InventoryKey.LU_CATEGORY:
|
|
3926
|
-
|
|
3927
|
-
nodes,
|
|
3928
|
-
ipcc_soil_category
|
|
3900
|
+
_InventoryKey.LU_CATEGORY: (
|
|
3901
|
+
site_type_ipcc_land_use_category if run_with_site_type
|
|
3902
|
+
else _assign_ipcc_land_use_category(nodes, ipcc_soil_category)
|
|
3929
3903
|
)
|
|
3930
3904
|
} for year, nodes in grouped_management.items()
|
|
3931
3905
|
}
|
|
@@ -3963,7 +3937,8 @@ def _build_inventory_tier_1(
|
|
|
3963
3937
|
kwargs = {
|
|
3964
3938
|
"eco_climate_zone": eco_climate_zone,
|
|
3965
3939
|
"ipcc_soil_category": ipcc_soil_category,
|
|
3966
|
-
"
|
|
3940
|
+
"run_with_site_type": run_with_site_type,
|
|
3941
|
+
"soc_ref": soc_ref
|
|
3967
3942
|
}
|
|
3968
3943
|
|
|
3969
3944
|
return inventory, kwargs
|
|
@@ -497,7 +497,8 @@ def _sum_values(values): return sum([value for term_id, value in values])
|
|
|
497
497
|
def _calculate_GE(cycle: dict, meanDE: float, system: dict):
|
|
498
498
|
animals = [
|
|
499
499
|
a for a in cycle.get('animals', []) if all([
|
|
500
|
-
a.get('value')
|
|
500
|
+
a.get('value'),
|
|
501
|
+
a.get('referencePeriod') == AnimalReferencePeriod.AVERAGE.value
|
|
501
502
|
])
|
|
502
503
|
]
|
|
503
504
|
|