hestia-earth-models 0.59.3__py3-none-any.whl → 0.59.5__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 (39) hide show
  1. hestia_earth/models/cycle/liveAnimal.py +3 -0
  2. hestia_earth/models/cycle/milkYield.py +1 -1
  3. hestia_earth/models/cycle/utils.py +1 -1
  4. hestia_earth/models/geospatialDatabase/potentialEvapotranspirationLongTermAnnualMean.py +2 -2
  5. hestia_earth/models/geospatialDatabase/potentialEvapotranspirationMonthly.py +99 -0
  6. hestia_earth/models/geospatialDatabase/precipitationMonthly.py +100 -0
  7. hestia_earth/models/geospatialDatabase/temperatureAnnual.py +2 -6
  8. hestia_earth/models/geospatialDatabase/temperatureLongTermAnnualMean.py +2 -3
  9. hestia_earth/models/geospatialDatabase/temperatureMonthly.py +98 -0
  10. hestia_earth/models/geospatialDatabase/utils.py +13 -1
  11. hestia_earth/models/ipcc2019/organicCarbonPerHa.py +72 -135
  12. hestia_earth/models/linkedImpactAssessment/__init__.py +78 -43
  13. hestia_earth/models/mocking/search-results.json +8 -47
  14. hestia_earth/models/schmidt2007/n2OToAirWasteTreatmentDirect.py +58 -0
  15. hestia_earth/models/schmidt2007/nh3ToAirWasteTreatment.py +58 -0
  16. hestia_earth/models/site/management.py +106 -13
  17. hestia_earth/models/site/pre_checks/cache_geospatialDatabase.py +27 -7
  18. hestia_earth/models/site/soilMeasurement.py +9 -9
  19. hestia_earth/models/site/utils.py +2 -6
  20. hestia_earth/models/utils/__init__.py +9 -0
  21. hestia_earth/models/utils/blank_node.py +3 -3
  22. hestia_earth/models/utils/site.py +8 -5
  23. hestia_earth/models/utils/term.py +0 -23
  24. hestia_earth/models/version.py +1 -1
  25. {hestia_earth_models-0.59.3.dist-info → hestia_earth_models-0.59.5.dist-info}/METADATA +2 -2
  26. {hestia_earth_models-0.59.3.dist-info → hestia_earth_models-0.59.5.dist-info}/RECORD +39 -29
  27. tests/models/geospatialDatabase/test_potentialEvapotranspirationMonthly.py +20 -0
  28. tests/models/geospatialDatabase/test_precipitationMonthly.py +20 -0
  29. tests/models/geospatialDatabase/test_temperatureMonthly.py +20 -0
  30. tests/models/ipcc2019/test_organicCarbonPerHa.py +8 -39
  31. tests/models/schmidt2007/test_n2OToAirWasteTreatmentDirect.py +45 -0
  32. tests/models/schmidt2007/test_nh3ToAirWasteTreatment.py +45 -0
  33. tests/models/site/test_management.py +37 -16
  34. tests/models/site/test_soilMeasurement.py +40 -21
  35. tests/models/utils/test_site.py +1 -1
  36. tests/models/utils/test_term.py +1 -8
  37. {hestia_earth_models-0.59.3.dist-info → hestia_earth_models-0.59.5.dist-info}/LICENSE +0 -0
  38. {hestia_earth_models-0.59.3.dist-info → hestia_earth_models-0.59.5.dist-info}/WHEEL +0 -0
  39. {hestia_earth_models-0.59.3.dist-info → hestia_earth_models-0.59.5.dist-info}/top_level.txt +0 -0
@@ -43,6 +43,9 @@ RETURNS = {
43
43
  "value": ""
44
44
  }]
45
45
  }
46
+ LOOKUPS = {
47
+ "animalProduct": "liveAnimalTermId"
48
+ }
46
49
  MODEL_KEY = 'liveAnimal'
47
50
  VALID_SITE_TYPES = [SiteSiteType.ANIMAL_HOUSING.value, SiteSiteType.PERMANENT_PASTURE.value]
48
51
 
@@ -48,7 +48,7 @@ RETURNS = {
48
48
  }]
49
49
  }
50
50
  LOOKUPS = {
51
- "animalProduct": ["liveAnimal", "milkYieldPracticeId"]
51
+ "animalProduct": ["liveAnimalTermId", "milkYieldPracticeId"]
52
52
  }
53
53
 
54
54
  MODEL_KEY = 'milkYield'
@@ -6,7 +6,7 @@ from . import MODEL
6
6
 
7
7
 
8
8
  def _get_liveAnimal_term_id(product: dict, **log_ars):
9
- term_id = get_lookup_value(product.get('term', {}), 'liveAnimal', model=MODEL, **log_ars)
9
+ term_id = get_lookup_value(product.get('term', {}), 'liveAnimalTermId', model=MODEL, **log_ars)
10
10
  return term_id.split(';')[0] if term_id else None
11
11
 
12
12
 
@@ -47,9 +47,9 @@ def _measurement(value: float):
47
47
 
48
48
 
49
49
  def _download(site: dict):
50
- scale = 10
50
+ factor = 0.1
51
51
  value = download(TERM_ID, site, EE_PARAMS)
52
- return value / scale if value else None
52
+ return value * factor if value else None
53
53
 
54
54
 
55
55
  def _run(site: dict):
@@ -0,0 +1,99 @@
1
+ """
2
+ Must be associated with at least 1 `Cycle` that has an
3
+ [endDate](https://hestia.earth/schema/Cycle#endDate) after `1979-01-01` and before `2020-06-01`.
4
+ """
5
+ from hestia_earth.schema import MeasurementMethodClassification
6
+ from hestia_earth.utils.tools import flatten, non_empty_list
7
+
8
+ from hestia_earth.models.log import logRequirements, logShouldRun
9
+ from hestia_earth.models.utils import first_day_of_month, last_day_of_month
10
+ from hestia_earth.models.utils.measurement import _new_measurement
11
+ from hestia_earth.models.utils.source import get_source
12
+ from hestia_earth.models.utils.site import related_years
13
+ from .utils import download, has_geospatial_data, should_download
14
+ from . import MODEL
15
+
16
+ REQUIREMENTS = {
17
+ "Site": {
18
+ "or": [
19
+ {"latitude": "", "longitude": ""},
20
+ {"boundary": {}},
21
+ {"region": {"@type": "Term", "termType": "region"}}
22
+ ]
23
+ }
24
+ }
25
+ RETURNS = {
26
+ "Measurement": [{
27
+ "value": "",
28
+ "dates": "",
29
+ "methodClassification": "geospatial dataset"
30
+ }]
31
+ }
32
+ TERM_ID = 'potentialEvapotranspirationMonthly'
33
+ EE_PARAMS = {
34
+ 'collection': 'IDAHO_EPSCOR/TERRACLIMATE',
35
+ 'band_name': 'pet',
36
+ 'ee_type': 'raster',
37
+ 'reducer': 'mean',
38
+ 'reducer_annual': 'sum'
39
+ }
40
+ BIBLIO_TITLE = 'ERA5: Fifth generation of ECMWF atmospheric reanalyses of the global climate'
41
+
42
+
43
+ def _measurement(site: dict, value: list, dates: list):
44
+ measurement = _new_measurement(TERM_ID)
45
+ measurement['value'] = value
46
+ measurement['dates'] = dates
47
+ measurement['methodClassification'] = MeasurementMethodClassification.GEOSPATIAL_DATASET.value
48
+ return measurement | get_source(site, BIBLIO_TITLE)
49
+
50
+
51
+ def _download(site: dict, start_date: str, end_date: str):
52
+ return download(
53
+ TERM_ID,
54
+ site,
55
+ {
56
+ **EE_PARAMS,
57
+ 'start_date': start_date,
58
+ 'end_date': end_date
59
+ }
60
+ )
61
+
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
+
69
+ def _run(site: dict, years: list):
70
+ # fetch from first year to last
71
+ years = range(years[0], years[-1] + 1) if len(years) > 1 else years
72
+
73
+ dates = flatten([
74
+ [
75
+ (first_day_of_month(year, month).strftime('%Y-%m-%d'), last_day_of_month(year, month).strftime('%Y-%m-%d'))
76
+ for month in range(1, 13)
77
+ ] for year in years
78
+ ])
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 []
81
+
82
+
83
+ def run(site: dict):
84
+ contains_geospatial_data = has_geospatial_data(site)
85
+ below_max_area_size = should_download(TERM_ID, site)
86
+
87
+ years = related_years(site)
88
+ has_years = len(years) > 0
89
+
90
+ logRequirements(site, model=MODEL, term=TERM_ID,
91
+ contains_geospatial_data=contains_geospatial_data,
92
+ below_max_area_size=below_max_area_size,
93
+ has_years=has_years,
94
+ years=';'.join(map(lambda y: str(y), years)))
95
+
96
+ should_run = all([contains_geospatial_data, below_max_area_size, has_years])
97
+ logShouldRun(site, MODEL, TERM_ID, should_run)
98
+
99
+ return _run(site, years) if should_run else []
@@ -0,0 +1,100 @@
1
+ """
2
+ Must be associated with at least 1 `Cycle` that has an
3
+ [endDate](https://hestia.earth/schema/Cycle#endDate) after `1979-01-01` and before `2020-06-01`.
4
+ """
5
+ from hestia_earth.schema import MeasurementMethodClassification
6
+ from hestia_earth.utils.tools import flatten, non_empty_list
7
+
8
+ from hestia_earth.models.log import logRequirements, logShouldRun
9
+ from hestia_earth.models.utils import first_day_of_month, last_day_of_month
10
+ from hestia_earth.models.utils.measurement import _new_measurement
11
+ from hestia_earth.models.utils.source import get_source
12
+ from hestia_earth.models.utils.site import related_years
13
+ from .utils import download, has_geospatial_data, should_download
14
+ from . import MODEL
15
+
16
+ REQUIREMENTS = {
17
+ "Site": {
18
+ "or": [
19
+ {"latitude": "", "longitude": ""},
20
+ {"boundary": {}},
21
+ {"region": {"@type": "Term", "termType": "region"}}
22
+ ]
23
+ }
24
+ }
25
+ RETURNS = {
26
+ "Measurement": [{
27
+ "value": "",
28
+ "dates": "",
29
+ "methodClassification": "geospatial dataset"
30
+ }]
31
+ }
32
+ TERM_ID = 'precipitationMonthly'
33
+ EE_PARAMS = {
34
+ 'collection': 'ECMWF/ERA5/MONTHLY',
35
+ 'band_name': 'total_precipitation',
36
+ 'ee_type': 'raster',
37
+ 'reducer': 'mean',
38
+ 'reducer_annual': 'sum'
39
+ }
40
+ BIBLIO_TITLE = 'ERA5: Fifth generation of ECMWF atmospheric reanalyses of the global climate'
41
+
42
+
43
+ def _measurement(site: dict, value: list, dates: list):
44
+ measurement = _new_measurement(TERM_ID)
45
+ measurement['value'] = value
46
+ measurement['dates'] = dates
47
+ measurement['methodClassification'] = MeasurementMethodClassification.GEOSPATIAL_DATASET.value
48
+ return measurement | get_source(site, BIBLIO_TITLE)
49
+
50
+
51
+ def _download(site: dict, start_date: str, end_date: str):
52
+ return download(
53
+ TERM_ID,
54
+ site,
55
+ {
56
+ **EE_PARAMS,
57
+ 'start_date': start_date,
58
+ 'end_date': end_date
59
+ }
60
+ )
61
+
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
+
70
+ def _run(site: dict, years: list):
71
+ # fetch from first year to last
72
+ years = range(years[0], years[-1] + 1) if len(years) > 1 else years
73
+
74
+ dates = flatten([
75
+ [
76
+ (first_day_of_month(year, month).strftime('%Y-%m-%d'), last_day_of_month(year, month).strftime('%Y-%m-%d'))
77
+ for month in range(1, 13)
78
+ ] for year in years
79
+ ])
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 []
82
+
83
+
84
+ def run(site: dict):
85
+ contains_geospatial_data = has_geospatial_data(site)
86
+ below_max_area_size = should_download(TERM_ID, site)
87
+
88
+ years = related_years(site)
89
+ has_years = len(years) > 0
90
+
91
+ logRequirements(site, model=MODEL, term=TERM_ID,
92
+ contains_geospatial_data=contains_geospatial_data,
93
+ below_max_area_size=below_max_area_size,
94
+ has_years=has_years,
95
+ years=';'.join(map(lambda y: str(y), years)))
96
+
97
+ should_run = all([contains_geospatial_data, below_max_area_size, has_years])
98
+ logShouldRun(site, MODEL, TERM_ID, should_run)
99
+
100
+ return _run(site, years) if should_run else []
@@ -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 download, has_geospatial_data, should_download
12
+ from .utils import to_celcius, download, has_geospatial_data, should_download
13
13
  from . import MODEL
14
14
 
15
15
  REQUIREMENTS = {
@@ -38,7 +38,6 @@ EE_PARAMS = {
38
38
  'reducer_annual': 'mean'
39
39
  }
40
40
  BIBLIO_TITLE = 'ERA5: Fifth generation of ECMWF atmospheric reanalyses of the global climate'
41
- KELVIN_0 = 273.15
42
41
 
43
42
 
44
43
  def _measurement(site: dict, value: float, year: int):
@@ -50,9 +49,6 @@ def _measurement(site: dict, value: float, year: int):
50
49
  return measurement | get_source(site, BIBLIO_TITLE)
51
50
 
52
51
 
53
- def _to_celcius(kelvin_value: int): return kelvin_value - KELVIN_0 if kelvin_value else None
54
-
55
-
56
52
  def _download(site: dict, year: int):
57
53
  return download(
58
54
  TERM_ID,
@@ -65,7 +61,7 @@ def _download(site: dict, year: int):
65
61
 
66
62
 
67
63
  def _run(site: dict, year: int):
68
- value = _to_celcius(_download(site, year))
64
+ value = to_celcius(_download(site, year))
69
65
  return _measurement(site, value, year) if value else None
70
66
 
71
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 = _to_celcius(download(TERM_ID, site, EE_PARAMS))
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
 
@@ -0,0 +1,98 @@
1
+ """
2
+ Must be associated with at least 1 `Cycle` that has an
3
+ [endDate](https://hestia.earth/schema/Cycle#endDate) after `1979-01-01` and before `2020-06-01`.
4
+ """
5
+ from hestia_earth.schema import MeasurementMethodClassification
6
+ from hestia_earth.utils.tools import flatten, non_empty_list
7
+
8
+ from hestia_earth.models.log import logRequirements, logShouldRun
9
+ from hestia_earth.models.utils import first_day_of_month, last_day_of_month
10
+ from hestia_earth.models.utils.measurement import _new_measurement
11
+ from hestia_earth.models.utils.source import get_source
12
+ from hestia_earth.models.utils.site import related_years
13
+ from .utils import to_celcius, download, has_geospatial_data, should_download
14
+ from . import MODEL
15
+
16
+ REQUIREMENTS = {
17
+ "Site": {
18
+ "or": [
19
+ {"latitude": "", "longitude": ""},
20
+ {"boundary": {}},
21
+ {"region": {"@type": "Term", "termType": "region"}}
22
+ ]
23
+ }
24
+ }
25
+ RETURNS = {
26
+ "Measurement": [{
27
+ "value": "",
28
+ "dates": "",
29
+ "methodClassification": "geospatial dataset"
30
+ }]
31
+ }
32
+ TERM_ID = 'temperatureMonthly'
33
+ EE_PARAMS = {
34
+ 'collection': 'ECMWF/ERA5/MONTHLY',
35
+ 'band_name': 'mean_2m_air_temperature',
36
+ 'ee_type': 'raster',
37
+ 'reducer': 'mean',
38
+ 'reducer_annual': 'mean'
39
+ }
40
+ BIBLIO_TITLE = 'ERA5: Fifth generation of ECMWF atmospheric reanalyses of the global climate'
41
+
42
+
43
+ def _measurement(site: dict, value: list, dates: list):
44
+ measurement = _new_measurement(TERM_ID)
45
+ measurement['value'] = value
46
+ measurement['dates'] = dates
47
+ measurement['methodClassification'] = MeasurementMethodClassification.GEOSPATIAL_DATASET.value
48
+ return measurement | get_source(site, BIBLIO_TITLE)
49
+
50
+
51
+ def _download(site: dict, start_date: str, end_date: str):
52
+ return download(
53
+ TERM_ID,
54
+ site,
55
+ {
56
+ **EE_PARAMS,
57
+ 'start_date': start_date,
58
+ 'end_date': end_date
59
+ }
60
+ )
61
+
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
+
68
+ def _run(site: dict, years: list):
69
+ # fetch from first year to last
70
+ years = range(years[0], years[-1] + 1) if len(years) > 1 else years
71
+
72
+ dates = flatten([
73
+ [
74
+ (first_day_of_month(year, month).strftime('%Y-%m-%d'), last_day_of_month(year, month).strftime('%Y-%m-%d'))
75
+ for month in range(1, 13)
76
+ ] for year in years
77
+ ])
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
+
81
+
82
+ def run(site: dict):
83
+ contains_geospatial_data = has_geospatial_data(site)
84
+ below_max_area_size = should_download(TERM_ID, site)
85
+
86
+ years = related_years(site)
87
+ has_years = len(years) > 0
88
+
89
+ logRequirements(site, model=MODEL, term=TERM_ID,
90
+ contains_geospatial_data=contains_geospatial_data,
91
+ below_max_area_size=below_max_area_size,
92
+ has_years=has_years,
93
+ years=';'.join(map(lambda y: str(y), years)))
94
+
95
+ should_run = all([contains_geospatial_data, below_max_area_size, has_years])
96
+ logShouldRun(site, MODEL, TERM_ID, should_run)
97
+
98
+ return _run(site, years) if should_run else []
@@ -1,6 +1,7 @@
1
1
  import os
2
2
  from hestia_earth.schema import TermTermType
3
3
  from hestia_earth.utils.api import download_hestia
4
+ from hestia_earth.utils.tools import non_empty_list
4
5
 
5
6
  from hestia_earth.models.log import debugValues, logErrorRun, logRequirements
6
7
  from hestia_earth.models.utils.site import cached_value, region_factor, region_level_1_id
@@ -19,6 +20,10 @@ GEOPANDAS_COLLECTION_NAME = {
19
20
  'gadm36_4': 'gadm/gadm36_4',
20
21
  'gadm36_5': 'gadm/gadm36_5'
21
22
  }
23
+ KELVIN_0 = 273.15
24
+
25
+
26
+ def to_celcius(kelvin_value: int): return kelvin_value - KELVIN_0 if kelvin_value else None
22
27
 
23
28
 
24
29
  def use_geopandas(): return os.getenv('HEE_USE_GEOPANDAS', 'false') == 'true'
@@ -131,8 +136,15 @@ def _parse_run_query(term: str, query: dict):
131
136
 
132
137
  def _get_cached_data(term: str, site: dict, data: dict):
133
138
  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
+ ]))
134
144
  # data can be grouped by year when required
135
- value = cache.get(data.get('year')) if data.get('year') and cache is not None else cache
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
136
148
  if value is not None:
137
149
  debugValues(site, model=MODEL, term=term, value_from_cache=value)
138
150
  return value