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
@@ -0,0 +1,51 @@
1
+ from hestia_earth.models.log import logRequirements, logShouldRun
2
+ from hestia_earth.models.utils.term import get_flooded_pre_season_terms
3
+ from hestia_earth.models.utils.practice import _new_practice
4
+ from . import MODEL
5
+
6
+ REQUIREMENTS = {
7
+ "Cycle": {
8
+ "none": {
9
+ "practices": [{
10
+ "@type": "Practice",
11
+ "term.termType": "landUseManagement",
12
+ "term.@id": [
13
+ "nonFloodedPreSeasonLessThan180Days",
14
+ "nonFloodedPreSeasonMoreThan180Days",
15
+ "nonFloodedPreSeasonMoreThan365Days",
16
+ "floodedPreSeasonMoreThan30Days"
17
+ ]
18
+ }]
19
+ }
20
+ }
21
+ }
22
+ RETURNS = {
23
+ "Practice": [{
24
+ "value": "100"
25
+ }]
26
+ }
27
+ TERM_ID = 'unknownPreSeasonWaterRegime'
28
+
29
+
30
+ def _practice():
31
+ practice = _new_practice(TERM_ID)
32
+ practice['value'] = [100]
33
+ return practice
34
+
35
+
36
+ def _should_run(cycle: dict):
37
+ practices = cycle.get('practices', [])
38
+ flooded_terms = get_flooded_pre_season_terms()
39
+ print(flooded_terms)
40
+ existing_practice = next((p for p in practices if p.get('term', {}).get('@id') in flooded_terms), None)
41
+
42
+ logRequirements(cycle, model=MODEL, term=TERM_ID,
43
+ existing_practice=existing_practice)
44
+
45
+ should_run = all([not existing_practice])
46
+ logShouldRun(cycle, MODEL, TERM_ID, should_run)
47
+ return should_run
48
+
49
+
50
+ def run(cycle: dict):
51
+ return [_practice()] if _should_run(cycle) else []
@@ -19,6 +19,7 @@ from hestia_earth.utils.tools import flatten, list_sum
19
19
 
20
20
  from hestia_earth.models.log import debugValues, logShouldRun, logRequirements
21
21
  from hestia_earth.models.data.ecoinventV3 import ecoinventV3_emissions
22
+ from hestia_earth.models.utils import is_from_model
22
23
  from hestia_earth.models.utils.emission import _new_emission
23
24
  from hestia_earth.models.utils.blank_node import group_by_keys
24
25
  from hestia_earth.models.utils.pesticideAI import get_pesticides_from_inputs
@@ -109,18 +110,33 @@ def _add_emission(cycle: dict, input: dict):
109
110
 
110
111
 
111
112
  def _run_input(cycle: dict):
113
+ emissions = cycle.get('emissions', [])
114
+
112
115
  def run(inputs: list):
113
116
  input = inputs[0]
114
117
  input_term_id = input.get('term', {}).get('@id')
118
+ operation_term_id = input.get('operation', {}).get('@id')
119
+ animal_term_id = input.get('animal', {}).get('@id')
115
120
  input_value = list_sum(flatten(input.get('value', []) for input in inputs))
116
121
  mappings = get_input_mappings(MODEL, cycle, input)
117
122
  has_mappings = len(mappings) > 0
123
+ # skip input that has background emissions we have already gap-filled (model run before)
124
+ has_no_gap_filled_background_emissions = not any([
125
+ is_from_model(e)
126
+ for e in emissions
127
+ if all([
128
+ any([i.get('@id') == input_term_id for i in e.get('inputs', [])]),
129
+ e.get('operation', {}).get('@id') == operation_term_id,
130
+ e.get('animal', {}).get('@id') == animal_term_id
131
+ ])
132
+ ])
118
133
 
119
134
  logRequirements(cycle, model=MODEL, term=input_term_id,
120
135
  has_ecoinvent_mappings=has_mappings,
121
- ecoinvent_mappings=';'.join([v[0] for v in mappings]))
136
+ ecoinvent_mappings=';'.join([v[0] for v in mappings]),
137
+ has_no_gap_filled_background_emissions=has_no_gap_filled_background_emissions)
122
138
 
123
- should_run = all([has_mappings])
139
+ should_run = all([has_mappings, has_no_gap_filled_background_emissions])
124
140
  logShouldRun(cycle, MODEL, input_term_id, should_run, methodTier=TIER)
125
141
  grouped_emissions = reduce(_add_emission(cycle, input), mappings, {}) if should_run else {}
126
142
  return [
@@ -16,7 +16,7 @@ REQUIREMENTS = {
16
16
  }
17
17
  }
18
18
  LOOKUPS = {
19
- "region-faostatCroplandArea": ""
19
+ "region-faostatArea": ""
20
20
  }
21
21
  RETURNS = {
22
22
  "Indicator": [{
@@ -16,7 +16,7 @@ REQUIREMENTS = {
16
16
  }
17
17
  }
18
18
  LOOKUPS = {
19
- "region-faostatCroplandArea": ""
19
+ "region-faostatArea": ""
20
20
  }
21
21
  RETURNS = {
22
22
  "Indicator": [{
@@ -62,14 +62,14 @@ def _cropland_split_delta(table_value: str, start_year: int, end_year: int):
62
62
 
63
63
 
64
64
  def get_cropland_ratio(country: str, start_year: int, end_year: int):
65
- lookup = download_lookup('region-faostatCroplandArea.csv')
65
+ lookup = download_lookup('region-faostatArea.csv')
66
66
  total_delta = _cropland_split_delta(
67
67
  get_table_value(lookup, 'termid', country, column_name('Cropland')), start_year, end_year
68
68
  )
69
69
 
70
70
  # get both values and only return result if we have both
71
71
  permanent_delta = _cropland_split_delta(
72
- get_table_value(lookup, 'termid', country, column_name('Land under permanent crops')), start_year, end_year
72
+ get_table_value(lookup, 'termid', country, column_name('Permanent crops')), start_year, end_year
73
73
  )
74
74
  temporary_delta = _cropland_split_delta(
75
75
  get_table_value(lookup, 'termid', country, column_name('Arable land')), start_year, end_year
@@ -1,4 +1,5 @@
1
1
  from hestia_earth.schema import MeasurementMethodClassification
2
+ from hestia_earth.utils.tools import non_empty_list
2
3
 
3
4
  from hestia_earth.models.log import logRequirements, logShouldRun
4
5
  from hestia_earth.models.utils.blank_node import has_original_by_ids
@@ -29,37 +30,63 @@ REQUIREMENTS = {
29
30
  RETURNS = {
30
31
  "Measurement": [{
31
32
  "value": "",
32
- "depthUpper": "0",
33
- "depthLower": "30",
33
+ "depthUpper": "",
34
+ "depthLower": "",
34
35
  "methodClassification": "geospatial dataset"
35
36
  }]
36
37
  }
37
38
  TERM_ID = 'clayContent'
38
- EE_PARAMS = {
39
- 'collection': 'T_CLAY',
40
- 'ee_type': 'raster',
41
- 'reducer': 'mean'
42
- }
43
- BIBLIO_TITLE = 'Harmonized World Soil Database Version 1.2. Food and Agriculture Organization of the United Nations (FAO).' # noqa: E501
39
+ EE_PARAMS = [
40
+ {
41
+ 'collection': 'T_CLAY_v2_depth_1',
42
+ 'ee_type': 'raster',
43
+ 'reducer': 'mean',
44
+ 'depthUpper': 0,
45
+ 'depthLower': 20
46
+ },
47
+ {
48
+ 'collection': 'T_CLAY_v2_depth_2',
49
+ 'ee_type': 'raster',
50
+ 'reducer': 'mean',
51
+ 'depthUpper': 20,
52
+ 'depthLower': 40
53
+ },
54
+ {
55
+ 'collection': 'T_CLAY_v2_depth_3',
56
+ 'ee_type': 'raster',
57
+ 'reducer': 'mean',
58
+ 'depthUpper': 40,
59
+ 'depthLower': 60
60
+ },
61
+ {
62
+ 'collection': 'T_CLAY_v2_depth_4',
63
+ 'ee_type': 'raster',
64
+ 'reducer': 'mean',
65
+ 'depthUpper': 60,
66
+ 'depthLower': 80
67
+ }
68
+ ]
69
+ BIBLIO_TITLE = 'Harmonized World Soil Database Version 2.0.'
44
70
 
45
71
 
46
- def _measurement(site: dict, value: int):
47
- measurement = _new_measurement(TERM_ID, None)
72
+ def _measurement(site: dict, value: int, depthUpper: int, depthLower: int):
73
+ measurement = _new_measurement(TERM_ID)
48
74
  measurement['value'] = [value]
49
- measurement['depthUpper'] = 0
50
- measurement['depthLower'] = 30
75
+ measurement['depthUpper'] = depthUpper
76
+ measurement['depthLower'] = depthLower
51
77
  measurement['methodClassification'] = MeasurementMethodClassification.GEOSPATIAL_DATASET.value
52
78
  return measurement | get_source(site, BIBLIO_TITLE)
53
79
 
54
80
 
55
- def _download(site: dict):
56
- value = download(TERM_ID, site, EE_PARAMS)
57
- return None if value is None else round(value, 2)
81
+ def _run_depths(site: dict, params: dict):
82
+ value = download(TERM_ID, site, params)
83
+ return None if value is None else (
84
+ _measurement(site, round(value, 2), params.get('depthUpper'), params.get('depthLower'))
85
+ )
58
86
 
59
87
 
60
88
  def _run(site: dict):
61
- value = _download(site)
62
- return [_measurement(site, value)] if value is not None else []
89
+ return non_empty_list([_run_depths(site, params) for params in EE_PARAMS])
63
90
 
64
91
 
65
92
  def _should_run(site: dict):
@@ -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,37 +19,63 @@ REQUIREMENTS = {
19
19
  RETURNS = {
20
20
  "Measurement": [{
21
21
  "value": "",
22
- "depthUpper": "0",
23
- "depthLower": "30",
22
+ "depthUpper": "",
23
+ "depthLower": "",
24
24
  "methodClassification": "geospatial dataset"
25
25
  }]
26
26
  }
27
27
  TERM_ID = 'organicCarbonPerKgSoil'
28
- EE_PARAMS = {
29
- 'collection': 'T_OC',
30
- 'ee_type': 'raster',
31
- 'reducer': 'mean'
32
- }
33
- BIBLIO_TITLE = 'Harmonized World Soil Database Version 1.2. Food and Agriculture Organization of the United Nations (FAO).' # noqa: E501
28
+ EE_PARAMS = [
29
+ {
30
+ 'collection': 'T_OC_v2_depth_1',
31
+ 'ee_type': 'raster',
32
+ 'reducer': 'mean',
33
+ 'depthUpper': 0,
34
+ 'depthLower': 20
35
+ },
36
+ {
37
+ 'collection': 'T_OC_v2_depth_2',
38
+ 'ee_type': 'raster',
39
+ 'reducer': 'mean',
40
+ 'depthUpper': 20,
41
+ 'depthLower': 40
42
+ },
43
+ {
44
+ 'collection': 'T_OC_v2_depth_3',
45
+ 'ee_type': 'raster',
46
+ 'reducer': 'mean',
47
+ 'depthUpper': 40,
48
+ 'depthLower': 60
49
+ },
50
+ {
51
+ 'collection': 'T_OC_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.'
34
59
 
35
60
 
36
- def _measurement(site: dict, value: float):
61
+ def _measurement(site: dict, value: int, depthUpper: int, depthLower: int):
37
62
  measurement = _new_measurement(TERM_ID)
38
63
  measurement['value'] = [value]
39
- measurement['depthUpper'] = 0
40
- measurement['depthLower'] = 30
64
+ measurement['depthUpper'] = depthUpper
65
+ measurement['depthLower'] = depthLower
41
66
  measurement['methodClassification'] = MeasurementMethodClassification.GEOSPATIAL_DATASET.value
42
67
  return measurement | get_source(site, BIBLIO_TITLE)
43
68
 
44
69
 
45
- def _download(site: dict):
46
- value = download(TERM_ID, site, EE_PARAMS)
47
- return safe_parse_float(value) * 10 if value is not None else None
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) * 10, params.get('depthUpper'), params.get('depthLower'))
74
+ )
48
75
 
49
76
 
50
77
  def _run(site: dict):
51
- value = _download(site)
52
- return [_measurement(site, value)] if value is not None else []
78
+ return non_empty_list([_run_depths(site, params) for params in EE_PARAMS])
53
79
 
54
80
 
55
81
  def _should_run(site: dict):
@@ -1,4 +1,5 @@
1
1
  from hestia_earth.schema import MeasurementMethodClassification
2
+ from hestia_earth.utils.tools import non_empty_list
2
3
 
3
4
  from hestia_earth.models.log import logRequirements, logShouldRun
4
5
  from hestia_earth.models.utils.blank_node import has_original_by_ids
@@ -29,37 +30,63 @@ REQUIREMENTS = {
29
30
  RETURNS = {
30
31
  "Measurement": [{
31
32
  "value": "",
32
- "depthUpper": "0",
33
- "depthLower": "30",
33
+ "depthUpper": "",
34
+ "depthLower": "",
34
35
  "methodClassification": "geospatial dataset"
35
36
  }]
36
37
  }
37
38
  TERM_ID = 'sandContent'
38
- EE_PARAMS = {
39
- 'collection': 'T_SAND',
40
- 'ee_type': 'raster',
41
- 'reducer': 'mean'
42
- }
43
- BIBLIO_TITLE = 'Harmonized World Soil Database Version 1.2. Food and Agriculture Organization of the United Nations (FAO).' # noqa: E501
39
+ EE_PARAMS = [
40
+ {
41
+ 'collection': 'T_SAND_v2_depth_1',
42
+ 'ee_type': 'raster',
43
+ 'reducer': 'mean',
44
+ 'depthUpper': 0,
45
+ 'depthLower': 20
46
+ },
47
+ {
48
+ 'collection': 'T_SAND_v2_depth_2',
49
+ 'ee_type': 'raster',
50
+ 'reducer': 'mean',
51
+ 'depthUpper': 20,
52
+ 'depthLower': 40
53
+ },
54
+ {
55
+ 'collection': 'T_SAND_v2_depth_3',
56
+ 'ee_type': 'raster',
57
+ 'reducer': 'mean',
58
+ 'depthUpper': 40,
59
+ 'depthLower': 60
60
+ },
61
+ {
62
+ 'collection': 'T_SAND_v2_depth_4',
63
+ 'ee_type': 'raster',
64
+ 'reducer': 'mean',
65
+ 'depthUpper': 60,
66
+ 'depthLower': 80
67
+ }
68
+ ]
69
+ BIBLIO_TITLE = 'Harmonized World Soil Database Version 2.0.'
44
70
 
45
71
 
46
- def _measurement(site: dict, value: int):
72
+ def _measurement(site: dict, value: int, depthUpper: int, depthLower: int):
47
73
  measurement = _new_measurement(TERM_ID)
48
74
  measurement['value'] = [value]
49
- measurement['depthUpper'] = 0
50
- measurement['depthLower'] = 30
75
+ measurement['depthUpper'] = depthUpper
76
+ measurement['depthLower'] = depthLower
51
77
  measurement['methodClassification'] = MeasurementMethodClassification.GEOSPATIAL_DATASET.value
52
78
  return measurement | get_source(site, BIBLIO_TITLE)
53
79
 
54
80
 
55
- def _download(site: dict):
56
- value = download(TERM_ID, site, EE_PARAMS)
57
- return None if value is None else round(value, 2)
81
+ def _run_depths(site: dict, params: dict):
82
+ value = download(TERM_ID, site, params)
83
+ return None if value is None else (
84
+ _measurement(site, round(value, 2), params.get('depthUpper'), params.get('depthLower'))
85
+ )
58
86
 
59
87
 
60
88
  def _run(site: dict):
61
- value = _download(site)
62
- return [_measurement(site, value)] if value is not None else []
89
+ return non_empty_list([_run_depths(site, params) for params in EE_PARAMS])
63
90
 
64
91
 
65
92
  def _should_run(site: dict):
@@ -1,12 +1,30 @@
1
1
  from hestia_earth.schema import MeasurementMethodClassification
2
+ from hestia_earth.utils.model import find_term_match
3
+ from hestia_earth.utils.tools import non_empty_list, flatten
2
4
 
3
- from hestia_earth.models.log import logRequirements, logShouldRun, log_blank_nodes_id
4
- from hestia_earth.models.utils.measurement import _new_measurement, measurement_value
5
+ from hestia_earth.models.log import logRequirements, logShouldRun, log_as_table
6
+ from hestia_earth.models.utils.measurement import _new_measurement, measurement_value, group_measurements_by_depth
5
7
  from hestia_earth.models.utils.source import get_source
6
8
  from . import MODEL, clayContent, sandContent
7
9
 
8
10
  REQUIREMENTS = {
9
11
  "Site": {
12
+ "measurements": [
13
+ {
14
+ "@type": "Measurement",
15
+ "term.@id": "clayContent",
16
+ "value": ">= 0",
17
+ "depthUpper": ">= 0",
18
+ "depthLower": ">= 0"
19
+ },
20
+ {
21
+ "@type": "Measurement",
22
+ "term.@id": "sandContent",
23
+ "value": ">= 0",
24
+ "depthUpper": ">= 0",
25
+ "depthLower": ">= 0"
26
+ }
27
+ ],
10
28
  "or": [
11
29
  {"latitude": "", "longitude": ""},
12
30
  {"boundary": {}},
@@ -17,8 +35,8 @@ REQUIREMENTS = {
17
35
  RETURNS = {
18
36
  "Measurement": [{
19
37
  "value": "",
20
- "depthUpper": "0",
21
- "depthLower": "30",
38
+ "depthUpper": "",
39
+ "depthLower": "",
22
40
  "methodClassification": "geospatial dataset"
23
41
  }]
24
42
  }
@@ -27,39 +45,61 @@ OTHER_TERM_IDS = [
27
45
  clayContent.TERM_ID,
28
46
  sandContent.TERM_ID
29
47
  ]
30
- BIBLIO_TITLE = 'Harmonized World Soil Database Version 1.2. Food and Agriculture Organization of the United Nations (FAO).' # noqa: E501
48
+ BIBLIO_TITLE = 'Harmonized World Soil Database Version 2.0.'
31
49
 
32
50
 
33
- def _measurement(site: dict, value: int):
51
+ def _measurement(site: dict, value: int, depthUpper: int, depthLower: int):
34
52
  measurement = _new_measurement(TERM_ID)
35
53
  measurement['value'] = [value]
36
- measurement['depthUpper'] = 0
37
- measurement['depthLower'] = 30
54
+ measurement['depthUpper'] = depthUpper
55
+ measurement['depthLower'] = depthLower
38
56
  measurement['methodClassification'] = MeasurementMethodClassification.GEOSPATIAL_DATASET.value
39
57
  return measurement | get_source(site, BIBLIO_TITLE)
40
58
 
41
59
 
42
60
  def _run(site: dict, measurements: list):
43
61
  value = 100 - sum([measurement_value(m) for m in measurements])
44
- return [_measurement(site, value)]
62
+ return [_measurement(site, value, measurements[0].get('depthUpper'), measurements[0].get('depthLower'))]
45
63
 
46
64
 
47
65
  def _should_run(site: dict):
48
- measurements = [
49
- m for m in site.get('measurements', [])
50
- if m.get('term', {}).get('@id') in OTHER_TERM_IDS and len(m.get('value', [])) > 0
66
+ grouped_measurements = group_measurements_by_depth(site.get('measurements', []), include_dates=False)
67
+ relevant_measurements = [
68
+ [
69
+ m for m in measurements if all([
70
+ m.get('term', {}).get('@id') in OTHER_TERM_IDS,
71
+ len(m.get('value', [])) > 0,
72
+ m.get('depthUpper', -1) >= 0,
73
+ m.get('depthLower', -1) >= 0
74
+ ])
75
+ ]
76
+ for measurements in grouped_measurements.values()
77
+ ]
78
+ valid_measurements = [
79
+ values for values in relevant_measurements if len(values) == len(OTHER_TERM_IDS)
51
80
  ]
52
- has_all_measurements = len(measurements) == len(OTHER_TERM_IDS)
81
+
82
+ has_valid_measurements = len(valid_measurements) > 0
53
83
 
54
84
  logRequirements(site, model=MODEL, term=TERM_ID,
55
- has_all_measurements=has_all_measurements,
56
- measurement_ids=log_blank_nodes_id(measurements))
85
+ has_valid_measurements=has_valid_measurements,
86
+ measurements=log_as_table([
87
+ {
88
+ 'depths': '-'.join(non_empty_list([
89
+ str(values[0].get('depthUpper', '')),
90
+ str(values[0].get('depthLower', ''))
91
+ ]))
92
+ } | {
93
+ term_id: measurement_value(find_term_match(values, term_id))
94
+ for term_id in OTHER_TERM_IDS
95
+ } for values in valid_measurements
96
+ ]))
57
97
 
58
- should_run = all([has_all_measurements])
98
+ should_run = all([has_valid_measurements])
59
99
  logShouldRun(site, MODEL, TERM_ID, should_run)
60
- return should_run, measurements
100
+ return should_run, valid_measurements
61
101
 
62
102
 
63
103
  def run(site: dict):
64
104
  should_run, measurements = _should_run(site)
65
- return _run(site, measurements) if should_run else []
105
+ return flatten([_run(site, values) for values in measurements]) if should_run else []
@@ -1,4 +1,5 @@
1
1
  from hestia_earth.schema import MeasurementMethodClassification
2
+ from hestia_earth.utils.tools import non_empty_list
2
3
 
3
4
  from hestia_earth.models.log import logRequirements, logShouldRun
4
5
  from hestia_earth.models.utils.measurement import _new_measurement
@@ -18,37 +19,63 @@ REQUIREMENTS = {
18
19
  RETURNS = {
19
20
  "Measurement": [{
20
21
  "value": "",
21
- "depthUpper": "0",
22
- "depthLower": "30",
22
+ "depthUpper": "",
23
+ "depthLower": "",
23
24
  "methodClassification": "geospatial dataset"
24
25
  }]
25
26
  }
26
27
  TERM_ID = 'soilPh'
27
- EE_PARAMS = {
28
- 'collection': 'T_PH_H2O',
29
- 'ee_type': 'raster',
30
- 'reducer': 'mean'
31
- }
32
- BIBLIO_TITLE = 'Harmonized World Soil Database Version 1.2. Food and Agriculture Organization of the United Nations (FAO).' # noqa: E501
28
+ EE_PARAMS = [
29
+ {
30
+ 'collection': 'T_PH_H2O_v2_depth_1',
31
+ 'ee_type': 'raster',
32
+ 'reducer': 'mean',
33
+ 'depthUpper': 0,
34
+ 'depthLower': 20
35
+ },
36
+ {
37
+ 'collection': 'T_PH_H2O_v2_depth_2',
38
+ 'ee_type': 'raster',
39
+ 'reducer': 'mean',
40
+ 'depthUpper': 20,
41
+ 'depthLower': 40
42
+ },
43
+ {
44
+ 'collection': 'T_PH_H2O_v2_depth_3',
45
+ 'ee_type': 'raster',
46
+ 'reducer': 'mean',
47
+ 'depthUpper': 40,
48
+ 'depthLower': 60
49
+ },
50
+ {
51
+ 'collection': 'T_PH_H2O_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.'
33
59
 
34
60
 
35
- def _measurement(site: dict, value: float):
61
+ def _measurement(site: dict, value: int, depthUpper: int, depthLower: int):
36
62
  measurement = _new_measurement(TERM_ID)
37
63
  measurement['value'] = [value]
38
- measurement['depthUpper'] = 0
39
- measurement['depthLower'] = 30
64
+ measurement['depthUpper'] = depthUpper
65
+ measurement['depthLower'] = depthLower
40
66
  measurement['methodClassification'] = MeasurementMethodClassification.GEOSPATIAL_DATASET.value
41
67
  return measurement | get_source(site, BIBLIO_TITLE)
42
68
 
43
69
 
44
- def _download(site: dict):
45
- value = download(TERM_ID, site, EE_PARAMS)
46
- return None if value is None else round(value, 7)
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, round(value, 7), params.get('depthUpper'), params.get('depthLower'))
74
+ )
47
75
 
48
76
 
49
77
  def _run(site: dict):
50
- value = _download(site)
51
- return [] if value is None else [_measurement(site, value)]
78
+ return non_empty_list([_run_depths(site, params) for params in EE_PARAMS])
52
79
 
53
80
 
54
81
  def _should_run(site: dict):