hestia-earth-models 0.72.2__py3-none-any.whl → 0.73.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.
Files changed (130) hide show
  1. hestia_earth/models/{akagiEtAl2011AndIpcc2006 → akagiEtAl2011}/__init__.py +1 -1
  2. hestia_earth/models/akagiEtAl2011/ch4ToAirCropResidueBurning.py +32 -0
  3. hestia_earth/models/akagiEtAl2011/nh3ToAirCropResidueBurning.py +32 -0
  4. hestia_earth/models/akagiEtAl2011/noxToAirCropResidueBurning.py +32 -0
  5. hestia_earth/models/akagiEtAl2011/pm25ToAirCropResidueBurning.py +32 -0
  6. hestia_earth/models/akagiEtAl2011/so2ToAirCropResidueBurning.py +32 -0
  7. hestia_earth/models/akagiEtAl2011/utils.py +45 -0
  8. hestia_earth/models/aware/scarcityWeightedWaterUse.py +2 -2
  9. hestia_earth/models/chaudharyBrooks2018/damageToTerrestrialEcosystemsTotalLandUseEffects.py +1 -1
  10. hestia_earth/models/chaudharyBrooks2018/utils.py +1 -1
  11. hestia_earth/models/config/Cycle.json +48 -7
  12. hestia_earth/models/config/ImpactAssessment.json +22 -0
  13. hestia_earth/models/cycle/completeness/soilAmendment.py +1 -1
  14. hestia_earth/models/cycle/product/economicValueShare.py +3 -1
  15. hestia_earth/models/cycle/product/price.py +35 -10
  16. hestia_earth/models/cycle/product/revenue.py +5 -2
  17. hestia_earth/models/dammgen2009/noxToAirExcreta.py +14 -18
  18. hestia_earth/models/ecoinventV3/__init__.py +11 -6
  19. hestia_earth/models/ecoinventV3AndEmberClimate/utils.py +1 -1
  20. hestia_earth/models/emepEea2019/utils.py +2 -1
  21. hestia_earth/models/faostat2018/liveweightPerHead.py +1 -1
  22. hestia_earth/models/faostat2018/product/price.py +2 -2
  23. hestia_earth/models/faostat2018/seed.py +3 -2
  24. hestia_earth/models/faostat2018/utils.py +6 -5
  25. hestia_earth/models/geospatialDatabase/altitude.py +2 -1
  26. hestia_earth/models/geospatialDatabase/drainageClass.py +2 -1
  27. hestia_earth/models/geospatialDatabase/organicCarbonPerKgSoil.py +2 -1
  28. hestia_earth/models/geospatialDatabase/totalNitrogenPerKgSoil.py +2 -1
  29. hestia_earth/models/geospatialDatabase/totalPhosphorusPerKgSoil.py +2 -1
  30. hestia_earth/models/geospatialDatabase/utils.py +1 -1
  31. hestia_earth/models/globalCropWaterModel2008/rootingDepth.py +1 -1
  32. hestia_earth/models/hestia/brackishWater.py +1 -1
  33. hestia_earth/models/hestia/default_emissions.py +105 -0
  34. hestia_earth/models/hestia/default_resourceUse.py +110 -0
  35. hestia_earth/models/hestia/freshWater.py +1 -1
  36. hestia_earth/models/hestia/inorganicFertiliser.py +12 -12
  37. hestia_earth/models/hestia/landCover.py +7 -5
  38. hestia_earth/models/hestia/landTransformation100YearAverageDuringCycle.py +3 -0
  39. hestia_earth/models/hestia/landTransformation20YearAverageDuringCycle.py +3 -0
  40. hestia_earth/models/hestia/liveAnimal.py +1 -1
  41. hestia_earth/models/hestia/management.py +1 -1
  42. hestia_earth/models/hestia/netPrimaryProduction.py +1 -1
  43. hestia_earth/models/hestia/organicCarbonPerHa.py +2 -2
  44. hestia_earth/models/hestia/salineWater.py +1 -1
  45. hestia_earth/models/hestia/seed_emissions.py +34 -20
  46. hestia_earth/models/hestia/totalNitrogenPerKgSoil.py +1 -1
  47. hestia_earth/models/hestia/waterSalinity.py +2 -1
  48. hestia_earth/models/ipcc2006/aboveGroundCropResidueRemoved.py +2 -2
  49. hestia_earth/models/ipcc2006/aboveGroundCropResidueTotal.py +10 -6
  50. hestia_earth/models/ipcc2006/belowGroundCropResidue.py +12 -8
  51. hestia_earth/models/ipcc2019/animal/utils.py +1 -1
  52. hestia_earth/models/ipcc2019/belowGroundCropResidue.py +1 -1
  53. hestia_earth/models/ipcc2019/carbonContent.py +1 -1
  54. hestia_earth/models/ipcc2019/ch4ToAirAquacultureSystems.py +17 -9
  55. hestia_earth/models/ipcc2019/ch4ToAirEntericFermentation.py +6 -6
  56. hestia_earth/models/ipcc2019/ch4ToAirExcreta.py +4 -2
  57. hestia_earth/models/ipcc2019/co2ToAirUreaHydrolysis.py +1 -1
  58. hestia_earth/models/ipcc2019/croppingDuration.py +4 -2
  59. hestia_earth/models/ipcc2019/ligninContent.py +1 -1
  60. hestia_earth/models/{akagiEtAl2011AndIpcc2006 → ipcc2019}/n2OToAirCropResidueBurningDirect.py +8 -4
  61. hestia_earth/models/ipcc2019/nitrogenContent.py +1 -1
  62. hestia_earth/models/ipcc2019/nonCo2EmissionsToAirNaturalVegetationBurning.py +6 -2
  63. hestia_earth/models/ipcc2019/pastureGrass_utils.py +13 -12
  64. hestia_earth/models/ipcc2019/utils.py +6 -2
  65. hestia_earth/models/koble2014/residueBurnt.py +6 -3
  66. hestia_earth/models/koble2014/residueRemoved.py +1 -1
  67. hestia_earth/models/mocking/search-results.json +1577 -1573
  68. hestia_earth/models/pooreNemecek2018/aboveGroundCropResidueTotal.py +1 -1
  69. hestia_earth/models/pooreNemecek2018/belowGroundCropResidue.py +1 -1
  70. hestia_earth/models/pooreNemecek2018/excretaKgVs.py +1 -1
  71. hestia_earth/models/pooreNemecek2018/freshwaterWithdrawalsDuringCycle.py +1 -1
  72. hestia_earth/models/pooreNemecek2018/longFallowDuration.py +1 -1
  73. hestia_earth/models/pooreNemecek2018/nurseryDensity.py +1 -1
  74. hestia_earth/models/pooreNemecek2018/nurseryDuration.py +1 -1
  75. hestia_earth/models/pooreNemecek2018/plantationDensity.py +1 -1
  76. hestia_earth/models/pooreNemecek2018/plantationLifespan.py +1 -1
  77. hestia_earth/models/pooreNemecek2018/plantationProductiveLifespan.py +3 -1
  78. hestia_earth/models/pooreNemecek2018/saplingsDepreciatedAmountPerCycle.py +1 -1
  79. hestia_earth/models/resourceUseNotRelevant/__init__.py +65 -0
  80. hestia_earth/models/schererPfister2015/nErosionSoilFlux.py +5 -3
  81. hestia_earth/models/schererPfister2015/pErosionSoilFlux.py +5 -3
  82. hestia_earth/models/schererPfister2015/utils.py +5 -4
  83. hestia_earth/models/stehfestBouwman2006/n2OToAirSoilFlux_utils.py +1 -1
  84. hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirSoilFlux_utils.py +3 -3
  85. hestia_earth/models/utils/background_emissions.py +14 -10
  86. hestia_earth/models/utils/blank_node.py +6 -4
  87. hestia_earth/models/utils/crop.py +1 -1
  88. hestia_earth/models/utils/cropResidue.py +16 -0
  89. hestia_earth/models/utils/cycle.py +1 -1
  90. hestia_earth/models/utils/ecoClimateZone.py +2 -2
  91. hestia_earth/models/utils/excretaManagement.py +1 -1
  92. hestia_earth/models/utils/feedipedia.py +3 -3
  93. hestia_earth/models/utils/fertiliser.py +7 -1
  94. hestia_earth/models/utils/inorganicFertiliser.py +2 -2
  95. hestia_earth/models/utils/input.py +34 -1
  96. hestia_earth/models/utils/liveAnimal.py +2 -2
  97. hestia_earth/models/utils/lookup.py +1 -1
  98. hestia_earth/models/utils/measurement.py +5 -4
  99. hestia_earth/models/utils/productivity.py +1 -1
  100. hestia_earth/models/utils/property.py +4 -2
  101. hestia_earth/models/utils/site.py +2 -1
  102. hestia_earth/models/version.py +1 -1
  103. {hestia_earth_models-0.72.2.dist-info → hestia_earth_models-0.73.0.dist-info}/METADATA +1 -1
  104. {hestia_earth_models-0.72.2.dist-info → hestia_earth_models-0.73.0.dist-info}/RECORD +124 -113
  105. tests/models/akagiEtAl2011/test_ch4ToAirCropResidueBurning.py +33 -0
  106. tests/models/akagiEtAl2011/test_nh3ToAirCropResidueBurning.py +33 -0
  107. tests/models/{akagiEtAl2011AndIpcc2006 → akagiEtAl2011}/test_noxToAirCropResidueBurning.py +5 -17
  108. tests/models/akagiEtAl2011/test_pm25ToAirCropResidueBurning.py +33 -0
  109. tests/models/akagiEtAl2011/test_so2ToAirCropResidueBurning.py +33 -0
  110. tests/models/akagiEtAl2011/test_utils.py +18 -0
  111. tests/models/cycle/product/test_price.py +1 -11
  112. tests/models/dammgen2009/test_noxToAirExcreta.py +30 -10
  113. tests/models/geospatialDatabase/test_utils.py +2 -1
  114. tests/models/hestia/test_default_emissions.py +25 -0
  115. tests/models/hestia/test_default_resourceUse.py +26 -0
  116. tests/models/hestia/test_landCover.py +2 -2
  117. tests/models/ipcc2019/test_ch4ToAirAquacultureSystems.py +2 -2
  118. tests/models/{akagiEtAl2011AndIpcc2006/test_nh3ToAirCropResidueBurning.py → ipcc2019/test_n2OToAirCropResidueBurningDirect.py} +2 -2
  119. tests/models/test_resourceUseNotRelevant.py +27 -0
  120. tests/models/{akagiEtAl2011AndIpcc2006/test_utils.py → utils/test_cropResidue.py} +6 -6
  121. hestia_earth/models/akagiEtAl2011AndIpcc2006/ch4ToAirCropResidueBurning.py +0 -57
  122. hestia_earth/models/akagiEtAl2011AndIpcc2006/nh3ToAirCropResidueBurning.py +0 -57
  123. hestia_earth/models/akagiEtAl2011AndIpcc2006/noxToAirCropResidueBurning.py +0 -57
  124. hestia_earth/models/akagiEtAl2011AndIpcc2006/utils.py +0 -15
  125. tests/models/akagiEtAl2011AndIpcc2006/test_ch4ToAirCropResidueBurning.py +0 -45
  126. tests/models/akagiEtAl2011AndIpcc2006/test_n2OToAirCropResidueBurningDirect.py +0 -46
  127. {hestia_earth_models-0.72.2.dist-info → hestia_earth_models-0.73.0.dist-info}/LICENSE +0 -0
  128. {hestia_earth_models-0.72.2.dist-info → hestia_earth_models-0.73.0.dist-info}/WHEEL +0 -0
  129. {hestia_earth_models-0.72.2.dist-info → hestia_earth_models-0.73.0.dist-info}/top_level.txt +0 -0
  130. /tests/models/{akagiEtAl2011AndIpcc2006 → akagiEtAl2011}/__init__.py +0 -0
@@ -83,6 +83,7 @@ def _run_emission(
83
83
  input_term_id = input_term.get('@id')
84
84
  seed_value = list_sum(seed_input.get('value'))
85
85
  value = emission_value * economicValueShare / 100 / total_yield * seed_value
86
+ logShouldRun(cycle, MODEL, input_term_id, True, methodTier=TIER, model_key=MODEL_KEY, emission_id=term_id)
86
87
  debugValues(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
87
88
  value=value,
88
89
  coefficient=1,
@@ -107,7 +108,7 @@ def _map_group_emissions(group_id: str, required_emission_term_ids: list, emissi
107
108
  included_emissions = list(filter(lambda v: v in emission_ids, emissions))
108
109
  missing_emissions = list(filter(lambda v: v not in emission_ids, emissions))
109
110
  return {
110
- 'id': group_id,
111
+ 'group-id': group_id,
111
112
  'total-emissions': len(emissions),
112
113
  'included-emissions': len(included_emissions),
113
114
  'missing-emissions': '-'.join(missing_emissions),
@@ -120,7 +121,7 @@ def _filter_emissions(cycle: dict):
120
121
 
121
122
  emissions = [
122
123
  {
123
- 'id': i.get('term', {}).get('@id'),
124
+ 'emission-id': i.get('term', {}).get('@id'),
124
125
  'group-id': get_lookup_value(i.get('term', {}), LOOKUPS['emission'], model=MODEL, model_key=MODEL_KEY),
125
126
  'value': list_sum(i.get('value'))
126
127
  }
@@ -130,7 +131,7 @@ def _filter_emissions(cycle: dict):
130
131
  len(i.get('value', [])) > 0
131
132
  ])
132
133
  ]
133
- emission_ids = set([v.get('id') for v in emissions])
134
+ emission_ids = set([v.get('emission-id') for v in emissions])
134
135
  group_ids = set([v.get('group-id') for v in emissions if v.get('group-id')])
135
136
 
136
137
  # for each group, get the list of all required emissions
@@ -140,7 +141,7 @@ def _filter_emissions(cycle: dict):
140
141
  ]
141
142
  # only keep groups that have all emissions present in the Cycle
142
143
  valid_groups = list(filter(lambda group: group.get('is-valid'), emissions_per_group))
143
- valid_group_ids = set([v.get('id') for v in valid_groups])
144
+ valid_group_ids = set([v.get('group-id') for v in valid_groups])
144
145
 
145
146
  # finally, only return emissions which groups are valid
146
147
  return list(filter(
@@ -151,19 +152,21 @@ def _filter_emissions(cycle: dict):
151
152
 
152
153
  def _evs(product: dict):
153
154
  return safe_parse_float(
154
- get_lookup_value(product.get('term', {}), 'global_economic_value_share', model=MODEL, model_key=MODEL_KEY)
155
+ get_lookup_value(product.get('term', {}), 'global_economic_value_share', model=MODEL, model_key=MODEL_KEY),
156
+ default=None
155
157
  ) or product.get('economicValueShare')
156
158
 
157
159
 
158
160
  def _faostat_yield(country_id: str, end_year: int, product: dict):
159
161
  grouping = get_crop_grouping_faostat_production(MODEL, product.get('term', {}))
160
- return safe_parse_float(extract_grouped_data_closest_date(get_region_lookup_value(
162
+ value = extract_grouped_data_closest_date(get_region_lookup_value(
161
163
  'region-crop-cropGroupingFaostatProduction-yield.csv',
162
164
  country_id,
163
165
  grouping,
164
166
  model=MODEL,
165
167
  model_key=MODEL_KEY
166
- ), end_year))
168
+ ), end_year)
169
+ return safe_parse_float(value, default=None)
167
170
 
168
171
 
169
172
  def _group_seed_inputs(inputs: list):
@@ -242,10 +245,11 @@ def _should_run(cycle: dict):
242
245
  emissions,
243
246
  {}
244
247
  )
248
+ has_single_land_cover = len(crop_land_cover_ids) <= 1
245
249
 
246
250
  should_run = all([
247
251
  site_type_valid,
248
- len(crop_land_cover_ids) <= 1,
252
+ has_single_land_cover,
249
253
  is_product_complete,
250
254
  total_economicValueShare,
251
255
  total_yield,
@@ -253,29 +257,39 @@ def _should_run(cycle: dict):
253
257
  bool(emissions)
254
258
  ])
255
259
 
260
+ logs = {
261
+ 'site_type_valid': site_type_valid,
262
+ 'crop_products': log_as_table(crop_products),
263
+ 'crop_land_cover_ids': ';'.join(crop_land_cover_ids),
264
+ 'has_single_land_cover': has_single_land_cover,
265
+ 'is_term_type_product_complete': is_product_complete,
266
+ 'total_economicValueShare': total_economicValueShare,
267
+ 'total_yield': total_yield,
268
+ 'end_year': end_year,
269
+ 'country_id': country_id
270
+ }
271
+
256
272
  for seed_input in seed_inputs:
257
273
  term_id = seed_input.get('input').get('term', {}).get('@id')
258
274
 
259
275
  logRequirements(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
260
- site_type_valid=site_type_valid,
261
- crop_products=log_as_table(crop_products),
262
- crop_land_cover_ids=';'.join(crop_land_cover_ids),
263
- is_term_type_product_complete=is_product_complete,
264
- total_economicValueShare=total_economicValueShare,
265
- total_yield=total_yield,
266
- end_year=end_year,
267
- country_id=country_id,
268
276
  emissions=log_as_table(emissions),
269
277
  emissions_per_group=log_as_table(emissions_per_group),
270
- **_omit(seed_input, 'input'))
278
+ **_omit(seed_input, 'input'),
279
+ **logs)
271
280
 
272
281
  logShouldRun(cycle, MODEL, term_id, should_run, methodTier=TIER, model_key=MODEL_KEY)
273
282
 
274
- # log missing emissions to show in the logs
283
+ # log failed emissions to show in the logs
275
284
  for group in emissions_per_group:
276
- if not group.get('is-valid'):
285
+ emission_id = group.get('group-id')
286
+ if not group.get('is-valid') or not should_run:
287
+ logRequirements(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY, emission_id=emission_id,
288
+ **group,
289
+ **_omit(seed_input, 'input'),
290
+ **logs)
277
291
  logShouldRun(cycle, MODEL, term_id, False,
278
- methodTier=TIER, model_key=MODEL_KEY, emission_id=group.get('id'))
292
+ methodTier=TIER, model_key=MODEL_KEY, emission_id=emission_id)
279
293
 
280
294
  return should_run, total_economicValueShare, total_yield, grouped_seed_inputs, grouped_emissions
281
295
 
@@ -45,7 +45,7 @@ def _should_run(site: dict):
45
45
  logRequirements(site, model=MODEL, term=TERM_ID,
46
46
  carbon_content_value=carbon_content_value)
47
47
 
48
- should_run = not is_from_model(carbon_content) and carbon_content_value > 0
48
+ should_run = all([not is_from_model(carbon_content), (carbon_content_value or 0) > 0])
49
49
  logShouldRun(site, MODEL, TERM_ID, should_run)
50
50
  return should_run, carbon_content_value
51
51
 
@@ -52,7 +52,8 @@ def _should_run(site: dict):
52
52
  {
53
53
  'product-id': product.get('term', {}).get('@id'),
54
54
  'lookup-value': safe_parse_float(
55
- get_lookup_value(product.get('term', {}), LOOKUPS['liveAquaticSpecies']), default=None
55
+ get_lookup_value(product.get('term', {}), LOOKUPS['liveAquaticSpecies']),
56
+ default=None
56
57
  ),
57
58
  'start-date': product.get('startDate') or cycle.get('startDate'),
58
59
  'end-date': product.get('endDate') or cycle.get('endDate')
@@ -38,11 +38,11 @@ def _product(value: float):
38
38
 
39
39
  def _get_value(product: dict, product_dm_property: dict):
40
40
  value = product.get('value', [0])[0]
41
- dm_percent = safe_parse_float(product_dm_property.get('value'))
41
+ dm_percent = safe_parse_float(product_dm_property.get('value'), default=None)
42
42
  debugValues(product, model=MODEL, term=product.get('term', {}).get('@id'),
43
43
  value=value,
44
44
  dm_percent=dm_percent)
45
- return value * dm_percent / 100
45
+ return value * dm_percent / 100 if dm_percent is not None else 0
46
46
 
47
47
 
48
48
  def _run(products: list):
@@ -41,21 +41,25 @@ def _product(value: float):
41
41
  def _get_value_dm(product: dict, dm_percent: float):
42
42
  term_id = product.get('term', {}).get('@id', '')
43
43
  product_yield = list_sum(product.get('value', [0]))
44
- yield_dm = product_yield * (dm_percent / 100)
44
+ yield_dm = product_yield * (dm_percent / 100) if dm_percent is not None else None
45
45
 
46
46
  # estimate the AG DM calculation
47
- slope = safe_parse_float(get_crop_lookup_value(MODEL, TERM_ID, term_id, LOOKUPS['crop'][1]), None)
48
- intercept = safe_parse_float(get_crop_lookup_value(MODEL, TERM_ID, term_id, LOOKUPS['crop'][0]), None)
47
+ slope = safe_parse_float(get_crop_lookup_value(MODEL, TERM_ID, term_id, LOOKUPS['crop'][1]), default=None)
48
+ intercept = safe_parse_float(get_crop_lookup_value(MODEL, TERM_ID, term_id, LOOKUPS['crop'][0]), default=None)
49
49
  debugValues(product, model=MODEL, term=TERM_ID,
50
50
  yield_dm=yield_dm,
51
51
  dryMatter_percent=dm_percent,
52
52
  slope=slope,
53
53
  intercept=intercept)
54
- return None if slope is None or intercept is None else (yield_dm * slope + intercept * 1000)
54
+ return None if any([
55
+ slope is None,
56
+ intercept is None,
57
+ yield_dm is None
58
+ ]) else (yield_dm * slope + intercept * 1000)
55
59
 
56
60
 
57
61
  def _run(product: dict, dm_property: dict):
58
- value = _get_value_dm(product, safe_parse_float(dm_property.get('value')))
62
+ value = _get_value_dm(product, safe_parse_float(dm_property.get('value'), default=None))
59
63
  return [_product(value)] if value is not None else []
60
64
 
61
65
 
@@ -63,7 +67,7 @@ def _should_run_product(product: dict):
63
67
  term_id = product.get('term', {}).get('@id')
64
68
  value = list_sum(product.get('value', [0]))
65
69
  return value > 0 and (
66
- safe_parse_float(get_crop_lookup_value(MODEL, TERM_ID, term_id, LOOKUPS['crop'][0]), None) is not None
70
+ safe_parse_float(get_crop_lookup_value(MODEL, TERM_ID, term_id, LOOKUPS['crop'][0]), default=None) is not None
67
71
  )
68
72
 
69
73
 
@@ -41,17 +41,17 @@ def _product(value: float):
41
41
  def _get_value_dm(product: dict, dm_percent: float):
42
42
  term_id = product.get('term', {}).get('@id', '')
43
43
  product_yield = list_sum(product.get('value', [0]))
44
- yield_dm = product_yield * (dm_percent / 100)
44
+ yield_dm = product_yield * (dm_percent / 100) if dm_percent is not None else None
45
45
 
46
46
  # TODO with the spreadsheet there are a number of ways this value is calculated.
47
47
  # Currently, the result of this model when applied to Sah et al does not match
48
48
  # the example due to hardcoded calc in the spreadsheet
49
49
 
50
50
  # estimate the BG DM calculation
51
- intercept = safe_parse_float(get_crop_lookup_value(MODEL, TERM_ID, term_id, LOOKUPS['crop'][0]))
52
- slope = safe_parse_float(get_crop_lookup_value(MODEL, TERM_ID, term_id, LOOKUPS['crop'][1]))
51
+ intercept = safe_parse_float(get_crop_lookup_value(MODEL, TERM_ID, term_id, LOOKUPS['crop'][0]), default=None)
52
+ slope = safe_parse_float(get_crop_lookup_value(MODEL, TERM_ID, term_id, LOOKUPS['crop'][1]), default=None)
53
53
  ab_bg_ratio = safe_parse_float(
54
- get_crop_lookup_value(MODEL, TERM_ID, term_id, LOOKUPS['crop'][2])
54
+ get_crop_lookup_value(MODEL, TERM_ID, term_id, LOOKUPS['crop'][2]), default=None
55
55
  )
56
56
  debugValues(product, model=MODEL, term=TERM_ID,
57
57
  yield_dm=yield_dm,
@@ -64,12 +64,16 @@ def _get_value_dm(product: dict, dm_percent: float):
64
64
  # https://www.ipcc-nggip.iges.or.jp/public/2019rf/pdf/4_Volume4/19R_V4_Ch11_Soils_N2O_CO2.pdf
65
65
  # only if site.type = pasture
66
66
  # multiply by the ratio of above to below matter
67
- return None if slope is None or intercept is None or ab_bg_ratio is None \
68
- else ((yield_dm * slope + intercept * 1000) + yield_dm) * ab_bg_ratio
67
+ return None if any([
68
+ yield_dm is None,
69
+ slope is None,
70
+ intercept is None,
71
+ ab_bg_ratio is None
72
+ ]) else ((yield_dm * slope + intercept * 1000) + yield_dm) * ab_bg_ratio
69
73
 
70
74
 
71
75
  def _run(product: dict, dm_property: dict):
72
- value = _get_value_dm(product, safe_parse_float(dm_property.get('value')))
76
+ value = _get_value_dm(product, safe_parse_float(dm_property.get('value'), default=None))
73
77
  return [_product(value)] if value is not None else []
74
78
 
75
79
 
@@ -77,7 +81,7 @@ def _should_run_product(product: dict):
77
81
  term_id = product.get('term', {}).get('@id')
78
82
  value = list_sum(product.get('value', [0]))
79
83
  return value > 0 and (
80
- safe_parse_float(get_crop_lookup_value(MODEL, TERM_ID, term_id, LOOKUPS['crop'][0]), None) is not None
84
+ safe_parse_float(get_crop_lookup_value(MODEL, TERM_ID, term_id, LOOKUPS['crop'][0]), default=None) is not None
81
85
  )
82
86
 
83
87
 
@@ -30,7 +30,7 @@ def productivity_lookup_value(term_id: str, lookup: str, country: dict, animal:
30
30
  return safe_parse_float(
31
31
  extract_grouped_data(value, productivity_key.value) or
32
32
  extract_grouped_data(value, PRODUCTIVITY.HIGH.value), # defaults to high if low is not found
33
- None
33
+ default=None
34
34
  )
35
35
 
36
36
 
@@ -42,7 +42,7 @@ def _product(value: float):
42
42
 
43
43
 
44
44
  def _get_lookup_value(term: dict, column: str):
45
- return safe_parse_float(get_lookup_value(term, column, model=MODEL, term=TERM_ID), None)
45
+ return safe_parse_float(get_lookup_value(term, column, model=MODEL, term=TERM_ID), default=None)
46
46
 
47
47
 
48
48
  def _product_value(product: dict):
@@ -67,7 +67,7 @@ def _crop_residue_lookup_col(term):
67
67
 
68
68
 
69
69
  def _get_lookup_value(term: dict, column: str):
70
- return safe_parse_float(get_lookup_value(term, column, model=MODEL, term=TERM_ID), None)
70
+ return safe_parse_float(get_lookup_value(term, column, model=MODEL, term=TERM_ID), default=None)
71
71
 
72
72
 
73
73
  # Single crop
@@ -63,15 +63,12 @@ def _find_measurement(site: dict):
63
63
  return measurements[0] if measurements else None
64
64
 
65
65
 
66
- def _run(cycle: dict):
66
+ def _run(cycle: dict, factors: list):
67
67
  cycle_duration = cycle.get('cycleDuration')
68
68
  site = cycle.get('site', {})
69
69
  site_area = site.get('area')
70
- water_term = _find_measurement(site).get('term', {})
71
- factor_value = safe_parse_float(get_lookup_value(water_term, LOOKUPS.get('measurement')))
72
- factor_min = safe_parse_float(get_lookup_value(water_term, f"{LOOKUPS.get('measurement')}-min"))
73
- factor_max = safe_parse_float(get_lookup_value(water_term, f"{LOOKUPS.get('measurement')}-max"))
74
70
  ratio = site_area * cycle_duration / 365
71
+ factor_value, factor_min, factor_max = factors
75
72
  return [_emission(ratio * factor_value, ratio * factor_min, ratio * factor_max)]
76
73
 
77
74
 
@@ -80,7 +77,13 @@ def _should_run(cycle: dict):
80
77
  is_relative = cycle.get('functionalUnit') == CycleFunctionalUnit.RELATIVE.value
81
78
  site = cycle.get('site', {})
82
79
  site_area = site.get('area')
83
- has_water_type = _find_measurement(site) is not None
80
+
81
+ water_measurement = _find_measurement(site)
82
+ has_water_type = water_measurement is not None
83
+ water_term = (water_measurement or {}).get('term', {})
84
+ factor_value = safe_parse_float(get_lookup_value(water_term, LOOKUPS.get('measurement')), default=None)
85
+ factor_min = safe_parse_float(get_lookup_value(water_term, f"{LOOKUPS.get('measurement')}-min"), default=None)
86
+ factor_max = safe_parse_float(get_lookup_value(water_term, f"{LOOKUPS.get('measurement')}-max"), default=None)
84
87
 
85
88
  logRequirements(cycle, model=MODEL, term=TERM_ID,
86
89
  cycle_duration=cycle_duration,
@@ -88,9 +91,14 @@ def _should_run(cycle: dict):
88
91
  site_area=site_area,
89
92
  has_water_type=has_water_type)
90
93
 
91
- should_run = all([cycle_duration, is_relative, site_area, has_water_type])
94
+ should_run = all([
95
+ cycle_duration, is_relative, site_area, has_water_type,
96
+ factor_value is not None, factor_min is not None, factor_max is not None
97
+ ])
92
98
  logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
93
- return should_run
99
+ return should_run, [factor_value, factor_min, factor_max]
94
100
 
95
101
 
96
- def run(cycle: dict): return _run(cycle) if _should_run(cycle) else []
102
+ def run(cycle: dict):
103
+ should_run, factors = _should_run(cycle)
104
+ return _run(cycle, factors) if should_run else []
@@ -172,7 +172,7 @@ def _extract_groupped_data(value: str, DE: float, NDF: float, ionophore: bool, m
172
172
  debugValues({}, model=MODEL, term=TERM_ID,
173
173
  value_key=value_key)
174
174
 
175
- return safe_parse_float(extract_grouped_data(value, value_key), None)
175
+ return safe_parse_float(extract_grouped_data(value, value_key), default=None)
176
176
 
177
177
 
178
178
  def _get_lookup_value(lookup, term: dict, lookup_col: str, DE: float, NDF: float, ionophore: bool, milk_yield: float):
@@ -215,9 +215,9 @@ def _get_default_values(lookup, term: dict):
215
215
  min = get_table_value(lookup, 'termid', term_id, column_name(LOOKUPS['liveAnimal'][4])) if term_id else None
216
216
  max = get_table_value(lookup, 'termid', term_id, column_name(LOOKUPS['liveAnimal'][5])) if term_id else None
217
217
  return {
218
- 'value': safe_parse_float(value, None),
219
- 'min': safe_parse_float(min, None),
220
- 'max': safe_parse_float(max, None)
218
+ 'value': safe_parse_float(value, default=None),
219
+ 'min': safe_parse_float(min, default=None),
220
+ 'max': safe_parse_float(max, default=None)
221
221
  }
222
222
 
223
223
 
@@ -257,10 +257,10 @@ def _should_run(cycle: dict):
257
257
 
258
258
  enteric_factor = safe_parse_float(_get_lookup_value(
259
259
  lookup, term, LOOKUPS['liveAnimal'][1], DE or DE_default, NDF, ionophore, milk_yield
260
- ), None)
260
+ ), default=None)
261
261
  enteric_sd = safe_parse_float(_get_lookup_value(
262
262
  lookup, term, LOOKUPS['liveAnimal'][2], DE or DE_default, NDF, ionophore, milk_yield
263
- ), None)
263
+ ), default=None)
264
264
 
265
265
  default_values = _get_default_values(lookup, term)
266
266
 
@@ -89,7 +89,8 @@ def _get_excreta_b0(country: dict, input: dict):
89
89
  data_values = get_region_lookup_value(lookup_name, country.get('@id'), term_id, model=MODEL, term=TERM_ID)
90
90
  return safe_parse_float(
91
91
  extract_grouped_data(data_values, productivity_key.value) or
92
- extract_grouped_data(data_values, PRODUCTIVITY.HIGH.value) # defaults to high if low is not found
92
+ extract_grouped_data(data_values, PRODUCTIVITY.HIGH.value), # defaults to high if low is not found
93
+ default=None
93
94
  )
94
95
 
95
96
 
@@ -100,7 +101,8 @@ def _get_excretaManagement_MCF_from_lookup(term_id: str, ecoClimateZone: int, du
100
101
  debugMissingLookup(lookup_name, 'termid', term_id, ecoClimateZone, data_values, model=MODEL, term=TERM_ID)
101
102
  return safe_parse_float(
102
103
  extract_grouped_data(data_values, duration_key.value)
103
- or extract_grouped_data(data_values, DEFAULT_DURATION.value) # defaults to 12 months if no duration specified
104
+ or extract_grouped_data(data_values, DEFAULT_DURATION.value), # defaults to 12 months if no duration specified
105
+ default=None
104
106
  ) if data_values else 0
105
107
 
106
108
 
@@ -38,7 +38,7 @@ def _emission(value: float):
38
38
 
39
39
 
40
40
  def _urea_emission_factor(term_id: str):
41
- return safe_parse_float(get_term_lookup(term_id, LOOKUPS['inorganicFertiliser'][2]), None)
41
+ return safe_parse_float(get_term_lookup(term_id, LOOKUPS['inorganicFertiliser'][2]), default=None)
42
42
 
43
43
 
44
44
  def _run(urea_values: list):
@@ -54,7 +54,9 @@ def _practice(value: float, min: float, max: float, sd: float):
54
54
 
55
55
 
56
56
  def _get_value(country: str, col: str):
57
- return safe_parse_float(get_region_lookup_value(LOOKUP_TABLE, country, col, model=MODEL, term=TERM_ID))
57
+ return safe_parse_float(
58
+ get_region_lookup_value(LOOKUP_TABLE, country, col, model=MODEL, term=TERM_ID), default=None
59
+ )
58
60
 
59
61
 
60
62
  def _run(country: str):
@@ -67,7 +69,7 @@ def _run(country: str):
67
69
 
68
70
  def _should_run(cycle: dict):
69
71
  country = cycle.get('site', {}).get('country', {}).get('@id')
70
- croppingDuration = _get_value(country, LOOKUP_COL_PREFIX)
72
+ croppingDuration = _get_value(country, LOOKUP_COL_PREFIX) or 0
71
73
 
72
74
  cycleDuration = cycle.get('cycleDuration', 0)
73
75
  flooded_rice = has_flooded_rice(cycle.get('products', []))
@@ -67,7 +67,7 @@ def _crop_residue_lookup_col(term):
67
67
 
68
68
 
69
69
  def _get_lookup_value(term: dict, column: str):
70
- return safe_parse_float(get_lookup_value(term, column, model=MODEL, term=TERM_ID), None)
70
+ return safe_parse_float(get_lookup_value(term, column, model=MODEL, term=TERM_ID), default=None)
71
71
 
72
72
 
73
73
  # Single crop
@@ -2,7 +2,8 @@ from hestia_earth.schema import EmissionMethodTier
2
2
 
3
3
  from hestia_earth.models.log import logRequirements, logShouldRun
4
4
  from hestia_earth.models.utils.emission import _new_emission
5
- from .utils import _get_crop_residue_burnt_value
5
+ from hestia_earth.models.utils.blank_node import get_lookup_value
6
+ from hestia_earth.models.utils.cropResidue import get_crop_residue_burnt_value
6
7
  from . import MODEL
7
8
 
8
9
  REQUIREMENTS = {
@@ -23,9 +24,11 @@ RETURNS = {
23
24
  "methodTier": "tier 1"
24
25
  }]
25
26
  }
27
+ LOOKUPS = {
28
+ "emission": ["ipcc2019CropResidueBurningFactor"]
29
+ }
26
30
  TERM_ID = 'n2OToAirCropResidueBurningDirect'
27
31
  TIER = EmissionMethodTier.TIER_1.value
28
- DRY_MATTER_FACTOR_TO_N2O = 0.07/1000
29
32
 
30
33
 
31
34
  def _emission(value: float):
@@ -37,11 +40,12 @@ def _emission(value: float):
37
40
 
38
41
  def _run(product_value: list):
39
42
  value = sum(product_value)
40
- return [_emission(value * DRY_MATTER_FACTOR_TO_N2O)]
43
+ factor = get_lookup_value({'termType': 'emission', '@id': TERM_ID}, LOOKUPS['emission'][0])
44
+ return [_emission(value * factor)]
41
45
 
42
46
 
43
47
  def _should_run(cycle: dict):
44
- crop_residue_burnt_value = _get_crop_residue_burnt_value(cycle)
48
+ crop_residue_burnt_value = get_crop_residue_burnt_value(cycle)
45
49
  has_crop_residue_burnt = len(crop_residue_burnt_value) > 0
46
50
 
47
51
  logRequirements(cycle, model=MODEL, term=TERM_ID,
@@ -67,7 +67,7 @@ def _crop_residue_lookup_col(term):
67
67
 
68
68
 
69
69
  def _get_lookup_value(term: dict, column: str):
70
- return safe_parse_float(get_lookup_value(term, column, model=MODEL, term=TERM_ID), None)
70
+ return safe_parse_float(get_lookup_value(term, column, model=MODEL, term=TERM_ID), default=None)
71
71
 
72
72
 
73
73
  # Single crop
@@ -314,7 +314,9 @@ def _get_fuel_factor(fuel_category: _FuelCategory) -> dict:
314
314
  debugMissingLookup(LOOKUP_FILENAME, "FuelCategory", row, target, data.get(target), model=MODEL, term=term_id)
315
315
 
316
316
  return (
317
- {k: parsed for k, v in data.items() if (parsed := safe_parse_float(v, None)) is not None} # remove missing
317
+ {
318
+ k: parsed for k, v in data.items() if (parsed := safe_parse_float(v, default=None)) is not None
319
+ } # remove missing
318
320
  or _DEFAULT_FACTOR # if parsed dict empty, return default
319
321
  )
320
322
 
@@ -343,7 +345,9 @@ def _get_emission_factor(term_id: _EmissionTermId, emission_category: _EmissionC
343
345
  )
344
346
 
345
347
  return (
346
- {k: parsed for k, v in data.items() if (parsed := safe_parse_float(v, None)) is not None} # remove missing
348
+ {
349
+ k: parsed for k, v in data.items() if (parsed := safe_parse_float(v, default=None)) is not None
350
+ } # remove missing
347
351
  or _DEFAULT_FACTOR # if parsed dict empty, return default
348
352
  )
349
353
 
@@ -34,7 +34,7 @@ def _get_activityCoefficient(animal: dict, systems: list) -> float:
34
34
  values = [(
35
35
  safe_parse_float(
36
36
  get_table_value(lookup, 'termid', system.get('term', {}).get('@id'), column_name(term_id)),
37
- 0
37
+ default=0
38
38
  ),
39
39
  list_sum(system.get('value', [0]))
40
40
  ) for system in systems]
@@ -46,7 +46,7 @@ def _calculate_NEm(cycle: dict, animal: dict) -> float:
46
46
  term = animal.get('term', {})
47
47
 
48
48
  mjDayKgCfiNetEnergyMaintenance = safe_parse_float(
49
- get_lookup_value(term, 'mjDayKgCfiNetEnergyMaintenanceIpcc2019', model=MODEL, model_key=MODEL_KEY), 0
49
+ get_lookup_value(term, 'mjDayKgCfiNetEnergyMaintenanceIpcc2019', model=MODEL, model_key=MODEL_KEY), default=0
50
50
  )
51
51
  liveweightPerHead = get_node_property(animal, 'liveweightPerHead', False).get('value', 0)
52
52
  animal_value = animal.get('value', 0)
@@ -102,13 +102,13 @@ def _calculate_NEl_sheepAndGoat(cycle: dict, animal: dict) -> float:
102
102
  milkYield = list_sum(milkYieldPractice.get('value', []))
103
103
  EV_milk = safe_parse_float(
104
104
  get_lookup_value(milkYieldPractice.get('term', {}), 'mjKgEvMilkIpcc2019', model=MODEL, model_key=MODEL_KEY),
105
- 0
105
+ default=0
106
106
  )
107
107
  default_fatContent = safe_parse_float(
108
108
  get_lookup_value(
109
109
  milkYieldPractice.get('term', {}), 'defaultFatContentEvMilkIpcc2019', model=MODEL, model_key=MODEL_KEY
110
110
  ),
111
- 7
111
+ default=7
112
112
  )
113
113
  fatContent = get_node_property(milkYieldPractice, 'fatContent').get('value', 0)
114
114
  animal_value = animal.get('value', 0)
@@ -138,9 +138,9 @@ def _calculate_NEwork(cycle: dict, animal: dict, NEm: float) -> float:
138
138
 
139
139
  def _get_pregnancy_ratio_per_birth(animal: dict, value: str) -> float:
140
140
  animalsPerBirth = get_node_property(animal, 'animalsPerBirth').get('value', 3)
141
- single = safe_parse_float(extract_grouped_data(value, 'singleBirth'), 0)
142
- double = safe_parse_float(extract_grouped_data(value, 'doubleBirth'), 0)
143
- tripple = safe_parse_float(extract_grouped_data(value, 'tripleBirthOrMore'))
141
+ single = safe_parse_float(extract_grouped_data(value, 'singleBirth'), default=0)
142
+ double = safe_parse_float(extract_grouped_data(value, 'doubleBirth'), default=0)
143
+ tripple = safe_parse_float(extract_grouped_data(value, 'tripleBirthOrMore'), default=0)
144
144
  return (
145
145
  single if animalsPerBirth <= 1 else
146
146
  ((animalsPerBirth-1)/2)*single * (1-((animalsPerBirth-1)/2)*double) if 1 < animalsPerBirth < 2 else
@@ -153,7 +153,7 @@ def _get_pregnancy_ratio_per_birth(animal: dict, value: str) -> float:
153
153
  def _get_pregnancy_ratio(animal: dict) -> float:
154
154
  term = animal.get('term', {})
155
155
  value = get_lookup_value(term, 'ratioCPregnancyNetEnergyPregnancyIpcc2019', model=MODEL, model_key=MODEL_KEY)
156
- return _get_pregnancy_ratio_per_birth(animal, value) if ';' in value else safe_parse_float(value, 0)
156
+ return _get_pregnancy_ratio_per_birth(animal, value) if ';' in value else safe_parse_float(value, default=0)
157
157
 
158
158
 
159
159
  def _calculate_NEp(cycle: dict, animal: dict, NEm: float) -> float:
@@ -168,7 +168,8 @@ def _calculate_NEg_cattleAndBuffalo(cycle: dict, animal: dict) -> float:
168
168
  term = animal.get('term', {})
169
169
 
170
170
  ratioCNetEnergyGrowthCattleBuffalo = safe_parse_float(
171
- get_lookup_value(term, 'ratioCNetEnergyGrowthCattleBuffaloIpcc2019', model=MODEL, model_key=MODEL_KEY), 0
171
+ get_lookup_value(term, 'ratioCNetEnergyGrowthCattleBuffaloIpcc2019', model=MODEL, model_key=MODEL_KEY),
172
+ default=0
172
173
  )
173
174
  liveweightPerHead = get_node_property(animal, 'liveweightPerHead').get('value', 0)
174
175
  weightAtMaturity = get_node_property(animal, 'weightAtMaturity').get('value', 0)
@@ -190,8 +191,8 @@ def _calculate_NEg_sheepAndGoat(cycle: dict, animal: dict) -> float:
190
191
 
191
192
  MjKgABNetEnergyGrowthSheepGoats = get_lookup_value(
192
193
  term, 'mjKgABNetEnergyGrowthSheepGoatsIpcc2019', model=MODEL, model_key=MODEL_KEY)
193
- MjKg_a = safe_parse_float(extract_grouped_data(MjKgABNetEnergyGrowthSheepGoats, 'a'), 0)
194
- MjKg_b = safe_parse_float(extract_grouped_data(MjKgABNetEnergyGrowthSheepGoats, 'b'), 0)
194
+ MjKg_a = safe_parse_float(extract_grouped_data(MjKgABNetEnergyGrowthSheepGoats, 'a'), default=0)
195
+ MjKg_b = safe_parse_float(extract_grouped_data(MjKgABNetEnergyGrowthSheepGoats, 'b'), default=0)
195
196
  BWi = get_node_property(animal, 'weightAtWeaning').get('value', 0)
196
197
  BWf = get_node_property(animal, 'weightAtOneYear').get('value', 0) or \
197
198
  get_node_property(animal, 'weightAtSlaughter').get('value', 0)
@@ -352,7 +353,7 @@ def calculate_meanDE(practices: list, **log_args) -> float:
352
353
 
353
354
 
354
355
  def product_wool_energy(product: dict):
355
- return safe_parse_float(get_lookup_value(product.get('term', {}), 'mjKgEvWoolNetEnergyWoolIpcc2019'), 24)
356
+ return safe_parse_float(get_lookup_value(product.get('term', {}), 'mjKgEvWoolNetEnergyWoolIpcc2019'), default=24)
356
357
 
357
358
 
358
359
  def should_run_practice(cycle: dict):
@@ -53,7 +53,9 @@ def get_FracNH3NOx_N2O(cycle: dict, term_id: str):
53
53
 
54
54
 
55
55
  def get_yield_dm(term_id: str, term: dict):
56
- return safe_parse_float(get_lookup_value(term, 'IPCC_2019_Ratio_AGRes_YieldDM', model=MODEL, term=term_id), None)
56
+ return safe_parse_float(
57
+ get_lookup_value(term, 'IPCC_2019_Ratio_AGRes_YieldDM', model=MODEL, term=term_id), default=None
58
+ )
57
59
 
58
60
 
59
61
  def get_milkYield_practice(node: dict):
@@ -146,7 +148,9 @@ EF5_FACTORS = {
146
148
 
147
149
 
148
150
  def _get_waterRegime_lookup(model_term_id: str, practice: dict, col: str):
149
- return safe_parse_float(get_lookup_value(practice.get('term', {}), col, model=MODEL, term=model_term_id), None)
151
+ return safe_parse_float(
152
+ get_lookup_value(practice.get('term', {}), col, model=MODEL, term=model_term_id), default=None
153
+ )
150
154
 
151
155
 
152
156
  def _is_wet(ecoClimateZone: str = None):
@@ -31,15 +31,18 @@ LOOKUP_NAME = 'region-crop-cropGroupingResidue-burnt.csv'
31
31
  def _get_default_percent(cycle: dict, term: dict, country_id: str):
32
32
  crop_grouping = get_lookup_value(term, LOOKUPS['crop'][0], model=MODEL, term=TERM_ID)
33
33
  percent = safe_parse_float(
34
- get_region_lookup_value(LOOKUP_NAME, country_id, crop_grouping, model=MODEL, term=TERM_ID), None
34
+ get_region_lookup_value(LOOKUP_NAME, country_id, crop_grouping, model=MODEL, term=TERM_ID), default=None
35
35
  ) if crop_grouping else None
36
- comb_factor = safe_parse_float(get_lookup_value(term, LOOKUPS['crop'][1]))
36
+ comb_factor = safe_parse_float(get_lookup_value(term, LOOKUPS['crop'][1]), default=None)
37
37
  logRequirements(cycle, model=MODEL, term=TERM_ID,
38
38
  crop_grouping=crop_grouping,
39
39
  country_id=country_id,
40
40
  percent=percent,
41
41
  comb_factor=comb_factor)
42
- return percent if comb_factor is None or percent is None else percent * comb_factor
42
+ return percent if any([
43
+ comb_factor is None,
44
+ percent is None
45
+ ]) else percent * comb_factor
43
46
 
44
47
 
45
48
  def _run(cycle: dict, remaining_value: float, primary_product: dict, country_id: str):
@@ -37,7 +37,7 @@ def _get_default_percent(cycle: dict, term: dict, country_id: str):
37
37
  crop_grouping=crop_grouping,
38
38
  country_id=country_id,
39
39
  percent=percent)
40
- return safe_parse_float(percent, None)
40
+ return safe_parse_float(percent, default=None)
41
41
 
42
42
 
43
43
  def _run(cycle: dict, remaining_value: float, primary_product: dict, country_id: str):