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
@@ -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 = 'rainfallMonthly'
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 = 'rainfallDaily'
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
 
@@ -36,7 +36,7 @@ TERM_ID = 'readyToCookWeightPerHead'
36
36
 
37
37
 
38
38
  def _property(value: float):
39
- prop = _new_property(TERM_ID)
39
+ prop = _new_property(TERM_ID, MODEL)
40
40
  prop['value'] = value
41
41
  return prop
42
42
 
@@ -25,7 +25,7 @@ TERM_ID = 'residueBurnt'
25
25
 
26
26
 
27
27
  def _practice(value: float):
28
- practice = _new_practice(TERM_ID)
28
+ practice = _new_practice(TERM_ID, MODEL)
29
29
  practice['value'] = [value]
30
30
  return practice
31
31
 
@@ -35,7 +35,7 @@ TERM_ID = 'residueIncorporated'
35
35
 
36
36
 
37
37
  def _practice(value: float):
38
- practice = _new_practice(TERM_ID)
38
+ practice = _new_practice(TERM_ID, MODEL)
39
39
  practice['value'] = [value]
40
40
  return practice
41
41
 
@@ -25,7 +25,7 @@ TERM_ID = 'residueLeftOnField'
25
25
 
26
26
 
27
27
  def _practice(value: float):
28
- practice = _new_practice(TERM_ID)
28
+ practice = _new_practice(TERM_ID, MODEL)
29
29
  practice['value'] = [value]
30
30
  return practice
31
31
 
@@ -1,5 +1,5 @@
1
1
  from hestia_earth.schema import TermTermType
2
- from hestia_earth.utils.model import filter_list_term_type
2
+ from hestia_earth.utils.model import filter_list_term_type, find_term_match
3
3
  from hestia_earth.utils.tools import list_sum
4
4
 
5
5
  from hestia_earth.models.log import logRequirements, logShouldRun, log_as_table
@@ -11,14 +11,20 @@ from . import MODEL
11
11
  REQUIREMENTS = {
12
12
  "Cycle": {
13
13
  "completeness.cropResidue": "False",
14
- "practices": [{
15
- "@type": "Practice",
16
- "term.@id": [
17
- "residueIncorporated",
18
- "residueIncorporatedLessThan30DaysBeforeCultivation",
19
- "residueIncorporatedMoreThan30DaysBeforeCultivation"
14
+ "or": {
15
+ "practices": [{
16
+ "@type": "Practice",
17
+ "term.@id": [
18
+ "residueIncorporated",
19
+ "residueIncorporatedLessThan30DaysBeforeCultivation",
20
+ "residueIncorporatedMoreThan30DaysBeforeCultivation"
21
+ ]
22
+ }],
23
+ "products": [
24
+ {"@type": "Product", "term.@id": "aboveGroundCropResidueTotal", "value": "> 0"},
25
+ {"@type": "Product", "term.@id": "aboveGroundCropResidueRemoved", "value": "> 0"}
20
26
  ]
21
- }],
27
+ },
22
28
  "none": {
23
29
  "practices": [{
24
30
  "@type": "Practice",
@@ -45,14 +51,57 @@ def _practice(value: float):
45
51
  return practice
46
52
 
47
53
 
48
- def _should_run(cycle: dict):
54
+ def _run_by_products(cycle: dict):
55
+ products = cycle.get('products', [])
56
+ aboveGroundCropResidueTotal = list_sum(find_term_match(products, 'aboveGroundCropResidueTotal').get('value'))
57
+ aboveGroundCropResidueRemoved = list_sum(find_term_match(products, 'aboveGroundCropResidueRemoved').get('value'))
58
+ return [_practice(aboveGroundCropResidueRemoved / aboveGroundCropResidueTotal * 100)]
59
+
60
+
61
+ def _should_run_by_products(cycle: dict):
62
+ crop_residue_incomplete = _is_term_type_incomplete(cycle, TermTermType.CROPRESIDUE)
63
+ products = cycle.get('products', [])
64
+ aboveGroundCropResidueTotal = list_sum(find_term_match(products, 'aboveGroundCropResidueTotal').get('value', [0]))
65
+ has_aboveGroundCropResidueTotal = aboveGroundCropResidueTotal > 0
66
+ aboveGroundCropResidueRemoved = list_sum(
67
+ find_term_match(products, 'aboveGroundCropResidueRemoved').get('value', [0]))
68
+ has_aboveGroundCropResidueRemoved = aboveGroundCropResidueRemoved > 0
69
+
70
+ logRequirements(cycle, model=MODEL, term=TERM_ID,
71
+ term_type_cropResidue_incomplete=crop_residue_incomplete,
72
+ has_aboveGroundCropResidueTotal=has_aboveGroundCropResidueTotal,
73
+ has_aboveGroundCropResidueRemoved=has_aboveGroundCropResidueRemoved)
74
+
75
+ should_run = all([crop_residue_incomplete, has_aboveGroundCropResidueTotal, has_aboveGroundCropResidueRemoved])
76
+ logShouldRun(cycle, MODEL, TERM_ID, should_run)
77
+ return should_run
78
+
79
+
80
+ def _is_incorporated_practice(practice: dict):
81
+ return all([
82
+ practice.get('term', {}).get('@id').startswith('residueIncorporated'),
83
+ practice.get('term', {}).get('termType') == TermTermType.CROPRESIDUEMANAGEMENT.value,
84
+ not is_from_model(practice)
85
+ ])
86
+
87
+
88
+ def _run_by_practices(cycle: dict):
89
+ incorporated_value = list_sum([
90
+ list_sum(p.get('value'))
91
+ for p in cycle.get('practices', [])
92
+ if _is_incorporated_practice(p)
93
+ ])
94
+ return [_practice(100 - (incorporated_value or 0))]
95
+
96
+
97
+ def _should_run_by_practices(cycle: dict):
49
98
  crop_residue_incomplete = _is_term_type_incomplete(cycle, TermTermType.CROPRESIDUE)
50
99
 
51
100
  practices = filter_list_term_type(cycle.get('practices', []), TermTermType.CROPRESIDUEMANAGEMENT)
52
101
  incorporated_practices = [
53
102
  {'id': p.get('term', {}).get('@id'), 'value': list_sum(p.get('value'), None)}
54
103
  for p in practices
55
- if p.get('term', {}).get('@id').startswith('residueIncorporated') and not is_from_model(p)
104
+ if _is_incorporated_practice(p)
56
105
  ]
57
106
  has_other_practices = any([
58
107
  not p.get('term', {}).get('@id').startswith('residueIncorporated')
@@ -68,9 +117,12 @@ def _should_run(cycle: dict):
68
117
 
69
118
  should_run = all([crop_residue_incomplete, incorporated_value, not has_other_practices])
70
119
  logShouldRun(cycle, MODEL, TERM_ID, should_run)
71
- return should_run, 100 - (incorporated_value or 0)
120
+ return should_run
72
121
 
73
122
 
74
123
  def run(cycle: dict):
75
- should_run, value = _should_run(cycle)
76
- return [_practice(value)] if should_run else []
124
+ return (
125
+ _run_by_products(cycle) if _should_run_by_products(cycle) else
126
+ _run_by_practices(cycle) if _should_run_by_practices(cycle) else
127
+ []
128
+ )
@@ -22,7 +22,7 @@ TERM_ID = 'salineWater'
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
@@ -32,7 +32,7 @@ STANDARD_DEPTHS = {(0, 30), (0, 50)}
32
32
 
33
33
 
34
34
  def _measurement(value: float, date: str, term_id: str, standard_fields: dict):
35
- data = _new_measurement(term=term_id)
35
+ data = _new_measurement(term_id, MODEL)
36
36
  data["value"] = [value]
37
37
  data["depthUpper"] = standard_fields["depthUpper"]
38
38
  data["depthLower"] = standard_fields["depthLower"]
@@ -28,7 +28,7 @@ TERM_ID = 'stockingDensityAnimalHousingAverage'
28
28
 
29
29
 
30
30
  def _practice(value: float):
31
- practice = _new_practice(TERM_ID)
31
+ practice = _new_practice(TERM_ID, MODEL)
32
32
  practice['value'] = [round(value, 7)]
33
33
  return practice
34
34
 
@@ -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 = 'temperatureMonthly'
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 = 'temperatureDaily'
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
 
@@ -25,7 +25,7 @@ BIBLIO_TITLE = 'Reducing food’s environmental impacts through producers and co
25
25
 
26
26
 
27
27
  def _measurement(site: dict, value: float):
28
- data = _new_measurement(TERM_ID)
28
+ data = _new_measurement(TERM_ID, MODEL)
29
29
  data['value'] = [value]
30
30
  data['depthUpper'] = 0
31
31
  data['depthLower'] = 50
@@ -28,7 +28,7 @@ TERM_ID = 'unknownPreSeasonWaterRegime'
28
28
 
29
29
 
30
30
  def _practice():
31
- practice = _new_practice(TERM_ID)
31
+ practice = _new_practice(TERM_ID, MODEL)
32
32
  practice['value'] = [100]
33
33
  return practice
34
34
 
@@ -1,6 +1,11 @@
1
+ from functools import reduce
1
2
  from hestia_earth.schema import TermTermType
3
+ from hestia_earth.utils.tools import non_empty_list
4
+ from hestia_earth.utils.date import DAY
2
5
 
6
+ from hestia_earth.models.utils import _omit, first_day_of_month, last_day_of_month
3
7
  from hestia_earth.models.utils.term import get_lookup_value
8
+ from hestia_earth.models.utils.measurement import _new_measurement, measurement_value, has_all_months
4
9
  from . import MODEL
5
10
 
6
11
  IPCC_LAND_USE_CATEGORY_ANNUAL = "Annual crops"
@@ -45,3 +50,91 @@ def crop_ipcc_land_use_category(
45
50
  column='IPCC_LAND_USE_CATEGORY',
46
51
  model=MODEL
47
52
  )
53
+
54
+
55
+ def get_liveAnimal_term_id(product: dict, **log_ars):
56
+ term_id = get_lookup_value(product.get('term', {}), 'liveAnimalTermId', model=MODEL, **log_ars)
57
+ return term_id.split(';')[0] if term_id else None
58
+
59
+
60
+ def _value_func(data: dict, apply_func, key: str = 'value'):
61
+ values = data.get(key, data.get('value', []))
62
+ return list(map(apply_func, values))
63
+
64
+
65
+ def copy_measurement(term_id: str, data: dict):
66
+ measurement = _new_measurement(term_id, MODEL)
67
+ return _omit(data, ['description', 'method']) | measurement
68
+
69
+
70
+ def slice_by_year(term_id: str, dates: list, values: list):
71
+ def group_values(group: dict, index: int):
72
+ try:
73
+ date = dates[index]
74
+ value = values[index]
75
+ month = dates[index][0:4]
76
+ group[month] = group.get(month, []) + [(date, value)]
77
+ except IndexError:
78
+ pass
79
+ return group
80
+
81
+ def iterate_values(data: list):
82
+ return (
83
+ measurement_value({
84
+ 'term': {
85
+ '@id': term_id,
86
+ 'termType': TermTermType.MEASUREMENT.value
87
+ },
88
+ 'value': non_empty_list([v for (_d, v) in data])
89
+ }, is_larger_unit=True),
90
+ data[0][0],
91
+ data[-1][0]
92
+ ) if has_all_months([d for (d, _v) in data]) else None
93
+
94
+ values_by_month = reduce(group_values, range(0, len(dates)), {})
95
+ return non_empty_list(map(iterate_values, values_by_month.values()))
96
+
97
+
98
+ def _extract_year_month(date: str):
99
+ try:
100
+ year = int(date[0:4])
101
+ month = int(date[5:7])
102
+ return year, month
103
+ except Exception:
104
+ return None, None
105
+
106
+
107
+ def group_by_month(term_id: str, dates: list, values: list):
108
+ def group_values(group: dict, index: int):
109
+ date = dates[index]
110
+ value = values[index]
111
+ month = dates[index][0:7]
112
+ group[month] = group.get(month, []) + [(date, value)]
113
+ return group
114
+
115
+ def map_to_month(data: list, year: int, month: int):
116
+ # make sure we got all the necessary days
117
+ difference = last_day_of_month(year, month) - first_day_of_month(year, month)
118
+ days_in_month = round(difference.days + difference.seconds / DAY, 1) + 1
119
+
120
+ return measurement_value({
121
+ 'term': {
122
+ '@id': term_id,
123
+ 'termType': TermTermType.MEASUREMENT.value
124
+ },
125
+ 'value': non_empty_list([v for (_d, v) in data])
126
+ }, is_larger_unit=True) if len(data) == days_in_month else None
127
+
128
+ values_by_month = reduce(group_values, range(0, len(dates)), {}) if len(dates) == len(values) else {}
129
+
130
+ values = []
131
+ dates = []
132
+ for month, data in values_by_month.items():
133
+ year, m = _extract_year_month(data[0][0])
134
+ # date might not contain a year or a month, cannot handle it
135
+ value = map_to_month(data, year, m) if year and m else None
136
+ if value is not None:
137
+ dates.append(month)
138
+ values.append(value)
139
+
140
+ return values, dates
@@ -25,7 +25,7 @@ SITE_TYPE_TO_DEPTH = {
25
25
 
26
26
 
27
27
  def _measurement(site: dict, value: float):
28
- data = _new_measurement(TERM_ID)
28
+ data = _new_measurement(TERM_ID, MODEL)
29
29
  data['value'] = [value]
30
30
  data['methodClassification'] = MeasurementMethodClassification.MODELLED_USING_OTHER_MEASUREMENTS.value
31
31
  return data | get_source(site, BIBLIO_TITLE)
@@ -0,0 +1,78 @@
1
+ from hestia_earth.schema import MeasurementMethodClassification, TermTermType
2
+ from hestia_earth.utils.model import filter_list_term_type
3
+ from hestia_earth.utils.tools import safe_parse_float
4
+
5
+ from hestia_earth.models.log import logRequirements, logShouldRun, log_as_table
6
+ from hestia_earth.models.utils.measurement import _new_measurement
7
+ from hestia_earth.models.utils.site import related_cycles
8
+ from hestia_earth.models.utils.blank_node import get_lookup_value
9
+ from . import MODEL
10
+
11
+ REQUIREMENTS = {
12
+ "Site": {
13
+ "related": {
14
+ "Cycle": {
15
+ "@type": "Cycle",
16
+ "products": [{
17
+ "@type": "Product",
18
+ "primary": "True",
19
+ "term.termType": "liveAquaticSpecies"
20
+ }]
21
+ }
22
+ }
23
+ }
24
+ }
25
+ RETURNS = {
26
+ "Measurement": [{
27
+ "value": "",
28
+ "startDate": "",
29
+ "endDate": "",
30
+ "methodClassification": "expert opinion"
31
+ }]
32
+ }
33
+ LOOKUPS = {
34
+ "liveAquaticSpecies": "defaultSalinity"
35
+ }
36
+ TERM_ID = 'waterSalinity'
37
+
38
+
39
+ def _measurement(value: float, start_date: str = None, end_date: str = None):
40
+ data = _new_measurement(TERM_ID, MODEL)
41
+ data['value'] = [value]
42
+ data['endDate'] = end_date
43
+ if start_date:
44
+ data['startDate'] = start_date
45
+ data['methodClassification'] = MeasurementMethodClassification.EXPERT_OPINION.value
46
+ return data
47
+
48
+
49
+ def _should_run(site: dict):
50
+ cycles = related_cycles(site)
51
+ relevant_products = [
52
+ {
53
+ 'product-id': product.get('term', {}).get('@id'),
54
+ 'lookup-value': safe_parse_float(
55
+ get_lookup_value(product.get('term', {}), LOOKUPS['liveAquaticSpecies']), default=None
56
+ ),
57
+ 'start-date': product.get('startDate') or cycle.get('startDate'),
58
+ 'end-date': product.get('endDate') or cycle.get('endDate')
59
+ }
60
+ for cycle in cycles
61
+ for product in filter_list_term_type(cycle.get('products', []), TermTermType.LIVEAQUATICSPECIES)
62
+ ]
63
+ has_valid_products = any([product.get('lookup-value') for product in relevant_products])
64
+
65
+ logRequirements(site, model=MODEL, term=TERM_ID,
66
+ live_aquatic_products=log_as_table(relevant_products))
67
+
68
+ should_run = all([has_valid_products])
69
+ logShouldRun(site, MODEL, TERM_ID, should_run)
70
+ return should_run, relevant_products
71
+
72
+
73
+ def run(site: dict):
74
+ should_run, values = _should_run(site)
75
+ return [
76
+ _measurement(value.get('lookup-value'), value.get('start-date'), value.get('end-date'))
77
+ for value in values if value.get('lookup-value') is not None
78
+ ] if should_run else []
@@ -568,7 +568,7 @@ def _measurement(
568
568
  "dates": [f"{year}-12-31" for year in timestamps],
569
569
  "methodClassification": _METHOD_CLASSIFICATION
570
570
  }
571
- measurement = _new_measurement(TERM_ID) | {
571
+ measurement = _new_measurement(TERM_ID, MODEL) | {
572
572
  key: value for key, value in update_dict.items() if value
573
573
  }
574
574
  return measurement
@@ -551,7 +551,7 @@ def _measurement(
551
551
  "dates": [f"{year}-12-31" for year in timestamps],
552
552
  "methodClassification": _METHOD_CLASSIFICATION
553
553
  }
554
- measurement = _new_measurement(TERM_ID) | {
554
+ measurement = _new_measurement(TERM_ID, MODEL) | {
555
555
  key: value for key, value in update_dict.items() if value
556
556
  }
557
557
  measurement["depthUpper"] = _DEPTH_UPPER
@@ -1,7 +1,7 @@
1
1
  from enum import Enum
2
2
  from functools import reduce
3
3
  from math import isclose
4
- from numpy import random
4
+ from numpy import inf, random
5
5
  from numpy.typing import NDArray
6
6
  from typing import Callable, Optional, Union
7
7
 
@@ -393,9 +393,7 @@ def sample_plus_minus_error(
393
393
  ) -> NDArray:
394
394
  """Randomly sample a model parameter with a truncated normal distribution described using plus/minus error."""
395
395
  sd = value * (error / 200)
396
- low = value - (value * (error / 100))
397
- high = value + (value * (error / 100))
398
- return truncated_normal_1d(shape=(1, iterations), mu=value, sigma=sd, low=low, high=high, seed=seed)
396
+ return truncated_normal_1d(shape=(1, iterations), mu=value, sigma=sd, low=0, high=inf, seed=seed)
399
397
 
400
398
 
401
399
  def sample_constant(*, iterations: int, value: float, **_) -> NDArray: