hestia-earth-models 0.74.10__py3-none-any.whl → 0.74.12__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of hestia-earth-models might be problematic. Click here for more details.

Files changed (410) hide show
  1. hestia_earth/models/agribalyse2016/fuelElectricity.py +1 -2
  2. hestia_earth/models/agribalyse2016/machineryInfrastructureDepreciatedAmountPerCycle.py +1 -7
  3. hestia_earth/models/akagiEtAl2011/utils.py +2 -6
  4. hestia_earth/models/aware/scarcityWeightedWaterUse.py +1 -4
  5. hestia_earth/models/aware2_0/scarcityWeightedWaterUse.py +1 -4
  6. hestia_earth/models/chaudharyBrooks2018/damageToTerrestrialEcosystemsLandOccupation.py +1 -4
  7. hestia_earth/models/chaudharyBrooks2018/damageToTerrestrialEcosystemsLandTransformation.py +1 -4
  8. hestia_earth/models/chaudharyBrooks2018/damageToTerrestrialEcosystemsTotalLandUseEffects.py +1 -4
  9. hestia_earth/models/cml2001Baseline/abioticResourceDepletionFossilFuels.py +1 -4
  10. hestia_earth/models/cml2001Baseline/abioticResourceDepletionMineralsAndMetals.py +1 -4
  11. hestia_earth/models/cml2001Baseline/eutrophicationPotentialExcludingFate.py +1 -4
  12. hestia_earth/models/cml2001Baseline/resourceUseEnergyDepletionDuringCycle.py +12 -10
  13. hestia_earth/models/cml2001Baseline/resourceUseMineralsAndMetalsDuringCycle.py +5 -5
  14. hestia_earth/models/cml2001Baseline/terrestrialAcidificationPotentialIncludingFateAverageEurope.py +1 -7
  15. hestia_earth/models/cml2001NonBaseline/eutrophicationPotentialIncludingFateAverageEurope.py +1 -7
  16. hestia_earth/models/cml2001NonBaseline/terrestrialAcidificationPotentialExcludingFate.py +1 -7
  17. hestia_earth/models/config/ImpactAssessment.json +12 -6
  18. hestia_earth/models/config/Site.json +16 -0
  19. hestia_earth/models/cycle/aboveGroundCropResidueTotal.py +1 -6
  20. hestia_earth/models/cycle/practice/landCover.py +9 -9
  21. hestia_earth/models/dammgen2009/noxToAirExcreta.py +1 -2
  22. hestia_earth/models/deRuijterEtAl2010/nh3ToAirCropResidueDecomposition.py +1 -2
  23. hestia_earth/models/ecoalimV9/cycle.py +1 -2
  24. hestia_earth/models/ecoalimV9/impact_assessment.py +10 -3
  25. hestia_earth/models/ecoinventV3/cycle.py +1 -2
  26. hestia_earth/models/ecoinventV3AndEmberClimate/cycle.py +1 -2
  27. hestia_earth/models/edip2003/ozoneDepletionPotential.py +1 -7
  28. hestia_earth/models/emepEea2019/utils.py +1 -2
  29. hestia_earth/models/emissionNotRelevant/__init__.py +2 -2
  30. hestia_earth/models/environmentalFootprintV3_1/environmentalFootprintSingleOverallScore.py +1 -4
  31. hestia_earth/models/environmentalFootprintV3_1/freshwaterEcotoxicityPotentialCtue.py +1 -7
  32. hestia_earth/models/environmentalFootprintV3_1/marineEutrophicationPotential.py +1 -7
  33. hestia_earth/models/environmentalFootprintV3_1/photochemicalOzoneCreationPotentialHumanHealthNmvocEq.py +1 -7
  34. hestia_earth/models/environmentalFootprintV3_1/scarcityWeightedWaterUse.py +1 -7
  35. hestia_earth/models/environmentalFootprintV3_1/soilQualityIndexLandOccupation.py +2 -7
  36. hestia_earth/models/environmentalFootprintV3_1/soilQualityIndexLandTransformation.py +2 -7
  37. hestia_earth/models/environmentalFootprintV3_1/soilQualityIndexTotalLandUseEffects.py +2 -7
  38. hestia_earth/models/epa2014/no3ToGroundwaterExcreta.py +1 -2
  39. hestia_earth/models/fantkeEtAl2016/damageToHumanHealthParticulateMatterFormation.py +2 -11
  40. hestia_earth/models/faostat2018/liveweightPerHead.py +11 -7
  41. hestia_earth/models/faostat2018/product/price.py +9 -5
  42. hestia_earth/models/faostat2018/seed.py +5 -12
  43. hestia_earth/models/faostat2018/utils.py +14 -6
  44. hestia_earth/models/frischknechtEtAl2000/ionisingRadiationKbqU235Eq.py +4 -8
  45. hestia_earth/models/geospatialDatabase/altitude.py +1 -2
  46. hestia_earth/models/geospatialDatabase/clayContent.py +1 -2
  47. hestia_earth/models/geospatialDatabase/croppingIntensity.py +1 -3
  48. hestia_earth/models/geospatialDatabase/drainageClass.py +1 -2
  49. hestia_earth/models/geospatialDatabase/ecoClimateZone.py +1 -2
  50. hestia_earth/models/geospatialDatabase/erodibility.py +1 -2
  51. hestia_earth/models/geospatialDatabase/heavyWinterPrecipitation.py +1 -2
  52. hestia_earth/models/geospatialDatabase/histosol.py +1 -2
  53. hestia_earth/models/geospatialDatabase/longFallowRatio.py +1 -3
  54. hestia_earth/models/geospatialDatabase/nutrientLossToAquaticEnvironment.py +1 -2
  55. hestia_earth/models/geospatialDatabase/organicCarbonPerKgSoil.py +1 -2
  56. hestia_earth/models/geospatialDatabase/potentialEvapotranspirationAnnual.py +1 -2
  57. hestia_earth/models/geospatialDatabase/potentialEvapotranspirationLongTermAnnualMean.py +1 -2
  58. hestia_earth/models/geospatialDatabase/potentialEvapotranspirationMonthly.py +1 -2
  59. hestia_earth/models/geospatialDatabase/precipitationAnnual.py +1 -2
  60. hestia_earth/models/geospatialDatabase/precipitationLongTermAnnualMean.py +1 -2
  61. hestia_earth/models/geospatialDatabase/precipitationMonthly.py +1 -2
  62. hestia_earth/models/geospatialDatabase/sandContent.py +1 -2
  63. hestia_earth/models/geospatialDatabase/siltContent.py +1 -2
  64. hestia_earth/models/geospatialDatabase/slope.py +1 -2
  65. hestia_earth/models/geospatialDatabase/slopeLength.py +1 -2
  66. hestia_earth/models/geospatialDatabase/soilPh.py +1 -2
  67. hestia_earth/models/geospatialDatabase/temperatureAnnual.py +1 -2
  68. hestia_earth/models/geospatialDatabase/temperatureLongTermAnnualMean.py +1 -2
  69. hestia_earth/models/geospatialDatabase/temperatureMonthly.py +1 -2
  70. hestia_earth/models/geospatialDatabase/totalNitrogenPerKgSoil.py +1 -2
  71. hestia_earth/models/geospatialDatabase/totalPhosphorusPerKgSoil.py +1 -2
  72. hestia_earth/models/geospatialDatabase/waterDepth.py +1 -2
  73. hestia_earth/models/hestia/aboveGroundCropResidue.py +1 -2
  74. hestia_earth/models/hestia/aboveGroundCropResidueTotal.py +1 -6
  75. hestia_earth/models/hestia/brackishWater.py +1 -2
  76. hestia_earth/models/hestia/cationExchangeCapacityPerKgSoil.py +1 -2
  77. hestia_earth/models/hestia/cropResidueManagement.py +1 -2
  78. hestia_earth/models/hestia/croppingIntensity.py +1 -7
  79. hestia_earth/models/hestia/default_emissions.py +3 -5
  80. hestia_earth/models/hestia/default_resourceUse.py +4 -11
  81. hestia_earth/models/hestia/excretaKgMass.py +9 -6
  82. hestia_earth/models/hestia/excretaKgN.py +8 -7
  83. hestia_earth/models/hestia/excretaKgVs.py +8 -7
  84. hestia_earth/models/hestia/feedConversionRatio/__init__.py +5 -7
  85. hestia_earth/models/hestia/flowingWater.py +1 -2
  86. hestia_earth/models/hestia/freshWater.py +1 -2
  87. hestia_earth/models/hestia/histosol.py +1 -2
  88. hestia_earth/models/hestia/inorganicFertiliser.py +2 -14
  89. hestia_earth/models/hestia/irrigatedTypeUnspecified.py +1 -7
  90. hestia_earth/models/hestia/landCover.py +192 -911
  91. hestia_earth/models/hestia/landCover_utils.py +769 -0
  92. hestia_earth/models/hestia/landOccupationDuringCycle.py +1 -2
  93. hestia_earth/models/hestia/liveAnimal.py +1 -3
  94. hestia_earth/models/hestia/longFallowRatio.py +1 -7
  95. hestia_earth/models/hestia/management.py +14 -8
  96. hestia_earth/models/hestia/materialAndSubstrate.py +1 -2
  97. hestia_earth/models/hestia/milkYield.py +2 -12
  98. hestia_earth/models/hestia/netPrimaryProduction.py +1 -2
  99. hestia_earth/models/hestia/organicCarbonPerHa.py +1 -2
  100. hestia_earth/models/hestia/pToSurfaceWaterAquacultureSystems.py +2 -4
  101. hestia_earth/models/hestia/pastureGrass.py +3 -4
  102. hestia_earth/models/hestia/pastureSystem.py +1 -7
  103. hestia_earth/models/hestia/potentialEvapotranspirationAnnual.py +1 -2
  104. hestia_earth/models/hestia/potentialEvapotranspirationMonthly.py +1 -2
  105. hestia_earth/models/hestia/precipitationAnnual.py +1 -2
  106. hestia_earth/models/hestia/precipitationMonthly.py +1 -2
  107. hestia_earth/models/hestia/rainfallAnnual.py +1 -2
  108. hestia_earth/models/hestia/rainfallMonthly.py +1 -2
  109. hestia_earth/models/hestia/residueBurnt.py +1 -7
  110. hestia_earth/models/hestia/residueIncorporated.py +1 -7
  111. hestia_earth/models/hestia/residueLeftOnField.py +1 -7
  112. hestia_earth/models/hestia/residueRemoved.py +3 -8
  113. hestia_earth/models/hestia/resourceUse_utils.py +4 -20
  114. hestia_earth/models/hestia/salineWater.py +1 -2
  115. hestia_earth/models/hestia/seed_emissions.py +5 -6
  116. hestia_earth/models/hestia/slope.py +44 -0
  117. hestia_earth/models/hestia/slopeLength.py +44 -0
  118. hestia_earth/models/hestia/soilMeasurement.py +1 -2
  119. hestia_earth/models/hestia/stockingDensityAnimalHousingAverage.py +1 -7
  120. hestia_earth/models/hestia/temperatureAnnual.py +1 -2
  121. hestia_earth/models/hestia/temperatureMonthly.py +1 -2
  122. hestia_earth/models/hestia/totalNitrogenPerKgSoil.py +1 -2
  123. hestia_earth/models/hestia/unknownPreSeasonWaterRegime.py +1 -7
  124. hestia_earth/models/hestia/utils.py +5 -5
  125. hestia_earth/models/hestia/waterDepth.py +1 -2
  126. hestia_earth/models/hestia/waterSalinity.py +1 -2
  127. hestia_earth/models/impact_assessment/emissions.py +8 -9
  128. hestia_earth/models/impact_assessment/post_checks/cycle.py +1 -1
  129. hestia_earth/models/impact_assessment/pre_checks/cycle.py +1 -1
  130. hestia_earth/models/ipcc2006/aboveGroundCropResidueRemoved.py +1 -3
  131. hestia_earth/models/ipcc2006/aboveGroundCropResidueTotal.py +1 -3
  132. hestia_earth/models/ipcc2006/belowGroundCropResidue.py +1 -3
  133. hestia_earth/models/ipcc2006/n2OToAirCropResidueDecompositionDirect.py +2 -6
  134. hestia_earth/models/ipcc2006/n2OToAirCropResidueDecompositionIndirect.py +1 -2
  135. hestia_earth/models/ipcc2006/n2OToAirExcretaDirect.py +1 -2
  136. hestia_earth/models/ipcc2006/n2OToAirExcretaIndirect.py +1 -2
  137. hestia_earth/models/ipcc2006/n2OToAirInorganicFertiliserDirect.py +1 -2
  138. hestia_earth/models/ipcc2006/n2OToAirInorganicFertiliserIndirect.py +1 -2
  139. hestia_earth/models/ipcc2006/n2OToAirOrganicFertiliserDirect.py +1 -2
  140. hestia_earth/models/ipcc2006/n2OToAirOrganicFertiliserIndirect.py +1 -2
  141. hestia_earth/models/ipcc2013ExcludingFeedbacks/gwp100.py +1 -7
  142. hestia_earth/models/ipcc2013IncludingFeedbacks/gwp100.py +1 -7
  143. hestia_earth/models/ipcc2019/aboveGroundBiomass.py +1 -1
  144. hestia_earth/models/ipcc2019/aboveGroundCropResidueTotal.py +1 -3
  145. hestia_earth/models/ipcc2019/animal/milkYieldPerAnimal.py +3 -7
  146. hestia_earth/models/ipcc2019/animal/pastureGrass.py +1 -2
  147. hestia_earth/models/ipcc2019/belowGroundBiomass.py +1 -1
  148. hestia_earth/models/ipcc2019/belowGroundCropResidue.py +1 -3
  149. hestia_earth/models/ipcc2019/biocharOrganicCarbonPerHa.py +1 -1
  150. hestia_earth/models/ipcc2019/ch4ToAirAquacultureSystems.py +2 -6
  151. hestia_earth/models/ipcc2019/ch4ToAirEntericFermentation.py +2 -12
  152. hestia_earth/models/ipcc2019/ch4ToAirExcreta.py +1 -2
  153. hestia_earth/models/ipcc2019/ch4ToAirFloodedRice.py +2 -10
  154. hestia_earth/models/ipcc2019/ch4ToAirOrganicSoilCultivation.py +1 -1
  155. hestia_earth/models/ipcc2019/co2ToAirAboveGroundBiomassStockChange.py +1 -1
  156. hestia_earth/models/ipcc2019/co2ToAirBelowGroundBiomassStockChange.py +1 -1
  157. hestia_earth/models/ipcc2019/co2ToAirBiocharStockChange.py +1 -1
  158. hestia_earth/models/ipcc2019/co2ToAirLimeHydrolysis.py +1 -2
  159. hestia_earth/models/ipcc2019/co2ToAirOrganicSoilCultivation.py +1 -1
  160. hestia_earth/models/ipcc2019/co2ToAirSoilOrganicCarbonStockChange.py +1 -1
  161. hestia_earth/models/ipcc2019/co2ToAirUreaHydrolysis.py +1 -2
  162. hestia_earth/models/ipcc2019/croppingDuration.py +1 -2
  163. hestia_earth/models/ipcc2019/n2OToAirCropResidueBurningDirect.py +1 -2
  164. hestia_earth/models/ipcc2019/n2OToAirCropResidueDecompositionDirect.py +2 -7
  165. hestia_earth/models/ipcc2019/n2OToAirExcretaDirect.py +1 -2
  166. hestia_earth/models/ipcc2019/n2OToAirInorganicFertiliserDirect.py +2 -7
  167. hestia_earth/models/ipcc2019/n2OToAirOrganicFertiliserDirect.py +2 -7
  168. hestia_earth/models/ipcc2019/n2OToAirOrganicSoilCultivationDirect.py +2 -7
  169. hestia_earth/models/ipcc2019/n2OToAir_indirect_emissions_utils.py +3 -9
  170. hestia_earth/models/ipcc2019/nh3ToAirInorganicFertiliser.py +2 -6
  171. hestia_earth/models/ipcc2019/nh3ToAirOrganicFertiliser.py +2 -6
  172. hestia_earth/models/ipcc2019/no3ToGroundwaterCropResidueDecomposition.py +2 -7
  173. hestia_earth/models/ipcc2019/no3ToGroundwaterExcreta.py +2 -8
  174. hestia_earth/models/ipcc2019/no3ToGroundwaterInorganicFertiliser.py +2 -7
  175. hestia_earth/models/ipcc2019/no3ToGroundwaterOrganicFertiliser.py +2 -7
  176. hestia_earth/models/ipcc2019/nonCo2EmissionsToAirNaturalVegetationBurning.py +1 -1
  177. hestia_earth/models/ipcc2019/noxToAirInorganicFertiliser.py +2 -6
  178. hestia_earth/models/ipcc2019/noxToAirOrganicFertiliser.py +2 -6
  179. hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_1.py +1 -1
  180. hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_2.py +1 -1
  181. hestia_earth/models/ipcc2019/pastureGrass.py +1 -2
  182. hestia_earth/models/ipcc2021/gwp100.py +2 -11
  183. hestia_earth/models/jarvisAndPain1994/n2ToAirExcreta.py +1 -2
  184. hestia_earth/models/koble2014/utils.py +1 -3
  185. hestia_earth/models/lcImpactAllEffects100Years/damageToFreshwaterEcosystemsClimateChange.py +1 -7
  186. hestia_earth/models/lcImpactAllEffects100Years/damageToFreshwaterEcosystemsFreshwaterEcotoxicity.py +1 -7
  187. hestia_earth/models/lcImpactAllEffects100Years/damageToFreshwaterEcosystemsFreshwaterEutrophication.py +1 -7
  188. hestia_earth/models/lcImpactAllEffects100Years/damageToFreshwaterEcosystemsPdfYear.py +1 -7
  189. hestia_earth/models/lcImpactAllEffects100Years/damageToFreshwaterEcosystemsWaterStress.py +1 -7
  190. hestia_earth/models/lcImpactAllEffects100Years/damageToHumanHealth.py +1 -7
  191. hestia_earth/models/lcImpactAllEffects100Years/damageToHumanHealthClimateChange.py +1 -7
  192. hestia_earth/models/lcImpactAllEffects100Years/damageToHumanHealthHumanToxicityCancerogenic.py +1 -7
  193. hestia_earth/models/lcImpactAllEffects100Years/damageToHumanHealthHumanToxicityNonCancerogenic.py +1 -7
  194. hestia_earth/models/lcImpactAllEffects100Years/damageToHumanHealthParticulateMatterFormation.py +1 -7
  195. hestia_earth/models/lcImpactAllEffects100Years/damageToHumanHealthPhotochemicalOzoneFormation.py +1 -7
  196. hestia_earth/models/lcImpactAllEffects100Years/damageToHumanHealthStratosphericOzoneDepletion.py +1 -7
  197. hestia_earth/models/lcImpactAllEffects100Years/damageToHumanHealthWaterStress.py +1 -7
  198. hestia_earth/models/lcImpactAllEffects100Years/damageToMarineEcosystemsMarineEcotoxicity.py +1 -7
  199. hestia_earth/models/lcImpactAllEffects100Years/damageToMarineEcosystemsMarineEutrophication.py +1 -7
  200. hestia_earth/models/lcImpactAllEffects100Years/damageToMarineEcosystemsPdfYear.py +1 -7
  201. hestia_earth/models/lcImpactAllEffects100Years/damageToTerrestrialEcosystemsClimateChange.py +1 -7
  202. hestia_earth/models/lcImpactAllEffects100Years/damageToTerrestrialEcosystemsPdfYear.py +1 -7
  203. hestia_earth/models/lcImpactAllEffects100Years/damageToTerrestrialEcosystemsPhotochemicalOzoneFormation.py +1 -7
  204. hestia_earth/models/lcImpactAllEffects100Years/damageToTerrestrialEcosystemsTerrestrialAcidification.py +1 -7
  205. hestia_earth/models/lcImpactAllEffects100Years/damageToTerrestrialEcosystemsTerrestrialEcotoxicity.py +1 -7
  206. hestia_earth/models/lcImpactAllEffectsInfinite/damageToFreshwaterEcosystemsClimateChange.py +1 -7
  207. hestia_earth/models/lcImpactAllEffectsInfinite/damageToFreshwaterEcosystemsFreshwaterEcotoxicity.py +1 -7
  208. hestia_earth/models/lcImpactAllEffectsInfinite/damageToFreshwaterEcosystemsFreshwaterEutrophication.py +1 -7
  209. hestia_earth/models/lcImpactAllEffectsInfinite/damageToFreshwaterEcosystemsPdfYear.py +1 -7
  210. hestia_earth/models/lcImpactAllEffectsInfinite/damageToFreshwaterEcosystemsWaterStress.py +1 -7
  211. hestia_earth/models/lcImpactAllEffectsInfinite/damageToHumanHealth.py +1 -7
  212. hestia_earth/models/lcImpactAllEffectsInfinite/damageToHumanHealthClimateChange.py +1 -7
  213. hestia_earth/models/lcImpactAllEffectsInfinite/damageToHumanHealthHumanToxicityCancerogenic.py +1 -7
  214. hestia_earth/models/lcImpactAllEffectsInfinite/damageToHumanHealthHumanToxicityNonCancerogenic.py +1 -7
  215. hestia_earth/models/lcImpactAllEffectsInfinite/damageToHumanHealthParticulateMatterFormation.py +1 -7
  216. hestia_earth/models/lcImpactAllEffectsInfinite/damageToHumanHealthPhotochemicalOzoneFormation.py +1 -7
  217. hestia_earth/models/lcImpactAllEffectsInfinite/damageToHumanHealthStratosphericOzoneDepletion.py +1 -7
  218. hestia_earth/models/lcImpactAllEffectsInfinite/damageToHumanHealthWaterStress.py +1 -7
  219. hestia_earth/models/lcImpactAllEffectsInfinite/damageToMarineEcosystemsMarineEcotoxicity.py +1 -7
  220. hestia_earth/models/lcImpactAllEffectsInfinite/damageToMarineEcosystemsMarineEutrophication.py +1 -7
  221. hestia_earth/models/lcImpactAllEffectsInfinite/damageToMarineEcosystemsPdfYear.py +1 -7
  222. hestia_earth/models/lcImpactAllEffectsInfinite/damageToTerrestrialEcosystemsClimateChange.py +1 -7
  223. hestia_earth/models/lcImpactAllEffectsInfinite/damageToTerrestrialEcosystemsPdfYear.py +1 -7
  224. hestia_earth/models/lcImpactAllEffectsInfinite/damageToTerrestrialEcosystemsPhotochemicalOzoneFormation.py +1 -7
  225. hestia_earth/models/lcImpactAllEffectsInfinite/damageToTerrestrialEcosystemsTerrestrialAcidification.py +1 -7
  226. hestia_earth/models/lcImpactAllEffectsInfinite/damageToTerrestrialEcosystemsTerrestrialEcotoxicity.py +1 -7
  227. hestia_earth/models/lcImpactCertainEffects100Years/damageToFreshwaterEcosystemsFreshwaterEcotoxicity.py +1 -7
  228. hestia_earth/models/lcImpactCertainEffects100Years/damageToFreshwaterEcosystemsFreshwaterEutrophication.py +1 -7
  229. hestia_earth/models/lcImpactCertainEffects100Years/damageToFreshwaterEcosystemsPdfYear.py +1 -7
  230. hestia_earth/models/lcImpactCertainEffects100Years/damageToFreshwaterEcosystemsWaterStress.py +1 -7
  231. hestia_earth/models/lcImpactCertainEffects100Years/damageToHumanHealth.py +1 -7
  232. hestia_earth/models/lcImpactCertainEffects100Years/damageToHumanHealthClimateChange.py +1 -7
  233. hestia_earth/models/lcImpactCertainEffects100Years/damageToHumanHealthHumanToxicityCancerogenic.py +1 -7
  234. hestia_earth/models/lcImpactCertainEffects100Years/damageToHumanHealthHumanToxicityNonCancerogenic.py +1 -7
  235. hestia_earth/models/lcImpactCertainEffects100Years/damageToHumanHealthParticulateMatterFormation.py +1 -7
  236. hestia_earth/models/lcImpactCertainEffects100Years/damageToHumanHealthPhotochemicalOzoneFormation.py +1 -7
  237. hestia_earth/models/lcImpactCertainEffects100Years/damageToHumanHealthStratosphericOzoneDepletion.py +1 -7
  238. hestia_earth/models/lcImpactCertainEffects100Years/damageToHumanHealthWaterStress.py +1 -7
  239. hestia_earth/models/lcImpactCertainEffects100Years/damageToMarineEcosystemsMarineEcotoxicity.py +1 -7
  240. hestia_earth/models/lcImpactCertainEffects100Years/damageToMarineEcosystemsMarineEutrophication.py +1 -7
  241. hestia_earth/models/lcImpactCertainEffects100Years/damageToMarineEcosystemsPdfYear.py +1 -7
  242. hestia_earth/models/lcImpactCertainEffects100Years/damageToTerrestrialEcosystemsClimateChange.py +1 -7
  243. hestia_earth/models/lcImpactCertainEffects100Years/damageToTerrestrialEcosystemsPdfYear.py +1 -7
  244. hestia_earth/models/lcImpactCertainEffects100Years/damageToTerrestrialEcosystemsPhotochemicalOzoneFormation.py +1 -7
  245. hestia_earth/models/lcImpactCertainEffects100Years/damageToTerrestrialEcosystemsTerrestrialAcidification.py +1 -7
  246. hestia_earth/models/lcImpactCertainEffects100Years/damageToTerrestrialEcosystemsTerrestrialEcotoxicity.py +1 -7
  247. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToFreshwaterEcosystemsFreshwaterEcotoxicity.py +1 -7
  248. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToFreshwaterEcosystemsFreshwaterEutrophication.py +1 -7
  249. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToFreshwaterEcosystemsPdfYear.py +1 -7
  250. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToFreshwaterEcosystemsWaterStress.py +1 -7
  251. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToHumanHealth.py +1 -7
  252. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToHumanHealthClimateChange.py +1 -7
  253. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToHumanHealthHumanToxicityCancerogenic.py +1 -7
  254. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToHumanHealthHumanToxicityNonCancerogenic.py +1 -7
  255. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToHumanHealthParticulateMatterFormation.py +1 -7
  256. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToHumanHealthPhotochemicalOzoneFormation.py +1 -7
  257. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToHumanHealthStratosphericOzoneDepletion.py +1 -7
  258. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToHumanHealthWaterStress.py +1 -7
  259. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToMarineEcosystemsMarineEcotoxicity.py +1 -7
  260. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToMarineEcosystemsMarineEutrophication.py +1 -7
  261. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToMarineEcosystemsPdfYear.py +1 -7
  262. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToTerrestrialEcosystemsClimateChange.py +1 -7
  263. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToTerrestrialEcosystemsPdfYear.py +1 -7
  264. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToTerrestrialEcosystemsPhotochemicalOzoneFormation.py +1 -7
  265. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToTerrestrialEcosystemsTerrestrialAcidification.py +1 -7
  266. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToTerrestrialEcosystemsTerrestrialEcotoxicity.py +1 -7
  267. hestia_earth/models/linkedImpactAssessment/emissions.py +4 -6
  268. hestia_earth/models/linkedImpactAssessment/utils.py +4 -6
  269. hestia_earth/models/mocking/search-results.json +1 -1
  270. hestia_earth/models/pooreNemecek2018/aboveGroundCropResidueTotal.py +1 -3
  271. hestia_earth/models/pooreNemecek2018/belowGroundCropResidue.py +1 -3
  272. hestia_earth/models/pooreNemecek2018/ch4ToAirAquacultureSystems.py +1 -2
  273. hestia_earth/models/pooreNemecek2018/excretaKgN.py +3 -4
  274. hestia_earth/models/pooreNemecek2018/excretaKgVs.py +4 -4
  275. hestia_earth/models/pooreNemecek2018/freshwaterWithdrawalsDuringCycle.py +3 -9
  276. hestia_earth/models/pooreNemecek2018/landOccupationDuringCycle.py +3 -7
  277. hestia_earth/models/pooreNemecek2018/longFallowDuration.py +1 -7
  278. hestia_earth/models/pooreNemecek2018/n2OToAirAquacultureSystemsDirect.py +1 -2
  279. hestia_earth/models/pooreNemecek2018/n2ToAirAquacultureSystems.py +1 -2
  280. hestia_earth/models/pooreNemecek2018/nh3ToAirAquacultureSystems.py +1 -2
  281. hestia_earth/models/pooreNemecek2018/no3ToGroundwaterCropResidueDecomposition.py +1 -2
  282. hestia_earth/models/pooreNemecek2018/no3ToGroundwaterExcreta.py +1 -2
  283. hestia_earth/models/pooreNemecek2018/no3ToGroundwaterInorganicFertiliser.py +1 -2
  284. hestia_earth/models/pooreNemecek2018/no3ToGroundwaterOrganicFertiliser.py +1 -2
  285. hestia_earth/models/pooreNemecek2018/no3ToGroundwaterSoilFlux_utils.py +1 -2
  286. hestia_earth/models/pooreNemecek2018/noxToAirAquacultureSystems.py +1 -2
  287. hestia_earth/models/pooreNemecek2018/nurseryDensity.py +1 -7
  288. hestia_earth/models/pooreNemecek2018/nurseryDuration.py +1 -7
  289. hestia_earth/models/pooreNemecek2018/plantationDensity.py +1 -7
  290. hestia_earth/models/pooreNemecek2018/plantationLifespan.py +1 -7
  291. hestia_earth/models/pooreNemecek2018/plantationProductiveLifespan.py +1 -7
  292. hestia_earth/models/pooreNemecek2018/rotationDuration.py +1 -7
  293. hestia_earth/models/pooreNemecek2018/saplingsDepreciatedAmountPerCycle.py +1 -7
  294. hestia_earth/models/poschEtAl2008/terrestrialAcidificationPotentialAccumulatedExceedance.py +1 -7
  295. hestia_earth/models/poschEtAl2008/terrestrialEutrophicationPotentialAccumulatedExceedance.py +1 -7
  296. hestia_earth/models/recipe2016Egalitarian/damageToFreshwaterEcosystemsSpeciesYear.py +1 -7
  297. hestia_earth/models/recipe2016Egalitarian/damageToHumanHealth.py +1 -7
  298. hestia_earth/models/recipe2016Egalitarian/damageToMarineEcosystemsSpeciesYear.py +1 -7
  299. hestia_earth/models/recipe2016Egalitarian/damageToResourceAvailability.py +1 -7
  300. hestia_earth/models/recipe2016Egalitarian/damageToTerrestrialEcosystemsSpeciesYear.py +1 -7
  301. hestia_earth/models/recipe2016Egalitarian/ecosystemDamageOzoneFormation.py +1 -7
  302. hestia_earth/models/recipe2016Egalitarian/fossilResourceScarcity.py +1 -7
  303. hestia_earth/models/recipe2016Egalitarian/freshwaterAquaticEcotoxicityPotential14Dcbeq.py +1 -7
  304. hestia_earth/models/recipe2016Egalitarian/freshwaterEutrophicationPotential.py +1 -7
  305. hestia_earth/models/recipe2016Egalitarian/humanCarcinogenicToxicity.py +1 -7
  306. hestia_earth/models/recipe2016Egalitarian/humanDamageOzoneFormation.py +2 -10
  307. hestia_earth/models/recipe2016Egalitarian/humanNonCarcinogenicToxicity.py +1 -7
  308. hestia_earth/models/recipe2016Egalitarian/marineAquaticEcotoxicityPotential14Dcbeq.py +1 -7
  309. hestia_earth/models/recipe2016Egalitarian/marineEutrophicationPotential.py +1 -7
  310. hestia_earth/models/recipe2016Egalitarian/ozoneDepletionPotential.py +1 -7
  311. hestia_earth/models/recipe2016Egalitarian/terrestrialAcidificationPotential.py +1 -7
  312. hestia_earth/models/recipe2016Egalitarian/terrestrialEcotoxicityPotential14Dcbeq.py +1 -7
  313. hestia_earth/models/recipe2016Hierarchist/damageToFreshwaterEcosystemsSpeciesYear.py +1 -7
  314. hestia_earth/models/recipe2016Hierarchist/damageToHumanHealth.py +1 -7
  315. hestia_earth/models/recipe2016Hierarchist/damageToMarineEcosystemsSpeciesYear.py +1 -7
  316. hestia_earth/models/recipe2016Hierarchist/damageToResourceAvailability.py +1 -7
  317. hestia_earth/models/recipe2016Hierarchist/damageToTerrestrialEcosystemsSpeciesYear.py +1 -7
  318. hestia_earth/models/recipe2016Hierarchist/ecosystemDamageOzoneFormation.py +2 -10
  319. hestia_earth/models/recipe2016Hierarchist/fossilResourceScarcity.py +1 -7
  320. hestia_earth/models/recipe2016Hierarchist/freshwaterAquaticEcotoxicityPotential14Dcbeq.py +1 -7
  321. hestia_earth/models/recipe2016Hierarchist/freshwaterEutrophicationPotential.py +1 -7
  322. hestia_earth/models/recipe2016Hierarchist/humanCarcinogenicToxicity.py +1 -7
  323. hestia_earth/models/recipe2016Hierarchist/humanDamageOzoneFormation.py +2 -10
  324. hestia_earth/models/recipe2016Hierarchist/humanNonCarcinogenicToxicity.py +1 -7
  325. hestia_earth/models/recipe2016Hierarchist/marineAquaticEcotoxicityPotential14Dcbeq.py +1 -7
  326. hestia_earth/models/recipe2016Hierarchist/marineEutrophicationPotential.py +1 -7
  327. hestia_earth/models/recipe2016Hierarchist/ozoneDepletionPotential.py +1 -7
  328. hestia_earth/models/recipe2016Hierarchist/terrestrialAcidificationPotential.py +1 -7
  329. hestia_earth/models/recipe2016Hierarchist/terrestrialEcotoxicityPotential14Dcbeq.py +1 -7
  330. hestia_earth/models/recipe2016Individualist/damageToFreshwaterEcosystemsSpeciesYear.py +1 -7
  331. hestia_earth/models/recipe2016Individualist/damageToHumanHealth.py +1 -7
  332. hestia_earth/models/recipe2016Individualist/damageToMarineEcosystemsSpeciesYear.py +1 -7
  333. hestia_earth/models/recipe2016Individualist/damageToResourceAvailability.py +1 -7
  334. hestia_earth/models/recipe2016Individualist/damageToTerrestrialEcosystemsSpeciesYear.py +1 -7
  335. hestia_earth/models/recipe2016Individualist/ecosystemDamageOzoneFormation.py +2 -10
  336. hestia_earth/models/recipe2016Individualist/fossilResourceScarcity.py +1 -7
  337. hestia_earth/models/recipe2016Individualist/freshwaterAquaticEcotoxicityPotential14Dcbeq.py +1 -7
  338. hestia_earth/models/recipe2016Individualist/freshwaterEutrophicationPotential.py +1 -7
  339. hestia_earth/models/recipe2016Individualist/humanCarcinogenicToxicity.py +1 -7
  340. hestia_earth/models/recipe2016Individualist/humanDamageOzoneFormation.py +2 -10
  341. hestia_earth/models/recipe2016Individualist/humanNonCarcinogenicToxicity.py +1 -7
  342. hestia_earth/models/recipe2016Individualist/marineAquaticEcotoxicityPotential14Dcbeq.py +1 -7
  343. hestia_earth/models/recipe2016Individualist/marineEutrophicationPotential.py +1 -7
  344. hestia_earth/models/recipe2016Individualist/ozoneDepletionPotential.py +1 -7
  345. hestia_earth/models/recipe2016Individualist/terrestrialAcidificationPotential.py +1 -7
  346. hestia_earth/models/recipe2016Individualist/terrestrialEcotoxicityPotential14Dcbeq.py +1 -7
  347. hestia_earth/models/resourceUseNotRelevant/__init__.py +2 -8
  348. hestia_earth/models/schererPfister2015/nErosionSoilFlux.py +1 -2
  349. hestia_earth/models/schererPfister2015/pErosionSoilFlux.py +1 -2
  350. hestia_earth/models/schererPfister2015/pToDrainageWaterSoilFlux.py +1 -2
  351. hestia_earth/models/schererPfister2015/pToGroundwaterSoilFlux.py +1 -2
  352. hestia_earth/models/schererPfister2015/pToSurfaceWaterSoilFlux.py +1 -2
  353. hestia_earth/models/schmidt2007/ch4ToAirWasteTreatment.py +1 -2
  354. hestia_earth/models/schmidt2007/h2SToAirWasteTreatment.py +1 -2
  355. hestia_earth/models/schmidt2007/n2OToAirWasteTreatmentDirect.py +1 -2
  356. hestia_earth/models/schmidt2007/nh3ToAirWasteTreatment.py +1 -2
  357. hestia_earth/models/site/grouped_measurement.py +2 -3
  358. hestia_earth/models/stehfestBouwman2006/n2OToAirCropResidueDecompositionDirect.py +1 -2
  359. hestia_earth/models/stehfestBouwman2006/n2OToAirExcretaDirect.py +1 -2
  360. hestia_earth/models/stehfestBouwman2006/n2OToAirInorganicFertiliserDirect.py +1 -2
  361. hestia_earth/models/stehfestBouwman2006/n2OToAirOrganicFertiliserDirect.py +1 -2
  362. hestia_earth/models/stehfestBouwman2006/n2OToAirSoilFlux_utils.py +1 -2
  363. hestia_earth/models/stehfestBouwman2006/noxToAirCropResidueDecomposition.py +1 -2
  364. hestia_earth/models/stehfestBouwman2006/noxToAirExcreta.py +1 -2
  365. hestia_earth/models/stehfestBouwman2006/noxToAirInorganicFertiliser.py +1 -2
  366. hestia_earth/models/stehfestBouwman2006/noxToAirOrganicFertiliser.py +1 -2
  367. hestia_earth/models/stehfestBouwman2006/noxToAirSoilFlux_utils.py +1 -2
  368. hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirCropResidueDecomposition.py +1 -2
  369. hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirExcreta.py +1 -2
  370. hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirInorganicFertiliser.py +1 -2
  371. hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirOrganicFertiliser.py +1 -2
  372. hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirSoilFlux_utils.py +1 -2
  373. hestia_earth/models/transformation/input/excreta.py +7 -5
  374. hestia_earth/models/transformation/product/excreta.py +4 -4
  375. hestia_earth/models/usetoxV2/freshwaterEcotoxicityPotentialCtue.py +1 -7
  376. hestia_earth/models/utils/__init__.py +26 -7
  377. hestia_earth/models/utils/background_emissions.py +3 -3
  378. hestia_earth/models/utils/blank_node.py +31 -12
  379. hestia_earth/models/utils/emission.py +24 -10
  380. hestia_earth/models/utils/indicator.py +28 -13
  381. hestia_earth/models/utils/input.py +22 -5
  382. hestia_earth/models/utils/management.py +18 -4
  383. hestia_earth/models/utils/measurement.py +14 -6
  384. hestia_earth/models/utils/practice.py +24 -4
  385. hestia_earth/models/utils/product.py +32 -14
  386. hestia_earth/models/version.py +1 -1
  387. hestia_earth/models/webbEtAl2012AndSintermannEtAl2012/nh3ToAirOrganicFertiliser.py +1 -2
  388. hestia_earth/orchestrator/models/__init__.py +22 -11
  389. {hestia_earth_models-0.74.10.dist-info → hestia_earth_models-0.74.12.dist-info}/METADATA +2 -2
  390. {hestia_earth_models-0.74.10.dist-info → hestia_earth_models-0.74.12.dist-info}/RECORD +410 -404
  391. tests/models/cml2001Baseline/test_abioticResourceDepletionFossilFuels.py +4 -9
  392. tests/models/cml2001Baseline/test_abioticResourceDepletionMineralsAndMetals.py +4 -9
  393. tests/models/environmentalFootprintV3_1/test_environmentalFootprintSingleOverallScore.py +4 -9
  394. tests/models/environmentalFootprintV3_1/test_marineEutrophicationPotential.py +1 -7
  395. tests/models/environmentalFootprintV3_1/test_scarcityWeightedWaterUse.py +2 -8
  396. tests/models/environmentalFootprintV3_1/test_soilQualityIndexLandTransformation.py +3 -13
  397. tests/models/hestia/test_default_emissions.py +2 -2
  398. tests/models/hestia/test_default_resourceUse.py +3 -3
  399. tests/models/hestia/test_landCover.py +42 -295
  400. tests/models/hestia/test_landCover_utils.py +233 -0
  401. tests/models/hestia/test_slope.py +23 -0
  402. tests/models/hestia/test_slopeLength.py +23 -0
  403. tests/models/ipcc2019/test_no3ToGroundwaterExcreta.py +1 -0
  404. tests/models/poschEtAl2008/test_terrestrialAcidificationPotentialAccumulatedExceedance.py +4 -9
  405. tests/models/poschEtAl2008/test_terrestrialEutrophicationPotentialAccumulatedExceedance.py +4 -9
  406. tests/models/utils/test_indicator.py +6 -4
  407. tests/models/utils/test_measurement.py +7 -5
  408. {hestia_earth_models-0.74.10.dist-info → hestia_earth_models-0.74.12.dist-info}/LICENSE +0 -0
  409. {hestia_earth_models-0.74.10.dist-info → hestia_earth_models-0.74.12.dist-info}/WHEEL +0 -0
  410. {hestia_earth_models-0.74.10.dist-info → hestia_earth_models-0.74.12.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,769 @@
1
+ import functools
2
+ import math
3
+ from functools import lru_cache
4
+ from collections import defaultdict
5
+ from hestia_earth.schema import TermTermType
6
+ from hestia_earth.utils.lookup import (
7
+ download_lookup, get_table_value, column_name, _is_missing_value, extract_grouped_data, lookup_columns
8
+ )
9
+ from hestia_earth.utils.tools import safe_parse_float
10
+
11
+ from hestia_earth.models.utils import clamp
12
+ from hestia_earth.models.utils.term import get_lookup_value
13
+ from hestia_earth.models.utils.lookup import get_region_lookup, get_region_lookup_value
14
+ from .utils import (
15
+ IPCC_LAND_USE_CATEGORY_ANNUAL,
16
+ IPCC_LAND_USE_CATEGORY_PERENNIAL,
17
+ LAND_USE_TERMS_FOR_TRANSFORMATION,
18
+ ANNUAL_CROPLAND,
19
+ PERMANENT_CROPLAND,
20
+ FOREST_LAND,
21
+ OTHER_LAND,
22
+ PERMANENT_PASTURE,
23
+ TOTAL_CROPLAND,
24
+ TOTAL_AGRICULTURAL_CHANGE,
25
+ ALL_LAND_USE_TERMS,
26
+ crop_ipcc_land_use_category
27
+ )
28
+ from . import MODEL
29
+
30
+ MODEL_KEY = 'landCover'
31
+
32
+ _LOOKUP_EXPANSION = 'region-crop-cropGroupingFaostatProduction-areaHarvestedUpTo20YearExpansion.csv'
33
+ _LAND_AREA = 'Land area'
34
+ _TOP_LEVEL_LAND_USE_TYPE_IDS = {"annualCropland", "permanentCropland", "permanentPasture", "cropland"}
35
+
36
+
37
+ @lru_cache()
38
+ def get_land_use_terms():
39
+ return [v[0] for v in LAND_USE_TERMS_FOR_TRANSFORMATION.values()]
40
+
41
+
42
+ def _is_missing_or_none(value) -> bool:
43
+ return value is None or _is_missing_value(value)
44
+
45
+
46
+ def _safe_divide(numerator, denominator, default=0) -> float:
47
+ return default if not denominator else numerator / denominator
48
+
49
+
50
+ def _scale_values_to_one(dictionary: dict) -> dict:
51
+ """
52
+ Takes a dictionary with numeric values.
53
+ Scales each value so that the sum of them all is one.
54
+ """
55
+ # Does not handle negative values.
56
+ sum_of_values = sum(dictionary.values())
57
+ return {key: value / sum_of_values for key, value in dictionary.items()} if sum_of_values != 0 else dictionary
58
+
59
+
60
+ def _site_area_sum_to_100(dict_of_percentages: dict):
61
+ return False if dict_of_percentages == {} else (
62
+ math.isclose(sum(dict_of_percentages.values()), 1.0, rel_tol=0.05) or
63
+ math.isclose(sum(dict_of_percentages.values()), 0.0, rel_tol=0.01)
64
+ )
65
+
66
+
67
+ def _cap_values(dictionary: dict, lower_limit: float = 0, upper_limit: float = 1) -> dict:
68
+ return {key: min([upper_limit, max([lower_limit, value])]) for key, value in dictionary.items()}
69
+
70
+
71
+ def _get_lookup_with_cache(lookup_term, column):
72
+ """Wrapper to get_lookup_value which pulls out the immutable parts of the term to allow caching."""
73
+ @functools.cache
74
+ def _get_immutable_lookup(term_id: str, term_type: str, col: str):
75
+ new_term = {"@id": term_id, "termType": term_type} if term_type and term_id else {}
76
+ return get_lookup_value(
77
+ lookup_term=new_term,
78
+ column=col,
79
+ skip_debug=False,
80
+ model=MODEL,
81
+ term=term_id
82
+ )
83
+
84
+ return _get_immutable_lookup(
85
+ term_id=lookup_term.get("@id"),
86
+ term_type=lookup_term.get("termType"),
87
+ col=column
88
+ )
89
+
90
+
91
+ def _get_changes(country_id: str, reference_year: int) -> tuple[dict, list]:
92
+ """
93
+ For each entry in ALL_LAND_USE_TERMS, creates a key: value in output dictionary, also TOTAL
94
+ """
95
+ lookup_name = "region-faostatArea-UpTo20YearExpansion.csv"
96
+ changes_dict = {
97
+ land_use_term: safe_parse_float(
98
+ extract_grouped_data(
99
+ get_region_lookup_value(lookup_name, country_id, land_use_term, model=MODEL, key=MODEL_KEY),
100
+ str(reference_year)
101
+ ),
102
+ default=None
103
+ )
104
+ for land_use_term in ALL_LAND_USE_TERMS + [_LAND_AREA]
105
+ }
106
+ missing_changes = [k for k, v in changes_dict.items() if v is None]
107
+ changes_dict = {k: v if v is not None else 0 for k, v in changes_dict.items()}
108
+ changes_dict[TOTAL_AGRICULTURAL_CHANGE] = (
109
+ float(changes_dict.get(TOTAL_CROPLAND, 0)) + float(changes_dict.get(PERMANENT_PASTURE, 0))
110
+ )
111
+
112
+ return changes_dict, missing_changes
113
+
114
+
115
+ def _get_ratio_start_and_end_values(
116
+ expansion: float,
117
+ fao_name: str,
118
+ country_id: str,
119
+ reference_year: int
120
+ ) -> float:
121
+ # expansion over twenty years / current area
122
+ table_value = get_region_lookup_value('region-faostatArea.csv', country_id, fao_name, model=MODEL, key=MODEL_KEY)
123
+ end_value = safe_parse_float(value=extract_grouped_data(table_value, str(reference_year)), default=None)
124
+ return max(0.0, _safe_divide(numerator=expansion, denominator=end_value))
125
+
126
+
127
+ def _get_ratio_between_land_use_types(
128
+ country_id: str,
129
+ reference_year: int,
130
+ first_land_use_term: str,
131
+ second_land_use_term: str
132
+ ) -> tuple:
133
+ """Returns a tuple of the values of the two land use terms for the same country and year."""
134
+ return tuple([
135
+ safe_parse_float(value=extract_grouped_data(
136
+ get_region_lookup_value(
137
+ 'region-faostatArea.csv', country_id, land_use_term, model=MODEL, key=MODEL_KEY
138
+ ),
139
+ str(reference_year)),
140
+ default=None
141
+ )
142
+ for land_use_term in [first_land_use_term, second_land_use_term]
143
+ ])
144
+
145
+
146
+ def _estimate_maximum_forest_change(
147
+ forest_change: float, total_cropland_change: float, pasture_change: float, total_agricultural_change: float
148
+ ):
149
+ """
150
+ (L): Estimate maximum forest loss
151
+ Gives a negative number representing forest loss. Does not currently handle forest gain.
152
+ """
153
+ positive_change = pasture_change > 0 and total_cropland_change > 0
154
+ return _negative_agricultural_land_change(
155
+ forest_change=forest_change,
156
+ pasture_change=pasture_change,
157
+ total_cropland_change=total_cropland_change
158
+ ) if not positive_change else (
159
+ -total_agricultural_change
160
+ if -min(forest_change, 0) > total_agricultural_change else
161
+ min(forest_change, 0)
162
+ )
163
+
164
+
165
+ def _negative_agricultural_land_change(forest_change, pasture_change, total_cropland_change):
166
+ return (
167
+ -pasture_change if 0 < pasture_change < -min(forest_change, 0)
168
+ else min(forest_change, 0) if pasture_change > 0
169
+ else -total_cropland_change if 0 < total_cropland_change < -min(forest_change, 0)
170
+ else min(forest_change, 0) if 0 < total_cropland_change
171
+ else 0
172
+ )
173
+
174
+
175
+ def _allocate_forest_loss(forest_loss: float, changes: dict):
176
+ """Allocate forest loss between agricultural categories for the specific country"""
177
+ return {
178
+ TOTAL_CROPLAND: forest_loss * _safe_divide(
179
+ numerator=max(changes[TOTAL_CROPLAND], 0),
180
+ denominator=max(changes[TOTAL_CROPLAND], 0) + max(changes[PERMANENT_PASTURE], 0)
181
+ ),
182
+ PERMANENT_PASTURE: forest_loss * _safe_divide(
183
+ numerator=max(changes[PERMANENT_PASTURE], 0),
184
+ denominator=max(changes[TOTAL_CROPLAND], 0) + max(changes[PERMANENT_PASTURE], 0)
185
+ )
186
+ }
187
+
188
+
189
+ def _additional_allocation(changes, max_forest_loss_to_cropland, max_forest_loss_to_permanent_pasture):
190
+ """Determine how much area still needs to be assigned"""
191
+ return {
192
+ TOTAL_CROPLAND: max(changes[TOTAL_CROPLAND], 0) + max_forest_loss_to_cropland,
193
+ PERMANENT_PASTURE: max(changes[PERMANENT_PASTURE], 0) + max_forest_loss_to_permanent_pasture
194
+ }
195
+
196
+
197
+ def _allocate_cropland_loss_to_pasture(changes: dict, land_required_for_permanent_pasture: float):
198
+ """Allocate changes between Permanent pasture and cropland"""
199
+ return (
200
+ max(-land_required_for_permanent_pasture, changes[TOTAL_CROPLAND])
201
+ if changes[TOTAL_CROPLAND] < 0 else 0
202
+ )
203
+
204
+
205
+ def _allocate_pasture_loss_to_cropland(changes: dict, land_required_for_cropland: float):
206
+ """Allocate changes between Permanent pasture and cropland"""
207
+ return (
208
+ max(-land_required_for_cropland, changes[PERMANENT_PASTURE])
209
+ if changes[PERMANENT_PASTURE] < 0 else 0
210
+ )
211
+
212
+
213
+ def _allocate_other_land(
214
+ changes: dict, max_forest_loss_to: dict, pasture_loss_to_cropland: float, cropland_loss_to_pasture: float
215
+ ) -> dict:
216
+ """Allocate changes between Other land and cropland"""
217
+ other_land_loss_to_cropland = (
218
+ -(max(changes[TOTAL_CROPLAND], 0) + max_forest_loss_to[TOTAL_CROPLAND]
219
+ + pasture_loss_to_cropland)
220
+ )
221
+ other_land_loss_to_pasture = (
222
+ -(max(changes[PERMANENT_PASTURE], 0) + max_forest_loss_to[PERMANENT_PASTURE]
223
+ + cropland_loss_to_pasture)
224
+ )
225
+ return {
226
+ TOTAL_CROPLAND: other_land_loss_to_cropland,
227
+ PERMANENT_PASTURE: other_land_loss_to_pasture,
228
+ TOTAL_AGRICULTURAL_CHANGE: other_land_loss_to_cropland + other_land_loss_to_pasture
229
+ }
230
+
231
+
232
+ def _allocate_annual_permanent_cropland_losses(changes: dict) -> tuple:
233
+ """
234
+ (Z, AA): Allocate changes between Annual cropland and Permanent cropland
235
+ Returns: annual_cropland_loss_to_permanent_cropland, permanent_cropland_loss_to_annual_cropland
236
+ """
237
+ return (
238
+ -min(-changes[ANNUAL_CROPLAND], changes[PERMANENT_CROPLAND])
239
+ if (changes[ANNUAL_CROPLAND] < 0 and changes[PERMANENT_CROPLAND] > 0) else 0,
240
+ -min(changes[ANNUAL_CROPLAND], -changes[PERMANENT_CROPLAND])
241
+ if (changes[ANNUAL_CROPLAND] > 0 and changes[PERMANENT_CROPLAND] < 0) else 0
242
+ )
243
+
244
+
245
+ def _estimate_conversions_to_annual_cropland(
246
+ changes: dict,
247
+ pasture_loss_to_crops: float,
248
+ forest_loss_to_cropland: float,
249
+ other_land_loss_to_annual_cropland: float,
250
+ permanent_to_annual_cropland: float
251
+ ) -> dict:
252
+ """(AC-AG): Estimate percentage of land sources when converted to: Annual cropland"""
253
+
254
+ # -> percent_annual_cropland_was[]
255
+ def conversion_to_annual_cropland(factor: float):
256
+ return factor * _safe_divide(
257
+ numerator=_safe_divide(
258
+ numerator=max(changes[ANNUAL_CROPLAND], 0),
259
+ denominator=max(changes[ANNUAL_CROPLAND], 0) + max(changes[PERMANENT_CROPLAND], 0)
260
+ ),
261
+ denominator=-changes[ANNUAL_CROPLAND]
262
+ )
263
+
264
+ percentages = {
265
+ FOREST_LAND: conversion_to_annual_cropland(forest_loss_to_cropland),
266
+ OTHER_LAND: conversion_to_annual_cropland(other_land_loss_to_annual_cropland),
267
+ PERMANENT_PASTURE: conversion_to_annual_cropland(pasture_loss_to_crops),
268
+ PERMANENT_CROPLAND: _safe_divide(numerator=permanent_to_annual_cropland, denominator=-changes[ANNUAL_CROPLAND])
269
+ }
270
+ return percentages
271
+
272
+
273
+ def _estimate_conversions_to_permanent_cropland(
274
+ changes: dict,
275
+ annual_loss_to_permanent_cropland: float,
276
+ pasture_loss_to_cropland: float,
277
+ forest_loss_to_cropland: float,
278
+ other_land_loss_to_annual_cropland: float
279
+ ) -> dict:
280
+ """Estimate percentage of land sources when converted to: Permanent cropland"""
281
+
282
+ def conversion_to_permanent_cropland(factor: float):
283
+ return _safe_divide(
284
+ numerator=_safe_divide(
285
+ numerator=factor * max(changes[PERMANENT_CROPLAND], 0),
286
+ denominator=max(changes[ANNUAL_CROPLAND], 0) + max(changes[PERMANENT_CROPLAND], 0)
287
+ ),
288
+ denominator=-changes[PERMANENT_CROPLAND]
289
+ )
290
+
291
+ percentages = {
292
+ FOREST_LAND: conversion_to_permanent_cropland(forest_loss_to_cropland),
293
+ OTHER_LAND: conversion_to_permanent_cropland(other_land_loss_to_annual_cropland),
294
+ PERMANENT_PASTURE: conversion_to_permanent_cropland(pasture_loss_to_cropland),
295
+ ANNUAL_CROPLAND: conversion_to_permanent_cropland(annual_loss_to_permanent_cropland)
296
+ }
297
+ return percentages
298
+
299
+
300
+ def _estimate_conversions_to_pasture(
301
+ changes: dict,
302
+ forest_loss_to_pasture: float,
303
+ total_cropland_loss_to_pasture: float,
304
+ other_land_loss_to_pasture: float
305
+ ) -> dict:
306
+ """Estimate percentage of land sources when converted to: Permanent pasture"""
307
+ percentages = {
308
+ FOREST_LAND: _safe_divide(
309
+ numerator=forest_loss_to_pasture,
310
+ denominator=-changes[PERMANENT_PASTURE],
311
+ ),
312
+ OTHER_LAND: _safe_divide(
313
+ numerator=other_land_loss_to_pasture,
314
+ denominator=-changes[PERMANENT_PASTURE]
315
+ ),
316
+ # AT
317
+ ANNUAL_CROPLAND: _safe_divide(
318
+ numerator=total_cropland_loss_to_pasture * _safe_divide(
319
+ numerator=min(changes[ANNUAL_CROPLAND], 0),
320
+ denominator=(min(changes[ANNUAL_CROPLAND], 0) + min(changes[PERMANENT_CROPLAND], 0))
321
+ ),
322
+ denominator=-changes[PERMANENT_PASTURE]
323
+ ),
324
+ PERMANENT_CROPLAND: _safe_divide(
325
+ numerator=total_cropland_loss_to_pasture * _safe_divide(
326
+ numerator=min(changes[PERMANENT_CROPLAND], 0),
327
+ denominator=(min(changes[ANNUAL_CROPLAND], 0) + min(changes[PERMANENT_CROPLAND], 0))
328
+ ),
329
+ denominator=-changes[PERMANENT_PASTURE]
330
+ )
331
+ }
332
+ return percentages
333
+
334
+
335
+ def _get_shares_of_expansion(
336
+ land_use_type: str,
337
+ percent_annual_cropland_was: dict,
338
+ percent_permanent_cropland_was: dict,
339
+ percent_pasture_was: dict
340
+ ) -> dict:
341
+ expansion_for_type = {
342
+ ANNUAL_CROPLAND: percent_annual_cropland_was,
343
+ PERMANENT_CROPLAND: percent_permanent_cropland_was,
344
+ PERMANENT_PASTURE: percent_pasture_was
345
+ }
346
+ return _scale_values_to_one({
347
+ k: expansion_for_type[land_use_type].get(k, 0)
348
+ for k in LAND_USE_TERMS_FOR_TRANSFORMATION.keys()
349
+ })
350
+
351
+
352
+ def _get_faostat_name(term: dict) -> str:
353
+ """For landCover terms, find the cropGroupingFaostatArea name for the landCover id."""
354
+ return _get_lookup_with_cache(term, "cropGroupingFaostatArea")
355
+
356
+
357
+ def _get_most_common_or_alphabetically_first(crop_terms: list) -> str:
358
+ histogram = {term: crop_terms.count(term) for term in crop_terms}
359
+ max_freq = max(histogram.values())
360
+ # Sorted; to be deterministic
361
+ return sorted([term for term, freq in histogram.items() if freq == max_freq])[0]
362
+
363
+
364
+ def _get_complete_faostat_to_crop_mapping() -> dict:
365
+ """Returns mapping in the format: {faostat_name: IPCC_LAND_USE_CATEGORY, ...}"""
366
+ lookup = download_lookup("crop.csv")
367
+ mappings = defaultdict(list)
368
+ for crop_term_id in [row[0] for row in lookup]:
369
+ key = column_name(
370
+ get_table_value(lookup, 'termid', crop_term_id, column_name("cropGroupingFaostatArea"))
371
+ )
372
+ if key:
373
+ mappings[key].append(crop_ipcc_land_use_category(crop_term_id=crop_term_id, lookup_term_type="crop"))
374
+ return {
375
+ fao_name: _get_most_common_or_alphabetically_first(crop_terms)
376
+ for fao_name, crop_terms in mappings.items()
377
+ }
378
+
379
+
380
+ def _get_harvested_area(country_id: str, year: int, faostat_name: str) -> float:
381
+ """
382
+ Returns a dictionary of harvested areas for the country & year, indexed by landCover term (crop)
383
+ """
384
+ lookup_name = "region-crop-cropGroupingFaostatProduction-areaHarvested.csv"
385
+
386
+ return safe_parse_float(
387
+ value=extract_grouped_data(
388
+ data=get_region_lookup_value(lookup_name, country_id, faostat_name, model=MODEL, key=MODEL_KEY),
389
+ key=str(year)
390
+ ),
391
+ default=None
392
+ )
393
+
394
+
395
+ def _get_ratio_of_expanded_area(country_id: str, fao_name: str, reference_year: int) -> float:
396
+ table_value = get_region_lookup_value(_LOOKUP_EXPANSION, country_id, fao_name, model=MODEL, key=MODEL_KEY)
397
+ expansion = safe_parse_float(value=extract_grouped_data(table_value, str(reference_year)), default=None)
398
+ end_value = _get_harvested_area(
399
+ country_id=country_id,
400
+ year=reference_year,
401
+ faostat_name=fao_name
402
+ )
403
+ return 0.0 if any([expansion is None, end_value is None]) else max(
404
+ 0.0, _safe_divide(numerator=expansion, denominator=end_value)
405
+ )
406
+
407
+
408
+ def _get_sum_for_land_category(
409
+ values: dict,
410
+ year: int,
411
+ ipcc_land_use_category,
412
+ fao_stat_to_ipcc_type: dict,
413
+ include_negatives: bool = True
414
+ ) -> float:
415
+ return sum([
416
+ safe_parse_float(value=extract_grouped_data(table_value, str(year)), default=None)
417
+ for fao_name, table_value in values.items()
418
+ if not _is_missing_or_none(extract_grouped_data(table_value, str(year))) and
419
+ fao_stat_to_ipcc_type[fao_name] == ipcc_land_use_category and
420
+ (
421
+ include_negatives or
422
+ safe_parse_float(value=extract_grouped_data(table_value, str(year)), default=None) > 0.0
423
+ )
424
+ ])
425
+
426
+
427
+ def _get_sums_of_crop_expansion(country_id: str, year: int, include_negatives: bool = True) -> tuple[float, float]:
428
+ """
429
+ Sum net expansion for all annual and permanent crops, returned as two values.
430
+ Returns a tuple of (expansion of annual crops, expansion of permanent crops)
431
+ """
432
+ lookup = get_region_lookup(lookup_name=_LOOKUP_EXPANSION, term_id=country_id)
433
+ columns = lookup_columns(lookup)
434
+ values = {
435
+ name: get_table_value(lookup, 'termid', country_id, column_name(name))
436
+ for name in columns if name != "termid"
437
+ }
438
+
439
+ fao_stat_to_ipcc_type = _get_complete_faostat_to_crop_mapping()
440
+
441
+ annual_sum_of_expansion = _get_sum_for_land_category(
442
+ values=values,
443
+ year=year,
444
+ ipcc_land_use_category=IPCC_LAND_USE_CATEGORY_ANNUAL,
445
+ fao_stat_to_ipcc_type=fao_stat_to_ipcc_type,
446
+ include_negatives=include_negatives
447
+ )
448
+ permanent_sum_of_expansion = _get_sum_for_land_category(
449
+ values=values,
450
+ year=year,
451
+ ipcc_land_use_category=IPCC_LAND_USE_CATEGORY_PERENNIAL,
452
+ fao_stat_to_ipcc_type=fao_stat_to_ipcc_type,
453
+ include_negatives=include_negatives
454
+ )
455
+
456
+ return annual_sum_of_expansion, permanent_sum_of_expansion
457
+
458
+
459
+ def _get_net_expansion_cultivated_vs_harvested(
460
+ annual_crops_net_expansion, changes, land_use_type, permanent_crops_net_expansion
461
+ ):
462
+ return (
463
+ _safe_divide(
464
+ numerator=max(0, changes[ANNUAL_CROPLAND]),
465
+ denominator=(annual_crops_net_expansion / 1000)
466
+ ) if land_use_type == ANNUAL_CROPLAND else
467
+ _safe_divide(
468
+ numerator=max(0, changes[PERMANENT_CROPLAND]),
469
+ denominator=(permanent_crops_net_expansion / 1000)
470
+ ) if land_use_type == PERMANENT_CROPLAND else
471
+ 1
472
+ )
473
+
474
+
475
+ def _scale_site_area_errors(site_area: dict) -> dict:
476
+ """Redistribute the result of any rounding error in proportion to the other land use types."""
477
+ # Positive errors would not have been capped, so won't be missing.
478
+ negative_errors = [v for v in site_area.values() if v < 0.0]
479
+ return {
480
+ k: v + negative_errors[0] * v for k, v in site_area.items()
481
+ } if negative_errors and abs(negative_errors[0]) < 1 and all([v < 1 for v in site_area.values()]) else site_area
482
+
483
+
484
+ def _historical_land_use_change_single_crop(
485
+ site: dict,
486
+ term: dict,
487
+ reference_year: int,
488
+ land_use_type: str
489
+ ) -> tuple[dict, bool, dict]:
490
+ """Calculate land use change percentages for a single management node/crop."""
491
+ country_id = site.get("country", {}).get("@id")
492
+
493
+ # (C-H).
494
+ changes, missing_changes = _get_changes(country_id=country_id, reference_year=reference_year)
495
+
496
+ # (L). Estimate maximum forest loss
497
+ forest_loss = _estimate_maximum_forest_change(
498
+ forest_change=changes[FOREST_LAND],
499
+ total_cropland_change=changes[TOTAL_CROPLAND],
500
+ pasture_change=changes[PERMANENT_PASTURE],
501
+ total_agricultural_change=changes[TOTAL_AGRICULTURAL_CHANGE]
502
+ )
503
+
504
+ # (M, N). Allocate forest loss between agricultural categories for the specific country
505
+ forest_loss_to = _allocate_forest_loss(forest_loss=forest_loss, changes=changes)
506
+
507
+ # (P, Q): Determine how much area still needs to be assigned
508
+ land_required_for = _additional_allocation(
509
+ changes=changes,
510
+ max_forest_loss_to_cropland=forest_loss_to[TOTAL_CROPLAND],
511
+ max_forest_loss_to_permanent_pasture=forest_loss_to[PERMANENT_PASTURE]
512
+ )
513
+
514
+ # (R): Allocate changes between Permanent pasture and cropland
515
+ cropland_loss_to_pasture = _allocate_cropland_loss_to_pasture(
516
+ changes=changes,
517
+ land_required_for_permanent_pasture=land_required_for[PERMANENT_PASTURE]
518
+ )
519
+ # (S)
520
+ pasture_loss_to_cropland = _allocate_pasture_loss_to_cropland(
521
+ changes=changes,
522
+ land_required_for_cropland=land_required_for[TOTAL_CROPLAND]
523
+ )
524
+
525
+ # (V): Allocate changes between Other land and cropland
526
+ other_land_loss_to = _allocate_other_land(
527
+ changes=changes,
528
+ max_forest_loss_to=forest_loss_to,
529
+ pasture_loss_to_cropland=pasture_loss_to_cropland,
530
+ cropland_loss_to_pasture=cropland_loss_to_pasture
531
+ )
532
+
533
+ # (Z, AA): Allocate changes between Annual cropland and Permanent cropland
534
+ annual_cropland_loss_to_permanent_cropland, permanent_cropland_loss_to_annual_cropland = (
535
+ _allocate_annual_permanent_cropland_losses(changes)
536
+ )
537
+
538
+ # (AC-AG): Estimate percentage of land sources when converted to: Annual cropland
539
+ # Note: All percentages are expressed as decimal fractions. 50% = 0.5
540
+ percent_annual_cropland_was = _estimate_conversions_to_annual_cropland(
541
+ changes=changes,
542
+ pasture_loss_to_crops=pasture_loss_to_cropland,
543
+ forest_loss_to_cropland=forest_loss_to[TOTAL_CROPLAND],
544
+ other_land_loss_to_annual_cropland=other_land_loss_to[TOTAL_CROPLAND],
545
+ permanent_to_annual_cropland=permanent_cropland_loss_to_annual_cropland,
546
+ )
547
+
548
+ # (AJ-AM): Estimate percentage of land sources when converted to: Permanent cropland
549
+ percent_permanent_cropland_was = _estimate_conversions_to_permanent_cropland(
550
+ changes=changes,
551
+ annual_loss_to_permanent_cropland=annual_cropland_loss_to_permanent_cropland,
552
+ pasture_loss_to_cropland=pasture_loss_to_cropland,
553
+ forest_loss_to_cropland=forest_loss_to[TOTAL_CROPLAND],
554
+ other_land_loss_to_annual_cropland=other_land_loss_to[TOTAL_CROPLAND]
555
+ )
556
+
557
+ # Estimate percentage of land sources when converted to: Permanent pasture
558
+ percent_pasture_was = _estimate_conversions_to_pasture(
559
+ changes=changes,
560
+ forest_loss_to_pasture=forest_loss_to[PERMANENT_PASTURE],
561
+ total_cropland_loss_to_pasture=cropland_loss_to_pasture,
562
+ other_land_loss_to_pasture=other_land_loss_to[PERMANENT_PASTURE]
563
+ )
564
+
565
+ # C14-G14
566
+ shares_of_expansion = _get_shares_of_expansion(
567
+ land_use_type=land_use_type,
568
+ percent_annual_cropland_was=percent_annual_cropland_was,
569
+ percent_permanent_cropland_was=percent_permanent_cropland_was,
570
+ percent_pasture_was=percent_pasture_was
571
+ )
572
+
573
+ fao_name = _get_faostat_name(term)
574
+
575
+ # Cell E8
576
+ expansion_factor = _get_ratio_start_and_end_values(
577
+ expansion=changes[land_use_type],
578
+ fao_name=land_use_type,
579
+ country_id=country_id,
580
+ reference_year=reference_year
581
+ ) if term.get("@id") in _TOP_LEVEL_LAND_USE_TYPE_IDS or fao_name == "" else _get_ratio_of_expanded_area(
582
+ country_id=country_id,
583
+ fao_name=fao_name,
584
+ reference_year=reference_year
585
+ )
586
+
587
+ # E9
588
+ annual_crops_net_expansion, permanent_crops_net_expansion = _get_sums_of_crop_expansion(
589
+ country_id=country_id,
590
+ year=reference_year,
591
+ include_negatives=True
592
+ )
593
+ annual_crops_gross_expansion, permanent_crops_gross_expansion = _get_sums_of_crop_expansion(
594
+ country_id=country_id,
595
+ year=reference_year,
596
+ include_negatives=False
597
+ )
598
+ e9_net_expansion = _safe_divide(
599
+ numerator=permanent_crops_net_expansion,
600
+ denominator=permanent_crops_gross_expansion
601
+ ) if land_use_type == PERMANENT_CROPLAND else (
602
+ _safe_divide(
603
+ numerator=annual_crops_net_expansion,
604
+ denominator=annual_crops_gross_expansion
605
+ ) if land_use_type == ANNUAL_CROPLAND else 1
606
+ )
607
+
608
+ # E10: Compare changes to annual/permanent cropland from net expansion.
609
+ net_expansion_cultivated_vs_harvested = _get_net_expansion_cultivated_vs_harvested(
610
+ annual_crops_net_expansion=annual_crops_net_expansion,
611
+ changes=changes,
612
+ land_use_type=land_use_type,
613
+ permanent_crops_net_expansion=permanent_crops_net_expansion
614
+ )
615
+ capped_expansion_factor = clamp(
616
+ value=expansion_factor * e9_net_expansion * net_expansion_cultivated_vs_harvested,
617
+ min_value=0,
618
+ max_value=1
619
+ )
620
+
621
+ site_area = {
622
+ land_type: (shares_of_expansion[land_type] * capped_expansion_factor)
623
+ for land_type in LAND_USE_TERMS_FOR_TRANSFORMATION.keys()
624
+ if land_type != land_use_type
625
+ }
626
+ site_area[land_use_type] = 1 - sum(site_area.values())
627
+ capped_site_area = _cap_values(dictionary=_scale_site_area_errors(site_area))
628
+
629
+ sum_of_site_areas_is_100 = _site_area_sum_to_100(capped_site_area)
630
+
631
+ logs = {
632
+ 'changes': changes,
633
+ 'missing-changes': missing_changes,
634
+ 'site-area': capped_site_area,
635
+ 'sum-site-area-is-100': sum_of_site_areas_is_100
636
+ }
637
+
638
+ is_valid = all([len(missing_changes) == 0, sum_of_site_areas_is_100])
639
+
640
+ return capped_site_area, is_valid, logs
641
+
642
+
643
+ def _scaled_value(
644
+ permanent_crops_value: float,
645
+ annual_crops_value: float,
646
+ permanent_crops_factor: float,
647
+ annual_crops_factor: float,
648
+ ):
649
+ total_area = permanent_crops_factor + annual_crops_factor
650
+ permanent_crops_scaled = permanent_crops_value * permanent_crops_factor / total_area
651
+ annual_crops_scaled = annual_crops_value * annual_crops_factor / total_area
652
+ return annual_crops_scaled + permanent_crops_scaled
653
+
654
+
655
+ def _scale_from_annual_and_permanent_results(
656
+ annual_cropland_results: dict,
657
+ permanent_cropland_results: dict,
658
+ annual_cropland_factor: float,
659
+ permanent_cropland_factor: float
660
+ ) -> dict:
661
+ return {
662
+ land_key: _scaled_value(
663
+ permanent_crops_value=permanent_cropland_results[land_key],
664
+ annual_crops_value=land_value,
665
+ permanent_crops_factor=permanent_cropland_factor,
666
+ annual_crops_factor=annual_cropland_factor
667
+ )
668
+ for land_key, land_value in annual_cropland_results.items()
669
+ }
670
+
671
+
672
+ def _new_landCover_term(new_land_use_term) -> dict:
673
+ return {
674
+ "@id": LAND_USE_TERMS_FOR_TRANSFORMATION[new_land_use_term][0],
675
+ "name": LAND_USE_TERMS_FOR_TRANSFORMATION[new_land_use_term][1],
676
+ "@type": "Term",
677
+ "termType": TermTermType.LANDCOVER.value
678
+ }
679
+
680
+
681
+ def _historical_land_use_change_total_cropland(site: dict, reference_year: int) -> tuple[dict, bool, dict]:
682
+ country_id = site.get("country", {}).get("@id")
683
+
684
+ # Run _should_run_historical_land_use_change_single_crop for annual and permanent
685
+ areas_for_annual_cropland, should_run_annual, *args = _historical_land_use_change_single_crop(
686
+ site=site,
687
+ term=_new_landCover_term(ANNUAL_CROPLAND),
688
+ reference_year=reference_year,
689
+ land_use_type=ANNUAL_CROPLAND
690
+ )
691
+ areas_for_permanent_cropland, should_run_permanent, *args = _historical_land_use_change_single_crop(
692
+ site=site,
693
+ term=_new_landCover_term(PERMANENT_CROPLAND),
694
+ reference_year=reference_year,
695
+ land_use_type=PERMANENT_CROPLAND
696
+ )
697
+ # Get current ratios ("Arable land" vs "Permanent crops")
698
+ annual_cropland_factor, permanent_crops_factor = _get_ratio_between_land_use_types(
699
+ country_id=country_id,
700
+ reference_year=reference_year,
701
+ first_land_use_term=ANNUAL_CROPLAND,
702
+ second_land_use_term=PERMANENT_CROPLAND
703
+ ) if should_run_annual and should_run_permanent else tuple([0, 0])
704
+ scaled_results = _scale_from_annual_and_permanent_results(
705
+ annual_cropland_results=areas_for_annual_cropland,
706
+ permanent_cropland_results=areas_for_permanent_cropland,
707
+ annual_cropland_factor=annual_cropland_factor,
708
+ permanent_cropland_factor=permanent_crops_factor
709
+ ) if should_run_annual and should_run_permanent else {}
710
+
711
+ logs = {
712
+ 'annualCropland': areas_for_annual_cropland,
713
+ 'annualCropland-factor': annual_cropland_factor,
714
+ 'permanentCropland': areas_for_permanent_cropland,
715
+ 'permanentCropland-factor': permanent_crops_factor
716
+ }
717
+
718
+ is_valid = all([should_run_annual, should_run_permanent])
719
+
720
+ return scaled_results, is_valid, logs
721
+
722
+
723
+ def compute_site_area(site: dict, term: dict, land_use_type: str, reference_year: int):
724
+ return (
725
+ # Assume a single management node for single-cropping
726
+ _historical_land_use_change_total_cropland(site, reference_year) if land_use_type == TOTAL_CROPLAND else
727
+ _historical_land_use_change_single_crop(
728
+ site=site,
729
+ term=term,
730
+ reference_year=reference_year,
731
+ land_use_type=land_use_type
732
+ )
733
+ )
734
+
735
+
736
+ def _get_land_cover_lookup_suffix(land_type: str) -> str:
737
+ return LAND_USE_TERMS_FOR_TRANSFORMATION[land_type][0]
738
+
739
+
740
+ def get_site_area_from_lookups(country_id: str, reference_year: int, term: dict):
741
+ """
742
+ Attempts to get the pre-calculated values for the landCover model calculation.
743
+ Returns: {"Arable land": <value>, "Forest land": <value>, "Other land": <value>,
744
+ "Permanent crops": <value>, "Permanent meadows and pastures": <value>}
745
+ Missing values are returned as None.
746
+ """
747
+ lookup_prefix = 'region-crop-cropGroupingFAOSTAT-landCover'
748
+ lookup_column = _get_faostat_name(term)
749
+ return {
750
+ # Divide by 100 to match site_area ratios
751
+ land_type: value / 100 if value is not None else value
752
+ for land_type, value in
753
+ {
754
+ land_type: safe_parse_float(
755
+ value=extract_grouped_data(
756
+ data=get_region_lookup_value(
757
+ lookup_name=f"{lookup_prefix}-{_get_land_cover_lookup_suffix(land_type)}.csv",
758
+ term_id=country_id,
759
+ column=lookup_column,
760
+ model=MODEL,
761
+ key=MODEL_KEY
762
+ ),
763
+ key=str(reference_year)
764
+ ),
765
+ default=None
766
+ )
767
+ for land_type in LAND_USE_TERMS_FOR_TRANSFORMATION.keys()
768
+ }.items()
769
+ }