pyholos 0.0.1__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 pyholos might be problematic. Click here for more details.
- pyholos/__init__.py +0 -0
- pyholos/common.py +141 -0
- pyholos/common2.py +157 -0
- pyholos/components/__init__.py +0 -0
- pyholos/components/animals/__init__.py +0 -0
- pyholos/components/animals/beef.py +766 -0
- pyholos/components/animals/common.py +2301 -0
- pyholos/components/animals/dairy.py +341 -0
- pyholos/components/animals/sheep.py +412 -0
- pyholos/components/common.py +170 -0
- pyholos/components/land_management/__init__.py +0 -0
- pyholos/components/land_management/carbon/__init__.py +0 -0
- pyholos/components/land_management/carbon/climate.py +863 -0
- pyholos/components/land_management/carbon/management.py +21 -0
- pyholos/components/land_management/carbon/relative_biomass_information.py +410 -0
- pyholos/components/land_management/carbon/tillage.py +88 -0
- pyholos/components/land_management/common.py +220 -0
- pyholos/components/land_management/crop.py +1233 -0
- pyholos/components/land_management/field_system.py +458 -0
- pyholos/components/land_management/utils.py +66 -0
- pyholos/config.py +49 -0
- pyholos/core_constants.py +20 -0
- pyholos/defaults.py +116 -0
- pyholos/farm/__init__.py +0 -0
- pyholos/farm/enums.py +54 -0
- pyholos/farm/farm.py +101 -0
- pyholos/farm/farm_inputs.py +633 -0
- pyholos/farm/farm_settings.py +542 -0
- pyholos/launching.py +86 -0
- pyholos/postprocessing/__init__.py +0 -0
- pyholos/postprocessing/plots.py +164 -0
- pyholos/postprocessing/postprocessing.py +38 -0
- pyholos/resources/holos/Table_16_Livestock_Coefficients_BeefAndDairy_Cattle_Provider.csv +21 -0
- pyholos/resources/holos/Table_21_Average_Milk_Production_For_Dairy_Cows_By_Province.csv +23 -0
- pyholos/resources/holos/Table_22_Livestock_Coefficients_For_Sheep.csv +28 -0
- pyholos/resources/holos/Table_29_Percentage_Total_Manure_Produced_In_Systems.csv +56 -0
- pyholos/resources/holos/Table_30_Default_Bedding_Material_Composition_Provider.csv +28 -0
- pyholos/resources/holos/Table_50_Fuel_Energy_Requirement_Estimates_By_Region.csv +81 -0
- pyholos/resources/holos/Table_51_Herbicide_Energy_Requirement_Estimates_By_Region.csv +81 -0
- pyholos/resources/holos/Table_61_Fractions_of_dairy_cattle_N_volatilized.csv +25 -0
- pyholos/resources/holos/Table_62_Fractions_of_swine_N_volatilized.csv +25 -0
- pyholos/resources/holos/Table_6_Manure_Types_And_Default_Composition.csv +126 -0
- pyholos/resources/holos/Table_7_Relative_Biomass_Information.csv +112 -0
- pyholos/resources/holos/Table_9_Default_Values_For_Nitrogen_Lignin_In_Crops.csv +72 -0
- pyholos/resources/holos/Table_Tillage_Factor.csv +13 -0
- pyholos/resources/holos/feeds.csv +223 -0
- pyholos/resources/holos/main_tables.py +493 -0
- pyholos/resources/holos/small_area_yields.csv +167159 -0
- pyholos/resources/soil_landscapes_of_canada_v3r2.zip +0 -0
- pyholos/soil.py +439 -0
- pyholos/utils.py +83 -0
- pyholos-0.0.1.dist-info/METADATA +16 -0
- pyholos-0.0.1.dist-info/RECORD +55 -0
- pyholos-0.0.1.dist-info/WHEEL +4 -0
- pyholos-0.0.1.dist-info/licenses/LICENSE +677 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from pyholos.core_constants import CoreConstants
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def calculate_management_factor(
|
|
5
|
+
climate_parameter: float,
|
|
6
|
+
tillage_factor: float,
|
|
7
|
+
) -> float:
|
|
8
|
+
"""Calculates the management factor.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
climate_parameter: (-) climate parameter
|
|
12
|
+
tillage_factor: (-) tillage factor
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
|
|
16
|
+
Holos source code:
|
|
17
|
+
https://github.com/holos-aafc/Holos/blob/90fad0a9950183da217137490cb756104ba3f7f4/H.Core/Services/LandManagement/FieldResultsService.cs#L294
|
|
18
|
+
https://github.com/holos-aafc/Holos/blob/90fad0a9950183da217137490cb756104ba3f7f4/H.Core/Calculators/Climate/ClimateParameterCalculator.cs#L269
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
return round(climate_parameter * tillage_factor, CoreConstants.DefaultNumberOfDecimalPlaces)
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field, NonNegativeFloat
|
|
4
|
+
|
|
5
|
+
from pyholos.components.common import convert_province_name
|
|
6
|
+
from pyholos.components.land_management.common import IrrigationType
|
|
7
|
+
from pyholos.components.land_management.crop import (CropType,
|
|
8
|
+
convert_crop_type_name)
|
|
9
|
+
from pyholos.config import PathsHolosResources
|
|
10
|
+
from pyholos.common2 import CanadianProvince
|
|
11
|
+
from pyholos.utils import clean_string
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class _IrrigationData:
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
irrigation_type: IrrigationType,
|
|
18
|
+
irrigation_lower_range_limit: float,
|
|
19
|
+
irrigation_upper_range_limit: float
|
|
20
|
+
):
|
|
21
|
+
self.irrigation_type = irrigation_type
|
|
22
|
+
self.irrigation_lower_range_limit = irrigation_lower_range_limit
|
|
23
|
+
self.irrigation_upper_range_limit = irrigation_upper_range_limit
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class _CarbonResidueData:
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
relative_biomass_product: float,
|
|
30
|
+
relative_biomass_straw: float,
|
|
31
|
+
relative_biomass_root: float,
|
|
32
|
+
relative_biomass_extraroot: float
|
|
33
|
+
):
|
|
34
|
+
self.relative_biomass_product = relative_biomass_product
|
|
35
|
+
self.relative_biomass_straw = relative_biomass_straw
|
|
36
|
+
self.relative_biomass_root = relative_biomass_root
|
|
37
|
+
self.relative_biomass_extraroot = relative_biomass_extraroot
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class _NitrogenResidueData:
|
|
41
|
+
def __init__(
|
|
42
|
+
self,
|
|
43
|
+
nitrogen_content_product: float,
|
|
44
|
+
nitrogen_content_straw: float,
|
|
45
|
+
nitrogen_content_root: float
|
|
46
|
+
):
|
|
47
|
+
self.nitrogen_content_product = nitrogen_content_product
|
|
48
|
+
self.nitrogen_content_straw = nitrogen_content_straw
|
|
49
|
+
self.nitrogen_content_root = nitrogen_content_root
|
|
50
|
+
self.nitrogen_content_extraroot = nitrogen_content_root
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class BiogasAndMethaneProductionParametersData:
|
|
54
|
+
def __init__(
|
|
55
|
+
self,
|
|
56
|
+
crop_type: CropType = CropType.NotSelected,
|
|
57
|
+
bio_methane_potential: float = 0,
|
|
58
|
+
methane_fraction: float = 0,
|
|
59
|
+
volatile_solids: float = 0,
|
|
60
|
+
total_solids: float = 0,
|
|
61
|
+
total_nitrogen: float = 0
|
|
62
|
+
):
|
|
63
|
+
"""Table_46_Biogas_Methane_Production_CropResidue_Data
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
crop_type: CropType class member
|
|
67
|
+
bio_methane_potential: (Nm3 ton-1 VS) biomethane potential given a substrate type (BMP)
|
|
68
|
+
methane_fraction: (-) fraction of methane in biogas (f_CH4)
|
|
69
|
+
volatile_solids: (%) percentage of total solids
|
|
70
|
+
total_solids: (kg t^-1)^3 total solids in the substrate type (TS)
|
|
71
|
+
total_nitrogen: (KG N t^-1)^5 total Nitrogen in the substrate
|
|
72
|
+
"""
|
|
73
|
+
self.crop_type = crop_type
|
|
74
|
+
self.bio_methane_potential = bio_methane_potential
|
|
75
|
+
self.methane_fraction = methane_fraction
|
|
76
|
+
self.volatile_solids = volatile_solids
|
|
77
|
+
self.total_solids = total_solids
|
|
78
|
+
self.total_nitrogen = total_nitrogen
|
|
79
|
+
|
|
80
|
+
def __eq__(self, other):
|
|
81
|
+
return self.__dict__ == other.__dict__ if isinstance(other, self.__class__) else False
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class RelativeBiomassInformationData(BaseModel):
|
|
85
|
+
"""Table_7_Relative_Biomass_Information_Data
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
crop_type: CropType class instance
|
|
89
|
+
irrigation_type: IrrigationType class instance
|
|
90
|
+
irrigation_lower_range_limit: (mm)
|
|
91
|
+
irrigation_upper_range_limit: (mm)
|
|
92
|
+
moisture_content_of_product: (%) product moisture content (between 0 and 100)
|
|
93
|
+
relative_biomass_product: (-) relative biomass allocation coefficient for product
|
|
94
|
+
relative_biomass_straw: (-) relative biomass allocation coefficient for straw
|
|
95
|
+
relative_biomass_root: (-) relative biomass allocation coefficient for root
|
|
96
|
+
relative_biomass_extraroot: (-) relative biomass allocation coefficient for extraroot
|
|
97
|
+
nitrogen_content_product: (g(N)/kg) product Nitrogen content
|
|
98
|
+
nitrogen_content_straw: (g(N)/kg) straw Nitrogen content
|
|
99
|
+
nitrogen_content_root: (g(N)/kg) root Nitrogen content
|
|
100
|
+
nitrogen_content_extraroot: (g(N)/kg) extraroot Nitrogen content
|
|
101
|
+
lignin_content: (-) fraction of lignin content in the carbon input (on dry basis, between 0 and 1)
|
|
102
|
+
province: CanadianProvince class instance
|
|
103
|
+
|
|
104
|
+
Holos Source Code:
|
|
105
|
+
https://github.com/holos-aafc/Holos/blob/b183dab99d211158d1fed9da5370ce599ac7c914/H.Core/Providers/Carbon/Table_7_Relative_Biomass_Information_Data.cs#L13
|
|
106
|
+
"""
|
|
107
|
+
crop_type: CropType = Field(default=CropType.NotSelected)
|
|
108
|
+
irrigation_type: IrrigationType | None = Field(default=None)
|
|
109
|
+
irrigation_lower_range_limit: NonNegativeFloat = Field(default=0)
|
|
110
|
+
irrigation_upper_range_limit: NonNegativeFloat = Field(default=0)
|
|
111
|
+
# irrigation_amount: NonNegativeFloat = Field(default=0)
|
|
112
|
+
moisture_content_of_product: float = Field(default=0, ge=0, lt=100)
|
|
113
|
+
relative_biomass_product: float = Field(default=0, ge=0, lt=100)
|
|
114
|
+
relative_biomass_straw: float = Field(default=0, ge=0, lt=100)
|
|
115
|
+
relative_biomass_root: float = Field(default=0, ge=0, lt=100)
|
|
116
|
+
relative_biomass_extraroot: float = Field(default=0, ge=0, lt=100)
|
|
117
|
+
nitrogen_content_product: NonNegativeFloat = Field(default=0)
|
|
118
|
+
nitrogen_content_straw: NonNegativeFloat = Field(default=0)
|
|
119
|
+
nitrogen_content_root: NonNegativeFloat = Field(default=0)
|
|
120
|
+
nitrogen_content_extraroot: NonNegativeFloat = Field(default=0)
|
|
121
|
+
# nitrogen_fertilizer_rate: float = Field(default=0)
|
|
122
|
+
# phosphorus_fertilizer_rate: float = Field(default=0)
|
|
123
|
+
lignin_content: float = Field(default=0, ge=0, le=1)
|
|
124
|
+
province: CanadianProvince | None = Field(default=None)
|
|
125
|
+
|
|
126
|
+
# biogas_and_methane_production_parameters_data: BiogasAndMethaneProductionParametersData = Field(
|
|
127
|
+
# default=BiogasAndMethaneProductionParametersData())
|
|
128
|
+
|
|
129
|
+
def __eq__(self, other):
|
|
130
|
+
return self.__dict__ == other.__dict__ if isinstance(other, self.__class__) else False
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def parse_crop_type(
|
|
134
|
+
raw_input: str
|
|
135
|
+
) -> CropType:
|
|
136
|
+
return convert_crop_type_name(name=raw_input.lower().replace(' ', '').replace('-', ''))
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def parse_irrigation_data(
|
|
140
|
+
raw_input: str,
|
|
141
|
+
) -> _IrrigationData:
|
|
142
|
+
raw_input = raw_input.replace(' ', '').lower()
|
|
143
|
+
|
|
144
|
+
irrigation_type = IrrigationType.RainFed if raw_input == "rainfed" else (
|
|
145
|
+
IrrigationType.Irrigated if raw_input == "irrigated" else None)
|
|
146
|
+
|
|
147
|
+
if "<" in raw_input:
|
|
148
|
+
# Lower range
|
|
149
|
+
irrigation_lower_range_limit = 0
|
|
150
|
+
irrigation_upper_range_limit = float(raw_input.replace("<", "").replace("mm", ""))
|
|
151
|
+
|
|
152
|
+
elif ">" in raw_input:
|
|
153
|
+
# Upper range
|
|
154
|
+
irrigation_lower_range_limit = float(raw_input.replace(">", "").replace("mm", ""))
|
|
155
|
+
irrigation_upper_range_limit = float('inf')
|
|
156
|
+
|
|
157
|
+
elif "-" in raw_input:
|
|
158
|
+
# Irrigation is a range
|
|
159
|
+
irrigation_lower_range_limit, irrigation_upper_range_limit = [
|
|
160
|
+
float(s) for s in raw_input.replace("mm", "").replace(" ", "").split('-')]
|
|
161
|
+
else:
|
|
162
|
+
irrigation_lower_range_limit = 0
|
|
163
|
+
irrigation_upper_range_limit = 0
|
|
164
|
+
|
|
165
|
+
return _IrrigationData(
|
|
166
|
+
irrigation_type=irrigation_type,
|
|
167
|
+
irrigation_lower_range_limit=irrigation_lower_range_limit,
|
|
168
|
+
irrigation_upper_range_limit=irrigation_upper_range_limit)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def parse_province_data(
|
|
172
|
+
raw_input: str
|
|
173
|
+
) -> None | CanadianProvince:
|
|
174
|
+
raw_input = raw_input.lower().replace(' ', '')
|
|
175
|
+
if any([len(raw_input) == 0] + [v in raw_input for v in ["canada", "rainfed", "irrigated", ">", "<", "-"]]):
|
|
176
|
+
province = None
|
|
177
|
+
else:
|
|
178
|
+
province = convert_province_name(name=raw_input)
|
|
179
|
+
|
|
180
|
+
return province
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def parse_moisture_content_data(
|
|
184
|
+
raw_input: str
|
|
185
|
+
) -> float:
|
|
186
|
+
raw_input = raw_input.lower().replace(" ", "")
|
|
187
|
+
return float(raw_input) if not len(raw_input) == 0 else 0
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def parse_carbon_residue_data(
|
|
191
|
+
raw_inputs: list[str]
|
|
192
|
+
) -> _CarbonResidueData:
|
|
193
|
+
raw_inputs = [float(s) if len(s.lower().replace(" ", "")) != 0 else 0 for s in raw_inputs]
|
|
194
|
+
return _CarbonResidueData(
|
|
195
|
+
relative_biomass_product=raw_inputs[0],
|
|
196
|
+
relative_biomass_straw=raw_inputs[1],
|
|
197
|
+
relative_biomass_root=raw_inputs[2],
|
|
198
|
+
relative_biomass_extraroot=raw_inputs[3]
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def parse_nitrogen_residue_data(
|
|
203
|
+
raw_inputs: list[str]
|
|
204
|
+
) -> _NitrogenResidueData:
|
|
205
|
+
raw_inputs = [float(s) if len(s.lower().replace(" ", "")) != 0 else 0 for s in raw_inputs]
|
|
206
|
+
return _NitrogenResidueData(
|
|
207
|
+
nitrogen_content_product=raw_inputs[0],
|
|
208
|
+
nitrogen_content_straw=raw_inputs[1],
|
|
209
|
+
nitrogen_content_root=raw_inputs[2]
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def parse_lignin_content_data(
|
|
214
|
+
raw_input: str
|
|
215
|
+
) -> float:
|
|
216
|
+
return float(raw_input) if len(raw_input.lower().replace(" ", "")) != 0 else 0
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def parse_biomethane_data(
|
|
220
|
+
crop_type: CropType,
|
|
221
|
+
raw_inputs: list[str]
|
|
222
|
+
) -> BiogasAndMethaneProductionParametersData:
|
|
223
|
+
raw_inputs = [float(s) if len(s.lower().replace(" ", "")) != 0 else 0 for s in raw_inputs]
|
|
224
|
+
return BiogasAndMethaneProductionParametersData(
|
|
225
|
+
crop_type=crop_type,
|
|
226
|
+
bio_methane_potential=raw_inputs[0],
|
|
227
|
+
methane_fraction=raw_inputs[1],
|
|
228
|
+
volatile_solids=raw_inputs[2],
|
|
229
|
+
total_solids=raw_inputs[3],
|
|
230
|
+
total_nitrogen=raw_inputs[4])
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def parse_relative_biomass_information_data(
|
|
234
|
+
raw_input: str
|
|
235
|
+
) -> RelativeBiomassInformationData:
|
|
236
|
+
columns = raw_input.replace('\n', '').split(',')
|
|
237
|
+
crop_type = parse_crop_type(raw_input=columns[1])
|
|
238
|
+
irrigation_data = parse_irrigation_data(raw_input=columns[2])
|
|
239
|
+
carbon_residue_data = parse_carbon_residue_data(columns[5: 9])
|
|
240
|
+
nitrogen_residue_data = parse_nitrogen_residue_data(raw_inputs=columns[11:14])
|
|
241
|
+
|
|
242
|
+
return RelativeBiomassInformationData(
|
|
243
|
+
crop_type=crop_type,
|
|
244
|
+
irrigation_type=irrigation_data.irrigation_type,
|
|
245
|
+
irrigation_lower_range_limit=irrigation_data.irrigation_lower_range_limit,
|
|
246
|
+
irrigation_upper_range_limit=irrigation_data.irrigation_upper_range_limit,
|
|
247
|
+
moisture_content_of_product=parse_moisture_content_data(raw_input=columns[3]),
|
|
248
|
+
relative_biomass_product=carbon_residue_data.relative_biomass_product,
|
|
249
|
+
relative_biomass_straw=carbon_residue_data.relative_biomass_straw,
|
|
250
|
+
relative_biomass_root=carbon_residue_data.relative_biomass_root,
|
|
251
|
+
relative_biomass_extraroot=carbon_residue_data.relative_biomass_extraroot,
|
|
252
|
+
nitrogen_content_product=nitrogen_residue_data.nitrogen_content_product,
|
|
253
|
+
nitrogen_content_straw=nitrogen_residue_data.nitrogen_content_straw,
|
|
254
|
+
nitrogen_content_root=nitrogen_residue_data.nitrogen_content_root,
|
|
255
|
+
nitrogen_content_extraroot=nitrogen_residue_data.nitrogen_content_extraroot,
|
|
256
|
+
lignin_content=parse_lignin_content_data(raw_input=columns[16]),
|
|
257
|
+
province=parse_province_data(raw_input=columns[2]),
|
|
258
|
+
# biogas_and_methane_production_parameters_data=parse_biomethane_data(crop_type=crop_type,
|
|
259
|
+
# raw_inputs=columns[17:22])
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def read_table_7():
|
|
264
|
+
with PathsHolosResources.Table_7_Relative_Biomass_Information.open(mode='r') as f:
|
|
265
|
+
return [v for v in f.readlines()[5:] if all([
|
|
266
|
+
not len(v.replace(' ', '').replace(',', '').replace('\n', '')) == 0,
|
|
267
|
+
not v.startswith('#')
|
|
268
|
+
])][2:]
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def parse_table_7() -> list[RelativeBiomassInformationData]:
|
|
272
|
+
return [parse_relative_biomass_information_data(raw_input=v) for v in read_table_7()]
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def get_relative_biomass_information_data(
|
|
276
|
+
table_7: list[RelativeBiomassInformationData],
|
|
277
|
+
crop_type: CropType,
|
|
278
|
+
irrigation_type: IrrigationType,
|
|
279
|
+
irrigation_amount: float,
|
|
280
|
+
province: CanadianProvince
|
|
281
|
+
) -> RelativeBiomassInformationData:
|
|
282
|
+
if any([
|
|
283
|
+
crop_type == CropType.NotSelected,
|
|
284
|
+
crop_type.is_fallow()
|
|
285
|
+
]):
|
|
286
|
+
return RelativeBiomassInformationData()
|
|
287
|
+
|
|
288
|
+
if crop_type.is_grassland():
|
|
289
|
+
# Only have values for grassland (native). If type is grassland (broken) or grassland (seeded), return values for grassland (native)
|
|
290
|
+
crop_type = CropType.RangelandNative
|
|
291
|
+
|
|
292
|
+
by_crop_type = [v for v in table_7 if v.crop_type == crop_type]
|
|
293
|
+
if len(by_crop_type) == 0:
|
|
294
|
+
# Trace.TraceError($"{nameof(Table_7_Relative_Biomass_Information_Provider)}.{nameof(this.GetResidueData)}: unknown crop type: '{cropType.GetDescription()}'. Returning default values.");
|
|
295
|
+
return RelativeBiomassInformationData()
|
|
296
|
+
|
|
297
|
+
elif len(by_crop_type) == 1:
|
|
298
|
+
return by_crop_type[0]
|
|
299
|
+
|
|
300
|
+
else:
|
|
301
|
+
by_crop_type_and_irrigation_amount = [v for v in by_crop_type if all(
|
|
302
|
+
[irrigation_amount >= v.irrigation_lower_range_limit,
|
|
303
|
+
irrigation_amount < v.irrigation_upper_range_limit])]
|
|
304
|
+
if len(by_crop_type_and_irrigation_amount) >= 1:
|
|
305
|
+
return by_crop_type_and_irrigation_amount[0]
|
|
306
|
+
else:
|
|
307
|
+
by_crop_type_and_irrigation_type = [v for v in by_crop_type if v.irrigation_type == irrigation_type]
|
|
308
|
+
if len(by_crop_type_and_irrigation_type) >= 1:
|
|
309
|
+
return by_crop_type_and_irrigation_type[0]
|
|
310
|
+
|
|
311
|
+
# Potato is a special case
|
|
312
|
+
by_province = [v for v in by_crop_type if all([
|
|
313
|
+
v.province is not None,
|
|
314
|
+
v.province == province
|
|
315
|
+
])]
|
|
316
|
+
if len(by_province) >= 1:
|
|
317
|
+
return by_province[0]
|
|
318
|
+
|
|
319
|
+
return [v for v in by_crop_type if v.province is None][0]
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
@dataclass
|
|
323
|
+
class NitrogenLigninContentInCropsData:
|
|
324
|
+
"""
|
|
325
|
+
Args:
|
|
326
|
+
CropType: CropType instance, the crop type for which we need the various information and values.
|
|
327
|
+
InterceptValue: The intercept value given the crop type. Taken from national inventory numbers.
|
|
328
|
+
SlopeValue: The slop value given the crop type. Taken from national inventory numbers.
|
|
329
|
+
RSTRatio: Shoot to root ratio of the crop. The ratio of below-ground root biomass to above-ground shoot
|
|
330
|
+
NitrogenContentResidues: Nitrogen Content of residues. Unit of measurement = Proportion of Carbon content
|
|
331
|
+
LigninContentResidues: Lignin content of residue. Unit of measurement = Proportion of Carbon content
|
|
332
|
+
MoistureContent: (%) Moisture content of crop
|
|
333
|
+
# BiomethaneData: Table_46_Biogas_Methane_Production_CropResidue_Data
|
|
334
|
+
|
|
335
|
+
Holos source code:
|
|
336
|
+
https://github.com/holos-aafc/Holos/blob/d62072ff1362eb356ba00f2736293e3fe0f8acc2/H.Core/Providers/Plants/Table_9_Nitrogen_Lignin_Content_In_Crops_Data.cs#L9
|
|
337
|
+
"""
|
|
338
|
+
CropType: CropType = CropType.NotSelected
|
|
339
|
+
InterceptValue: float = 0
|
|
340
|
+
SlopeValue: float = 0
|
|
341
|
+
RSTRatio: float = 0
|
|
342
|
+
NitrogenContentResidues: float = 0
|
|
343
|
+
LigninContentResidues: float = 0
|
|
344
|
+
MoistureContent: float = 0
|
|
345
|
+
BiomethaneData: BiogasAndMethaneProductionParametersData = field(
|
|
346
|
+
default_factory=BiogasAndMethaneProductionParametersData)
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def parse_nitrogen_lignin_content_in_crops_data(
|
|
350
|
+
raw_input: str
|
|
351
|
+
) -> NitrogenLigninContentInCropsData:
|
|
352
|
+
"""
|
|
353
|
+
Holos source code:
|
|
354
|
+
https://github.com/holos-aafc/Holos/blob/d62072ff1362eb356ba00f2736293e3fe0f8acc2/H.Core/Providers/Plants/Table_9_Nitrogen_Lignin_Content_In_Crops_Provider.cs#L104
|
|
355
|
+
"""
|
|
356
|
+
columns = raw_input.replace('\n', '').split(',')
|
|
357
|
+
crop_type = parse_crop_type(raw_input=columns[1])
|
|
358
|
+
|
|
359
|
+
columns = [clean_string(input_string=v) for v in columns]
|
|
360
|
+
biomethane_data = BiogasAndMethaneProductionParametersData() if (''.join(columns[8:]) == '') else (
|
|
361
|
+
BiogasAndMethaneProductionParametersData(crop_type, *[float(v) if v != '' else 0 for v in columns[8:]]))
|
|
362
|
+
|
|
363
|
+
return NitrogenLigninContentInCropsData(
|
|
364
|
+
CropType=crop_type,
|
|
365
|
+
InterceptValue=float(columns[2]),
|
|
366
|
+
SlopeValue=float(columns[3]),
|
|
367
|
+
RSTRatio=float(columns[4]),
|
|
368
|
+
NitrogenContentResidues=float(columns[5]),
|
|
369
|
+
LigninContentResidues=float(columns[6]),
|
|
370
|
+
MoistureContent=float(columns[7]),
|
|
371
|
+
BiomethaneData=biomethane_data
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def read_table_9() -> list[str]:
|
|
376
|
+
with PathsHolosResources.Table_9_Default_Values_For_Nitrogen_Lignin_In_Crops.open(mode='r') as f:
|
|
377
|
+
return [v for v in f.readlines() if all([
|
|
378
|
+
not len(v.replace(' ', '').replace(',', '').replace('\n', '')) == 0,
|
|
379
|
+
not v.startswith('#')
|
|
380
|
+
])][1:]
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def parse_table_9() -> list[NitrogenLigninContentInCropsData]:
|
|
384
|
+
"""
|
|
385
|
+
Holos source code:
|
|
386
|
+
https://github.com/holos-aafc/Holos/blob/d62072ff1362eb356ba00f2736293e3fe0f8acc2/H.Core/Providers/Plants/Table_9_Nitrogen_Lignin_Content_In_Crops_Provider.cs#L104
|
|
387
|
+
"""
|
|
388
|
+
return [parse_nitrogen_lignin_content_in_crops_data(raw_input=v) for v in read_table_9()]
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def get_nitrogen_lignin_content_in_crops_data(
|
|
392
|
+
table_9: list[NitrogenLigninContentInCropsData],
|
|
393
|
+
crop_type: CropType
|
|
394
|
+
) -> NitrogenLigninContentInCropsData:
|
|
395
|
+
"""
|
|
396
|
+
|
|
397
|
+
Args:
|
|
398
|
+
table_9: parsed data of table 9
|
|
399
|
+
crop_type: CropType class member
|
|
400
|
+
|
|
401
|
+
Holos source code:
|
|
402
|
+
https://github.com/holos-aafc/Holos/blob/d62072ff1362eb356ba00f2736293e3fe0f8acc2/H.Core/Providers/Plants/Table_9_Nitrogen_Lignin_Content_In_Crops_Provider.cs#L57
|
|
403
|
+
"""
|
|
404
|
+
|
|
405
|
+
lookup_type = CropType.Durum if (crop_type == CropType.Wheat) else (
|
|
406
|
+
CropType.Rye if crop_type == CropType.RyeSecaleCerealeWinterRyeCerealRye else crop_type)
|
|
407
|
+
|
|
408
|
+
res = [v for v in table_9 if v.CropType == lookup_type]
|
|
409
|
+
|
|
410
|
+
return res[0] if len(res) > 0 else NitrogenLigninContentInCropsData()
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from pyholos.common import verify_is_prairie_province
|
|
2
|
+
from pyholos.components.land_management.common import TillageType
|
|
3
|
+
from pyholos.components.land_management.crop import CropType
|
|
4
|
+
from pyholos.config import PathsHolosResources
|
|
5
|
+
from pyholos.common2 import CanadianProvince
|
|
6
|
+
from pyholos.soil import SoilFunctionalCategory
|
|
7
|
+
from pyholos.utils import read_holos_resource_table
|
|
8
|
+
|
|
9
|
+
TABLE_TILLAGE_FACTOR = read_holos_resource_table(
|
|
10
|
+
PathsHolosResources.Table_Tillage_Factor,
|
|
11
|
+
index_col=('SoilFunctionalCategory', 'TillageType'))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def calculate_crop_tillage_factor(
|
|
15
|
+
soil_functional_category: SoilFunctionalCategory,
|
|
16
|
+
tillage_type: TillageType
|
|
17
|
+
) -> float:
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
soil_functional_category: SoilFunctionalCategory class member
|
|
22
|
+
tillage_type: TillageType class member
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
(-) tillage factor
|
|
26
|
+
|
|
27
|
+
Holos source code:
|
|
28
|
+
https://github.com/holos-aafc/Holos/blob/b73623b6beec5ac2e9fea747c0ff5be0477038fa/H.Core/Calculators/Tillage/TillageFactorCalculator.cs#L153
|
|
29
|
+
|
|
30
|
+
Note:
|
|
31
|
+
"Calculates the tillage factor for various types. Table 3 - rc factor – Alberta, Saskatchewan, Manitoba only."
|
|
32
|
+
"""
|
|
33
|
+
try:
|
|
34
|
+
res = TABLE_TILLAGE_FACTOR.loc[(soil_functional_category, tillage_type), 'TillageFactor']
|
|
35
|
+
except KeyError:
|
|
36
|
+
res = 1.
|
|
37
|
+
|
|
38
|
+
return res
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def calculate_tillage_factor_for_perennials(
|
|
42
|
+
soil_functional_category: SoilFunctionalCategory,
|
|
43
|
+
province: CanadianProvince
|
|
44
|
+
) -> float:
|
|
45
|
+
"""Returns the value of the tillage factor for perennial crops.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
soil_functional_category: SoilFunctionalCategory class member
|
|
49
|
+
province: CanadianProvince class member
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
(-) value of the tillage factor for perennial crops
|
|
53
|
+
|
|
54
|
+
Holos source code:
|
|
55
|
+
https://github.com/holos-aafc/Holos/blob/90fad0a9950183da217137490cb756104ba3f7f4/H.Core/Calculators/Tillage/TillageFactorCalculator.cs#L138
|
|
56
|
+
"""
|
|
57
|
+
if not verify_is_prairie_province(province=province):
|
|
58
|
+
res = 0.9
|
|
59
|
+
else:
|
|
60
|
+
res = calculate_crop_tillage_factor(
|
|
61
|
+
soil_functional_category=soil_functional_category,
|
|
62
|
+
tillage_type=TillageType.NoTill)
|
|
63
|
+
return res
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def calculate_tillage_factor(
|
|
67
|
+
province: CanadianProvince,
|
|
68
|
+
soil_functional_category: SoilFunctionalCategory,
|
|
69
|
+
tillage_type: TillageType,
|
|
70
|
+
crop_type: CropType
|
|
71
|
+
) -> float:
|
|
72
|
+
if crop_type.is_root_crop():
|
|
73
|
+
res = 1.13
|
|
74
|
+
elif crop_type.is_annual() and not verify_is_prairie_province(province=province):
|
|
75
|
+
res = 1
|
|
76
|
+
else:
|
|
77
|
+
simplified_soil_category = soil_functional_category.get_simplified_soil_category()
|
|
78
|
+
if crop_type.is_perennial():
|
|
79
|
+
res = calculate_tillage_factor_for_perennials(
|
|
80
|
+
soil_functional_category=simplified_soil_category,
|
|
81
|
+
province=province)
|
|
82
|
+
|
|
83
|
+
else:
|
|
84
|
+
res = calculate_crop_tillage_factor(
|
|
85
|
+
soil_functional_category=simplified_soil_category,
|
|
86
|
+
tillage_type=tillage_type)
|
|
87
|
+
|
|
88
|
+
return res
|