hestia-earth-models 0.61.7__py3-none-any.whl → 0.61.8__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.

Files changed (43) hide show
  1. hestia_earth/models/cycle/completeness/electricityFuel.py +56 -0
  2. hestia_earth/models/emepEea2019/nh3ToAirInorganicFertiliser.py +44 -59
  3. hestia_earth/models/geospatialDatabase/histosol.py +4 -0
  4. hestia_earth/models/ipcc2006/co2ToAirOrganicSoilCultivation.py +4 -2
  5. hestia_earth/models/ipcc2006/n2OToAirOrganicSoilCultivationDirect.py +1 -1
  6. hestia_earth/models/ipcc2019/aboveGroundCropResidueTotal.py +1 -1
  7. hestia_earth/models/ipcc2019/belowGroundCropResidue.py +1 -1
  8. hestia_earth/models/ipcc2019/ch4ToAirExcreta.py +1 -1
  9. hestia_earth/models/ipcc2019/co2ToAirSoilOrganicCarbonStockChangeManagementChange.py +511 -458
  10. hestia_earth/models/ipcc2019/co2ToAirUreaHydrolysis.py +5 -1
  11. hestia_earth/models/ipcc2019/organicCarbonPerHa.py +117 -3881
  12. hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_1_utils.py +2060 -0
  13. hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_2_utils.py +1630 -0
  14. hestia_earth/models/ipcc2019/organicCarbonPerHa_utils.py +324 -0
  15. hestia_earth/models/mocking/search-results.json +252 -252
  16. hestia_earth/models/site/organicCarbonPerHa.py +58 -44
  17. hestia_earth/models/site/soilMeasurement.py +18 -13
  18. hestia_earth/models/utils/__init__.py +28 -0
  19. hestia_earth/models/utils/array_builders.py +578 -0
  20. hestia_earth/models/utils/blank_node.py +2 -3
  21. hestia_earth/models/utils/descriptive_stats.py +285 -0
  22. hestia_earth/models/utils/emission.py +73 -2
  23. hestia_earth/models/utils/inorganicFertiliser.py +2 -2
  24. hestia_earth/models/utils/measurement.py +118 -4
  25. hestia_earth/models/version.py +1 -1
  26. {hestia_earth_models-0.61.7.dist-info → hestia_earth_models-0.61.8.dist-info}/METADATA +1 -1
  27. {hestia_earth_models-0.61.7.dist-info → hestia_earth_models-0.61.8.dist-info}/RECORD +43 -31
  28. tests/models/cycle/completeness/test_electricityFuel.py +21 -0
  29. tests/models/emepEea2019/test_nh3ToAirInorganicFertiliser.py +2 -2
  30. tests/models/ipcc2019/test_co2ToAirSoilOrganicCarbonStockChangeManagementChange.py +54 -165
  31. tests/models/ipcc2019/test_organicCarbonPerHa.py +219 -460
  32. tests/models/ipcc2019/test_organicCarbonPerHa_tier_1_utils.py +471 -0
  33. tests/models/ipcc2019/test_organicCarbonPerHa_tier_2_utils.py +208 -0
  34. tests/models/ipcc2019/test_organicCarbonPerHa_utils.py +75 -0
  35. tests/models/site/test_organicCarbonPerHa.py +3 -12
  36. tests/models/site/test_soilMeasurement.py +3 -18
  37. tests/models/utils/test_array_builders.py +253 -0
  38. tests/models/utils/test_descriptive_stats.py +134 -0
  39. tests/models/utils/test_emission.py +51 -1
  40. tests/models/utils/test_measurement.py +54 -2
  41. {hestia_earth_models-0.61.7.dist-info → hestia_earth_models-0.61.8.dist-info}/LICENSE +0 -0
  42. {hestia_earth_models-0.61.7.dist-info → hestia_earth_models-0.61.8.dist-info}/WHEEL +0 -0
  43. {hestia_earth_models-0.61.7.dist-info → hestia_earth_models-0.61.8.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,324 @@
1
+ from enum import Enum
2
+ from functools import lru_cache
3
+ from numpy.typing import NDArray
4
+ from typing import NamedTuple, Optional
5
+
6
+ from hestia_earth.schema import MeasurementStatsDefinition, SiteSiteType
7
+
8
+ from hestia_earth.models.utils.array_builders import (
9
+ repeat_single, plus_minus_uncertainty_to_normal_1d, truncated_normal_1d
10
+ )
11
+ from hestia_earth.models.utils.blank_node import cumulative_nodes_term_match
12
+ from hestia_earth.models.utils.term import (
13
+ get_cover_crop_property_terms, get_crop_residue_incorporated_or_left_on_field_terms, get_irrigated_terms,
14
+ get_residue_removed_or_burnt_terms, get_upland_rice_crop_terms, get_upland_rice_land_cover_terms
15
+ )
16
+
17
+ STATS_DEFINITION = MeasurementStatsDefinition.SIMULATED.value
18
+ DEPTH_UPPER = 0
19
+ DEPTH_LOWER = 30
20
+
21
+ MIN_AREA_THRESHOLD = 30 # 30% as per IPCC guidelines
22
+ SUPER_MAJORITY_AREA_THRESHOLD = 100 - MIN_AREA_THRESHOLD
23
+ MIN_YIELD_THRESHOLD = 1
24
+
25
+
26
+ def get_cover_crop_property_terms_with_cache():
27
+ return lru_cache()(get_cover_crop_property_terms)()
28
+
29
+
30
+ def get_crop_residue_inc_or_left_terms_with_cache():
31
+ return lru_cache()(get_crop_residue_incorporated_or_left_on_field_terms)()
32
+
33
+
34
+ def get_irrigated_terms_with_cache():
35
+ return lru_cache()(get_irrigated_terms)()
36
+
37
+
38
+ def get_residue_removed_or_burnt_terms_with_cache():
39
+ return lru_cache()(get_residue_removed_or_burnt_terms)()
40
+
41
+
42
+ def get_upland_rice_crop_terms_with_cache():
43
+ return lru_cache()(get_upland_rice_crop_terms)()
44
+
45
+
46
+ def get_upland_rice_land_cover_terms_with_cache():
47
+ return lru_cache()(get_upland_rice_land_cover_terms)()
48
+
49
+
50
+ class EcoClimateZone(Enum):
51
+ """
52
+ Enum representing eco-climate zones. The value of each member of the Enum correctly corresponds with the values of
53
+ `ecoClimateZone` term and the `ecoClimateZone-lookup.csv`.
54
+ """
55
+ WARM_TEMPERATE_MOIST = 1
56
+ WARM_TEMPERATE_DRY = 2
57
+ COOL_TEMPERATE_MOIST = 3
58
+ COOL_TEMPERATE_DRY = 4
59
+ POLAR_MOIST = 5
60
+ POLAR_DRY = 6
61
+ BOREAL_MOIST = 7
62
+ BOREAL_DRY = 8
63
+ TROPICAL_MONTANE = 9
64
+ TROPICAL_WET = 10
65
+ TROPICAL_MOIST = 11
66
+ TROPICAL_DRY = 12
67
+
68
+
69
+ class IpccSoilCategory(Enum):
70
+ """
71
+ Enum representing IPCC Soil Categories.
72
+
73
+ See [IPCC (2019) Vol 4, Ch. 2 and 3](https://www.ipcc-nggip.iges.or.jp/public/2019rf/vol4.html) for more
74
+ information.
75
+ """
76
+ ORGANIC_SOILS = "organic soils"
77
+ SANDY_SOILS = "sandy soils"
78
+ WETLAND_SOILS = "wetland soils"
79
+ VOLCANIC_SOILS = "volcanic soils"
80
+ SPODIC_SOILS = "spodic soils"
81
+ HIGH_ACTIVITY_CLAY_SOILS = "high-activity clay soils"
82
+ LOW_ACTIVITY_CLAY_SOILS = "low-activity clay soils"
83
+
84
+
85
+ IPCC_SOIL_CATEGORY_TO_SOIL_TYPE_LOOKUP_VALUE = {
86
+ IpccSoilCategory.ORGANIC_SOILS: "Organic soils",
87
+ IpccSoilCategory.SANDY_SOILS: "Sandy soils",
88
+ IpccSoilCategory.WETLAND_SOILS: "Wetland soils",
89
+ IpccSoilCategory.VOLCANIC_SOILS: "Volcanic soils",
90
+ IpccSoilCategory.SPODIC_SOILS: "Spodic soils",
91
+ IpccSoilCategory.HIGH_ACTIVITY_CLAY_SOILS: "High-activity clay soils",
92
+ IpccSoilCategory.LOW_ACTIVITY_CLAY_SOILS: "Low-activity clay soils",
93
+ }
94
+ """
95
+ A dictionary mapping IPCC soil categories to corresponding soil type and USDA soil type lookup values in the
96
+ `"IPCC_SOIL_CATEGORY"` column.
97
+ """
98
+
99
+
100
+ class IpccLandUseCategory(Enum):
101
+ """
102
+ Enum representing IPCC Land Use Categories.
103
+
104
+ See [IPCC (2019) Vol 4](https://www.ipcc-nggip.iges.or.jp/public/2019rf/vol4.html) for more information.
105
+ """
106
+ GRASSLAND = "grassland"
107
+ PERENNIAL_CROPS = "perennial crops"
108
+ PADDY_RICE_CULTIVATION = "paddy rice cultivation"
109
+ ANNUAL_CROPS_WET = "annual crops (wet)"
110
+ ANNUAL_CROPS = "annual crops"
111
+ SET_ASIDE = "set aside"
112
+ FOREST = "forest"
113
+ NATIVE = "native"
114
+ OTHER = "other"
115
+
116
+
117
+ SITE_TYPE_TO_IPCC_LAND_USE_CATEGORY = {
118
+ SiteSiteType.PERMANENT_PASTURE.value: IpccLandUseCategory.GRASSLAND,
119
+ SiteSiteType.FOREST.value: IpccLandUseCategory.FOREST,
120
+ SiteSiteType.OTHER_NATURAL_VEGETATION.value: IpccLandUseCategory.NATIVE
121
+ }
122
+ """
123
+ A dictionary mapping site types to corresponding IPCC land use categories.
124
+ """
125
+
126
+ IPCC_LAND_USE_CATEGORY_TO_LAND_COVER_LOOKUP_VALUE = {
127
+ IpccLandUseCategory.GRASSLAND: "Grassland",
128
+ IpccLandUseCategory.PERENNIAL_CROPS: "Perennial crops",
129
+ IpccLandUseCategory.PADDY_RICE_CULTIVATION: "Paddy rice cultivation",
130
+ IpccLandUseCategory.ANNUAL_CROPS_WET: "Annual crops",
131
+ IpccLandUseCategory.ANNUAL_CROPS: "Annual crops",
132
+ IpccLandUseCategory.SET_ASIDE: [
133
+ "Annual crops", "Paddy rice cultivation", "Perennial crops", "Set aside"
134
+ ],
135
+ IpccLandUseCategory.FOREST: "Forest",
136
+ IpccLandUseCategory.NATIVE: "Native"
137
+ }
138
+ """
139
+ A dictionary mapping IPCC land use categories to corresponding land cover lookup values in the
140
+ `"IPCC_LAND_USE_CATEGORY"` column.
141
+ """
142
+
143
+
144
+ class IpccManagementCategory(Enum):
145
+ """
146
+ Enum representing IPCC Management Categories for grasslands and annual croplands.
147
+
148
+ See [IPCC (2019) Vol. 4, Ch. 5 and 6](https://www.ipcc-nggip.iges.or.jp/public/2019rf/vol4.html) for more
149
+ information.
150
+ """
151
+ SEVERELY_DEGRADED = "severely degraded"
152
+ IMPROVED_GRASSLAND = "improved grassland"
153
+ HIGH_INTENSITY_GRAZING = "high-intensity grazing"
154
+ NOMINALLY_MANAGED = "nominally managed"
155
+ FULL_TILLAGE = "full tillage"
156
+ REDUCED_TILLAGE = "reduced tillage"
157
+ NO_TILLAGE = "no tillage"
158
+ OTHER = "other"
159
+
160
+
161
+ IPCC_MANAGEMENT_CATEGORY_TO_GRASSLAND_MANAGEMENT_TERM_ID = {
162
+ IpccManagementCategory.SEVERELY_DEGRADED: "severelyDegradedPasture",
163
+ IpccManagementCategory.IMPROVED_GRASSLAND: "improvedPasture",
164
+ IpccManagementCategory.HIGH_INTENSITY_GRAZING: "highIntensityGrazingPasture",
165
+ IpccManagementCategory.NOMINALLY_MANAGED: "nominallyManagedPasture",
166
+ IpccManagementCategory.OTHER: "nativePasture"
167
+ }
168
+ """
169
+ A dictionary mapping IPCC management categories to corresponding grassland management term IDs from the land cover
170
+ glossary.
171
+ """
172
+
173
+
174
+ IPCC_MANAGEMENT_CATEGORY_TO_TILLAGE_MANAGEMENT_LOOKUP_VALUE = {
175
+ IpccManagementCategory.FULL_TILLAGE: "Full tillage",
176
+ IpccManagementCategory.REDUCED_TILLAGE: "Reduced tillage",
177
+ IpccManagementCategory.NO_TILLAGE: "No tillage"
178
+ }
179
+ """
180
+ A dictionary mapping IPCC management categories to corresponding tillage lookup values in the
181
+ `"IPCC_TILLAGE_MANAGEMENT_CATEGORY" column`.
182
+ """
183
+
184
+
185
+ class IpccCarbonInputCategory(Enum):
186
+ """
187
+ Enum representing IPCC Carbon Input Categories for improved grasslands and annual croplands.
188
+
189
+ See [IPCC (2019) Vol. 4, Ch. 4, 5 and 6](https://www.ipcc-nggip.iges.or.jp/public/2019rf/vol4.html) for more
190
+ information.
191
+ """
192
+ GRASSLAND_HIGH = "grassland high"
193
+ GRASSLAND_MEDIUM = "grassland medium"
194
+ CROPLAND_HIGH_WITH_MANURE = "cropland high (with manure)"
195
+ CROPLAND_HIGH_WITHOUT_MANURE = "cropland high (without manure)"
196
+ CROPLAND_MEDIUM = "cropland medium"
197
+ CROPLAND_LOW = "cropland low"
198
+ OTHER = "other"
199
+
200
+
201
+ CarbonSource = NamedTuple(
202
+ "CarbonSource",
203
+ [
204
+ ("mass", float),
205
+ ("carbon_content", float),
206
+ ("nitrogen_content", float),
207
+ ("lignin_content", float),
208
+ ]
209
+ )
210
+ """
211
+ A single carbon source (e.g. crop residues or organic amendment).
212
+
213
+ Attributes
214
+ -----------
215
+ mass : float
216
+ The dry-matter mass of the carbon source, kg ha-1
217
+ carbon_content : float
218
+ The carbon content of the carbon source, decimal proportion, kg C (kg d.m.)-1.
219
+ nitrogen_content : float
220
+ The nitrogen content of the carbon source, decimal_proportion, kg N (kg d.m.)-1.
221
+ lignin_content : float
222
+ The lignin content of the carbon source, decimal_proportion, kg lignin (kg d.m.)-1.
223
+ """
224
+
225
+
226
+ def check_consecutive(ints: list[int]) -> bool:
227
+ """
228
+ Checks whether a list of integers are consecutive.
229
+
230
+ Used to determine whether annualised data is complete from every year from beggining to end.
231
+
232
+ Parameters
233
+ ----------
234
+ ints : list[int]
235
+ A list of integer values.
236
+
237
+ Returns
238
+ -------
239
+ bool
240
+ Whether or not the list of integers is consecutive.
241
+ """
242
+ range_list = list(range(min(ints), max(ints)+1)) if ints else []
243
+ return all(a == b for a, b in zip(ints, range_list))
244
+
245
+
246
+ def check_irrigation(water_regime_nodes: list[dict]) -> bool:
247
+ """
248
+ Check if irrigation is present in the water regime nodes.
249
+
250
+ Parameters
251
+ ----------
252
+ water_regime_nodes : list[dict]
253
+ List of water regime nodes to be checked.
254
+
255
+ Returns
256
+ -------
257
+ bool
258
+ `True` if irrigation is present, `False` otherwise.
259
+ """
260
+ return cumulative_nodes_term_match(
261
+ water_regime_nodes,
262
+ target_term_ids=get_irrigated_terms_with_cache(),
263
+ cumulative_threshold=MIN_AREA_THRESHOLD
264
+ )
265
+
266
+
267
+ def sample_truncated_normal(
268
+ *, iterations: int, value: float, sd: float, min: float, max: float, seed: Optional[int] = None, **_
269
+ ) -> NDArray:
270
+ """Randomly sample a model parameter with a truncated normal distribution."""
271
+ return truncated_normal_1d(shape=(1, iterations), mu=value, sigma=sd, low=min, high=max, seed=seed)
272
+
273
+
274
+ def sample_plus_minus_uncertainty(
275
+ *, iterations: int, value: float, uncertainty: float, seed: Optional[int] = None, **_
276
+ ) -> NDArray:
277
+ """Randomly sample a model parameter with a plus/minus uncertainty distribution."""
278
+ return plus_minus_uncertainty_to_normal_1d(shape=(1, iterations), value=value, uncertainty=uncertainty, seed=seed)
279
+
280
+
281
+ def sample_plus_minus_error(
282
+ *, iterations: int, value: float, error: float, seed: Optional[int] = None, **_
283
+ ) -> NDArray:
284
+ """Randomly sample a model parameter with a truncated normal distribution described using plus/minus error."""
285
+ sd = value * (error / 200)
286
+ low = value - (value * (error / 100))
287
+ high = value + (value * (error / 100))
288
+ return truncated_normal_1d(shape=(1, iterations), mu=value, sigma=sd, low=low, high=high, seed=seed)
289
+
290
+
291
+ def sample_constant(*, iterations: int, value: float, **_) -> NDArray:
292
+ """Sample a constant model parameter."""
293
+ return repeat_single(shape=(1, iterations), value=value)
294
+
295
+
296
+ def format_bool(value: Optional[bool]) -> str:
297
+ """Format a bool for logging in a table."""
298
+ return str(bool(value))
299
+
300
+
301
+ def format_number(value: Optional[float]) -> str:
302
+ """Format a float for logging in a table."""
303
+ return f"{value:.1f}" if isinstance(value, (float, int)) else "None"
304
+
305
+
306
+ def format_enum(value: Optional[Enum]) -> str:
307
+ """Format an enum for logging in a table."""
308
+ return value.value if isinstance(value, Enum) else "None"
309
+
310
+
311
+ def format_bool_list(values: Optional[list[bool]]) -> str:
312
+ """Format a list of bools for logging in a table."""
313
+ return (
314
+ " ".join(format_bool(value) for value in values) or "None" if isinstance(values, list)
315
+ else "None"
316
+ )
317
+
318
+
319
+ def format_number_list(values: Optional[list[float]]) -> str:
320
+ """Format a list of floats for logging in a table."""
321
+ return (
322
+ " ".join(format_number(value) for value in values) or "None"if isinstance(values, list)
323
+ else "None"
324
+ )