hestia-earth-models 0.63.0__py3-none-any.whl → 0.64.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.

Files changed (53) hide show
  1. hestia_earth/models/cycle/unknownPreSeasonWaterRegime.py +51 -0
  2. hestia_earth/models/ecoinventV3/__init__.py +18 -2
  3. hestia_earth/models/faostat2018/landTransformationFromCropland100YearAverage.py +1 -1
  4. hestia_earth/models/faostat2018/landTransformationFromCropland20YearAverage.py +1 -1
  5. hestia_earth/models/faostat2018/utils.py +2 -2
  6. hestia_earth/models/geospatialDatabase/clayContent.py +44 -17
  7. hestia_earth/models/geospatialDatabase/organicCarbonPerKgSoil.py +43 -17
  8. hestia_earth/models/geospatialDatabase/sandContent.py +43 -16
  9. hestia_earth/models/geospatialDatabase/siltContent.py +58 -18
  10. hestia_earth/models/geospatialDatabase/soilPh.py +43 -16
  11. hestia_earth/models/geospatialDatabase/totalNitrogenPerKgSoil.py +45 -15
  12. hestia_earth/models/geospatialDatabase/utils.py +11 -5
  13. hestia_earth/models/hyde32/landTransformationFromCropland100YearAverageDuringCycle.py +2 -1
  14. hestia_earth/models/hyde32/landTransformationFromCropland20YearAverageDuringCycle.py +2 -1
  15. hestia_earth/models/hyde32/landTransformationFromForest100YearAverageDuringCycle.py +2 -1
  16. hestia_earth/models/hyde32/landTransformationFromForest20YearAverageDuringCycle.py +2 -1
  17. hestia_earth/models/hyde32/landTransformationFromOtherNaturalVegetation100YearAverageDuringCycle.py +2 -1
  18. hestia_earth/models/hyde32/landTransformationFromOtherNaturalVegetation20YearAverageDuringCycle.py +2 -1
  19. hestia_earth/models/hyde32/landTransformationFromPermanentPasture100YearAverageDuringCycle.py +2 -1
  20. hestia_earth/models/hyde32/landTransformationFromPermanentPasture20YearAverageDuringCycle.py +2 -1
  21. hestia_earth/models/hyde32/utils.py +7 -4
  22. hestia_earth/models/impact_assessment/allocationMethod.py +39 -0
  23. hestia_earth/models/impact_assessment/emissions.py +3 -1
  24. hestia_earth/models/mocking/search-results.json +60 -18
  25. hestia_earth/models/site/management.py +15 -1
  26. hestia_earth/models/site/pre_checks/cache_geospatialDatabase.py +23 -16
  27. hestia_earth/models/utils/indicator.py +3 -1
  28. hestia_earth/models/utils/term.py +34 -0
  29. hestia_earth/models/version.py +1 -1
  30. {hestia_earth_models-0.63.0.dist-info → hestia_earth_models-0.64.0.dist-info}/METADATA +2 -2
  31. {hestia_earth_models-0.63.0.dist-info → hestia_earth_models-0.64.0.dist-info}/RECORD +53 -49
  32. tests/models/cycle/test_unknownPreSeasonWaterRegime.py +36 -0
  33. tests/models/geospatialDatabase/test_clayContent.py +16 -2
  34. tests/models/geospatialDatabase/test_organicCarbonPerKgSoil.py +16 -2
  35. tests/models/geospatialDatabase/test_sandContent.py +16 -2
  36. tests/models/geospatialDatabase/test_siltContent.py +2 -2
  37. tests/models/geospatialDatabase/test_soilPh.py +16 -2
  38. tests/models/geospatialDatabase/test_totalNitrogenPerKgSoil.py +16 -2
  39. tests/models/hyde32/test_landTransformationFromCropland100YearAverageDuringCycle.py +1 -0
  40. tests/models/hyde32/test_landTransformationFromCropland20YearAverageDuringCycle.py +1 -0
  41. tests/models/hyde32/test_landTransformationFromForest100YearAverageDuringCycle.py +1 -0
  42. tests/models/hyde32/test_landTransformationFromForest20YearAverageDuringCycle.py +1 -0
  43. tests/models/hyde32/test_landTransformationFromOtherNaturalVegetation100YearAverageDuringCycle.py +1 -0
  44. tests/models/hyde32/test_landTransformationFromOtherNaturalVegetation20YearAverageDuringCycle.py +1 -0
  45. tests/models/hyde32/test_landTransformationFromPermanentPasture100YearAverageDuringCycle.py +1 -0
  46. tests/models/hyde32/test_landTransformationFromPermanentPasture20YearAverageDuringCycle.py +1 -0
  47. tests/models/impact_assessment/test_allocationMethod.py +48 -0
  48. tests/models/test_cache_sites.py +10 -4
  49. tests/models/test_ecoinventV3.py +1 -0
  50. tests/models/utils/test_source.py +1 -1
  51. {hestia_earth_models-0.63.0.dist-info → hestia_earth_models-0.64.0.dist-info}/LICENSE +0 -0
  52. {hestia_earth_models-0.63.0.dist-info → hestia_earth_models-0.64.0.dist-info}/WHEEL +0 -0
  53. {hestia_earth_models-0.63.0.dist-info → hestia_earth_models-0.64.0.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,5 @@
1
1
  from hestia_earth.schema import MeasurementMethodClassification
2
- from hestia_earth.utils.tools import safe_parse_float
2
+ from hestia_earth.utils.tools import safe_parse_float, non_empty_list
3
3
 
4
4
  from hestia_earth.models.log import logRequirements, logShouldRun
5
5
  from hestia_earth.models.utils.measurement import _new_measurement
@@ -19,33 +19,63 @@ REQUIREMENTS = {
19
19
  RETURNS = {
20
20
  "Measurement": [{
21
21
  "value": "",
22
- "depthUpper": "0",
23
- "depthLower": "50",
22
+ "depthUpper": "",
23
+ "depthLower": "",
24
24
  "methodClassification": "geospatial dataset"
25
25
  }]
26
26
  }
27
27
  TERM_ID = 'totalNitrogenPerKgSoil'
28
- EE_PARAMS = {
29
- 'collection': 'T_N',
30
- 'ee_type': 'raster',
31
- 'reducer': 'mean'
32
- }
33
- BIBLIO_TITLE = 'Harmonized soil property values for broad-scale modelling (WISE30sec) '
34
- 'with estimates of global soil carbon stocks'
28
+ EE_PARAMS = [
29
+ {
30
+ 'collection': 'T_N_v2_depth_1',
31
+ 'ee_type': 'raster',
32
+ 'reducer': 'mean',
33
+ 'depthUpper': 0,
34
+ 'depthLower': 20
35
+ },
36
+ {
37
+ 'collection': 'T_N_v2_depth_2',
38
+ 'ee_type': 'raster',
39
+ 'reducer': 'mean',
40
+ 'depthUpper': 20,
41
+ 'depthLower': 40
42
+ },
43
+ {
44
+ 'collection': 'T_N_v2_depth_3',
45
+ 'ee_type': 'raster',
46
+ 'reducer': 'mean',
47
+ 'depthUpper': 40,
48
+ 'depthLower': 60
49
+ },
50
+ {
51
+ 'collection': 'T_N_v2_depth_4',
52
+ 'ee_type': 'raster',
53
+ 'reducer': 'mean',
54
+ 'depthUpper': 60,
55
+ 'depthLower': 80
56
+ }
57
+ ]
58
+ BIBLIO_TITLE = 'Harmonized World Soil Database Version 2.0.'
35
59
 
36
60
 
37
- def _measurement(site: dict, value: float):
61
+ def _measurement(site: dict, value: int, depthUpper: int, depthLower: int):
38
62
  measurement = _new_measurement(TERM_ID)
39
63
  measurement['value'] = [value]
40
- measurement['depthUpper'] = 0
41
- measurement['depthLower'] = 50
64
+ measurement['depthUpper'] = depthUpper
65
+ measurement['depthLower'] = depthLower
42
66
  measurement['methodClassification'] = MeasurementMethodClassification.GEOSPATIAL_DATASET.value
43
67
  return measurement | get_source(site, BIBLIO_TITLE)
44
68
 
45
69
 
70
+ def _run_depths(site: dict, params: dict):
71
+ value = download(TERM_ID, site, params)
72
+ return None if value is None else (
73
+ _measurement(site, safe_parse_float(value), params.get('depthUpper'), params.get('depthLower'))
74
+ )
75
+
76
+
46
77
  def _run(site: dict):
47
- value = download(TERM_ID, site, EE_PARAMS)
48
- return [_measurement(site, safe_parse_float(value))] if value is not None else []
78
+ return non_empty_list([_run_depths(site, params) for params in EE_PARAMS])
49
79
 
50
80
 
51
81
  def _should_run(site: dict):
@@ -134,13 +134,19 @@ def _parse_run_query(term: str, query: dict):
134
134
  return None
135
135
 
136
136
 
137
+ def _cache_sub_key(collection: dict):
138
+ return '-'.join(non_empty_list([
139
+ str(collection.get('year', '')),
140
+ str(collection.get('start_date', '')),
141
+ str(collection.get('end_date', '')),
142
+ str(collection.get('depthUpper', '')),
143
+ str(collection.get('depthLower', ''))
144
+ ]))
145
+
146
+
137
147
  def _get_cached_data(term: str, site: dict, data: dict):
138
148
  cache = _cached_value(site, term)
139
- cache_sub_key = '-'.join(non_empty_list([
140
- data.get('year'),
141
- data.get('start_date'),
142
- data.get('end_date')
143
- ]))
149
+ cache_sub_key = _cache_sub_key(data)
144
150
  # data can be grouped by year when required
145
151
  value = cache.get(cache_sub_key) if (
146
152
  isinstance(cache, dict) and cache_sub_key in cache and cache is not None
@@ -50,7 +50,8 @@ LOOKUPS = {
50
50
  }
51
51
  RETURNS = {
52
52
  "Indicator": [{
53
- "value": ""
53
+ "value": "",
54
+ "landCover": ""
54
55
  }]
55
56
  }
56
57
  TERM_ID = 'landTransformationFromCropland100YearAverageDuringCycle'
@@ -50,7 +50,8 @@ LOOKUPS = {
50
50
  }
51
51
  RETURNS = {
52
52
  "Indicator": [{
53
- "value": ""
53
+ "value": "",
54
+ "landCover": ""
54
55
  }]
55
56
  }
56
57
  TERM_ID = 'landTransformationFromCropland20YearAverageDuringCycle'
@@ -50,7 +50,8 @@ LOOKUPS = {
50
50
  }
51
51
  RETURNS = {
52
52
  "Indicator": [{
53
- "value": ""
53
+ "value": "",
54
+ "landCover": ""
54
55
  }]
55
56
  }
56
57
  TERM_ID = 'landTransformationFromForest100YearAverageDuringCycle'
@@ -50,7 +50,8 @@ LOOKUPS = {
50
50
  }
51
51
  RETURNS = {
52
52
  "Indicator": [{
53
- "value": ""
53
+ "value": "",
54
+ "landCover": ""
54
55
  }]
55
56
  }
56
57
  TERM_ID = 'landTransformationFromForest20YearAverageDuringCycle'
@@ -50,7 +50,8 @@ LOOKUPS = {
50
50
  }
51
51
  RETURNS = {
52
52
  "Indicator": [{
53
- "value": ""
53
+ "value": "",
54
+ "landCover": ""
54
55
  }]
55
56
  }
56
57
  TERM_ID = 'landTransformationFromOtherNaturalVegetation100YearAverageDuringCycle'
@@ -50,7 +50,8 @@ LOOKUPS = {
50
50
  }
51
51
  RETURNS = {
52
52
  "Indicator": [{
53
- "value": ""
53
+ "value": "",
54
+ "landCover": ""
54
55
  }]
55
56
  }
56
57
  TERM_ID = 'landTransformationFromOtherNaturalVegetation20YearAverageDuringCycle'
@@ -50,7 +50,8 @@ LOOKUPS = {
50
50
  }
51
51
  RETURNS = {
52
52
  "Indicator": [{
53
- "value": ""
53
+ "value": "",
54
+ "landCover": ""
54
55
  }]
55
56
  }
56
57
  TERM_ID = 'landTransformationFromPermanentPasture100YearAverageDuringCycle'
@@ -50,7 +50,8 @@ LOOKUPS = {
50
50
  }
51
51
  RETURNS = {
52
52
  "Indicator": [{
53
- "value": ""
53
+ "value": "",
54
+ "landCover": ""
54
55
  }]
55
56
  }
56
57
  TERM_ID = 'landTransformationFromPermanentPasture20YearAverageDuringCycle'
@@ -6,6 +6,7 @@ from hestia_earth.models.log import debugMissingLookup, debugValues, logRequirem
6
6
  from hestia_earth.models.utils.indicator import _new_indicator
7
7
  from hestia_earth.models.utils.impact_assessment import get_product, get_site, get_region_id
8
8
  from hestia_earth.models.utils.cycle import land_occupation_per_kg
9
+ from hestia_earth.models.utils.site import get_land_cover_term_id
9
10
  from . import MODEL
10
11
 
11
12
 
@@ -28,17 +29,19 @@ def _get_emission_factor(term_id: str, impact_assessment: dict, average_years: s
28
29
  return safe_parse_float(extract_grouped_data_closest_date(value, end_date.year), None) if end_date else None
29
30
 
30
31
 
31
- def _indicator(term_id: str, value: float):
32
- indicator = _new_indicator(term_id, MODEL)
32
+ def _indicator(term_id: str, value: float, land_covert_term_id: str):
33
+ indicator = _new_indicator(term_id, MODEL, land_covert_term_id)
33
34
  indicator['value'] = value
34
35
  return indicator
35
36
 
36
37
 
37
38
  def _run(impact_assessment: dict, term_id: str, land_occupation_m2: float, factor: float):
39
+ land_covert_term_id = get_land_cover_term_id(get_site(impact_assessment).get('siteType'))
38
40
  value = land_occupation_m2 * (factor or 0)
39
41
  debugValues(impact_assessment, model=MODEL, term=term_id,
40
- value=value)
41
- return _indicator(term_id, value)
42
+ value=value,
43
+ land_covert_term_id=land_covert_term_id)
44
+ return _indicator(term_id, value, land_covert_term_id)
42
45
 
43
46
 
44
47
  def _should_run(impact_assessment: dict, term_id: str, from_site_type: SiteSiteType, years: int):
@@ -0,0 +1,39 @@
1
+ """
2
+ Allocation Method
3
+
4
+ If any of the impact `emissionsResourceUse`, `impacts`, or `endpoints`, have been modified by the calculations,
5
+ the `allocationMethod` will be set to `economic`.
6
+ """
7
+ from hestia_earth.schema import ImpactAssessmentAllocationMethod
8
+
9
+ from hestia_earth.models.log import logShouldRun, logRequirements
10
+ from . import MODEL
11
+
12
+ REQUIREMENTS = {
13
+ "ImpactAssessment": {
14
+ "updated": ["emissionsResourceUse", "impacts", "endpoints"],
15
+ "added": ["emissionsResourceUse", "impacts", "endpoints"]
16
+ }
17
+ }
18
+ RETURNS = {
19
+ "`economic` if any indicators were updated or added by the HESTIA models": ""
20
+ }
21
+
22
+ MODEL_KEY = 'allocationMethod'
23
+ _MODIFIED_KEYS = ["emissionsResourceUse", "impacts", "endpoints"]
24
+
25
+
26
+ def _should_run(impact: dict):
27
+ modified = impact.get('updated', []) + impact.get('added', [])
28
+ is_modified_by_hestia = any([key for key in _MODIFIED_KEYS if key in modified])
29
+
30
+ logRequirements(impact, model=MODEL, key=MODEL_KEY,
31
+ is_modified_by_hestia=is_modified_by_hestia)
32
+
33
+ should_run = all([is_modified_by_hestia])
34
+ logShouldRun(impact, MODEL, None, should_run, key=MODEL_KEY)
35
+ return should_run
36
+
37
+
38
+ def run(impact: dict):
39
+ return ImpactAssessmentAllocationMethod.ECONOMIC.value if _should_run(impact) else None
@@ -31,7 +31,8 @@ REQUIREMENTS = {
31
31
  RETURNS = {
32
32
  "Indicator": [{
33
33
  "term": "",
34
- "value": ""
34
+ "value": "",
35
+ "methodTier": ""
35
36
  }]
36
37
  }
37
38
  MODEL_KEY = 'emissions'
@@ -44,6 +45,7 @@ def _indicator(product: dict):
44
45
 
45
46
  indicator = _new_indicator(emission.get('term', {}), emission.get('methodModel'))
46
47
  indicator['value'] = value
48
+ indicator['methodTier'] = emission.get('methodTier')
47
49
 
48
50
  if len(emission.get('inputs', [])):
49
51
  indicator['inputs'] = emission['inputs']
@@ -979,11 +979,11 @@
979
979
  },
980
980
  {
981
981
  "@type": "Term",
982
- "@id": "shortFallowCrop"
982
+ "@id": "longFallowCrop"
983
983
  },
984
984
  {
985
985
  "@type": "Term",
986
- "@id": "longFallowCrop"
986
+ "@id": "shortFallowCrop"
987
987
  }
988
988
  ]
989
989
  },
@@ -1058,11 +1058,11 @@
1058
1058
  },
1059
1059
  {
1060
1060
  "@type": "Term",
1061
- "@id": "residueIncorporatedMoreThan30DaysBeforeCultivation"
1061
+ "@id": "residueRemoved"
1062
1062
  },
1063
1063
  {
1064
1064
  "@type": "Term",
1065
- "@id": "residueRemoved"
1065
+ "@id": "residueIncorporatedMoreThan30DaysBeforeCultivation"
1066
1066
  },
1067
1067
  {
1068
1068
  "@type": "Term",
@@ -1475,6 +1475,48 @@
1475
1475
  }
1476
1476
  ]
1477
1477
  },
1478
+ {
1479
+ "name": "get_flooded_pre_season_terms",
1480
+ "query": {
1481
+ "bool": {
1482
+ "must": [
1483
+ {
1484
+ "match": {
1485
+ "@type": "Term"
1486
+ }
1487
+ },
1488
+ {
1489
+ "match": {
1490
+ "termType": "landUseManagement"
1491
+ }
1492
+ },
1493
+ {
1494
+ "match_phrase": {
1495
+ "name": "flooded pre-season"
1496
+ }
1497
+ }
1498
+ ]
1499
+ }
1500
+ },
1501
+ "results": [
1502
+ {
1503
+ "@type": "Term",
1504
+ "@id": "floodedPreSeasonMoreThan30Days"
1505
+ },
1506
+ {
1507
+ "@type": "Term",
1508
+ "@id": "nonFloodedPreSeasonMoreThan180Days"
1509
+ },
1510
+ {
1511
+ "@type": "Term",
1512
+ "@id": "nonFloodedPreSeasonLessThan180Days"
1513
+ },
1514
+ {
1515
+ "@type": "Term",
1516
+ "@id": "nonFloodedPreSeasonMoreThan365Days"
1517
+ }
1518
+ ]
1519
+ },
1478
1520
  {
1479
1521
  "name": "get_generic_crop",
1480
1522
  "query": {
@@ -1486,7 +1528,7 @@
1486
1528
  "@type": "Term",
1487
1529
  "name": "Generic crop, seed",
1488
1530
  "@id": "genericCropSeed",
1489
- "_score": 26.36456
1531
+ "_score": 26.448057
1490
1532
  }
1491
1533
  ]
1492
1534
  },
@@ -1722,61 +1764,61 @@
1722
1764
  "@type": "Term",
1723
1765
  "name": "Glass or high accessible cover",
1724
1766
  "@id": "glassOrHighAccessibleCover",
1725
- "_score": 59.78251
1767
+ "_score": 59.747684
1726
1768
  },
1727
1769
  {
1728
1770
  "@type": "Term",
1729
1771
  "name": "River or stream",
1730
1772
  "@id": "riverOrStream",
1731
- "_score": 51.118263
1773
+ "_score": 51.048874
1732
1774
  },
1733
1775
  {
1734
1776
  "@type": "Term",
1735
1777
  "name": "Other natural vegetation",
1736
1778
  "@id": "otherNaturalVegetation",
1737
- "_score": 41.25843
1779
+ "_score": 41.325626
1738
1780
  },
1739
1781
  {
1740
1782
  "@type": "Term",
1741
1783
  "name": "Natural forest",
1742
1784
  "@id": "naturalForest",
1743
- "_score": 31.747753
1785
+ "_score": 31.698704
1744
1786
  },
1745
1787
  {
1746
1788
  "@type": "Term",
1747
1789
  "name": "Permanent pasture",
1748
1790
  "@id": "permanentPasture",
1749
- "_score": 28.454437
1791
+ "_score": 28.502478
1750
1792
  },
1751
1793
  {
1752
1794
  "@type": "Term",
1753
1795
  "name": "Animal housing",
1754
1796
  "@id": "animalHousing",
1755
- "_score": 27.424242
1797
+ "_score": 27.39837
1756
1798
  },
1757
1799
  {
1758
1800
  "@type": "Term",
1759
1801
  "name": "Root or tuber crop plant",
1760
1802
  "@id": "rootOrTuberCropPlant",
1761
- "_score": 25.260658
1803
+ "_score": 25.22627
1762
1804
  },
1763
1805
  {
1764
1806
  "@type": "Term",
1765
1807
  "name": "High intensity grazing pasture",
1766
1808
  "@id": "highIntensityGrazingPasture",
1767
- "_score": 24.038225
1809
+ "_score": 24.007807
1768
1810
  },
1769
1811
  {
1770
1812
  "@type": "Term",
1771
1813
  "name": "Permanent cropland",
1772
1814
  "@id": "permanentCropland",
1773
- "_score": 20.689457
1815
+ "_score": 20.544846
1774
1816
  },
1775
1817
  {
1776
1818
  "@type": "Term",
1777
1819
  "name": "Forest",
1778
1820
  "@id": "forest",
1779
- "_score": 20.366226
1821
+ "_score": 20.397137
1780
1822
  }
1781
1823
  ]
1782
1824
  },
@@ -2024,15 +2066,15 @@
2024
2066
  "results": [
2025
2067
  {
2026
2068
  "@type": "Term",
2027
- "@id": "noTillage"
2069
+ "@id": "verticalTillage"
2028
2070
  },
2029
2071
  {
2030
2072
  "@type": "Term",
2031
- "@id": "ridgeTillage"
2073
+ "@id": "noTillage"
2032
2074
  },
2033
2075
  {
2034
2076
  "@type": "Term",
2035
- "@id": "verticalTillage"
2077
+ "@id": "ridgeTillage"
2036
2078
  },
2037
2079
  {
2038
2080
  "@type": "Term",
@@ -85,7 +85,8 @@ LOOKUPS = {
85
85
  "forage": ["landCoverTermId"],
86
86
  "inorganicFertiliser": "nitrogenContent",
87
87
  "organicFertiliser": "ANIMAL_MANURE",
88
- "soilAmendment": "PRACTICE_INCREASING_C_INPUT"
88
+ "soilAmendment": "PRACTICE_INCREASING_C_INPUT",
89
+ "landUseManagement": "GAP_FILL_TO_MANAGEMENT"
89
90
  }
90
91
  MODEL_KEY = 'management'
91
92
  LAND_COVER_KEY = LOOKUPS['crop'][0]
@@ -216,6 +217,18 @@ def _get_relevant_inputs(cycles: list[dict]) -> list:
216
217
  return relevant_inputs
217
218
 
218
219
 
220
+ def _has_gap_fill_to_management_set(practices: list) -> list:
221
+ """
222
+ Include only landUseManagement practices where GAP_FILL_TO_MANAGEMENT = True
223
+ """
224
+ result = [
225
+ p for p in practices
226
+ if p.get("term", {}).get("termType", {}) != TermTermType.LANDUSEMANAGEMENT.value
227
+ or get_lookup_value(lookup_term=p.get("term", {}), column=LOOKUPS["landUseManagement"])
228
+ ]
229
+ return result
230
+
231
+
219
232
  def _should_run_all_products(cycles: list, site_type: str):
220
233
  products_land_cover = [
221
234
  _extract_node_value(
@@ -292,6 +305,7 @@ def _should_run(site: dict):
292
305
  ]
293
306
  )
294
307
  ]
308
+ practices = _has_gap_fill_to_management_set(practices)
295
309
  practices = condense_nodes(practices)
296
310
 
297
311
  relevant_inputs = _get_relevant_inputs(cycles)
@@ -3,15 +3,16 @@ Pre Checks Cache Geospatial Database
3
3
 
4
4
  This model caches results from Geospatial Database.
5
5
  """
6
+ from typing import Union, List
6
7
  from functools import reduce
7
- from hestia_earth.utils.tools import flatten, non_empty_list
8
+ from hestia_earth.utils.tools import flatten
8
9
 
9
10
  from hestia_earth.models.log import debugValues
10
11
  from hestia_earth.models.utils import CACHE_KEY, cached_value, first_day_of_month, last_day_of_month
11
12
  from hestia_earth.models.utils.site import CACHE_YEARS_KEY
12
13
  from hestia_earth.models.geospatialDatabase.utils import (
13
14
  MAX_AREA_SIZE, CACHE_VALUE, CACHE_AREA_SIZE,
14
- has_geospatial_data, has_coordinates, get_area_size, geospatial_data, _run_query, _collection_name
15
+ has_geospatial_data, has_coordinates, get_area_size, geospatial_data, _run_query, _collection_name, _cache_sub_key
15
16
  )
16
17
  from hestia_earth.models.geospatialDatabase import list_ee_params
17
18
 
@@ -34,11 +35,7 @@ def cache_site_results(results: list, collections: list, area_size: int = None):
34
35
  collection = collections[index]
35
36
  name = collection.get('name')
36
37
  value = results[index]
37
- cache_sub_key = '-'.join(non_empty_list([
38
- collection.get('year'),
39
- collection.get('start_date'),
40
- collection.get('end_date')
41
- ]))
38
+ cache_sub_key = _cache_sub_key(collection)
42
39
  data = (group.get(name, {}) | {cache_sub_key: value} if cache_sub_key else value)
43
40
  return group | {name: data}
44
41
 
@@ -62,20 +59,24 @@ def _extend_collection_by_month(year: int):
62
59
  } for month in range(1, 13)]
63
60
 
64
61
 
65
- def _extend_collection(name: str, collection: dict, years: list = []):
66
- data = collection | {'name': name, 'collection': _collection_name(collection.get('collection'))}
62
+ def _extend_collection_data(name: str, collection: dict):
63
+ return collection | {'name': name, 'collection': _collection_name(collection.get('collection'))}
67
64
 
65
+
66
+ def _extend_collection(name: str, collection: Union[List[dict], dict], years: list = []):
68
67
  year_params = [{'year': str(year)} for year in years]
69
68
  # fetch from first year to last
70
69
  month_years = range(years[0], years[-1] + 1) if len(years) > 1 else years
71
70
  month_params = flatten(map(_extend_collection_by_month, month_years))
72
71
 
73
72
  return [
74
- (data | params) for params in year_params
73
+ (_extend_collection_data(name, collection) | params) for params in year_params
75
74
  ] if name.endswith('Annual') else [
76
- (data | params) for params in month_params
75
+ (_extend_collection_data(name, collection) | params) for params in month_params
77
76
  ] if name.endswith('Monthly') else [
78
- data
77
+ _extend_collection_data(name, col) for col in collection
78
+ ] if isinstance(collection, list) else [
79
+ _extend_collection_data(name, collection)
79
80
  ]
80
81
 
81
82
 
@@ -85,18 +86,24 @@ def _extend_collections(values: list, years: list = []):
85
86
  ])
86
87
 
87
88
 
89
+ def _is_type(value: dict, ee_type: str):
90
+ params = value.get('params')
91
+ return any([
92
+ p.get('ee_type') == ee_type for p in params
93
+ ]) if isinstance(params, list) else params.get('ee_type') == ee_type
94
+
95
+
88
96
  def list_collections(years: list = [], include_region: bool = False, years_only: bool = False):
89
97
  ee_params = list_ee_params()
90
98
  # only cache `raster` results as can be combined in a single query
91
- rasters = [value for value in ee_params if value.get('params').get('ee_type') == 'raster']
99
+ rasters = [value for value in ee_params if _is_type(value, 'raster')]
92
100
  rasters = _extend_collections(rasters, years or [])
93
101
  rasters = [raster for raster in rasters if not years_only or _is_collection_by_year(raster)]
94
102
 
95
103
  vectors = [
96
- value for value in ee_params if all([
97
- value.get('params').get('ee_type') == 'vector',
104
+ value for value in ee_params if _is_type(value, 'vector') and (
98
105
  include_region or not value.get('params').get('collection', '').startswith('gadm36')
99
- ])
106
+ )
100
107
  ]
101
108
  # no vectors are running with specific years
102
109
  vectors = [] if years_only else _extend_collections(vectors)
@@ -5,7 +5,9 @@ from hestia_earth.utils.model import linked_node
5
5
  from . import _term_id, _include_methodModel
6
6
 
7
7
 
8
- def _new_indicator(term, model=None):
8
+ def _new_indicator(term, model=None, land_cover_id=None):
9
9
  node = {'@type': SchemaType.INDICATOR.value}
10
10
  node['term'] = linked_node(term if isinstance(term, dict) else download_hestia(_term_id(term)))
11
+ if land_cover_id:
12
+ node['landCover'] = linked_node(download_hestia(land_cover_id))
11
13
  return _include_methodModel(node, model)
@@ -252,6 +252,40 @@ def get_rice_paddy_terms():
252
252
  return [n['@id'] for n in terms if 'depth' not in n['@id'].lower()]
253
253
 
254
254
 
255
+ def get_flooded_pre_season_terms():
256
+ """
257
+ Find all `landUseManagement` terms of "flooded pre season" from the Glossary:
258
+ https://hestia.earth/glossary?termType=landUseManagement&query=flooded%20pre-season
259
+
260
+ Returns
261
+ -------
262
+ list
263
+ List of matching term `@id` as `str`.
264
+ """
265
+ terms = search({
266
+ "bool": {
267
+ "must": [
268
+ {
269
+ "match": {
270
+ "@type": SchemaType.TERM.value
271
+ }
272
+ },
273
+ {
274
+ "match": {
275
+ "termType": TermTermType.LANDUSEMANAGEMENT.value
276
+ }
277
+ },
278
+ {
279
+ "match_phrase": {
280
+ "name": "flooded pre-season"
281
+ }
282
+ }
283
+ ]
284
+ }
285
+ }, limit=LIMIT)
286
+ return list(map(lambda n: n['@id'], terms))
287
+
288
+
255
289
  def get_crop_residue_terms():
256
290
  """
257
291
  Find all `cropResidue` terms from the Glossary:
@@ -1 +1 @@
1
- VERSION = '0.63.0'
1
+ VERSION = '0.64.0'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hestia-earth-models
3
- Version: 0.63.0
3
+ Version: 0.64.0
4
4
  Summary: HESTIA's set of modules for filling gaps in the activity data using external datasets (e.g. populating soil properties with a geospatial dataset using provided coordinates) and internal lookups (e.g. populating machinery use from fuel use). Includes rules for when gaps should be filled versus not (e.g. never gap fill yield, gap fill crop residue if yield provided etc.).
5
5
  Home-page: https://gitlab.com/hestia-earth/hestia-engine-models
6
6
  Author: HESTIA Team
@@ -11,7 +11,7 @@ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
11
11
  Classifier: Programming Language :: Python :: 3.6
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
- Requires-Dist: hestia-earth.schema==29.*
14
+ Requires-Dist: hestia-earth.schema==30.*
15
15
  Requires-Dist: hestia-earth.utils>=0.13.3
16
16
  Requires-Dist: python-dateutil>=2.8.1
17
17
  Requires-Dist: CurrencyConverter==0.16.8