hestia-earth-models 0.57.2__py3-none-any.whl → 0.59.0__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 (109) hide show
  1. hestia_earth/models/cycle/aboveGroundCropResidueTotal.py +17 -12
  2. hestia_earth/models/cycle/excretaKgMass.py +4 -5
  3. hestia_earth/models/cycle/excretaKgN.py +4 -5
  4. hestia_earth/models/cycle/excretaKgVs.py +4 -5
  5. hestia_earth/models/cycle/inorganicFertiliser.py +2 -2
  6. hestia_earth/models/cycle/{irrigated.py → irrigatedTypeUnspecified.py} +4 -4
  7. hestia_earth/models/cycle/liveAnimal.py +9 -11
  8. hestia_earth/models/cycle/milkYield.py +154 -0
  9. hestia_earth/models/cycle/residueIncorporated.py +1 -1
  10. hestia_earth/models/cycle/utils.py +6 -0
  11. hestia_earth/models/emepEea2019/nh3ToAirInorganicFertiliser.py +3 -3
  12. hestia_earth/models/faostat2018/seed.py +2 -3
  13. hestia_earth/models/geospatialDatabase/clayContent.py +17 -4
  14. hestia_earth/models/geospatialDatabase/sandContent.py +17 -4
  15. hestia_earth/models/geospatialDatabase/siltContent.py +2 -2
  16. hestia_earth/models/impact_assessment/irrigated.py +0 -3
  17. hestia_earth/models/ipcc2006/co2ToAirOrganicSoilCultivation.py +2 -2
  18. hestia_earth/models/ipcc2006/n2OToAirCropResidueDecompositionIndirect.py +2 -2
  19. hestia_earth/models/ipcc2006/n2OToAirExcretaDirect.py +1 -1
  20. hestia_earth/models/ipcc2006/n2OToAirExcretaIndirect.py +8 -4
  21. hestia_earth/models/ipcc2006/n2OToAirInorganicFertiliserDirect.py +4 -1
  22. hestia_earth/models/ipcc2006/n2OToAirInorganicFertiliserIndirect.py +1 -1
  23. hestia_earth/models/ipcc2006/n2OToAirOrganicFertiliserDirect.py +1 -1
  24. hestia_earth/models/ipcc2006/n2OToAirOrganicFertiliserIndirect.py +1 -1
  25. hestia_earth/models/ipcc2006/utils.py +11 -8
  26. hestia_earth/models/ipcc2019/ch4ToAirEntericFermentation.py +4 -4
  27. hestia_earth/models/ipcc2019/ch4ToAirFloodedRice.py +16 -7
  28. hestia_earth/models/ipcc2019/co2ToAirSoilCarbonStockChangeManagementChange.py +759 -0
  29. hestia_earth/models/ipcc2019/croppingDuration.py +12 -6
  30. hestia_earth/models/ipcc2019/n2OToAirCropResidueDecompositionDirect.py +5 -52
  31. hestia_earth/models/ipcc2019/n2OToAirInorganicFertiliserDirect.py +104 -0
  32. hestia_earth/models/ipcc2019/n2OToAirInorganicFertiliserIndirect.py +1 -1
  33. hestia_earth/models/ipcc2019/n2OToAirOrganicFertiliserDirect.py +105 -0
  34. hestia_earth/models/ipcc2019/n2OToAirOrganicFertiliserIndirect.py +1 -1
  35. hestia_earth/models/ipcc2019/no3ToGroundwaterCropResidueDecomposition.py +1 -1
  36. hestia_earth/models/ipcc2019/no3ToGroundwaterExcreta.py +1 -1
  37. hestia_earth/models/ipcc2019/no3ToGroundwaterInorganicFertiliser.py +1 -1
  38. hestia_earth/models/ipcc2019/no3ToGroundwaterOrganicFertiliser.py +1 -1
  39. hestia_earth/models/ipcc2019/organicCarbonPerHa.py +1088 -1268
  40. hestia_earth/models/ipcc2019/pastureGrass.py +4 -4
  41. hestia_earth/models/ipcc2019/utils.py +102 -1
  42. hestia_earth/models/koble2014/aboveGroundCropResidue.py +15 -17
  43. hestia_earth/models/koble2014/cropResidueManagement.py +2 -2
  44. hestia_earth/models/koble2014/utils.py +19 -3
  45. hestia_earth/models/linkedImpactAssessment/__init__.py +4 -2
  46. hestia_earth/models/log.py +15 -3
  47. hestia_earth/models/mocking/search-results.json +184 -118
  48. hestia_earth/models/pooreNemecek2018/excretaKgN.py +6 -7
  49. hestia_earth/models/pooreNemecek2018/excretaKgVs.py +7 -6
  50. hestia_earth/models/pooreNemecek2018/no3ToGroundwaterCropResidueDecomposition.py +3 -2
  51. hestia_earth/models/pooreNemecek2018/no3ToGroundwaterExcreta.py +3 -2
  52. hestia_earth/models/pooreNemecek2018/no3ToGroundwaterInorganicFertiliser.py +3 -2
  53. hestia_earth/models/pooreNemecek2018/saplings.py +0 -1
  54. hestia_earth/models/site/management.py +168 -0
  55. hestia_earth/models/site/organicCarbonPerHa.py +251 -89
  56. hestia_earth/models/stehfestBouwman2006/n2OToAirCropResidueDecompositionDirect.py +3 -2
  57. hestia_earth/models/stehfestBouwman2006/n2OToAirExcretaDirect.py +3 -2
  58. hestia_earth/models/stehfestBouwman2006/n2OToAirInorganicFertiliserDirect.py +3 -2
  59. hestia_earth/models/stehfestBouwman2006/n2OToAirOrganicFertiliserDirect.py +3 -2
  60. hestia_earth/models/stehfestBouwman2006/noxToAirCropResidueDecomposition.py +3 -2
  61. hestia_earth/models/stehfestBouwman2006/noxToAirExcreta.py +3 -2
  62. hestia_earth/models/stehfestBouwman2006/noxToAirInorganicFertiliser.py +3 -2
  63. hestia_earth/models/stehfestBouwman2006/noxToAirOrganicFertiliser.py +3 -2
  64. hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirCropResidueDecomposition.py +3 -2
  65. hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirExcreta.py +3 -2
  66. hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirInorganicFertiliser.py +3 -2
  67. hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirOrganicFertiliser.py +3 -2
  68. hestia_earth/models/utils/aggregated.py +1 -0
  69. hestia_earth/models/utils/blank_node.py +394 -72
  70. hestia_earth/models/utils/cropResidue.py +13 -0
  71. hestia_earth/models/utils/cycle.py +18 -9
  72. hestia_earth/models/utils/measurement.py +1 -1
  73. hestia_earth/models/utils/property.py +4 -4
  74. hestia_earth/models/utils/term.py +48 -3
  75. hestia_earth/models/version.py +1 -1
  76. {hestia_earth_models-0.57.2.dist-info → hestia_earth_models-0.59.0.dist-info}/METADATA +5 -9
  77. {hestia_earth_models-0.57.2.dist-info → hestia_earth_models-0.59.0.dist-info}/RECORD +109 -97
  78. {hestia_earth_models-0.57.2.dist-info → hestia_earth_models-0.59.0.dist-info}/WHEEL +1 -1
  79. tests/models/cycle/animal/input/test_hestiaAggregatedData.py +2 -14
  80. tests/models/cycle/input/test_hestiaAggregatedData.py +4 -16
  81. tests/models/cycle/test_coldCarcassWeightPerHead.py +1 -1
  82. tests/models/cycle/test_coldDressedCarcassWeightPerHead.py +1 -1
  83. tests/models/cycle/{test_irrigated.py → test_irrigatedTypeUnspecified.py} +1 -1
  84. tests/models/cycle/test_milkYield.py +58 -0
  85. tests/models/cycle/test_readyToCookWeightPerHead.py +1 -1
  86. tests/models/emepEea2019/test_nh3ToAirInorganicFertiliser.py +1 -1
  87. tests/models/geospatialDatabase/test_clayContent.py +9 -3
  88. tests/models/geospatialDatabase/test_sandContent.py +9 -3
  89. tests/models/ipcc2006/test_n2OToAirExcretaDirect.py +7 -2
  90. tests/models/ipcc2006/test_n2OToAirExcretaIndirect.py +1 -1
  91. tests/models/ipcc2006/test_n2OToAirInorganicFertiliserDirect.py +7 -2
  92. tests/models/ipcc2006/test_n2OToAirInorganicFertiliserIndirect.py +7 -2
  93. tests/models/ipcc2006/test_n2OToAirOrganicFertiliserDirect.py +7 -2
  94. tests/models/ipcc2006/test_n2OToAirOrganicFertiliserIndirect.py +7 -2
  95. tests/models/ipcc2019/test_ch4ToAirEntericFermentation.py +1 -1
  96. tests/models/ipcc2019/test_co2ToAirSoilCarbonStockChangeManagementChange.py +228 -0
  97. tests/models/ipcc2019/test_n2OToAirInorganicFertiliserDirect.py +74 -0
  98. tests/models/ipcc2019/test_n2OToAirOrganicFertiliserDirect.py +74 -0
  99. tests/models/ipcc2019/test_organicCarbonPerHa.py +303 -1044
  100. tests/models/koble2014/test_residueBurnt.py +1 -2
  101. tests/models/koble2014/test_residueLeftOnField.py +1 -2
  102. tests/models/koble2014/test_residueRemoved.py +1 -2
  103. tests/models/koble2014/test_utils.py +52 -0
  104. tests/models/site/test_management.py +117 -0
  105. tests/models/site/test_organicCarbonPerHa.py +51 -5
  106. tests/models/utils/test_blank_node.py +230 -34
  107. tests/models/utils/test_term.py +17 -3
  108. {hestia_earth_models-0.57.2.dist-info → hestia_earth_models-0.59.0.dist-info}/LICENSE +0 -0
  109. {hestia_earth_models-0.57.2.dist-info → hestia_earth_models-0.59.0.dist-info}/top_level.txt +0 -0
@@ -96,7 +96,6 @@ LOOKUPS = {
96
96
  "liveAquaticSpecies": ["excretaKgVsTermId", "allowedExcretaKgVsTermIds"]
97
97
  }
98
98
  MODEL_KEY = 'excretaKgVs'
99
- MODEL_LOG = '/'.join([MODEL, MODEL_KEY])
100
99
 
101
100
  Conv_AQ_CLW_CO2CR = 1
102
101
  Conv_AQ_CLW_CExcr = 0.5
@@ -121,7 +120,9 @@ def _run(excreta_product: dict, mass_balance_items: list, inputs_c: float, alter
121
120
 
122
121
  def _get_carbonContent(cycle: dict):
123
122
  primary_prod = find_primary_product(cycle) or {}
124
- return safe_parse_float(get_lookup_value(primary_prod.get('term', {}), 'carbonContent', model=MODEL)) / 100
123
+ return safe_parse_float(
124
+ get_lookup_value(primary_prod.get('term', {}), 'carbonContent', model=MODEL, model_key=MODEL_KEY)
125
+ ) / 100
125
126
 
126
127
 
127
128
  def _get_conv_aq_ocsed(siteType: str):
@@ -146,7 +147,7 @@ def _should_run(cycle: dict):
146
147
  carbonContent = _get_carbonContent(cycle)
147
148
 
148
149
  inputs_feed = get_feed_inputs(cycle)
149
- inputs_c = convert_to_carbon(cycle, MODEL_LOG, excreta_term_id, inputs_feed)
150
+ inputs_c = convert_to_carbon(cycle, MODEL, excreta_term_id, inputs_feed, model_key=MODEL_KEY)
150
151
 
151
152
  practices = cycle.get('practices', [])
152
153
  tsy = list_sum(find_term_match(practices, 'yieldOfPrimaryAquacultureProductLiveweightPerM2').get('value', []))
@@ -162,7 +163,7 @@ def _should_run(cycle: dict):
162
163
  excretaKgN = list_sum(excreta_n_product.get('value', [0]))
163
164
  vsc = get_node_property(excreta_n_product, 'volatileSolidsContent').get('value', 0)
164
165
 
165
- logRequirements(cycle, model=MODEL_LOG, term=excreta_term_id,
166
+ logRequirements(cycle, model=MODEL, term=excreta_term_id, model_key=MODEL_KEY,
166
167
  is_animalFeed_complete=is_animalFeed_complete,
167
168
  is_product_complete=is_product_complete,
168
169
  aqocsed=aqocsed,
@@ -187,8 +188,8 @@ def _should_run(cycle: dict):
187
188
  ])
188
189
  # only log if the excreta term does not exist to avoid showing failure when it already exists
189
190
  if should_add_product:
190
- logShouldRun(cycle, MODEL_LOG, excreta_term_id, should_run)
191
- logShouldRun(cycle, MODEL_LOG, None, should_run)
191
+ logShouldRun(cycle, MODEL, excreta_term_id, should_run, model_key=MODEL_KEY)
192
+ logShouldRun(cycle, MODEL, None, should_run)
192
193
  return should_run, excreta_product, mass_balance_items, inputs_c, alternate_items
193
194
 
194
195
 
@@ -49,9 +49,10 @@ def _emission(value: float):
49
49
  def _run(cycle: dict, N_total: float, content_list_of_items: list):
50
50
  no3ToGroundwaterSoilFlux = _get_value(cycle, N_total, content_list_of_items, TERM_ID)
51
51
  N_crop_residue = get_crop_residue_decomposition_N_total(cycle)
52
- return [_emission(N_crop_residue / N_total * no3ToGroundwaterSoilFlux if all([
52
+ value = N_crop_residue / N_total * no3ToGroundwaterSoilFlux if all([
53
53
  N_crop_residue, N_total
54
- ]) else 0)]
54
+ ]) else 0
55
+ return [_emission(value)]
55
56
 
56
57
 
57
58
  def run(cycle: dict):
@@ -54,9 +54,10 @@ def _emission(value: float):
54
54
  def _run(cycle: dict, N_total: float, content_list_of_items: list):
55
55
  no3ToGroundwaterSoilFlux = _get_value(cycle, N_total, content_list_of_items, TERM_ID)
56
56
  N_excreta = get_excreta_N_total(cycle)
57
- return [_emission(N_excreta / N_total * no3ToGroundwaterSoilFlux if all([
57
+ value = N_excreta / N_total * no3ToGroundwaterSoilFlux if all([
58
58
  N_excreta, N_total
59
- ]) else 0)]
59
+ ]) else 0
60
+ return [_emission(value)]
60
61
 
61
62
 
62
63
  def run(cycle: dict):
@@ -49,9 +49,10 @@ def _emission(value: float):
49
49
  def _run(cycle: dict, N_total: float, content_list_of_items: list):
50
50
  no3ToGroundwaterSoilFlux = _get_value(cycle, N_total, content_list_of_items, TERM_ID)
51
51
  N_inorganic_fertiliser = get_inorganic_fertiliser_N_total(cycle)
52
- return [_emission(N_inorganic_fertiliser / N_total * no3ToGroundwaterSoilFlux if all([
52
+ value = N_inorganic_fertiliser / N_total * no3ToGroundwaterSoilFlux if all([
53
53
  N_inorganic_fertiliser, N_total
54
- ]) else 0)]
54
+ ]) else 0
55
+ return [_emission(value)]
55
56
 
56
57
 
57
58
  def run(cycle: dict):
@@ -12,7 +12,6 @@ REQUIREMENTS = {
12
12
  "Cycle": {
13
13
  "completeness.other": "False",
14
14
  "products": [{"@type": "Product", "value": "", "term.termType": "crop"}],
15
- "site": {"@type": "Site", "siteType": ["cropland", "permanent pasture"]},
16
15
  "practices": [{"@type": "Practice", "value": "", "term.@id": "plantationLifespan"}]
17
16
  }
18
17
  }
@@ -0,0 +1,168 @@
1
+ """
2
+ Management node with data gap-filled data from cycles.
3
+ """
4
+ from typing import List
5
+ from functools import reduce
6
+ from hestia_earth.schema import SchemaType, TermTermType
7
+ from hestia_earth.utils.api import download_hestia
8
+ from hestia_earth.utils.model import filter_list_term_type, linked_node
9
+ from hestia_earth.utils.tools import flatten
10
+
11
+ from hestia_earth.models.log import logRequirements, logShouldRun, log_blank_nodes_id
12
+ from hestia_earth.models.utils.site import related_cycles
13
+ from hestia_earth.models.utils.term import get_lookup_value
14
+ from hestia_earth.models.utils.blank_node import get_node_value
15
+ from . import MODEL
16
+
17
+ REQUIREMENTS = {
18
+ "Site": {
19
+ "related": {
20
+ "Cycle": [{
21
+ "@type": "Cycle",
22
+ "startDate": "",
23
+ "endDate": "",
24
+ "products": [
25
+ {
26
+ "@type": "Product",
27
+ "term.termType": ["crop", "forage", "landCover"]
28
+ }
29
+ ],
30
+ "practices": [
31
+ {
32
+ "term.termType": [
33
+ "waterRegime",
34
+ "tillage",
35
+ "cropResidueManagement",
36
+ "landUseManagement"
37
+ ],
38
+ "value": ""
39
+ }
40
+ ]
41
+ }]
42
+ }
43
+ }
44
+ }
45
+ RETURNS = {
46
+ "Management": [{
47
+ "@type": "Management",
48
+ "term.termType": [
49
+ "landCover", "waterRegime", "tillage", "cropResidueManagement", "landUseManagement"
50
+ ],
51
+ "value": "",
52
+ "endDate": "",
53
+ "startDate": ""
54
+ }]
55
+ }
56
+
57
+ MODEL_KEY = 'management'
58
+ LAND_COVER_KEY = 'landCoverId'
59
+
60
+
61
+ def management(data: dict):
62
+ node = {'@type': SchemaType.MANAGEMENT.value}
63
+ return node | data
64
+
65
+
66
+ def _extract_node_value(node: dict) -> dict:
67
+ return node | {'value': get_node_value(node)}
68
+
69
+
70
+ def _include(value: dict, keys: list): return {k: v for k, v in value.items() if k in keys}
71
+
72
+
73
+ def _include_start_end(cycle: dict, values: list):
74
+ return [(_include(cycle, ['startDate', 'endDate']) | v) for v in values]
75
+
76
+
77
+ def _copy_item_if_exists(source: dict, keys: List[str] = [], dest: dict = {}) -> dict:
78
+ return reduce(lambda p, c: p | ({c: source[c]} if c in source else {}), keys, dest)
79
+
80
+
81
+ def _get_landCover_term_id(product: dict) -> str:
82
+ value = get_lookup_value(product.get('term', {}), LAND_COVER_KEY, model=MODEL, model_key=LAND_COVER_KEY)
83
+ # TODO: what should happen when there are multiple values?
84
+ return value.split(';')[0] if value else None
85
+
86
+
87
+ def _get_items_with_relevant_term_type(cycles: List[dict], item_name: str, relevant_values: list):
88
+ """Get items from the list of cycles with any of the relevant values. Also adds dates if missing."""
89
+ return flatten(
90
+ [
91
+ _include_start_end(
92
+ cycle=cycle,
93
+ values=filter_list_term_type(cycle.get(item_name, []), relevant_values)
94
+ ) for cycle in cycles
95
+ ]
96
+ )
97
+
98
+
99
+ def should_run(site: dict):
100
+ # Only get related cycles once.
101
+ cycles = related_cycles(site.get("@id"))
102
+
103
+ products_land_cover = [
104
+ _extract_node_value(
105
+ _include(
106
+ value=product,
107
+ keys=["term", "value", "startDate", "endDate", "properties"]
108
+ )
109
+ ) for product in _get_items_with_relevant_term_type(
110
+ cycles=cycles,
111
+ item_name="products",
112
+ relevant_values=[TermTermType.LANDCOVER]
113
+ )
114
+ ]
115
+
116
+ products_crop_forage = _get_items_with_relevant_term_type(
117
+ cycles=cycles,
118
+ item_name="products",
119
+ relevant_values=[TermTermType.CROP, TermTermType.FORAGE]
120
+ )
121
+ products_crop_forage = [
122
+ _copy_item_if_exists(
123
+ source=product,
124
+ keys=["startDate", "endDate", "properties"],
125
+ dest={
126
+ "term": linked_node(download_hestia(_get_landCover_term_id(product))),
127
+ "value": 100
128
+ }
129
+ )
130
+ for product in list(filter(_get_landCover_term_id, products_crop_forage))
131
+ ]
132
+
133
+ practices = [
134
+ _extract_node_value(
135
+ _include(
136
+ value=practice,
137
+ keys=["term", "value", "startDate", "endDate"]
138
+ )
139
+ ) for practice in _get_items_with_relevant_term_type(
140
+ cycles=cycles,
141
+ item_name="practices",
142
+ relevant_values=[
143
+ TermTermType.WATERREGIME,
144
+ TermTermType.TILLAGE,
145
+ TermTermType.CROPRESIDUEMANAGEMENT,
146
+ TermTermType.LANDUSEMANAGEMENT
147
+ ]
148
+ )
149
+ ]
150
+
151
+ logRequirements(
152
+ site,
153
+ model=MODEL,
154
+ term=None,
155
+ model_key=MODEL_KEY,
156
+ products_crop_forage_ids=log_blank_nodes_id(products_crop_forage),
157
+ products_land_cover_ids=log_blank_nodes_id(products_land_cover),
158
+ practice_ids=log_blank_nodes_id(practices)
159
+ )
160
+
161
+ _should_run = any(products_crop_forage + products_land_cover + practices)
162
+ logShouldRun(site, MODEL, None, should_run=_should_run, model_key=MODEL_KEY)
163
+ return _should_run, products_crop_forage + products_land_cover, practices
164
+
165
+
166
+ def run(site: dict):
167
+ _should_run, products, practices = should_run(site)
168
+ return list(map(management, products + practices)) if _should_run else []