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
@@ -28,7 +28,7 @@ DRY_VALUE = 19.2 # Bone dry wood has an energy content of 19.2 MJ/kg
28
28
 
29
29
 
30
30
  def _property(value: float):
31
- prop = _new_property(TERM_ID)
31
+ prop = _new_property(TERM_ID, MODEL)
32
32
  prop['value'] = value
33
33
  return prop
34
34
 
@@ -14,6 +14,7 @@ REQUIREMENTS = {
14
14
  "products": [
15
15
  {
16
16
  "@type": "Product",
17
+ "value": "",
17
18
  "term.termType": "excreta",
18
19
  "term.units": ["kg N", "kg VS"]
19
20
  }
@@ -36,16 +37,20 @@ UNITS = [
36
37
 
37
38
 
38
39
  def _product(value: float, term_id: str):
39
- product = _new_product(term_id, value)
40
+ product = _new_product(term_id, value, MODEL)
40
41
  return product
41
42
 
42
43
 
43
44
  def _convert_by_product(cycle: dict, product: dict, term_id: str):
44
45
  existing_product = find_term_match(cycle.get('products', []), term_id)
46
+ existing_product_value = list_sum(existing_product.get('value', []), default=None)
45
47
 
46
48
  conversion_to_kg_ratio = convert_product_to_unit(product, existing_product.get('term', {}).get('units')) \
47
49
  if existing_product else None
48
- value = list_sum(existing_product.get('value', [])) / conversion_to_kg_ratio if conversion_to_kg_ratio else None
50
+ value = existing_product_value / conversion_to_kg_ratio if all([
51
+ existing_product_value is not None,
52
+ conversion_to_kg_ratio
53
+ ]) else None
49
54
 
50
55
  debugValues(cycle, model=MODEL, term=term_id,
51
56
  using_excreta_product=existing_product.get('term', {}).get('@id'),
@@ -65,7 +70,7 @@ def _run_product(cycle: dict, product_term_id: str):
65
70
  # convert to 1kg first, then apply ratio to current value
66
71
  term = download_term(product_term_id, TermTermType.EXCRETA)
67
72
  product = {
68
- 'term': term,
73
+ 'term': term or {},
69
74
  'value': [1]
70
75
  }
71
76
 
@@ -30,7 +30,7 @@ MODEL_KEY = 'excretaKgN'
30
30
 
31
31
 
32
32
  def _product(value: float, term_id: str):
33
- product = _new_product(term_id, value)
33
+ product = _new_product(term_id, value, MODEL)
34
34
  return product
35
35
 
36
36
 
@@ -30,7 +30,7 @@ MODEL_KEY = 'excretaKgVs'
30
30
 
31
31
 
32
32
  def _product(value: float, term_id: str):
33
- product = _new_product(term_id, value)
33
+ product = _new_product(term_id, value, MODEL)
34
34
  return product
35
35
 
36
36
 
@@ -24,7 +24,7 @@ MODELS = [
24
24
 
25
25
 
26
26
  def _practice(term_id: str, value: float):
27
- practice = _new_practice(term_id)
27
+ practice = _new_practice(term_id, MODEL)
28
28
  practice['value'] = [value]
29
29
  return practice
30
30
 
@@ -25,7 +25,7 @@ SITE_TYPE_TO_TERM_ID = {
25
25
 
26
26
 
27
27
  def _measurement(site: dict, term_id: str):
28
- data = _new_measurement(term_id)
28
+ data = _new_measurement(term_id, MODEL)
29
29
  data['value'] = [True]
30
30
  data['methodClassification'] = MeasurementMethodClassification.MODELLED_USING_OTHER_MEASUREMENTS.value
31
31
  return data | get_source(site, BIBLIO_TITLE)
@@ -22,7 +22,7 @@ TERM_ID = 'freshWater'
22
22
 
23
23
 
24
24
  def _measurement():
25
- data = _new_measurement(TERM_ID)
25
+ data = _new_measurement(TERM_ID, MODEL)
26
26
  data['value'] = [True]
27
27
  data['methodClassification'] = MeasurementMethodClassification.MODELLED_USING_OTHER_MEASUREMENTS.value
28
28
  return data
@@ -70,7 +70,7 @@ VALUE_BY_UNIT = {
70
70
 
71
71
 
72
72
  def _input(term_id: str, value: float, min: float = None, max: float = None):
73
- input = _new_input(term_id)
73
+ input = _new_input(term_id, MODEL)
74
74
  input['value'] = [value]
75
75
  if min is not None:
76
76
  input['min'] = [min]
@@ -1,15 +1,13 @@
1
- from hestia_earth.schema import TermTermType, CycleFunctionalUnit
1
+ from hestia_earth.schema import CycleFunctionalUnit
2
2
 
3
3
  from hestia_earth.models.log import logRequirements, logShouldRun
4
4
  from hestia_earth.models.utils.cycle import is_irrigated
5
5
  from hestia_earth.models.utils.practice import _new_practice
6
6
  from hestia_earth.models.utils.input import get_total_irrigation_m3
7
- from hestia_earth.models.utils.completeness import _is_term_type_complete
8
7
  from . import MODEL
9
8
 
10
9
  REQUIREMENTS = {
11
10
  "Cycle": {
12
- "completeness.water": "",
13
11
  "functionalUnit": "1 ha",
14
12
  "none": {
15
13
  "practices": [{"@type": "Practice", "value": "> 0", "term.termType": "waterRegime"}]
@@ -31,38 +29,35 @@ TERM_ID = 'irrigatedTypeUnspecified'
31
29
  MIN_IRRIGATION_M3 = 250
32
30
 
33
31
 
34
- def _practice(value: float):
35
- practice = _new_practice(TERM_ID)
36
- practice['value'] = [value]
32
+ def _practice():
33
+ practice = _new_practice(TERM_ID, MODEL)
34
+ practice['value'] = [100]
37
35
  return practice
38
36
 
39
37
 
40
- def _run(irrigation_m3: float):
41
- value = 100 if irrigation_m3 > MIN_IRRIGATION_M3 else 0
42
- return [_practice(value)]
43
-
44
-
45
38
  def _should_run(cycle: dict):
46
39
  functional_unit = cycle.get('functionalUnit')
47
- water_complete = _is_term_type_complete(cycle, TermTermType.WATER)
48
40
  irrigation_value_m3 = get_total_irrigation_m3(cycle)
41
+ is_1_ha_functional_unit = functional_unit == CycleFunctionalUnit._1_HA.value
49
42
 
50
43
  no_irrigation_practice = not is_irrigated(cycle, model=MODEL, term=TERM_ID)
51
44
 
52
45
  logRequirements(cycle, model=MODEL, term=TERM_ID,
53
46
  no_irrigation_practice=no_irrigation_practice,
54
- term_type_water_complete=water_complete,
55
- irrigation_value_m3=irrigation_value_m3)
47
+ is_1_ha_functional_unit=is_1_ha_functional_unit,
48
+ irrigation_value_m3=irrigation_value_m3,
49
+ irrigation_min_m3=MIN_IRRIGATION_M3,
50
+ is_irrigated=irrigation_value_m3 > MIN_IRRIGATION_M3)
56
51
 
57
52
  should_run = all([
58
53
  no_irrigation_practice,
59
- functional_unit == CycleFunctionalUnit._1_HA.value,
60
- any([water_complete, irrigation_value_m3 > MIN_IRRIGATION_M3])
54
+ is_1_ha_functional_unit,
55
+ irrigation_value_m3 > MIN_IRRIGATION_M3
61
56
  ])
62
57
  logShouldRun(cycle, MODEL, TERM_ID, should_run)
63
- return should_run, irrigation_value_m3
58
+ return should_run
64
59
 
65
60
 
66
61
  def run(cycle: dict):
67
- should_run, irrigation_m3 = _should_run(cycle)
68
- return _run(irrigation_m3) if should_run else []
62
+ should_run = _should_run(cycle)
63
+ return [_practice()] if should_run else []
@@ -11,6 +11,7 @@ from hestia_earth.utils.model import filter_list_term_type
11
11
  from hestia_earth.utils.tools import safe_parse_float, to_precision
12
12
 
13
13
  from hestia_earth.models.log import logRequirements, log_as_table, logShouldRun
14
+ from hestia_earth.models.utils import _omit
14
15
  from hestia_earth.models.utils.constant import DAYS_IN_YEAR
15
16
  from hestia_earth.models.utils.management import _new_management
16
17
  from hestia_earth.models.utils.term import get_lookup_value
@@ -91,6 +92,7 @@ SITE_TYPES = {
91
92
  DEFAULT_WINDOW_IN_YEARS = 20
92
93
  DATE_TOLERANCE_IN_YEARS = 2
93
94
  OUTPUT_SIGNIFICANT_DIGITS = 3
95
+ ALLOWED_LAND_USE_TYPES = [ANNUAL_CROPLAND, PERMANENT_CROPLAND, PERMANENT_PASTURE]
94
96
  _LOOKUP_EXPANSION = "region-crop-cropGroupingFaostatProduction-areaHarvestedUpTo20YearExpansion.csv"
95
97
 
96
98
 
@@ -751,16 +753,21 @@ def _collect_land_use_types(nodes: list) -> list:
751
753
  """Look up the land use type from management nodes."""
752
754
  return [
753
755
  {
756
+ "value": node.get("value", ""),
757
+ "term": node.get("term", {}),
754
758
  "id": node.get("term", {}).get("@id"),
755
759
  "land-use-type": _get_land_use_term_from_node(node),
756
- "endDate": _gapfill_datestr(datestr=node.get("endDate"), mode=DatestrGapfillMode.END)[:10]
760
+ "endDate": _gapfill_datestr(datestr=node.get("endDate"), mode=DatestrGapfillMode.END)[:10],
761
+ "startDate": _gapfill_datestr(
762
+ datestr=node.get("startDate"), mode=DatestrGapfillMode.START
763
+ )[:10] if node.get("startDate") else None
757
764
  } for node in nodes
758
765
  ]
759
766
 
760
767
 
761
- def _no_prior_land_cover_data(nodes: list, end_date: str) -> bool:
768
+ def _no_prior_land_cover_data(nodes: list, node: dict) -> bool:
762
769
  target_date = (
763
- datetime.strptime(end_date, DatestrFormat.YEAR_MONTH_DAY.value)
770
+ datetime.strptime(node.get('startDate') or node.get('endDate'), DatestrFormat.YEAR_MONTH_DAY.value)
764
771
  - timedelta(days=DEFAULT_WINDOW_IN_YEARS * DAYS_IN_YEAR)
765
772
  )
766
773
  previous_nodes = [
@@ -770,45 +777,46 @@ def _no_prior_land_cover_data(nodes: list, end_date: str) -> bool:
770
777
  return len(previous_nodes) == 0
771
778
 
772
779
 
773
- def _should_run(site: dict, management_nodes: list) -> tuple[bool, dict]:
774
- summarised_nodes = _collect_land_use_types(management_nodes)
775
- allowed_land_use_types = [ANNUAL_CROPLAND, PERMANENT_CROPLAND, PERMANENT_PASTURE]
780
+ def _should_run(site: dict) -> tuple[bool, dict]:
781
+ management_nodes = _collect_land_use_types(
782
+ [
783
+ node for node in filter_list_term_type(site.get("management", []), TermTermType.LANDCOVER)
784
+ if not _should_group_landCover(node)
785
+ ]
786
+ )
776
787
  relevant_nodes = sorted(
777
788
  [
778
- node for node in summarised_nodes
779
- if node["land-use-type"] in allowed_land_use_types
789
+ node for node in management_nodes
790
+ if node["land-use-type"] in ALLOWED_LAND_USE_TYPES
780
791
  ],
781
- key=lambda n: n.get("endDate")
792
+ key=lambda n: n.get("startDate") or n.get("endDate")
782
793
  )
794
+
783
795
  land_use_type = relevant_nodes[0].get("land-use-type") if relevant_nodes else None
784
796
 
785
797
  has_no_prior_land_cover_data = _no_prior_land_cover_data(
786
- nodes=management_nodes,
787
- end_date=relevant_nodes[-1:][0].get("endDate")
798
+ nodes=relevant_nodes,
799
+ node=relevant_nodes[-1:][0]
788
800
  ) if relevant_nodes else None
789
801
 
790
802
  should_run_nodes, site_area = _should_run_historical_land_use_change(
791
803
  site=site,
792
- nodes=management_nodes,
804
+ nodes=relevant_nodes,
793
805
  land_use_type=land_use_type
794
806
  ) if all([land_use_type, has_no_prior_land_cover_data]) else (False, {})
795
807
 
796
808
  logRequirements(site, model=MODEL, model_key=MODEL_KEY,
797
- has_management_nodes=bool(management_nodes),
809
+ has_management_nodes=bool(relevant_nodes),
798
810
  land_use_type=land_use_type,
799
- allowed_land_use_types=';'.join(allowed_land_use_types),
811
+ allowed_land_use_types=';'.join(ALLOWED_LAND_USE_TYPES),
800
812
  has_no_prior_land_cover_data=has_no_prior_land_cover_data,
801
- summarised_nodes=log_as_table(summarised_nodes))
813
+ management_nodes=log_as_table([_omit(n, ['term']) for n in relevant_nodes]))
802
814
 
803
815
  should_run = all([land_use_type, has_no_prior_land_cover_data, should_run_nodes])
804
816
  logShouldRun(site, MODEL, None, should_run, model_key=MODEL_KEY)
805
- return should_run_nodes, site_area
817
+ return should_run_nodes, relevant_nodes, site_area
806
818
 
807
819
 
808
820
  def run(site: dict) -> list:
809
- management_nodes = [
810
- node for node in filter_list_term_type(site.get("management", []), TermTermType.LANDCOVER)
811
- if not _should_group_landCover(node)
812
- ]
813
- should_run, site_area = _should_run(site=site, management_nodes=management_nodes)
814
- return _run(site, management_nodes, site_area) if should_run else []
821
+ should_run, relevant_nodes, site_area = _should_run(site=site)
822
+ return _run(site, relevant_nodes, site_area) if should_run else []
@@ -46,7 +46,7 @@ VALID_SITE_TYPES = [SiteSiteType.ANIMAL_HOUSING.value, SiteSiteType.PERMANENT_PA
46
46
 
47
47
 
48
48
  def _product(term: str, value: float):
49
- product = _new_product(term, value)
49
+ product = _new_product(term, value, MODEL)
50
50
  return product
51
51
 
52
52
 
@@ -22,7 +22,7 @@ TERM_ID = 'longFallowRatio'
22
22
 
23
23
 
24
24
  def _practice(value: float):
25
- practice = _new_practice(TERM_ID)
25
+ practice = _new_practice(TERM_ID, MODEL)
26
26
  practice['value'] = [round(value, 7)]
27
27
  return practice
28
28
 
@@ -147,7 +147,7 @@ def _get_cycle_duration(cycle: dict, land_cover_id: str):
147
147
  land_cover_id,
148
148
  column_name('maximumCycleDuration')
149
149
  ), default=None)
150
- return cycle_duration or (lookup_value - 1 if lookup_value else None)
150
+ return cycle_duration or lookup_value
151
151
 
152
152
 
153
153
  def _gap_filled_date_only_str(date_str: str, mode: str = DatestrGapfillMode.END) -> str:
@@ -165,11 +165,9 @@ def _gap_filled_start_date(land_cover_id: str, end_date: str, cycle: dict) -> di
165
165
  """If possible, gap-fill the startDate based on the endDate - cycleDuration"""
166
166
  cycle_duration = _get_cycle_duration(cycle, land_cover_id)
167
167
  return {
168
- "startDate": max(
169
- _gap_filled_date_obj(end_date) - timedelta(days=cycle_duration)
170
- if cycle_duration else datetime.fromtimestamp(0),
171
- _gap_filled_date_obj(cycle.get("startDate"), mode=DatestrGapfillMode.START)
172
- if cycle.get("startDate") else datetime.fromtimestamp(0)
168
+ "startDate": (
169
+ _gap_filled_date_obj(cycle.get("startDate"), mode=DatestrGapfillMode.START) if cycle.get("startDate") else
170
+ _gap_filled_date_obj(end_date) - timedelta(days=cycle_duration - 1)
173
171
  )
174
172
  } if any([cycle_duration, cycle.get("startDate")]) else {}
175
173
 
@@ -53,7 +53,7 @@ _SIGNIFICANT_DIGITS = 5
53
53
 
54
54
 
55
55
  def _input(term_id: str, value: float, stats: dict) -> dict:
56
- node = _new_input(term_id + _ID_SUFFIX)
56
+ node = _new_input(term_id + _ID_SUFFIX, MODEL)
57
57
  node['value'] = [value]
58
58
  return node | stats
59
59
 
@@ -51,7 +51,7 @@ VALID_SITE_TYPES = [
51
51
 
52
52
 
53
53
  def practice(term_id: str, value: float, properties: list, sd: float = None, min: float = None, max: float = None):
54
- data = _new_practice(term_id)
54
+ data = _new_practice(term_id, MODEL)
55
55
  data['value'] = [round(value, 2)]
56
56
  if properties:
57
57
  data['properties'] = properties
@@ -24,7 +24,7 @@ NPP_Aqua = {TemperatureLevel.LOW: 2, TemperatureLevel.MEDIUM: 4, TemperatureLeve
24
24
 
25
25
 
26
26
  def _measurement(site: dict, value: float):
27
- data = _new_measurement(TERM_ID)
27
+ data = _new_measurement(TERM_ID, MODEL)
28
28
  data['value'] = [value]
29
29
  data['methodClassification'] = MeasurementMethodClassification.MODELLED_USING_OTHER_MEASUREMENTS.value
30
30
  return data | get_source(site, BIBLIO_TITLE)
@@ -64,7 +64,7 @@ VALID_MEASUREMENT_METHOD_CLASSIFICATIONS = {
64
64
  def _measurement(
65
65
  site: dict, value: float, depthUpper: Union[int, float], depthLower: Union[int, float], date: Optional[str] = None
66
66
  ) -> dict:
67
- data = _new_measurement(TERM_ID)
67
+ data = _new_measurement(TERM_ID, MODEL)
68
68
  data['value'] = [value]
69
69
  data['depthUpper'] = int(depthUpper)
70
70
  data['depthLower'] = int(depthLower)
@@ -0,0 +1,148 @@
1
+ from hestia_earth.schema import EmissionMethodTier, EmissionStatsDefinition, TermTermType
2
+ from hestia_earth.utils.model import filter_list_term_type
3
+ from hestia_earth.utils.tools import list_sum, non_empty_list
4
+
5
+ from hestia_earth.models.log import logRequirements, logShouldRun, debugValues, log_as_table
6
+ from hestia_earth.models.utils import _filter_list_term_unit
7
+ from hestia_earth.models.utils.emission import _new_emission
8
+ from hestia_earth.models.utils.constant import Units, convert_to_unit, get_atomic_conversion
9
+ from hestia_earth.models.utils.product import convert_product_to_unit
10
+ from hestia_earth.models.utils.completeness import _is_term_type_complete
11
+ from . import MODEL
12
+
13
+ REQUIREMENTS = {
14
+ "Cycle": {
15
+ "completeness.animalFeed": "True",
16
+ "completeness.product": "True",
17
+ "completeness.fertiliser": "True",
18
+ "completeness.liveAnimalInput": "True",
19
+ "inputs": [
20
+ {
21
+ "@type": "Input",
22
+ "term.termType": [
23
+ "crop",
24
+ "liveAnimal",
25
+ "liveAquaticSpecies",
26
+ "animalProduct",
27
+ "processedFood",
28
+ "feedFoodAdditive",
29
+ "organicFertiliser",
30
+ "forage",
31
+ "excreta",
32
+ "waste"
33
+ ],
34
+ "optional": {
35
+ "properties": [
36
+ {"@type": "Property", "value": "", "term.@id": "phosphorusContentAsP"},
37
+ {"@type": "Property", "value": "", "term.@id": "phosphateContentAsP2O5"}
38
+ ]
39
+ }
40
+ },
41
+ {
42
+ "@type": "Input",
43
+ "term.termType": "inorganicFertiliser",
44
+ "term.units": "kg P2O5"
45
+ }
46
+ ],
47
+ "products": [{
48
+ "@type": "Product",
49
+ "term.termType": ["liveAquaticSpecies", "liveAnimal", "animalProduct", "crop"],
50
+ "optional": {
51
+ "properties": [
52
+ {"@type": "Property", "value": "", "term.@id": "phosphorusContentAsP"},
53
+ {"@type": "Property", "value": "", "term.@id": "phosphateContentAsP2O5"}
54
+ ]
55
+ }
56
+ }]
57
+ }
58
+ }
59
+ RETURNS = {
60
+ "Emission": [{
61
+ "value": "",
62
+ "min": "",
63
+ "max": "",
64
+ "methodTier": "tier 1",
65
+ "statsDefinition": "modelled"
66
+ }]
67
+ }
68
+ TERM_ID = 'pToSurfaceWaterAquacultureSystems'
69
+ TIER = EmissionMethodTier.TIER_1.value
70
+
71
+
72
+ def _emission(value: float):
73
+ emission = _new_emission(TERM_ID, MODEL)
74
+ emission['value'] = [value]
75
+ emission['statsDefinition'] = EmissionStatsDefinition.MODELLED.value
76
+ emission['methodTier'] = TIER
77
+ return emission
78
+
79
+
80
+ def _convert_to_P(blank_node: dict):
81
+ return {
82
+ 'id': blank_node.get('term', {}).get('@id'),
83
+ 'value': list_sum(blank_node.get('value'), default=None),
84
+ 'value-converted': (
85
+ convert_product_to_unit(blank_node, Units.KG_P) or
86
+ convert_product_to_unit(blank_node, Units.KG_P2O5) / get_atomic_conversion(Units.KG_P2O5, Units.KG_P) or
87
+ convert_to_unit(blank_node, Units.KG_P)
88
+ )
89
+ }
90
+
91
+
92
+ def _run(cycle: dict):
93
+ inputs = filter_list_term_type(cycle.get('inputs', []), [
94
+ TermTermType.CROP,
95
+ TermTermType.LIVEANIMAL,
96
+ TermTermType.LIVEAQUATICSPECIES,
97
+ TermTermType.ANIMALPRODUCT,
98
+ TermTermType.PROCESSEDFOOD,
99
+ TermTermType.FEEDFOODADDITIVE,
100
+ TermTermType.ORGANICFERTILISER,
101
+ TermTermType.FORAGE,
102
+ TermTermType.EXCRETA,
103
+ TermTermType.WASTE,
104
+ ]) + _filter_list_term_unit(filter_list_term_type(cycle.get('inputs', []), [
105
+ TermTermType.INORGANICFERTILISER
106
+ ]), Units.KG_P2O5)
107
+ inputs_P = list(map(_convert_to_P, inputs))
108
+ total_inputs_P = list_sum(non_empty_list([i.get('value-converted', 0) for i in inputs_P]))
109
+
110
+ products = filter_list_term_type(cycle.get('products', []), [
111
+ TermTermType.CROP,
112
+ TermTermType.LIVEANIMAL,
113
+ TermTermType.LIVEAQUATICSPECIES,
114
+ TermTermType.ANIMALPRODUCT
115
+ ])
116
+ products_P = list(map(_convert_to_P, products))
117
+ total_products_P = list_sum(non_empty_list([i.get('value-converted', 0) for i in products_P]))
118
+
119
+ debugValues(cycle, model=MODEL, term=TERM_ID,
120
+ inputs_P=log_as_table(inputs_P),
121
+ products_P=log_as_table(products_P))
122
+
123
+ return [_emission(total_inputs_P - total_products_P)]
124
+
125
+
126
+ def _should_run(cycle: dict):
127
+ is_animalFeed_complete = _is_term_type_complete(cycle, 'animalFeed')
128
+ is_product_complete = _is_term_type_complete(cycle, 'product')
129
+ is_fertiliser_complete = _is_term_type_complete(cycle, 'fertiliser')
130
+ is_liveAnimalInput_complete = _is_term_type_complete(cycle, 'liveAnimalInput')
131
+
132
+ logRequirements(cycle, model=MODEL, term=TERM_ID,
133
+ is_term_type_animalFeed_complete=is_animalFeed_complete,
134
+ is_term_type_product_complete=is_product_complete,
135
+ is_term_type_fertiliser_complete=is_fertiliser_complete,
136
+ is_term_type_liveAnimalInput_complete=is_liveAnimalInput_complete)
137
+
138
+ should_run = all([
139
+ is_animalFeed_complete,
140
+ is_product_complete,
141
+ is_fertiliser_complete,
142
+ is_liveAnimalInput_complete
143
+ ])
144
+ logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
145
+ return should_run
146
+
147
+
148
+ def run(cycle: dict): return _run(cycle) if _should_run(cycle) else []
@@ -25,7 +25,7 @@ KEY_TERM_ID = 'genericGrassPlant'
25
25
 
26
26
 
27
27
  def _practice():
28
- node = _new_practice(TERM_ID)
28
+ node = _new_practice(TERM_ID, MODEL)
29
29
  node['value'] = [100]
30
30
  node['key'] = linked_node(download_term(KEY_TERM_ID, TermTermType.LANDCOVER))
31
31
  return node
@@ -33,7 +33,7 @@ VALID_SITE_TYPES = [SiteSiteType.PERMANENT_PASTURE.value]
33
33
 
34
34
 
35
35
  def _practice(term_id: str):
36
- practice = _new_practice(term_id)
36
+ practice = _new_practice(term_id, MODEL)
37
37
  practice['value'] = [100]
38
38
  return practice
39
39
 
@@ -3,7 +3,7 @@ from hestia_earth.utils.tools import flatten, non_empty_list
3
3
 
4
4
  from hestia_earth.models.log import logRequirements, logShouldRun
5
5
  from hestia_earth.models.utils.measurement import _new_measurement
6
- from .utils import _slice_by_year
6
+ from .utils import slice_by_year
7
7
  from . import MODEL
8
8
 
9
9
  REQUIREMENTS = {
@@ -26,7 +26,7 @@ MEASUREMENT_ID = 'potentialEvapotranspirationMonthly'
26
26
 
27
27
 
28
28
  def _measurement(value: float, start_date: str, end_date: str):
29
- data = _new_measurement(TERM_ID)
29
+ data = _new_measurement(TERM_ID, MODEL)
30
30
  data['value'] = [value]
31
31
  data['startDate'] = start_date
32
32
  data['endDate'] = end_date
@@ -38,7 +38,7 @@ def _run(measurement: dict):
38
38
  values = measurement.get('value', [])
39
39
  dates = measurement.get('dates', [])
40
40
  term_id = measurement.get('term', {}).get('@id')
41
- results = _slice_by_year(term_id, dates, values)
41
+ results = slice_by_year(term_id, dates, values)
42
42
  return [_measurement(value, start_date, end_date) for (value, start_date, end_date) in results]
43
43
 
44
44
 
@@ -3,7 +3,7 @@ from hestia_earth.utils.tools import flatten, non_empty_list
3
3
 
4
4
  from hestia_earth.models.log import logRequirements, logShouldRun
5
5
  from hestia_earth.models.utils.measurement import _new_measurement
6
- from .utils import _group_by_month
6
+ from .utils import group_by_month
7
7
  from . import MODEL
8
8
 
9
9
  REQUIREMENTS = {
@@ -25,7 +25,7 @@ MEASUREMENT_ID = 'potentialEvapotranspirationDaily'
25
25
 
26
26
 
27
27
  def _measurement(value: list, dates: list):
28
- data = _new_measurement(TERM_ID)
28
+ data = _new_measurement(TERM_ID, MODEL)
29
29
  data['value'] = value
30
30
  data['dates'] = dates
31
31
  data['methodClassification'] = MeasurementMethodClassification.MODELLED_USING_OTHER_MEASUREMENTS.value
@@ -36,7 +36,7 @@ def _run(measurement: dict):
36
36
  values = measurement.get('value', [])
37
37
  dates = measurement.get('dates', [])
38
38
  term_id = measurement.get('term', {}).get('@id')
39
- result = _group_by_month(term_id, dates, values)
39
+ result = group_by_month(term_id, dates, values)
40
40
  return _measurement(result[0], result[1]) if len(result[0]) > 0 else None
41
41
 
42
42
 
@@ -3,7 +3,7 @@ from hestia_earth.utils.tools import flatten, non_empty_list
3
3
 
4
4
  from hestia_earth.models.log import logRequirements, logShouldRun
5
5
  from hestia_earth.models.utils.measurement import _new_measurement
6
- from .utils import _slice_by_year
6
+ from .utils import slice_by_year
7
7
  from . import MODEL
8
8
 
9
9
  REQUIREMENTS = {
@@ -26,7 +26,7 @@ MEASUREMENT_ID = 'precipitationMonthly'
26
26
 
27
27
 
28
28
  def _measurement(value: float, start_date: str, end_date: str):
29
- data = _new_measurement(TERM_ID)
29
+ data = _new_measurement(TERM_ID, MODEL)
30
30
  data['value'] = [value]
31
31
  data['startDate'] = start_date
32
32
  data['endDate'] = end_date
@@ -38,7 +38,7 @@ def _run(measurement: dict):
38
38
  values = measurement.get('value', [])
39
39
  dates = measurement.get('dates', [])
40
40
  term_id = measurement.get('term', {}).get('@id')
41
- results = _slice_by_year(term_id, dates, values)
41
+ results = slice_by_year(term_id, dates, values)
42
42
  return [_measurement(value, start_date, end_date) for (value, start_date, end_date) in results]
43
43
 
44
44
 
@@ -3,7 +3,7 @@ from hestia_earth.utils.tools import flatten, non_empty_list
3
3
 
4
4
  from hestia_earth.models.log import logRequirements, logShouldRun
5
5
  from hestia_earth.models.utils.measurement import _new_measurement
6
- from .utils import _group_by_month
6
+ from .utils import group_by_month
7
7
  from . import MODEL
8
8
 
9
9
  REQUIREMENTS = {
@@ -25,7 +25,7 @@ MEASUREMENT_ID = 'precipitationDaily'
25
25
 
26
26
 
27
27
  def _measurement(value: list, dates: list):
28
- data = _new_measurement(TERM_ID)
28
+ data = _new_measurement(TERM_ID, MODEL)
29
29
  data['value'] = value
30
30
  data['dates'] = dates
31
31
  data['methodClassification'] = MeasurementMethodClassification.MODELLED_USING_OTHER_MEASUREMENTS.value
@@ -36,7 +36,7 @@ def _run(measurement: dict):
36
36
  values = measurement.get('value', [])
37
37
  dates = measurement.get('dates', [])
38
38
  term_id = measurement.get('term', {}).get('@id')
39
- result = _group_by_month(term_id, dates, values)
39
+ result = group_by_month(term_id, dates, values)
40
40
  return _measurement(result[0], result[1]) if len(result[0]) > 0 else None
41
41
 
42
42