hestia-earth-models 0.67.0__py3-none-any.whl → 0.68.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. hestia_earth/models/aware/scarcityWeightedWaterUse.py +5 -6
  2. hestia_earth/models/blonkConsultants2016/ch4ToAirNaturalVegetationBurning.py +1 -1
  3. hestia_earth/models/blonkConsultants2016/co2ToAirAboveGroundBiomassStockChangeLandUseChange.py +1 -1
  4. hestia_earth/models/blonkConsultants2016/n2OToAirNaturalVegetationBurningDirect.py +1 -1
  5. hestia_earth/models/blonkConsultants2016/utils.py +9 -9
  6. hestia_earth/models/cache_sites.py +26 -14
  7. hestia_earth/models/chaudharyBrooks2018/damageToTerrestrialEcosystemsLandOccupation.py +2 -2
  8. hestia_earth/models/chaudharyBrooks2018/damageToTerrestrialEcosystemsLandTransformation.py +2 -2
  9. hestia_earth/models/chaudharyBrooks2018/utils.py +13 -8
  10. hestia_earth/models/cml2001Baseline/abioticResourceDepletionFossilFuels.py +2 -3
  11. hestia_earth/models/cml2001Baseline/abioticResourceDepletionMineralsAndMetals.py +1 -1
  12. hestia_earth/models/cml2001Baseline/resourceUseEnergyDepletionDuringCycle.py +5 -10
  13. hestia_earth/models/config/Cycle.json +15 -0
  14. hestia_earth/models/config/ImpactAssessment.json +14 -1
  15. hestia_earth/models/config/Site.json +8 -0
  16. hestia_earth/models/cycle/completeness/freshForage.py +7 -3
  17. hestia_earth/models/cycle/excretaKgMass.py +2 -2
  18. hestia_earth/models/cycle/inorganicFertiliser.py +67 -17
  19. hestia_earth/models/cycle/materialAndSubstrate.py +3 -2
  20. hestia_earth/models/cycle/pastureGrass.py +3 -3
  21. hestia_earth/models/dammgen2009/noxToAirExcreta.py +1 -1
  22. hestia_earth/models/ecoinventV3AndEmberClimate/__init__.py +1 -1
  23. hestia_earth/models/ecoinventV3AndEmberClimate/utils.py +2 -6
  24. hestia_earth/models/emissionNotRelevant/__init__.py +4 -4
  25. hestia_earth/models/environmentalFootprintV3_1/environmentalFootprintSingleOverallScore.py +60 -46
  26. hestia_earth/models/environmentalFootprintV3_1/photochemicalOzoneCreationPotentialHumanHealthNmvocEq.py +36 -0
  27. hestia_earth/models/environmentalFootprintV3_1/scarcityWeightedWaterUse.py +2 -2
  28. hestia_earth/models/environmentalFootprintV3_1/soilQualityIndexLandOccupation.py +9 -8
  29. hestia_earth/models/environmentalFootprintV3_1/soilQualityIndexLandTransformation.py +45 -34
  30. hestia_earth/models/environmentalFootprintV3_1/soilQualityIndexTotalLandUseEffects.py +24 -21
  31. hestia_earth/models/faostat2018/coldCarcassWeightPerHead.py +2 -2
  32. hestia_earth/models/faostat2018/coldDressedCarcassWeightPerHead.py +2 -2
  33. hestia_earth/models/faostat2018/liveweightPerHead.py +7 -8
  34. hestia_earth/models/faostat2018/product/price.py +34 -28
  35. hestia_earth/models/faostat2018/readyToCookWeightPerHead.py +2 -2
  36. hestia_earth/models/faostat2018/utils.py +15 -27
  37. hestia_earth/models/frischknechtEtAl2000/ionisingRadiationKbqU235Eq.py +16 -9
  38. hestia_earth/models/geospatialDatabase/altitude.py +60 -0
  39. hestia_earth/models/geospatialDatabase/croppingIntensity.py +1 -1
  40. hestia_earth/models/geospatialDatabase/ecoClimateZone.py +2 -2
  41. hestia_earth/models/geospatialDatabase/longFallowRatio.py +1 -1
  42. hestia_earth/models/geospatialDatabase/utils.py +4 -1
  43. hestia_earth/models/globalCropWaterModel2008/rootingDepth.py +2 -3
  44. hestia_earth/models/haversineFormula/transport/distance.py +3 -3
  45. hestia_earth/models/hestia/landCover.py +72 -45
  46. hestia_earth/models/hestia/landTransformation100YearAverageDuringCycle.py +1 -1
  47. hestia_earth/models/hestia/landTransformation20YearAverageDuringCycle.py +1 -1
  48. hestia_earth/models/hestia/seed_emissions.py +11 -7
  49. hestia_earth/models/impact_assessment/__init__.py +3 -3
  50. hestia_earth/models/ipcc2019/aboveGroundBiomass.py +1 -1
  51. hestia_earth/models/ipcc2019/animal/fatContent.py +1 -1
  52. hestia_earth/models/ipcc2019/animal/hoursWorkedPerDay.py +1 -1
  53. hestia_earth/models/ipcc2019/animal/liveweightGain.py +1 -1
  54. hestia_earth/models/ipcc2019/animal/liveweightPerHead.py +1 -1
  55. hestia_earth/models/ipcc2019/animal/milkYieldPerAnimal.py +1 -1
  56. hestia_earth/models/ipcc2019/animal/pastureGrass.py +1 -1
  57. hestia_earth/models/ipcc2019/animal/pregnancyRateTotal.py +1 -1
  58. hestia_earth/models/ipcc2019/animal/trueProteinContent.py +1 -1
  59. hestia_earth/models/ipcc2019/animal/utils.py +5 -7
  60. hestia_earth/models/ipcc2019/animal/weightAtMaturity.py +1 -1
  61. hestia_earth/models/ipcc2019/belowGroundBiomass.py +1 -1
  62. hestia_earth/models/ipcc2019/ch4ToAirEntericFermentation.py +2 -2
  63. hestia_earth/models/ipcc2019/ch4ToAirExcreta.py +6 -7
  64. hestia_earth/models/ipcc2019/ch4ToAirFloodedRice.py +5 -3
  65. hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +1 -1
  66. hestia_earth/models/ipcc2019/croppingDuration.py +3 -6
  67. hestia_earth/models/ipcc2019/nonCo2EmissionsToAirNaturalVegetationBurning.py +947 -0
  68. hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_1_utils.py +4 -4
  69. hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_2_utils.py +1 -1
  70. hestia_earth/models/ipcc2019/pastureGrass.py +1 -1
  71. hestia_earth/models/koble2014/residueBurnt.py +5 -7
  72. hestia_earth/models/koble2014/residueRemoved.py +5 -7
  73. hestia_earth/models/lcImpactAllEffects100Years/damageToHumanHealthWaterStress.py +2 -2
  74. hestia_earth/models/lcImpactAllEffectsInfinite/damageToHumanHealthWaterStress.py +2 -2
  75. hestia_earth/models/lcImpactCertainEffects100Years/damageToHumanHealthWaterStress.py +2 -2
  76. hestia_earth/models/lcImpactCertainEffectsInfinite/damageToHumanHealthWaterStress.py +2 -2
  77. hestia_earth/models/log.py +1 -1
  78. hestia_earth/models/mocking/search-results.json +3477 -1045
  79. hestia_earth/models/site/management.py +1 -1
  80. hestia_earth/models/site/post_checks/__init__.py +3 -2
  81. hestia_earth/models/site/post_checks/country.py +9 -0
  82. hestia_earth/models/site/pre_checks/__init__.py +3 -2
  83. hestia_earth/models/site/pre_checks/country.py +9 -0
  84. hestia_earth/models/utils/__init__.py +1 -16
  85. hestia_earth/models/utils/blank_node.py +89 -36
  86. hestia_earth/models/utils/completeness.py +3 -2
  87. hestia_earth/models/utils/cycle.py +5 -4
  88. hestia_earth/models/utils/ecoClimateZone.py +2 -2
  89. hestia_earth/models/utils/emission.py +5 -5
  90. hestia_earth/models/utils/feedipedia.py +6 -6
  91. hestia_earth/models/utils/impact_assessment.py +6 -6
  92. hestia_earth/models/utils/indicator.py +9 -7
  93. hestia_earth/models/utils/inorganicFertiliser.py +4 -6
  94. hestia_earth/models/utils/input.py +6 -5
  95. hestia_earth/models/utils/lookup.py +35 -105
  96. hestia_earth/models/utils/management.py +4 -4
  97. hestia_earth/models/utils/measurement.py +6 -7
  98. hestia_earth/models/utils/method.py +20 -0
  99. hestia_earth/models/utils/practice.py +4 -5
  100. hestia_earth/models/utils/product.py +4 -5
  101. hestia_earth/models/utils/property.py +12 -22
  102. hestia_earth/models/utils/site.py +14 -8
  103. hestia_earth/models/utils/term.py +27 -1
  104. hestia_earth/models/version.py +1 -1
  105. hestia_earth/orchestrator/log.py +0 -11
  106. hestia_earth/orchestrator/models/__init__.py +17 -4
  107. hestia_earth/orchestrator/strategies/run/add_blank_node_if_missing.py +2 -20
  108. {hestia_earth_models-0.67.0.dist-info → hestia_earth_models-0.68.0.dist-info}/METADATA +2 -2
  109. {hestia_earth_models-0.67.0.dist-info → hestia_earth_models-0.68.0.dist-info}/RECORD +159 -151
  110. tests/models/cml2001Baseline/test_abioticResourceDepletionFossilFuels.py +3 -3
  111. tests/models/cml2001Baseline/test_resourceUseEnergyDepletionDuringCycle.py +68 -35
  112. tests/models/cycle/test_coldCarcassWeightPerHead.py +1 -1
  113. tests/models/cycle/test_coldDressedCarcassWeightPerHead.py +1 -1
  114. tests/models/cycle/test_concentrateFeed.py +1 -1
  115. tests/models/cycle/test_energyContentLowerHeatingValue.py +1 -1
  116. tests/models/cycle/test_excretaKgMass.py +1 -1
  117. tests/models/cycle/test_feedConversionRatio.py +3 -3
  118. tests/models/cycle/test_pastureGrass.py +1 -1
  119. tests/models/cycle/test_readyToCookWeightPerHead.py +1 -1
  120. tests/models/environmentalFootprintV3_1/test_environmentalFootprintSingleOverallScore.py +38 -8
  121. tests/models/environmentalFootprintV3_1/test_photochemicalOzoneCreationPotentialHumanHealthNmvocEq.py +30 -0
  122. tests/models/environmentalFootprintV3_1/test_soilQualityIndexLandTransformation.py +65 -36
  123. tests/models/environmentalFootprintV3_1/test_soilQualityIndexTotalLandUseEffects.py +30 -7
  124. tests/models/faostat2018/product/test_price.py +27 -14
  125. tests/models/faostat2018/test_faostat_utils.py +4 -24
  126. tests/models/faostat2018/test_liveweightPerHead.py +9 -9
  127. tests/models/globalCropWaterModel2008/test_rootingDepth.py +7 -3
  128. tests/models/haversineFormula/transport/test_distance.py +1 -1
  129. tests/models/hestia/test_landCover.py +53 -5
  130. tests/models/ipcc2019/animal/test_pastureGrass.py +5 -3
  131. tests/models/ipcc2019/test_aboveGroundCropResidueTotal.py +4 -4
  132. tests/models/ipcc2019/test_belowGroundCropResidue.py +4 -4
  133. tests/models/ipcc2019/test_ch4ToAirEntericFermentation.py +10 -10
  134. tests/models/ipcc2019/test_croppingDuration.py +1 -1
  135. tests/models/ipcc2019/test_nonCo2EmissionsToAirNaturalVegetationBurning.py +83 -0
  136. tests/models/ipcc2019/test_organicCarbonPerHa.py +12 -12
  137. tests/models/ipcc2019/test_pastureGrass.py +5 -3
  138. tests/models/pooreNemecek2018/test_excretaKgN.py +5 -5
  139. tests/models/pooreNemecek2018/test_excretaKgVs.py +2 -2
  140. tests/models/site/post_checks/test_country.py +6 -0
  141. tests/models/site/pre_checks/test_cache_geospatialDatabase.py +1 -1
  142. tests/models/site/pre_checks/test_country.py +12 -0
  143. tests/models/site/test_management.py +1 -4
  144. tests/models/test_ecoinventV3.py +7 -3
  145. tests/models/utils/test_blank_node.py +17 -177
  146. tests/models/utils/test_dataCompleteness.py +5 -5
  147. tests/models/utils/test_emission.py +2 -2
  148. tests/models/utils/test_indicator.py +2 -2
  149. tests/models/utils/test_input.py +2 -2
  150. tests/models/utils/test_measurement.py +2 -4
  151. tests/models/utils/test_practice.py +4 -2
  152. tests/models/utils/test_product.py +2 -2
  153. tests/models/utils/test_property.py +4 -2
  154. tests/models/utils/test_site.py +7 -0
  155. tests/orchestrator/models/test_transformations.py +4 -1
  156. tests/orchestrator/strategies/run/test_add_blank_node_if_missing.py +4 -9
  157. hestia_earth/models/environmentalFootprintV3_1/utils.py +0 -17
  158. tests/models/utils/test_lookup.py +0 -10
  159. {hestia_earth_models-0.67.0.dist-info → hestia_earth_models-0.68.0.dist-info}/LICENSE +0 -0
  160. {hestia_earth_models-0.67.0.dist-info → hestia_earth_models-0.68.0.dist-info}/WHEEL +0 -0
  161. {hestia_earth_models-0.67.0.dist-info → hestia_earth_models-0.68.0.dist-info}/top_level.txt +0 -0
@@ -3,7 +3,7 @@ This model calculates the scarcity weighted water use based on the geospatial AW
3
3
  (see UNEP (2016); Boulay et al (2016); Boulay et al (2020); EC-JRC (2017)).
4
4
  """
5
5
  from hestia_earth.schema import SiteSiteType
6
- from hestia_earth.utils.lookup import download_lookup, _get_single_table_value, column_name, get_table_value
6
+ from hestia_earth.utils.lookup import download_lookup, _get_single_table_value, column_name
7
7
  from hestia_earth.utils.tools import safe_parse_float
8
8
 
9
9
  from hestia_earth.models.log import logRequirements, debugMissingLookup, logShouldRun
@@ -13,6 +13,7 @@ from hestia_earth.models.utils.impact_assessment import (
13
13
  convert_value_from_cycle, emission_value, get_product, get_site, get_region_id
14
14
  )
15
15
  from hestia_earth.models.utils.input import sum_input_impacts
16
+ from hestia_earth.models.utils.lookup import get_region_lookup_value
16
17
  from . import MODEL
17
18
 
18
19
  REQUIREMENTS = {
@@ -40,8 +41,8 @@ RETURNS = {
40
41
  }
41
42
  LOOKUPS = {
42
43
  "@doc": "Different lookup files are used depending on the situation",
43
- "awareWaterBasinId": "using `awareWaterBasinId` and `YR_IRRI` (for `cropland`, `glass or high accessible cover`, or `permanent pasture`) or `YR_NONIRRI`", # noqa: E501
44
- "region-aware-factors": "using `region` and `YR_IRRI` (for `cropland`, `glass or high accessible cover` or `permanent pasture`) or `YR_NONIRRI`" # noqa: E501
44
+ "awareWaterBasinId": "",
45
+ "region-aware-factors": ""
45
46
  }
46
47
  TERM_ID = 'scarcityWeightedWaterUse'
47
48
  AWARE_KEY = 'awareWaterBasinId'
@@ -71,11 +72,9 @@ def _get_factor_from_region(impact_assessment: dict, site: dict):
71
72
  region_id = get_region_id(impact_assessment)
72
73
  site_type = site.get('siteType')
73
74
  lookup_name = 'region-aware-factors.csv'
74
- lookup = download_lookup(lookup_name)
75
75
  lookup_suffix = 'unspecified' if not site_type else ('irri' if site_type in IRRIGATED_SITE_TYPES else 'non_irri')
76
76
  column = f"Agg_CF_{lookup_suffix}"
77
- value = get_table_value(lookup, 'termid', region_id, column_name(column))
78
- debugMissingLookup(lookup_name, 'termid', region_id, column, value, model=MODEL, term=TERM_ID)
77
+ value = get_region_lookup_value(lookup_name, region_id, column, model=MODEL, term=TERM_ID)
79
78
  return safe_parse_float(value, None)
80
79
 
81
80
 
@@ -34,7 +34,7 @@ REQUIREMENTS = {
34
34
  }
35
35
  LOOKUPS = {
36
36
  "crop": ["isPlantation", "cropGroupingFaostatArea"],
37
- "region-crop-cropGroupingFaostatArea-ch4forestBiomassBurning": "use crop grouping above or default to site.siteType"
37
+ "region-crop-cropGroupingFaostatArea-ch4forestBiomassBurning": ""
38
38
  }
39
39
  RETURNS = {
40
40
  "Emission": [{
@@ -34,7 +34,7 @@ REQUIREMENTS = {
34
34
  }
35
35
  LOOKUPS = {
36
36
  "crop": ["isPlantation", "cropGroupingFaostatArea"],
37
- "region-crop-cropGroupingFaostatArea-co2LandUseChange": "use crop grouping above or default to site.siteType"
37
+ "region-crop-cropGroupingFaostatArea-co2LandUseChange": ""
38
38
  }
39
39
  RETURNS = {
40
40
  "Emission": [{
@@ -34,7 +34,7 @@ REQUIREMENTS = {
34
34
  }
35
35
  LOOKUPS = {
36
36
  "crop": ["isPlantation", "cropGroupingFaostatArea"],
37
- "region-crop-cropGroupingFaostatArea-n2oforestBiomassBurning": "use crop grouping above or default to site.siteType"
37
+ "region-crop-cropGroupingFaostatArea-n2oforestBiomassBurning": ""
38
38
  }
39
39
  RETURNS = {
40
40
  "Emission": [{
@@ -1,9 +1,10 @@
1
1
  from hestia_earth.utils.model import find_primary_product
2
- from hestia_earth.utils.lookup import download_lookup, get_table_value, column_name, extract_grouped_data
2
+ from hestia_earth.utils.lookup import extract_grouped_data
3
3
  from hestia_earth.utils.tools import safe_parse_float
4
4
 
5
- from hestia_earth.models.log import debugMissingLookup, logger
5
+ from hestia_earth.models.log import logger
6
6
  from hestia_earth.models.utils.crop import FAOSTAT_AREA_LOOKUP_COLUMN, get_crop_grouping_faostat_area
7
+ from hestia_earth.models.utils.lookup import get_region_lookup_value
7
8
  from . import MODEL
8
9
 
9
10
 
@@ -18,13 +19,12 @@ def get_emission_factor(term_id: str, cycle: dict, factor: str):
18
19
  MODEL, country_id, product_id, f"'{crop_grouping}'")
19
20
 
20
21
  lookup_name = f"region-crop-{FAOSTAT_AREA_LOOKUP_COLUMN}-{factor}.csv"
21
- lookup = download_lookup(lookup_name)
22
- value = get_table_value(lookup, 'termid', country_id, column_name(crop_grouping)) if crop_grouping else None
23
- debugMissingLookup(lookup_name, 'termid', country_id, crop_grouping, value, model=MODEL, term=term_id)
22
+ value = get_region_lookup_value(
23
+ lookup_name, country_id, crop_grouping, model=MODEL, term=term_id
24
+ ) if crop_grouping else get_region_lookup_value(
25
+ lookup_name, country_id, 'NONE', model=MODEL, term=term_id
26
+ )
24
27
 
25
28
  data = safe_parse_float(value, None)
26
29
  # fallback to site.siteType data if possible
27
- return data if data is not None else safe_parse_float(
28
- extract_grouped_data(get_table_value(lookup, 'termid', country_id, column_name('NONE')), site.get('siteType')),
29
- None
30
- )
30
+ return data if data is not None else safe_parse_float(extract_grouped_data(value, site.get('siteType')), None)
@@ -2,7 +2,7 @@ from functools import reduce
2
2
  from enum import Enum
3
3
  from pydash.objects import merge
4
4
  from hestia_earth.utils.api import download_hestia
5
- from hestia_earth.utils.tools import flatten
5
+ from hestia_earth.utils.tools import flatten, non_empty_list
6
6
 
7
7
  from .log import logger
8
8
  from .utils import CACHE_KEY, cached_value
@@ -30,14 +30,24 @@ _VALUE_AS_PARAM = {
30
30
  }
31
31
 
32
32
 
33
+ def _value_as_param(param_type: ParamType = None): return _VALUE_AS_PARAM.get(param_type, lambda *args: None)
34
+
35
+
33
36
  def _cache_results(results: list, collections: list, index: int):
34
37
  start = index * len(collections)
35
38
  end = start + len(collections)
36
39
  return cache_site_results(results[start:end], collections)
37
40
 
38
41
 
39
- def _run_values(sites: list, param_type: ParamType, rasters: list = [], vectors: list = [], years: list = None):
40
- param_values = list(map(_VALUE_AS_PARAM.get(param_type), sites))
42
+ def _run_values(
43
+ sites: list,
44
+ param_type: ParamType = None,
45
+ rasters: list = [],
46
+ vectors: list = [],
47
+ years: list = None
48
+ ):
49
+ get_param_values = _value_as_param(param_type)
50
+ param_values = non_empty_list(map(get_param_values, sites))
41
51
  # unique list
42
52
  param_values = list(set(param_values)) if param_type == ParamType.GADM_IDS else list({
43
53
  str(v): v for v in param_values
@@ -59,13 +69,13 @@ def _run_values(sites: list, param_type: ParamType, rasters: list = [], vectors:
59
69
  site, area_size = site_values
60
70
 
61
71
  # get real index in values to handle duplicates
62
- param_value = _VALUE_AS_PARAM.get(param_type)([site])
63
- index = param_values.index(param_value)
72
+ param_value = get_param_values([site])
73
+ index = param_values.index(param_value) if param_value is not None else None
64
74
 
65
- cached_data = {
75
+ cached_data = ({
66
76
  **_cache_results(raster_results, rasters, index),
67
77
  **_cache_results(vector_results, vectors, index)
68
- } | ({CACHE_AREA_SIZE: area_size} if area_size is not None else {})
78
+ } if index is not None else {}) | ({CACHE_AREA_SIZE: area_size} if area_size is not None else {})
69
79
  cached_data = merge(cached_value(site, CACHE_GEOSPATIAL_KEY, {}), cached_data)
70
80
  site_cache = merge(
71
81
  site.get(CACHE_KEY, {}),
@@ -96,33 +106,35 @@ def _group_sites(sites: dict, check_has_cache: bool = True):
96
106
  (n, ) + (_should_run(n, area_size=get_region_area_size(n), check_has_cache=check_has_cache)) for n in sites
97
107
  ]
98
108
  # restrict sites based on should_cache result
99
- sites = [(site, area_size) for site, should_cache, area_size in sites if should_cache]
109
+ sites_run = [(site, area_size) for site, should_cache, area_size in sites if should_cache]
110
+ # will only cache area and years
111
+ sites_no_run = [(site, area_size) for site, should_cache, area_size in sites if not should_cache]
100
112
 
101
113
  with_coordinates = [
102
- (site, area_size) for site, area_size in sites if has_coordinates(site)
114
+ (site, area_size) for site, area_size in sites_run if has_coordinates(site)
103
115
  ]
104
116
  with_boundaries = [
105
- (site, area_size) for site, area_size in sites if not has_coordinates(site) and has_boundary(site)
117
+ (site, area_size) for site, area_size in sites_run if not has_coordinates(site) and has_boundary(site)
106
118
  ]
107
119
  with_gadm_ids = [
108
- (site, area_size) for site, area_size in sites if not has_coordinates(site) and not has_boundary(site)
120
+ (site, area_size) for site, area_size in sites_run if not has_coordinates(site) and not has_boundary(site)
109
121
  ]
110
122
 
111
123
  return {
112
124
  ParamType.COORDINATES: with_coordinates,
113
125
  ParamType.BOUNDARIES: with_boundaries,
114
126
  ParamType.GADM_IDS: with_gadm_ids
115
- }
127
+ }, sites_no_run
116
128
 
117
129
 
118
130
  def _run(sites: list, years: list = [], years_only: bool = False):
119
131
  rasters = list_rasters(years=years, years_only=years_only)
120
132
  vectors = [] if years_only else list_vectors(sites)
121
- filtered_data = _group_sites(sites, not years_only)
133
+ filtered_data, sites_no_run = _group_sites(sites, not years_only)
122
134
  return flatten([
123
135
  _run_values(filtered_data.get(param_type), param_type, rasters, vectors, years)
124
136
  for param_type in [e for e in ParamType] if len(filtered_data.get(param_type)) > 0
125
- ])
137
+ ] + _run_values(sites_no_run, years=years))
126
138
 
127
139
 
128
140
  def run(sites: list, years: list = None):
@@ -53,8 +53,8 @@ RETURNS = {
53
53
  }
54
54
  LOOKUPS = {
55
55
  "@doc": "Different lookup files are used depending on the situation",
56
- "ecoregion-siteType-LandOccupationChaudaryBrooks2018CF": "using `ecoregion`",
57
- "region-siteType-LandOccupationChaudaryBrooks2018CF": "using `country`"
56
+ "ecoregion-siteType-LandOccupationChaudaryBrooks2018CF": "",
57
+ "region-siteType-LandOccupationChaudaryBrooks2018CF": ""
58
58
  }
59
59
  TERM_ID = 'damageToTerrestrialEcosystemsLandOccupation'
60
60
  LOOKUP_SUFFIX = 'LandOccupationChaudaryBrooks2018CF'
@@ -41,8 +41,8 @@ RETURNS = {
41
41
  }
42
42
  LOOKUPS = {
43
43
  "@doc": "Different lookup files are used depending on the situation",
44
- "ecoregion-siteType-LandTransformationChaudaryBrooks2018CF": "using `ecoregion`",
45
- "region-siteType-LandTransformationChaudaryBrooks2018CF": "using `country`"
44
+ "ecoregion-siteType-LandTransformationChaudaryBrooks2018CF": "",
45
+ "region-siteType-LandTransformationChaudaryBrooks2018CF": ""
46
46
  }
47
47
  TERM_ID = 'damageToTerrestrialEcosystemsLandTransformation'
48
48
 
@@ -3,14 +3,14 @@ from hestia_earth.utils.tools import safe_parse_float
3
3
 
4
4
  from hestia_earth.models.log import debugMissingLookup, logRequirements
5
5
  from hestia_earth.models.utils.impact_assessment import get_site, get_country_id
6
+ from hestia_earth.models.utils.lookup import get_region_lookup_value
6
7
  from . import MODEL
7
8
 
8
9
 
9
- def _lookup_value(term_id: str, lookup_name: str, col_match: str, col_val: str, column: str, group_key: str = None):
10
- value = get_table_value(download_lookup(f"{lookup_name}.csv"), col_match, col_val, column_name(column))
11
- value = extract_grouped_data(value, group_key) if group_key else value
12
- debugMissingLookup(f"{lookup_name}.csv", col_match, col_val, column, value, model=MODEL, term=term_id)
13
- return safe_parse_float(value)
10
+ def _lookup_value(term_id: str, lookup_name: str, col_match: str, col_val: str, column: str):
11
+ value = get_table_value(download_lookup(lookup_name), col_match, col_val, column_name(column))
12
+ debugMissingLookup(lookup_name, col_match, col_val, column, value, model=MODEL, term=term_id)
13
+ return value
14
14
 
15
15
 
16
16
  def get_region_factor(term_id: str, impact_assessment: dict, lookup_suffix: str, group_key: str = None):
@@ -20,12 +20,17 @@ def get_region_factor(term_id: str, impact_assessment: dict, lookup_suffix: str,
20
20
  site_type = site.get('siteType')
21
21
 
22
22
  lookup_prefix = 'ecoregion' if ecoregion else 'region' if country_id else None
23
- col_name = 'ecoregion' if ecoregion else 'termid'
24
- col_val = ecoregion or country_id
23
+ lookup_name = f"{lookup_prefix}-siteType-{lookup_suffix}.csv"
25
24
 
26
25
  logRequirements(impact_assessment, model=MODEL, term=term_id,
27
26
  site_type=site_type,
28
27
  ecoregion=ecoregion,
29
28
  country_id=country_id)
30
29
 
31
- return _lookup_value(term_id, f"{lookup_prefix}-siteType-{lookup_suffix}", col_name, col_val, site_type, group_key)
30
+ value = get_region_lookup_value(
31
+ lookup_name, country_id, site_type, model=MODEL, term=term_id
32
+ ) if lookup_prefix == 'region' else _lookup_value(
33
+ term_id, lookup_name, 'ecoregion', ecoregion, site_type
34
+ )
35
+ value = extract_grouped_data(value, group_key) if group_key else value
36
+ return safe_parse_float(value)
@@ -17,7 +17,7 @@ Source: [JRC Technical reports Suggestions for updating the Product Environmenta
17
17
  Source: [Differences between EF model versions](https://eplca.jrc.ec.europa.eu/EFVersioning.html)
18
18
  """ # noqa: E501
19
19
  from itertools import chain
20
- from hestia_earth.utils.lookup import download_lookup, column_name
20
+ from hestia_earth.utils.lookup import download_lookup, column_name, find_term_ids_by
21
21
  from hestia_earth.utils.tools import list_sum, flatten
22
22
 
23
23
  from hestia_earth.models.log import logShouldRun, logRequirements, log_as_table
@@ -66,8 +66,7 @@ def get_all_non_renewable_terms(lookup_file_name: str, column: str) -> list:
66
66
  returns all non renewable term ids in lookup files like `electricity.csv` or `fuel.csv`
67
67
  """
68
68
  lookup = download_lookup(lookup_file_name)
69
- results = lookup[lookup[column_name(column)] == True]["termid"] # noqa: E712
70
- return list(map(str, results))
69
+ return find_term_ids_by(lookup, column_name(column), True)
71
70
 
72
71
 
73
72
  def _valid_resource_indicator(resource: dict) -> bool:
@@ -95,7 +95,7 @@ def _should_run(impact_assessment: dict) -> tuple[bool, list]:
95
95
  "indicator-input-is-valid": _valid_input(input),
96
96
  "value": _node_value(resource_indicator),
97
97
  "coefficient": get_table_value(
98
- array=download_lookup(filename=f"{input.get('termType')}.csv"),
98
+ lookup=download_lookup(filename=f"{input.get('termType')}.csv"),
99
99
  col_match='termid',
100
100
  col_match_with=input.get('@id'),
101
101
  col_val=column_name(LOOKUPS.get(input.get('termType'), ''))) if input else None
@@ -1,6 +1,6 @@
1
1
  """
2
2
  This model converts all "energy" terms found in a `Cycle > Inputs` to `MJ` using optional
3
- `energyContentHigherHeatingValue` and `density` properties or the term's "defaultProperties",
3
+ `energyContentLowerHeatingValue` and `density` properties or the term's "defaultProperties",
4
4
  aggregates them, and places them inside a 'resourceUseEnergyDepletionDuringCycle' indicator per aggregated input id.
5
5
  """
6
6
  from collections import defaultdict
@@ -12,7 +12,7 @@ from hestia_earth.utils.model import filter_list_term_type
12
12
  from hestia_earth.utils.tools import list_sum
13
13
 
14
14
  from hestia_earth.models.log import logRequirements, logShouldRun, log_as_table
15
- from hestia_earth.models.utils import Units
15
+ from hestia_earth.models.utils import Units, _include
16
16
  from hestia_earth.models.utils.blank_node import convert_unit
17
17
  from hestia_earth.models.utils.indicator import _new_indicator
18
18
  from . import MODEL
@@ -31,7 +31,7 @@ REQUIREMENTS = {
31
31
  {
32
32
  "@type": "Property",
33
33
  "value": "",
34
- "term.@id": "energyContentHigherHeatingValue",
34
+ "term.@id": "energyContentLowerHeatingValue",
35
35
  "term.units": "MJ / kg"
36
36
  },
37
37
  {
@@ -57,7 +57,7 @@ RETURNS = {
57
57
  }
58
58
 
59
59
  LOOKUPS = {
60
- "fuel": ["energyContentHigherHeatingValue", "density"]
60
+ "fuel": ["energyContentLowerHeatingValue", "density"]
61
61
  }
62
62
 
63
63
  TERM_ID = 'resourceUseEnergyDepletionDuringCycle'
@@ -123,12 +123,7 @@ def _should_run(cycle: dict) -> Tuple[bool, dict]:
123
123
  grouped_energy_terms[k].extend(list(v))
124
124
 
125
125
  logs = [
126
- {
127
- 'id': input.get('@id'),
128
- 'units': input.get('units'),
129
- 'termType': input.get('termType'),
130
- 'value': input.get('value'),
131
- 'value-in-MJ': input.get('value-in-MJ'),
126
+ _include(input, ['id', 'units', 'termType', 'value', 'value-in-MJ']) | {
132
127
  'properties': " ".join([
133
128
  f"{p.get('term', {}).get('@id')}= {p.get('value')} ({p.get('term', {}).get('units')})"
134
129
  for p in input.get('properties', [])
@@ -1183,6 +1183,21 @@
1183
1183
  },
1184
1184
  "stage": 2
1185
1185
  },
1186
+ {
1187
+ "key": "emissions",
1188
+ "model": "ipcc2019",
1189
+ "value": "nonCo2EmissionsToAirNaturalVegetationBurning",
1190
+ "runStrategy": "always",
1191
+ "runArgs": {
1192
+ "runNonMeasured": true,
1193
+ "runNonAddedTerm": true
1194
+ },
1195
+ "mergeStrategy": "list",
1196
+ "mergeArgs": {
1197
+ "replaceThreshold": ["value", 0.01]
1198
+ },
1199
+ "stage": 2
1200
+ },
1186
1201
  {
1187
1202
  "key": "emissions",
1188
1203
  "model": "schmidt2007",
@@ -865,7 +865,20 @@
865
865
  },
866
866
  "stage": 1
867
867
  },
868
-
868
+ {
869
+ "key": "impacts",
870
+ "model": "environmentalFootprintV3-1",
871
+ "value": "photochemicalOzoneCreationPotentialHumanHealthNmvocEq",
872
+ "runStrategy": "always",
873
+ "mergeStrategy": "list",
874
+ "mergeArgs": {
875
+ "replaceThreshold": [
876
+ "value",
877
+ 0.01
878
+ ]
879
+ },
880
+ "stage": 1
881
+ },
869
882
  {
870
883
  "key": "impacts",
871
884
  "model": "environmentalFootprintV3-1",
@@ -340,6 +340,14 @@
340
340
  "runStrategy": "add_blank_node_if_missing",
341
341
  "mergeStrategy": "list",
342
342
  "stage": 1
343
+ },
344
+ {
345
+ "key": "measurements",
346
+ "model": "geospatialDatabase",
347
+ "value": "altitude",
348
+ "runStrategy": "add_blank_node_if_missing",
349
+ "mergeStrategy": "list",
350
+ "stage": 1
343
351
  }
344
352
  ],
345
353
  [
@@ -4,7 +4,8 @@ Completeness Fresh Forage
4
4
  This model checks if we have the requirements below and updates the
5
5
  [Data Completeness](https://hestia.earth/schema/Completeness#cropResidue) value.
6
6
  """
7
- from hestia_earth.schema import SiteSiteType
7
+ from hestia_earth.schema import SiteSiteType, TermTermType
8
+ from hestia_earth.utils.model import filter_list_term_type
8
9
  from hestia_earth.utils.tools import list_sum
9
10
 
10
11
  from hestia_earth.models.log import logRequirements
@@ -46,18 +47,21 @@ ALLOWED_SITE_TYPES = [
46
47
  def _valid_input(input: dict): return is_from_model(input) and list_sum(input.get('value', [-1])) >= 0
47
48
 
48
49
 
50
+ def _inputs(node: dict): return filter_list_term_type(node.get('inputs', []), TermTermType.FORAGE)
51
+
52
+
49
53
  def run(cycle: dict):
50
54
  site_type = cycle.get('site', {}).get('siteType')
51
55
  site_type_allowed = site_type in ALLOWED_SITE_TYPES
52
56
 
53
- cycle_has_added_forage_input = any(map(_valid_input, cycle.get('inputs', [])))
57
+ cycle_has_added_forage_input = any(map(_valid_input, _inputs(cycle)))
54
58
 
55
59
  animals = [
56
60
  a for a in cycle.get('animals', [])
57
61
  if get_lookup_value(a.get('term', {}), 'isGrazingAnimal', model=MODEL, key=MODEL_KEY)
58
62
  ]
59
63
  all_animals_have_added_forage_input = bool(animals) and all([
60
- any(map(_valid_input, animal.get('inputs', []))) for animal in animals
64
+ any(map(_valid_input, _inputs(animal))) for animal in animals
61
65
  ])
62
66
 
63
67
  logRequirements(cycle, model=MODEL, term=None, key=MODEL_KEY,
@@ -4,12 +4,12 @@ Excreta (kg)
4
4
  This model calculates the amount of excreta in `kg` based on the amount of excreta in `kg N` or `kg Vs`.
5
5
  """
6
6
  from hestia_earth.schema import NodeType, TermTermType
7
- from hestia_earth.utils.api import download_hestia
8
7
  from hestia_earth.utils.model import filter_list_term_type, find_term_match
9
8
  from hestia_earth.utils.tools import non_empty_list, list_sum
10
9
 
11
10
  from hestia_earth.models.log import debugValues, logRequirements, logShouldRun
12
11
  from hestia_earth.models.utils import get_kg_term_id, get_kg_N_term_id, get_kg_VS_term_id
12
+ from hestia_earth.models.utils.term import download_term
13
13
  from hestia_earth.models.utils.constant import Units
14
14
  from hestia_earth.models.utils.product import _new_product, convert_product_to_unit
15
15
  from . import MODEL
@@ -68,7 +68,7 @@ def _run_product(cycle: dict, product_term_id: str):
68
68
  ]
69
69
 
70
70
  # convert to 1kg first, then apply ratio to current value
71
- term = download_hestia(product_term_id)
71
+ term = download_term(product_term_id, TermTermType.EXCRETA)
72
72
  product = {
73
73
  'term': term,
74
74
  'value': [1]
@@ -49,16 +49,28 @@ UNITS = [
49
49
  ]
50
50
  VALUE_BY_UNIT = {
51
51
  Units.KG_N.value: {
52
- Units.KG_K2O.value: lambda value, nContent, p2O5Content, k2OContent: value * k2OContent / nContent,
53
- Units.KG_P2O5.value: lambda value, nContent, p2O5Content, k2OContent: value * p2O5Content / nContent
52
+ Units.KG_K2O.value: lambda data: (
53
+ data.get('value') / data.get('nitrogenContent-divide')
54
+ ) * data.get('potassiumContentAsK2O-multiply'),
55
+ Units.KG_P2O5.value: lambda data: (
56
+ data.get('value') / data.get('nitrogenContent-divide')
57
+ ) * data.get('phosphateContentAsP2O5-multiply')
54
58
  },
55
59
  Units.KG_K2O.value: {
56
- Units.KG_N.value: lambda value, nContent, p2O5Content, k2OContent: value / k2OContent * nContent,
57
- Units.KG_P2O5.value: lambda value, nContent, p2O5Content, k2OContent: value / k2OContent * p2O5Content
60
+ Units.KG_N.value: lambda data: (
61
+ data.get('value') / data.get('potassiumContentAsK2O-divide')
62
+ ) * data.get('nitrogenContent-multiply'),
63
+ Units.KG_P2O5.value: lambda data: (
64
+ data.get('value') / data.get('potassiumContentAsK2O-divide')
65
+ ) * data.get('phosphateContentAsP2O5-multiply')
58
66
  },
59
67
  Units.KG_P2O5.value: {
60
- Units.KG_N.value: lambda value, nContent, p2O5Content, k2OContent: value / p2O5Content * nContent,
61
- Units.KG_K2O.value: lambda value, nContent, p2O5Content, k2OContent: value / p2O5Content * k2OContent
68
+ Units.KG_N.value: lambda data: (
69
+ data.get('value') / data.get('phosphateContentAsP2O5-divide')
70
+ ) * data.get('nitrogenContent-multiply'),
71
+ Units.KG_K2O.value: lambda data: (
72
+ data.get('value') / data.get('phosphateContentAsP2O5-divide')
73
+ ) * data.get('potassiumContentAsK2O-multiply')
62
74
  }
63
75
  }
64
76
 
@@ -81,6 +93,7 @@ def _include_term_ids(term_id: str):
81
93
 
82
94
  def _run_input(cycle: dict, input: dict):
83
95
  term_id = input.get('term', {}).get('@id')
96
+ input_term_ids = _include_term_ids(term_id)
84
97
  nitrogenContent = safe_parse_float(get_term_lookup(term_id, 'nitrogenContent'), 0)
85
98
  nitrogenContent_min = safe_parse_float(get_term_lookup(term_id, 'nitrogenContent-min'), None)
86
99
  nitrogenContent_max = safe_parse_float(get_term_lookup(term_id, 'nitrogenContent-max'), None)
@@ -96,28 +109,64 @@ def _run_input(cycle: dict, input: dict):
96
109
  min_values = non_empty_list([nitrogenContent_min, phosphateContentAsP2O5_min, potassiumContentAsK2O_min])
97
110
  max_values = non_empty_list([nitrogenContent_max, phosphateContentAsP2O5_max, potassiumContentAsK2O_max])
98
111
 
99
- def include_input(input_term_id):
112
+ def include_input(input_term_id: str):
100
113
  to_units = Units.KG_N.value if input_term_id.endswith('KgN') else (
101
114
  Units.KG_K2O.value if input_term_id.endswith('KgK2O') else Units.KG_P2O5.value
102
115
  )
103
116
 
104
117
  debugValues(cycle, model=MODEL_LOG, term=input_term_id,
118
+ from_input_id=term_id,
105
119
  from_units=from_units,
106
120
  to_units=to_units,
107
- input_value=input_value)
108
-
109
- value = VALUE_BY_UNIT.get(from_units, {}).get(to_units, lambda *args: None)(
110
- input_value, nitrogenContent, phosphateContentAsP2O5, potassiumContentAsK2O
121
+ input_value=input_value,
122
+ nitrogenContent=nitrogenContent,
123
+ nitrogenContent_min=nitrogenContent_min,
124
+ nitrogenContent_max=nitrogenContent_max,
125
+ phosphateContentAsP2O5=phosphateContentAsP2O5,
126
+ phosphateContentAsP2O5_min=phosphateContentAsP2O5_min,
127
+ phosphateContentAsP2O5_max=phosphateContentAsP2O5_max,
128
+ potassiumContentAsK2O=potassiumContentAsK2O,
129
+ potassiumContentAsK2O_min=potassiumContentAsK2O_min,
130
+ potassiumContentAsK2O_max=potassiumContentAsK2O_max)
131
+
132
+ converter = VALUE_BY_UNIT.get(from_units, {}).get(to_units, lambda *args: None)
133
+ value = converter(
134
+ {
135
+ 'value': input_value,
136
+ 'nitrogenContent-multiply': nitrogenContent,
137
+ 'nitrogenContent-divide': nitrogenContent,
138
+ 'phosphateContentAsP2O5-multiply': phosphateContentAsP2O5,
139
+ 'phosphateContentAsP2O5-divide': phosphateContentAsP2O5,
140
+ 'potassiumContentAsK2O-multiply': potassiumContentAsK2O,
141
+ 'potassiumContentAsK2O-divide': potassiumContentAsK2O,
142
+ }
111
143
  )
112
- min = VALUE_BY_UNIT.get(from_units, {}).get(to_units, lambda *args: None)(
113
- input_value, nitrogenContent_min, phosphateContentAsP2O5_min, potassiumContentAsK2O_min
144
+ min = converter(
145
+ {
146
+ 'value': input_value,
147
+ 'nitrogenContent-multiply': nitrogenContent_min,
148
+ 'nitrogenContent-divide': nitrogenContent_max,
149
+ 'phosphateContentAsP2O5-multiply': phosphateContentAsP2O5_min,
150
+ 'phosphateContentAsP2O5-divide': phosphateContentAsP2O5_max,
151
+ 'potassiumContentAsK2O-multiply': potassiumContentAsK2O_min,
152
+ 'potassiumContentAsK2O-divide': potassiumContentAsK2O_max,
153
+ }
114
154
  ) if len(min_values) >= 2 else None
115
- max = VALUE_BY_UNIT.get(from_units, {}).get(to_units, lambda *args: None)(
116
- input_value, nitrogenContent_max, phosphateContentAsP2O5_max, potassiumContentAsK2O_max
155
+ max = converter(
156
+ {
157
+ 'value': input_value,
158
+ 'nitrogenContent-multiply': nitrogenContent_max,
159
+ 'nitrogenContent-divide': nitrogenContent_min,
160
+ 'phosphateContentAsP2O5-multiply': phosphateContentAsP2O5_max,
161
+ 'phosphateContentAsP2O5-divide': phosphateContentAsP2O5_min,
162
+ 'potassiumContentAsK2O-multiply': potassiumContentAsK2O_max,
163
+ 'potassiumContentAsK2O-divide': potassiumContentAsK2O_min,
164
+ }
117
165
  ) if len(max_values) >= 2 else None
166
+
118
167
  return _input(input_term_id, value, min, max) if value else None
119
168
 
120
- return list(map(include_input, _include_term_ids(term_id)))
169
+ return list(map(include_input, input_term_ids))
121
170
 
122
171
 
123
172
  def _should_run_input(cycle: dict, input: dict):
@@ -130,7 +179,8 @@ def _should_run_input(cycle: dict, input: dict):
130
179
  # skip inputs that already have all the inlcuded term with a value
131
180
  inputs = cycle.get('inputs', [])
132
181
  include_term_ids = [
133
- term_id for term_id in _include_term_ids(term_id) if len(find_term_match(inputs, term_id).get('value', [])) == 0
182
+ term_id for term_id in _include_term_ids(term_id)
183
+ if len(find_term_match(inputs, term_id).get('value', [])) == 0
134
184
  ]
135
185
  should_run = all([
136
186
  has_value,
@@ -5,7 +5,7 @@ This model gap-fills depreciated amount per Cycle from Site Infrastructure node.
5
5
  """
6
6
  from typing import Union
7
7
  from hestia_earth.schema import TermTermType
8
- from hestia_earth.utils.lookup import download_lookup
8
+ from hestia_earth.utils.lookup import download_lookup, lookup_term_ids
9
9
  from hestia_earth.utils.tools import to_precision, flatten, list_sum
10
10
  from hestia_earth.utils.model import filter_list_term_type
11
11
 
@@ -100,7 +100,8 @@ def _run_input(cycle: dict, input_node: dict) -> dict:
100
100
 
101
101
  def _has_depreciated_term(term: dict):
102
102
  lookup = download_lookup(f"{term.get('termType')}.csv")
103
- return term.get('@id') + _ID_SUFFIX in list(lookup.termid)
103
+ term_ids = lookup_term_ids(lookup)
104
+ return term.get('@id') + _ID_SUFFIX in term_ids
104
105
 
105
106
 
106
107
  def _should_run_input(cycle: dict, input_node: dict) -> bool:
@@ -1,9 +1,9 @@
1
- from hestia_earth.schema import SiteSiteType
2
- from hestia_earth.utils.api import download_hestia
1
+ from hestia_earth.schema import SiteSiteType, TermTermType
3
2
  from hestia_earth.utils.model import linked_node
4
3
 
5
4
  from hestia_earth.models.log import logRequirements, logShouldRun
6
5
  from hestia_earth.models.utils.practice import _new_practice
6
+ from hestia_earth.models.utils.term import download_term
7
7
  from . import MODEL
8
8
 
9
9
  REQUIREMENTS = {
@@ -27,7 +27,7 @@ KEY_TERM_ID = 'genericGrassPlant'
27
27
  def _practice():
28
28
  node = _new_practice(TERM_ID)
29
29
  node['value'] = [100]
30
- node['key'] = linked_node(download_hestia(KEY_TERM_ID))
30
+ node['key'] = linked_node(download_term(KEY_TERM_ID, TermTermType.LANDCOVER))
31
31
  return node
32
32
 
33
33
 
@@ -15,7 +15,7 @@ REQUIREMENTS = {
15
15
  }
16
16
  }
17
17
  LOOKUPS = {
18
- "excretaManagement": "EF_NON-N"
18
+ "excretaManagement": "EF_NO-N"
19
19
  }
20
20
  RETURNS = {
21
21
  "Emission": [{