hestia-earth-models 0.59.2__py3-none-any.whl → 0.59.4__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 (34) hide show
  1. hestia_earth/models/geospatialDatabase/potentialEvapotranspirationMonthly.py +98 -0
  2. hestia_earth/models/geospatialDatabase/precipitationMonthly.py +98 -0
  3. hestia_earth/models/geospatialDatabase/temperatureAnnual.py +1 -2
  4. hestia_earth/models/geospatialDatabase/temperatureMonthly.py +98 -0
  5. hestia_earth/models/geospatialDatabase/utils.py +8 -1
  6. hestia_earth/models/ipcc2006/n2OToAirCropResidueDecompositionDirect.py +83 -0
  7. hestia_earth/models/ipcc2006/utils.py +12 -0
  8. hestia_earth/models/ipcc2019/nh3ToAirInorganicFertiliser.py +112 -0
  9. hestia_earth/models/ipcc2019/nh3ToAirOrganicFertiliser.py +6 -3
  10. hestia_earth/models/ipcc2019/noxToAirInorganicFertiliser.py +112 -0
  11. hestia_earth/models/ipcc2019/noxToAirOrganicFertiliser.py +6 -3
  12. hestia_earth/models/ipcc2019/organicCarbonPerHa.py +13 -28
  13. hestia_earth/models/mocking/search-results.json +8 -8
  14. hestia_earth/models/site/management.py +6 -6
  15. hestia_earth/models/site/pre_checks/cache_geospatialDatabase.py +27 -7
  16. hestia_earth/models/site/utils.py +2 -6
  17. hestia_earth/models/utils/__init__.py +9 -0
  18. hestia_earth/models/utils/site.py +8 -5
  19. hestia_earth/models/version.py +1 -1
  20. {hestia_earth_models-0.59.2.dist-info → hestia_earth_models-0.59.4.dist-info}/METADATA +2 -2
  21. {hestia_earth_models-0.59.2.dist-info → hestia_earth_models-0.59.4.dist-info}/RECORD +34 -22
  22. tests/models/geospatialDatabase/test_potentialEvapotranspirationMonthly.py +20 -0
  23. tests/models/geospatialDatabase/test_precipitationMonthly.py +20 -0
  24. tests/models/geospatialDatabase/test_temperatureMonthly.py +20 -0
  25. tests/models/ipcc2006/test_n2OToAirCropResidueDecompositionDirect.py +50 -0
  26. tests/models/ipcc2019/test_nh3ToAirInorganicFertiliser.py +47 -0
  27. tests/models/ipcc2019/test_noxToAirInorganicFertiliser.py +47 -0
  28. tests/models/ipcc2019/test_organicCarbonPerHa.py +10 -22
  29. tests/models/site/test_management.py +13 -13
  30. tests/models/utils/test_blank_node.py +5 -5
  31. tests/models/utils/test_site.py +1 -1
  32. {hestia_earth_models-0.59.2.dist-info → hestia_earth_models-0.59.4.dist-info}/LICENSE +0 -0
  33. {hestia_earth_models-0.59.2.dist-info → hestia_earth_models-0.59.4.dist-info}/WHEEL +0 -0
  34. {hestia_earth_models-0.59.2.dist-info → hestia_earth_models-0.59.4.dist-info}/top_level.txt +0 -0
@@ -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 KELVIN_0, 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 _to_celcius(kelvin_value: int): return kelvin_value - KELVIN_0 if kelvin_value else None
52
+
53
+
54
+ def _download(site: dict, start_date: str, end_date: str):
55
+ return download(
56
+ TERM_ID,
57
+ site,
58
+ {
59
+ **EE_PARAMS,
60
+ 'start_date': start_date,
61
+ 'end_date': end_date
62
+ }
63
+ )
64
+
65
+
66
+ def _run(site: dict, years: list):
67
+ # fetch from first year to last
68
+ years = range(years[0], years[-1] + 1) if len(years) > 1 else years
69
+
70
+ dates = flatten([
71
+ [
72
+ (first_day_of_month(year, month).strftime('%Y-%m-%d'), last_day_of_month(year, month).strftime('%Y-%m-%d'))
73
+ for month in range(1, 13)
74
+ ] for year in years
75
+ ])
76
+ values = non_empty_list([
77
+ (_to_celcius(_download(site, start_date, end_date)), start_date[0:7]) for start_date, end_date in dates
78
+ ])
79
+ return _measurement(site, [v for v, d in values], [d for v, d in values])
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 []
@@ -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 KELVIN_0, 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 _to_celcius(kelvin_value: int): return kelvin_value - KELVIN_0 if kelvin_value else None
52
+
53
+
54
+ def _download(site: dict, start_date: str, end_date: str):
55
+ return download(
56
+ TERM_ID,
57
+ site,
58
+ {
59
+ **EE_PARAMS,
60
+ 'start_date': start_date,
61
+ 'end_date': end_date
62
+ }
63
+ )
64
+
65
+
66
+ def _run(site: dict, years: list):
67
+ # fetch from first year to last
68
+ years = range(years[0], years[-1] + 1) if len(years) > 1 else years
69
+
70
+ dates = flatten([
71
+ [
72
+ (first_day_of_month(year, month).strftime('%Y-%m-%d'), last_day_of_month(year, month).strftime('%Y-%m-%d'))
73
+ for month in range(1, 13)
74
+ ] for year in years
75
+ ])
76
+ values = non_empty_list([
77
+ (_to_celcius(_download(site, start_date, end_date)), start_date[0:7]) for start_date, end_date in dates
78
+ ])
79
+ return _measurement(site, [v for v, d in values], [d for v, d in values])
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 []
@@ -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 KELVIN_0, 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):
@@ -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 KELVIN_0, 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 _to_celcius(kelvin_value: int): return kelvin_value - KELVIN_0 if kelvin_value else None
52
+
53
+
54
+ def _download(site: dict, start_date: str, end_date: str):
55
+ return download(
56
+ TERM_ID,
57
+ site,
58
+ {
59
+ **EE_PARAMS,
60
+ 'start_date': start_date,
61
+ 'end_date': end_date
62
+ }
63
+ )
64
+
65
+
66
+ def _run(site: dict, years: list):
67
+ # fetch from first year to last
68
+ years = range(years[0], years[-1] + 1) if len(years) > 1 else years
69
+
70
+ dates = flatten([
71
+ [
72
+ (first_day_of_month(year, month).strftime('%Y-%m-%d'), last_day_of_month(year, month).strftime('%Y-%m-%d'))
73
+ for month in range(1, 13)
74
+ ] for year in years
75
+ ])
76
+ values = non_empty_list([
77
+ (_to_celcius(_download(site, start_date, end_date)), start_date[0:7]) for start_date, end_date in dates
78
+ ])
79
+ return _measurement(site, [v for v, d in values], [d for v, d in values])
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,7 @@ GEOPANDAS_COLLECTION_NAME = {
19
20
  'gadm36_4': 'gadm/gadm36_4',
20
21
  'gadm36_5': 'gadm/gadm36_5'
21
22
  }
23
+ KELVIN_0 = 273.15
22
24
 
23
25
 
24
26
  def use_geopandas(): return os.getenv('HEE_USE_GEOPANDAS', 'false') == 'true'
@@ -131,8 +133,13 @@ def _parse_run_query(term: str, query: dict):
131
133
 
132
134
  def _get_cached_data(term: str, site: dict, data: dict):
133
135
  cache = _cached_value(site, term)
136
+ cache_sub_key = '-'.join(non_empty_list([
137
+ data.get('year'),
138
+ data.get('start_date'),
139
+ data.get('end_date')
140
+ ]))
134
141
  # 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
142
+ value = cache.get(cache_sub_key) if cache_sub_key and cache is not None else cache
136
143
  if value is not None:
137
144
  debugValues(site, model=MODEL, term=term, value_from_cache=value)
138
145
  return value
@@ -0,0 +1,83 @@
1
+ from hestia_earth.schema import EmissionMethodTier, EmissionStatsDefinition, TermTermType
2
+
3
+ from hestia_earth.models.log import logRequirements, logShouldRun, debugValues, log_as_table
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.emission import _new_emission
7
+ from hestia_earth.models.utils.cycle import get_crop_residue_decomposition_N_total
8
+ from hestia_earth.models.utils.product import has_flooded_rice
9
+ from .utils import N2O_FACTORS
10
+ from . import MODEL
11
+
12
+ REQUIREMENTS = {
13
+ "Cycle": {
14
+ "completeness.cropResidue": "True",
15
+ "products": [{
16
+ "@type": "Product",
17
+ "value": "",
18
+ "term.termType": "cropResidue",
19
+ "properties": [{"@type": "Property", "value": "", "term.@id": "nitrogenContent"}]
20
+ }],
21
+ "optional": {
22
+ "products": [{"@type": "Product", "term.@id": "riceGrainInHuskFlooded"}]
23
+ }
24
+ }
25
+ }
26
+ RETURNS = {
27
+ "Emission": [{
28
+ "value": "",
29
+ "min": "",
30
+ "max": "",
31
+ "methodTier": "tier 1",
32
+ "statsDefinition": "modelled"
33
+ }]
34
+ }
35
+ LOOKUPS = {
36
+ "cropResidue": "decomposesOnField"
37
+ }
38
+ TERM_ID = 'n2OToAirCropResidueDecompositionDirect'
39
+ TIER = EmissionMethodTier.TIER_1.value
40
+
41
+
42
+ def _emission(value: float, min: float, max: float):
43
+ emission = _new_emission(TERM_ID, MODEL)
44
+ emission['value'] = [value]
45
+ emission['min'] = [min]
46
+ emission['max'] = [max]
47
+ emission['methodTier'] = TIER
48
+ emission['statsDefinition'] = EmissionStatsDefinition.MODELLED.value
49
+ return emission
50
+
51
+
52
+ def _run(cycle: dict, N_total: float):
53
+ flooded_rice = has_flooded_rice(cycle.get('products', []))
54
+
55
+ converted_N_total = N_total * get_atomic_conversion(Units.KG_N2O, Units.TO_N)
56
+ factors = N2O_FACTORS['flooded_rice'] if flooded_rice else N2O_FACTORS['default']
57
+
58
+ debugValues(cycle, model=MODEL, term=TERM_ID,
59
+ has_flooded_rice=flooded_rice,
60
+ factors_used=log_as_table(factors))
61
+
62
+ value = converted_N_total * factors['value']
63
+ min = converted_N_total * factors['min']
64
+ max = converted_N_total * factors['max']
65
+ return [_emission(value, min, max)]
66
+
67
+
68
+ def _should_run(cycle: dict):
69
+ term_type_complete = _is_term_type_complete(cycle, TermTermType.CROPRESIDUE)
70
+ N_crop_residue = get_crop_residue_decomposition_N_total(cycle)
71
+
72
+ logRequirements(cycle, model=MODEL, term=TERM_ID,
73
+ term_type_cropResidue_complete=term_type_complete,
74
+ N_crop_residue=N_crop_residue)
75
+
76
+ should_run = all([N_crop_residue is not None, term_type_complete])
77
+ logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
78
+ return should_run, N_crop_residue
79
+
80
+
81
+ def run(cycle: dict):
82
+ should_run, N_total = _should_run(cycle)
83
+ return _run(cycle, N_total) if should_run else []
@@ -2,6 +2,18 @@ from hestia_earth.utils.model import find_primary_product
2
2
 
3
3
  COEFF_NH3NOX_N2O = 0.01
4
4
  COEFF_NO3_N2O = 0.0075
5
+ N2O_FACTORS = {
6
+ 'default': {
7
+ 'value': 0.01,
8
+ 'min': 0.003,
9
+ 'max': 0.03
10
+ },
11
+ 'flooded_rice': {
12
+ 'value': 0.003,
13
+ 'min': 0,
14
+ 'max': 0.006
15
+ }
16
+ }
5
17
 
6
18
 
7
19
  def get_N_N2O_excreta_coeff_from_primary_product(cycle: dict):
@@ -0,0 +1,112 @@
1
+ from hestia_earth.schema import EmissionMethodTier, EmissionStatsDefinition, TermTermType
2
+ from hestia_earth.utils.model import filter_list_term_type, find_term_match
3
+ from hestia_earth.utils.tools import list_sum
4
+
5
+ from hestia_earth.models.log import logRequirements, logShouldRun, debugValues, log_as_table
6
+ from hestia_earth.models.utils.blank_node import get_N_total
7
+ from hestia_earth.models.utils.constant import Units, get_atomic_conversion
8
+ from hestia_earth.models.utils.completeness import _is_term_type_complete
9
+ from hestia_earth.models.utils.emission import _new_emission
10
+ from hestia_earth.models.utils.cycle import get_inorganic_fertiliser_N_total
11
+ from hestia_earth.models.utils.term import get_lookup_value
12
+ from . import MODEL
13
+
14
+ REQUIREMENTS = {
15
+ "Cycle": {
16
+ "completeness.fertiliser": "True",
17
+ "inputs": [
18
+ {
19
+ "@type": "Input",
20
+ "value": "",
21
+ "term.termType": "inorganicFertiliser",
22
+ "optional": {
23
+ "properties": [{"@type": "Property", "value": "", "term.@id": "nitrogenContent"}]
24
+ }
25
+ }
26
+ ]
27
+ }
28
+ }
29
+ RETURNS = {
30
+ "Emission": [{
31
+ "value": "",
32
+ "sd": "",
33
+ "min": "",
34
+ "max": "",
35
+ "methodTier": "tier 1",
36
+ "statsDefinition": "modelled",
37
+ "methodModelDescription": ["Aggregated version", "Disaggragated version"]
38
+ }]
39
+ }
40
+ LOOKUPS = {
41
+ "inorganicFertiliser": ["IPCC_2019_FRACGASF_NH3-N", "IPCC_2019_FRACGASF_NH3-N-min", "IPCC_2019_FRACGASF_NH3-N-max"]
42
+ }
43
+ TERM_ID = 'nh3ToAirInorganicFertiliser'
44
+ TIER = EmissionMethodTier.TIER_1.value
45
+ TERM_TYPE = TermTermType.INORGANICFERTILISER
46
+ UNSPECIFIED_TERM_ID = 'inorganicNitrogenFertiliserUnspecifiedKgN'
47
+
48
+
49
+ def _emission(value: float, min: float, max: float, aggregated: bool = False):
50
+ emission = _new_emission(TERM_ID, MODEL)
51
+ emission['value'] = [value]
52
+ emission['min'] = [min]
53
+ emission['max'] = [max]
54
+ emission['methodTier'] = TIER
55
+ emission['statsDefinition'] = EmissionStatsDefinition.MODELLED.value
56
+ emission['methodModelDescription'] = 'Aggregated version' if aggregated else 'Disaggregated version'
57
+ return emission
58
+
59
+
60
+ def _input_values(input: dict):
61
+ N_total = list_sum(get_N_total([input]))
62
+ lookups = LOOKUPS[TERM_TYPE.value]
63
+ return {
64
+ 'id': input.get('term', {}).get('@id'),
65
+ 'N': N_total,
66
+ 'value': get_lookup_value(input.get('term', {}), lookups[0]),
67
+ 'min': get_lookup_value(input.get('term', {}), lookups[1]),
68
+ 'max': get_lookup_value(input.get('term', {}), lookups[2])
69
+ }
70
+
71
+
72
+ def _filter_input_values(values: list, key: str): return [value for value in values if value.get(key)]
73
+
74
+
75
+ def _run(cycle: dict):
76
+ inputs = filter_list_term_type(cycle.get('inputs', []), TERM_TYPE)
77
+ input_values = list(map(_input_values, inputs))
78
+
79
+ debugValues(cycle, model=MODEL, term=TERM_ID,
80
+ input_values=log_as_table(input_values))
81
+
82
+ value = list_sum([
83
+ v.get('N', 0) * v.get('value', 0) for v in _filter_input_values(input_values, 'value')
84
+ ]) * get_atomic_conversion(Units.KG_NH3, Units.TO_N)
85
+
86
+ min = list_sum([
87
+ v.get('N', 0) * v.get('min', 0) for v in _filter_input_values(input_values, 'min')
88
+ ]) * get_atomic_conversion(Units.KG_NH3, Units.TO_N)
89
+
90
+ max = list_sum([
91
+ v.get('N', 0) * v.get('max', 0) for v in _filter_input_values(input_values, 'max')
92
+ ]) * get_atomic_conversion(Units.KG_NH3, Units.TO_N)
93
+
94
+ aggregated = list_sum(find_term_match(inputs, UNSPECIFIED_TERM_ID).get('value', [0])) > 0
95
+
96
+ return [_emission(value, min, max, aggregated=aggregated)]
97
+
98
+
99
+ def _should_run(cycle: dict):
100
+ N_inorganic_fertiliser = get_inorganic_fertiliser_N_total(cycle)
101
+ fertiliser_complete = _is_term_type_complete(cycle, 'fertiliser')
102
+
103
+ logRequirements(cycle, model=MODEL, term=TERM_ID,
104
+ N_inorganic_fertiliser=N_inorganic_fertiliser,
105
+ term_type_fertiliser_complete=fertiliser_complete)
106
+
107
+ should_run = all([N_inorganic_fertiliser is not None, fertiliser_complete])
108
+ logShouldRun(cycle, MODEL, TERM_ID, should_run)
109
+ return should_run
110
+
111
+
112
+ def run(cycle: dict): return _run(cycle) if _should_run(cycle) else []
@@ -66,6 +66,9 @@ def _input_values(input: dict):
66
66
  }
67
67
 
68
68
 
69
+ def _filter_input_values(values: list, key: str): return [value for value in values if value.get(key)]
70
+
71
+
69
72
  def _run(cycle: dict):
70
73
  inputs = filter_list_term_type(cycle.get('inputs', []), TermTermType.ORGANICFERTILISER)
71
74
  input_values = list(map(_input_values, inputs))
@@ -74,15 +77,15 @@ def _run(cycle: dict):
74
77
  input_values=log_as_table(input_values))
75
78
 
76
79
  value = list_sum([
77
- v.get('N', 0) * v.get('value', 0) for v in input_values
80
+ v.get('N', 0) * v.get('value', 0) for v in _filter_input_values(input_values, 'value')
78
81
  ]) * get_atomic_conversion(Units.KG_NH3, Units.TO_N)
79
82
 
80
83
  min = list_sum([
81
- v.get('N', 0) * v.get('min', 0) for v in input_values
84
+ v.get('N', 0) * v.get('min', 0) for v in _filter_input_values(input_values, 'min')
82
85
  ]) * get_atomic_conversion(Units.KG_NH3, Units.TO_N)
83
86
 
84
87
  max = list_sum([
85
- v.get('N', 0) * v.get('max', 0) for v in input_values
88
+ v.get('N', 0) * v.get('max', 0) for v in _filter_input_values(input_values, 'max')
86
89
  ]) * get_atomic_conversion(Units.KG_NH3, Units.TO_N)
87
90
 
88
91
  return [_emission(value, min, max)]