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.

Files changed (55) hide show
  1. pyholos/__init__.py +0 -0
  2. pyholos/common.py +141 -0
  3. pyholos/common2.py +157 -0
  4. pyholos/components/__init__.py +0 -0
  5. pyholos/components/animals/__init__.py +0 -0
  6. pyholos/components/animals/beef.py +766 -0
  7. pyholos/components/animals/common.py +2301 -0
  8. pyholos/components/animals/dairy.py +341 -0
  9. pyholos/components/animals/sheep.py +412 -0
  10. pyholos/components/common.py +170 -0
  11. pyholos/components/land_management/__init__.py +0 -0
  12. pyholos/components/land_management/carbon/__init__.py +0 -0
  13. pyholos/components/land_management/carbon/climate.py +863 -0
  14. pyholos/components/land_management/carbon/management.py +21 -0
  15. pyholos/components/land_management/carbon/relative_biomass_information.py +410 -0
  16. pyholos/components/land_management/carbon/tillage.py +88 -0
  17. pyholos/components/land_management/common.py +220 -0
  18. pyholos/components/land_management/crop.py +1233 -0
  19. pyholos/components/land_management/field_system.py +458 -0
  20. pyholos/components/land_management/utils.py +66 -0
  21. pyholos/config.py +49 -0
  22. pyholos/core_constants.py +20 -0
  23. pyholos/defaults.py +116 -0
  24. pyholos/farm/__init__.py +0 -0
  25. pyholos/farm/enums.py +54 -0
  26. pyholos/farm/farm.py +101 -0
  27. pyholos/farm/farm_inputs.py +633 -0
  28. pyholos/farm/farm_settings.py +542 -0
  29. pyholos/launching.py +86 -0
  30. pyholos/postprocessing/__init__.py +0 -0
  31. pyholos/postprocessing/plots.py +164 -0
  32. pyholos/postprocessing/postprocessing.py +38 -0
  33. pyholos/resources/holos/Table_16_Livestock_Coefficients_BeefAndDairy_Cattle_Provider.csv +21 -0
  34. pyholos/resources/holos/Table_21_Average_Milk_Production_For_Dairy_Cows_By_Province.csv +23 -0
  35. pyholos/resources/holos/Table_22_Livestock_Coefficients_For_Sheep.csv +28 -0
  36. pyholos/resources/holos/Table_29_Percentage_Total_Manure_Produced_In_Systems.csv +56 -0
  37. pyholos/resources/holos/Table_30_Default_Bedding_Material_Composition_Provider.csv +28 -0
  38. pyholos/resources/holos/Table_50_Fuel_Energy_Requirement_Estimates_By_Region.csv +81 -0
  39. pyholos/resources/holos/Table_51_Herbicide_Energy_Requirement_Estimates_By_Region.csv +81 -0
  40. pyholos/resources/holos/Table_61_Fractions_of_dairy_cattle_N_volatilized.csv +25 -0
  41. pyholos/resources/holos/Table_62_Fractions_of_swine_N_volatilized.csv +25 -0
  42. pyholos/resources/holos/Table_6_Manure_Types_And_Default_Composition.csv +126 -0
  43. pyholos/resources/holos/Table_7_Relative_Biomass_Information.csv +112 -0
  44. pyholos/resources/holos/Table_9_Default_Values_For_Nitrogen_Lignin_In_Crops.csv +72 -0
  45. pyholos/resources/holos/Table_Tillage_Factor.csv +13 -0
  46. pyholos/resources/holos/feeds.csv +223 -0
  47. pyholos/resources/holos/main_tables.py +493 -0
  48. pyholos/resources/holos/small_area_yields.csv +167159 -0
  49. pyholos/resources/soil_landscapes_of_canada_v3r2.zip +0 -0
  50. pyholos/soil.py +439 -0
  51. pyholos/utils.py +83 -0
  52. pyholos-0.0.1.dist-info/METADATA +16 -0
  53. pyholos-0.0.1.dist-info/RECORD +55 -0
  54. pyholos-0.0.1.dist-info/WHEEL +4 -0
  55. 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