hestia-earth-models 0.57.2__py3-none-any.whl → 0.59.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/cycle/aboveGroundCropResidueTotal.py +17 -12
- hestia_earth/models/cycle/excretaKgMass.py +4 -5
- hestia_earth/models/cycle/excretaKgN.py +4 -5
- hestia_earth/models/cycle/excretaKgVs.py +4 -5
- hestia_earth/models/cycle/inorganicFertiliser.py +2 -2
- hestia_earth/models/cycle/{irrigated.py → irrigatedTypeUnspecified.py} +4 -4
- hestia_earth/models/cycle/liveAnimal.py +9 -11
- hestia_earth/models/cycle/milkYield.py +154 -0
- hestia_earth/models/cycle/residueIncorporated.py +1 -1
- hestia_earth/models/cycle/utils.py +6 -0
- hestia_earth/models/emepEea2019/nh3ToAirInorganicFertiliser.py +3 -3
- hestia_earth/models/faostat2018/seed.py +2 -3
- hestia_earth/models/geospatialDatabase/clayContent.py +17 -4
- hestia_earth/models/geospatialDatabase/sandContent.py +17 -4
- hestia_earth/models/geospatialDatabase/siltContent.py +2 -2
- hestia_earth/models/impact_assessment/irrigated.py +0 -3
- hestia_earth/models/ipcc2006/co2ToAirOrganicSoilCultivation.py +2 -2
- hestia_earth/models/ipcc2006/n2OToAirCropResidueDecompositionIndirect.py +2 -2
- hestia_earth/models/ipcc2006/n2OToAirExcretaDirect.py +1 -1
- hestia_earth/models/ipcc2006/n2OToAirExcretaIndirect.py +8 -4
- hestia_earth/models/ipcc2006/n2OToAirInorganicFertiliserDirect.py +4 -1
- hestia_earth/models/ipcc2006/n2OToAirInorganicFertiliserIndirect.py +1 -1
- hestia_earth/models/ipcc2006/n2OToAirOrganicFertiliserDirect.py +1 -1
- hestia_earth/models/ipcc2006/n2OToAirOrganicFertiliserIndirect.py +1 -1
- hestia_earth/models/ipcc2006/utils.py +11 -8
- hestia_earth/models/ipcc2019/ch4ToAirEntericFermentation.py +4 -4
- hestia_earth/models/ipcc2019/ch4ToAirFloodedRice.py +16 -7
- hestia_earth/models/ipcc2019/co2ToAirSoilCarbonStockChangeManagementChange.py +759 -0
- hestia_earth/models/ipcc2019/croppingDuration.py +12 -6
- hestia_earth/models/ipcc2019/n2OToAirCropResidueDecompositionDirect.py +5 -52
- hestia_earth/models/ipcc2019/n2OToAirInorganicFertiliserDirect.py +104 -0
- hestia_earth/models/ipcc2019/n2OToAirInorganicFertiliserIndirect.py +1 -1
- hestia_earth/models/ipcc2019/n2OToAirOrganicFertiliserDirect.py +105 -0
- hestia_earth/models/ipcc2019/n2OToAirOrganicFertiliserIndirect.py +1 -1
- hestia_earth/models/ipcc2019/no3ToGroundwaterCropResidueDecomposition.py +1 -1
- hestia_earth/models/ipcc2019/no3ToGroundwaterExcreta.py +1 -1
- hestia_earth/models/ipcc2019/no3ToGroundwaterInorganicFertiliser.py +1 -1
- hestia_earth/models/ipcc2019/no3ToGroundwaterOrganicFertiliser.py +1 -1
- hestia_earth/models/ipcc2019/organicCarbonPerHa.py +1088 -1268
- hestia_earth/models/ipcc2019/pastureGrass.py +4 -4
- hestia_earth/models/ipcc2019/utils.py +102 -1
- hestia_earth/models/koble2014/aboveGroundCropResidue.py +15 -17
- hestia_earth/models/koble2014/cropResidueManagement.py +2 -2
- hestia_earth/models/koble2014/utils.py +19 -3
- hestia_earth/models/linkedImpactAssessment/__init__.py +4 -2
- hestia_earth/models/log.py +15 -3
- hestia_earth/models/mocking/search-results.json +184 -118
- hestia_earth/models/pooreNemecek2018/excretaKgN.py +6 -7
- hestia_earth/models/pooreNemecek2018/excretaKgVs.py +7 -6
- hestia_earth/models/pooreNemecek2018/no3ToGroundwaterCropResidueDecomposition.py +3 -2
- hestia_earth/models/pooreNemecek2018/no3ToGroundwaterExcreta.py +3 -2
- hestia_earth/models/pooreNemecek2018/no3ToGroundwaterInorganicFertiliser.py +3 -2
- hestia_earth/models/pooreNemecek2018/saplings.py +0 -1
- hestia_earth/models/site/management.py +168 -0
- hestia_earth/models/site/organicCarbonPerHa.py +251 -89
- hestia_earth/models/stehfestBouwman2006/n2OToAirCropResidueDecompositionDirect.py +3 -2
- hestia_earth/models/stehfestBouwman2006/n2OToAirExcretaDirect.py +3 -2
- hestia_earth/models/stehfestBouwman2006/n2OToAirInorganicFertiliserDirect.py +3 -2
- hestia_earth/models/stehfestBouwman2006/n2OToAirOrganicFertiliserDirect.py +3 -2
- hestia_earth/models/stehfestBouwman2006/noxToAirCropResidueDecomposition.py +3 -2
- hestia_earth/models/stehfestBouwman2006/noxToAirExcreta.py +3 -2
- hestia_earth/models/stehfestBouwman2006/noxToAirInorganicFertiliser.py +3 -2
- hestia_earth/models/stehfestBouwman2006/noxToAirOrganicFertiliser.py +3 -2
- hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirCropResidueDecomposition.py +3 -2
- hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirExcreta.py +3 -2
- hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirInorganicFertiliser.py +3 -2
- hestia_earth/models/stehfestBouwman2006GisImplementation/noxToAirOrganicFertiliser.py +3 -2
- hestia_earth/models/utils/aggregated.py +1 -0
- hestia_earth/models/utils/blank_node.py +394 -72
- hestia_earth/models/utils/cropResidue.py +13 -0
- hestia_earth/models/utils/cycle.py +18 -9
- hestia_earth/models/utils/measurement.py +1 -1
- hestia_earth/models/utils/property.py +4 -4
- hestia_earth/models/utils/term.py +48 -3
- hestia_earth/models/version.py +1 -1
- {hestia_earth_models-0.57.2.dist-info → hestia_earth_models-0.59.0.dist-info}/METADATA +5 -9
- {hestia_earth_models-0.57.2.dist-info → hestia_earth_models-0.59.0.dist-info}/RECORD +109 -97
- {hestia_earth_models-0.57.2.dist-info → hestia_earth_models-0.59.0.dist-info}/WHEEL +1 -1
- tests/models/cycle/animal/input/test_hestiaAggregatedData.py +2 -14
- tests/models/cycle/input/test_hestiaAggregatedData.py +4 -16
- tests/models/cycle/test_coldCarcassWeightPerHead.py +1 -1
- tests/models/cycle/test_coldDressedCarcassWeightPerHead.py +1 -1
- tests/models/cycle/{test_irrigated.py → test_irrigatedTypeUnspecified.py} +1 -1
- tests/models/cycle/test_milkYield.py +58 -0
- tests/models/cycle/test_readyToCookWeightPerHead.py +1 -1
- tests/models/emepEea2019/test_nh3ToAirInorganicFertiliser.py +1 -1
- tests/models/geospatialDatabase/test_clayContent.py +9 -3
- tests/models/geospatialDatabase/test_sandContent.py +9 -3
- tests/models/ipcc2006/test_n2OToAirExcretaDirect.py +7 -2
- tests/models/ipcc2006/test_n2OToAirExcretaIndirect.py +1 -1
- tests/models/ipcc2006/test_n2OToAirInorganicFertiliserDirect.py +7 -2
- tests/models/ipcc2006/test_n2OToAirInorganicFertiliserIndirect.py +7 -2
- tests/models/ipcc2006/test_n2OToAirOrganicFertiliserDirect.py +7 -2
- tests/models/ipcc2006/test_n2OToAirOrganicFertiliserIndirect.py +7 -2
- tests/models/ipcc2019/test_ch4ToAirEntericFermentation.py +1 -1
- tests/models/ipcc2019/test_co2ToAirSoilCarbonStockChangeManagementChange.py +228 -0
- tests/models/ipcc2019/test_n2OToAirInorganicFertiliserDirect.py +74 -0
- tests/models/ipcc2019/test_n2OToAirOrganicFertiliserDirect.py +74 -0
- tests/models/ipcc2019/test_organicCarbonPerHa.py +303 -1044
- tests/models/koble2014/test_residueBurnt.py +1 -2
- tests/models/koble2014/test_residueLeftOnField.py +1 -2
- tests/models/koble2014/test_residueRemoved.py +1 -2
- tests/models/koble2014/test_utils.py +52 -0
- tests/models/site/test_management.py +117 -0
- tests/models/site/test_organicCarbonPerHa.py +51 -5
- tests/models/utils/test_blank_node.py +230 -34
- tests/models/utils/test_term.py +17 -3
- {hestia_earth_models-0.57.2.dist-info → hestia_earth_models-0.59.0.dist-info}/LICENSE +0 -0
- {hestia_earth_models-0.57.2.dist-info → hestia_earth_models-0.59.0.dist-info}/top_level.txt +0 -0
|
@@ -5,10 +5,11 @@ and crop residue products are provided. Examples:
|
|
|
5
5
|
- if `residueLeftOnField` = `100%` and `aboveGroundCropResidueLeftOnField` = `1000kg`, the total is `1000kg`.
|
|
6
6
|
"""
|
|
7
7
|
from hestia_earth.schema import TermTermType
|
|
8
|
-
from hestia_earth.utils.model import filter_list_term_type
|
|
8
|
+
from hestia_earth.utils.model import filter_list_term_type, find_term_match
|
|
9
9
|
from hestia_earth.utils.tools import list_sum, non_empty_list
|
|
10
10
|
|
|
11
11
|
from hestia_earth.models.log import logRequirements, logShouldRun
|
|
12
|
+
from hestia_earth.models.utils.cropResidue import PRODUCT_ID_TO_PRACTICES_ID
|
|
12
13
|
from hestia_earth.models.utils.product import _new_product
|
|
13
14
|
from . import MODEL
|
|
14
15
|
|
|
@@ -34,24 +35,28 @@ def _product(value: float):
|
|
|
34
35
|
def _run(practice: dict, product: dict):
|
|
35
36
|
practice_value = list_sum(practice.get('value', []))
|
|
36
37
|
product_value = list_sum(product.get('value', []))
|
|
37
|
-
value =
|
|
38
|
-
return [_product(value)]
|
|
38
|
+
value = product_value / (practice_value / 100)
|
|
39
|
+
return [_product(round(value, 2))]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _matching_product_by_practice(term_id: str):
|
|
43
|
+
return next((v.get('product') for v in PRODUCT_ID_TO_PRACTICES_ID if term_id in v.get('practices')), None)
|
|
39
44
|
|
|
40
45
|
|
|
41
46
|
def _should_run(cycle: dict):
|
|
42
|
-
# run if any practice
|
|
47
|
+
# run if any practice with a value matches a product with a value
|
|
43
48
|
practices = filter_list_term_type(cycle.get('practices', []), TermTermType.CROPRESIDUEMANAGEMENT)
|
|
44
49
|
products = filter_list_term_type(cycle.get('products', []), TermTermType.CROPRESIDUE)
|
|
45
50
|
|
|
46
51
|
def _matching_product(practice: dict):
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return (practice, product) if
|
|
52
|
+
practice_term_id = practice.get('term', {}).get('@id')
|
|
53
|
+
product_term_id = _matching_product_by_practice(practice_term_id)
|
|
54
|
+
product = find_term_match(products, product_term_id)
|
|
55
|
+
|
|
56
|
+
practice_value = list_sum(practice.get('value', []))
|
|
57
|
+
product_value = list_sum(product.get('value', []))
|
|
58
|
+
|
|
59
|
+
return (practice, product) if all([practice_value, product_value]) else None
|
|
55
60
|
|
|
56
61
|
matching_practices = non_empty_list(map(_matching_product, practices))
|
|
57
62
|
practice, matching_product = (matching_practices or [(None, None)])[0]
|
|
@@ -33,7 +33,6 @@ RETURNS = {
|
|
|
33
33
|
}]
|
|
34
34
|
}
|
|
35
35
|
MODEL_KEY = 'excretaKgMass'
|
|
36
|
-
MODEL_LOG = '/'.join([MODEL, MODEL_KEY])
|
|
37
36
|
|
|
38
37
|
UNITS = [
|
|
39
38
|
Units.KG_N.value,
|
|
@@ -53,7 +52,7 @@ def _convert_by_product(cycle: dict, product: dict, term_id: str):
|
|
|
53
52
|
if existing_product else None
|
|
54
53
|
value = list_sum(existing_product.get('value', [])) / conversion_to_kg_ratio if conversion_to_kg_ratio else None
|
|
55
54
|
|
|
56
|
-
debugValues(cycle, model=
|
|
55
|
+
debugValues(cycle, model=MODEL, term=term_id,
|
|
57
56
|
using_excreta_product=existing_product.get('term', {}).get('@id'),
|
|
58
57
|
conversion_to_kg_ratio=conversion_to_kg_ratio,
|
|
59
58
|
value=value)
|
|
@@ -98,7 +97,7 @@ def _should_run(cycle: dict):
|
|
|
98
97
|
]
|
|
99
98
|
has_gap_fill_term_ids = len(gap_fill_term_ids) > 0
|
|
100
99
|
|
|
101
|
-
logRequirements(cycle, model=
|
|
100
|
+
logRequirements(cycle, model=MODEL, model_key=MODEL_KEY,
|
|
102
101
|
node_type=node_type,
|
|
103
102
|
has_gap_fill_term_ids=has_gap_fill_term_ids,
|
|
104
103
|
gap_fill_term_ids=';'.join(gap_fill_term_ids))
|
|
@@ -106,9 +105,9 @@ def _should_run(cycle: dict):
|
|
|
106
105
|
should_run = all([node_type == NodeType.CYCLE.value, has_gap_fill_term_ids])
|
|
107
106
|
|
|
108
107
|
for term_id in gap_fill_term_ids:
|
|
109
|
-
logShouldRun(cycle,
|
|
108
|
+
logShouldRun(cycle, MODEL, term_id, should_run, model_key=MODEL_KEY)
|
|
110
109
|
|
|
111
|
-
logShouldRun(cycle,
|
|
110
|
+
logShouldRun(cycle, MODEL, None, should_run)
|
|
112
111
|
return should_run, gap_fill_term_ids
|
|
113
112
|
|
|
114
113
|
|
|
@@ -32,7 +32,6 @@ RETURNS = {
|
|
|
32
32
|
}]
|
|
33
33
|
}
|
|
34
34
|
MODEL_KEY = 'excretaKgN'
|
|
35
|
-
MODEL_LOG = '/'.join([MODEL, MODEL_KEY])
|
|
36
35
|
|
|
37
36
|
|
|
38
37
|
def _product(value: float, term_id: str):
|
|
@@ -44,7 +43,7 @@ def _run_product(cycle: dict, term_id: str):
|
|
|
44
43
|
existing_kg_product = find_term_match(cycle.get('products', []), get_kg_term_id(term_id))
|
|
45
44
|
value = convert_product_to_unit(existing_kg_product, Units.KG_N)
|
|
46
45
|
|
|
47
|
-
debugValues(cycle, model=
|
|
46
|
+
debugValues(cycle, model=MODEL, term=term_id,
|
|
48
47
|
using_excreta_product=existing_kg_product.get('term', {}).get('@id'),
|
|
49
48
|
value=value)
|
|
50
49
|
|
|
@@ -66,7 +65,7 @@ def _should_run(cycle: dict):
|
|
|
66
65
|
]
|
|
67
66
|
has_gap_fill_term_ids = len(gap_fill_term_ids) > 0
|
|
68
67
|
|
|
69
|
-
logRequirements(cycle, model=
|
|
68
|
+
logRequirements(cycle, model=MODEL, model_key=MODEL_KEY,
|
|
70
69
|
node_type=node_type,
|
|
71
70
|
has_gap_fill_term_ids=has_gap_fill_term_ids,
|
|
72
71
|
gap_fill_term_ids=';'.join(gap_fill_term_ids))
|
|
@@ -74,9 +73,9 @@ def _should_run(cycle: dict):
|
|
|
74
73
|
should_run = all([node_type == NodeType.CYCLE.value, has_gap_fill_term_ids])
|
|
75
74
|
|
|
76
75
|
for term_id in gap_fill_term_ids:
|
|
77
|
-
logShouldRun(cycle,
|
|
76
|
+
logShouldRun(cycle, MODEL, term_id, should_run, model_key=MODEL_KEY)
|
|
78
77
|
|
|
79
|
-
logShouldRun(cycle,
|
|
78
|
+
logShouldRun(cycle, MODEL, None, should_run)
|
|
80
79
|
return should_run, gap_fill_term_ids
|
|
81
80
|
|
|
82
81
|
|
|
@@ -32,7 +32,6 @@ RETURNS = {
|
|
|
32
32
|
}]
|
|
33
33
|
}
|
|
34
34
|
MODEL_KEY = 'excretaKgVs'
|
|
35
|
-
MODEL_LOG = '/'.join([MODEL, MODEL_KEY])
|
|
36
35
|
|
|
37
36
|
|
|
38
37
|
def _product(value: float, term_id: str):
|
|
@@ -44,7 +43,7 @@ def _run_product(cycle: dict, term_id: str):
|
|
|
44
43
|
existing_kg_product = find_term_match(cycle.get('products', []), get_kg_term_id(term_id))
|
|
45
44
|
value = convert_product_to_unit(existing_kg_product, Units.KG_VS)
|
|
46
45
|
|
|
47
|
-
debugValues(cycle, model=
|
|
46
|
+
debugValues(cycle, model=MODEL, term=term_id,
|
|
48
47
|
using_excreta_product=existing_kg_product.get('term', {}).get('@id'),
|
|
49
48
|
value=value)
|
|
50
49
|
|
|
@@ -66,7 +65,7 @@ def _should_run(cycle: dict):
|
|
|
66
65
|
]
|
|
67
66
|
has_gap_fill_term_ids = len(gap_fill_term_ids) > 0
|
|
68
67
|
|
|
69
|
-
logRequirements(cycle, model=
|
|
68
|
+
logRequirements(cycle, model=MODEL, model_key=MODEL_KEY,
|
|
70
69
|
node_type=node_type,
|
|
71
70
|
has_gap_fill_term_ids=has_gap_fill_term_ids,
|
|
72
71
|
gap_fill_term_ids=';'.join(gap_fill_term_ids))
|
|
@@ -74,9 +73,9 @@ def _should_run(cycle: dict):
|
|
|
74
73
|
should_run = all([node_type == NodeType.CYCLE.value, gap_fill_term_ids])
|
|
75
74
|
|
|
76
75
|
for term_id in gap_fill_term_ids:
|
|
77
|
-
logShouldRun(cycle,
|
|
76
|
+
logShouldRun(cycle, MODEL, term_id, should_run, model_key=MODEL_KEY)
|
|
78
77
|
|
|
79
|
-
logShouldRun(cycle,
|
|
78
|
+
logShouldRun(cycle, MODEL, None, should_run)
|
|
80
79
|
return should_run, gap_fill_term_ids
|
|
81
80
|
|
|
82
81
|
|
|
@@ -138,12 +138,12 @@ def _should_run_input(cycle: dict, input: dict):
|
|
|
138
138
|
])
|
|
139
139
|
|
|
140
140
|
for term_id in include_term_ids:
|
|
141
|
-
logRequirements(cycle, model=MODEL_LOG, term=term_id,
|
|
141
|
+
logRequirements(cycle, model=MODEL_LOG, term=term_id, model_key=MODEL_KEY,
|
|
142
142
|
nitrogenContent=nitrogenContent,
|
|
143
143
|
phosphateContentAsP2O5=phosphateContentAsP2O5,
|
|
144
144
|
potassiumContentAsK2O=potassiumContentAsK2O)
|
|
145
145
|
|
|
146
|
-
logShouldRun(cycle, MODEL_LOG, term_id, should_run)
|
|
146
|
+
logShouldRun(cycle, MODEL_LOG, term_id, should_run, model_key=MODEL_KEY)
|
|
147
147
|
return should_run
|
|
148
148
|
|
|
149
149
|
|
|
@@ -24,7 +24,7 @@ RETURNS = {
|
|
|
24
24
|
"value": ""
|
|
25
25
|
}]
|
|
26
26
|
}
|
|
27
|
-
TERM_ID = '
|
|
27
|
+
TERM_ID = 'irrigatedTypeUnspecified'
|
|
28
28
|
MIN_IRRIGATION_M3 = 250
|
|
29
29
|
|
|
30
30
|
|
|
@@ -34,6 +34,9 @@ def _practice(value: float):
|
|
|
34
34
|
return practice
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
def _is_irrigation_practice(practice: dict): return practice.get('term', {}).get('units', '') in ['%', '% area']
|
|
38
|
+
|
|
39
|
+
|
|
37
40
|
def _run(irrigation_m3: float):
|
|
38
41
|
value = 100 if irrigation_m3 > MIN_IRRIGATION_M3 else 0
|
|
39
42
|
return [_practice(value)]
|
|
@@ -61,9 +64,6 @@ def _should_run(cycle: dict):
|
|
|
61
64
|
return should_run, irrigation_value_m3
|
|
62
65
|
|
|
63
66
|
|
|
64
|
-
def _is_irrigation_practice(practice: dict): return practice.get('term', {}).get('units', '') in ['%', '% area']
|
|
65
|
-
|
|
66
|
-
|
|
67
67
|
def run(cycle: dict):
|
|
68
68
|
should_run, irrigation_m3 = _should_run(cycle)
|
|
69
69
|
return _run(irrigation_m3) if should_run else []
|
|
@@ -9,8 +9,8 @@ from hestia_earth.utils.tools import list_sum, safe_parse_float
|
|
|
9
9
|
|
|
10
10
|
from hestia_earth.models.log import logRequirements, logShouldRun
|
|
11
11
|
from hestia_earth.models.utils.product import _new_product
|
|
12
|
-
from hestia_earth.models.utils.term import get_lookup_value
|
|
13
12
|
from hestia_earth.models.utils.site import valid_site_type
|
|
13
|
+
from .utils import _get_liveAnimal_term_id
|
|
14
14
|
from . import MODEL
|
|
15
15
|
|
|
16
16
|
REQUIREMENTS = {
|
|
@@ -57,25 +57,21 @@ def _run(term_id: str, product_value: dict, propertyPerHead: float):
|
|
|
57
57
|
return [_product(term_id, value)] if value else []
|
|
58
58
|
|
|
59
59
|
|
|
60
|
-
def _get_liveAnimal_term_id(product: dict):
|
|
61
|
-
return get_lookup_value(product.get('term', {}), MODEL_KEY, model=MODEL, model_key=MODEL_KEY)
|
|
62
|
-
|
|
63
|
-
|
|
64
60
|
def _should_run(cycle: dict):
|
|
65
61
|
site_type_valid = valid_site_type(cycle.get('site'), site_types=VALID_SITE_TYPES)
|
|
66
62
|
product = find_primary_product(cycle) or {}
|
|
67
63
|
product_value = list_sum(product.get('value', []))
|
|
68
64
|
is_animalProduct = product.get('term', {}).get('termType') == TermTermType.ANIMALPRODUCT.value
|
|
69
65
|
units = f"{product.get('term', {}).get('units')} / head"
|
|
70
|
-
|
|
66
|
+
propertyPerHead = next(
|
|
71
67
|
(p for p in product.get('properties', []) if p.get('term', {}).get('units') == units), {}
|
|
72
68
|
) or next(
|
|
73
69
|
(p for p in product.get('properties', []) if p.get('term', {}).get('@id').endswith('PerHead')), {}
|
|
74
70
|
)
|
|
75
|
-
|
|
71
|
+
propertyPerHead_value = safe_parse_float(propertyPerHead.get('value'), None)
|
|
76
72
|
|
|
77
73
|
# make sure the `liveAnimal` Term is not already present as a Product or Input
|
|
78
|
-
term_id = _get_liveAnimal_term_id(product)
|
|
74
|
+
term_id = _get_liveAnimal_term_id(product, model_key=MODEL_KEY)
|
|
79
75
|
has_liveAnimal_product = find_term_match(cycle.get('products', []), term_id, None) is not None
|
|
80
76
|
has_liveAnimal_input = find_term_match(cycle.get('products', []), term_id, None) is not None
|
|
81
77
|
|
|
@@ -85,7 +81,8 @@ def _should_run(cycle: dict):
|
|
|
85
81
|
is_animalProduct,
|
|
86
82
|
not has_liveAnimal_product,
|
|
87
83
|
not has_liveAnimal_input,
|
|
88
|
-
product_value,
|
|
84
|
+
product_value,
|
|
85
|
+
propertyPerHead_value
|
|
89
86
|
])
|
|
90
87
|
|
|
91
88
|
# if the Term is added as Input, do not shows logs for it
|
|
@@ -95,10 +92,11 @@ def _should_run(cycle: dict):
|
|
|
95
92
|
is_animalProduct=is_animalProduct,
|
|
96
93
|
has_liveAnimal_product=has_liveAnimal_product,
|
|
97
94
|
product_value=product_value,
|
|
98
|
-
|
|
95
|
+
propertyPerHead_term_id=propertyPerHead.get('term', {}).get('@id'),
|
|
96
|
+
propertyPerHead_value=propertyPerHead_value)
|
|
99
97
|
|
|
100
98
|
logShouldRun(cycle, MODEL, term_id, should_run, model_key=MODEL_KEY)
|
|
101
|
-
return should_run, term_id, product_value,
|
|
99
|
+
return should_run, term_id, product_value, propertyPerHead_value
|
|
102
100
|
|
|
103
101
|
|
|
104
102
|
def run(cycle: dict):
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Milk Yield
|
|
3
|
+
|
|
4
|
+
This model gap-fills the practice "Milk yield per animal X (raw/FPCM)" (e.g. `Milk yield per cow (raw)`) when:
|
|
5
|
+
|
|
6
|
+
1. The corresponding milk term in the animalProduct glossary (e.g. Milk, cow, raw) is added as a Product of the Cycle;
|
|
7
|
+
2. The number of lactating animals is known.
|
|
8
|
+
|
|
9
|
+
It also adds the properties of the Product to the gap-filled Practice.
|
|
10
|
+
"""
|
|
11
|
+
from hestia_earth.schema import TermTermType, SiteSiteType, PracticeStatsDefinition
|
|
12
|
+
from hestia_earth.utils.model import filter_list_term_type, find_term_match
|
|
13
|
+
from hestia_earth.utils.tools import list_sum
|
|
14
|
+
|
|
15
|
+
from hestia_earth.models.log import logRequirements, logShouldRun, log_blank_nodes_id
|
|
16
|
+
from hestia_earth.models.utils.practice import _new_practice
|
|
17
|
+
from hestia_earth.models.utils.site import valid_site_type
|
|
18
|
+
from hestia_earth.models.utils.term import get_lookup_value
|
|
19
|
+
from .utils import _get_liveAnimal_term_id
|
|
20
|
+
from . import MODEL
|
|
21
|
+
|
|
22
|
+
REQUIREMENTS = {
|
|
23
|
+
"Cycle": {
|
|
24
|
+
"cycleDuration": "",
|
|
25
|
+
"site": {
|
|
26
|
+
"@type": "Site",
|
|
27
|
+
"siteType": ["cropland", "permanent pasture", "animal housing"]
|
|
28
|
+
},
|
|
29
|
+
"products": [{
|
|
30
|
+
"@type": "Product",
|
|
31
|
+
"value": "> 0",
|
|
32
|
+
"termType": "animalProduct"
|
|
33
|
+
}],
|
|
34
|
+
"animals": [{
|
|
35
|
+
"@type": "Animal",
|
|
36
|
+
"value": "> 0",
|
|
37
|
+
"termType": "liveAnimal"
|
|
38
|
+
}]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
RETURNS = {
|
|
42
|
+
"Practice": [{
|
|
43
|
+
"value": "",
|
|
44
|
+
"min": "",
|
|
45
|
+
"max": "",
|
|
46
|
+
"sd": "",
|
|
47
|
+
"statsDefinition": "modelled"
|
|
48
|
+
}]
|
|
49
|
+
}
|
|
50
|
+
LOOKUPS = {
|
|
51
|
+
"animalProduct": ["liveAnimal", "milkYieldPracticeId"]
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
MODEL_KEY = 'milkYield'
|
|
55
|
+
VALID_SITE_TYPES = [
|
|
56
|
+
SiteSiteType.CROPLAND.value, SiteSiteType.ANIMAL_HOUSING.value, SiteSiteType.PERMANENT_PASTURE.value
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def practice(term_id: str, value: float, properties: list, sd: float = None, min: float = None, max: float = None):
|
|
61
|
+
data = _new_practice(term_id)
|
|
62
|
+
data['value'] = [round(value, 2)]
|
|
63
|
+
if properties:
|
|
64
|
+
data['properties'] = properties
|
|
65
|
+
if sd is not None:
|
|
66
|
+
data['sd'] = [round(sd, 2)]
|
|
67
|
+
data['statsDefinition'] = PracticeStatsDefinition.MODELLED.value
|
|
68
|
+
if min is not None:
|
|
69
|
+
data['min'] = [round(min, 2)]
|
|
70
|
+
data['statsDefinition'] = PracticeStatsDefinition.MODELLED.value
|
|
71
|
+
if max is not None:
|
|
72
|
+
data['max'] = [round(max, 2)]
|
|
73
|
+
data['statsDefinition'] = PracticeStatsDefinition.MODELLED.value
|
|
74
|
+
return data
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _run(cycle: dict, product: dict):
|
|
78
|
+
cycleDuration = cycle.get('cycleDuration')
|
|
79
|
+
|
|
80
|
+
term = product.get('term', {})
|
|
81
|
+
practice_id = get_lookup_value(term, 'milkYieldPracticeId')
|
|
82
|
+
|
|
83
|
+
live_animal_term_id = _get_liveAnimal_term_id(product, model_key=MODEL_KEY)
|
|
84
|
+
live_animal_node = find_term_match(cycle.get('animals', []), live_animal_term_id)
|
|
85
|
+
|
|
86
|
+
value = list_sum(product.get('value')) / cycleDuration / live_animal_node.get('value')
|
|
87
|
+
sd = list_sum(product.get('sd')) / cycleDuration / live_animal_node.get('value') if all([
|
|
88
|
+
list_sum(product.get('sd', [])) > 0
|
|
89
|
+
]) else None
|
|
90
|
+
min = list_sum(product.get('min')) / cycleDuration / live_animal_node.get('value') if all([
|
|
91
|
+
list_sum(product.get('min', [])) > 0
|
|
92
|
+
]) else None
|
|
93
|
+
max = list_sum(product.get('max')) / cycleDuration / live_animal_node.get('value') if all([
|
|
94
|
+
list_sum(product.get('max', [])) > 0
|
|
95
|
+
]) else None
|
|
96
|
+
|
|
97
|
+
return live_animal_node | {
|
|
98
|
+
'practices': live_animal_node.get('practices', []) + [
|
|
99
|
+
practice(practice_id, value, product.get('properties', []), sd=sd, min=min, max=max)
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _should_run_product(cycle: dict, product: dict):
|
|
105
|
+
cycleDuration = cycle.get('cycleDuration')
|
|
106
|
+
site_type_valid = valid_site_type(cycle.get('site'), site_types=VALID_SITE_TYPES)
|
|
107
|
+
|
|
108
|
+
term = product.get('term', {})
|
|
109
|
+
term_id = term.get('@id')
|
|
110
|
+
|
|
111
|
+
has_product_value = list_sum(product.get('value', [])) > 0
|
|
112
|
+
|
|
113
|
+
live_animal_term_id = _get_liveAnimal_term_id(product, model_key=MODEL_KEY)
|
|
114
|
+
live_animal_node = find_term_match(cycle.get('animals', []), live_animal_term_id)
|
|
115
|
+
has_live_animal_node_value = live_animal_node.get('value', 0) > 0
|
|
116
|
+
|
|
117
|
+
practice_id = get_lookup_value(term, 'milkYieldPracticeId', model=MODEL, model_key=MODEL_KEY)
|
|
118
|
+
has_practice_id = any([
|
|
119
|
+
find_term_match(cycle.get('practices', []), practice_id),
|
|
120
|
+
find_term_match((live_animal_node or {}).get('practices', []), practice_id)
|
|
121
|
+
])
|
|
122
|
+
missing_milkYield_practice = not has_practice_id
|
|
123
|
+
|
|
124
|
+
logRequirements(cycle, model=MODEL, term=term_id,
|
|
125
|
+
cycleDuration=cycleDuration,
|
|
126
|
+
site_type_valid=site_type_valid,
|
|
127
|
+
has_product_value=has_product_value,
|
|
128
|
+
live_animal_term_id=live_animal_term_id,
|
|
129
|
+
has_live_animal_node_value=has_live_animal_node_value,
|
|
130
|
+
practice_id=practice_id,
|
|
131
|
+
missing_milkYield_practice=missing_milkYield_practice)
|
|
132
|
+
|
|
133
|
+
should_run = all([
|
|
134
|
+
has_product_value, has_live_animal_node_value, practice_id, missing_milkYield_practice
|
|
135
|
+
])
|
|
136
|
+
logShouldRun(cycle, MODEL, term_id, should_run, model_key=MODEL_KEY)
|
|
137
|
+
return should_run
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _should_run(cycle: dict):
|
|
141
|
+
products = filter_list_term_type(cycle.get('products', []), TermTermType.ANIMALPRODUCT)
|
|
142
|
+
products = [p for p in products if _should_run_product(cycle, p)]
|
|
143
|
+
|
|
144
|
+
logRequirements(cycle, model=MODEL, term=None,
|
|
145
|
+
animal_product_ids=log_blank_nodes_id(products))
|
|
146
|
+
|
|
147
|
+
should_run = all([products])
|
|
148
|
+
logShouldRun(cycle, MODEL, None, should_run, model_key=MODEL_KEY)
|
|
149
|
+
return should_run, products
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def run(cycle: dict):
|
|
153
|
+
should_run, products = _should_run(cycle)
|
|
154
|
+
return [_run(cycle, p) for p in products] if should_run else []
|
|
@@ -15,7 +15,7 @@ REQUIREMENTS = {
|
|
|
15
15
|
{"@type": "Product", "term.@id": "aboveGroundCropResidueTotal", "value": "> 0"},
|
|
16
16
|
{"@type": "Product", "term.@id": "aboveGroundCropResidueIncorporated", "value": "> 0"}
|
|
17
17
|
],
|
|
18
|
-
"
|
|
18
|
+
"none": {
|
|
19
19
|
"practices": [{
|
|
20
20
|
"@type": "Practice",
|
|
21
21
|
"term.@id": [
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
from hestia_earth.utils.tools import list_average
|
|
2
2
|
|
|
3
3
|
from hestia_earth.models.log import logShouldRun
|
|
4
|
+
from hestia_earth.models.utils.term import get_lookup_value
|
|
4
5
|
from . import MODEL
|
|
5
6
|
|
|
6
7
|
|
|
8
|
+
def _get_liveAnimal_term_id(product: dict, **log_ars):
|
|
9
|
+
term_id = get_lookup_value(product.get('term', {}), 'liveAnimal', model=MODEL, **log_ars)
|
|
10
|
+
return term_id.split(';')[0] if term_id else None
|
|
11
|
+
|
|
12
|
+
|
|
7
13
|
def _should_run_property_by_min_max(property: dict):
|
|
8
14
|
return all([
|
|
9
15
|
property.get('min') is not None,
|
|
@@ -42,11 +42,11 @@ LOOKUPS = {
|
|
|
42
42
|
RETURNS = {
|
|
43
43
|
"Emission": [{
|
|
44
44
|
"value": "",
|
|
45
|
-
"methodTier": "tier
|
|
45
|
+
"methodTier": "tier 2"
|
|
46
46
|
}]
|
|
47
47
|
}
|
|
48
48
|
TERM_ID = 'nh3ToAirInorganicFertiliser'
|
|
49
|
-
TIER = EmissionMethodTier.
|
|
49
|
+
TIER = EmissionMethodTier.TIER_2.value
|
|
50
50
|
UNSPECIFIED_TERM_ID = 'inorganicNitrogenFertiliserUnspecifiedKgN'
|
|
51
51
|
|
|
52
52
|
|
|
@@ -127,7 +127,7 @@ def _should_run(cycle: dict):
|
|
|
127
127
|
run_with_unspecified = (has_country_data and has_unspecifiedKgN) or fertiliser_complete
|
|
128
128
|
unspecifiedKgN = (
|
|
129
129
|
0 if len(unspecifiedKgN) == 0 and fertiliser_complete else list_sum(unspecifiedKgN, None)
|
|
130
|
-
) if run_with_unspecified else
|
|
130
|
+
) if run_with_unspecified else None
|
|
131
131
|
|
|
132
132
|
logRequirements(cycle, model=MODEL, term=TERM_ID,
|
|
133
133
|
temperature=temperature,
|
|
@@ -2,7 +2,7 @@ from hestia_earth.schema import InputStatsDefinition, TermTermType
|
|
|
2
2
|
from hestia_earth.utils.model import filter_list_term_type
|
|
3
3
|
from hestia_earth.utils.tools import list_sum, safe_parse_float
|
|
4
4
|
|
|
5
|
-
from hestia_earth.models.log import logRequirements, logShouldRun
|
|
5
|
+
from hestia_earth.models.log import logRequirements, logShouldRun, log_blank_nodes_id
|
|
6
6
|
from hestia_earth.models.utils.term import get_lookup_value
|
|
7
7
|
from hestia_earth.models.utils.input import _new_input
|
|
8
8
|
from hestia_earth.models.utils.completeness import _is_term_type_incomplete
|
|
@@ -67,12 +67,11 @@ def _should_run(cycle: dict):
|
|
|
67
67
|
products = cycle.get('products', [])
|
|
68
68
|
crop_products = list(filter(_should_run_product, filter_list_term_type(products, TermTermType.CROP)))
|
|
69
69
|
has_crop_products = len(crop_products) > 0
|
|
70
|
-
product_ids = ';'.join([p.get('term', {}).get('@id') for p in crop_products])
|
|
71
70
|
term_type_incomplete = _is_term_type_incomplete(cycle, TermTermType.SEED.value)
|
|
72
71
|
|
|
73
72
|
logRequirements(cycle, model=MODEL, term=TERM_ID,
|
|
74
73
|
term_type_seed_incomplete=term_type_incomplete,
|
|
75
|
-
crop_product_ids=
|
|
74
|
+
crop_product_ids=log_blank_nodes_id(crop_products))
|
|
76
75
|
|
|
77
76
|
should_run = all([term_type_incomplete, has_crop_products])
|
|
78
77
|
logShouldRun(cycle, MODEL, TERM_ID, should_run)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from hestia_earth.schema import MeasurementMethodClassification
|
|
2
2
|
|
|
3
3
|
from hestia_earth.models.log import logRequirements, logShouldRun
|
|
4
|
-
from hestia_earth.models.utils.
|
|
4
|
+
from hestia_earth.models.utils.blank_node import has_original_by_ids
|
|
5
|
+
from hestia_earth.models.utils.measurement import SOIL_TEXTURE_IDS, _new_measurement
|
|
5
6
|
from hestia_earth.models.utils.source import get_source
|
|
6
7
|
from .utils import download, has_geospatial_data, should_download
|
|
7
8
|
from . import MODEL
|
|
@@ -12,7 +13,17 @@ REQUIREMENTS = {
|
|
|
12
13
|
{"latitude": "", "longitude": ""},
|
|
13
14
|
{"boundary": {}},
|
|
14
15
|
{"region": {"@type": "Term", "termType": "region"}}
|
|
15
|
-
]
|
|
16
|
+
],
|
|
17
|
+
"none": {
|
|
18
|
+
"measurements": [{
|
|
19
|
+
"@type": "Measurement",
|
|
20
|
+
"term.@id": [
|
|
21
|
+
"clayContent",
|
|
22
|
+
"sandContent",
|
|
23
|
+
"siltContent"
|
|
24
|
+
]
|
|
25
|
+
}]
|
|
26
|
+
}
|
|
16
27
|
}
|
|
17
28
|
}
|
|
18
29
|
RETURNS = {
|
|
@@ -54,12 +65,14 @@ def _run(site: dict):
|
|
|
54
65
|
def _should_run(site: dict):
|
|
55
66
|
contains_geospatial_data = has_geospatial_data(site)
|
|
56
67
|
below_max_area_size = should_download(TERM_ID, site)
|
|
68
|
+
has_original_texture_measurements = has_original_by_ids(site.get('measurements', []), SOIL_TEXTURE_IDS)
|
|
57
69
|
|
|
58
70
|
logRequirements(site, model=MODEL, term=TERM_ID,
|
|
59
71
|
contains_geospatial_data=contains_geospatial_data,
|
|
60
|
-
below_max_area_size=below_max_area_size
|
|
72
|
+
below_max_area_size=below_max_area_size,
|
|
73
|
+
has_original_texture_measurements=has_original_texture_measurements)
|
|
61
74
|
|
|
62
|
-
should_run = all([contains_geospatial_data, below_max_area_size])
|
|
75
|
+
should_run = all([contains_geospatial_data, below_max_area_size, not has_original_texture_measurements])
|
|
63
76
|
logShouldRun(site, MODEL, TERM_ID, should_run)
|
|
64
77
|
return should_run
|
|
65
78
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from hestia_earth.schema import MeasurementMethodClassification
|
|
2
2
|
|
|
3
3
|
from hestia_earth.models.log import logRequirements, logShouldRun
|
|
4
|
-
from hestia_earth.models.utils.
|
|
4
|
+
from hestia_earth.models.utils.blank_node import has_original_by_ids
|
|
5
|
+
from hestia_earth.models.utils.measurement import SOIL_TEXTURE_IDS, _new_measurement
|
|
5
6
|
from hestia_earth.models.utils.source import get_source
|
|
6
7
|
from .utils import download, has_geospatial_data, should_download
|
|
7
8
|
from . import MODEL
|
|
@@ -12,7 +13,17 @@ REQUIREMENTS = {
|
|
|
12
13
|
{"latitude": "", "longitude": ""},
|
|
13
14
|
{"boundary": {}},
|
|
14
15
|
{"region": {"@type": "Term", "termType": "region"}}
|
|
15
|
-
]
|
|
16
|
+
],
|
|
17
|
+
"none": {
|
|
18
|
+
"measurements": [{
|
|
19
|
+
"@type": "Measurement",
|
|
20
|
+
"term.@id": [
|
|
21
|
+
"clayContent",
|
|
22
|
+
"sandContent",
|
|
23
|
+
"siltContent"
|
|
24
|
+
]
|
|
25
|
+
}]
|
|
26
|
+
}
|
|
16
27
|
}
|
|
17
28
|
}
|
|
18
29
|
RETURNS = {
|
|
@@ -54,12 +65,14 @@ def _run(site: dict):
|
|
|
54
65
|
def _should_run(site: dict):
|
|
55
66
|
contains_geospatial_data = has_geospatial_data(site)
|
|
56
67
|
below_max_area_size = should_download(TERM_ID, site)
|
|
68
|
+
has_original_texture_measurements = has_original_by_ids(site.get('measurements', []), SOIL_TEXTURE_IDS)
|
|
57
69
|
|
|
58
70
|
logRequirements(site, model=MODEL, term=TERM_ID,
|
|
59
71
|
contains_geospatial_data=contains_geospatial_data,
|
|
60
|
-
below_max_area_size=below_max_area_size
|
|
72
|
+
below_max_area_size=below_max_area_size,
|
|
73
|
+
has_original_texture_measurements=has_original_texture_measurements)
|
|
61
74
|
|
|
62
|
-
should_run = all([contains_geospatial_data, below_max_area_size])
|
|
75
|
+
should_run = all([contains_geospatial_data, below_max_area_size, not has_original_texture_measurements])
|
|
63
76
|
logShouldRun(site, MODEL, TERM_ID, should_run)
|
|
64
77
|
return should_run
|
|
65
78
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from hestia_earth.schema import MeasurementMethodClassification
|
|
2
2
|
|
|
3
|
-
from hestia_earth.models.log import logRequirements, logShouldRun
|
|
3
|
+
from hestia_earth.models.log import logRequirements, logShouldRun, log_blank_nodes_id
|
|
4
4
|
from hestia_earth.models.utils.measurement import _new_measurement, measurement_value
|
|
5
5
|
from hestia_earth.models.utils.source import get_source
|
|
6
6
|
from . import MODEL, clayContent, sandContent
|
|
@@ -53,7 +53,7 @@ def _should_run(site: dict):
|
|
|
53
53
|
|
|
54
54
|
logRequirements(site, model=MODEL, term=TERM_ID,
|
|
55
55
|
has_all_measurements=has_all_measurements,
|
|
56
|
-
|
|
56
|
+
measurement_ids=log_blank_nodes_id(measurements))
|
|
57
57
|
|
|
58
58
|
should_run = all([has_all_measurements])
|
|
59
59
|
logShouldRun(site, MODEL, TERM_ID, should_run)
|
|
@@ -67,7 +67,7 @@ def _should_run(cycle: dict):
|
|
|
67
67
|
def _get_measurement_content(term_id: str):
|
|
68
68
|
return most_relevant_measurement_value(measurements, term_id, end_date)
|
|
69
69
|
|
|
70
|
-
histosol = _get_measurement_content('histosol')
|
|
70
|
+
histosol = _get_measurement_content('histosol')
|
|
71
71
|
eco_climate_zone = _get_measurement_content('ecoClimateZone')
|
|
72
72
|
organic_soil_factor = _get_CO2_factor(eco_climate_zone, site_type) if eco_climate_zone else 0
|
|
73
73
|
land_occupation = land_occupation_per_ha(MODEL, TERM_ID, cycle)
|
|
@@ -77,7 +77,7 @@ def _should_run(cycle: dict):
|
|
|
77
77
|
land_occupation=land_occupation,
|
|
78
78
|
histosol=histosol)
|
|
79
79
|
|
|
80
|
-
should_run = all([organic_soil_factor, land_occupation])
|
|
80
|
+
should_run = all([organic_soil_factor, land_occupation, histosol is not None])
|
|
81
81
|
logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
|
|
82
82
|
return should_run, histosol, organic_soil_factor, land_occupation
|
|
83
83
|
|
|
@@ -43,7 +43,7 @@ def _run(no3: float, nh3: float, nox: float):
|
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
def _should_run(cycle: dict):
|
|
46
|
-
nh3_n, no3_n, nox_n = get_nh3_no3_nox_to_n(cycle, NH3_TERM_ID, NO3_TERM_ID, NOX_TERM_ID)
|
|
46
|
+
nh3_n, no3_n, nox_n = get_nh3_no3_nox_to_n(cycle, NH3_TERM_ID, NO3_TERM_ID, NOX_TERM_ID, allow_none=False)
|
|
47
47
|
term_type_complete = _is_term_type_complete(cycle, TermTermType.CROPRESIDUE)
|
|
48
48
|
|
|
49
49
|
logRequirements(cycle, model=MODEL, term=TERM_ID,
|
|
@@ -52,7 +52,7 @@ def _should_run(cycle: dict):
|
|
|
52
52
|
nox_n=nox_n,
|
|
53
53
|
term_type_cropResidue_complete=term_type_complete)
|
|
54
54
|
|
|
55
|
-
should_run = all([no3_n, nh3_n, nox_n, term_type_complete])
|
|
55
|
+
should_run = all([no3_n is not None, nh3_n is not None, nox_n is not None, term_type_complete])
|
|
56
56
|
logShouldRun(cycle, MODEL, TERM_ID, should_run, methodTier=TIER)
|
|
57
57
|
return should_run, no3_n, nh3_n, nox_n
|
|
58
58
|
|