hestia-earth-models 0.61.6__py3-none-any.whl → 0.61.8__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 (52) hide show
  1. hestia_earth/models/cycle/completeness/electricityFuel.py +56 -0
  2. hestia_earth/models/cycle/input/hestiaAggregatedData.py +1 -1
  3. hestia_earth/models/emepEea2019/nh3ToAirInorganicFertiliser.py +44 -59
  4. hestia_earth/models/geospatialDatabase/histosol.py +4 -0
  5. hestia_earth/models/ipcc2006/co2ToAirOrganicSoilCultivation.py +4 -2
  6. hestia_earth/models/ipcc2006/n2OToAirOrganicSoilCultivationDirect.py +1 -1
  7. hestia_earth/models/ipcc2019/aboveGroundCropResidueTotal.py +1 -1
  8. hestia_earth/models/ipcc2019/belowGroundCropResidue.py +1 -1
  9. hestia_earth/models/ipcc2019/ch4ToAirExcreta.py +1 -1
  10. hestia_earth/models/ipcc2019/co2ToAirSoilOrganicCarbonStockChangeManagementChange.py +511 -458
  11. hestia_earth/models/ipcc2019/co2ToAirUreaHydrolysis.py +5 -1
  12. hestia_earth/models/ipcc2019/organicCarbonPerHa.py +117 -3881
  13. hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_1_utils.py +2060 -0
  14. hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_2_utils.py +1630 -0
  15. hestia_earth/models/ipcc2019/organicCarbonPerHa_utils.py +324 -0
  16. hestia_earth/models/mocking/search-results.json +360 -260
  17. hestia_earth/models/schererPfister2015/pToDrainageWaterSoilFlux.py +1 -1
  18. hestia_earth/models/schererPfister2015/pToGroundwaterSoilFlux.py +1 -1
  19. hestia_earth/models/site/organicCarbonPerHa.py +58 -44
  20. hestia_earth/models/site/soilMeasurement.py +25 -38
  21. hestia_earth/models/utils/__init__.py +28 -0
  22. hestia_earth/models/utils/aquacultureManagement.py +2 -2
  23. hestia_earth/models/utils/array_builders.py +578 -0
  24. hestia_earth/models/utils/blank_node.py +2 -3
  25. hestia_earth/models/utils/crop.py +24 -1
  26. hestia_earth/models/utils/cycle.py +0 -23
  27. hestia_earth/models/utils/descriptive_stats.py +285 -0
  28. hestia_earth/models/utils/emission.py +73 -2
  29. hestia_earth/models/utils/inorganicFertiliser.py +2 -2
  30. hestia_earth/models/utils/lookup.py +6 -3
  31. hestia_earth/models/utils/measurement.py +118 -4
  32. hestia_earth/models/utils/site.py +25 -13
  33. hestia_earth/models/version.py +1 -1
  34. {hestia_earth_models-0.61.6.dist-info → hestia_earth_models-0.61.8.dist-info}/METADATA +1 -1
  35. {hestia_earth_models-0.61.6.dist-info → hestia_earth_models-0.61.8.dist-info}/RECORD +52 -40
  36. tests/models/cycle/completeness/test_electricityFuel.py +21 -0
  37. tests/models/emepEea2019/test_nh3ToAirInorganicFertiliser.py +2 -2
  38. tests/models/ipcc2019/test_co2ToAirSoilOrganicCarbonStockChangeManagementChange.py +54 -165
  39. tests/models/ipcc2019/test_organicCarbonPerHa.py +219 -460
  40. tests/models/ipcc2019/test_organicCarbonPerHa_tier_1_utils.py +471 -0
  41. tests/models/ipcc2019/test_organicCarbonPerHa_tier_2_utils.py +208 -0
  42. tests/models/ipcc2019/test_organicCarbonPerHa_utils.py +75 -0
  43. tests/models/site/test_organicCarbonPerHa.py +3 -12
  44. tests/models/site/test_soilMeasurement.py +5 -19
  45. tests/models/utils/test_array_builders.py +253 -0
  46. tests/models/utils/{test_cycle.py → test_crop.py} +2 -2
  47. tests/models/utils/test_descriptive_stats.py +134 -0
  48. tests/models/utils/test_emission.py +51 -1
  49. tests/models/utils/test_measurement.py +54 -2
  50. {hestia_earth_models-0.61.6.dist-info → hestia_earth_models-0.61.8.dist-info}/LICENSE +0 -0
  51. {hestia_earth_models-0.61.6.dist-info → hestia_earth_models-0.61.8.dist-info}/WHEEL +0 -0
  52. {hestia_earth_models-0.61.6.dist-info → hestia_earth_models-0.61.8.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,56 @@
1
+ """
2
+ Completeness Electricity Fuel
3
+
4
+ This model checks if we have the requirements below and updates the
5
+ [Data Completeness](https://hestia.earth/schema/Completeness#electricityFuel) value.
6
+ """
7
+ from hestia_earth.schema import TermTermType
8
+ from hestia_earth.utils.model import filter_list_term_type
9
+
10
+ from hestia_earth.models.log import logRequirements, log_as_table
11
+ from hestia_earth.models.utils.blank_node import get_lookup_value
12
+ from . import MODEL
13
+
14
+ REQUIREMENTS = {
15
+ "Cycle": {
16
+ "completeness.electricityFuel": "False",
17
+ "practices": [
18
+ {"@type": "Practice", "value": "", "term.termType": "operation"}
19
+ ]
20
+ }
21
+ }
22
+ RETURNS = {
23
+ "Completeness": {
24
+ "electricityFuel": ""
25
+ }
26
+ }
27
+ LOOKUPS = {
28
+ "operation": ["fuelUse", "combustionType"]
29
+ }
30
+ MODEL_KEY = 'electricityFuel'
31
+ _VALID_COMBUSTION_TYPES = ['mobile', 'stationary']
32
+
33
+
34
+ def _lookup_value(practice: dict, lookup_name: str):
35
+ return get_lookup_value(practice.get('term', {}), lookup_name, model=MODEL, model_key=MODEL_KEY)
36
+
37
+
38
+ def _practice_value(practice: dict):
39
+ term = practice.get('term', {})
40
+ fuel_use = _lookup_value(practice, LOOKUPS['operation'][0])
41
+ return {'id': term.get('@id'), 'fuel_use': fuel_use}
42
+
43
+
44
+ def run(cycle: dict):
45
+ practices = filter_list_term_type(cycle.get('practices', []), TermTermType.OPERATION)
46
+ combustion_practices = [
47
+ p for p in practices if _lookup_value(p, LOOKUPS['operation'][1]) in _VALID_COMBUSTION_TYPES
48
+ ]
49
+ practices_values = list(map(_practice_value, combustion_practices))
50
+
51
+ logRequirements(cycle, model=MODEL, term=None, key=MODEL_KEY,
52
+ values=log_as_table(practices_values))
53
+
54
+ is_complete = all([p.get('fuel_use') for p in practices_values])
55
+
56
+ return is_complete
@@ -10,7 +10,7 @@ from hestia_earth.schema import TermTermType
10
10
  from hestia_earth.utils.model import find_primary_product, find_term_match, linked_node
11
11
 
12
12
  from hestia_earth.models.log import debugValues, logRequirements, logShouldRun
13
- from hestia_earth.models.utils.cycle import valid_site_type
13
+ from hestia_earth.models.utils.crop import valid_site_type
14
14
  from hestia_earth.models.utils.term import get_generic_crop
15
15
  from hestia_earth.models.utils.aggregated import (
16
16
  should_link_input_to_impact, link_inputs_to_impact, find_closest_impact, aggregated_end_date
@@ -1,14 +1,13 @@
1
1
  from functools import reduce
2
2
  from hestia_earth.schema import EmissionMethodTier
3
- from hestia_earth.utils.lookup import download_lookup
4
3
  from hestia_earth.utils.model import find_term_match
5
- from hestia_earth.utils.tools import list_sum
4
+ from hestia_earth.utils.tools import list_sum, non_empty_list
6
5
 
7
- from hestia_earth.models.log import debugValues, logRequirements, logShouldRun
6
+ from hestia_earth.models.log import logRequirements, logShouldRun, log_as_table
8
7
  from hestia_earth.models.utils import _filter_list_term_unit
9
8
  from hestia_earth.models.utils.completeness import _is_term_type_complete
10
9
  from hestia_earth.models.utils.inorganicFertiliser import (
11
- get_NH3_emission_factor, get_terms, get_term_lookup, BREAKDOWN_LOOKUP, get_country_breakdown, get_cycle_inputs
10
+ get_NH3_emission_factor, get_terms, get_term_lookup, get_country_breakdown, get_cycle_inputs
12
11
  )
13
12
  from hestia_earth.models.utils.constant import Units
14
13
  from hestia_earth.models.utils.emission import _new_emission
@@ -66,23 +65,21 @@ def _emission(value: float):
66
65
  return emission
67
66
 
68
67
 
69
- def _get_input_value(cycle: dict, soilPh: float, temperature: float):
68
+ def _input_with_factor(soilPh: float, temperature: float):
70
69
  def get_value(input: dict):
71
70
  term_id = input.get('term', {}).get('@id')
72
- factor = get_NH3_emission_factor(term_id, soilPh, temperature)
73
- value = list_sum(input.get('value'))
74
- debugValues(cycle, model=MODEL, term=TERM_ID,
75
- product=term_id,
76
- factor=factor,
77
- value=value)
78
- return value * factor
71
+ factor = get_NH3_emission_factor(term_id, soilPh, temperature) if all([
72
+ soilPh is not None,
73
+ temperature is not None
74
+ ]) else None
75
+ value = list_sum(input.get('value'), None)
76
+ return {'id': term_id, 'value': value, 'factor': factor} if all([
77
+ value is not None,
78
+ factor is not None
79
+ ]) else None
79
80
  return get_value
80
81
 
81
82
 
82
- def _run(cycle: dict, temperature: float, soilPh: float, inputs: float):
83
- return list_sum(list(map(_get_input_value(cycle, soilPh, temperature), inputs)))
84
-
85
-
86
83
  def _get_groupings():
87
84
  term_ids = get_terms()
88
85
 
@@ -93,23 +90,22 @@ def _get_groupings():
93
90
  return reduce(get_grouping, term_ids, {})
94
91
 
95
92
 
96
- def _get_term_value(cycle: dict, soilPh: float, temperature: float, country_id: str, grouping: str, term_id: str):
97
- factor = get_NH3_emission_factor(term_id, soilPh, temperature)
98
- value = get_country_breakdown(MODEL, TERM_ID, country_id, grouping)
99
- debugValues(cycle, model=MODEL, term=TERM_ID,
100
- grouping=grouping,
101
- NH3_factor=factor,
102
- country_breakdown=value)
103
- return value * factor
104
-
105
-
106
- def _run_with_unspecified(cycle: dict, temperature: float, soilPh: float, unspecifiedKgN_value: float, country_id: str):
93
+ def _unspecified_inputs_with_factor(temperature: float, soilPh: float, unspecifiedKgN_value: float, site: dict):
94
+ country_id = site.get('country', {}).get('@id')
107
95
  # creates a dictionary grouping => term_id with only a single key per group (avoid counting twice)
108
96
  groupings = _get_groupings()
109
- return list_sum([
110
- _get_term_value(cycle, soilPh, temperature, country_id, grouping, term_id)
111
- for grouping, term_id in groupings.items()
112
- ]) * unspecifiedKgN_value
97
+ breakdown_inputs = [(
98
+ term_id, get_country_breakdown(MODEL, TERM_ID, country_id, grouping)
99
+ ) for grouping, term_id in groupings.items()] if all([country_id, unspecifiedKgN_value is not None]) else []
100
+ # create inputs from country breakdown
101
+ N_inputs = [
102
+ {
103
+ 'term': {'@id': term_id},
104
+ 'value': [value * unspecifiedKgN_value]
105
+ }
106
+ for term_id, value in breakdown_inputs if value is not None
107
+ ]
108
+ return non_empty_list(map(_input_with_factor(soilPh, temperature), N_inputs))
113
109
 
114
110
 
115
111
  def _should_run(cycle: dict):
@@ -121,49 +117,38 @@ def _should_run(cycle: dict):
121
117
  measurements, 'temperatureAnnual', end_date) or most_relevant_measurement_value(
122
118
  measurements, 'temperatureLongTermAnnualMean', end_date)
123
119
 
124
- inputs = get_cycle_inputs(cycle)
125
- N_inputs = _filter_list_term_unit(inputs, Units.KG_N)
120
+ N_inputs = _filter_list_term_unit(get_cycle_inputs(cycle), Units.KG_N)
126
121
  has_N_inputs = len(N_inputs) > 0
127
122
 
128
- unspecifiedKgN = find_term_match(cycle.get('inputs', []), UNSPECIFIED_TERM_ID).get('value', [])
129
- fertiliser_complete = _is_term_type_complete(cycle, 'fertiliser')
130
- has_unspecifiedKgN = len(unspecifiedKgN) > 0 or fertiliser_complete
123
+ N_inputs_with_factor = non_empty_list(map(_input_with_factor(soilPh, temperature), N_inputs))
124
+ has_N_inputs_with_factor = len(N_inputs_with_factor) > 0
131
125
 
132
- country_id = site.get('country', {}).get('@id')
133
- lookup = download_lookup(BREAKDOWN_LOOKUP)
134
- has_country_data = country_id in list(lookup.termid)
126
+ # fallback using country averages of fertilisers usage
127
+ unspecifiedKgN_value = list_sum(find_term_match(N_inputs, UNSPECIFIED_TERM_ID).get('value'), None)
128
+ unspecified_inputs_with_factor = _unspecified_inputs_with_factor(temperature, soilPh, unspecifiedKgN_value, site)
129
+ has_unspecified_inputs_with_factor = len(unspecified_inputs_with_factor) > 0
135
130
 
136
- run_with_unspecified = (has_country_data and has_unspecifiedKgN) or fertiliser_complete
137
- unspecifiedKgN = (
138
- 0 if len(unspecifiedKgN) == 0 and fertiliser_complete else list_sum(unspecifiedKgN, None)
139
- ) if run_with_unspecified else None
131
+ fertiliser_complete = _is_term_type_complete(cycle, 'fertiliser')
140
132
 
141
133
  logRequirements(cycle, model=MODEL, term=TERM_ID,
134
+ term_type_fertiliser_complete=fertiliser_complete,
142
135
  temperature=temperature,
143
136
  soilPh=soilPh,
144
- term_type_fertiliser_complete=fertiliser_complete,
145
- has_unspecifiedKgN=has_unspecifiedKgN,
146
- has_country_data=has_country_data,
147
- run_with_unspecified=run_with_unspecified,
148
- has_N_inputs=has_N_inputs)
137
+ has_N_inputs=has_N_inputs,
138
+ inorganic_fertiliser_inputs=log_as_table(N_inputs_with_factor),
139
+ unspecified_fertiliser_inputs=log_as_table(unspecified_inputs_with_factor))
149
140
 
150
141
  should_run = all([
142
+ fertiliser_complete,
151
143
  temperature,
152
144
  soilPh,
153
- any([
154
- run_with_unspecified,
155
- has_N_inputs,
156
- not has_N_inputs and fertiliser_complete
157
- ])
145
+ not has_N_inputs or has_N_inputs_with_factor or has_unspecified_inputs_with_factor
158
146
  ])
159
147
  logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
160
- return should_run, temperature, soilPh, N_inputs, unspecifiedKgN, country_id
148
+ return should_run, N_inputs_with_factor or unspecified_inputs_with_factor
161
149
 
162
150
 
163
151
  def run(cycle: dict):
164
- should_run, temperature, soilPh, N_inputs, unspecifiedKgN, country_id = _should_run(cycle)
165
- value = _run(cycle, temperature, soilPh, N_inputs) or (
166
- _run_with_unspecified(cycle, temperature, soilPh, unspecifiedKgN, country_id)
167
- if unspecifiedKgN is not None else None
168
- ) if should_run else None
152
+ should_run, N_inputs_with_factor = _should_run(cycle)
153
+ value = list_sum([i.get('value') * i.get('factor') for i in N_inputs_with_factor]) if should_run else None
169
154
  return [_emission(value)] if value is not None else []
@@ -21,6 +21,8 @@ REQUIREMENTS = {
21
21
  RETURNS = {
22
22
  "Measurement": [{
23
23
  "value": "",
24
+ "depthUpper": "0",
25
+ "depthLower": "30",
24
26
  "methodClassification": "geospatial dataset"
25
27
  }]
26
28
  }
@@ -36,6 +38,8 @@ BIBLIO_TITLE = 'Harmonized World Soil Database Version 1.2. Food and Agriculture
36
38
  def _measurement(site: dict, value: float):
37
39
  measurement = _new_measurement(TERM_ID)
38
40
  measurement['value'] = [round(value, 7)]
41
+ measurement['depthUpper'] = 0
42
+ measurement['depthLower'] = 30
39
43
  measurement['methodClassification'] = MeasurementMethodClassification.GEOSPATIAL_DATASET.value
40
44
  return measurement | get_source(site, BIBLIO_TITLE)
41
45
 
@@ -1,6 +1,7 @@
1
1
  from hestia_earth.schema import EmissionMethodTier
2
2
 
3
3
  from hestia_earth.models.log import logRequirements, logShouldRun
4
+ from hestia_earth.models.utils.constant import Units, get_atomic_conversion
4
5
  from hestia_earth.models.utils.emission import _new_emission
5
6
  from hestia_earth.models.utils.measurement import most_relevant_measurement_value
6
7
  from hestia_earth.models.utils.ecoClimateZone import get_ecoClimateZone_lookup_value
@@ -39,7 +40,6 @@ RETURNS = {
39
40
  }
40
41
  TERM_ID = 'co2ToAirOrganicSoilCultivation'
41
42
  TIER = EmissionMethodTier.TIER_1.value
42
- CONVERT_FACTOR = 44 / 120
43
43
 
44
44
 
45
45
  def _emission(value: float):
@@ -55,7 +55,9 @@ def _run(histosol: float, organic_soil_factor: float, land_occupation: float):
55
55
 
56
56
 
57
57
  def _get_CO2_factor(eco_climate_zone: str, site_type: str):
58
- return get_ecoClimateZone_lookup_value(eco_climate_zone, LOOKUPS['ecoClimateZone'], site_type) * CONVERT_FACTOR
58
+ return get_ecoClimateZone_lookup_value(
59
+ eco_climate_zone, LOOKUPS['ecoClimateZone'], site_type
60
+ ) * 1000 * get_atomic_conversion(Units.KG_CO2, Units.TO_C)
59
61
 
60
62
 
61
63
  def _should_run(cycle: dict):
@@ -57,7 +57,7 @@ def _run(histosol: float, organic_soil_factor: float, land_occupation: float):
57
57
  def _get_N2O_factor(eco_climate_zone: str):
58
58
  return get_ecoClimateZone_lookup_value(
59
59
  eco_climate_zone, LOOKUPS['ecoClimateZone']
60
- ) * get_atomic_conversion(Units.KG_N2O, Units.TO_N) / 10000
60
+ ) * get_atomic_conversion(Units.KG_N2O, Units.TO_N)
61
61
 
62
62
 
63
63
  def _should_run(cycle: dict):
@@ -75,7 +75,7 @@ def _should_run(cycle: dict):
75
75
  term_type_incomplete = _is_term_type_incomplete(cycle, TERM_ID)
76
76
 
77
77
  logRequirements(cycle, model=MODEL, term=TERM_ID,
78
- has_crop_forage_products=has_crop_forage_products,
78
+ has_crop_forage_products_with_dryMatter=has_crop_forage_products,
79
79
  term_type_cropResidue_incomplete=term_type_incomplete)
80
80
 
81
81
  should_run = all([term_type_incomplete, has_crop_forage_products])
@@ -82,7 +82,7 @@ def _should_run(cycle: dict):
82
82
  term_type_incomplete = _is_term_type_incomplete(cycle, TERM_ID)
83
83
 
84
84
  logRequirements(cycle, model=MODEL, term=TERM_ID,
85
- has_crop_forage_products=has_crop_forage_products,
85
+ has_crop_forage_products_with_dryMatter=has_crop_forage_products,
86
86
  term_type_cropResidue_incomplete=term_type_incomplete)
87
87
 
88
88
  should_run = all([term_type_incomplete, has_crop_forage_products])
@@ -95,7 +95,7 @@ def _get_excreta_b0(country: dict, input: dict):
95
95
  )
96
96
 
97
97
 
98
- def _get_excretaManagement_MCF_from_lookup(term_id: str, ecoClimateZone: int, duration_key: DURATION_KEY):
98
+ def _get_excretaManagement_MCF_from_lookup(term_id: str, ecoClimateZone: int, duration_key: DURATION):
99
99
  lookup_name = 'excretaManagement-ecoClimateZone-CH4conv.csv'
100
100
  lookup = download_lookup(lookup_name)
101
101
  data_values = get_table_value(lookup, 'termid', term_id, str(ecoClimateZone))