hestia-earth-models 0.65.8__py3-none-any.whl → 0.65.10__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.
Files changed (39) hide show
  1. hestia_earth/models/cml2001Baseline/abioticResourceDepletionFossilFuels.py +3 -5
  2. hestia_earth/models/cml2001Baseline/abioticResourceDepletionMineralsAndMetals.py +1 -1
  3. hestia_earth/models/config/Cycle.json +368 -388
  4. hestia_earth/models/config/Site.json +18 -0
  5. hestia_earth/models/config/__init__.py +6 -0
  6. hestia_earth/models/config/run-calculations.json +5 -5
  7. hestia_earth/models/config/trigger-calculations.json +1 -1
  8. hestia_earth/models/cycle/materialAndSubstrate.py +1 -1
  9. hestia_earth/models/cycle/milkYield.py +9 -6
  10. hestia_earth/models/cycle/product/economicValueShare.py +8 -4
  11. hestia_earth/models/cycle/product/revenue.py +11 -7
  12. hestia_earth/models/environmentalFootprintV3/soilQualityIndexLandTransformation.py +12 -4
  13. hestia_earth/models/faostat2018/product/price.py +1 -1
  14. hestia_earth/models/geospatialDatabase/utils.py +22 -17
  15. hestia_earth/models/hestia/landCover.py +2 -2
  16. hestia_earth/models/mocking/search-results.json +843 -843
  17. hestia_earth/models/site/defaultMethodClassification.py +35 -0
  18. hestia_earth/models/site/defaultMethodClassificationDescription.py +39 -0
  19. hestia_earth/models/site/management.py +34 -23
  20. hestia_earth/models/utils/impact_assessment.py +5 -3
  21. hestia_earth/models/utils/lookup.py +3 -3
  22. hestia_earth/models/version.py +1 -1
  23. {hestia_earth_models-0.65.8.dist-info → hestia_earth_models-0.65.10.dist-info}/METADATA +2 -2
  24. {hestia_earth_models-0.65.8.dist-info → hestia_earth_models-0.65.10.dist-info}/RECORD +39 -35
  25. tests/models/cml2001Baseline/test_abioticResourceDepletionFossilFuels.py +2 -16
  26. tests/models/cml2001Baseline/test_abioticResourceDepletionMineralsAndMetals.py +2 -16
  27. tests/models/edip2003/test_ozoneDepletionPotential.py +0 -13
  28. tests/models/environmentalFootprintV3/test_soilQualityIndexLandTransformation.py +8 -15
  29. tests/models/hestia/test_landCover.py +2 -1
  30. tests/models/ipcc2021/test_gwp100.py +0 -9
  31. tests/models/poschEtAl2008/test_terrestrialAcidificationPotentialAccumulatedExceedance.py +0 -14
  32. tests/models/poschEtAl2008/test_terrestrialEutrophicationPotentialAccumulatedExceedance.py +0 -14
  33. tests/models/site/test_defaultMethodClassification.py +18 -0
  34. tests/models/site/test_defaultMethodClassificationDescription.py +18 -0
  35. tests/models/site/test_management.py +2 -1
  36. tests/models/test_config.py +11 -2
  37. {hestia_earth_models-0.65.8.dist-info → hestia_earth_models-0.65.10.dist-info}/LICENSE +0 -0
  38. {hestia_earth_models-0.65.8.dist-info → hestia_earth_models-0.65.10.dist-info}/WHEEL +0 -0
  39. {hestia_earth_models-0.65.8.dist-info → hestia_earth_models-0.65.10.dist-info}/top_level.txt +0 -0
@@ -432,6 +432,24 @@
432
432
  "stage": 2
433
433
  }
434
434
  ],
435
+ [
436
+ {
437
+ "key": "defaultMethodClassification",
438
+ "model": "site",
439
+ "value": "defaultMethodClassification",
440
+ "runStrategy": "add_key_if_missing",
441
+ "mergeStrategy": "default",
442
+ "stage": 2
443
+ },
444
+ {
445
+ "key": "defaultMethodClassificationDescription",
446
+ "model": "site",
447
+ "value": "defaultMethodClassificationDescription",
448
+ "runStrategy": "add_key_if_missing",
449
+ "mergeStrategy": "default",
450
+ "stage": 2
451
+ }
452
+ ],
435
453
  [
436
454
  {
437
455
  "key": "measurements",
@@ -69,3 +69,9 @@ def load_run_config(node_type: str, stage: int):
69
69
 
70
70
  def load_trigger_config(node_type: str, stage: int):
71
71
  return _load_stage_config('trigger-calculations', node_type, stage)
72
+
73
+
74
+ def get_max_stage(node_type: str):
75
+ config = _load_config('run-calculations').get(node_type, {})
76
+ stages = list(map(lambda k: int(k.replace('stage-', '')), config.keys()))
77
+ return max(stages)
@@ -15,11 +15,6 @@
15
15
  "key": "nested",
16
16
  "type": "Site",
17
17
  "stage": 1
18
- },
19
- {
20
- "key": "nested",
21
- "type": "ImpactAssessment",
22
- "stage": 1
23
18
  }
24
19
  ],
25
20
  "stage-2": [
@@ -27,6 +22,11 @@
27
22
  "key": "nested",
28
23
  "type": "Site",
29
24
  "stage": 2
25
+ },
26
+ {
27
+ "key": "nested",
28
+ "type": "ImpactAssessment",
29
+ "stage": 1
30
30
  }
31
31
  ]
32
32
  },
@@ -36,7 +36,7 @@
36
36
  {
37
37
  "key": "related",
38
38
  "type": "Cycle",
39
- "stage": 1
39
+ "stage": 2
40
40
  }
41
41
  ]
42
42
  }
@@ -106,7 +106,7 @@ def _has_depreciated_term(term: dict):
106
106
  def _should_run_input(cycle: dict, input_node: dict) -> bool:
107
107
  term = input_node.get('term', {})
108
108
  term_id = term.get('@id')
109
- has_lifespan = input_node.get('lifespan', 0) > 0
109
+ has_lifespan = input_node.get('lifespan') or 0 > 0
110
110
  has_valid_value = _get_value(input_node, 'value') > 0
111
111
  has_depreciated_term = _has_depreciated_term(term)
112
112
 
@@ -39,12 +39,15 @@ REQUIREMENTS = {
39
39
  }
40
40
  }
41
41
  RETURNS = {
42
- "Practice": [{
43
- "value": "",
44
- "min": "",
45
- "max": "",
46
- "sd": "",
47
- "statsDefinition": "modelled"
42
+ "Animal": [{
43
+ "practices": [{
44
+ "@type": "Practice",
45
+ "value": "",
46
+ "min": "",
47
+ "max": "",
48
+ "sd": "",
49
+ "statsDefinition": "modelled"
50
+ }]
48
51
  }]
49
52
  }
50
53
  LOOKUPS = {
@@ -15,7 +15,7 @@ corresponding value, the `economicValueShare` will be proportionally distributed
15
15
  from hestia_earth.utils.model import find_term_match
16
16
  from hestia_earth.utils.tools import list_sum
17
17
 
18
- from hestia_earth.models.log import logRequirements, logShouldRun
18
+ from hestia_earth.models.log import logRequirements, logShouldRun, log_as_table
19
19
  from hestia_earth.models.utils.blank_node import get_lookup_value
20
20
  from hestia_earth.models.utils.cycle import unique_currencies
21
21
  from .utils import lookup_share
@@ -55,7 +55,7 @@ MIN_COMPLETE_VALUE = 80 # when the products are complete lower the min threshol
55
55
 
56
56
 
57
57
  def _product(product: dict, value: float):
58
- return {**product, MODEL_KEY: value}
58
+ return product | {MODEL_KEY: value}
59
59
 
60
60
 
61
61
  def _is_complete(cycle: dict): return cycle.get('completeness', {}).get('product', False)
@@ -69,7 +69,7 @@ def _total_evs(products: list): return sum([p.get(MODEL_KEY, 0) for p in product
69
69
 
70
70
  def _product_with_value(product: dict):
71
71
  value = product.get(MODEL_KEY, lookup_share(MODEL_KEY, product))
72
- return {**product, MODEL_KEY: value} if value is not None else product
72
+ return product | {MODEL_KEY: value} if value is not None else product
73
73
 
74
74
 
75
75
  def _rescale_value(products: list, total: float):
@@ -87,7 +87,11 @@ def _should_run_by_default(cycle: dict, products: list):
87
87
  for p in products:
88
88
  term_id = p.get('term', {}).get('@id')
89
89
  logRequirements(cycle, model=MODEL, term=term_id, key=MODEL_KEY, by=run_by,
90
- all_with_economicValueShare=all_with_economicValueShare)
90
+ all_with_economicValueShare=all_with_economicValueShare,
91
+ products_with_share=log_as_table([{
92
+ 'id': p.get('term', {}).get('@id'),
93
+ MODEL_KEY: p.get(MODEL_KEY)
94
+ } for p in products]))
91
95
  logShouldRun(cycle, MODEL, term_id, should_run, key=MODEL_KEY, by=run_by)
92
96
 
93
97
  return should_run
@@ -48,18 +48,22 @@ def _run(cycle: dict):
48
48
  def _should_run(cycle: dict):
49
49
  def should_run_product(product: dict):
50
50
  term_id = product.get('term', {}).get('@id')
51
- has_yield = len(product.get('value', [])) > 0
52
- has_price = product.get('price', 0) > 0
53
- has_yield_and_price = has_yield and has_price
54
- is_yield_0 = list_sum(product.get('value', []), -1) == 0
55
- is_price_0 = product.get('price', -1) == 0
51
+
52
+ value = list_sum(product.get('value') or [], default=None)
53
+ has_yield = bool(value)
54
+ is_yield_0 = value == 0
55
+
56
+ price = product.get('price') or -1
57
+ has_price = price > 0
58
+ is_price_0 = price == 0
56
59
 
57
60
  logRequirements(cycle, model=MODEL, term=term_id, key=MODEL_KEY,
58
- has_yield_and_price=has_yield_and_price,
61
+ has_yield=has_yield,
62
+ has_price=has_price,
59
63
  is_yield_0=is_yield_0,
60
64
  is_price_0=is_price_0)
61
65
 
62
- should_run = any([has_yield_and_price, is_yield_0, is_price_0])
66
+ should_run = any([has_yield and has_price, is_yield_0, is_price_0])
63
67
  logShouldRun(cycle, MODEL, term_id, should_run, key=MODEL_KEY)
64
68
  return should_run
65
69
  return should_run_product
@@ -25,7 +25,8 @@ REQUIREMENTS = {
25
25
  {
26
26
  "@type": "Indicator",
27
27
  "term.termType": "resourceUse",
28
- "term.name": "Land transformation",
28
+ "term.@id": ["landTransformation20YearAverageInputsProduction",
29
+ "landTransformation20YearAverageDuringCycle"],
29
30
  "value": "> 0",
30
31
  "landCover": {"@type": "Term", "term.termType": "landCover"},
31
32
  "previousLandCover": {"@type": "Term", "term.termType": "landCover"}
@@ -74,6 +75,10 @@ def _run(transformations: List[dict]):
74
75
  return _indicator(list_sum(values))
75
76
 
76
77
 
78
+ def _is_valid_indicator(indicator: dict) -> bool:
79
+ return indicator['term']['@id'] in REQUIREMENTS['ImpactAssessment']['emissionsResourceUse'][0]['term.@id']
80
+
81
+
77
82
  def _should_run(impact_assessment: dict) -> Tuple[bool, list]:
78
83
  resource_uses = filter_list_term_type(impact_assessment.get('emissionsResourceUse', []), TermTermType.RESOURCEUSE)
79
84
  found_transformations = [
@@ -82,7 +87,9 @@ def _should_run(impact_assessment: dict) -> Tuple[bool, list]:
82
87
  'land-cover-id-from': transformation_indicator.get('previousLandCover', {}).get("@id"),
83
88
  'land-cover-id-to': transformation_indicator.get('landCover', {}).get("@id"),
84
89
  'indicator-id': transformation_indicator.get('term', {}).get('@id', ''),
85
- 'good-land-cover-term': transformation_indicator.get('landCover', {}).get('termType') == 'landCover',
90
+ 'indicator-is-valid': _is_valid_indicator(transformation_indicator),
91
+ 'good-land-cover-term': all([bool(transformation_indicator.get('landCover')),
92
+ bool(transformation_indicator.get('previousLandCover'))]),
86
93
  'country-id': get_country_id(impact_assessment),
87
94
  'area-is-valid': _node_value(transformation_indicator) is not None and _node_value(
88
95
  transformation_indicator) > 0,
@@ -112,19 +119,20 @@ def _should_run(impact_assessment: dict) -> Tuple[bool, list]:
112
119
  valid_transformations_with_coef = [
113
120
  t for t in found_transformations_with_coefficient if all([
114
121
  t['area-is-valid'],
122
+ t['indicator-is-valid'],
115
123
  t['factor-from'] is not None,
116
124
  t['factor-to'] is not None
117
125
  ])
118
126
  ]
119
127
 
120
128
  has_land_transformation_indicators = any([
121
- indicator.get('term', {}).get('@id').startswith('landTransformation')
129
+ _is_valid_indicator(indicator)
122
130
  for indicator in resource_uses
123
131
  ])
124
132
 
125
133
  all_transformations_are_valid = all(
126
134
  [
127
- all([t['area-is-valid'], t['good-land-cover-term']])
135
+ all([t['area-is-valid'], t['indicator-is-valid'], t['good-land-cover-term']])
128
136
  for t in found_transformations_with_coefficient
129
137
  ]
130
138
  ) if found_transformations_with_coefficient else False
@@ -129,7 +129,7 @@ def _run_by_country(cycle: dict, product: dict, country_id: str, year: int = Non
129
129
  term_type = product_term.get('termType')
130
130
  term_units = product_term.get('units')
131
131
 
132
- has_yield = len(product.get('value', [])) > 0
132
+ has_yield = len(product.get('value') or []) > 0
133
133
  not_already_set = MODEL_KEY not in product.keys()
134
134
 
135
135
  # get the grouping used in region lookup
@@ -29,6 +29,11 @@ def to_celcius(kelvin_value: int): return kelvin_value - KELVIN_0 if kelvin_valu
29
29
  def use_geopandas(): return os.getenv('HEE_USE_GEOPANDAS', 'false') == 'true'
30
30
 
31
31
 
32
+ def _has_cache(site: dict):
33
+ cache = cached_value(site, key=CACHE_VALUE, default=None)
34
+ return bool(cache)
35
+
36
+
32
37
  def _cached_value(site: dict, key: str):
33
38
  return cached_value(site, key=CACHE_VALUE, default={}).get(key)
34
39
 
@@ -166,23 +171,23 @@ def download(term: str, site: dict, data: dict, only_coordinates=False) -> dict:
166
171
  Data returned from the API.
167
172
  """
168
173
  # check if we have cached the result already, else run and parse result
169
- value = _get_cached_data(term, site, data)
170
-
171
- # make sure to run only if value is None (not 0)
172
- if value is None:
173
- location_data = geospatial_data(site, only_coordinates=only_coordinates)
174
- query = {
175
- 'ee_type': data.get('ee_type'),
176
- **location_data,
177
- 'collections': [
178
- {
179
- **data,
180
- 'collection': _collection_name(data.get('collection'))
181
- }
182
- ]
183
- }
184
- value = _parse_run_query(term, query)
185
-
174
+ if _has_cache(site):
175
+ # even if the cached value is null, we do not want to run the query again
176
+ # TODO: we might want to store the date it was cached, and run again if more than 30 days
177
+ return _get_cached_data(term, site, data)
178
+
179
+ location_data = geospatial_data(site, only_coordinates=only_coordinates)
180
+ query = {
181
+ 'ee_type': data.get('ee_type'),
182
+ **location_data,
183
+ 'collections': [
184
+ {
185
+ **data,
186
+ 'collection': _collection_name(data.get('collection'))
187
+ }
188
+ ]
189
+ }
190
+ value = _parse_run_query(term, query)
186
191
  if value is None:
187
192
  debugValues(site, model=MODEL, term=term, value_from_earth_engine=None)
188
193
  return value
@@ -34,7 +34,7 @@ from .utils import (
34
34
  crop_ipcc_land_use_category,
35
35
  )
36
36
  from . import MODEL
37
- from ..utils.blank_node import _node_date, DatestrFormat
37
+ from ..utils.blank_node import _node_date, DatestrFormat, _gapfill_datestr, DatestrGapfillMode
38
38
  from ..utils.constant import DAYS_IN_YEAR
39
39
 
40
40
  REQUIREMENTS = {
@@ -697,7 +697,7 @@ def _collect_land_use_types(nodes: list) -> list:
697
697
  {
698
698
  "id": node.get("term", {}).get("@id"),
699
699
  "land-use-type": _get_land_use_term_from_node(node),
700
- "endDate": node.get("endDate")
700
+ "endDate": _gapfill_datestr(datestr=node.get("endDate"), mode=DatestrGapfillMode.END)[:10]
701
701
  } for node in nodes
702
702
  ]
703
703