hestia-earth-models 0.70.0__py3-none-any.whl → 0.70.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hestia_earth/models/aware/scarcityWeightedWaterUse.py +8 -16
- hestia_earth/models/cml2001Baseline/resourceUseMineralsAndMetalsDuringCycle.py +2 -1
- hestia_earth/models/config/Cycle.json +98 -50
- hestia_earth/models/config/ImpactAssessment.json +12 -4
- hestia_earth/models/config/Site.json +40 -21
- hestia_earth/models/cycle/transformation.py +1 -1
- hestia_earth/models/cycle/utils.py +0 -6
- hestia_earth/models/data/ecoinventV3/__init__.py +15 -13
- hestia_earth/models/ecoalimV9/__init__.py +13 -0
- hestia_earth/models/ecoalimV9/cycle.py +128 -0
- hestia_earth/models/ecoalimV9/impact_assessment.py +125 -0
- hestia_earth/models/ecoalimV9/utils.py +31 -0
- hestia_earth/models/ecoinventV3/__init__.py +6 -14
- hestia_earth/models/ecoinventV3/utils.py +1 -29
- hestia_earth/models/ecoinventV3AndEmberClimate/__init__.py +8 -2
- hestia_earth/models/emissionNotRelevant/__init__.py +33 -8
- hestia_earth/models/{cycle → hestia}/aboveGroundCropResidue.py +4 -3
- hestia_earth/models/{cycle → hestia}/aboveGroundCropResidueTotal.py +1 -1
- hestia_earth/models/{site → hestia}/brackishWater.py +1 -1
- hestia_earth/models/{site → hestia}/cationExchangeCapacityPerKgSoil.py +1 -1
- hestia_earth/models/{cycle → hestia}/coldCarcassWeightPerHead.py +1 -1
- hestia_earth/models/{cycle → hestia}/coldDressedCarcassWeightPerHead.py +1 -1
- hestia_earth/models/{cycle → hestia}/concentrateFeed.py +1 -1
- hestia_earth/models/{cycle → hestia}/cropResidueManagement.py +1 -1
- hestia_earth/models/{cycle → hestia}/croppingIntensity.py +1 -1
- hestia_earth/models/{cycle → hestia}/energyContentLowerHeatingValue.py +1 -1
- hestia_earth/models/{cycle → hestia}/excretaKgMass.py +8 -3
- hestia_earth/models/{cycle → hestia}/excretaKgN.py +1 -1
- hestia_earth/models/{cycle → hestia}/excretaKgVs.py +1 -1
- hestia_earth/models/{cycle → hestia}/feedConversionRatio/__init__.py +1 -1
- hestia_earth/models/{site → hestia}/flowingWater.py +1 -1
- hestia_earth/models/{site → hestia}/freshWater.py +1 -1
- hestia_earth/models/{cycle → hestia}/inorganicFertiliser.py +1 -1
- hestia_earth/models/{cycle → hestia}/irrigatedTypeUnspecified.py +14 -19
- hestia_earth/models/hestia/landCover.py +30 -22
- hestia_earth/models/{cycle → hestia}/liveAnimal.py +1 -1
- hestia_earth/models/{cycle → hestia}/longFallowRatio.py +1 -1
- hestia_earth/models/{site → hestia}/management.py +4 -6
- hestia_earth/models/{cycle → hestia}/materialAndSubstrate.py +1 -1
- hestia_earth/models/{cycle → hestia}/milkYield.py +1 -1
- hestia_earth/models/{site → hestia}/netPrimaryProduction.py +1 -1
- hestia_earth/models/{site → hestia}/organicCarbonPerHa.py +1 -1
- hestia_earth/models/hestia/pToSurfaceWaterAquacultureSystems.py +148 -0
- hestia_earth/models/{cycle → hestia}/pastureGrass.py +1 -1
- hestia_earth/models/{cycle → hestia}/pastureSystem.py +1 -1
- hestia_earth/models/{site → hestia}/potentialEvapotranspirationAnnual.py +3 -3
- hestia_earth/models/{site → hestia}/potentialEvapotranspirationMonthly.py +3 -3
- hestia_earth/models/{site → hestia}/precipitationAnnual.py +3 -3
- hestia_earth/models/{site → hestia}/precipitationMonthly.py +3 -3
- hestia_earth/models/{site → hestia}/rainfallAnnual.py +3 -3
- hestia_earth/models/{site → hestia}/rainfallMonthly.py +3 -3
- hestia_earth/models/{cycle → hestia}/readyToCookWeightPerHead.py +1 -1
- hestia_earth/models/{cycle → hestia}/residueBurnt.py +1 -1
- hestia_earth/models/{cycle → hestia}/residueIncorporated.py +1 -1
- hestia_earth/models/{cycle → hestia}/residueLeftOnField.py +1 -1
- hestia_earth/models/hestia/residueRemoved.py +65 -13
- hestia_earth/models/{site → hestia}/salineWater.py +1 -1
- hestia_earth/models/{site → hestia}/soilMeasurement.py +1 -1
- hestia_earth/models/{cycle → hestia}/stockingDensityAnimalHousingAverage.py +1 -1
- hestia_earth/models/{site → hestia}/temperatureAnnual.py +3 -3
- hestia_earth/models/{site → hestia}/temperatureMonthly.py +3 -3
- hestia_earth/models/{site → hestia}/totalNitrogenPerKgSoil.py +1 -1
- hestia_earth/models/{cycle → hestia}/unknownPreSeasonWaterRegime.py +1 -1
- hestia_earth/models/hestia/utils.py +93 -0
- hestia_earth/models/{site → hestia}/waterDepth.py +1 -1
- hestia_earth/models/hestia/waterSalinity.py +78 -0
- hestia_earth/models/ipcc2019/aboveGroundBiomass.py +1 -1
- hestia_earth/models/ipcc2019/belowGroundBiomass.py +1 -1
- hestia_earth/models/ipcc2019/biomass_utils.py +2 -4
- hestia_earth/models/ipcc2019/ch4ToAirFloodedRice.py +166 -79
- hestia_earth/models/ipcc2019/ch4ToAirOrganicSoilCultivation.py +270 -0
- hestia_earth/models/ipcc2019/co2ToAirAboveGroundBiomassStockChange.py +0 -3
- hestia_earth/models/ipcc2019/co2ToAirBelowGroundBiomassStockChange.py +0 -3
- hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +88 -63
- hestia_earth/models/ipcc2019/co2ToAirLimeHydrolysis.py +7 -5
- hestia_earth/models/ipcc2019/co2ToAirOrganicSoilCultivation.py +215 -0
- hestia_earth/models/ipcc2019/co2ToAirSoilOrganicCarbonStockChange.py +0 -3
- hestia_earth/models/ipcc2019/co2ToAirUreaHydrolysis.py +16 -9
- hestia_earth/models/ipcc2019/n2OToAirOrganicSoilCultivationDirect.py +161 -0
- hestia_earth/models/ipcc2019/nonCo2EmissionsToAirNaturalVegetationBurning.py +35 -47
- hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_1.py +86 -1
- hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_2.py +127 -1
- hestia_earth/models/ipcc2019/organicCarbonPerHa_utils.py +7 -5
- hestia_earth/models/ipcc2019/organicSoilCultivation_utils.py +159 -0
- hestia_earth/models/mocking/search-results.json +1113 -1113
- hestia_earth/models/pooreNemecek2018/utils.py +8 -2
- hestia_earth/models/schmidt2007/ch4ToAirWasteTreatment.py +1 -4
- hestia_earth/models/schmidt2007/h2SToAirWasteTreatment.py +1 -4
- hestia_earth/models/schmidt2007/n2OToAirWasteTreatmentDirect.py +1 -4
- hestia_earth/models/schmidt2007/nh3ToAirWasteTreatment.py +1 -4
- hestia_earth/models/site/grouped_measurement.py +132 -0
- hestia_earth/models/utils/__init__.py +4 -3
- hestia_earth/models/utils/background_emissions.py +52 -0
- hestia_earth/models/utils/blank_node.py +47 -14
- hestia_earth/models/utils/constant.py +26 -20
- hestia_earth/models/utils/impact_assessment.py +26 -17
- hestia_earth/models/utils/lookup.py +48 -39
- hestia_earth/models/utils/measurement.py +3 -3
- hestia_earth/models/utils/product.py +39 -1
- hestia_earth/models/utils/property.py +14 -6
- hestia_earth/models/version.py +1 -1
- {hestia_earth_models-0.70.0.dist-info → hestia_earth_models-0.70.2.dist-info}/METADATA +2 -2
- {hestia_earth_models-0.70.0.dist-info → hestia_earth_models-0.70.2.dist-info}/RECORD +187 -171
- tests/models/aware/test_scarcityWeightedWaterUse.py +1 -12
- tests/models/ecoalimV9/__init__.py +0 -0
- tests/models/ecoalimV9/test_cycle.py +21 -0
- tests/models/ecoalimV9/test_impact_assessment.py +24 -0
- tests/models/environmentalFootprintV3_1/test_scarcityWeightedWaterUse.py +4 -2
- tests/models/{cycle → hestia}/test_aboveGroundCropResidue.py +1 -1
- tests/models/{cycle → hestia}/test_aboveGroundCropResidueTotal.py +1 -1
- tests/models/{site → hestia}/test_brackishWater.py +1 -1
- tests/models/{site → hestia}/test_cationExchangeCapacityPerKgSoil.py +1 -1
- tests/models/{cycle → hestia}/test_coldCarcassWeightPerHead.py +1 -1
- tests/models/{cycle → hestia}/test_coldDressedCarcassWeightPerHead.py +1 -1
- tests/models/{cycle → hestia}/test_concentrateFeed.py +1 -1
- tests/models/{cycle → hestia}/test_cropResidueManagement.py +1 -1
- tests/models/{cycle → hestia}/test_croppingIntensity.py +1 -1
- tests/models/{cycle → hestia}/test_energyContentLowerHeatingValue.py +5 -3
- tests/models/{cycle → hestia}/test_excretaKgMass.py +1 -1
- tests/models/{cycle → hestia}/test_excretaKgN.py +1 -1
- tests/models/{cycle → hestia}/test_excretaKgVs.py +1 -1
- tests/models/{cycle → hestia}/test_feedConversionRatio.py +3 -4
- tests/models/{site → hestia}/test_flowingWater.py +1 -1
- tests/models/{site → hestia}/test_freshWater.py +1 -1
- tests/models/{cycle → hestia}/test_inorganicFertiliser.py +1 -1
- tests/models/{cycle → hestia}/test_irrigatedTypeUnspecified.py +2 -5
- tests/models/hestia/test_landCover.py +4 -34
- tests/models/{cycle → hestia}/test_liveAnimal.py +1 -1
- tests/models/{cycle → hestia}/test_longFallowRatio.py +1 -1
- tests/models/{site → hestia}/test_management.py +1 -1
- tests/models/{cycle → hestia}/test_materialsAndSubstrate.py +1 -1
- tests/models/{cycle → hestia}/test_milkYield.py +1 -1
- tests/models/{site → hestia}/test_netPrimaryProduction.py +1 -1
- tests/models/{site → hestia}/test_organicCarbonPerHa.py +1 -1
- tests/models/{site → hestia}/test_organicCarbonPerKgSoil.py +1 -1
- tests/models/{site → hestia}/test_organicCarbonPerM3Soil.py +1 -1
- tests/models/{site → hestia}/test_organicMatterPerKgSoil.py +1 -1
- tests/models/{site → hestia}/test_organicMatterPerM3Soil.py +1 -1
- tests/models/hestia/test_pToSurfaceWaterAquacultureSystems.py +56 -0
- tests/models/{cycle → hestia}/test_pastureGrass.py +1 -1
- tests/models/{cycle → hestia}/test_pastureSystem.py +1 -1
- tests/models/{site → hestia}/test_potentialEvapotranspirationAnnual.py +1 -1
- tests/models/{site → hestia}/test_potentialEvapotranspirationMonthly.py +1 -1
- tests/models/{site → hestia}/test_precipitationAnnual.py +1 -1
- tests/models/{site → hestia}/test_precipitationMonthly.py +1 -1
- tests/models/{site → hestia}/test_rainfallAnnual.py +1 -1
- tests/models/{site → hestia}/test_rainfallMonthly.py +1 -1
- tests/models/{cycle → hestia}/test_readyToCookWeightPerHead.py +1 -1
- tests/models/{cycle → hestia}/test_residueBurnt.py +1 -1
- tests/models/{cycle → hestia}/test_residueIncorporated.py +1 -1
- tests/models/{cycle → hestia}/test_residueLeftOnField.py +1 -1
- tests/models/hestia/test_residueRemoved.py +15 -3
- tests/models/{site → hestia}/test_salineWater.py +1 -1
- tests/models/{site → hestia}/test_soilMeasurement.py +13 -21
- tests/models/{cycle → hestia}/test_stockingDensityAnimalHousingAverage.py +1 -1
- tests/models/{site → hestia}/test_temperatureAnnual.py +1 -1
- tests/models/{site → hestia}/test_temperatureMonthly.py +1 -1
- tests/models/{site → hestia}/test_totalNitrogenPerKgSoil.py +1 -1
- tests/models/{cycle → hestia}/test_unknownPreSeasonWaterRegime.py +1 -1
- tests/models/{site → hestia}/test_waterDepth.py +1 -1
- tests/models/hestia/test_waterSalinity.py +26 -0
- tests/models/ipcc2019/test_ch4ToAirEntericFermentation.py +2 -5
- tests/models/ipcc2019/test_ch4ToAirFloodedRice.py +10 -42
- tests/models/ipcc2019/test_ch4ToAirOrganicSoilCultivation.py +61 -0
- tests/models/ipcc2019/test_co2ToAirAboveGroundBiomassStockChange.py +11 -9
- tests/models/ipcc2019/test_co2ToAirBelowGroundBiomassStockChange.py +10 -8
- tests/models/ipcc2019/test_co2ToAirLimeHydrolysis.py +1 -1
- tests/models/ipcc2019/test_co2ToAirOrganicSoilCultivation.py +62 -0
- tests/models/ipcc2019/test_co2ToAirSoilOrganicCarbonStockChange.py +11 -8
- tests/models/ipcc2019/test_n2OToAirOrganicSoilCultivationDirect.py +61 -0
- tests/models/ipcc2019/test_nonCo2EmissionsToAirNaturalVegetationBurning.py +3 -2
- tests/models/site/test_grouped_measurement.py +20 -0
- tests/models/test_ecoinventV3AndEmberClimate.py +2 -2
- tests/models/test_emissionNotRelevant.py +0 -8
- tests/models/utils/test_measurement.py +1 -1
- hestia_earth/models/cycle/residueRemoved.py +0 -54
- hestia_earth/models/hestia/nh3ToSurfaceWaterAquacultureSystems.py +0 -64
- hestia_earth/models/site/utils.py +0 -93
- tests/models/cycle/test_residueRemoved.py +0 -37
- tests/models/hestia/test_nh3ToSurfaceWaterAquacultureSystems.py +0 -51
- /hestia_earth/models/{cycle → hestia}/feedConversionRatio/feedConversionRatioCarbon.py +0 -0
- /hestia_earth/models/{cycle → hestia}/feedConversionRatio/feedConversionRatioDryMatter.py +0 -0
- /hestia_earth/models/{cycle → hestia}/feedConversionRatio/feedConversionRatioEnergy.py +0 -0
- /hestia_earth/models/{cycle → hestia}/feedConversionRatio/feedConversionRatioFedWeight.py +0 -0
- /hestia_earth/models/{cycle → hestia}/feedConversionRatio/feedConversionRatioNitrogen.py +0 -0
- /hestia_earth/models/{site → hestia}/organicCarbonPerKgSoil.py +0 -0
- /hestia_earth/models/{site → hestia}/organicCarbonPerM3Soil.py +0 -0
- /hestia_earth/models/{site → hestia}/organicMatterPerKgSoil.py +0 -0
- /hestia_earth/models/{site → hestia}/organicMatterPerM3Soil.py +0 -0
- {hestia_earth_models-0.70.0.dist-info → hestia_earth_models-0.70.2.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.70.0.dist-info → hestia_earth_models-0.70.2.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.70.0.dist-info → hestia_earth_models-0.70.2.dist-info}/top_level.txt +0 -0
@@ -31,12 +31,18 @@ def run_products_average(cycle: dict, term_id: str, get_value_func):
|
|
31
31
|
return list_average(values) if should_run else None
|
32
32
|
|
33
33
|
|
34
|
+
def _excreta_product_id(data: str, term_id):
|
35
|
+
value = extract_grouped_data(data, term_id) or ''
|
36
|
+
return value.split('|')[0] if '|' in value else value
|
37
|
+
|
38
|
+
|
34
39
|
def get_excreta_product_with_ratio(cycle: dict, lookup: str, **log_args):
|
35
40
|
product = find_primary_product(cycle) or {}
|
36
41
|
|
37
42
|
data = get_lookup_value(product.get('term'), lookup, model=MODEL, **log_args)
|
38
43
|
|
39
|
-
|
44
|
+
# TODO: handle multiple products delimited by `|`
|
45
|
+
default_product_id = _excreta_product_id(data, 'default')
|
40
46
|
|
41
47
|
# find matching practices and assign a ratio for each
|
42
48
|
# if no matches, use default id with 100% ratio
|
@@ -44,7 +50,7 @@ def get_excreta_product_with_ratio(cycle: dict, lookup: str, **log_args):
|
|
44
50
|
practices = [
|
45
51
|
{
|
46
52
|
'id': practice.get('term', {}).get('@id'),
|
47
|
-
'product-id':
|
53
|
+
'product-id': _excreta_product_id(data, practice.get('term', {}).get('@id')) or default_product_id,
|
48
54
|
'value': list_sum(practice.get('value'))
|
49
55
|
}
|
50
56
|
for practice in practices
|
@@ -0,0 +1,132 @@
|
|
1
|
+
from functools import reduce
|
2
|
+
from hestia_earth.schema import MeasurementMethodClassification
|
3
|
+
from hestia_earth.utils.tools import non_empty_list, flatten, is_number, list_sum
|
4
|
+
|
5
|
+
from hestia_earth.models.log import logRequirements, logShouldRun
|
6
|
+
from hestia_earth.models.utils import _include
|
7
|
+
from hestia_earth.models.utils.measurement import _new_measurement
|
8
|
+
from hestia_earth.models.utils.blank_node import get_lookup_value
|
9
|
+
from . import MODEL
|
10
|
+
|
11
|
+
REQUIREMENTS = {
|
12
|
+
"Site": {
|
13
|
+
"measurements": [
|
14
|
+
{"@type": "Measurement", "depthUpper": "", "depthLower": "", "value": ""}
|
15
|
+
]
|
16
|
+
}
|
17
|
+
}
|
18
|
+
RETURNS = {
|
19
|
+
"Measurement": [{
|
20
|
+
"value": "0",
|
21
|
+
"depthUpper": "",
|
22
|
+
"depthLower": "",
|
23
|
+
"dates": "",
|
24
|
+
"methodClassification": "modelled using other measurements"
|
25
|
+
}]
|
26
|
+
}
|
27
|
+
LOOKUPS = {
|
28
|
+
"measurement": ["sumIs100Group", "sumMax100Group"]
|
29
|
+
}
|
30
|
+
MODEL_KEY = 'grouped_measurement'
|
31
|
+
|
32
|
+
|
33
|
+
def _measurement(term_id: str, measurement: dict):
|
34
|
+
data = _new_measurement(term_id) | _include(measurement, [
|
35
|
+
'depthUpper', 'depthLower', 'startDate', 'endDate', 'dates'
|
36
|
+
])
|
37
|
+
data["value"] = [0]
|
38
|
+
data["methodClassification"] = MeasurementMethodClassification.MODELLED_USING_OTHER_MEASUREMENTS.value
|
39
|
+
return data
|
40
|
+
|
41
|
+
|
42
|
+
def _measurement_term_ids(measurements: list):
|
43
|
+
return list(set([m.get('term', {}).get('@id') for m in measurements]))
|
44
|
+
|
45
|
+
|
46
|
+
def _formatDepth(depth: str):
|
47
|
+
# handle float values
|
48
|
+
return str(int(depth)) if is_number(depth) else ''
|
49
|
+
|
50
|
+
|
51
|
+
def _group_by_depth(measurements: list):
|
52
|
+
def group_by(group: dict, measurement: dict):
|
53
|
+
keys = non_empty_list([
|
54
|
+
_formatDepth(measurement.get('depthUpper')),
|
55
|
+
_formatDepth(measurement.get('depthLower'))
|
56
|
+
])
|
57
|
+
key = '-'.join(keys) if len(keys) > 0 else 'default'
|
58
|
+
group[key] = group.get(key, []) + [measurement]
|
59
|
+
return group
|
60
|
+
|
61
|
+
return reduce(group_by, measurements, {})
|
62
|
+
|
63
|
+
|
64
|
+
def _run_measurements(site: dict, all_term_ids: list, measurements: list):
|
65
|
+
term_ids = _measurement_term_ids(measurements)
|
66
|
+
|
67
|
+
# check the total value is 100%
|
68
|
+
total_value = list_sum([
|
69
|
+
list_sum(m.get('value')) for m in measurements
|
70
|
+
])
|
71
|
+
is_total_100 = 99.5 <= total_value <= 100.5
|
72
|
+
|
73
|
+
should_run = all([is_total_100])
|
74
|
+
|
75
|
+
other_term_ids = [v for v in all_term_ids if v not in term_ids]
|
76
|
+
for term_id in other_term_ids:
|
77
|
+
logRequirements(site, model=MODEL, term=term_id, model_key=MODEL_KEY,
|
78
|
+
total_value=total_value)
|
79
|
+
|
80
|
+
logShouldRun(site, MODEL, term_id, should_run, model_key=MODEL_KEY)
|
81
|
+
|
82
|
+
return [
|
83
|
+
_measurement(term_id=term_id, measurement=measurements[0])
|
84
|
+
for term_id in other_term_ids
|
85
|
+
] if should_run else []
|
86
|
+
|
87
|
+
|
88
|
+
def _run(site: dict, measurements: list):
|
89
|
+
term_ids = _measurement_term_ids(measurements)
|
90
|
+
grouped_measurements = _group_by_depth(measurements)
|
91
|
+
|
92
|
+
return flatten([
|
93
|
+
_run_measurements(site, term_ids, values)
|
94
|
+
for values in grouped_measurements.values()
|
95
|
+
]) if len(grouped_measurements.keys()) > 1 else []
|
96
|
+
|
97
|
+
|
98
|
+
def _group_by_100group(measurements: list):
|
99
|
+
def group_by(group: dict, measurement: dict):
|
100
|
+
term = measurement.get('term', {})
|
101
|
+
sum_group_key = (
|
102
|
+
get_lookup_value(term, 'sumIs100Group', skip_debug=True, model=MODEL) or
|
103
|
+
get_lookup_value(term, 'sumMax100Group', skip_debug=True, model=MODEL)
|
104
|
+
)
|
105
|
+
keys = non_empty_list([
|
106
|
+
sum_group_key,
|
107
|
+
measurement.get('startDate'),
|
108
|
+
measurement.get('endDate'),
|
109
|
+
'-'.join(measurement.get('dates') or []),
|
110
|
+
])
|
111
|
+
key = '-'.join(keys) if len(keys) > 0 else 'default'
|
112
|
+
|
113
|
+
if all([
|
114
|
+
sum_group_key,
|
115
|
+
measurement.get('value', []),
|
116
|
+
measurement.get('depthUpper') is not None,
|
117
|
+
measurement.get('depthLower') is not None
|
118
|
+
]):
|
119
|
+
group[key] = group.get(key, []) + [measurement]
|
120
|
+
|
121
|
+
return group
|
122
|
+
|
123
|
+
return reduce(group_by, measurements, {})
|
124
|
+
|
125
|
+
|
126
|
+
def run(site: dict):
|
127
|
+
grouped_measurements = _group_by_100group(site.get('measurements', []))
|
128
|
+
return flatten([
|
129
|
+
_run(site, values)
|
130
|
+
for values in grouped_measurements.values()
|
131
|
+
if len(values) > 1
|
132
|
+
])
|
@@ -8,7 +8,7 @@ import datetime
|
|
8
8
|
from functools import reduce
|
9
9
|
import operator
|
10
10
|
from pydash.objects import get
|
11
|
-
from typing import
|
11
|
+
from typing import Union, List, Callable
|
12
12
|
from hestia_earth.schema import SchemaType
|
13
13
|
from hestia_earth.utils.api import download_hestia
|
14
14
|
from hestia_earth.utils.tools import flatten, non_empty_list
|
@@ -54,8 +54,9 @@ def _load_calculated_node(node, type: SchemaType, data_state='recalculated'):
|
|
54
54
|
def _unit_str(unit) -> str: return unit if isinstance(unit, str) else unit.value
|
55
55
|
|
56
56
|
|
57
|
-
def _filter_list_term_unit(values: list, unit:
|
58
|
-
units =
|
57
|
+
def _filter_list_term_unit(values: list, unit: Union[str, List[str]]):
|
58
|
+
units = unit if isinstance(unit, list) else[unit]
|
59
|
+
units = list(map(_unit_str, units))
|
59
60
|
return list(filter(lambda i: i.get('term', {}).get('units') in units, values))
|
60
61
|
|
61
62
|
|
@@ -0,0 +1,52 @@
|
|
1
|
+
from hestia_earth.utils.model import find_term_match
|
2
|
+
from hestia_earth.utils.tools import flatten
|
3
|
+
|
4
|
+
from . import is_from_model
|
5
|
+
|
6
|
+
|
7
|
+
def _animal_inputs(animal: dict):
|
8
|
+
inputs = animal.get('inputs', [])
|
9
|
+
return [(input | {'animal': animal.get('term', {})}) for input in inputs]
|
10
|
+
|
11
|
+
|
12
|
+
def _should_run_input(products: list):
|
13
|
+
def should_run(input: dict):
|
14
|
+
return all([
|
15
|
+
# make sure Input is not a Product as well or we might double-count emissions
|
16
|
+
find_term_match(products, input.get('term', {}).get('@id'), None) is None,
|
17
|
+
# ignore inputs which are flagged as Product of the Cycle
|
18
|
+
not input.get('fromCycle', False),
|
19
|
+
not input.get('producedInCycle', False)
|
20
|
+
])
|
21
|
+
return should_run
|
22
|
+
|
23
|
+
|
24
|
+
def get_background_inputs(cycle: dict, extra_inputs: list = []):
|
25
|
+
# add all the properties of some Term that inlcude others with the mapping
|
26
|
+
inputs = flatten(
|
27
|
+
cycle.get('inputs', []) +
|
28
|
+
list(map(_animal_inputs, cycle.get('animals', []))) +
|
29
|
+
extra_inputs
|
30
|
+
)
|
31
|
+
return list(filter(_should_run_input(cycle.get('products', [])), inputs))
|
32
|
+
|
33
|
+
|
34
|
+
def no_gap_filled_background_emissions(cycle: dict):
|
35
|
+
emissions = cycle.get('emissions', [])
|
36
|
+
|
37
|
+
def check_input(input: dict):
|
38
|
+
input_term_id = input.get('term', {}).get('@id')
|
39
|
+
operation_term_id = input.get('operation', {}).get('@id')
|
40
|
+
animal_term_id = input.get('animal', {}).get('@id')
|
41
|
+
|
42
|
+
return not any([
|
43
|
+
is_from_model(emission)
|
44
|
+
for emission in emissions
|
45
|
+
if all([
|
46
|
+
any([i.get('@id') == input_term_id for i in emission.get('inputs', [])]),
|
47
|
+
emission.get('operation', {}).get('@id') == operation_term_id,
|
48
|
+
emission.get('animal', {}).get('@id') == animal_term_id
|
49
|
+
])
|
50
|
+
])
|
51
|
+
|
52
|
+
return check_input
|
@@ -22,11 +22,11 @@ from hestia_earth.utils.tools import (
|
|
22
22
|
list_sum,
|
23
23
|
list_average,
|
24
24
|
safe_parse_date,
|
25
|
-
safe_parse_float,
|
26
25
|
non_empty_list
|
27
26
|
)
|
28
27
|
from hestia_earth.utils.lookup_utils import (
|
29
28
|
is_model_siteType_allowed,
|
29
|
+
is_model_product_id_allowed,
|
30
30
|
is_siteType_allowed,
|
31
31
|
is_product_id_allowed,
|
32
32
|
is_product_termType_allowed,
|
@@ -124,13 +124,16 @@ def _module_term_id(term_id: str, module):
|
|
124
124
|
return getattr(module, 'TERM_ID', term_id_str).split(',')[0]
|
125
125
|
|
126
126
|
|
127
|
-
def _run_model_required(model: str, term_id: str, data: dict):
|
127
|
+
def _run_model_required(model: str, term_id: str, data: dict, skip_logs: bool = False):
|
128
128
|
siteType_allowed = is_model_siteType_allowed(model, term_id, data)
|
129
|
+
product_id_allowed = is_model_product_id_allowed(model, term_id, data)
|
129
130
|
|
130
|
-
run_required = all([siteType_allowed])
|
131
|
-
|
132
|
-
|
133
|
-
|
131
|
+
run_required = all([siteType_allowed, product_id_allowed])
|
132
|
+
if not skip_logs:
|
133
|
+
debugValues(data, model=model, term=term_id,
|
134
|
+
run_required=run_required,
|
135
|
+
siteType_allowed=siteType_allowed,
|
136
|
+
product_id_allowed=product_id_allowed)
|
134
137
|
return run_required
|
135
138
|
|
136
139
|
|
@@ -234,16 +237,21 @@ def get_total_value(nodes: list):
|
|
234
237
|
|
235
238
|
def _value_as(term_id: str, convert_to_property=True):
|
236
239
|
def get_value(node: dict):
|
237
|
-
|
240
|
+
factor = get_node_property_value(
|
241
|
+
None, node, term_id, default=0, handle_percents=False
|
242
|
+
) or get_lookup_value(
|
243
|
+
lookup_term=node.get('term', {}),
|
244
|
+
column=term_id
|
245
|
+
) or 0
|
238
246
|
# ignore node value if property is not found
|
239
|
-
factor = safe_parse_float(property.get('value', 0))
|
240
247
|
value = list_sum(node.get('value', []))
|
248
|
+
property = get_node_property(node, term_id, find_default_property=False, download_from_hestia=True)
|
241
249
|
ratio = factor / 100 if property.get('term', {}).get('units', '') == '%' else factor
|
242
250
|
return 0 if ratio == 0 else (value * ratio if convert_to_property else value / ratio)
|
243
251
|
return get_value
|
244
252
|
|
245
253
|
|
246
|
-
def get_total_value_converted(nodes: list, conversion_property, convert_to_property=True):
|
254
|
+
def get_total_value_converted(nodes: list, conversion_property: Union[List[str], str], convert_to_property=True):
|
247
255
|
"""
|
248
256
|
Get the total `value` of a list of Blank Nodes converted using a property of each Blank Node.
|
249
257
|
|
@@ -367,14 +375,39 @@ def get_KG_total(nodes: list) -> list:
|
|
367
375
|
return get_total_value(kg_nodes) + get_total_value_converted(kg_N_nodes, 'nitrogenContent', False)
|
368
376
|
|
369
377
|
|
378
|
+
def get_P_total(nodes: list) -> list:
|
379
|
+
"""
|
380
|
+
Get the total phosphorous content of a list of Blank Node.
|
381
|
+
|
382
|
+
The result contains the values of the following nodes:
|
383
|
+
1. Every blank node specified in `kg P` will be used.
|
384
|
+
1. Every blank node specified in `kg N` will be multiplied by the `phosphateContentAsP` property.
|
385
|
+
2. Every blank node specified in `kg` will be multiplied by the `phosphateContentAsP` property.
|
386
|
+
|
387
|
+
Parameters
|
388
|
+
----------
|
389
|
+
nodes : list
|
390
|
+
A list of Blank Node.
|
391
|
+
|
392
|
+
Returns
|
393
|
+
-------
|
394
|
+
list
|
395
|
+
The phosphorous values as a list of numbers.
|
396
|
+
"""
|
397
|
+
kg_P_nodes = _filter_list_term_unit(nodes, Units.KG_P)
|
398
|
+
kg_N_nodes = _filter_list_term_unit(nodes, Units.KG_N)
|
399
|
+
kg_nodes = _filter_list_term_unit(nodes, Units.KG)
|
400
|
+
return get_total_value(kg_P_nodes) + get_total_value_converted(kg_N_nodes + kg_nodes, 'phosphateContentAsP')
|
401
|
+
|
402
|
+
|
370
403
|
def get_P2O5_total(nodes: list) -> list:
|
371
404
|
"""
|
372
405
|
Get the total phosphate content of a list of Blank Node.
|
373
406
|
|
374
407
|
The result contains the values of the following nodes:
|
375
|
-
1. Every
|
376
|
-
1. Every
|
377
|
-
2. Every
|
408
|
+
1. Every blank node specified in `kg P2O5` will be used.
|
409
|
+
1. Every blank node specified in `kg N` will be multiplied by the `phosphateContentAsP2O5` property.
|
410
|
+
2. Every blank node specified in `kg` will be multiplied by the `phosphateContentAsP2O5` property.
|
378
411
|
|
379
412
|
Parameters
|
380
413
|
----------
|
@@ -386,10 +419,10 @@ def get_P2O5_total(nodes: list) -> list:
|
|
386
419
|
list
|
387
420
|
The phosphate values as a list of numbers.
|
388
421
|
"""
|
389
|
-
|
422
|
+
kg_P2O5_nodes = _filter_list_term_unit(nodes, Units.KG_P2O5)
|
390
423
|
kg_N_nodes = _filter_list_term_unit(nodes, Units.KG_N)
|
391
424
|
kg_nodes = _filter_list_term_unit(nodes, Units.KG)
|
392
|
-
return get_total_value(
|
425
|
+
return get_total_value(kg_P2O5_nodes) + get_total_value_converted(kg_N_nodes + kg_nodes, 'phosphateContentAsP2O5')
|
393
426
|
|
394
427
|
|
395
428
|
def convert_to_nitrogen(node: dict, model: str, blank_nodes: list, **log_args):
|
@@ -19,7 +19,7 @@ class Units(Enum):
|
|
19
19
|
KG_CO2 = 'kg CO2'
|
20
20
|
KG_K = 'kg K'
|
21
21
|
KG_K2O = 'kg K2O'
|
22
|
-
|
22
|
+
KG_CAMGCO32 = 'kg CaMg(CO3)2'
|
23
23
|
KG_N = 'kg N'
|
24
24
|
KG_N2 = 'kg N2'
|
25
25
|
KG_N2O = 'kg N2O'
|
@@ -48,58 +48,62 @@ C = 12.012
|
|
48
48
|
CA = 40.078
|
49
49
|
H = 1.008
|
50
50
|
K = 39.098
|
51
|
+
MG = 24.305
|
51
52
|
N = 14.007
|
52
53
|
_O = 15.999
|
53
54
|
P = 30.974
|
54
55
|
ATOMIC_WEIGHT_CONVERSIONS = {
|
55
56
|
Units.KG_P.value: {
|
56
|
-
Units.KG_P2O5.value: (P*2) / (P*2 + _O*5),
|
57
|
-
Units.KG_PO43.value: P / ((P + _O*4)*3)
|
57
|
+
Units.KG_P2O5.value: (P*2) / (P*2 + _O*5),
|
58
|
+
Units.KG_PO43.value: P / ((P + _O*4)*3)
|
58
59
|
},
|
59
60
|
Units.KG_PO43.value: {
|
60
|
-
Units.KG_P2O5.value: ((P + _O*4)*3) / (P*2 + _O*5)
|
61
|
+
Units.KG_P2O5.value: ((P + _O*4)*3) / (P*2 + _O*5)
|
62
|
+
},
|
63
|
+
Units.KG_P2O5.value: {
|
64
|
+
Units.KG_P.value: (P*2 + _O*5) / (P*2)
|
61
65
|
},
|
62
66
|
Units.KG_K.value: {
|
63
|
-
Units.KG_K2O.value: (K*2) / (K*2 + _O)
|
67
|
+
Units.KG_K2O.value: (K*2) / (K*2 + _O)
|
64
68
|
},
|
65
69
|
Units.KG_CA.value: {
|
66
|
-
Units.KG_CAO.value: CA / (CA + _O)
|
70
|
+
Units.KG_CAO.value: CA / (CA + _O)
|
67
71
|
},
|
68
72
|
Units.KG_CAO.value: {
|
69
|
-
Units.KG_CACO3.value: (CA + _O) / (CA + C + _O*3)
|
73
|
+
Units.KG_CACO3.value: (CA + _O) / (CA + C + _O*3)
|
70
74
|
},
|
71
75
|
Units.KG_CACO3.value: {
|
72
|
-
Units.KG_CO2.value:
|
76
|
+
Units.KG_CO2.value: (CA + C + _O*3) / C
|
73
77
|
},
|
74
|
-
Units.
|
75
|
-
Units.KG_CO2.value:
|
78
|
+
Units.KG_CAMGCO32.value: {
|
79
|
+
Units.KG_CO2.value: (CA + MG + (C + _O*3)*2) / (C*2)
|
76
80
|
},
|
77
81
|
Units.KG_CH4.value: {
|
78
|
-
Units.TO_C.value: (C + H*4) / C
|
82
|
+
Units.TO_C.value: (C + H*4) / C
|
79
83
|
},
|
80
84
|
Units.KG_CO2.value: {
|
81
|
-
Units.TO_C.value: (C + _O*2) / C
|
85
|
+
Units.TO_C.value: (C + _O*2) / C
|
82
86
|
},
|
83
87
|
Units.KG_NOX.value: {
|
84
|
-
Units.TO_N.value: (N + _O) / N
|
88
|
+
Units.TO_N.value: (N + _O) / N
|
85
89
|
},
|
86
90
|
Units.KG_N2.value: {
|
87
91
|
Units.TO_N.value: 1
|
88
92
|
},
|
89
93
|
Units.KG_N2O.value: {
|
90
|
-
Units.TO_N.value: (N*2 + _O) / (N*2)
|
94
|
+
Units.TO_N.value: (N*2 + _O) / (N*2)
|
91
95
|
},
|
92
96
|
Units.KG_NO2.value: {
|
93
|
-
Units.TO_N.value: (N + _O*2) / N
|
97
|
+
Units.TO_N.value: (N + _O*2) / N
|
94
98
|
},
|
95
99
|
Units.KG_NO3.value: {
|
96
|
-
Units.TO_N.value: (N + _O*3) / N
|
100
|
+
Units.TO_N.value: (N + _O*3) / N
|
97
101
|
},
|
98
102
|
Units.KG_NH3.value: {
|
99
|
-
Units.TO_N.value: (N + H*3) / N
|
103
|
+
Units.TO_N.value: (N + H*3) / N
|
100
104
|
},
|
101
105
|
Units.KG_NH4.value: {
|
102
|
-
Units.TO_N.value: (N + H*4) / N
|
106
|
+
Units.TO_N.value: (N + H*4) / N
|
103
107
|
},
|
104
108
|
Units.KW_H.value: {
|
105
109
|
Units.MJ.value: 3.6
|
@@ -113,8 +117,10 @@ def get_atomic_conversion(src_unit: Units, dest_unit: Units, default_value=1):
|
|
113
117
|
return ATOMIC_WEIGHT_CONVERSIONS.get(src_key, {}).get(dest_key, default_value)
|
114
118
|
|
115
119
|
|
116
|
-
def convert_to_unit(node: dict, dest_unit: Units):
|
117
|
-
|
120
|
+
def convert_to_unit(node: dict, dest_unit: Units, default_value=None):
|
121
|
+
value = list_sum(node.get('value', []), default=None)
|
122
|
+
conversion = get_atomic_conversion(node.get('term', {}).get('units'), dest_unit, default_value=None)
|
123
|
+
return value / conversion if all([value is not None, conversion is not None]) else default_value
|
118
124
|
|
119
125
|
|
120
126
|
def convert_to_N(node: dict):
|
@@ -3,7 +3,7 @@ from hestia_earth.schema import TermTermType
|
|
3
3
|
from hestia_earth.utils.model import find_term_match, filter_list_term_type
|
4
4
|
from hestia_earth.utils.tools import list_sum, safe_parse_date
|
5
5
|
|
6
|
-
from hestia_earth.models.log import debugValues
|
6
|
+
from hestia_earth.models.log import debugValues
|
7
7
|
from .lookup import all_factor_value, _term_factor_value, _aware_factor_value, fallback_country
|
8
8
|
from .product import find_by_product
|
9
9
|
from .site import region_level_1_id
|
@@ -157,22 +157,22 @@ def impact_country_value(
|
|
157
157
|
The impact total value.
|
158
158
|
"""
|
159
159
|
term_type = TermTermType.RESOURCEUSE.value if 'resourceUse' in lookup else TermTermType.EMISSION.value
|
160
|
-
|
160
|
+
blank_nodes = filter_list_term_type(impact.get('emissionsResourceUse', []), term_type)
|
161
161
|
|
162
162
|
country_id = get_country_id(impact)
|
163
163
|
country_id = fallback_country(country_id, [lookup]) if country_fallback else country_id
|
164
164
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
165
|
+
return all_factor_value(
|
166
|
+
model=model,
|
167
|
+
term_id=term_id,
|
168
|
+
node=impact,
|
169
|
+
lookup_name=lookup,
|
170
|
+
lookup_col=country_id,
|
171
|
+
blank_nodes=blank_nodes,
|
172
|
+
grouped_key=group_key,
|
173
|
+
default_no_values=None,
|
174
|
+
factor_value_func=_term_factor_value
|
175
|
+
)
|
176
176
|
|
177
177
|
|
178
178
|
def impact_aware_value(model: str, term_id: str, impact: dict, lookup: str, group_key: str = None) -> float:
|
@@ -197,14 +197,23 @@ def impact_aware_value(model: str, term_id: str, impact: dict, lookup: str, grou
|
|
197
197
|
int
|
198
198
|
The impact total value.
|
199
199
|
"""
|
200
|
-
|
200
|
+
blank_nodes = impact.get('emissionsResourceUse', [])
|
201
201
|
site = get_site(impact)
|
202
202
|
aware_id = site.get('awareWaterBasinId')
|
203
203
|
if aware_id is None:
|
204
204
|
return None
|
205
|
-
|
206
|
-
|
207
|
-
|
205
|
+
|
206
|
+
return all_factor_value(
|
207
|
+
model=model,
|
208
|
+
term_id=term_id,
|
209
|
+
node=impact,
|
210
|
+
lookup_name=lookup,
|
211
|
+
lookup_col=aware_id,
|
212
|
+
blank_nodes=blank_nodes,
|
213
|
+
grouped_key=group_key,
|
214
|
+
default_no_values=None,
|
215
|
+
factor_value_func=_aware_factor_value
|
216
|
+
)
|
208
217
|
|
209
218
|
|
210
219
|
def impact_endpoint_value(model: str, term_id: str, impact: dict, lookup_col: str) -> float:
|