hestia-earth-models 0.50.0__py3-none-any.whl → 0.51.1__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 (58) hide show
  1. hestia_earth/models/agribalyse2016/fuelElectricity.py +7 -4
  2. hestia_earth/models/agribalyse2016/machineryInfrastructureDepreciatedAmountPerCycle.py +14 -5
  3. hestia_earth/models/cycle/input/ecoinventV3.py +10 -2
  4. hestia_earth/models/cycle/input/hestiaAggregatedData.py +5 -2
  5. hestia_earth/models/emepEea2019/co2ToAirFuelCombustion.py +5 -2
  6. hestia_earth/models/emepEea2019/n2OToAirFuelCombustionDirect.py +5 -2
  7. hestia_earth/models/emepEea2019/nh3ToAirExcreta.py +10 -4
  8. hestia_earth/models/emepEea2019/noxToAirFuelCombustion.py +5 -2
  9. hestia_earth/models/emepEea2019/so2ToAirFuelCombustion.py +5 -2
  10. hestia_earth/models/emepEea2019/utils.py +22 -3
  11. hestia_earth/models/environmentalFootprintV3/{freshwaterEcotoxicityPotentialPaf.py → freshwaterEcotoxicityPotentialCtue.py} +2 -2
  12. hestia_earth/models/geospatialDatabase/aware.py +5 -4
  13. hestia_earth/models/geospatialDatabase/ecoregion.py +5 -4
  14. hestia_earth/models/geospatialDatabase/region.py +7 -11
  15. hestia_earth/models/geospatialDatabase/utils.py +39 -25
  16. hestia_earth/models/geospatialDatabase/waterDepth.py +5 -4
  17. hestia_earth/models/impact_assessment/__init__.py +3 -3
  18. hestia_earth/models/ipcc2019/ch4ToAirExcreta.py +4 -2
  19. hestia_earth/models/ipcc2019/croppingDuration.py +1 -1
  20. hestia_earth/models/ipcc2019/n2OToAirInorganicFertiliserIndirect.py +106 -0
  21. hestia_earth/models/ipcc2019/n2OToAirOrganicFertiliserIndirect.py +108 -0
  22. hestia_earth/models/ipcc2019/utils.py +37 -0
  23. hestia_earth/models/jarvisAndPain1994/__init__.py +13 -0
  24. hestia_earth/models/jarvisAndPain1994/n2ToAirExcreta.py +53 -0
  25. hestia_earth/models/koble2014/aboveGroundCropResidue.py +44 -21
  26. hestia_earth/models/koble2014/utils.py +5 -1
  27. hestia_earth/models/log.py +19 -0
  28. hestia_earth/models/mocking/search-results.json +301 -252
  29. hestia_earth/models/pooreNemecek2018/aboveGroundCropResidueTotal.py +15 -8
  30. hestia_earth/models/pooreNemecek2018/plantationProductiveLifespan.py +18 -6
  31. hestia_earth/models/pooreNemecek2018/rotationDuration.py +15 -5
  32. hestia_earth/models/pooreNemecek2018/utils.py +4 -2
  33. hestia_earth/models/schmidt2007/__init__.py +13 -0
  34. hestia_earth/models/schmidt2007/ch4ToAirWasteTreatment.py +60 -0
  35. hestia_earth/models/schmidt2007/utils.py +16 -0
  36. hestia_earth/models/transformation/input/excreta.py +4 -2
  37. hestia_earth/models/transformation/product/excreta.py +2 -2
  38. hestia_earth/models/usetoxV2/{freshwaterEcotoxicityPotentialPaf.py → freshwaterEcotoxicityPotentialCtue.py} +2 -2
  39. hestia_earth/models/utils/term.py +6 -0
  40. hestia_earth/models/version.py +1 -1
  41. {hestia_earth_models-0.50.0.dist-info → hestia_earth_models-0.51.1.dist-info}/METADATA +2 -2
  42. {hestia_earth_models-0.50.0.dist-info → hestia_earth_models-0.51.1.dist-info}/RECORD +58 -44
  43. tests/models/emepEea2019/test_utils.py +17 -3
  44. tests/models/environmentalFootprintV3/{test_freshwaterEcotoxicityPotentialPaf.py → test_freshwaterEcotoxicityPotentialCtue.py} +1 -1
  45. tests/models/geospatialDatabase/test_region.py +4 -5
  46. tests/models/geospatialDatabase/test_utils.py +10 -1
  47. tests/models/ipcc2019/test_n2OToAirInorganicFertiliserIndirect.py +48 -0
  48. tests/models/ipcc2019/test_n2OToAirOrganicFertiliserIndirect.py +48 -0
  49. tests/models/jarvisAndPain1994/__init__.py +0 -0
  50. tests/models/jarvisAndPain1994/test_n2ToAirExcreta.py +37 -0
  51. tests/models/koble2014/test_aboveGroundCropResidue.py +13 -0
  52. tests/models/schmidt2007/__init__.py +0 -0
  53. tests/models/schmidt2007/test_ch4ToAirWasteTreatment.py +45 -0
  54. tests/models/schmidt2007/test_utils.py +39 -0
  55. tests/models/usetoxV2/{test_freshwaterEcotoxicityPotentialPaf.py → test_freshwaterEcotoxicityPotentialCtue.py} +1 -1
  56. {hestia_earth_models-0.50.0.dist-info → hestia_earth_models-0.51.1.dist-info}/LICENSE +0 -0
  57. {hestia_earth_models-0.50.0.dist-info → hestia_earth_models-0.51.1.dist-info}/WHEEL +0 -0
  58. {hestia_earth_models-0.50.0.dist-info → hestia_earth_models-0.51.1.dist-info}/top_level.txt +0 -0
@@ -8,7 +8,7 @@ from hestia_earth.schema import InputStatsDefinition, TermTermType
8
8
  from hestia_earth.utils.model import filter_list_term_type
9
9
  from hestia_earth.utils.tools import flatten, list_sum, non_empty_list
10
10
 
11
- from hestia_earth.models.log import debugValues, logRequirements, logShouldRun
11
+ from hestia_earth.models.log import debugValues, logRequirements, logShouldRun, log_as_table
12
12
  from hestia_earth.models.utils.term import get_lookup_value
13
13
  from hestia_earth.models.utils.input import _new_input
14
14
  from . import MODEL
@@ -53,9 +53,12 @@ def _operation_input(operation: dict):
53
53
  def _run_operation(cycle: dict):
54
54
  def exec(operations: list):
55
55
  input_term_id = operations[0].get('input').get('id')
56
- values_logs = ';'.join([
57
- f"id:{p.get('term').get('@id')}_value:{p.get('value')}_coefficient:{p.get('input').get('value')}"
58
- for p in operations
56
+ values_logs = log_as_table([
57
+ {
58
+ 'id': p.get('term').get('@id'),
59
+ 'value': p.get('value'),
60
+ 'coefficient': p.get('input').get('value')
61
+ } for p in operations
59
62
  ])
60
63
 
61
64
  debugValues(cycle, model=MODEL, term=input_term_id,
@@ -10,9 +10,9 @@ the machinery-to-diesel ratio was doubled in countries with a [Human Development
10
10
  of less than 0.8.
11
11
  """
12
12
  from hestia_earth.schema import InputStatsDefinition
13
- from hestia_earth.utils.model import find_term_match
13
+ from hestia_earth.utils.tools import list_sum, flatten
14
14
 
15
- from hestia_earth.models.log import logRequirements, logShouldRun
15
+ from hestia_earth.models.log import logRequirements, logShouldRun, debugValues, log_as_table
16
16
  from hestia_earth.models.utils.productivity import _get_productivity, PRODUCTIVITY
17
17
  from hestia_earth.models.utils.input import _new_input
18
18
  from hestia_earth.models.utils.completeness import _is_term_type_incomplete
@@ -55,15 +55,24 @@ def _input(value: float):
55
55
 
56
56
 
57
57
  def _get_input_value_from_term(inputs: list, term_id: str):
58
- val = find_term_match(inputs, term_id, None)
59
- return val.get('value', [0])[0] if val is not None else 0
58
+ values = flatten([
59
+ input.get('value', []) for input in inputs if input.get('term', {}).get('@id') == term_id
60
+ ])
61
+ return list_sum(values, 0) if len(values) > 0 else None
60
62
 
61
63
 
62
64
  def get_value(country: dict, cycle: dict):
63
65
  liquid_fuels = get_liquid_fuel_terms()
64
66
  productivity_key = _get_productivity(country)
65
67
  machinery_usage = 11.5 if productivity_key == PRODUCTIVITY.HIGH else 23
66
- fuel_use = sum([_get_input_value_from_term(cycle.get('inputs', []), term_id) for term_id in liquid_fuels])
68
+ values = [(term_id, _get_input_value_from_term(cycle.get('inputs', []), term_id)) for term_id in liquid_fuels]
69
+ value_logs = log_as_table([{'id': term_id, 'value': value} for term_id, value in values])
70
+ values = [value for term_id, value in values if value is not None]
71
+ fuel_use = list_sum(values, 0)
72
+ debugValues(cycle, model=MODEL, term=TERM_ID,
73
+ productivity_key=productivity_key.value,
74
+ fuel_use_details=value_logs,
75
+ fuel_use=fuel_use)
67
76
  return fuel_use/machinery_usage if fuel_use > 0 else None
68
77
 
69
78
 
@@ -27,7 +27,13 @@ from hestia_earth.models.utils.blank_node import group_by_keys
27
27
 
28
28
  REQUIREMENTS = {
29
29
  "Cycle": {
30
- "inputs": [{"@type": "Input", "value": "> 0"}]
30
+ "inputs": [{
31
+ "@type": "Input",
32
+ "value": "> 0",
33
+ "none": {
34
+ "fromCycle": "True"
35
+ }
36
+ }]
31
37
  }
32
38
  }
33
39
  RETURNS = {
@@ -113,7 +119,9 @@ def _should_run_input(products: list):
113
119
  return all([
114
120
  list_sum(input.get('value', [])) > 0,
115
121
  # make sure Input is not a Product as well or we might double-count emissions
116
- find_term_match(products, input.get('term', {}).get('@id'), None) is None
122
+ find_term_match(products, input.get('term', {}).get('@id'), None) is None,
123
+ # ignore inputs which are flagged as Product of the Cycle
124
+ not input.get('fromCycle', False)
117
125
  ])
118
126
  return should_run
119
127
 
@@ -23,7 +23,8 @@ REQUIREMENTS = {
23
23
  "@type": "Input",
24
24
  "value": "",
25
25
  "none": {
26
- "impactAssessment": ""
26
+ "impactAssessment": "",
27
+ "fromCycle": "True"
27
28
  },
28
29
  "optional": {
29
30
  "country": {"@type": "Term", "termType": "region"},
@@ -196,7 +197,9 @@ def _should_run_input(products: list):
196
197
  not input.get(MODEL_KEY),
197
198
  _should_aggregate_input(term),
198
199
  # make sure Input is not a Product as well or we might double-count emissions
199
- find_term_match(products, term.get('@id'), None) is None
200
+ find_term_match(products, term.get('@id'), None) is None,
201
+ # ignore inputs which are flagged as Product of the Cycle
202
+ not input.get('fromCycle', False)
200
203
  ])
201
204
  return should_run
202
205
 
@@ -10,7 +10,9 @@ REQUIREMENTS = {
10
10
  "Cycle": {
11
11
  "or": {
12
12
  "inputs": [
13
- {"@type": "Input", "value": "", "term.termType": "fuel"}
13
+ {"@type": "Input", "value": "", "term.termType": "fuel", "optional": {
14
+ "operation": ""
15
+ }}
14
16
  ],
15
17
  "completeness.electricityFuel": "True"
16
18
  }
@@ -24,7 +26,8 @@ RETURNS = {
24
26
  }]
25
27
  }
26
28
  LOOKUPS = {
27
- "fuel": "co2ToAirFuelCombustionEmepEea2019"
29
+ "fuel": "co2ToAirFuelCombustionEmepEea2019",
30
+ "operation": "co2ToAirFuelCombustionEmepEea2019"
28
31
  }
29
32
  TERM_ID = 'co2ToAirFuelCombustion'
30
33
  TIER = EmissionMethodTier.TIER_1.value
@@ -10,7 +10,9 @@ REQUIREMENTS = {
10
10
  "Cycle": {
11
11
  "or": {
12
12
  "inputs": [
13
- {"@type": "Input", "value": "", "term.termType": "fuel"}
13
+ {"@type": "Input", "value": "", "term.termType": "fuel", "optional": {
14
+ "operation": ""
15
+ }}
14
16
  ],
15
17
  "completeness.electricityFuel": "True"
16
18
  }
@@ -24,7 +26,8 @@ RETURNS = {
24
26
  }]
25
27
  }
26
28
  LOOKUPS = {
27
- "fuel": "n2oToAirFuelCombustionEmepEea2019"
29
+ "fuel": "n2OToAirFuelCombustionEmepEea2019",
30
+ "operation": "n2OToAirFuelCombustionEmepEea2019"
28
31
  }
29
32
  TERM_ID = 'n2OToAirFuelCombustionDirect'
30
33
  TIER = EmissionMethodTier.TIER_1.value
@@ -3,9 +3,10 @@ from hestia_earth.utils.lookup import column_name, download_lookup, get_table_va
3
3
  from hestia_earth.utils.model import filter_list_term_type
4
4
  from hestia_earth.utils.tools import safe_parse_float, list_sum
5
5
 
6
- from hestia_earth.models.log import logRequirements, debugMissingLookup, logShouldRun
6
+ from hestia_earth.models.log import logRequirements, debugMissingLookup, logShouldRun, log_as_table
7
7
  from hestia_earth.models.utils import _filter_list_term_unit
8
8
  from hestia_earth.models.utils.constant import Units, get_atomic_conversion
9
+ from hestia_earth.models.utils.completeness import _is_term_type_complete
9
10
  from hestia_earth.models.utils.emission import _new_emission
10
11
  from hestia_earth.models.utils.input import total_excreta_tan
11
12
  from . import MODEL
@@ -62,6 +63,8 @@ def _run(excreta_EF_product: float):
62
63
 
63
64
 
64
65
  def _should_run(cycle: dict):
66
+ excreta_complete = _is_term_type_complete(cycle, {'termType': TermTermType.EXCRETA.value})
67
+
65
68
  practices = filter_list_term_type(cycle.get('practices', []), TermTermType.EXCRETAMANAGEMENT)
66
69
  practice_id = practices[0].get('term', {}).get('@id') if len(practices) > 0 else None
67
70
 
@@ -71,18 +74,21 @@ def _should_run(cycle: dict):
71
74
  excreta_values = [
72
75
  (i.get('term', {}).get('@id'), total_excreta_tan([i]), _get_nh3_factor(practice_id, i)) for i in excreta
73
76
  ]
74
- excreta_logs = ';'.join([f"id:{id}_value:{v}_EF:{f}" for id, v, f in excreta_values])
77
+ excreta_logs = log_as_table([
78
+ {'id': id, 'value': v, 'EF': ef} for id, v, ef in excreta_values
79
+ ])
75
80
  excreta_EF_products = [v * f for id, v, f in excreta_values if f is not None]
76
81
  has_excreta_EF_products = len(excreta_EF_products) > 0
77
- excreta_EF_product = list_sum(excreta_EF_products)
82
+ excreta_EF_product = list_sum(excreta_EF_products, 0)
78
83
 
79
84
  logRequirements(cycle, model=MODEL, term=TERM_ID,
85
+ excreta_complete=excreta_complete,
80
86
  practice_id=practice_id,
81
87
  excreta=excreta_logs,
82
88
  excreta_EF_product=excreta_EF_product,
83
89
  has_excreta_EF_products=has_excreta_EF_products)
84
90
 
85
- should_run = all([has_excreta_EF_products])
91
+ should_run = excreta_complete or all([has_excreta_EF_products])
86
92
  logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
87
93
  return should_run, excreta_EF_product
88
94
 
@@ -10,7 +10,9 @@ REQUIREMENTS = {
10
10
  "Cycle": {
11
11
  "or": {
12
12
  "inputs": [
13
- {"@type": "Input", "value": "", "term.termType": "fuel"}
13
+ {"@type": "Input", "value": "", "term.termType": "fuel", "optional": {
14
+ "operation": ""
15
+ }}
14
16
  ],
15
17
  "completeness.electricityFuel": "True"
16
18
  }
@@ -24,7 +26,8 @@ RETURNS = {
24
26
  }]
25
27
  }
26
28
  LOOKUPS = {
27
- "fuel": "noxToAirFuelCombustionEmepEea2019"
29
+ "fuel": "noxToAirFuelCombustionEmepEea2019",
30
+ "operation": "noxToAirFuelCombustionEmepEea2019"
28
31
  }
29
32
  TERM_ID = 'noxToAirFuelCombustion'
30
33
  TIER = EmissionMethodTier.TIER_1.value
@@ -10,7 +10,9 @@ REQUIREMENTS = {
10
10
  "Cycle": {
11
11
  "or": {
12
12
  "inputs": [
13
- {"@type": "Input", "value": "", "term.termType": "fuel"}
13
+ {"@type": "Input", "value": "", "term.termType": "fuel", "optional": {
14
+ "operation": ""
15
+ }}
14
16
  ],
15
17
  "completeness.electricityFuel": "True"
16
18
  }
@@ -24,7 +26,8 @@ RETURNS = {
24
26
  }]
25
27
  }
26
28
  LOOKUPS = {
27
- "fuel": "so2ToAirFuelCombustionEmepEea2019"
29
+ "fuel": "so2ToAirFuelCombustionEmepEea2019",
30
+ "operation": "so2ToAirFuelCombustionEmepEea2019"
28
31
  }
29
32
  TERM_ID = 'so2ToAirFuelCombustion'
30
33
  TIER = EmissionMethodTier.TIER_1.value
@@ -1,14 +1,33 @@
1
1
  from hestia_earth.schema import NodeType, TermTermType
2
2
  from hestia_earth.utils.model import filter_list_term_type
3
- from hestia_earth.utils.tools import non_empty_list
3
+ from hestia_earth.utils.lookup import extract_grouped_data
4
+ from hestia_earth.utils.tools import list_sum, safe_parse_float
4
5
 
5
6
  from hestia_earth.models.utils.completeness import _is_term_type_complete
6
- from hestia_earth.models.utils.lookup import factor_value
7
+ from hestia_earth.models.utils.term import get_lookup_value
8
+ from . import MODEL
9
+
10
+
11
+ def _get_fuel_input_value(term_id: str, lookup_col: str):
12
+ def get_value(input: dict):
13
+ input_term = input.get('term', {})
14
+ input_term_id = input_term.get('@id')
15
+ operation_term = input.get('operation', {})
16
+ input_value = list_sum(input.get('value', []))
17
+
18
+ operation_factor = extract_grouped_data(
19
+ get_lookup_value(operation_term, lookup_col, model=MODEL, term=term_id), input_term_id
20
+ ) if operation_term else None
21
+ input_factor = operation_factor or get_lookup_value(input_term, lookup_col, model=MODEL, term=term_id)
22
+
23
+ return input_value * safe_parse_float(input_factor)
24
+ return get_value
7
25
 
8
26
 
9
27
  def get_fuel_values(term_id: str, cycle: dict, lookup_col: str):
10
28
  inputs = filter_list_term_type(cycle.get('inputs', []), TermTermType.FUEL)
11
- values = non_empty_list(map(factor_value(None, term_id, f"{TermTermType.FUEL.value}.csv", lookup_col), inputs))
29
+ values = list(map(_get_fuel_input_value(term_id, lookup_col), inputs))
30
+
12
31
  return [0] if all([
13
32
  len(values) == 0,
14
33
  _is_term_type_complete(cycle, {'termType': 'electricityFuel'}),
@@ -17,9 +17,9 @@ RETURNS = {
17
17
  }
18
18
  }
19
19
  LOOKUPS = {
20
- "pesticideAI": "pafM3DFreshwaterEcotoxicityUsetoxHC20EC10eq"
20
+ "pesticideAI": "pafM3DFreshwaterEcotoxicityUsetox2-1Hc20Ec10eq"
21
21
  }
22
- TERM_ID = 'freshwaterEcotoxicityPotentialPaf'
22
+ TERM_ID = 'freshwaterEcotoxicityPotentialCtue'
23
23
 
24
24
 
25
25
  def _indicator(value: float):
@@ -11,7 +11,8 @@ REQUIREMENTS = {
11
11
  "Site": {
12
12
  "or": [
13
13
  {"latitude": "", "longitude": ""},
14
- {"boundary": {}}
14
+ {"boundary": {}},
15
+ {"region": {"@type": "Term", "termType": "region"}}
15
16
  ]
16
17
  }
17
18
  }
@@ -27,15 +28,15 @@ EE_PARAMS = {
27
28
 
28
29
 
29
30
  def _download(site: dict):
30
- return download(MODEL_KEY, site, EE_PARAMS, EE_PARAMS['field'], by_region=False)
31
+ return download(MODEL_KEY, site, EE_PARAMS, EE_PARAMS['field'])
31
32
 
32
33
 
33
34
  def _run(site: dict): return _download(site)
34
35
 
35
36
 
36
37
  def _should_run(site: dict):
37
- contains_geospatial_data = has_geospatial_data(site, by_region=False)
38
- below_max_area_size = should_download(MODEL_KEY, site, by_region=False)
38
+ contains_geospatial_data = has_geospatial_data(site)
39
+ below_max_area_size = should_download(MODEL_KEY, site)
39
40
 
40
41
  logRequirements(site, model=MODEL, model_key=MODEL_KEY,
41
42
  contains_geospatial_data=contains_geospatial_data,
@@ -13,7 +13,8 @@ REQUIREMENTS = {
13
13
  "Site": {
14
14
  "or": [
15
15
  {"latitude": "", "longitude": ""},
16
- {"boundary": {}}
16
+ {"boundary": {}},
17
+ {"region": {"@type": "Term", "termType": "region"}}
17
18
  ]
18
19
  }
19
20
  }
@@ -29,7 +30,7 @@ EE_PARAMS = {
29
30
 
30
31
 
31
32
  def _download(site: dict):
32
- return download(MODEL_KEY, site, EE_PARAMS, EE_PARAMS['fields'], by_region=False)
33
+ return download(MODEL_KEY, site, EE_PARAMS, EE_PARAMS['fields'])
33
34
 
34
35
 
35
36
  def _run(site: dict):
@@ -41,8 +42,8 @@ def _run(site: dict):
41
42
 
42
43
 
43
44
  def _should_run(site: dict):
44
- contains_geospatial_data = has_geospatial_data(site, by_region=False)
45
- below_max_area_size = should_download(MODEL_KEY, site, by_region=False)
45
+ contains_geospatial_data = has_geospatial_data(site)
46
+ below_max_area_size = should_download(MODEL_KEY, site)
46
47
 
47
48
  logRequirements(site, model=MODEL, key=MODEL_KEY,
48
49
  contains_geospatial_data=contains_geospatial_data,
@@ -8,15 +8,13 @@ from hestia_earth.utils.api import download_hestia
8
8
  from hestia_earth.utils.model import linked_node
9
9
 
10
10
  from hestia_earth.models.log import debugValues, logRequirements, logShouldRun
11
- from .utils import download, has_geospatial_data, should_download
11
+ from .utils import download, has_coordinates
12
12
  from . import MODEL
13
13
 
14
14
  REQUIREMENTS = {
15
15
  "Site": {
16
- "or": [
17
- {"latitude": "", "longitude": ""},
18
- {"boundary": {}}
19
- ]
16
+ "latitude": "",
17
+ "longitude": ""
20
18
  }
21
19
  }
22
20
  RETURNS = {
@@ -39,7 +37,7 @@ def _download_by_level(site: dict, level: int):
39
37
  'fields': field
40
38
  },
41
39
  field,
42
- by_region=False
40
+ only_coordinates=True
43
41
  )
44
42
  try:
45
43
  return None if gadm_id is None else linked_node(download_hestia(f"GADM-{gadm_id}"))
@@ -60,14 +58,12 @@ def _run(site: dict):
60
58
 
61
59
 
62
60
  def _should_run(site: dict):
63
- contains_geospatial_data = has_geospatial_data(site, by_region=False)
64
- below_max_area_size = should_download(MODEL_KEY, site, by_region=False)
61
+ contains_coordinates = has_coordinates(site)
65
62
 
66
63
  logRequirements(site, model=MODEL, key=MODEL_KEY,
67
- contains_geospatial_data=contains_geospatial_data,
68
- below_max_area_size=below_max_area_size)
64
+ contains_coordinates=contains_coordinates)
69
65
 
70
- should_run = all([contains_geospatial_data, below_max_area_size])
66
+ should_run = all([contains_coordinates])
71
67
  logShouldRun(site, MODEL, None, should_run, key=MODEL_KEY)
72
68
  return should_run
73
69
 
@@ -15,13 +15,16 @@ MAX_AREA_SIZE = int(os.getenv('MAX_AREA_SIZE', '5000'))
15
15
  def _collection_name(id: str): return id if '/' in id else f"users/hestiaplatform/{id}"
16
16
 
17
17
 
18
- def _has_coordinates(site: dict): return site.get('latitude') is not None and site.get('longitude') is not None
18
+ def has_coordinates(site: dict): return all([site.get('latitude') is not None, site.get('longitude') is not None])
19
+
20
+
21
+ def has_boundary(site: dict): return site.get('boundary') is not None
19
22
 
20
23
 
21
24
  def _site_gadm_id(site: dict): return site.get('region', site.get('country', {})).get('@id')
22
25
 
23
26
 
24
- def has_geospatial_data(site: dict, by_region=True):
27
+ def has_geospatial_data(site: dict):
25
28
  """
26
29
  Determines whether the Site has enough geospatial data to run calculations. We are checking for:
27
30
  1. If the coordinates (latitude and longitude) are present
@@ -33,49 +36,60 @@ def has_geospatial_data(site: dict, by_region=True):
33
36
  ----------
34
37
  site : dict
35
38
  The `Site` node.
36
- by_region : bool
37
- If we can run using the region ID (`region` or `country` fields). Defaults to true.
38
39
 
39
40
  Returns
40
41
  -------
41
42
  bool
42
43
  If we should run geospatial calculations on this model or not.
43
44
  """
44
- has_region = _site_gadm_id(site) is not None
45
- has_boundary = site.get('boundary') is not None
46
- return _has_coordinates(site) or (by_region and has_region) or has_boundary
45
+ return has_coordinates(site) or _site_gadm_id(site) is not None or has_boundary(site)
47
46
 
48
47
 
49
- def _geospatial_data(site: dict, by_region=True):
48
+ def _geospatial_data(site: dict, only_coordinates=False):
50
49
  return {
51
50
  'latitude': site.get('latitude'),
52
51
  'longitude': site.get('longitude'),
53
- 'boundary': site.get('boundary'),
54
- **({'gadm_id': _site_gadm_id(site)} if by_region else {})
52
+ **({} if only_coordinates else {
53
+ 'boundary': site.get('boundary'),
54
+ 'gadm_id': _site_gadm_id(site)
55
+ })
55
56
  }
56
57
 
57
58
 
58
- def should_download(term: str, site: dict, by_region=True) -> bool:
59
+ def _get_geospatial_area_size(site: dict):
59
60
  try:
60
61
  from hestia_earth.earth_engine import get_size_km2
61
62
  except ImportError:
62
63
  raise ImportError("Run `pip install hestia_earth.earth_engine` to use this functionality")
63
64
 
64
65
  try:
65
- current_size = get_size_km2(_geospatial_data(site, by_region))
66
- # coordinates will not return a size
67
- if current_size is not None:
68
- logRequirements(site, model=MODEL, term=term,
69
- current_size=int(current_size),
70
- max_area_size=MAX_AREA_SIZE)
71
- return current_size <= MAX_AREA_SIZE
72
- return True
73
- except Exception as e:
74
- # if the type is unknown, a geospatial param is missing and will be detected by `has_geospatial_data`
75
- return 'Unkown type' in str(e)
66
+ return get_size_km2(_geospatial_data(site))
67
+ except Exception:
68
+ return None
69
+
70
+
71
+ def _get_area_size(site: dict):
72
+ return (
73
+ # fallback if `boundary` provided but no `boundaryArea` was computed
74
+ site.get('boundaryArea') or _get_geospatial_area_size(site)
75
+ ) if has_boundary(site) else download_hestia(_site_gadm_id(site)).get('area')
76
+
77
+
78
+ def _is_below_max_size(term: str, site: dict) -> bool:
79
+ current_size = _get_area_size(site)
80
+ if current_size is not None:
81
+ logRequirements(site, model=MODEL, term=term,
82
+ current_size=int(current_size),
83
+ max_area_size=MAX_AREA_SIZE)
84
+ return current_size <= MAX_AREA_SIZE
85
+ return True
86
+
87
+
88
+ def should_download(term: str, site: dict) -> bool:
89
+ return has_coordinates(site) or _is_below_max_size(term, site)
76
90
 
77
91
 
78
- def download(term: str, site: dict, data: dict, field: str, by_region=True) -> dict:
92
+ def download(term: str, site: dict, data: dict, field: str, only_coordinates=False) -> dict:
79
93
  """
80
94
  Downloads data from Hestia Earth Engine API.
81
95
 
@@ -93,7 +107,7 @@ def download(term: str, site: dict, data: dict, field: str, by_region=True) -> d
93
107
  collection = data.get('collection')
94
108
  res = run({
95
109
  **data,
96
- **_geospatial_data(site, by_region=by_region),
110
+ **_geospatial_data(site, only_coordinates=only_coordinates),
97
111
  'max_area': MAX_AREA_SIZE,
98
112
  'collection': _collection_name(collection)
99
113
  })
@@ -124,7 +138,7 @@ def _coordinates_query(site: dict):
124
138
  }
125
139
  }
126
140
  }
127
- } if _has_coordinates(site) else None
141
+ } if has_coordinates(site) else None
128
142
 
129
143
 
130
144
  def _region_query(site: dict):
@@ -9,7 +9,8 @@ REQUIREMENTS = {
9
9
  "Site": {
10
10
  "or": [
11
11
  {"latitude": "", "longitude": ""},
12
- {"boundary": {}}
12
+ {"boundary": {}},
13
+ {"region": {"@type": "Term", "termType": "region"}}
13
14
  ]
14
15
  }
15
16
  }
@@ -38,7 +39,7 @@ def _measurement(value: float):
38
39
 
39
40
 
40
41
  def _download(site: dict):
41
- return download(TERM_ID, site, EE_PARAMS, EE_PARAMS['reducer'], by_region=False)
42
+ return download(TERM_ID, site, EE_PARAMS, EE_PARAMS['reducer'])
42
43
 
43
44
 
44
45
  def _run(site: dict):
@@ -47,8 +48,8 @@ def _run(site: dict):
47
48
 
48
49
 
49
50
  def _should_run(site: dict):
50
- contains_geospatial_data = has_geospatial_data(site, by_region=False)
51
- below_max_area_size = should_download(TERM_ID, site, by_region=False)
51
+ contains_geospatial_data = has_geospatial_data(site)
52
+ below_max_area_size = should_download(TERM_ID, site)
52
53
 
53
54
  logRequirements(site, model=MODEL, term=TERM_ID,
54
55
  contains_geospatial_data=contains_geospatial_data,
@@ -2,12 +2,12 @@ from os.path import dirname, abspath
2
2
  import sys
3
3
  from importlib import import_module
4
4
 
5
+ from hestia_earth.models.utils.blank_node import run_if_required
6
+
5
7
  CURRENT_DIR = dirname(abspath(__file__)) + '/'
6
8
  sys.path.append(CURRENT_DIR)
7
9
  MODEL = 'impact_assessment'
8
10
  PKG = '.'.join(['hestia_earth', 'models', MODEL])
9
11
 
10
12
 
11
- def run(model: str, data):
12
- run = getattr(import_module(f".{model}", package=PKG), 'run')
13
- return run(data)
13
+ def run(model: str, data): return run_if_required(MODEL, model, data, import_module(f".{model}", package=PKG))
@@ -4,7 +4,7 @@ from hestia_earth.utils.lookup import column_name, download_lookup, get_table_va
4
4
  from hestia_earth.utils.model import filter_list_term_type
5
5
  from hestia_earth.utils.tools import safe_parse_float, list_sum
6
6
 
7
- from hestia_earth.models.log import debugValues, logRequirements, debugMissingLookup, logShouldRun
7
+ from hestia_earth.models.log import debugValues, logRequirements, debugMissingLookup, logShouldRun, log_as_table
8
8
  from hestia_earth.models.utils import _filter_list_term_unit
9
9
  from hestia_earth.models.utils.constant import Units
10
10
  from hestia_earth.models.utils.completeness import _is_term_type_complete
@@ -142,7 +142,9 @@ def _should_run(cycle: dict):
142
142
  excreta_values = [
143
143
  (i.get('term', {}).get('@id'), total_excreta([i], Units.KG_VS), _get_excreta_b0(country, i)) for i in excreta
144
144
  ]
145
- excreta_logs = ';'.join([f"id:{id}_value:{v}_b0:{f}" for id, v, f in excreta_values])
145
+ excreta_logs = log_as_table([
146
+ {'id': id, 'value': v, 'b0': b0} for id, v, b0 in excreta_values
147
+ ])
146
148
  excreta_b0_product = list_sum([v * f for id, v, f in excreta_values])
147
149
 
148
150
  ch4_conv_factor = _get_ch4_conv_factor(cycle)
@@ -76,7 +76,7 @@ def _should_run(cycle: dict):
76
76
  logRequirements(cycle, model=MODEL, term=TERM_ID,
77
77
  country=country,
78
78
  cycleDuration=cycleDuration,
79
- flooded_rice=flooded_rice)
79
+ has_flooded_rice=flooded_rice)
80
80
 
81
81
  should_run = all([country, cycleDuration, flooded_rice])
82
82
  logShouldRun(cycle, MODEL, TERM_ID, should_run)