hestia-earth-models 0.70.0__py3-none-any.whl → 0.70.2__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 (192) hide show
  1. hestia_earth/models/aware/scarcityWeightedWaterUse.py +8 -16
  2. hestia_earth/models/cml2001Baseline/resourceUseMineralsAndMetalsDuringCycle.py +2 -1
  3. hestia_earth/models/config/Cycle.json +98 -50
  4. hestia_earth/models/config/ImpactAssessment.json +12 -4
  5. hestia_earth/models/config/Site.json +40 -21
  6. hestia_earth/models/cycle/transformation.py +1 -1
  7. hestia_earth/models/cycle/utils.py +0 -6
  8. hestia_earth/models/data/ecoinventV3/__init__.py +15 -13
  9. hestia_earth/models/ecoalimV9/__init__.py +13 -0
  10. hestia_earth/models/ecoalimV9/cycle.py +128 -0
  11. hestia_earth/models/ecoalimV9/impact_assessment.py +125 -0
  12. hestia_earth/models/ecoalimV9/utils.py +31 -0
  13. hestia_earth/models/ecoinventV3/__init__.py +6 -14
  14. hestia_earth/models/ecoinventV3/utils.py +1 -29
  15. hestia_earth/models/ecoinventV3AndEmberClimate/__init__.py +8 -2
  16. hestia_earth/models/emissionNotRelevant/__init__.py +33 -8
  17. hestia_earth/models/{cycle → hestia}/aboveGroundCropResidue.py +4 -3
  18. hestia_earth/models/{cycle → hestia}/aboveGroundCropResidueTotal.py +1 -1
  19. hestia_earth/models/{site → hestia}/brackishWater.py +1 -1
  20. hestia_earth/models/{site → hestia}/cationExchangeCapacityPerKgSoil.py +1 -1
  21. hestia_earth/models/{cycle → hestia}/coldCarcassWeightPerHead.py +1 -1
  22. hestia_earth/models/{cycle → hestia}/coldDressedCarcassWeightPerHead.py +1 -1
  23. hestia_earth/models/{cycle → hestia}/concentrateFeed.py +1 -1
  24. hestia_earth/models/{cycle → hestia}/cropResidueManagement.py +1 -1
  25. hestia_earth/models/{cycle → hestia}/croppingIntensity.py +1 -1
  26. hestia_earth/models/{cycle → hestia}/energyContentLowerHeatingValue.py +1 -1
  27. hestia_earth/models/{cycle → hestia}/excretaKgMass.py +8 -3
  28. hestia_earth/models/{cycle → hestia}/excretaKgN.py +1 -1
  29. hestia_earth/models/{cycle → hestia}/excretaKgVs.py +1 -1
  30. hestia_earth/models/{cycle → hestia}/feedConversionRatio/__init__.py +1 -1
  31. hestia_earth/models/{site → hestia}/flowingWater.py +1 -1
  32. hestia_earth/models/{site → hestia}/freshWater.py +1 -1
  33. hestia_earth/models/{cycle → hestia}/inorganicFertiliser.py +1 -1
  34. hestia_earth/models/{cycle → hestia}/irrigatedTypeUnspecified.py +14 -19
  35. hestia_earth/models/hestia/landCover.py +30 -22
  36. hestia_earth/models/{cycle → hestia}/liveAnimal.py +1 -1
  37. hestia_earth/models/{cycle → hestia}/longFallowRatio.py +1 -1
  38. hestia_earth/models/{site → hestia}/management.py +4 -6
  39. hestia_earth/models/{cycle → hestia}/materialAndSubstrate.py +1 -1
  40. hestia_earth/models/{cycle → hestia}/milkYield.py +1 -1
  41. hestia_earth/models/{site → hestia}/netPrimaryProduction.py +1 -1
  42. hestia_earth/models/{site → hestia}/organicCarbonPerHa.py +1 -1
  43. hestia_earth/models/hestia/pToSurfaceWaterAquacultureSystems.py +148 -0
  44. hestia_earth/models/{cycle → hestia}/pastureGrass.py +1 -1
  45. hestia_earth/models/{cycle → hestia}/pastureSystem.py +1 -1
  46. hestia_earth/models/{site → hestia}/potentialEvapotranspirationAnnual.py +3 -3
  47. hestia_earth/models/{site → hestia}/potentialEvapotranspirationMonthly.py +3 -3
  48. hestia_earth/models/{site → hestia}/precipitationAnnual.py +3 -3
  49. hestia_earth/models/{site → hestia}/precipitationMonthly.py +3 -3
  50. hestia_earth/models/{site → hestia}/rainfallAnnual.py +3 -3
  51. hestia_earth/models/{site → hestia}/rainfallMonthly.py +3 -3
  52. hestia_earth/models/{cycle → hestia}/readyToCookWeightPerHead.py +1 -1
  53. hestia_earth/models/{cycle → hestia}/residueBurnt.py +1 -1
  54. hestia_earth/models/{cycle → hestia}/residueIncorporated.py +1 -1
  55. hestia_earth/models/{cycle → hestia}/residueLeftOnField.py +1 -1
  56. hestia_earth/models/hestia/residueRemoved.py +65 -13
  57. hestia_earth/models/{site → hestia}/salineWater.py +1 -1
  58. hestia_earth/models/{site → hestia}/soilMeasurement.py +1 -1
  59. hestia_earth/models/{cycle → hestia}/stockingDensityAnimalHousingAverage.py +1 -1
  60. hestia_earth/models/{site → hestia}/temperatureAnnual.py +3 -3
  61. hestia_earth/models/{site → hestia}/temperatureMonthly.py +3 -3
  62. hestia_earth/models/{site → hestia}/totalNitrogenPerKgSoil.py +1 -1
  63. hestia_earth/models/{cycle → hestia}/unknownPreSeasonWaterRegime.py +1 -1
  64. hestia_earth/models/hestia/utils.py +93 -0
  65. hestia_earth/models/{site → hestia}/waterDepth.py +1 -1
  66. hestia_earth/models/hestia/waterSalinity.py +78 -0
  67. hestia_earth/models/ipcc2019/aboveGroundBiomass.py +1 -1
  68. hestia_earth/models/ipcc2019/belowGroundBiomass.py +1 -1
  69. hestia_earth/models/ipcc2019/biomass_utils.py +2 -4
  70. hestia_earth/models/ipcc2019/ch4ToAirFloodedRice.py +166 -79
  71. hestia_earth/models/ipcc2019/ch4ToAirOrganicSoilCultivation.py +270 -0
  72. hestia_earth/models/ipcc2019/co2ToAirAboveGroundBiomassStockChange.py +0 -3
  73. hestia_earth/models/ipcc2019/co2ToAirBelowGroundBiomassStockChange.py +0 -3
  74. hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +88 -63
  75. hestia_earth/models/ipcc2019/co2ToAirLimeHydrolysis.py +7 -5
  76. hestia_earth/models/ipcc2019/co2ToAirOrganicSoilCultivation.py +215 -0
  77. hestia_earth/models/ipcc2019/co2ToAirSoilOrganicCarbonStockChange.py +0 -3
  78. hestia_earth/models/ipcc2019/co2ToAirUreaHydrolysis.py +16 -9
  79. hestia_earth/models/ipcc2019/n2OToAirOrganicSoilCultivationDirect.py +161 -0
  80. hestia_earth/models/ipcc2019/nonCo2EmissionsToAirNaturalVegetationBurning.py +35 -47
  81. hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_1.py +86 -1
  82. hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_2.py +127 -1
  83. hestia_earth/models/ipcc2019/organicCarbonPerHa_utils.py +7 -5
  84. hestia_earth/models/ipcc2019/organicSoilCultivation_utils.py +159 -0
  85. hestia_earth/models/mocking/search-results.json +1113 -1113
  86. hestia_earth/models/pooreNemecek2018/utils.py +8 -2
  87. hestia_earth/models/schmidt2007/ch4ToAirWasteTreatment.py +1 -4
  88. hestia_earth/models/schmidt2007/h2SToAirWasteTreatment.py +1 -4
  89. hestia_earth/models/schmidt2007/n2OToAirWasteTreatmentDirect.py +1 -4
  90. hestia_earth/models/schmidt2007/nh3ToAirWasteTreatment.py +1 -4
  91. hestia_earth/models/site/grouped_measurement.py +132 -0
  92. hestia_earth/models/utils/__init__.py +4 -3
  93. hestia_earth/models/utils/background_emissions.py +52 -0
  94. hestia_earth/models/utils/blank_node.py +47 -14
  95. hestia_earth/models/utils/constant.py +26 -20
  96. hestia_earth/models/utils/impact_assessment.py +26 -17
  97. hestia_earth/models/utils/lookup.py +48 -39
  98. hestia_earth/models/utils/measurement.py +3 -3
  99. hestia_earth/models/utils/product.py +39 -1
  100. hestia_earth/models/utils/property.py +14 -6
  101. hestia_earth/models/version.py +1 -1
  102. {hestia_earth_models-0.70.0.dist-info → hestia_earth_models-0.70.2.dist-info}/METADATA +2 -2
  103. {hestia_earth_models-0.70.0.dist-info → hestia_earth_models-0.70.2.dist-info}/RECORD +187 -171
  104. tests/models/aware/test_scarcityWeightedWaterUse.py +1 -12
  105. tests/models/ecoalimV9/__init__.py +0 -0
  106. tests/models/ecoalimV9/test_cycle.py +21 -0
  107. tests/models/ecoalimV9/test_impact_assessment.py +24 -0
  108. tests/models/environmentalFootprintV3_1/test_scarcityWeightedWaterUse.py +4 -2
  109. tests/models/{cycle → hestia}/test_aboveGroundCropResidue.py +1 -1
  110. tests/models/{cycle → hestia}/test_aboveGroundCropResidueTotal.py +1 -1
  111. tests/models/{site → hestia}/test_brackishWater.py +1 -1
  112. tests/models/{site → hestia}/test_cationExchangeCapacityPerKgSoil.py +1 -1
  113. tests/models/{cycle → hestia}/test_coldCarcassWeightPerHead.py +1 -1
  114. tests/models/{cycle → hestia}/test_coldDressedCarcassWeightPerHead.py +1 -1
  115. tests/models/{cycle → hestia}/test_concentrateFeed.py +1 -1
  116. tests/models/{cycle → hestia}/test_cropResidueManagement.py +1 -1
  117. tests/models/{cycle → hestia}/test_croppingIntensity.py +1 -1
  118. tests/models/{cycle → hestia}/test_energyContentLowerHeatingValue.py +5 -3
  119. tests/models/{cycle → hestia}/test_excretaKgMass.py +1 -1
  120. tests/models/{cycle → hestia}/test_excretaKgN.py +1 -1
  121. tests/models/{cycle → hestia}/test_excretaKgVs.py +1 -1
  122. tests/models/{cycle → hestia}/test_feedConversionRatio.py +3 -4
  123. tests/models/{site → hestia}/test_flowingWater.py +1 -1
  124. tests/models/{site → hestia}/test_freshWater.py +1 -1
  125. tests/models/{cycle → hestia}/test_inorganicFertiliser.py +1 -1
  126. tests/models/{cycle → hestia}/test_irrigatedTypeUnspecified.py +2 -5
  127. tests/models/hestia/test_landCover.py +4 -34
  128. tests/models/{cycle → hestia}/test_liveAnimal.py +1 -1
  129. tests/models/{cycle → hestia}/test_longFallowRatio.py +1 -1
  130. tests/models/{site → hestia}/test_management.py +1 -1
  131. tests/models/{cycle → hestia}/test_materialsAndSubstrate.py +1 -1
  132. tests/models/{cycle → hestia}/test_milkYield.py +1 -1
  133. tests/models/{site → hestia}/test_netPrimaryProduction.py +1 -1
  134. tests/models/{site → hestia}/test_organicCarbonPerHa.py +1 -1
  135. tests/models/{site → hestia}/test_organicCarbonPerKgSoil.py +1 -1
  136. tests/models/{site → hestia}/test_organicCarbonPerM3Soil.py +1 -1
  137. tests/models/{site → hestia}/test_organicMatterPerKgSoil.py +1 -1
  138. tests/models/{site → hestia}/test_organicMatterPerM3Soil.py +1 -1
  139. tests/models/hestia/test_pToSurfaceWaterAquacultureSystems.py +56 -0
  140. tests/models/{cycle → hestia}/test_pastureGrass.py +1 -1
  141. tests/models/{cycle → hestia}/test_pastureSystem.py +1 -1
  142. tests/models/{site → hestia}/test_potentialEvapotranspirationAnnual.py +1 -1
  143. tests/models/{site → hestia}/test_potentialEvapotranspirationMonthly.py +1 -1
  144. tests/models/{site → hestia}/test_precipitationAnnual.py +1 -1
  145. tests/models/{site → hestia}/test_precipitationMonthly.py +1 -1
  146. tests/models/{site → hestia}/test_rainfallAnnual.py +1 -1
  147. tests/models/{site → hestia}/test_rainfallMonthly.py +1 -1
  148. tests/models/{cycle → hestia}/test_readyToCookWeightPerHead.py +1 -1
  149. tests/models/{cycle → hestia}/test_residueBurnt.py +1 -1
  150. tests/models/{cycle → hestia}/test_residueIncorporated.py +1 -1
  151. tests/models/{cycle → hestia}/test_residueLeftOnField.py +1 -1
  152. tests/models/hestia/test_residueRemoved.py +15 -3
  153. tests/models/{site → hestia}/test_salineWater.py +1 -1
  154. tests/models/{site → hestia}/test_soilMeasurement.py +13 -21
  155. tests/models/{cycle → hestia}/test_stockingDensityAnimalHousingAverage.py +1 -1
  156. tests/models/{site → hestia}/test_temperatureAnnual.py +1 -1
  157. tests/models/{site → hestia}/test_temperatureMonthly.py +1 -1
  158. tests/models/{site → hestia}/test_totalNitrogenPerKgSoil.py +1 -1
  159. tests/models/{cycle → hestia}/test_unknownPreSeasonWaterRegime.py +1 -1
  160. tests/models/{site → hestia}/test_waterDepth.py +1 -1
  161. tests/models/hestia/test_waterSalinity.py +26 -0
  162. tests/models/ipcc2019/test_ch4ToAirEntericFermentation.py +2 -5
  163. tests/models/ipcc2019/test_ch4ToAirFloodedRice.py +10 -42
  164. tests/models/ipcc2019/test_ch4ToAirOrganicSoilCultivation.py +61 -0
  165. tests/models/ipcc2019/test_co2ToAirAboveGroundBiomassStockChange.py +11 -9
  166. tests/models/ipcc2019/test_co2ToAirBelowGroundBiomassStockChange.py +10 -8
  167. tests/models/ipcc2019/test_co2ToAirLimeHydrolysis.py +1 -1
  168. tests/models/ipcc2019/test_co2ToAirOrganicSoilCultivation.py +62 -0
  169. tests/models/ipcc2019/test_co2ToAirSoilOrganicCarbonStockChange.py +11 -8
  170. tests/models/ipcc2019/test_n2OToAirOrganicSoilCultivationDirect.py +61 -0
  171. tests/models/ipcc2019/test_nonCo2EmissionsToAirNaturalVegetationBurning.py +3 -2
  172. tests/models/site/test_grouped_measurement.py +20 -0
  173. tests/models/test_ecoinventV3AndEmberClimate.py +2 -2
  174. tests/models/test_emissionNotRelevant.py +0 -8
  175. tests/models/utils/test_measurement.py +1 -1
  176. hestia_earth/models/cycle/residueRemoved.py +0 -54
  177. hestia_earth/models/hestia/nh3ToSurfaceWaterAquacultureSystems.py +0 -64
  178. hestia_earth/models/site/utils.py +0 -93
  179. tests/models/cycle/test_residueRemoved.py +0 -37
  180. tests/models/hestia/test_nh3ToSurfaceWaterAquacultureSystems.py +0 -51
  181. /hestia_earth/models/{cycle → hestia}/feedConversionRatio/feedConversionRatioCarbon.py +0 -0
  182. /hestia_earth/models/{cycle → hestia}/feedConversionRatio/feedConversionRatioDryMatter.py +0 -0
  183. /hestia_earth/models/{cycle → hestia}/feedConversionRatio/feedConversionRatioEnergy.py +0 -0
  184. /hestia_earth/models/{cycle → hestia}/feedConversionRatio/feedConversionRatioFedWeight.py +0 -0
  185. /hestia_earth/models/{cycle → hestia}/feedConversionRatio/feedConversionRatioNitrogen.py +0 -0
  186. /hestia_earth/models/{site → hestia}/organicCarbonPerKgSoil.py +0 -0
  187. /hestia_earth/models/{site → hestia}/organicCarbonPerM3Soil.py +0 -0
  188. /hestia_earth/models/{site → hestia}/organicMatterPerKgSoil.py +0 -0
  189. /hestia_earth/models/{site → hestia}/organicMatterPerM3Soil.py +0 -0
  190. {hestia_earth_models-0.70.0.dist-info → hestia_earth_models-0.70.2.dist-info}/LICENSE +0 -0
  191. {hestia_earth_models-0.70.0.dist-info → hestia_earth_models-0.70.2.dist-info}/WHEEL +0 -0
  192. {hestia_earth_models-0.70.0.dist-info → hestia_earth_models-0.70.2.dist-info}/top_level.txt +0 -0
@@ -1,8 +1,10 @@
1
+ from functools import reduce
1
2
  from hestia_earth.schema import EmissionMethodTier, EmissionStatsDefinition, TermTermType
2
3
  from hestia_earth.utils.model import filter_list_term_type, find_term_match
3
- from hestia_earth.utils.tools import list_sum, safe_parse_float
4
+ from hestia_earth.utils.tools import list_sum, safe_parse_float, non_empty_list
4
5
 
5
- from hestia_earth.models.log import debugValues, logRequirements, logShouldRun
6
+ from hestia_earth.models.log import logRequirements, logShouldRun, log_as_table, debugValues
7
+ from hestia_earth.models.utils import multiply_values
6
8
  from hestia_earth.models.utils.term import get_lookup_value
7
9
  from hestia_earth.models.utils.emission import _new_emission
8
10
  from hestia_earth.models.utils.product import has_flooded_rice
@@ -12,48 +14,54 @@ from . import MODEL
12
14
 
13
15
  REQUIREMENTS = {
14
16
  "Cycle": {
15
- "practices": [{"@type": "Practice", "value": "", "term.@id": "croppingDuration"}],
17
+ "practices": [
18
+ {"@type": "Practice", "value": "", "term.@id": "croppingDuration"},
19
+ {"@type": "Practice", "value": "", "term.termType": ["landUseManagement", "waterRegime"]},
20
+ {"@type": "Practice", "value": "", "term.termType": "cropResidueManagement"}
21
+ ],
22
+ "products": [{"@type": "Product", "value": "", "term.@id": "aboveGroundCropResidueIncorporated"}],
16
23
  "site": {
17
24
  "@type": "Site",
18
25
  "country": {"@type": "Term", "termType": "region"}
19
26
  },
20
27
  "optional": {
21
28
  "inputs": [
22
- {
23
- "@type": "Input",
24
- "value": "",
25
- "term.termType": "organicFertiliser"
26
- },
29
+ {"@type": "Input", "value": "", "term.termType": "organicFertiliser"},
27
30
  {
28
31
  "@type": "Input",
29
32
  "value": "",
30
33
  "term.termType": "fertiliserBrandName",
31
34
  "properties": [{"@type": "Property", "value": "", "key.termType": "organicFertiliser"}]
32
35
  }
33
- ],
34
- "products": [{"@type": "Product", "value": "", "term.@id": "aboveGroundCropResidueIncorporated"}],
35
- "practices": [
36
- {"@type": "Practice", "value": "", "term.termType": "cropResidueManagement"},
37
- {"@type": "Practice", "value": "", "term.termType": "landUseManagement"},
38
- {"@type": "Practice", "value": "", "term.termType": "waterRegime"}
39
36
  ]
40
37
  }
41
38
  }
42
39
  }
43
40
  LOOKUPS = {
44
41
  "landUseManagement": [
45
- "IPCC_2019_CH4_rice_SFw", "IPCC_2019_CH4_rice_SFw-min", "IPCC_2019_CH4_rice_SFw-max",
46
- "IPCC_2019_CH4_rice_SFw-sd",
47
- "IPCC_2019_CH4_rice_SFp", "IPCC_2019_CH4_rice_SFp-min", "IPCC_2019_CH4_rice_SFp-max",
42
+ "IPCC_2019_CH4_rice_SFp",
43
+ "IPCC_2019_CH4_rice_SFp-min",
44
+ "IPCC_2019_CH4_rice_SFp-max",
48
45
  "IPCC_2019_CH4_rice_SFp-sd"
49
46
  ],
50
47
  "waterRegime": [
51
- "IPCC_2019_CH4_rice_SFw", "IPCC_2019_CH4_rice_SFw-min", "IPCC_2019_CH4_rice_SFw-max",
52
- "IPCC_2019_CH4_rice_SFw-sd",
53
- "IPCC_2019_CH4_rice_SFp", "IPCC_2019_CH4_rice_SFp-min", "IPCC_2019_CH4_rice_SFp-max",
54
- "IPCC_2019_CH4_rice_SFp-sd"
48
+ "IPCC_2019_CH4_rice_SFw",
49
+ "IPCC_2019_CH4_rice_SFw-min",
50
+ "IPCC_2019_CH4_rice_SFw-max",
51
+ "IPCC_2019_CH4_rice_SFw-sd"
52
+ ],
53
+ "organicFertiliser": [
54
+ "IPCC_2019_CH4_rice_CFOA_kg_fresh_weight",
55
+ "IPCC_2019_CH4_rice_CFOA_kg_fresh_weight_min",
56
+ "IPCC_2019_CH4_rice_CFOA_kg_fresh_weight_max",
57
+ "IPCC_2019_CH4_rice_CFOA_kg_fresh_weight_sd"
58
+ ],
59
+ "cropResidueManagement": [
60
+ "IPCC_2019_CH4_rice_CFOA_kg_dry_weight",
61
+ "IPCC_2019_CH4_rice_CFOA_kg_dry_weight_min",
62
+ "IPCC_2019_CH4_rice_CFOA_kg_dry_weight_max",
63
+ "IPCC_2019_CH4_rice_CFOA_kg_dry_weight_sd"
55
64
  ],
56
- "organicFertiliser": ["IPCC_2019_CH4_rice_CFOA_kg_fresh_weight", "IPCC_2019_CH4_rice_CFOA_kg_dry_weight"],
57
65
  "region-ch4ef-IPCC2019": ["CH4_ef", "CH4_ef_min", "CH4_ef_max", "CH4_ef_sd"]
58
66
  }
59
67
  RETURNS = {
@@ -68,92 +76,140 @@ RETURNS = {
68
76
  }
69
77
  TERM_ID = 'ch4ToAirFloodedRice'
70
78
  TIER = EmissionMethodTier.TIER_1.value
79
+ _STATS = ['value', 'min', 'max', 'sd']
71
80
 
72
81
 
73
82
  def _emission(value: float, min: float, max: float, sd: float):
74
83
  emission = _new_emission(TERM_ID, MODEL)
75
84
  emission['value'] = [value]
76
- emission['min'] = [min]
77
- emission['max'] = [max]
78
- emission['sd'] = [sd]
85
+ if min is not None:
86
+ emission['min'] = [min]
87
+ if max is not None:
88
+ emission['max'] = [max]
89
+ if sd is not None:
90
+ emission['sd'] = [sd]
79
91
  emission['methodTier'] = TIER
80
92
  emission['statsDefinition'] = EmissionStatsDefinition.MODELLED.value
81
93
  return emission
82
94
 
83
95
 
84
- def _get_CH4_ef(country: str, suffix: str = ''):
96
+ def _get_CH4_ef(country: str, suffix: str = 'value'):
85
97
  lookup_name = 'region-ch4ef-IPCC2019.csv'
98
+ lookup = 'CH4_ef'
99
+ lookup = '_'.join([lookup, suffix]) if suffix != 'value' else lookup
86
100
  return safe_parse_float(
87
- get_region_lookup_value(lookup_name, country, 'CH4_ef' + suffix, model=MODEL, term=TERM_ID)
101
+ get_region_lookup_value(lookup_name, country, lookup, model=MODEL, term=TERM_ID),
102
+ default=None
88
103
  )
89
104
 
90
105
 
91
- def _get_practice_lookup(term: dict, col: str):
92
- return safe_parse_float(get_lookup_value(term, col, model=MODEL, term=TERM_ID))
93
-
94
-
95
- def _get_cropResidue_value(cycle: dict, suffix: str = ''):
106
+ def _get_cropResidue_value(cycle: dict, suffix: str = 'value'):
107
+ product_id = 'aboveGroundCropResidueIncorporated'
96
108
  abgIncorporated = list_sum(
97
- find_term_match(cycle.get('products', []), 'aboveGroundCropResidueIncorporated').get('value', [])
109
+ find_term_match(cycle.get('products', []), product_id).get('value', []),
110
+ default=None
98
111
  )
99
112
  abgManagement = filter_list_term_type(cycle.get('practices', []), TermTermType.CROPRESIDUEMANAGEMENT)
100
113
  term = abgManagement[0].get('term', {}) if len(abgManagement) > 0 else None
114
+ lookup = 'IPCC_2019_CH4_rice_CFOA_kg_dry_weight'
115
+ lookup = '_'.join([lookup, suffix]) if suffix != 'value' else lookup
101
116
  factor = safe_parse_float(
102
- get_lookup_value(term, LOOKUPS['organicFertiliser'][1] + suffix, model=MODEL, term=TERM_ID)
103
- ) if term else 0
104
- return abgIncorporated * factor
117
+ get_lookup_value(term, lookup, model=MODEL, term=TERM_ID),
118
+ default=None
119
+ ) if term else None
105
120
 
121
+ debugValues(cycle, model=MODEL, term=TERM_ID,
122
+ **{'cropResidue_' + suffix: log_as_table({
123
+ 'product-id': product_id,
124
+ 'product-value': abgIncorporated,
125
+ 'factor': factor
126
+ })})
106
127
 
107
- def _get_fertiliser_value(input: dict, suffix: str = ''):
128
+ return multiply_values([abgIncorporated, factor])
129
+
130
+
131
+ def _get_fertiliser_values(input: dict, suffix: str = 'value'):
108
132
  term = input.get('term', {})
133
+ lookup = 'IPCC_2019_CH4_rice_CFOA_kg_fresh_weight'
134
+ lookup = '_'.join([lookup, suffix]) if suffix != 'value' else lookup
109
135
  factor = safe_parse_float(
110
- get_lookup_value(term, LOOKUPS['organicFertiliser'][0] + suffix, model=MODEL, term=TERM_ID)
136
+ get_lookup_value(term, lookup, model=MODEL, term=TERM_ID),
137
+ default=None
111
138
  )
112
- return list_sum(input.get('value', [])) * factor
139
+ value = list_sum(input.get('value', []))
140
+ return {'input-id': term.get('@id'), 'input-value': value, 'factor': factor}
113
141
 
114
142
 
115
- def _calculate_SFo(cycle: dict, suffix: str = ''):
116
- cropResidue = _get_cropResidue_value(cycle, suffix)
117
- fertilisers = get_organicFertiliser_inputs(cycle)
118
- fert_value = list_sum([_get_fertiliser_value(i, suffix) for i in fertilisers])
119
- return (1 + (fert_value/1000) + (cropResidue/1000)) ** 0.59
143
+ def _get_fertiliser_value(cycle: dict, suffix: str = 'value'):
144
+ fertiliser_values = [_get_fertiliser_values(i, suffix) for i in get_organicFertiliser_inputs(cycle)]
120
145
 
146
+ debugValues(cycle, model=MODEL, term=TERM_ID,
147
+ **{'fertiliser_' + suffix: log_as_table(fertiliser_values)})
121
148
 
122
- def _calculate_SF_average(practices: list, factor: str):
123
- values = [
124
- (_get_practice_lookup(p.get('term', {}), factor), list_sum(p.get('value', []), None)) for p in practices
149
+ valid_fertiliser_values = [
150
+ value for value in fertiliser_values
151
+ if all([value.get('input-value') is not None, value.get('factor') is not None])
125
152
  ]
126
- # sum only values that are numbers
127
- return list_sum([factor * percent / 100 for factor, percent in values if percent is not None])
153
+ fert_value = list_sum([
154
+ value.get('input-value') * value.get('factor')
155
+ for value in valid_fertiliser_values
156
+ ])
157
+ return fert_value
128
158
 
129
159
 
130
- def _calculate_factor(cycle: dict, country: str, practices: list, suffix: str = ''):
131
- CH4_ef = _get_CH4_ef(country, suffix)
132
- SFw = _calculate_SF_average(practices, 'IPCC_2019_CH4_rice_SFw' + suffix)
133
- SFp = _calculate_SF_average(practices, 'IPCC_2019_CH4_rice_SFp' + suffix)
134
- SFo = _calculate_SFo(cycle, suffix)
135
- debugValues(cycle, model=MODEL, term=TERM_ID, **{
136
- 'CH4_ef' + suffix: CH4_ef,
137
- 'SFw' + suffix: SFw,
138
- 'SFp' + suffix: SFp,
139
- 'SFo' + suffix: SFo
140
- })
141
- return CH4_ef * (SFw if SFw > 0 else 1) * (SFp if SFp > 0 else 1) * SFo
160
+ def _calculate_SFo(cycle: dict, suffix: str = 'value'):
161
+ cropResidue = _get_cropResidue_value(cycle, suffix)
162
+ fertiliser = _get_fertiliser_value(cycle, suffix)
163
+ return (1 + (fertiliser/1000) + (cropResidue/1000)) ** 0.59 if all([
164
+ fertiliser is not None,
165
+ cropResidue is not None
166
+ ]) else None
142
167
 
143
168
 
144
- def _get_croppingDuration(croppingDuration: dict, key: str = 'value'):
145
- return list_sum(croppingDuration.get(key, croppingDuration.get('value', [])))
169
+ def _get_practice_values(practice: dict, col: str, default=None):
170
+ term = practice.get('term', {})
171
+ factor = safe_parse_float(get_lookup_value(term, col, model=MODEL, term=TERM_ID), default)
172
+ return {
173
+ 'practice-id': term.get('@id'),
174
+ 'factor': factor,
175
+ 'practice-value': list_sum(practice.get('value', []), default=default)
176
+ } if factor is not None else None
146
177
 
147
178
 
148
- def _run(cycle: dict, croppingDuration: dict, country: str):
149
- practices = filter_list_term_type(cycle.get('practices', []), [
150
- TermTermType.WATERREGIME, TermTermType.LANDUSEMANAGEMENT
151
- ])
179
+ def _calculate_SF_total(cycle: dict, practices: list, lookup: str, suffix: str = 'value', default=None):
180
+ lookup_column = '-'.join([lookup, suffix]) if suffix != 'value' else lookup
181
+ values = non_empty_list([_get_practice_values(p, lookup_column) for p in practices])
152
182
 
153
- value = _calculate_factor(cycle, country, practices) * _get_croppingDuration(croppingDuration)
154
- min = _calculate_factor(cycle, country, practices, '_min') * _get_croppingDuration(croppingDuration, 'min')
155
- max = _calculate_factor(cycle, country, practices, '_max') * _get_croppingDuration(croppingDuration, 'max')
156
- sd = (max-min)/4
183
+ debugValues(cycle, model=MODEL, term=TERM_ID,
184
+ **{lookup_column: log_as_table(values)})
185
+
186
+ used_values = [value for value in values if value.get('practice-value') is not None]
187
+
188
+ # sum only values that are numbers
189
+ return (
190
+ list_sum([
191
+ value.get('factor') * value.get('practice-value') for value in used_values
192
+ ], default=None) / list_sum([
193
+ value.get('practice-value') for value in used_values
194
+ ])
195
+ ) if used_values else (
196
+ default if suffix == 'value' else None
197
+ )
198
+
199
+
200
+ def _value_from_factors(values: list, key: str = 'value'):
201
+ # get the value from all factors, and only run if all are provided
202
+ all_values = [value.get(key) for value in values]
203
+ return multiply_values(all_values) if all([v is not None for v in all_values]) else None
204
+
205
+
206
+ def _run(values: list):
207
+ value = _value_from_factors(values, 'value')
208
+ min = _value_from_factors(values, 'min')
209
+ max = _value_from_factors(values, 'max')
210
+ sd = _value_from_factors(values, 'sd')
211
+
212
+ sd = (max-min)/4 if all([max, min]) else None
157
213
 
158
214
  return [_emission(value, min, max, sd)]
159
215
 
@@ -162,20 +218,51 @@ def _should_run(cycle: dict):
162
218
  country = cycle.get('site', {}).get('country', {}).get('@id')
163
219
 
164
220
  flooded_rice = has_flooded_rice(cycle.get('products', []))
221
+ practices = cycle.get('practices', [])
165
222
 
166
- croppingDuration = find_term_match(cycle.get('practices', []), 'croppingDuration', None)
223
+ croppingDuration = find_term_match(practices, 'croppingDuration', None)
167
224
  has_croppingDuration = croppingDuration is not None
225
+ croppingDuration = reduce(lambda p, key: p | {
226
+ key: list_sum(croppingDuration.get(key) or [], default=None)
227
+ }, _STATS, {}) if has_croppingDuration else {}
228
+
229
+ CH4_ef = reduce(lambda p, key: p | {key: _get_CH4_ef(country, key)}, _STATS, {})
230
+ SFo = reduce(lambda p, key: p | {key: _calculate_SFo(cycle, key)}, _STATS, {})
231
+
232
+ water_regime = filter_list_term_type(practices, TermTermType.WATERREGIME)
233
+ SFw = reduce(lambda p, key: p | {
234
+ key: _calculate_SF_total(cycle, water_regime, 'IPCC_2019_CH4_rice_SFw', key)
235
+ }, _STATS, {})
236
+
237
+ land_use_management = filter_list_term_type(practices, TermTermType.LANDUSEMANAGEMENT)
238
+ SFp = reduce(lambda p, key: p | {
239
+ key: _calculate_SF_total(cycle, land_use_management, 'IPCC_2019_CH4_rice_SFp', key, default=1)
240
+ }, _STATS, {})
168
241
 
169
242
  logRequirements(cycle, model=MODEL, term=TERM_ID,
170
243
  has_flooded_rice=flooded_rice,
171
- has_croppingDuration=has_croppingDuration,
172
- country=country)
173
-
174
- should_run = all([flooded_rice, has_croppingDuration, country])
244
+ country=country,
245
+ values=log_as_table([
246
+ {'name': 'croppingDuration'} | croppingDuration,
247
+ {'name': 'CH4-ef'} | CH4_ef,
248
+ {'name': 'SFo'} | SFo,
249
+ {'name': 'SFw'} | SFw,
250
+ {'name': 'SFp'} | SFp,
251
+ ]))
252
+
253
+ should_run = all([
254
+ flooded_rice,
255
+ has_croppingDuration,
256
+ country,
257
+ CH4_ef.get('value') is not None,
258
+ SFo.get('value') is not None,
259
+ SFw.get('value') is not None,
260
+ SFp.get('value') is not None,
261
+ ])
175
262
  logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
176
- return should_run, croppingDuration, country
263
+ return should_run, [croppingDuration, CH4_ef, SFo, SFw, SFp]
177
264
 
178
265
 
179
266
  def run(cycle: dict):
180
- should_run, croppingDuration, country = _should_run(cycle)
181
- return _run(cycle, croppingDuration, country) if should_run else []
267
+ should_run, values = _should_run(cycle)
268
+ return _run(values) if should_run else []
@@ -0,0 +1,270 @@
1
+ import numpy as np
2
+ import numpy.typing as npt
3
+ from typing import Callable, Union
4
+
5
+ from hestia_earth.schema import EmissionMethodTier, EmissionStatsDefinition
6
+
7
+ from hestia_earth.models.log import logRequirements, logShouldRun
8
+ from hestia_earth.models.utils.array_builders import (
9
+ discrete_uniform_1d, gen_seed, normal_1d, repeat_single, triangular_1d
10
+ )
11
+ from hestia_earth.models.utils.cycle import land_occupation_per_ha
12
+ from hestia_earth.models.utils.descriptive_stats import calc_descriptive_stats
13
+ from hestia_earth.models.utils.ecoClimateZone import EcoClimateZone, get_eco_climate_zone_value
14
+ from hestia_earth.models.utils.emission import _new_emission
15
+ from hestia_earth.models.utils.measurement import most_relevant_measurement_value
16
+ from hestia_earth.models.utils.site import valid_site_type
17
+
18
+ from .organicSoilCultivation_utils import (
19
+ assign_ditch_category, assign_organic_soil_category, calc_emission, DitchCategory, get_ditch_frac,
20
+ get_emission_factor, OrganicSoilCategory, remap_categories, valid_eco_climate_zone
21
+ )
22
+ from . import MODEL
23
+
24
+ REQUIREMENTS = {
25
+ "Cycle": {
26
+ "or": [
27
+ {
28
+ "cycleDuration": "",
29
+ "practices": [{"@type": "Practice", "value": "", "term.@id": "longFallowRatio"}]
30
+ },
31
+ {
32
+ "@doc": "for plantations, additional properties are required",
33
+ "practices": [
34
+ {"@type": "Practice", "value": "", "term.@id": "nurseryDensity"},
35
+ {"@type": "Practice", "value": "", "term.@id": "nurseryDuration"},
36
+ {"@type": "Practice", "value": "", "term.@id": "plantationProductiveLifespan"},
37
+ {"@type": "Practice", "value": "", "term.@id": "plantationDensity"},
38
+ {"@type": "Practice", "value": "", "term.@id": "plantationLifespan"},
39
+ {"@type": "Practice", "value": "", "term.@id": "rotationDuration"}
40
+ ]
41
+ }
42
+ ],
43
+ "site": {
44
+ "@type": "Site",
45
+ "measurements": [
46
+ {"@type": "Measurement", "value": "", "term.@id": "histosol"},
47
+ {"@type": "Measurement", "value": "", "term.@id": "ecoClimateZone"}
48
+ ]
49
+ },
50
+ "optional": {
51
+ "cycleDuration": ""
52
+ }
53
+ }
54
+ }
55
+ LOOKUPS = {
56
+ "crop": [
57
+ "isPlantation",
58
+ "IPCC_2013_ORGANIC_SOIL_CULTIVATION_CATEGORY"
59
+ ],
60
+ "forage": [
61
+ "isPlantation",
62
+ "IPCC_2013_ORGANIC_SOIL_CULTIVATION_CATEGORY"
63
+ ],
64
+ "ecoClimateZone": [
65
+ "IPCC_2013_ORGANIC_SOILS_TONNES_CH4_HECTARE_ANNUAL_CROPS",
66
+ "IPCC_2013_ORGANIC_SOILS_TONNES_CH4_HECTARE_PERENNIAL_CROPS",
67
+ "IPCC_2013_ORGANIC_SOILS_TONNES_CH4_HECTARE_ACACIA",
68
+ "IPCC_2013_ORGANIC_SOILS_TONNES_CH4_HECTARE_OIL_PALM",
69
+ "IPCC_2013_ORGANIC_SOILS_TONNES_CH4_HECTARE_SAGO_PALM",
70
+ "IPCC_2013_ORGANIC_SOILS_TONNES_CH4_HECTARE_PADDY_RICE_CULTIVATION",
71
+ "IPCC_2013_ORGANIC_SOILS_TONNES_CH4_HECTARE_GRASSLAND",
72
+ "IPCC_2013_ORGANIC_SOILS_TONNES_CH4_HECTARE_DITCH",
73
+ "IPCC_2013_ORGANIC_SOILS_TONNES_CH4_HECTARE_OTHER",
74
+ "IPCC_2013_DRAINED_ORGANIC_SOILS_DITCH_FRAC_AGRICULTURAL_LAND",
75
+ "IPCC_2013_DRAINED_ORGANIC_SOILS_DITCH_FRAC_NETHERLANDS"
76
+ ]
77
+ }
78
+ RETURNS = {
79
+ "Emission": [{
80
+ "value": "",
81
+ "sd": "",
82
+ "min": "",
83
+ "max": "",
84
+ "observations": "",
85
+ "statsDefinition": "simulated",
86
+ "methodTier": "tier 1"
87
+ }]
88
+ }
89
+ TERM_ID = 'ch4ToAirOrganicSoilCultivation'
90
+ TIER = EmissionMethodTier.TIER_1.value
91
+
92
+ _STATS_DEFINITION = EmissionStatsDefinition.SIMULATED.value
93
+ _ITERATIONS = 100000
94
+
95
+ _CATEGORY_REMAPPER = {
96
+ OrganicSoilCategory.ACACIA: OrganicSoilCategory.PERENNIAL_CROPS
97
+ }
98
+
99
+
100
+ def _emission(descriptive_stats: dict):
101
+ emission = _new_emission(TERM_ID, MODEL) | descriptive_stats
102
+ emission['methodTier'] = TIER
103
+ return emission
104
+
105
+
106
+ def sample_emission_factor(
107
+ eco_climate_zone: EcoClimateZone,
108
+ organic_soil_category: OrganicSoilCategory,
109
+ seed: Union[int, np.random.Generator, None] = None,
110
+ ) -> npt.NDArray:
111
+ category = remap_categories(organic_soil_category, _CATEGORY_REMAPPER) # fewer categories than CO2 model
112
+ factor_data = get_emission_factor(TERM_ID, eco_climate_zone, category)
113
+ sample_func = _get_sample_func(factor_data)
114
+ return sample_func(iterations=_ITERATIONS, seed=seed, **factor_data)
115
+
116
+
117
+ def sample_ditch_frac(
118
+ eco_climate_zone: EcoClimateZone,
119
+ ditch_category: DitchCategory,
120
+ seed: Union[int, np.random.Generator, None] = None,
121
+ ) -> npt.NDArray:
122
+ factor_data = get_ditch_frac(eco_climate_zone, ditch_category, term=TERM_ID)
123
+ sample_func = _get_sample_func(factor_data)
124
+ return sample_func(iterations=_ITERATIONS, seed=seed, **factor_data)
125
+
126
+
127
+ def _sample_normal(
128
+ *, iterations: int, value: float, sd: float, seed: Union[int, np.random.Generator, None] = None, **_
129
+ ) -> npt.NDArray:
130
+ return normal_1d(shape=(1, iterations), mu=value, sigma=sd, seed=seed)
131
+
132
+
133
+ def _sample_uniform(
134
+ *, iterations: int, min: float, max: float, seed: Union[int, np.random.Generator, None] = None, **_
135
+ ) -> npt.NDArray:
136
+ return discrete_uniform_1d(shape=(1, iterations), low=min, high=max, seed=seed)
137
+
138
+
139
+ def _sample_triangular(
140
+ *, iterations: int, value: float, min: float, max: float, seed: Union[int, np.random.Generator, None] = None, **_
141
+ ) -> npt.NDArray:
142
+ return triangular_1d(shape=(1, iterations), mode=value, low=min, high=max, seed=seed)
143
+
144
+
145
+ def _sample_constant(*, value: float, **_) -> npt.NDArray:
146
+ """Sample a constant model parameter."""
147
+ return repeat_single(shape=(1, 1), value=value)
148
+
149
+
150
+ _KWARGS_TO_SAMPLE_FUNC = {
151
+ ("value", "sd"): _sample_normal,
152
+ ("value", "min", "max"): _sample_triangular,
153
+ ("min", "max"): _sample_uniform,
154
+ ("value",): _sample_constant
155
+ }
156
+ """
157
+ Mapping from available distribution data to sample function.
158
+ """
159
+
160
+
161
+ def _get_sample_func(kwargs: dict) -> Callable:
162
+ """
163
+ Select the correct sample function for a parameter based on the distribution data available. All possible
164
+ parameters for the model should have, at a minimum, a `value`, meaning that no default function needs to be
165
+ specified.
166
+
167
+ This function has been extracted into it's own method to allow for mocking of sample function.
168
+
169
+ Keyword Args
170
+ ------------
171
+ value : float
172
+ The distribution mean.
173
+ sd : float
174
+ The standard deviation of the distribution.
175
+ se : float
176
+ The standard error of the distribution.
177
+ n : float
178
+ Sample size.
179
+
180
+ Returns
181
+ -------
182
+ Callable
183
+ The sample function for the distribution.
184
+ """
185
+ return next(
186
+ sample_func for required_kwargs, sample_func in _KWARGS_TO_SAMPLE_FUNC.items()
187
+ if all(kwarg in kwargs.keys() for kwarg in required_kwargs)
188
+ )
189
+
190
+
191
+ def _should_run(cycle: dict):
192
+ end_date = cycle.get('endDate')
193
+ site = cycle.get('site', {})
194
+ measurements = site.get('measurements', [])
195
+
196
+ seed = gen_seed(cycle, MODEL, TERM_ID)
197
+ rng = np.random.default_rng(seed)
198
+
199
+ def _get_measurement_content(term_id: str):
200
+ return most_relevant_measurement_value(measurements, term_id, end_date)
201
+
202
+ histosol = _get_measurement_content('histosol')
203
+ eco_climate_zone = get_eco_climate_zone_value(cycle, as_enum=True)
204
+ organic_soil_category = assign_organic_soil_category(cycle, log_id=TERM_ID)
205
+ ditch_category = assign_ditch_category(cycle)
206
+
207
+ emission_factor = (
208
+ sample_emission_factor(eco_climate_zone, organic_soil_category, seed=rng) if eco_climate_zone
209
+ else None
210
+ )
211
+ ditch_factor = (
212
+ sample_emission_factor(eco_climate_zone, OrganicSoilCategory.DITCH, seed=rng) if eco_climate_zone
213
+ else None
214
+ )
215
+ ditch_frac = (
216
+ sample_ditch_frac(eco_climate_zone, ditch_category, seed=rng) if eco_climate_zone
217
+ else None
218
+ )
219
+
220
+ land_occupation = land_occupation_per_ha(MODEL, TERM_ID, cycle)
221
+
222
+ logRequirements(
223
+ cycle, model=MODEL, term=TERM_ID,
224
+ eco_climate_zone=eco_climate_zone,
225
+ organic_soil_category=organic_soil_category,
226
+ ditch_category=ditch_category,
227
+ emission_factor=f"{np.mean(emission_factor):.3f}",
228
+ ditch_factor=f"{np.mean(ditch_factor):.3f}",
229
+ ditch_frac=f"{np.mean(ditch_frac):.3f}",
230
+ land_occupation=land_occupation,
231
+ histosol=histosol
232
+ )
233
+
234
+ should_run = all([
235
+ valid_site_type(site),
236
+ valid_eco_climate_zone(eco_climate_zone),
237
+ all(
238
+ var is not None for var in [
239
+ emission_factor,
240
+ ditch_factor,
241
+ ditch_frac,
242
+ land_occupation,
243
+ histosol
244
+ ]
245
+ )
246
+ ])
247
+
248
+ logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
249
+
250
+ return should_run, emission_factor, ditch_factor, ditch_frac, histosol, land_occupation
251
+
252
+
253
+ def _run(
254
+ emission_factor: npt.NDArray,
255
+ ditch_factor: npt.NDArray,
256
+ ditch_frac: npt.NDArray,
257
+ histosol: float,
258
+ land_occupation: float
259
+ ):
260
+ land_emission = calc_emission(TERM_ID, emission_factor, histosol, land_occupation)
261
+ ditch_emission = calc_emission(TERM_ID, ditch_factor, histosol, land_occupation)
262
+
263
+ result = (ditch_emission * ditch_frac) + (land_emission * (1 - ditch_frac))
264
+ descriptive_stats = calc_descriptive_stats(result, _STATS_DEFINITION)
265
+ return [_emission(descriptive_stats)]
266
+
267
+
268
+ def run(cycle: dict):
269
+ should_run, *args = _should_run(cycle)
270
+ return _run(*args) if should_run else []
@@ -186,13 +186,11 @@ def _should_compile_inventory_func(
186
186
  ) for cycle in cycles
187
187
  )
188
188
 
189
- has_stock_measurements = len(carbon_stock_measurements) > 0
190
189
  has_cycles = len(cycles) > 0
191
190
  has_functional_unit_1_ha = all(cycle.get('functionalUnit') == CycleFunctionalUnit._1_HA.value for cycle in cycles)
192
191
 
193
192
  should_run = all([
194
193
  has_soil,
195
- has_stock_measurements,
196
194
  has_cycles,
197
195
  has_functional_unit_1_ha
198
196
  ])
@@ -201,7 +199,6 @@ def _should_compile_inventory_func(
201
199
  "site_type": site_type,
202
200
  "has_soil": has_soil,
203
201
  "carbon_stock_term": _CARBON_STOCK_TERM_ID,
204
- "has_stock_measurements": has_stock_measurements,
205
202
  "has_cycles": has_cycles,
206
203
  "has_functional_unit_1_ha": has_functional_unit_1_ha,
207
204
  }
@@ -199,13 +199,11 @@ def _should_compile_inventory_func(
199
199
  ) for cycle in cycles
200
200
  )
201
201
 
202
- has_stock_measurements = len(carbon_stock_measurements) > 0
203
202
  has_cycles = len(cycles) > 0
204
203
  has_functional_unit_1_ha = all(cycle.get('functionalUnit') == CycleFunctionalUnit._1_HA.value for cycle in cycles)
205
204
 
206
205
  should_run = all([
207
206
  has_soil,
208
- has_stock_measurements,
209
207
  has_cycles,
210
208
  has_functional_unit_1_ha
211
209
  ])
@@ -214,7 +212,6 @@ def _should_compile_inventory_func(
214
212
  "site_type": site_type,
215
213
  "has_soil": has_soil,
216
214
  "carbon_stock_term": _CARBON_STOCK_TERM_ID,
217
- "has_stock_measurements": has_stock_measurements,
218
215
  "has_cycles": has_cycles,
219
216
  "has_functional_unit_1_ha": has_functional_unit_1_ha,
220
217
  }