hestia-earth-models 0.64.14__py3-none-any.whl → 0.65.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.
Potentially problematic release.
This version of hestia-earth-models might be problematic. Click here for more details.
- hestia_earth/models/agribalyse2016/fuelElectricity.py +1 -1
- hestia_earth/models/cache_sites.py +15 -24
- hestia_earth/models/chaudharyBrooks2018/damageToTerrestrialEcosystemsLandTransformation.py +6 -9
- hestia_earth/models/cycle/input/hestiaAggregatedData.py +46 -22
- hestia_earth/models/cycle/pre_checks/cache_sources.py +3 -25
- hestia_earth/models/cycle/product/economicValueShare.py +2 -2
- hestia_earth/models/environmentalFootprintV3/soilQualityIndexLandTransformation.py +11 -33
- hestia_earth/models/faostat2018/landTransformation100YearAverageDuringCycle.py +34 -0
- hestia_earth/models/faostat2018/landTransformation20YearAverageDuringCycle.py +34 -0
- hestia_earth/models/faostat2018/utils.py +47 -3
- hestia_earth/models/hestia/landCover.py +5 -5
- hestia_earth/models/hestia/seed_emissions.py +275 -0
- hestia_earth/models/ipcc2019/aboveGroundBiomass.py +2 -2
- hestia_earth/models/ipcc2019/belowGroundBiomass.py +8 -2
- hestia_earth/models/ipcc2019/biomass_utils.py +11 -4
- hestia_earth/models/ipcc2019/ch4ToAirEntericFermentation.py +19 -10
- hestia_earth/models/ipcc2019/co2ToAirAboveGroundBiomassStockChange.py +2 -1
- hestia_earth/models/ipcc2019/co2ToAirBelowGroundBiomassStockChange.py +2 -1
- hestia_earth/models/ipcc2019/co2ToAirCarbonStockChange_utils.py +8 -7
- hestia_earth/models/ipcc2019/co2ToAirSoilOrganicCarbonStockChange.py +2 -1
- hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_1_utils.py +28 -34
- hestia_earth/models/ipcc2019/organicCarbonPerHa_tier_2_utils.py +8 -12
- hestia_earth/models/ipcc2019/organicCarbonPerHa_utils.py +13 -30
- hestia_earth/models/linkedImpactAssessment/{landTransformationFromCropland20YearAverageInputsProduction.py → landTransformation100YearAverageInputsProduction.py} +5 -2
- hestia_earth/models/linkedImpactAssessment/{landTransformationFromCropland100YearAverageInputsProduction.py → landTransformation20YearAverageInputsProduction.py} +5 -2
- hestia_earth/models/linkedImpactAssessment/utils.py +69 -12
- hestia_earth/models/mocking/search-results.json +444 -444
- hestia_earth/models/pooreNemecek2018/excretaKgN.py +45 -41
- hestia_earth/models/pooreNemecek2018/excretaKgVs.py +89 -63
- hestia_earth/models/pooreNemecek2018/saplingsDepreciatedAmountPerCycle.py +8 -8
- hestia_earth/models/pooreNemecek2018/utils.py +60 -19
- hestia_earth/models/schererPfister2015/nErosionSoilFlux.py +4 -3
- hestia_earth/models/schererPfister2015/pErosionSoilFlux.py +4 -3
- hestia_earth/models/schererPfister2015/utils.py +12 -9
- hestia_earth/models/site/management.py +70 -55
- hestia_earth/models/site/pre_checks/cache_sources.py +2 -20
- hestia_earth/models/utils/__init__.py +12 -1
- hestia_earth/models/utils/aggregated.py +1 -1
- hestia_earth/models/utils/blank_node.py +20 -12
- hestia_earth/models/utils/cache_sources.py +15 -0
- hestia_earth/models/utils/crop.py +5 -0
- hestia_earth/models/utils/indicator.py +3 -1
- hestia_earth/models/version.py +1 -1
- {hestia_earth_models-0.64.14.dist-info → hestia_earth_models-0.65.0.dist-info}/METADATA +2 -2
- {hestia_earth_models-0.64.14.dist-info → hestia_earth_models-0.65.0.dist-info}/RECORD +75 -104
- tests/models/cml2001Baseline/test_abioticResourceDepletionMineralsAndMetals.py +1 -1
- tests/models/cycle/input/test_hestiaAggregatedData.py +5 -2
- tests/models/environmentalFootprintV3/test_soilQualityIndexLandTransformation.py +39 -28
- tests/models/{hyde32/test_landTransformationFromForest20YearAverageDuringCycle.py → faostat2018/test_landTransformation100YearAverageDuringCycle.py} +5 -5
- tests/models/{hyde32/test_landTransformationFromForest100YearAverageDuringCycle.py → faostat2018/test_landTransformation20YearAverageDuringCycle.py} +5 -5
- tests/models/faostat2018/test_utils.py +28 -0
- tests/models/hestia/test_landCover.py +2 -1
- tests/models/hestia/test_seed_emissions.py +27 -0
- tests/models/ipcc2019/test_aboveGroundBiomass.py +40 -4
- tests/models/ipcc2019/test_belowGroundBiomass.py +40 -4
- tests/models/ipcc2019/test_co2ToAirAboveGroundBiomassStockChange.py +52 -15
- tests/models/ipcc2019/test_co2ToAirBelowGroundBiomassStockChange.py +50 -14
- tests/models/ipcc2019/test_co2ToAirSoilOrganicCarbonStockChange.py +53 -32
- tests/models/ipcc2019/test_organicCarbonPerHa.py +91 -108
- tests/models/ipcc2019/test_organicCarbonPerHa_tier_1_utils.py +33 -50
- tests/models/ipcc2019/test_organicCarbonPerHa_tier_2_utils.py +0 -52
- tests/models/linkedImpactAssessment/test_freshwaterWithdrawalsInputsProduction.py +6 -4
- tests/models/linkedImpactAssessment/test_landOccupationInputsProduction.py +6 -4
- tests/models/linkedImpactAssessment/{test_landTransformationFromForest100YearAverageInputsProduction.py → test_landTransformation100YearAverageInputsProduction.py} +7 -5
- tests/models/linkedImpactAssessment/{test_landTransformationFromForest20YearAverageInputsProduction.py → test_landTransformation20YearAverageInputsProduction.py} +7 -5
- tests/models/pooreNemecek2018/test_excretaKgN.py +2 -2
- tests/models/pooreNemecek2018/test_excretaKgVs.py +1 -1
- tests/models/pooreNemecek2018/test_utils.py +26 -0
- tests/models/site/test_management.py +10 -27
- tests/models/test_cache_sites.py +40 -12
- tests/models/utils/test_blank_node.py +0 -8
- tests/models/utils/test_cache_sources.py +21 -0
- hestia_earth/models/blonkConsultants2016/landTransformationFromForest20YearAverageDuringCycle.py +0 -90
- hestia_earth/models/faostat2018/landTransformationFromCropland100YearAverage.py +0 -74
- hestia_earth/models/faostat2018/landTransformationFromCropland20YearAverage.py +0 -74
- hestia_earth/models/hyde32/__init__.py +0 -13
- hestia_earth/models/hyde32/landTransformationFromCropland100YearAverageDuringCycle.py +0 -60
- hestia_earth/models/hyde32/landTransformationFromCropland20YearAverageDuringCycle.py +0 -60
- hestia_earth/models/hyde32/landTransformationFromForest100YearAverageDuringCycle.py +0 -60
- hestia_earth/models/hyde32/landTransformationFromForest20YearAverageDuringCycle.py +0 -60
- hestia_earth/models/hyde32/landTransformationFromOtherNaturalVegetation100YearAverageDuringCycle.py +0 -61
- hestia_earth/models/hyde32/landTransformationFromOtherNaturalVegetation20YearAverageDuringCycle.py +0 -61
- hestia_earth/models/hyde32/landTransformationFromPermanentPasture100YearAverageDuringCycle.py +0 -61
- hestia_earth/models/hyde32/landTransformationFromPermanentPasture20YearAverageDuringCycle.py +0 -61
- hestia_earth/models/hyde32/utils.py +0 -72
- hestia_earth/models/linkedImpactAssessment/landTransformationFromForest100YearAverageInputsProduction.py +0 -36
- hestia_earth/models/linkedImpactAssessment/landTransformationFromForest20YearAverageInputsProduction.py +0 -36
- hestia_earth/models/linkedImpactAssessment/landTransformationFromOtherNaturalVegetation100YearAverageInputsProduction.py +0 -36
- hestia_earth/models/linkedImpactAssessment/landTransformationFromOtherNaturalVegetation20YearAverageInputsProduction.py +0 -36
- hestia_earth/models/linkedImpactAssessment/landTransformationFromPermanentPasture100YearAverageInputsProduction.py +0 -36
- hestia_earth/models/linkedImpactAssessment/landTransformationFromPermanentPasture20YearAverageInputsProduction.py +0 -36
- tests/models/blonkConsultants2016/test_landTransformationFromForest20YearAverageDuringCycle.py +0 -36
- tests/models/cycle/pre_checks/test_cache_sources.py +0 -25
- tests/models/faostat2018/test_landTransformationFromCropland100YearAverage.py +0 -40
- tests/models/faostat2018/test_landTransformationFromCropland20YearAverage.py +0 -40
- tests/models/hyde32/__init__.py +0 -0
- tests/models/hyde32/test_landTransformationFromCropland100YearAverageDuringCycle.py +0 -21
- tests/models/hyde32/test_landTransformationFromCropland20YearAverageDuringCycle.py +0 -21
- tests/models/hyde32/test_landTransformationFromOtherNaturalVegetation100YearAverageDuringCycle.py +0 -23
- tests/models/hyde32/test_landTransformationFromOtherNaturalVegetation20YearAverageDuringCycle.py +0 -21
- tests/models/hyde32/test_landTransformationFromPermanentPasture100YearAverageDuringCycle.py +0 -21
- tests/models/hyde32/test_landTransformationFromPermanentPasture20YearAverageDuringCycle.py +0 -21
- tests/models/linkedImpactAssessment/test_landTransformationFromCropland100YearAverageInputsProduction.py +0 -23
- tests/models/linkedImpactAssessment/test_landTransformationFromCropland20YearAverageInputsProduction.py +0 -23
- tests/models/linkedImpactAssessment/test_landTransformationFromOtherNaturalVegetation100YearAverageInputsProduction.py +0 -23
- tests/models/linkedImpactAssessment/test_landTransformationFromOtherNaturalVegetation20YearAverageInputsProduction.py +0 -23
- tests/models/linkedImpactAssessment/test_landTransformationFromPermanentPasture100YearAverageInputsProduction.py +0 -24
- tests/models/linkedImpactAssessment/test_landTransformationFromPermanentPasture20YearAverageInputsProduction.py +0 -24
- tests/models/site/pre_checks/test_cache_sources.py +0 -21
- {hestia_earth_models-0.64.14.dist-info → hestia_earth_models-0.65.0.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.64.14.dist-info → hestia_earth_models-0.65.0.dist-info}/WHEEL +0 -0
- {hestia_earth_models-0.64.14.dist-info → hestia_earth_models-0.65.0.dist-info}/top_level.txt +0 -0
|
@@ -21,13 +21,13 @@ from hestia_earth.models.utils.property import _get_nitrogen_content
|
|
|
21
21
|
from hestia_earth.models.utils.input import get_feed_inputs
|
|
22
22
|
from hestia_earth.models.utils.product import _new_product, get_animal_produced_nitrogen
|
|
23
23
|
from hestia_earth.models.utils.blank_node import convert_to_nitrogen
|
|
24
|
-
from .utils import
|
|
24
|
+
from .utils import get_excreta_product_with_ratio
|
|
25
25
|
from . import MODEL
|
|
26
26
|
|
|
27
27
|
REQUIREMENTS = {
|
|
28
28
|
"Cycle": {
|
|
29
|
-
"completeness.animalFeed": "",
|
|
30
|
-
"completeness.product": "",
|
|
29
|
+
"completeness.animalFeed": "True",
|
|
30
|
+
"completeness.product": "True",
|
|
31
31
|
"products": [{
|
|
32
32
|
"@type": "Product",
|
|
33
33
|
"value": "",
|
|
@@ -63,7 +63,10 @@ REQUIREMENTS = {
|
|
|
63
63
|
]
|
|
64
64
|
}]
|
|
65
65
|
}
|
|
66
|
-
]
|
|
66
|
+
],
|
|
67
|
+
"optional": {
|
|
68
|
+
"practices": [{"@type": "Practice", "term.termType": "systemn"}]
|
|
69
|
+
}
|
|
67
70
|
}
|
|
68
71
|
}
|
|
69
72
|
RETURNS = {
|
|
@@ -73,9 +76,9 @@ RETURNS = {
|
|
|
73
76
|
}
|
|
74
77
|
LOOKUPS = {
|
|
75
78
|
"crop-property": ["nitrogenContent", "crudeProteinContent"],
|
|
76
|
-
"animalProduct": ["excretaKgNTermIds"
|
|
77
|
-
"liveAnimal": ["excretaKgNTermIds"
|
|
78
|
-
"liveAquaticSpecies": ["excretaKgNTermIds"
|
|
79
|
+
"animalProduct": ["excretaKgNTermIds"],
|
|
80
|
+
"liveAnimal": ["excretaKgNTermIds"],
|
|
81
|
+
"liveAquaticSpecies": ["excretaKgNTermIds"]
|
|
79
82
|
}
|
|
80
83
|
MODEL_KEY = 'excretaKgN'
|
|
81
84
|
|
|
@@ -85,30 +88,29 @@ def _product(excreta_product: str, value: float):
|
|
|
85
88
|
return excreta_product | product
|
|
86
89
|
|
|
87
90
|
|
|
88
|
-
def _run(
|
|
91
|
+
def _run(excreta_products: list, mass_balance_items: list, alternate_items: list):
|
|
89
92
|
inputs_n, products_n = mass_balance_items
|
|
90
93
|
product_value, nitrogen_content = alternate_items
|
|
91
94
|
value = inputs_n - products_n if all(mass_balance_items) else 3.31 * product_value * nitrogen_content / 100
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return get_excreta_product(cycle, term, 'excretaKgNTermIds', 'allowedExcretaKgNTermIds')
|
|
95
|
+
# ratio is stored in product value
|
|
96
|
+
return [
|
|
97
|
+
_product(excreta_product, round(value * excreta_product.get('value')[0] / 100, 7))
|
|
98
|
+
for excreta_product in excreta_products
|
|
99
|
+
] if value > 0 else []
|
|
98
100
|
|
|
99
101
|
|
|
100
102
|
def _should_run(cycle: dict):
|
|
101
103
|
primary_prod = find_primary_product(cycle) or {}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
|
|
105
|
+
excreta_products = get_excreta_product_with_ratio(cycle, 'excretaKgNTermIds', model_key=MODEL_KEY)
|
|
106
|
+
first_term_id = excreta_products[0].get('term', {}).get('@id') if excreta_products else None
|
|
105
107
|
|
|
106
108
|
dc = cycle.get('completeness', {})
|
|
107
109
|
is_animalFeed_complete = dc.get('animalFeed', False)
|
|
108
110
|
is_product_complete = dc.get('product', False)
|
|
109
111
|
|
|
110
112
|
inputs_feed = get_feed_inputs(cycle)
|
|
111
|
-
inputs_n = convert_to_nitrogen(cycle, MODEL,
|
|
113
|
+
inputs_n = convert_to_nitrogen(cycle, MODEL, inputs_feed, term=first_term_id, model_key=MODEL_KEY)
|
|
112
114
|
|
|
113
115
|
products_n = get_animal_produced_nitrogen(MODEL, cycle.get('products', []))
|
|
114
116
|
|
|
@@ -117,37 +119,39 @@ def _should_run(cycle: dict):
|
|
|
117
119
|
product_value = list_sum(primary_prod.get('value', [0]))
|
|
118
120
|
nitrogen_content = _get_nitrogen_content(primary_prod)
|
|
119
121
|
|
|
120
|
-
if is_liveAquaticSpecies:
|
|
121
|
-
logRequirements(cycle, model=MODEL, term=excreta_term_id, model_key=MODEL_KEY,
|
|
122
|
-
is_liveAquaticSpecies=is_liveAquaticSpecies,
|
|
123
|
-
product_value=product_value,
|
|
124
|
-
nitrogen_content=nitrogen_content)
|
|
125
|
-
|
|
126
|
-
else:
|
|
127
|
-
logRequirements(cycle, model=MODEL, term=excreta_term_id, model_key=MODEL_KEY,
|
|
128
|
-
is_animalFeed_complete=is_animalFeed_complete,
|
|
129
|
-
is_product_complete=is_product_complete,
|
|
130
|
-
inputs_n=inputs_n,
|
|
131
|
-
products_n=products_n)
|
|
132
|
-
|
|
133
122
|
mass_balance_items = [inputs_n, products_n]
|
|
134
123
|
alternate_items = [product_value, nitrogen_content]
|
|
135
124
|
|
|
136
125
|
should_run = all([
|
|
137
|
-
|
|
138
|
-
|
|
126
|
+
is_animalFeed_complete,
|
|
127
|
+
is_product_complete,
|
|
139
128
|
any([
|
|
140
|
-
|
|
129
|
+
all(mass_balance_items),
|
|
141
130
|
is_liveAquaticSpecies and all(alternate_items)
|
|
142
131
|
])
|
|
143
132
|
])
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
133
|
+
|
|
134
|
+
for excreta_product in excreta_products:
|
|
135
|
+
term_id = excreta_product.get('term', {}).get('@id')
|
|
136
|
+
|
|
137
|
+
if is_liveAquaticSpecies:
|
|
138
|
+
logRequirements(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
|
|
139
|
+
is_liveAquaticSpecies=is_liveAquaticSpecies,
|
|
140
|
+
product_value=product_value,
|
|
141
|
+
nitrogen_content=nitrogen_content)
|
|
142
|
+
|
|
143
|
+
else:
|
|
144
|
+
logRequirements(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
|
|
145
|
+
is_animalFeed_complete=is_animalFeed_complete,
|
|
146
|
+
is_product_complete=is_product_complete,
|
|
147
|
+
inputs_n=inputs_n,
|
|
148
|
+
products_n=products_n)
|
|
149
|
+
|
|
150
|
+
logShouldRun(cycle, MODEL, term_id, should_run, model_key=MODEL_KEY)
|
|
151
|
+
|
|
152
|
+
return should_run, excreta_products, mass_balance_items, alternate_items
|
|
149
153
|
|
|
150
154
|
|
|
151
155
|
def run(cycle: dict):
|
|
152
|
-
should_run,
|
|
153
|
-
return _run(
|
|
156
|
+
should_run, excreta_products, mass_balance_items, alternate_items = _should_run(cycle)
|
|
157
|
+
return _run(excreta_products, mass_balance_items, alternate_items) if should_run else []
|
|
@@ -9,23 +9,26 @@ If the mass balance fails
|
|
|
9
9
|
(i.e. [animal feed](https://hestia.earth/schema/Completeness#animalFeed) is not complete, see requirements below),
|
|
10
10
|
the fomula is = total excreta as N / [Volatile solids content](https://hestia.earth/term/volatileSolidsContent).
|
|
11
11
|
"""
|
|
12
|
-
from hestia_earth.schema import SiteSiteType
|
|
13
|
-
from hestia_earth.utils.model import find_primary_product, find_term_match
|
|
12
|
+
from hestia_earth.schema import SiteSiteType, TermTermType
|
|
13
|
+
from hestia_earth.utils.model import find_primary_product, find_term_match, filter_list_term_type
|
|
14
14
|
from hestia_earth.utils.tools import list_sum, safe_parse_float
|
|
15
15
|
|
|
16
16
|
from hestia_earth.models.log import logRequirements, logShouldRun
|
|
17
|
+
from hestia_earth.models.utils import get_kg_VS_term_id, _filter_list_term_unit
|
|
18
|
+
from hestia_earth.models.utils.constant import Units
|
|
17
19
|
from hestia_earth.models.utils.term import get_lookup_value
|
|
18
20
|
from hestia_earth.models.utils.property import get_node_property
|
|
19
21
|
from hestia_earth.models.utils.product import _new_product
|
|
20
22
|
from hestia_earth.models.utils.input import get_feed_inputs
|
|
21
23
|
from hestia_earth.models.utils.measurement import most_relevant_measurement_value
|
|
22
24
|
from hestia_earth.models.utils.blank_node import convert_to_carbon
|
|
23
|
-
from .utils import
|
|
24
|
-
from .excretaKgN import _get_excreta_product as get_excreta_n_product
|
|
25
|
+
from .utils import get_excreta_product_with_ratio
|
|
25
26
|
from . import MODEL
|
|
26
27
|
|
|
27
28
|
REQUIREMENTS = {
|
|
28
29
|
"Cycle": {
|
|
30
|
+
"completeness.animalFeed": "True",
|
|
31
|
+
"completeness.product": "True",
|
|
29
32
|
"products": [{
|
|
30
33
|
"@type": "Product",
|
|
31
34
|
"primary": "True",
|
|
@@ -34,8 +37,20 @@ REQUIREMENTS = {
|
|
|
34
37
|
}],
|
|
35
38
|
"or": [
|
|
36
39
|
{
|
|
37
|
-
"
|
|
38
|
-
|
|
40
|
+
"products": [{
|
|
41
|
+
"@type": "Product",
|
|
42
|
+
"primary": "True",
|
|
43
|
+
"value": "",
|
|
44
|
+
"properties": [{"@type": "Property", "value": "", "term.@id": "carbonContent"}]
|
|
45
|
+
}],
|
|
46
|
+
"practices": [
|
|
47
|
+
{"@type": "Practice", "value": "", "term.@id": "slaughterAge"},
|
|
48
|
+
{"@type": "Practice", "value": "", "term.@id": "yieldOfPrimaryAquacultureProductLiveweightPerM2"}
|
|
49
|
+
],
|
|
50
|
+
"site": {
|
|
51
|
+
"@type": "Site",
|
|
52
|
+
"measurements": [{"@type": "Measurement", "value": "", "term.@id": "netPrimaryProduction"}]
|
|
53
|
+
},
|
|
39
54
|
"or": [
|
|
40
55
|
{
|
|
41
56
|
"animals": [{
|
|
@@ -64,20 +79,18 @@ REQUIREMENTS = {
|
|
|
64
79
|
}]
|
|
65
80
|
}
|
|
66
81
|
],
|
|
82
|
+
"optional": {
|
|
83
|
+
"practices": [{"@type": "Practice", "term.termType": "systemn"}]
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
{
|
|
67
87
|
"products": [{
|
|
68
88
|
"@type": "Product",
|
|
69
|
-
"
|
|
89
|
+
"term.termType": "excreta",
|
|
90
|
+
"term.units": "kg N",
|
|
70
91
|
"value": "",
|
|
71
|
-
"properties": [{"@type": "Property", "value": "", "term.@id": "
|
|
72
|
-
}]
|
|
73
|
-
"practices": [
|
|
74
|
-
{"@type": "Practice", "value": "", "term.@id": "slaughterAge"},
|
|
75
|
-
{"@type": "Practice", "value": "", "term.@id": "yieldOfPrimaryAquacultureProductLiveweightPerM2"}
|
|
76
|
-
],
|
|
77
|
-
"site": {
|
|
78
|
-
"@type": "Site",
|
|
79
|
-
"measurements": [{"@type": "Measurement", "value": "", "term.@id": "netPrimaryProduction"}]
|
|
80
|
-
}
|
|
92
|
+
"properties": [{"@type": "Property", "value": "", "term.@id": "volatileSolidsContent"}]
|
|
93
|
+
}]
|
|
81
94
|
}
|
|
82
95
|
]
|
|
83
96
|
}
|
|
@@ -89,9 +102,9 @@ RETURNS = {
|
|
|
89
102
|
}
|
|
90
103
|
LOOKUPS = {
|
|
91
104
|
"crop-property": ["carbonContent", "energyContentHigherHeatingValue"],
|
|
92
|
-
"animalProduct": ["excretaKgVsTermIds"
|
|
93
|
-
"liveAnimal": ["excretaKgVsTermIds"
|
|
94
|
-
"liveAquaticSpecies": ["excretaKgVsTermIds"
|
|
105
|
+
"animalProduct": ["excretaKgVsTermIds"],
|
|
106
|
+
"liveAnimal": ["excretaKgVsTermIds"],
|
|
107
|
+
"liveAquaticSpecies": ["excretaKgVsTermIds"]
|
|
95
108
|
}
|
|
96
109
|
MODEL_KEY = 'excretaKgVs'
|
|
97
110
|
|
|
@@ -106,14 +119,20 @@ def _product(excreta_product: str, value: float):
|
|
|
106
119
|
return excreta_product | product
|
|
107
120
|
|
|
108
121
|
|
|
109
|
-
def _run(
|
|
122
|
+
def _run(excreta_vs_products: list, excreta_n_products: list, mass_balance_items: list, inputs_c: float):
|
|
110
123
|
carbonContent, tsy, slaughterAge, aqocsed, npp = mass_balance_items
|
|
111
|
-
excretaKgN, vsc = alternate_items
|
|
112
124
|
value = max(
|
|
113
125
|
inputs_c + (npp * slaughterAge) / (tsy * 1000) - carbonContent - carbonContent * Conv_AQ_CLW_CO2CR,
|
|
114
126
|
carbonContent * Conv_AQ_CLW_CExcr
|
|
115
|
-
) * aqocsed if all(mass_balance_items) else
|
|
116
|
-
return [
|
|
127
|
+
) * aqocsed if all(mass_balance_items) else 0
|
|
128
|
+
return [
|
|
129
|
+
_product(excreta_product, excreta_product.get('value'))
|
|
130
|
+
for excreta_product in excreta_n_products
|
|
131
|
+
] if excreta_n_products else [
|
|
132
|
+
# ratio is stored in product value
|
|
133
|
+
_product(excreta_product, round(value * excreta_product.get('value')[0] / 100, 7))
|
|
134
|
+
for excreta_product in excreta_vs_products
|
|
135
|
+
] if value > 0 else []
|
|
117
136
|
|
|
118
137
|
|
|
119
138
|
def _get_carbonContent(cycle: dict):
|
|
@@ -127,16 +146,9 @@ def _get_conv_aq_ocsed(siteType: str):
|
|
|
127
146
|
return Conv_AQ_OC_OCSed_Marine if siteType == SiteSiteType.SEA_OR_OCEAN.value else Conv_AQ_OC_OCSed_Fresh
|
|
128
147
|
|
|
129
148
|
|
|
130
|
-
def _get_excreta_product(cycle: dict, primary_product: dict):
|
|
131
|
-
term = primary_product.get('term', {})
|
|
132
|
-
return get_excreta_product(cycle, term, 'excretaKgVsTermIds', 'allowedExcretaKgVsTermIds')
|
|
133
|
-
|
|
134
|
-
|
|
135
149
|
def _should_run(cycle: dict):
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
excreta_term_id = excreta_product.get('term', {}).get('@id')
|
|
139
|
-
should_add_product = all([not excreta_product.get('value', [])])
|
|
150
|
+
excreta_vs_products = get_excreta_product_with_ratio(cycle, 'excretaKgVsTermIds', model_key=MODEL_KEY)
|
|
151
|
+
first_term_id = excreta_vs_products[0].get('term', {}).get('@id') if excreta_vs_products else None
|
|
140
152
|
|
|
141
153
|
dc = cycle.get('completeness', {})
|
|
142
154
|
is_animalFeed_complete = dc.get('animalFeed', False)
|
|
@@ -145,7 +157,7 @@ def _should_run(cycle: dict):
|
|
|
145
157
|
carbonContent = _get_carbonContent(cycle)
|
|
146
158
|
|
|
147
159
|
inputs_feed = get_feed_inputs(cycle)
|
|
148
|
-
inputs_c = convert_to_carbon(cycle, MODEL,
|
|
160
|
+
inputs_c = convert_to_carbon(cycle, MODEL, inputs_feed, term=first_term_id, model_key=MODEL_KEY)
|
|
149
161
|
|
|
150
162
|
practices = cycle.get('practices', [])
|
|
151
163
|
tsy = list_sum(find_term_match(practices, 'yieldOfPrimaryAquacultureProductLiveweightPerM2').get('value', []))
|
|
@@ -157,40 +169,54 @@ def _should_run(cycle: dict):
|
|
|
157
169
|
npp = most_relevant_measurement_value(site.get('measurements', []), 'netPrimaryProduction', end_date, 0)
|
|
158
170
|
|
|
159
171
|
# we can still run the model with excreta in "kg N" units
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
excreta_products = filter_list_term_type(cycle.get('products', []), TermTermType.EXCRETA)
|
|
173
|
+
default_using_kg_N = not any([
|
|
174
|
+
find_term_match(excreta_products, product.get('term', {}).get('@id'))
|
|
175
|
+
for product in excreta_vs_products
|
|
176
|
+
])
|
|
177
|
+
excreta_n_products = _filter_list_term_unit(excreta_products, Units.KG_N) if default_using_kg_N else []
|
|
178
|
+
excreta_n_products = [
|
|
179
|
+
(
|
|
180
|
+
excreta_n_product,
|
|
181
|
+
get_node_property(excreta_n_product, 'volatileSolidsContent').get('value', 0)
|
|
182
|
+
)
|
|
183
|
+
for excreta_n_product in excreta_n_products
|
|
184
|
+
]
|
|
185
|
+
excreta_n_products = [
|
|
186
|
+
{
|
|
187
|
+
'term': {'@id': get_kg_VS_term_id(excreta_n_product.get('term', {}).get('@id'))},
|
|
188
|
+
'value': list_sum(excreta_n_product.get('value', [])) * vsc / 100
|
|
189
|
+
}
|
|
190
|
+
for (excreta_n_product, vsc) in excreta_n_products
|
|
191
|
+
if vsc > 0
|
|
192
|
+
]
|
|
175
193
|
|
|
176
194
|
mass_balance_items = [carbonContent, tsy, slaughterAge, aqocsed, npp]
|
|
177
|
-
alternate_items = [excretaKgN, vsc]
|
|
178
195
|
|
|
179
196
|
should_run = all([
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
is_animalFeed_complete and is_product_complete and all(mass_balance_items),
|
|
184
|
-
all(alternate_items)
|
|
185
|
-
])
|
|
197
|
+
is_animalFeed_complete,
|
|
198
|
+
is_product_complete,
|
|
199
|
+
all(mass_balance_items) or excreta_n_products
|
|
186
200
|
])
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
201
|
+
|
|
202
|
+
for excreta_product in excreta_vs_products + excreta_n_products:
|
|
203
|
+
term_id = excreta_product.get('term', {}).get('@id')
|
|
204
|
+
|
|
205
|
+
logRequirements(cycle, model=MODEL, term=term_id, model_key=MODEL_KEY,
|
|
206
|
+
is_animalFeed_complete=is_animalFeed_complete,
|
|
207
|
+
is_product_complete=is_product_complete,
|
|
208
|
+
aqocsed=aqocsed,
|
|
209
|
+
inputs_c=inputs_c,
|
|
210
|
+
carbonContent=carbonContent,
|
|
211
|
+
yield_of_target_species=tsy,
|
|
212
|
+
slaughterAge=slaughterAge,
|
|
213
|
+
netPrimaryProduction=npp,
|
|
214
|
+
default_using_kg_N=default_using_kg_N)
|
|
215
|
+
logShouldRun(cycle, MODEL, term_id, should_run)
|
|
216
|
+
|
|
217
|
+
return should_run, excreta_vs_products, excreta_n_products, mass_balance_items, inputs_c
|
|
192
218
|
|
|
193
219
|
|
|
194
220
|
def run(cycle: dict):
|
|
195
|
-
should_run,
|
|
196
|
-
return _run(
|
|
221
|
+
should_run, excreta_vs_products, excreta_n_products, mass_balance_items, inputs_c = _should_run(cycle)
|
|
222
|
+
return _run(excreta_vs_products, excreta_n_products, mass_balance_items, inputs_c) if should_run else []
|
|
@@ -38,9 +38,9 @@ def _get_value(product: dict):
|
|
|
38
38
|
return safe_parse_float(get_crop_lookup_value(MODEL, TERM_ID, term_id, LOOKUPS['crop']), None)
|
|
39
39
|
|
|
40
40
|
|
|
41
|
-
def _run(product: dict,
|
|
41
|
+
def _run(product: dict, plantationLifespan: float, cycleDuration: float):
|
|
42
42
|
value = _get_value(product)
|
|
43
|
-
return [_input(value /
|
|
43
|
+
return [_input(value / plantationLifespan * cycleDuration)]
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
def _should_run_product(product: dict): return _get_value(product) is not None
|
|
@@ -50,19 +50,19 @@ def _should_run(cycle: dict):
|
|
|
50
50
|
cycleDuration = cycle.get('cycleDuration')
|
|
51
51
|
term_type_incomplete = _is_term_type_incomplete(cycle, TERM_ID)
|
|
52
52
|
product = next((p for p in cycle.get('products', []) if _should_run_product(p)), None)
|
|
53
|
-
|
|
53
|
+
plantationLifespan = list_sum(find_term_match(cycle.get('practices', []), PRACTICE_TERM_ID).get('value'), None)
|
|
54
54
|
|
|
55
55
|
logRequirements(cycle, model=MODEL, term=TERM_ID,
|
|
56
56
|
term_type_seed_incomplete=term_type_incomplete,
|
|
57
57
|
product_id=(product or {}).get('term', {}).get('@id'),
|
|
58
|
-
|
|
58
|
+
plantationLifespan=plantationLifespan,
|
|
59
59
|
cycleDuration=cycleDuration)
|
|
60
60
|
|
|
61
|
-
should_run = all([term_type_incomplete, product,
|
|
61
|
+
should_run = all([term_type_incomplete, product, plantationLifespan, (cycleDuration or 0) > 0])
|
|
62
62
|
logShouldRun(cycle, MODEL, TERM_ID, should_run)
|
|
63
|
-
return should_run, product,
|
|
63
|
+
return should_run, product, plantationLifespan, cycleDuration
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
def run(cycle: dict):
|
|
67
|
-
should_run, product,
|
|
68
|
-
return _run(product,
|
|
67
|
+
should_run, product, plantationLifespan, cycleDuration = _should_run(cycle)
|
|
68
|
+
return _run(product, plantationLifespan, cycleDuration) if should_run else []
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
from
|
|
2
|
-
from hestia_earth.
|
|
1
|
+
from functools import reduce
|
|
2
|
+
from hestia_earth.schema import TermTermType
|
|
3
|
+
from hestia_earth.utils.model import find_term_match, filter_list_term_type, find_primary_product
|
|
4
|
+
from hestia_earth.utils.tools import non_empty_list, list_average, list_sum
|
|
3
5
|
from hestia_earth.utils.lookup import extract_grouped_data
|
|
4
6
|
|
|
5
7
|
from hestia_earth.models.log import logShouldRun, logRequirements, log_as_table
|
|
@@ -29,21 +31,60 @@ def run_products_average(cycle: dict, term_id: str, get_value_func):
|
|
|
29
31
|
return list_average(values) if should_run else None
|
|
30
32
|
|
|
31
33
|
|
|
32
|
-
def
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
34
|
+
def get_excreta_product_with_ratio(cycle: dict, lookup: str, **log_args):
|
|
35
|
+
product = find_primary_product(cycle) or {}
|
|
36
|
+
|
|
37
|
+
data = get_lookup_value(product.get('term'), lookup, model=MODEL, **log_args)
|
|
38
|
+
|
|
39
|
+
default_product_id = extract_grouped_data(data, 'default')
|
|
40
|
+
|
|
41
|
+
# find matching practices and assign a ratio for each
|
|
42
|
+
# if no matches, use default id with 100% ratio
|
|
43
|
+
practices = filter_list_term_type(cycle.get('practices', []), TermTermType.SYSTEM)
|
|
44
|
+
practices = [
|
|
45
|
+
{
|
|
46
|
+
'id': practice.get('term', {}).get('@id'),
|
|
47
|
+
'product-id': extract_grouped_data(data, practice.get('term', {}).get('@id')) or default_product_id,
|
|
48
|
+
'value': list_sum(practice.get('value'))
|
|
49
|
+
}
|
|
50
|
+
for practice in practices
|
|
51
|
+
# only keep practices with positive value
|
|
52
|
+
if list_sum(practice.get('value', [-1]), 0) > 0
|
|
53
|
+
]
|
|
54
|
+
logRequirements(cycle, model=MODEL, **log_args,
|
|
55
|
+
practices=log_as_table(practices),
|
|
56
|
+
default_product_id=default_product_id)
|
|
57
|
+
|
|
58
|
+
total_value = list_sum([p.get('value') for p in practices])
|
|
59
|
+
|
|
60
|
+
# group practices by product id
|
|
61
|
+
grouped_practices = reduce(lambda p, c: p | {
|
|
62
|
+
c['product-id']: p.get(c['product-id'], []) + [c]
|
|
63
|
+
}, practices, {})
|
|
64
|
+
# calculate ratio for each product
|
|
65
|
+
grouped_practices = [
|
|
66
|
+
values[0] | {'ratio': round(list_sum([v.get('value') for v in values]) * 100 / total_value, 2)}
|
|
67
|
+
for values in grouped_practices.values()
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
practices_with_products = [
|
|
71
|
+
(find_term_match(cycle.get('products', []), p.get('product-id')), p)
|
|
72
|
+
for p in grouped_practices
|
|
73
|
+
]
|
|
74
|
+
products = [
|
|
75
|
+
(
|
|
76
|
+
product or {
|
|
77
|
+
'@type': 'Product',
|
|
78
|
+
'term': {'@type': 'Term', '@id': practice.get('product-id')}
|
|
79
|
+
}
|
|
80
|
+
) | {'value': [practice.get('ratio')]}
|
|
81
|
+
for product, practice in practices_with_products
|
|
82
|
+
# ignore matching products with an existing value
|
|
83
|
+
if not product or not product.get('value', [])
|
|
84
|
+
] if practices_with_products else None
|
|
85
|
+
|
|
86
|
+
return products or [{
|
|
47
87
|
'@type': 'Product',
|
|
48
|
-
'term': {'@type': 'Term', '@id':
|
|
49
|
-
|
|
88
|
+
'term': {'@type': 'Term', '@id': default_product_id},
|
|
89
|
+
'value': [100]
|
|
90
|
+
}]
|
|
@@ -84,10 +84,10 @@ def _should_run(cycle: dict):
|
|
|
84
84
|
precipitation = _get_measurement_content('precipitationAnnual')
|
|
85
85
|
water = get_water(cycle, precipitation)
|
|
86
86
|
|
|
87
|
-
practice_factor = get_practice_factor(site)
|
|
87
|
+
practice_factor = get_practice_factor(TERM_ID, site)
|
|
88
88
|
pcorr = get_pcorr(slope / 100) if slope is not None else None
|
|
89
|
-
p_ef_c1 = get_p_ef_c1(cycle)
|
|
90
|
-
ef_p_c2 = get_ef_p_c2(cycle)
|
|
89
|
+
p_ef_c1 = get_p_ef_c1(TERM_ID, cycle)
|
|
90
|
+
ef_p_c2 = get_ef_p_c2(TERM_ID, cycle)
|
|
91
91
|
|
|
92
92
|
list_of_contents_for_A = [
|
|
93
93
|
practice_factor, erodibility, slope_length,
|
|
@@ -96,6 +96,7 @@ def _should_run(cycle: dict):
|
|
|
96
96
|
list_of_contents_for_value = [nla_environment, soil_nitrogen_content]
|
|
97
97
|
|
|
98
98
|
logRequirements(cycle, model=MODEL, term=TERM_ID,
|
|
99
|
+
country=site.get('country', {}).get('@id'),
|
|
99
100
|
practice_factor=practice_factor,
|
|
100
101
|
erodibility=erodibility,
|
|
101
102
|
slope_length=slope_length,
|
|
@@ -85,10 +85,10 @@ def _should_run(cycle: dict):
|
|
|
85
85
|
precipitation = _get_measurement_content('precipitationAnnual')
|
|
86
86
|
water = get_water(cycle, precipitation)
|
|
87
87
|
|
|
88
|
-
practice_factor = get_practice_factor(site)
|
|
88
|
+
practice_factor = get_practice_factor(TERM_ID, site)
|
|
89
89
|
pcorr = get_pcorr(slope / 100) if slope is not None else None
|
|
90
|
-
p_ef_c1 = get_p_ef_c1(cycle)
|
|
91
|
-
ef_p_c2 = get_ef_p_c2(cycle)
|
|
90
|
+
p_ef_c1 = get_p_ef_c1(TERM_ID, cycle)
|
|
91
|
+
ef_p_c2 = get_ef_p_c2(TERM_ID, cycle)
|
|
92
92
|
|
|
93
93
|
list_of_contents_for_A = [
|
|
94
94
|
practice_factor, erodibility, slope_length,
|
|
@@ -97,6 +97,7 @@ def _should_run(cycle: dict):
|
|
|
97
97
|
list_of_contents_for_value = [nla_environment, soil_phosphorus_content]
|
|
98
98
|
|
|
99
99
|
logRequirements(cycle, model=MODEL, term=TERM_ID,
|
|
100
|
+
country=site.get('country', {}).get('@id'),
|
|
100
101
|
practice_factor=practice_factor,
|
|
101
102
|
erodibility=erodibility,
|
|
102
103
|
slope_length=slope_length,
|
|
@@ -6,6 +6,7 @@ from hestia_earth.models.utils.blank_node import get_total_value, get_P2O5_total
|
|
|
6
6
|
from hestia_earth.models.utils.term import get_lookup_value, get_tillage_terms
|
|
7
7
|
from hestia_earth.models.utils.input import match_lookup_value
|
|
8
8
|
from hestia_earth.models.utils.organicFertiliser import get_cycle_inputs as get_organicFertiliser_inputs
|
|
9
|
+
from . import MODEL
|
|
9
10
|
|
|
10
11
|
SLOPE_RANGE = [
|
|
11
12
|
[0.0, 0.03, 1.2],
|
|
@@ -41,24 +42,26 @@ def get_pcorr(slope: float):
|
|
|
41
42
|
return next((element[2] for element in SLOPE_RANGE if slope >= element[0] and slope < element[1]), None)
|
|
42
43
|
|
|
43
44
|
|
|
44
|
-
def _get_C2_factor(term: dict):
|
|
45
|
-
return safe_parse_float(get_lookup_value(term, 'C2_FACTORS'), None)
|
|
45
|
+
def _get_C2_factor(term_id: str, term: dict):
|
|
46
|
+
return safe_parse_float(get_lookup_value(term, 'C2_FACTORS', model=MODEL, term=term_id), None)
|
|
46
47
|
|
|
47
48
|
|
|
48
|
-
def get_practice_factor(site: dict):
|
|
49
|
-
return safe_parse_float(
|
|
49
|
+
def get_practice_factor(term_id: str, site: dict):
|
|
50
|
+
return safe_parse_float(
|
|
51
|
+
get_lookup_value(site.get('country', {}), 'Practice_Factor', model=MODEL, term=term_id), None)
|
|
50
52
|
|
|
51
53
|
|
|
52
|
-
def get_p_ef_c1(cycle: dict):
|
|
54
|
+
def get_p_ef_c1(term_id: str, cycle: dict):
|
|
53
55
|
primary_product = find_primary_product(cycle) or {}
|
|
54
|
-
return safe_parse_float(
|
|
56
|
+
return safe_parse_float(
|
|
57
|
+
get_lookup_value(primary_product.get('term', {}), 'P_EF_C1', model=MODEL, term=term_id), None)
|
|
55
58
|
|
|
56
59
|
|
|
57
|
-
def get_ef_p_c2(cycle: dict):
|
|
60
|
+
def get_ef_p_c2(term_id: str, cycle: dict):
|
|
58
61
|
tillage = _get_tillage(cycle)
|
|
59
62
|
country = cycle.get('site', {}).get('country', {})
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
return _get_C2_factor(term_id, tillage) if tillage else safe_parse_float(
|
|
64
|
+
get_lookup_value(country, 'EF_P_C2', model=MODEL, term=term_id), None)
|
|
62
65
|
|
|
63
66
|
|
|
64
67
|
def get_water(cycle: dict, precipitation: float):
|