hestia-earth-models 0.51.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 (44) hide show
  1. hestia_earth/models/agribalyse2016/machineryInfrastructureDepreciatedAmountPerCycle.py +14 -5
  2. hestia_earth/models/emepEea2019/co2ToAirFuelCombustion.py +5 -2
  3. hestia_earth/models/emepEea2019/n2OToAirFuelCombustionDirect.py +5 -2
  4. hestia_earth/models/emepEea2019/nh3ToAirExcreta.py +6 -2
  5. hestia_earth/models/emepEea2019/noxToAirFuelCombustion.py +5 -2
  6. hestia_earth/models/emepEea2019/so2ToAirFuelCombustion.py +5 -2
  7. hestia_earth/models/emepEea2019/utils.py +22 -3
  8. hestia_earth/models/geospatialDatabase/aware.py +5 -4
  9. hestia_earth/models/geospatialDatabase/ecoregion.py +5 -4
  10. hestia_earth/models/geospatialDatabase/region.py +7 -11
  11. hestia_earth/models/geospatialDatabase/utils.py +39 -25
  12. hestia_earth/models/geospatialDatabase/waterDepth.py +5 -4
  13. hestia_earth/models/impact_assessment/__init__.py +3 -3
  14. hestia_earth/models/ipcc2019/croppingDuration.py +1 -1
  15. hestia_earth/models/ipcc2019/n2OToAirInorganicFertiliserIndirect.py +106 -0
  16. hestia_earth/models/ipcc2019/n2OToAirOrganicFertiliserIndirect.py +108 -0
  17. hestia_earth/models/ipcc2019/utils.py +37 -0
  18. hestia_earth/models/jarvisAndPain1994/__init__.py +13 -0
  19. hestia_earth/models/jarvisAndPain1994/n2ToAirExcreta.py +53 -0
  20. hestia_earth/models/koble2014/aboveGroundCropResidue.py +44 -21
  21. hestia_earth/models/koble2014/utils.py +5 -1
  22. hestia_earth/models/mocking/search-results.json +298 -261
  23. hestia_earth/models/pooreNemecek2018/aboveGroundCropResidueTotal.py +15 -8
  24. hestia_earth/models/schmidt2007/__init__.py +13 -0
  25. hestia_earth/models/schmidt2007/ch4ToAirWasteTreatment.py +60 -0
  26. hestia_earth/models/schmidt2007/utils.py +16 -0
  27. hestia_earth/models/utils/term.py +6 -0
  28. hestia_earth/models/version.py +1 -1
  29. {hestia_earth_models-0.51.0.dist-info → hestia_earth_models-0.51.1.dist-info}/METADATA +1 -1
  30. {hestia_earth_models-0.51.0.dist-info → hestia_earth_models-0.51.1.dist-info}/RECORD +44 -30
  31. tests/models/emepEea2019/test_utils.py +17 -3
  32. tests/models/geospatialDatabase/test_region.py +4 -5
  33. tests/models/geospatialDatabase/test_utils.py +10 -1
  34. tests/models/ipcc2019/test_n2OToAirInorganicFertiliserIndirect.py +48 -0
  35. tests/models/ipcc2019/test_n2OToAirOrganicFertiliserIndirect.py +48 -0
  36. tests/models/jarvisAndPain1994/__init__.py +0 -0
  37. tests/models/jarvisAndPain1994/test_n2ToAirExcreta.py +37 -0
  38. tests/models/koble2014/test_aboveGroundCropResidue.py +13 -0
  39. tests/models/schmidt2007/__init__.py +0 -0
  40. tests/models/schmidt2007/test_ch4ToAirWasteTreatment.py +45 -0
  41. tests/models/schmidt2007/test_utils.py +39 -0
  42. {hestia_earth_models-0.51.0.dist-info → hestia_earth_models-0.51.1.dist-info}/LICENSE +0 -0
  43. {hestia_earth_models-0.51.0.dist-info → hestia_earth_models-0.51.1.dist-info}/WHEEL +0 -0
  44. {hestia_earth_models-0.51.0.dist-info → hestia_earth_models-0.51.1.dist-info}/top_level.txt +0 -0
@@ -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
 
@@ -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
@@ -6,6 +6,7 @@ from hestia_earth.utils.tools import safe_parse_float, list_sum
6
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
 
@@ -76,15 +79,16 @@ def _should_run(cycle: dict):
76
79
  ])
77
80
  excreta_EF_products = [v * f for id, v, f in excreta_values if f is not None]
78
81
  has_excreta_EF_products = len(excreta_EF_products) > 0
79
- excreta_EF_product = list_sum(excreta_EF_products)
82
+ excreta_EF_product = list_sum(excreta_EF_products, 0)
80
83
 
81
84
  logRequirements(cycle, model=MODEL, term=TERM_ID,
85
+ excreta_complete=excreta_complete,
82
86
  practice_id=practice_id,
83
87
  excreta=excreta_logs,
84
88
  excreta_EF_product=excreta_EF_product,
85
89
  has_excreta_EF_products=has_excreta_EF_products)
86
90
 
87
- should_run = all([has_excreta_EF_products])
91
+ should_run = excreta_complete or all([has_excreta_EF_products])
88
92
  logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
89
93
  return should_run, excreta_EF_product
90
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'}),
@@ -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))
@@ -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)
@@ -0,0 +1,106 @@
1
+ from hestia_earth.schema import EmissionMethodTier, EmissionStatsDefinition, TermTermType
2
+
3
+ from hestia_earth.models.log import debugValues, logRequirements, logShouldRun
4
+ from hestia_earth.models.utils.constant import Units, get_atomic_conversion
5
+ from hestia_earth.models.utils.completeness import _is_term_type_complete
6
+ from hestia_earth.models.utils.cycle import get_inorganic_fertiliser_N_total, get_ecoClimateZone
7
+ from hestia_earth.models.utils.emission import _new_emission
8
+ from .utils import get_nh3_no3_nox_to_n, COEFF_NO3_N2O, COEFF_N_NH3NOX_inorganic, get_FracNH3NOx_N2O, get_FracLEACH_H
9
+ from . import MODEL
10
+
11
+ REQUIREMENTS = {
12
+ "Cycle": {
13
+ "completeness.fertiliser": "True",
14
+ "completeness.water": "True",
15
+ "inputs": [
16
+ {
17
+ "@type": "Input",
18
+ "value": "",
19
+ "term.termType": "inorganicFertiliser",
20
+ "term.units": "kg N"
21
+ }
22
+ ],
23
+ "emissions": [
24
+ {"@type": "Emission", "value": "", "term.@id": "no3ToGroundwaterInorganicFertiliser"},
25
+ {"@type": "Emission", "value": "", "term.@id": "nh3ToAirInorganicFertiliser"},
26
+ {"@type": "Emission", "value": "", "term.@id": "noxToAirInorganicFertiliser"}
27
+ ],
28
+ "site": {
29
+ "@type": "Site",
30
+ "measurements": [{"@type": "Measurement", "value": "", "term.@id": "ecoClimateZone"}]
31
+ },
32
+ "optional": {
33
+ "practices": [{"@type": "Practice", "value": "", "term.termType": "waterRegime"}]
34
+ }
35
+ }
36
+ }
37
+ RETURNS = {
38
+ "Emission": [{
39
+ "value": "",
40
+ "sd": "",
41
+ "min": "",
42
+ "max": "",
43
+ "methodTier": "tier 1",
44
+ "statsDefinition": "modelled"
45
+ }]
46
+ }
47
+
48
+ TERM_ID = 'n2OToAirInorganicFertiliserIndirect'
49
+ NO3_TERM_ID = 'no3ToGroundwaterInorganicFertiliser'
50
+ NH3_TERM_ID = 'nh3ToAirInorganicFertiliser'
51
+ NOX_TERM_ID = 'noxToAirInorganicFertiliser'
52
+ TIER = EmissionMethodTier.TIER_1.value
53
+
54
+
55
+ def _emission(value: float, sd: float, min: float, max: float):
56
+ emission = _new_emission(TERM_ID, MODEL)
57
+ emission['value'] = [value]
58
+ emission['sd'] = [sd]
59
+ emission['min'] = [min]
60
+ emission['max'] = [max]
61
+ emission['methodTier'] = TIER
62
+ emission['statsDefinition'] = EmissionStatsDefinition.MODELLED.value
63
+ return emission
64
+
65
+
66
+ def _run(cycle: dict):
67
+ N_total = get_inorganic_fertiliser_N_total(cycle)
68
+ nh3_n, no3_n, nox_n = get_nh3_no3_nox_to_n(cycle, NH3_TERM_ID, NO3_TERM_ID, NOX_TERM_ID)
69
+ debugValues(cycle, model=MODEL, term=TERM_ID,
70
+ no3_n=no3_n,
71
+ nh3_n=nh3_n,
72
+ nox_n=nox_n)
73
+ value, min_val, max_val, std = [
74
+ get_FracNH3NOx_N2O(cycle, TERM_ID)[x] * (
75
+ N_total * COEFF_N_NH3NOX_inorganic[x] if nox_n == 0 or nh3_n == 0 else nh3_n + nox_n
76
+ ) +
77
+ COEFF_NO3_N2O[x] * (
78
+ N_total * get_FracLEACH_H(cycle, TERM_ID)[x] if no3_n == 0 else no3_n
79
+ ) for x in range(4)
80
+ ]
81
+ return [_emission(
82
+ value * get_atomic_conversion(Units.KG_N2O, Units.TO_N),
83
+ std * get_atomic_conversion(Units.KG_N2O, Units.TO_N),
84
+ min_val * get_atomic_conversion(Units.KG_N2O, Units.TO_N),
85
+ max_val * get_atomic_conversion(Units.KG_N2O, Units.TO_N)
86
+ )]
87
+
88
+
89
+ def _should_run(cycle: dict):
90
+ N_inorganic_fertiliser = get_inorganic_fertiliser_N_total(cycle)
91
+ ecoClimateZone = get_ecoClimateZone(cycle)
92
+ fertiliser_complete = _is_term_type_complete(cycle, {'termType': 'fertiliser'})
93
+ water_complete = _is_term_type_complete(cycle, {'termType': TermTermType.WATER.value})
94
+
95
+ logRequirements(cycle, model=MODEL, term=TERM_ID,
96
+ N_inorganic_fertiliser=N_inorganic_fertiliser,
97
+ ecoClimateZone=ecoClimateZone,
98
+ fertiliser_complete=fertiliser_complete,
99
+ water_complete=water_complete)
100
+
101
+ should_run = all([N_inorganic_fertiliser >= 0, ecoClimateZone, fertiliser_complete, water_complete])
102
+ logShouldRun(cycle, MODEL, TERM_ID, should_run)
103
+ return should_run
104
+
105
+
106
+ def run(cycle: dict): return _run(cycle) if _should_run(cycle) else []