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,2301 @@
1
+ from enum import auto
2
+ from typing import ClassVar
3
+
4
+ from pandas import DataFrame
5
+ from pydantic import BaseModel, Field, NonNegativeFloat
6
+
7
+ from pyholos import utils
8
+ from pyholos.common import (ClimateZones, EnumGeneric, HolosVar, Region,
9
+ get_climate_zone, get_region)
10
+ from pyholos.components.common import (
11
+ ComponentCategory,
12
+ calculate_fraction_of_nitrogen_lost_by_leaching_and_runoff)
13
+ from pyholos.config import PathsHolosResources
14
+ from pyholos.defaults import Defaults
15
+ from pyholos.common2 import CanadianProvince
16
+ from pyholos.soil import SoilTexture
17
+ from pyholos.utils import AutoNameEnum, read_holos_resource_table
18
+
19
+
20
+ class DietAdditiveType(EnumGeneric):
21
+ """Holos source code: https://github.com/holos-aafc/Holos/blob/396f1ab9bc7247e6d78766f9445c14d2eb7c0d9d/H.Core/Enumerations/DietAdditiveType.cs#L6
22
+
23
+ """
24
+ two_percent_fat: str = "TwoPercentFat"
25
+ four_percent_fat: str = "FourPercentFat"
26
+ five_percent_fat: str = "FivePercentFat"
27
+ ionophore: str = "Inonophore"
28
+ ionophore_plus_two_percent_fat: str = "InonophorePlusTwoPercentFat"
29
+ ionophore_plus_four_percent_fat: str = "InonophorePlusFourPercentFat"
30
+ ionophore_plus_five_percent_fat: str = "IonophorePlusFivePercentFat"
31
+ custom: str = "Custom"
32
+ NONE: str = "None"
33
+
34
+
35
+ class ProductionStage(EnumGeneric):
36
+ gestating: str = "Gestating"
37
+ """Animals that are pregnant.
38
+ """
39
+
40
+ lactating: str = "Lactating"
41
+ """Animals that are lactating. Also known as farrowing in swine systems.
42
+ """
43
+
44
+ open: str = "Open"
45
+ """Animals that are neither lactating or pregnant.
46
+ """
47
+
48
+ weaning: str = "Weaning"
49
+ """Animals that have not been weaned yet.
50
+ """
51
+
52
+ growing_and_finishing: str = "GrowingAndFinishing"
53
+ """Animals that have not been weaned yet.
54
+ """
55
+
56
+ breeding_stock: str = "BreedingStock"
57
+ """Animals that are used for breeding (boars, bulls, etc.)
58
+ """
59
+
60
+ weaned: str = "Weaned"
61
+ """Animals that have been weaned and are no longer milk fed.
62
+ """
63
+
64
+
65
+ class AnimalType(EnumGeneric):
66
+ not_selected: str = "NotSelected"
67
+ alpacas: str = "Alpacas"
68
+ beef_backgrounder: str = "BeefBackgrounder"
69
+ beef_backgrounder_steer: str = "BeefBackgrounderSteer"
70
+ beef_backgrounder_heifer: str = "BeefBackgrounderHeifer"
71
+ beef_finishing_steer: str = "BeefFinishingSteer"
72
+ beef_finishing_heifer: str = "BeefFinishingHeifer"
73
+ beef: str = "Beef"
74
+ beef_bulls: str = "BeefBulls"
75
+ beef_calf: str = "BeefCalf"
76
+ beef_cow_lactating: str = "BeefCowLactating" # This also means 'regular' cows (i.e. non-lactating)
77
+ beef_cow_dry: str = "BeefCowDry"
78
+ beef_finisher: str = "BeefFinisher" # /// Also known as buffalo
79
+ bison: str = "Bison"
80
+ swine_boar: str = "SwineBoar"
81
+ broilers: str = "Broilers"
82
+ chicken: str = "Chicken"
83
+ cow_calf: str = "CowCalf"
84
+ beef_cow: str = "BeefCow"
85
+ calf: str = "Calf"
86
+ dairy: str = "Dairy"
87
+ dairy_bulls: str = "DairyBulls"
88
+ dairy_dry_cow: str = "DairyDryCow"
89
+ dairy_calves: str = "DairyCalves"
90
+ dairy_heifers: str = "DairyHeifers"
91
+ dairy_lactating_cow: str = "DairyLactatingCow"
92
+ deer: str = "Deer"
93
+ swine_dry_sow: str = "SwineDrySow"
94
+ ducks: str = "Ducks"
95
+ elk: str = "Elk"
96
+ ewes: str = "Ewes" # Assumption is all ewes are pregnant
97
+ geese: str = "Geese"
98
+ goats: str = "Goats"
99
+ swine_grower: str = "SwineGrower" # Also known as Hogs
100
+ horses: str = "Horses"
101
+ lambs: str = "Lambs"
102
+ lambs_and_ewes: str = "LambsAndEwes"
103
+ swine_lactating_sow: str = "SwineLactatingSow"
104
+ layers_dry_poultry: str = "LayersDryPoultry"
105
+ layers_wet_poultry: str = "LayersWetPoultry"
106
+ llamas: str = "Llamas"
107
+ mules: str = "Mules"
108
+ other_livestock: str = "OtherLivestock"
109
+ poultry: str = "Poultry"
110
+ beef_replacement_heifers: str = "BeefReplacementHeifers"
111
+ sheep: str = "Sheep"
112
+ ram: str = "Ram"
113
+ weaned_lamb: str = "WeanedLamb"
114
+ sheep_feedlot: str = "SheepFeedlot"
115
+ stockers: str = "Stockers"
116
+ stocker_steers: str = "StockerSteers"
117
+ stocker_heifers: str = "StockerHeifers"
118
+ swine: str = "Swine"
119
+ swine_starter: str = "SwineStarter"
120
+ swine_finisher: str = "SwineFinisher"
121
+ turkeys: str = "Turkeys"
122
+ young_bulls: str = "YoungBulls"
123
+ swine_gilts: str = "SwineGilts" # Female pigs that have not farrowed a litter. Also known as maiden gilts.
124
+ swine_sows: str = "SwineSows"
125
+ swine_piglets: str = "SwinePiglets"
126
+ chicken_pullets: str = "ChickenPullets" # Juvenile female
127
+ chicken_cockerels: str = "ChickenCockerels" # Juvenile male
128
+ chicken_roosters: str = "ChickenRoosters" # Adult male
129
+ chicken_hens: str = "ChickenHens" # Adult female
130
+ young_tom: str = "YoungTom" # Juvenile male turkey
131
+ tom: str = "Tom" # Adult male turkey
132
+ young_turkey_hen: str = "YoungTurkeyHen" # Young female turkey
133
+ turkey_hen: str = "TurkeyHen" # Adult female turkey
134
+ chicken_eggs: str = "ChickenEggs"
135
+ turkey_eggs: str = "TurkeyEggs"
136
+ chicks: str = "Chicks" # Newly hatched chicken
137
+ poults: str = "Poults" # Newly hatched turkey
138
+ cattle: str = "Cattle"
139
+ layers: str = "Layers"
140
+
141
+ def is_young_type(self):
142
+ return self in {
143
+ self.__class__.beef_calf,
144
+ self.__class__.dairy_calves,
145
+ self.__class__.swine_piglets,
146
+ self.__class__.weaned_lamb,
147
+ self.__class__.lambs
148
+ }
149
+
150
+ def is_beef_cattle_type(self):
151
+ return self in {
152
+ self.__class__.beef,
153
+ self.__class__.beef_backgrounder,
154
+ self.__class__.beef_bulls,
155
+ self.__class__.beef_backgrounder_heifer,
156
+ self.__class__.beef_finishing_steer,
157
+ self.__class__.beef_finishing_heifer,
158
+ self.__class__.beef_replacement_heifers,
159
+ self.__class__.beef_finisher,
160
+ self.__class__.beef_backgrounder_steer,
161
+ self.__class__.beef_calf,
162
+ self.__class__.stockers,
163
+ self.__class__.stocker_heifers,
164
+ self.__class__.stocker_steers,
165
+ self.__class__.beef_cow_lactating,
166
+ self.__class__.beef_cow,
167
+ self.__class__.beef_cow_dry
168
+ }
169
+
170
+ def is_dairy_cattle_type(self):
171
+ return self in {
172
+ self.__class__.dairy,
173
+ self.__class__.dairy_lactating_cow,
174
+ self.__class__.dairy_bulls,
175
+ self.__class__.dairy_calves,
176
+ self.__class__.dairy_dry_cow,
177
+ self.__class__.dairy_heifers
178
+ }
179
+
180
+ def is_swine_type(self):
181
+ return self in {
182
+ self.__class__.swine,
183
+ self.__class__.swine_finisher,
184
+ self.__class__.swine_starter,
185
+ self.__class__.swine_lactating_sow,
186
+ self.__class__.swine_dry_sow,
187
+ self.__class__.swine_grower,
188
+ self.__class__.swine_sows,
189
+ self.__class__.swine_boar,
190
+ self.__class__.swine_gilts,
191
+ self.__class__.swine_piglets
192
+ }
193
+
194
+ def is_sheep_type(self):
195
+ return self in {
196
+ self.__class__.sheep,
197
+ self.__class__.lambs_and_ewes,
198
+ self.__class__.ram,
199
+ self.__class__.weaned_lamb,
200
+ self.__class__.lambs,
201
+ self.__class__.ewes,
202
+ self.__class__.sheep_feedlot
203
+ }
204
+
205
+ def is_poultry_type(self):
206
+ return self in {
207
+ self.__class__.poultry,
208
+ self.__class__.layers_wet_poultry,
209
+ self.__class__.layers_dry_poultry,
210
+ self.__class__.layers,
211
+ self.__class__.broilers,
212
+ self.__class__.turkeys,
213
+ self.__class__.ducks,
214
+ self.__class__.geese,
215
+ self.__class__.chicken_pullets,
216
+ self.__class__.chicken_cockerels,
217
+ self.__class__.chicken_roosters,
218
+ self.__class__.chicken_hens,
219
+ self.__class__.young_tom,
220
+ self.__class__.tom,
221
+ self.__class__.young_turkey_hen,
222
+ self.__class__.turkey_hen,
223
+ self.__class__.chicken_eggs,
224
+ self.__class__.turkey_eggs,
225
+ self.__class__.chicks,
226
+ self.__class__.poults
227
+ }
228
+
229
+ def is_other_animal_type(self):
230
+ return self in {
231
+ self.__class__.other_livestock,
232
+ self.__class__.goats,
233
+ self.__class__.alpacas,
234
+ self.__class__.deer,
235
+ self.__class__.elk,
236
+ self.__class__.llamas,
237
+ self.__class__.horses,
238
+ self.__class__.mules,
239
+ self.__class__.bison
240
+ }
241
+
242
+ def is_chicken_type(self):
243
+ return self in {
244
+ self.__class__.chicken,
245
+ self.__class__.chicken_hens,
246
+ self.__class__.layers,
247
+ self.__class__.broilers,
248
+ self.__class__.chicken_roosters,
249
+ self.__class__.chicken_pullets,
250
+ self.__class__.chicken_cockerels,
251
+ self.__class__.chicken_eggs,
252
+ self.__class__.chicks
253
+ }
254
+
255
+ def is_turkey_type(self):
256
+ return self in {
257
+ self.__class__.turkey_hen,
258
+ self.__class__.young_turkey_hen,
259
+ self.__class__.tom,
260
+ self.__class__.turkey_eggs,
261
+ self.__class__.young_tom,
262
+ self.__class__.poults
263
+ }
264
+
265
+ def is_layers_type(self):
266
+ return self in {
267
+ self.__class__.layers,
268
+ self.__class__.layers_dry_poultry,
269
+ self.__class__.layers_wet_poultry
270
+ }
271
+
272
+ def is_lactating_type(self):
273
+ return self in {
274
+ self.__class__.beef_cow_lactating,
275
+ self.__class__.beef_cow,
276
+ self.__class__.dairy_lactating_cow,
277
+ self.__class__.ewes
278
+ }
279
+
280
+ def is_eggs(self):
281
+ return self in {
282
+ self.__class__.chicken_eggs,
283
+ self.__class__.turkey_eggs
284
+ }
285
+
286
+ def is_newly_hatched_eggs(self):
287
+ return self in {
288
+ self.__class__.poults,
289
+ self.__class__.chicks
290
+ }
291
+
292
+ def is_pregnant_type(self):
293
+ return self in {
294
+ self.__class__.beef_cow,
295
+ self.__class__.beef_cow_lactating,
296
+ self.__class__.dairy_lactating_cow,
297
+ self.__class__.dairy_dry_cow,
298
+ self.__class__.ewes
299
+ }
300
+
301
+ def get_category(self):
302
+ if self.is_other_animal_type():
303
+ res = self.other_livestock
304
+
305
+ elif self.is_poultry_type():
306
+ res = self.poultry
307
+
308
+ elif self.is_sheep_type():
309
+ res = self.sheep
310
+
311
+ elif self.is_swine_type():
312
+ res = self.swine
313
+
314
+ elif self.is_dairy_cattle_type():
315
+ res = self.dairy
316
+
317
+ elif self.is_beef_cattle_type():
318
+ res = self.beef
319
+
320
+ else:
321
+ res = self.not_selected
322
+
323
+ return res
324
+
325
+ def get_component_category_from_animal_type(self):
326
+ if self.is_beef_cattle_type():
327
+ res = ComponentCategory.BeefProduction
328
+ elif self.is_dairy_cattle_type():
329
+ res = ComponentCategory.Dairy
330
+ elif self.is_swine_type():
331
+ res = ComponentCategory.Swine
332
+ elif self.is_poultry_type():
333
+ res = ComponentCategory.Poultry
334
+ elif self.is_sheep_type():
335
+ res = ComponentCategory.Sheep
336
+ else:
337
+ res = ComponentCategory.OtherLivestock
338
+
339
+ return res
340
+
341
+
342
+ def convert_animal_type_name(name: str) -> AnimalType:
343
+ """Maps animal type name to its nearest AnimalType Enum.
344
+
345
+ Holos source code:
346
+ https://github.com/RamiALBASHA/Holos/blob/71638efd97c84c6ded45e342ce664477df6f803f/H.Core/Converters/AnimalTypeStringConverter.cs#L10
347
+
348
+ Notes:
349
+ lines followed by multiple '#' were modified from the original code
350
+ """
351
+ cleaned_input = name.lower().strip().replace(' ', '').replace('-', '')
352
+
353
+ match cleaned_input:
354
+ # Beef cattle
355
+ case "backgrounding" | "backgrounder":
356
+ return AnimalType.beef_backgrounder
357
+ case "backgroundingsteers":
358
+ return AnimalType.beef_backgrounder_steer
359
+ case "backgroundingheifers":
360
+ return AnimalType.beef_backgrounder_heifer
361
+ case "beef" | "nondairycattle" | "beefcattle":
362
+ return AnimalType.beef
363
+ case "beeffinisher" | "finisher":
364
+ return AnimalType.beef_finisher
365
+ case "cowcalf":
366
+ return AnimalType.cow_calf
367
+ case "stockers":
368
+ return AnimalType.stockers
369
+ case "beefcalves" | "beefcalf":
370
+ return AnimalType.beef_calf
371
+
372
+ # Dairy
373
+ case "dairy" | "dairycattle":
374
+ return AnimalType.dairy
375
+ case "dairybulls":
376
+ return AnimalType.dairy_bulls
377
+ case "dairydry" | "dairydrycow":
378
+ return AnimalType.dairy_dry_cow
379
+ case "dairyheifers":
380
+ return AnimalType.dairy_heifers
381
+ case "dairylactating":
382
+ return AnimalType.dairy_lactating_cow
383
+
384
+ # Swine
385
+ case "boar" | "swineboar":
386
+ return AnimalType.swine_boar
387
+ case "weaners" | "piglets":
388
+ return AnimalType.swine_piglets
389
+ case "drysow":
390
+ return AnimalType.swine_dry_sow
391
+ case "sow" | "sows":
392
+ return AnimalType.swine_sows
393
+ case "grower" | "hogs" | "swinegrower":
394
+ return AnimalType.swine_grower
395
+ case "lactatingsow":
396
+ return AnimalType.swine_lactating_sow
397
+ case "swine":
398
+ return AnimalType.swine
399
+ case "swinefinisher":
400
+ return AnimalType.swine_finisher
401
+
402
+ # Sheep
403
+ case "sheepfeedlot":
404
+ return AnimalType.sheep_feedlot
405
+ case "ewe" | "ewes":
406
+ return AnimalType.ewes
407
+ case "ram" | "rams": ###################
408
+ return AnimalType.ram
409
+ case "sheep" | "sheepandlambs":
410
+ return AnimalType.sheep
411
+ case "weanedlambs" | "lambs": ####################
412
+ return AnimalType.lambs
413
+
414
+ # Other livestock
415
+ case "horse" | "horses":
416
+ return AnimalType.horses
417
+ case "goat" | "goats":
418
+ return AnimalType.goats
419
+ case "mules" | "mule":
420
+ return AnimalType.mules
421
+ case "bull":
422
+ return AnimalType.beef_bulls
423
+ case "llamas":
424
+ return AnimalType.llamas
425
+ case "alpacas":
426
+ return AnimalType.alpacas
427
+ case "deer":
428
+ return AnimalType.deer
429
+ case "elk":
430
+ return AnimalType.elk
431
+ case "bison":
432
+ return AnimalType.bison
433
+
434
+ # Poultry
435
+ case "poultry":
436
+ return AnimalType.poultry
437
+ case "poultrypulletsbroilers" | "chickenbroilers" | "broilers":
438
+ return AnimalType.broilers
439
+ case "chickenpullets" | "pullets":
440
+ return AnimalType.chicken_pullets
441
+ case "chicken":
442
+ return AnimalType.chicken
443
+ case "chickencockerels" | "cockerels":
444
+ return AnimalType.chicken_cockerels
445
+ case "roasters" | "roosters" | "chickenroosters": ####################
446
+ return AnimalType.chicken_roosters
447
+ case "hens":
448
+ return AnimalType.chicken_hens
449
+ case "poultryturkeys" | "turkey" | "ducks":
450
+ return AnimalType.ducks
451
+ case "geese":
452
+ return AnimalType.geese
453
+ case "turkeys":
454
+ return AnimalType.turkeys
455
+ case "layersdry" | "layersdrypoultry": ################
456
+ return AnimalType.layers_dry_poultry
457
+ case "layerswet" | "layerswetpoultry": ################
458
+ return AnimalType.layers_wet_poultry
459
+ case "poultrylayers" | "chickenlayers" | "layers":
460
+ return AnimalType.layers
461
+ case _:
462
+ # raise ValueError(f"unknown animal type. Returning {AnimalType.beef_backgrounder}")
463
+ return AnimalType.beef_backgrounder
464
+
465
+
466
+ class ManureAnimalSourceTypes(AutoNameEnum):
467
+ """
468
+ Holos source type:
469
+ https://github.com/holos-aafc/Holos/blob/c06f6619907fba89c3ddc29b4239a903a8c20a7a/H.Core/Enumerations/ManureAnimalSourceTypes.cs#L9
470
+ """
471
+ NotSelected = auto()
472
+ BeefManure = auto()
473
+ DairyManure = auto()
474
+ SwineManure = auto()
475
+ PoultryManure = auto()
476
+ SheepManure = auto()
477
+ OtherLivestockManure = auto()
478
+
479
+
480
+ class ManureLocationSourceType(AutoNameEnum):
481
+ NotSelected = auto()
482
+ Livestock = auto()
483
+ Imported = auto()
484
+ OnFarmAnaerobicDigestor = auto()
485
+
486
+
487
+ class Milk(BaseModel):
488
+ """Milk production data
489
+
490
+ Args:
491
+ production: (kg) average milk production value based on the province and year specified by user
492
+ fat_content: (%) fat content of milk
493
+ protein_content_as_percentage: (%) protein content of milk
494
+
495
+ Notes:
496
+ arg 'protein_content_as_percentage' is deprecated and will be removed in future version.
497
+ """
498
+ production: float = 0
499
+ fat_content: float = 4
500
+ protein_content_as_percentage: float = 3.5
501
+
502
+
503
+ class Diet(BaseModel):
504
+ specs: ClassVar = Field(NonNegativeFloat, ge=0, le=100)
505
+ """Diet composition data
506
+
507
+ Args:
508
+ crude_protein_percentage: (-) percentage of crude protein in the diet dry matter (between 0 and 100)
509
+ forage_percentage: (-) percentage of forage in the diet dry matter (between 0 and 100)
510
+ total_digestible_nutrient_percentage: (-) percentage of total digestible nutrient in the diet dry matter (between 0 and 100)
511
+ ash_percentage: (-) percentage of ash in the diet dry matter (between 0 and 100)
512
+ starch_percentage: (-) percentage of starch in the diet dry matter (between 0 and 100)
513
+ fat_percentage: (-) percentage of fat in the diet dry matter (between 0 and 100)
514
+ neutral_detergent_fiber_percentage: (-) percentage of neutral detergent fiber in the diet dry matter (between 0 and 100)
515
+ metabolizable_energy: (Mcal kg-1) metabolizable energy of the diet
516
+ """
517
+ crude_protein_percentage: NonNegativeFloat
518
+ forage_percentage: NonNegativeFloat
519
+ total_digestible_nutrient_percentage: NonNegativeFloat
520
+ ash_percentage: NonNegativeFloat
521
+ starch_percentage: NonNegativeFloat
522
+ fat_percentage: NonNegativeFloat
523
+ neutral_detergent_fiber_percentage: NonNegativeFloat
524
+ metabolizable_energy: NonNegativeFloat
525
+
526
+ # dietary_net_energy_concentration: float
527
+
528
+ @staticmethod
529
+ def calc_dietary_net_energy_concentration(
530
+ net_energy_for_maintenance: float,
531
+ net_energy_for_growth: float
532
+ ) -> float:
533
+ """Calculates the dietary net energy concentration
534
+
535
+ Args:
536
+ net_energy_for_maintenance: (Mcal/kg DM) net energy for maintenance
537
+ net_energy_for_growth: (Mcal/kg DM) net energy for growth
538
+
539
+ Returns:
540
+ (MJ/kg DM): dietary net energy concentration
541
+
542
+ Notes:
543
+ NEmf (MJ/kg DM) = [NEma (Mcal/kg DM) + NEga (Mcal/kg DM)] * 4.184 (conversion factor for Mcal to MJ)
544
+
545
+ References:
546
+ Holos source code https://github.com/holos-aafc/Holos/blob/396f1ab9bc7247e6d78766f9445c14d2eb7c0d9d/H.Core/Providers/Feed/FeedIngredient.cs#L1319
547
+
548
+ """
549
+ return (net_energy_for_maintenance + net_energy_for_growth) * 4.184
550
+
551
+ def calc_dietary_net_energy_concentration_for_beef(self) -> float:
552
+ """Calculates the dietary net energy concentration of a beef cattle diet as a function of the metabolizable energy.
553
+
554
+ Returns:
555
+ (MJ (kg DM)^-1) dietary net energy concentration
556
+
557
+ Notes:
558
+ This relationship is deduced from the dairy cattle feed composition table provided in the Holos source code
559
+ 'https://github.com/holos-aafc/Holos/blob/main/H.Content/Resources/dairy_feed_composition.csv
560
+
561
+ """
562
+ return self.calc_dietary_net_energy_concentration(
563
+ net_energy_for_maintenance=self.metabolizable_energy * 0.8756 - 0.5972,
564
+ net_energy_for_growth=self.metabolizable_energy * 0.7632 - 0.9276)
565
+
566
+ def calc_dietary_net_energy_concentration_for_dairy(self) -> float:
567
+ """Calculates the dietary net energy concentration of a dairy cattle diet as a function of the metabolizable energy.
568
+
569
+ Returns:
570
+ (MJ (kg DM)^-1) dietary net energy concentration
571
+
572
+ Notes:
573
+ This relationship is deduced from the feed composition table provided in the Holos source code
574
+ https://github.com/holos-aafc/Holos/blob/main/H.Content/Resources/feeds.csv
575
+
576
+ """
577
+ return self.calc_dietary_net_energy_concentration(
578
+ net_energy_for_maintenance=self.metabolizable_energy * 0.8134 - 0.3518,
579
+ net_energy_for_growth=self.metabolizable_energy * 0.6299 - 0.5162)
580
+
581
+ def calc_methane_conversion_factor_for_beef_and_dairy_cattle(
582
+ self,
583
+ animal_type: AnimalType
584
+ ) -> float:
585
+ """Calculates the methane conversion factor based on the animal type.
586
+
587
+ Args:
588
+ animal_type: AnimalType class instance
589
+
590
+ Returns:
591
+ (kg CH4 kg CH4-1) methane conversion factor for diet (Y_m)
592
+
593
+ Holos Source Code:
594
+ https://github.com/holos-aafc/Holos/blob/2bc9704a51449a8ffd4005462a6a7e6fb8a27f2d/H.Core/Providers/Feed/Diet.cs#L602
595
+ """
596
+ # Assign a default ym so that if there are no cases that cover the diet below, there will be a value assigned
597
+ result = 0.4
598
+ total_digestible_nutrient = self.total_digestible_nutrient_percentage
599
+
600
+ if animal_type.is_dairy_cattle_type():
601
+ if total_digestible_nutrient >= 65:
602
+ result = 0.063
603
+ elif 55 <= total_digestible_nutrient < 65:
604
+ result = 0.065
605
+ else:
606
+ result = 0.07
607
+
608
+ if animal_type.is_beef_cattle_type():
609
+ if total_digestible_nutrient >= 65:
610
+ result = 0.065
611
+ elif 55 <= total_digestible_nutrient < 65:
612
+ result = 0.07
613
+ else:
614
+ result = 0.08
615
+
616
+ if animal_type == AnimalType.beef_finisher:
617
+ if total_digestible_nutrient >= 82:
618
+ result = 0.03
619
+ else:
620
+ result = 0.04
621
+ # The percentage threshold value of 82 is the rounded value of TDN for the basic diet CornGrainBasedDiet.
622
+ # This TDN value is the weighted average of the TDN values of all three ingredients of this diet, i.e.
623
+ # BarleySilage (% TDN = 60.6, % DM in diet=10) and BarleyGrain (% TDN = 84.1, % DM in diet=90)
624
+ # The original code for this part of the function in commented below.
625
+ # if (string.IsNullOrWhiteSpace(this.Name) == false)
626
+ # {
627
+ # if (this.Name.Equals(Resources.LabelCornGrainBasedDiet))
628
+ # {
629
+ # result = 0.03;
630
+ # }
631
+ #
632
+ # if (this.Name.Equals(Resources.LabelBarleyGrainBasedDiet))
633
+ # {
634
+ # result = 0.04;
635
+ #
636
+ # }
637
+ # }
638
+
639
+ return result
640
+
641
+ @staticmethod
642
+ def calc_methane_conversion_factor_for_sheep() -> float:
643
+ """Returns the methane conversion factor for sheep irrespective of feed quality values
644
+
645
+ Returns:
646
+ (kg CH4 kg CH4-1) methane conversion factor for diet (Y_m)
647
+
648
+ Holos Source Code:
649
+ https://github.com/holos-aafc/Holos/blob/2bc9704a51449a8ffd4005462a6a7e6fb8a27f2d/H.Content/Resources/Table_18_26_Diet_Coefficients_For_Beef_Dairy_Sheep.csv#L33
650
+
651
+ """
652
+ return 0.067
653
+
654
+ def calc_methane_conversion_factor(
655
+ self,
656
+ animal_type: AnimalType
657
+ ) -> float:
658
+ """Calculates the methane conversion factor based on the animal type.
659
+
660
+ Args:
661
+ animal_type: AnimalType class instance
662
+
663
+ Returns:
664
+ (kg CH4 kg CH4-1) methane conversion factor for diet (Y_m)
665
+ """
666
+ if animal_type.is_beef_cattle_type() or animal_type.is_dairy_cattle_type():
667
+ res = self.calc_methane_conversion_factor_for_beef_and_dairy_cattle(animal_type=animal_type)
668
+ elif animal_type.is_sheep_type():
669
+ res = self.calc_methane_conversion_factor_for_sheep()
670
+ else:
671
+ res = None
672
+
673
+ return res
674
+
675
+
676
+ class HousingType(EnumGeneric):
677
+ not_selected: str = "NotSelected"
678
+ confined_no_barn: str = "ConfinedNoBarn"
679
+ """Also known as 'Confined no barn (feedlot)'
680
+ """
681
+ housed_in_barn: str = "HousedInBarn"
682
+ housed_ewes: str = "HousedEwes"
683
+ housed_in_barn_solid: str = "HousedInBarnSolid"
684
+ housed_in_barn_slurry: str = "HousedInBarnSlurry"
685
+ enclosed_pasture: str = "EnclosedPasture"
686
+ open_range_or_hills: str = "OpenRangeOrHills"
687
+ tie_stall: str = "TieStall"
688
+ small_free_stall: str = "SmallFreeStall"
689
+ large_free_stall: str = "LargeFreeStall"
690
+ grazing_under3km: str = "GrazingUnder3km"
691
+ grazing_over3km: str = "GrazingOver3km"
692
+ confined: str = "Confined"
693
+ flat_pasture: str = "FlatPasture"
694
+ hilly_pasture_or_open_range: str = "HillyPastureOrOpenRange"
695
+ pasture: str = "Pasture"
696
+ """Pasture, range, or paddock
697
+ """
698
+ dry_lot: str = "DryLot"
699
+ """Also known as 'Standing or exercise yard'
700
+ """
701
+ swath_grazing: str = "SwathGrazing"
702
+ custom: str = "Custom"
703
+ free_stall_barn_solid_litter: str = "FreeStallBarnSolidLitter"
704
+ free_stall_barn_slurry_scraping: str = "FreeStallBarnSlurryScraping"
705
+ free_stall_barn_flushing: str = "FreeStallBarnFlushing"
706
+ free_stall_barn_milk_parlour_slurry_flushing: str = "FreeStallBarnMilkParlourSlurryFlushing"
707
+ """Also known as 'Milking parlour (slurry - flushing)'
708
+ """
709
+ tie_stall_solid_litter: str = "TieStallSolidLitter"
710
+ """Also known as 'Tie-stall barn (solid)'
711
+ """
712
+ tie_stall_slurry: str = "TieStallSlurry"
713
+ """Also known as 'Tie-stall barn (slurry)'
714
+ """
715
+
716
+ # This section corresponds to the HousingTypeExtensions class in the original holos source code
717
+ # https://github.com/holos-aafc/Holos/blob/53f778f9bd4579d164de10f5b04db34d020b96a9/H.Core/Enumerations/HousingTypeExtensions.cs#L10
718
+
719
+ def is_free_stall(self):
720
+ return self in {
721
+ self.__class__.small_free_stall,
722
+ self.__class__.large_free_stall,
723
+ self.__class__.free_stall_barn_flushing,
724
+ self.__class__.free_stall_barn_milk_parlour_slurry_flushing,
725
+ self.__class__.free_stall_barn_slurry_scraping,
726
+ self.__class__.free_stall_barn_solid_litter
727
+ }
728
+
729
+ def is_tie_stall(self):
730
+ return self in {
731
+ self.__class__.tie_stall,
732
+ self.__class__.tie_stall_slurry,
733
+ self.__class__.tie_stall_solid_litter
734
+ }
735
+
736
+ def is_barn(self):
737
+ return self in {
738
+ self.__class__.housed_in_barn,
739
+ self.__class__.housed_in_barn_slurry,
740
+ self.__class__.housed_in_barn_solid
741
+ }
742
+
743
+ def is_feed_lot(self):
744
+ return self in {
745
+ self.__class__.confined,
746
+ self.__class__.confined_no_barn
747
+ }
748
+
749
+ def is_electrical_consuming_housing_type(self):
750
+ return any([
751
+ self.is_free_stall(),
752
+ self.is_barn(),
753
+ self.is_tie_stall(),
754
+ self.is_feed_lot()])
755
+
756
+ def is_indoor_housing(self):
757
+ return self in {
758
+ self.__class__.housed_in_barn,
759
+ self.__class__.housed_in_barn_slurry,
760
+ self.__class__.housed_in_barn_solid,
761
+ self.__class__.free_stall_barn_flushing,
762
+ self.__class__.free_stall_barn_solid_litter,
763
+ self.__class__.free_stall_barn_slurry_scraping,
764
+ self.__class__.free_stall_barn_milk_parlour_slurry_flushing
765
+ }
766
+
767
+ def is_pasture(self):
768
+ return self in {
769
+ self.__class__.pasture,
770
+ self.__class__.enclosed_pasture,
771
+ self.__class__.flat_pasture,
772
+ self.__class__.grazing_over3km,
773
+ self.__class__.grazing_under3km,
774
+ self.__class__.hilly_pasture_or_open_range,
775
+ self.__class__.open_range_or_hills,
776
+ self.__class__.swath_grazing
777
+ }
778
+
779
+
780
+ class BeddingMaterialType(EnumGeneric):
781
+ straw: str = 'Straw'
782
+ wood_chip: str = 'WoodChip'
783
+ separated_manure_solid: str = 'SeparatedManureSolid'
784
+ sand: str = 'Sand'
785
+ straw_long: str = 'StrawLong'
786
+ straw_chopped: str = 'StrawChopped'
787
+ shavings: str = 'Shavings'
788
+ sawdust: str = 'Sawdust'
789
+ paper_products: str = 'PaperProducts'
790
+ peat: str = 'Peat'
791
+ hemp: str = 'Hemp'
792
+ NONE = None
793
+
794
+
795
+ class Bedding:
796
+ def __init__(
797
+ self,
798
+ housing_type: HousingType,
799
+ bedding_material_type: BeddingMaterialType | None,
800
+ animal_type: AnimalType,
801
+ total_carbon_kilograms_dry_matter_for_bedding: float = None,
802
+ total_nitrogen_kilograms_dry_matter_for_bedding: float = None,
803
+ moisture_content_of_bedding_material: float = None
804
+ ):
805
+ default_bedding_material_composition = self.get_bedding_material_composition(
806
+ bedding_material_type=bedding_material_type,
807
+ animal_type=animal_type)
808
+
809
+ if total_carbon_kilograms_dry_matter_for_bedding is None:
810
+ total_carbon_kilograms_dry_matter_for_bedding = default_bedding_material_composition[
811
+ 'TotalCarbonKilogramsDryMatter']
812
+ if total_nitrogen_kilograms_dry_matter_for_bedding is None:
813
+ total_nitrogen_kilograms_dry_matter_for_bedding = default_bedding_material_composition[
814
+ 'TotalNitrogenKilogramsDryMatter']
815
+ if moisture_content_of_bedding_material is None:
816
+ moisture_content_of_bedding_material = default_bedding_material_composition['MoistureContent']
817
+
818
+ self.user_defined_bedding_rate = HolosVar(
819
+ name='User Defined Bedding Rate',
820
+ value=self.get_default_bedding_rate(
821
+ housing_type=housing_type,
822
+ bedding_material_type=bedding_material_type,
823
+ animal_type=animal_type))
824
+ self.total_carbon_kilograms_dry_matter_for_bedding = HolosVar(
825
+ name='Total Carbon Kilograms Dry Matter For Bedding',
826
+ value=total_carbon_kilograms_dry_matter_for_bedding)
827
+ self.total_nitrogen_kilograms_dry_matter_for_bedding = HolosVar(
828
+ name='Total Nitrogen Kilograms Dry Matter For Bedding',
829
+ value=total_nitrogen_kilograms_dry_matter_for_bedding)
830
+ self.moisture_content_of_bedding_material = HolosVar(
831
+ name='Moisture Content Of Bedding Material',
832
+ value=moisture_content_of_bedding_material)
833
+
834
+ @staticmethod
835
+ def get_default_bedding_rate(
836
+ housing_type: HousingType,
837
+ bedding_material_type: BeddingMaterialType,
838
+ animal_type: AnimalType
839
+ ) -> int | float:
840
+ # https://github.com/holos-aafc/Holos/blob/53f778f9bd4579d164de10f5b04db34d020b96a9/H.Core/Providers/Animals/Table_30_Default_Bedding_Material_Composition_Provider.cs#L301
841
+
842
+ if housing_type.is_pasture():
843
+ return 0
844
+
845
+ if animal_type.is_young_type():
846
+ return 0
847
+
848
+ if animal_type.is_beef_cattle_type():
849
+ if bedding_material_type == BeddingMaterialType.straw:
850
+ if housing_type.is_feed_lot():
851
+ return 1.5
852
+
853
+ if housing_type.is_barn():
854
+ return 3.5
855
+
856
+ if bedding_material_type == BeddingMaterialType.wood_chip:
857
+ if housing_type.is_feed_lot():
858
+ return 3.6
859
+
860
+ if housing_type.is_barn():
861
+ return 5.0
862
+
863
+ if animal_type.is_dairy_cattle_type():
864
+ # Currently, all housing types have same rates for bedding types
865
+ if any([
866
+ housing_type.is_tie_stall(),
867
+ housing_type.is_free_stall(),
868
+ housing_type == HousingType.dry_lot]):
869
+ if bedding_material_type == BeddingMaterialType.sand:
870
+ return 24.3
871
+
872
+ if bedding_material_type == BeddingMaterialType.separated_manure_solid:
873
+ return 0
874
+
875
+ if bedding_material_type == BeddingMaterialType.straw_long:
876
+ return 0.7
877
+
878
+ if bedding_material_type == BeddingMaterialType.straw_chopped:
879
+ return 0.7
880
+
881
+ if bedding_material_type == BeddingMaterialType.shavings:
882
+ return 2.1
883
+
884
+ if bedding_material_type == BeddingMaterialType.sawdust:
885
+ return 2.1
886
+
887
+ # Footnote 8 for sheep value reference.
888
+ if animal_type.is_sheep_type():
889
+ return 0.57
890
+
891
+ if animal_type.is_swine_type():
892
+ if bedding_material_type == BeddingMaterialType.straw_long:
893
+ return 0.70
894
+ else:
895
+ return 0.79
896
+
897
+ if animal_type.is_poultry_type():
898
+ if any([
899
+ bedding_material_type == BeddingMaterialType.sawdust,
900
+ bedding_material_type == BeddingMaterialType.straw,
901
+ bedding_material_type == BeddingMaterialType.shavings]):
902
+ if animal_type == AnimalType.broilers:
903
+ return 0.0014
904
+
905
+ if animal_type == AnimalType.chicken_pullets:
906
+ return 0.0014
907
+
908
+ if any([
909
+ animal_type == AnimalType.layers,
910
+ animal_type == AnimalType.chicken_hens]):
911
+ return 0.0028
912
+
913
+ if animal_type.is_turkey_type():
914
+ return 0.011
915
+
916
+ else:
917
+ return 0
918
+ else:
919
+ return 0
920
+
921
+ if animal_type.is_other_animal_type():
922
+ # Footnote 11 for Other livestock value reference
923
+ match animal_type:
924
+ case AnimalType.llamas:
925
+ return 0.57
926
+
927
+ case AnimalType.alpacas:
928
+ return 0.57
929
+
930
+ case AnimalType.deer:
931
+ return 1.5
932
+
933
+ case AnimalType.elk:
934
+ return 1.5
935
+
936
+ case AnimalType.goats:
937
+ return 0.57
938
+
939
+ case AnimalType.horses:
940
+ return 1.5
941
+
942
+ case AnimalType.mules:
943
+ return 1.5
944
+
945
+ case AnimalType.bison:
946
+ return 1.5
947
+
948
+ # added here since the original case statement in C# does not cover all possibilities
949
+ case _:
950
+ return 1
951
+ else:
952
+ return 1
953
+
954
+ pass
955
+
956
+ @staticmethod
957
+ def get_bedding_material_composition(
958
+ bedding_material_type: BeddingMaterialType,
959
+ animal_type: AnimalType
960
+ ) -> dict:
961
+ if animal_type.is_beef_cattle_type():
962
+ animal_lookup_type = AnimalType.beef
963
+ elif animal_type.is_dairy_cattle_type():
964
+ animal_lookup_type = AnimalType.dairy
965
+ elif animal_type.is_sheep_type():
966
+ animal_lookup_type = AnimalType.sheep
967
+ elif animal_type.is_swine_type():
968
+ animal_lookup_type = AnimalType.swine
969
+ elif animal_type.is_poultry_type():
970
+ animal_lookup_type = AnimalType.poultry
971
+ else:
972
+ # Other animals have a value for animal group (Horses, Goats, etc.)
973
+ animal_lookup_type = animal_type
974
+
975
+ df = HolosTables.Table_30_Default_Bedding_Material_Composition_Provider
976
+
977
+ result = df[
978
+ (df['BeddingMaterial'] == bedding_material_type.value) &
979
+ (df['AnimalType'] == animal_lookup_type.value)]
980
+
981
+ if not result.empty:
982
+ return result.iloc[0].to_dict()
983
+ else:
984
+ # Trace.TraceError($"{nameof(Farm)}.{nameof(GetBeddingMaterialComposition)}: unable to return bedding material data for {animalType.GetDescription()}, and {beddingMaterialType.GetHashCode()}. Returning default value of 1.");
985
+
986
+ # return new Table_30_Default_Bedding_Material_Composition_Data();
987
+ return {k: None for k in result.columns}
988
+
989
+
990
+ class AnimalCoefficientData:
991
+ def __init__(
992
+ self,
993
+ baseline_maintenance_coefficient: float = 0,
994
+ gain_coefficient: float = 0,
995
+ default_initial_weight: float = 0,
996
+ default_final_weight: float = 0
997
+ ):
998
+ """Table 16. Livestock coefficients for beef cattle and dairy cattle.
999
+
1000
+ Args:
1001
+ baseline_maintenance_coefficient: (MJ d-1 kg-1) baseline maintenance coefficient (C_f)
1002
+ gain_coefficient: (dimensionless?) gain coefficient (C_d)
1003
+ default_initial_weight: (kg) initial weight
1004
+ default_final_weight: (kg) final weight
1005
+ """
1006
+ self.baseline_maintenance_coefficient = baseline_maintenance_coefficient
1007
+ self.gain_coefficient = gain_coefficient
1008
+ self.default_initial_weight = default_initial_weight
1009
+ self.default_final_weight = default_final_weight
1010
+
1011
+
1012
+ def get_methane_producing_capacity_of_manure(
1013
+ animal_type: AnimalType
1014
+ ) -> float:
1015
+ """Returns the default methane producing capacity of manure as a function of the animal type
1016
+
1017
+ Args:
1018
+ animal_type: animal type object
1019
+
1020
+ Returns:
1021
+ (m^3 CH4 kg^-1 VS): Methane producing capacity of manure (B_o)
1022
+
1023
+ References:
1024
+ https://github.com/holos-aafc/Holos/blob/396f1ab9bc7247e6d78766f9445c14d2eb7c0d9d/H.Core/Providers/Animals/Table_35_Methane_Producing_Capacity_Default_Values_Provider.cs#L15
1025
+
1026
+ """
1027
+ # Table 35. Default values for maximum methane producing capacity (Bo).
1028
+ # <para>Source: IPCC (2019), Table 10.16</para>
1029
+ # Footnote 3 : For Methane producing capacity (B0) value reference.
1030
+
1031
+ if animal_type.is_beef_cattle_type():
1032
+ res = 0.19
1033
+
1034
+ elif animal_type.is_dairy_cattle_type():
1035
+ res = 0.24
1036
+
1037
+ elif animal_type.is_swine_type():
1038
+ res = 0.48
1039
+
1040
+ elif animal_type.is_sheep_type():
1041
+ res = 0.19
1042
+
1043
+ elif any([
1044
+ animal_type == AnimalType.chicken_roosters,
1045
+ animal_type == AnimalType.broilers
1046
+ ]):
1047
+ # Used for broilers from algorithm document
1048
+ res = 0.36
1049
+
1050
+ elif any((
1051
+ animal_type == AnimalType.chicken_hens,
1052
+ animal_type == AnimalType.chicken_pullets,
1053
+ animal_type == AnimalType.chicken_cockerels,
1054
+ animal_type == AnimalType.layers
1055
+ )):
1056
+ # Used for layers (wet/dry) from algorithm document
1057
+ res = 0.39
1058
+
1059
+ elif animal_type == AnimalType.goats:
1060
+ res = 0.18
1061
+
1062
+ elif animal_type == AnimalType.horses:
1063
+ res = 0.30
1064
+
1065
+ elif animal_type == AnimalType.mules:
1066
+ res = 0.33
1067
+
1068
+ # Footnote 2
1069
+ elif any((
1070
+ animal_type == AnimalType.llamas,
1071
+ animal_type == AnimalType.alpacas
1072
+ )):
1073
+ res = 0.19
1074
+
1075
+ # Footnote 1
1076
+ elif animal_type == AnimalType.bison:
1077
+ res = 0.10
1078
+
1079
+ else:
1080
+ res = 0
1081
+
1082
+ # Footnote 1: Value for non-dairy cattle used
1083
+ # Footnote 2: Value for sheep used
1084
+ # Footnote 3: For all animals on pasture, range or paddock, the Bo should be set to 0.19
1085
+
1086
+ return res
1087
+
1088
+
1089
+ def get_default_methane_producing_capacity_of_manure(
1090
+ is_pasture: bool,
1091
+ animal_type: AnimalType
1092
+ ) -> float:
1093
+ """Returns the default methane producing capacity of manure.
1094
+
1095
+ Args:
1096
+ is_pasture: True if the housing type is pasture, otherwise False
1097
+ animal_type: animal type class
1098
+
1099
+ Returns:
1100
+ (m^3 CH4 kg^-1 VS): Methane producing capacity of manure (B_o)
1101
+
1102
+ Notes:
1103
+ When housed on pasture, this value should be set to a constant.
1104
+ See table 38 "Default values (in Holos source code) for maximum methane producing capacity (Bo)" footnote 3.
1105
+
1106
+ References:
1107
+ https://github.com/holos-aafc/Holos/blob/396f1ab9bc7247e6d78766f9445c14d2eb7c0d9d/H.Core/Services/Initialization/Animals/AnimalInitializationService.Methane.cs#L89
1108
+ """
1109
+ return 0.19 if is_pasture else get_methane_producing_capacity_of_manure(animal_type=animal_type)
1110
+
1111
+
1112
+ class FractionOfOrganicNitrogenMineralizedData:
1113
+ def __init__(
1114
+ self,
1115
+ fraction_immobilized: float = 0,
1116
+ fraction_mineralized: float = 0,
1117
+ fraction_nitrified: float = 0,
1118
+ fraction_denitrified: float = 0,
1119
+ n2o_n: float = 0,
1120
+ no_n: float = 0,
1121
+ n2_n: float = 0,
1122
+ n_leached: float = 0,
1123
+ ):
1124
+ """Mineralization of organic N (fecal N and bedding N)
1125
+
1126
+ Args:
1127
+ fraction_mineralized: (dimensionless) fraction of nitrogen mineralized
1128
+ fraction_immobilized: (dimensionless) fraction of nitrogen immobilized
1129
+ fraction_nitrified: (dimensionless) fraction of nitrogen nitrified
1130
+ fraction_denitrified: (dimensionless) fraction of nitrogen denitrified
1131
+ n2o_n:
1132
+ no_n:
1133
+ n2_n:
1134
+ n_leached:
1135
+ """
1136
+ self.fraction_mineralized = fraction_mineralized
1137
+ self.fraction_immobilized = fraction_immobilized
1138
+ self.fraction_nitrified = fraction_nitrified
1139
+ self.fraction_denitrified = fraction_denitrified
1140
+ self.n2o_n = n2o_n
1141
+ self.no_n = no_n
1142
+ self.n2_n = n2_n
1143
+ self.n_leached = n_leached
1144
+
1145
+ def __eq__(self, other):
1146
+ return self.__dict__ == other.__dict__ if isinstance(other, self.__class__) else False
1147
+
1148
+
1149
+ class ManureStateType(EnumGeneric):
1150
+ not_selected: str = "NotSelected"
1151
+ anaerobic_digester: str = "AnaerobicDigester"
1152
+ composted: str = "Composted"
1153
+ compost_intensive: str = "CompostIntensive" # Also known as 'compost - intensive windrow'
1154
+ compost_passive: str = "CompostPassive" # Also known as 'compost - passive windrow'
1155
+ daily_spread: str = "DailySpread"
1156
+ deep_bedding: str = "DeepBedding"
1157
+ deep_pit: str = "DeepPit" # Also known as 'Deep pit under barn'
1158
+ liquid: str = "Liquid"
1159
+ liquid_crust: str = "LiquidCrust" # [Obsolete]
1160
+ liquid_separated: str = "LiquidSeparated" # [Obsolete]
1161
+ liquid_no_crust: str = "LiquidNoCrust" # Also known as 'Liquid/Slurry with no natural crust'
1162
+ pasture: str = "Pasture"
1163
+ range: str = "Range"
1164
+ paddock: str = "Paddock"
1165
+ solid: str = "Solid"
1166
+ slurry: str = "Slurry" # [Obsolete]
1167
+ slurry_with_natural_crust: str = "SlurryWithNaturalCrust" # [Obsolete]
1168
+ slurry_without_natural_crust: str = "SlurryWithoutNaturalCrust" # [Obsolete]
1169
+ solid_storage: str = "SolidStorage" # Also known as 'Solid storage (stockpiled)'
1170
+ custom: str = "Custom"
1171
+ pit_lagoon_no_cover: str = "PitLagoonNoCover" # [Obsolete]
1172
+ liquid_with_natural_crust: str = "LiquidWithNaturalCrust" # Also known as 'Liquid/Slurry with natural crust'
1173
+ liquid_with_solid_cover: str = "LiquidWithSolidCover" # Also known as Liquid/Slurry with solid cover
1174
+ composted_in_vessel: str = "CompostedInVessel" # (Swine system)
1175
+ solid_storage_with_or_without_litter: str = "SolidStorageWithOrWithoutLitter" # (Poultry system) No different than 'Solid Storage' but poultry solid storage needs the term 'litter' which is incorrect to use in the case of cattle 'Solid Storage' since there is no 'litter' only 'bedding' when considering the cattle system
1176
+
1177
+ # These methods correspond to the ManureStateTypeExtensions
1178
+ # https://github.com/holos-aafc/Holos/blob/396f1ab9bc7247e6d78766f9445c14d2eb7c0d9d/H.Core/Enumerations/ManureStateTypeExtensions.cs#L9
1179
+ def is_grazing_area(self) -> bool:
1180
+ return self in {
1181
+ self.__class__.paddock,
1182
+ self.__class__.range,
1183
+ self.__class__.pasture
1184
+ }
1185
+
1186
+ def is_liquid_manure(self) -> bool:
1187
+ """Indicates if the storage type being used houses liquid manure.
1188
+
1189
+ Returns:
1190
+ True if the storage type is for liquid manure, False otherwise
1191
+ """
1192
+ return self in {
1193
+ self.__class__.liquid_no_crust,
1194
+ self.__class__.liquid_with_natural_crust,
1195
+ self.__class__.liquid_with_solid_cover,
1196
+ self.__class__.deep_pit
1197
+ }
1198
+
1199
+ def is_compost(self) -> bool:
1200
+ return self in {
1201
+ self.__class__.compost_intensive,
1202
+ self.__class__.compost_passive,
1203
+ self.__class__.composted
1204
+ }
1205
+
1206
+ def is_solid_manure(self) -> bool:
1207
+ """Indicates if the storage type being used houses solid manure.
1208
+
1209
+ Returns:
1210
+ True if the storage type is for solid manure, False otherwise
1211
+ """
1212
+ return not self.is_liquid_manure()
1213
+
1214
+ def is_covered_system(self) -> bool:
1215
+ # Dairy manure systems can be covered with a lid/cap etc.
1216
+ return self in {
1217
+ self.__class__.liquid_with_natural_crust,
1218
+ self.__class__.liquid_with_solid_cover
1219
+ }
1220
+
1221
+
1222
+ def get_fraction_of_organic_nitrogen_mineralized_data(
1223
+ state_type: ManureStateType,
1224
+ animal_type: AnimalType,
1225
+ fraction_of_tan_in_liquid_manure_storage_system: float = 1
1226
+ ) -> FractionOfOrganicNitrogenMineralizedData:
1227
+ """Table 44. Fraction of organic N mineralized as TAN and the fraction of TAN immobilized to organic N and nitrified
1228
+ and denitrified during solid and liquid manure storage for beef and dairy cattle (based on TAN content)
1229
+ (Chai et al., 2014,2016).
1230
+
1231
+ Args:
1232
+ state_type: manure handling system type
1233
+ animal_type: animal type
1234
+ fraction_of_tan_in_liquid_manure_storage_system: (-) fraction of excreted N in animal urine (cf. Note 4)
1235
+
1236
+ Returns:
1237
+
1238
+
1239
+ Notes:
1240
+ 1. Mineralization of organic N (fecal N and bedding N)
1241
+ 2. Solid manure composted for ≥ 10 months; data from Chai et al. (2014); these values are used for compost passive and compost intensive beef and dairy cattle manure
1242
+ 3. Solid manure stockpiled for ≥ 4 months; data from Chai et al. (2014); these values are also used for deep bedding beef and dairy cattle manure
1243
+ 4. FracurinaryN is the fraction of TAN in the liquid manure storage system (includes liquid/slurry with natural crust, liquid/slurry with no natural crust, liquid/slurry with solid cover and deep pit under barn).
1244
+ 5. Nitrification of TAN in liquid manure with natural crust (formed from manure, bedding, or waste forage) was considered since the natural crust can be assumed as similar to solid manure (stockpile) in terms of being aerobic. The N2O-N emission factor for liquid manure with a natural crust is 0.005 of total N IPCC (2006), which can be expressed as the TAN based EFs
1245
+ 6. Nitrification of TAN in liquid manure with no natural crust is assumed to be zero because of anaerobic conditions
1246
+ 7. All nitrified TAN (nitrate-N) was assumed to be denitrified (no leaching, runoff) in liquid systems.
1247
+ """
1248
+ if animal_type.is_beef_cattle_type():
1249
+ # FracMineralized = Note 1.
1250
+ match state_type:
1251
+ # // Solid-compost - beef
1252
+ # // Note 2
1253
+ case ManureStateType.compost_intensive | ManureStateType.compost_passive:
1254
+ return FractionOfOrganicNitrogenMineralizedData(
1255
+ fraction_immobilized=0,
1256
+ fraction_mineralized=0.46,
1257
+ fraction_nitrified=0.25,
1258
+ fraction_denitrified=0,
1259
+ n2o_n=0.033,
1260
+ no_n=0.0033,
1261
+ n2_n=0.099,
1262
+ n_leached=0.0575)
1263
+
1264
+ # // Solid-stockpiled - beef
1265
+ # // Note 3
1266
+ case ManureStateType.deep_bedding | ManureStateType.solid_storage:
1267
+ return FractionOfOrganicNitrogenMineralizedData(
1268
+ fraction_immobilized=0,
1269
+ fraction_mineralized=0.28,
1270
+ fraction_nitrified=0.125,
1271
+ fraction_denitrified=0,
1272
+ n2o_n=0.033,
1273
+ no_n=0.0033,
1274
+ n2_n=0.099,
1275
+ n_leached=0.0575
1276
+ )
1277
+ elif animal_type.is_dairy_cattle_type():
1278
+ match state_type:
1279
+ # // Solid-compost - dairy
1280
+ # // Note 2
1281
+ case ManureStateType.compost_intensive | ManureStateType.compost_passive:
1282
+ return FractionOfOrganicNitrogenMineralizedData(
1283
+ fraction_immobilized=0,
1284
+ fraction_mineralized=0.46,
1285
+ fraction_nitrified=0.282,
1286
+ fraction_denitrified=0.152,
1287
+ n2o_n=0.037,
1288
+ no_n=0.0037,
1289
+ n2_n=0.111,
1290
+ n_leached=0.13)
1291
+
1292
+ # // Solid-stockpiled - dairy
1293
+ # // Note 3
1294
+ case ManureStateType.deep_bedding | ManureStateType.solid_storage:
1295
+ return FractionOfOrganicNitrogenMineralizedData(
1296
+ fraction_immobilized=0,
1297
+ fraction_mineralized=0.28,
1298
+ fraction_nitrified=0.141,
1299
+ fraction_denitrified=0.076,
1300
+ n2o_n=0.0185,
1301
+ no_n=0.0019,
1302
+ n2_n=0.0555,
1303
+ n_leached=0.065)
1304
+
1305
+ # // Liquid systems for both beef and dairy
1306
+ match state_type:
1307
+ # // Liquid with natural crust
1308
+ # // Note 5, 7
1309
+ case ManureStateType.liquid_with_natural_crust | ManureStateType.liquid_with_solid_cover | ManureStateType.deep_pit:
1310
+ return FractionOfOrganicNitrogenMineralizedData(
1311
+ fraction_immobilized=0,
1312
+ fraction_mineralized=0.1,
1313
+ fraction_nitrified=0.021 / min(1., fraction_of_tan_in_liquid_manure_storage_system),
1314
+ fraction_denitrified=0.021 / min(1., fraction_of_tan_in_liquid_manure_storage_system),
1315
+ n2o_n=0.005 / min(1., fraction_of_tan_in_liquid_manure_storage_system),
1316
+ no_n=0.0005 / min(1., fraction_of_tan_in_liquid_manure_storage_system),
1317
+ n2_n=0.015 / min(1., fraction_of_tan_in_liquid_manure_storage_system),
1318
+ n_leached=0)
1319
+
1320
+ # // Liquid without natural crust
1321
+ # // Note 6, 7
1322
+ case ManureStateType.liquid_no_crust:
1323
+ return FractionOfOrganicNitrogenMineralizedData(
1324
+ fraction_immobilized=0,
1325
+ fraction_mineralized=0.1,
1326
+ fraction_nitrified=0.0,
1327
+ fraction_denitrified=0,
1328
+ n2o_n=0,
1329
+ no_n=0,
1330
+ n2_n=0,
1331
+ n_leached=0
1332
+ )
1333
+
1334
+ return FractionOfOrganicNitrogenMineralizedData()
1335
+
1336
+
1337
+ def get_ammonia_emission_factor_for_storage_of_poultry_manure(
1338
+ animal_type: AnimalType
1339
+ ) -> float:
1340
+ """Returns the default ammonia emission factor for housing manure of Poultry-type animals.
1341
+
1342
+ Args:
1343
+ animal_type: animal type object
1344
+
1345
+ Returns:
1346
+ (kg NH3-N kg^-1 TAN): default ammonia emission factor for housing
1347
+
1348
+ References:
1349
+ Holos source code: https://github.com/holos-aafc/Holos/blob/396f1ab9bc7247e6d78766f9445c14d2eb7c0d9d/H.Core/Providers/Animals/DefaultAmmoniaEmissionFactorsForPoultryManureStorageProvider.cs#L7
1350
+
1351
+ """
1352
+ if animal_type.is_chicken_type():
1353
+ if any((
1354
+ animal_type == AnimalType.chicken_hens,
1355
+ animal_type == AnimalType.layers)):
1356
+ res = 0.24
1357
+ else:
1358
+ res = 0.25
1359
+ else:
1360
+ # Turkeys
1361
+ res = 0.24
1362
+
1363
+ return res
1364
+
1365
+
1366
+ def get_ammonia_emission_factor_for_storage_of_beef_and_dairy_cattle_manure(
1367
+ storage_type: ManureStateType
1368
+ ) -> float:
1369
+ """Returns the default ammonia emission factor for housing of beef and dairy cattle manure.
1370
+
1371
+ Args:
1372
+ storage_type: manure handling system type
1373
+
1374
+ Returns:
1375
+ (kg NH3-N kg^-1 TAN): default ammonia emission factor for housing
1376
+
1377
+ References:
1378
+ Holos source code: https://github.com/holos-aafc/Holos/blob/396f1ab9bc7247e6d78766f9445c14d2eb7c0d9d/H.Core/Providers/Animals/Table_43_Beef_Dairy_Default_Emission_Factors_Provider.cs#L77
1379
+
1380
+ """
1381
+ # Footnote 1: Read for data reference information.
1382
+
1383
+ if any((
1384
+ storage_type.is_liquid_manure(),
1385
+ storage_type == ManureStateType.deep_pit
1386
+ )):
1387
+ res = 0.13
1388
+
1389
+ elif storage_type.is_compost():
1390
+ res = 0.7
1391
+
1392
+ elif any((
1393
+ storage_type == ManureStateType.solid_storage,
1394
+ storage_type == ManureStateType.deep_bedding)):
1395
+ res = 0.35
1396
+
1397
+ else:
1398
+ res = 0
1399
+
1400
+ return res
1401
+
1402
+
1403
+ def get_emission_factor_for_volatilization_based_on_climate(
1404
+ mean_annual_precipitation: float,
1405
+ mean_annual_potential_evapotranspiration: float
1406
+ ) -> float:
1407
+ """Returns emission factor for volatilization (EF_volatilization)
1408
+
1409
+ Args:
1410
+ mean_annual_precipitation: (mm) mean annual precipitation
1411
+ mean_annual_potential_evapotranspiration: (mm) mean annual potential evapotranspiration
1412
+
1413
+ Returns:
1414
+ (kg(N2O-N) kg(N)-1): emission factor for volatilization
1415
+
1416
+ Notes:
1417
+ In IPCC (2019), Table 11.3: Disaggregation by climate for EFvolatilization (based on long-term averages):
1418
+ Wet climates occur in temperate and boreal zones where the ratio of annual precipitation (P) / potential evapotranspiration (PE) >1
1419
+ Dry climates occur in temperate and boreal zones where the ratio of annual P/PE <1
1420
+
1421
+ Holos Source Code:
1422
+ https://github.com/holos-aafc/Holos/blob/396f1ab9bc7247e6d78766f9445c14d2eb7c0d9d/H.Core/Providers/Animals/Table_36_Livestock_Emission_Conversion_Factors_Provider.cs#L515
1423
+ """
1424
+ return 0.014 if mean_annual_precipitation > mean_annual_potential_evapotranspiration else 0.005
1425
+
1426
+
1427
+ class LivestockEmissionConversionFactorsData:
1428
+ def __init__(
1429
+ self,
1430
+ methane_conversion_factor: float = 0,
1431
+ n2o_direct_emission_factor: float = 0,
1432
+ volatilization_fraction: float = 0,
1433
+ emission_factor_volatilization: float = 0,
1434
+ leaching_fraction: float = 0,
1435
+ emission_factor_leach: float = 0,
1436
+ methane_enteric_rat: float = 0,
1437
+ methane_manure_rate: float = 0,
1438
+ nitrogen_excretion_rate: float = 0
1439
+ ):
1440
+ """class that hosts manure emission factors of livestock
1441
+
1442
+ Args:
1443
+ methane_conversion_factor: (kg kg^-1) Methane conversion factor of manure (MCF)
1444
+ n2o_direct_emission_factor: (kg(N2O-N) kg (N)-1) Direct N2O emission factor (EF_direct)
1445
+ volatilization_fraction: (kg(NH3-N) kg(N)-1) Fraction of volatilization (Frac_volatilization)
1446
+ emission_factor_volatilization: (kg(N2O-N) kg(N)-1) Emission factor for volatilization (EF_volatilization)
1447
+ leaching_fraction: (kg(N) kg(N)-1) Fraction of leaching (Frac_leach)
1448
+ emission_factor_leach: (kg(N2O-N) kg(N)-1) Emission factor for leaching (EF_leach)
1449
+ methane_enteric_rat: (kg Head-1 day-1)
1450
+ methane_manure_rate: (kg Head-1 day-1)
1451
+ nitrogen_excretion_rate: (kg Head-1 day-1)
1452
+ """
1453
+ # public AnimalType AnimalType { get; set; }
1454
+ # public ManureStateType HandlingSystem { get; set; }
1455
+
1456
+ self.MethaneConversionFactor = methane_conversion_factor
1457
+ self.N2ODirectEmissionFactor = n2o_direct_emission_factor
1458
+ self.VolatilizationFraction = volatilization_fraction
1459
+ self.EmissionFactorVolatilization = emission_factor_volatilization
1460
+ self.LeachingFraction = leaching_fraction
1461
+ self.EmissionFactorLeach = emission_factor_leach
1462
+ self.MethaneEntericRat = methane_enteric_rat
1463
+ self.MethaneManureRate = methane_manure_rate
1464
+ self.NitrogenExcretionRate = nitrogen_excretion_rate
1465
+
1466
+
1467
+ def get_methane_conversion_factor(
1468
+ manure_state_type: ManureStateType,
1469
+ climate_zone: ClimateZones,
1470
+ ) -> float:
1471
+ """Returns the methane conversion factor by climate zone (kg kg-1)
1472
+
1473
+ Args:
1474
+ manure_state_type:
1475
+ climate_zone:
1476
+
1477
+ Returns:
1478
+ (kg kg-1) methane conversion factor
1479
+
1480
+ Holos Source Code:
1481
+ https://github.com/holos-aafc/Holos/blob/396f1ab9bc7247e6d78766f9445c14d2eb7c0d9d/H.Core/Providers/Animals/Table_37_MCF_By_Climate_Livestock_MansureSystem_Provider.cs#L16
1482
+ """
1483
+ if any([
1484
+ manure_state_type == ManureStateType.solid_storage,
1485
+ manure_state_type == ManureStateType.solid
1486
+ ]):
1487
+ match climate_zone:
1488
+ case ClimateZones.CoolTemperateMoist | ClimateZones.CoolTemperateDry | ClimateZones.BorealDry | ClimateZones.BorealMoist:
1489
+ return 0.02
1490
+
1491
+ case ClimateZones.WarmTemperateDry | ClimateZones.WarmTemperateMoist:
1492
+ return 0.04
1493
+
1494
+ if manure_state_type == ManureStateType.compost_intensive:
1495
+ match climate_zone:
1496
+ case ClimateZones.CoolTemperateMoist | ClimateZones.CoolTemperateDry | ClimateZones.BorealDry | ClimateZones.BorealMoist:
1497
+ return 0.005
1498
+
1499
+ case ClimateZones.WarmTemperateDry | ClimateZones.WarmTemperateMoist:
1500
+ return 0.01
1501
+
1502
+ if manure_state_type == ManureStateType.compost_passive:
1503
+ match climate_zone:
1504
+ case ClimateZones.CoolTemperateMoist | ClimateZones.CoolTemperateDry | ClimateZones.BorealDry | ClimateZones.BorealMoist:
1505
+ return 0.01
1506
+
1507
+ case ClimateZones.WarmTemperateDry | ClimateZones.WarmTemperateMoist:
1508
+ return 0.02
1509
+
1510
+ if manure_state_type == ManureStateType.deep_bedding:
1511
+ match climate_zone:
1512
+ case ClimateZones.CoolTemperateMoist:
1513
+ return 0.21
1514
+ case ClimateZones.CoolTemperateDry:
1515
+ return 0.26
1516
+ case ClimateZones.BorealDry | ClimateZones.BorealMoist:
1517
+ return 0.14
1518
+ case ClimateZones.WarmTemperateDry:
1519
+ return 0.37
1520
+ case ClimateZones.WarmTemperateMoist:
1521
+ return 0.41
1522
+
1523
+ if manure_state_type == ManureStateType.composted_in_vessel:
1524
+ match climate_zone:
1525
+ case ClimateZones.CoolTemperateMoist | ClimateZones.CoolTemperateDry | ClimateZones.BorealDry | ClimateZones.BorealMoist | ClimateZones.WarmTemperateDry | ClimateZones.WarmTemperateMoist:
1526
+ return 0.005
1527
+
1528
+ if manure_state_type == ManureStateType.daily_spread:
1529
+ match climate_zone:
1530
+ case ClimateZones.CoolTemperateMoist | ClimateZones.CoolTemperateDry | ClimateZones.BorealDry | ClimateZones.BorealMoist:
1531
+ return 0.001
1532
+
1533
+ case ClimateZones.WarmTemperateDry | ClimateZones.WarmTemperateMoist:
1534
+ return 0.005
1535
+
1536
+ if manure_state_type == ManureStateType.deep_pit:
1537
+ match climate_zone:
1538
+ case ClimateZones.CoolTemperateMoist:
1539
+ return 0.06
1540
+ case ClimateZones.CoolTemperateDry:
1541
+ return 0.08
1542
+ case ClimateZones.BorealDry:
1543
+ return 0.04
1544
+ case ClimateZones.BorealMoist:
1545
+ return 0.04
1546
+ case ClimateZones.WarmTemperateDry:
1547
+ return 0.15
1548
+ case ClimateZones.WarmTemperateMoist:
1549
+ return 0.13
1550
+
1551
+ # Pasture, etc. have non-temperature dependent values
1552
+ return 0
1553
+
1554
+
1555
+ def get_direct_emission_factor_based_on_climate(
1556
+ mean_annual_precipitation: float,
1557
+ mean_annual_potential_evapotranspiration: float
1558
+ ) -> float:
1559
+ """Returns the default N2O direct emission factor
1560
+
1561
+ Args:
1562
+ mean_annual_precipitation: (mm) mean annual precipitation
1563
+ mean_annual_potential_evapotranspiration: (mm) mean annual potential evapotranspiration
1564
+
1565
+ Returns:
1566
+ (kg(N2O-N) kg (N)-1) Direct N2O emission factor (EF_direct)
1567
+
1568
+ Holos Source Code:
1569
+ https://github.com/holos-aafc/Holos/blob/396f1ab9bc7247e6d78766f9445c14d2eb7c0d9d/H.Core/Providers/Animals/Table_36_Livestock_Emission_Conversion_Factors_Provider.cs#L534
1570
+ """
1571
+ return 0.006 if mean_annual_precipitation > mean_annual_potential_evapotranspiration else 0.002
1572
+
1573
+
1574
+ def get_volatilization_fractions_from_land_applied_manure_data_for_swine_type(
1575
+ province: CanadianProvince,
1576
+ year: int
1577
+ ) -> float:
1578
+ """Returns the average volatilization fraction of applied swine manure
1579
+
1580
+ Args:
1581
+ province: Canadian Province class
1582
+ year: year
1583
+
1584
+ Returns:
1585
+ (kg NH3-N volatilized kg-1 manure N applied)
1586
+
1587
+ Holos Source Code:
1588
+ https://github.com/holos-aafc/Holos/blob/396f1ab9bc7247e6d78766f9445c14d2eb7c0d9d/H.Core/Providers/Animals/Table%2070/Table_62_Volatilization_Fractions_From_Land_Applied_Swine_Manure_Provider.cs#L23
1589
+ """
1590
+ df = HolosTables.Table_62_Fractions_of_swine_N_volatilized
1591
+ return df.iloc[(df['Year'] - year).abs().idxmin()][province.value.abbreviation]
1592
+
1593
+
1594
+ def get_volatilization_fractions_from_land_applied_manure_data_for_dairy_cattle_type(
1595
+ province: CanadianProvince,
1596
+ year: int
1597
+ ) -> float:
1598
+ """Returns the average volatilization fraction of applied dairy cattle manure
1599
+
1600
+ Args:
1601
+ province: Canadian Province class
1602
+ year: year
1603
+
1604
+ Returns:
1605
+ (kg NH3-N volatilized kg-1 manure N applied)
1606
+
1607
+ Holos Source Code:
1608
+ https://github.com/holos-aafc/Holos/blob/396f1ab9bc7247e6d78766f9445c14d2eb7c0d9d/H.Core/Providers/Animals/Table%2069/Table_61_Volatilization_Fractions_From_Land_Applied_Dairy_Manure_Provider.cs#L48
1609
+ """
1610
+ df = HolosTables.Table_61_Fractions_of_dairy_cattle_N_volatilized
1611
+ return df.iloc[(df['Year'] - year).abs().idxmin()][province.value.abbreviation]
1612
+
1613
+
1614
+ def get_volatilization_fraction_for_land_application(
1615
+ animal_type: AnimalType,
1616
+ province: CanadianProvince,
1617
+ year: int
1618
+ ) -> float:
1619
+ """Returns the average volatilization fraction of applied manure
1620
+
1621
+ Args:
1622
+ animal_type: animal type class
1623
+ province: Canadian Province class
1624
+ year: year
1625
+
1626
+ (kg NH3-N volatilized kg-1 manure N applied)
1627
+
1628
+ Holos Source Code:
1629
+ https://github.com/holos-aafc/Holos/blob/396f1ab9bc7247e6d78766f9445c14d2eb7c0d9d/H.Core/Providers/Animals/Table_36_Livestock_Emission_Conversion_Factors_Provider.cs#L96
1630
+ """
1631
+ # Swine and dairy have more accurate volatilization fractions based on province and year
1632
+ if animal_type.is_swine_type():
1633
+ volatilization_fraction = get_volatilization_fractions_from_land_applied_manure_data_for_swine_type(
1634
+ province=province,
1635
+ year=year)
1636
+
1637
+ # return volatilizationFraction.ImpliedEmissionFactor;
1638
+ elif animal_type.is_dairy_cattle_type():
1639
+ volatilization_fraction = get_volatilization_fractions_from_land_applied_manure_data_for_dairy_cattle_type(
1640
+ province=province,
1641
+ year=year)
1642
+
1643
+ # return volatilizationFraction.ImpliedEmissionFactor;
1644
+
1645
+ else:
1646
+ volatilization_fraction = 0.21
1647
+
1648
+ return volatilization_fraction
1649
+
1650
+
1651
+ def get_land_application_factors(
1652
+ province: CanadianProvince,
1653
+ mean_annual_precipitation: float,
1654
+ mean_annual_evapotranspiration: float,
1655
+ growing_season_precipitation: float,
1656
+ growing_season_evapotranspiration: float,
1657
+ animal_type: AnimalType,
1658
+ year: int,
1659
+ soil_texture: SoilTexture
1660
+ ) -> LivestockEmissionConversionFactorsData:
1661
+ """Returns default manure application factor per region per year
1662
+
1663
+ Args:
1664
+ province: Canadian Province class
1665
+ mean_annual_precipitation: (mm) mean annual precipitation
1666
+ mean_annual_evapotranspiration: (mm) mean annual potential evapotranspiration
1667
+ growing_season_precipitation: (mm) total amount of precipitations during the growing season (e.g. may to oct.)
1668
+ growing_season_evapotranspiration: (mm) total amount of evapotranspiration during the growing season (e.g. may to oct.)
1669
+ animal_type: animal type class
1670
+ year: year
1671
+ soil_texture: soil texture as set in Holos
1672
+
1673
+ Holos Source Code:
1674
+ (1) https://github.com/RamiALBASHA/Holos/blob/71638efd97c84c6ded45e342ce664477df6f803f/H.Core/Providers/Animals/Table_36_Livestock_Emission_Conversion_Factors_Provider.cs#L41
1675
+ (2) https://github.com/holos-aafc/Holos/blob/267abf1066bb5494e5ec6a4085a85ab42dfa76c7/H.Core/Services/Initialization/Animals/AnimalInitializationService.Ammonia.cs#L55
1676
+ """
1677
+ region = get_region(province=province)
1678
+ climate_dependent_emission_factor_for_volatilization = get_emission_factor_for_volatilization_based_on_climate(
1679
+ mean_annual_precipitation=mean_annual_precipitation,
1680
+ mean_annual_potential_evapotranspiration=mean_annual_evapotranspiration)
1681
+
1682
+ climate_dependent_direct_emission_factor = get_direct_emission_factor_based_on_climate(
1683
+ mean_annual_precipitation=mean_annual_precipitation,
1684
+ mean_annual_potential_evapotranspiration=mean_annual_evapotranspiration)
1685
+
1686
+ factors = LivestockEmissionConversionFactorsData(
1687
+ methane_conversion_factor=0.0047,
1688
+ n2o_direct_emission_factor=climate_dependent_direct_emission_factor,
1689
+ volatilization_fraction=0.21,
1690
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization)
1691
+
1692
+ factors.EmissionFactorLeach = Defaults.EmissionFactorForLeachingAndRunoff
1693
+
1694
+ if region == Region.WesternCanada:
1695
+ factors.N2ODirectEmissionFactor = 0.00043
1696
+ else:
1697
+ if soil_texture == SoilTexture.Fine:
1698
+ factors.N2ODirectEmissionFactor = 0.0078
1699
+ elif soil_texture == SoilTexture.Medium:
1700
+ factors.N2ODirectEmissionFactor = 0.0062
1701
+ else:
1702
+ # SoilTexture = Coarse
1703
+ # Footnote 1
1704
+ factors.N2ODirectEmissionFactor = 0.0047
1705
+
1706
+ factors.VolatilizationFraction = get_volatilization_fraction_for_land_application(
1707
+ animal_type=animal_type,
1708
+ province=province,
1709
+ year=year)
1710
+
1711
+ # This part of the code comes from Holos Source Code (2)
1712
+ factors.LeachingFraction = calculate_fraction_of_nitrogen_lost_by_leaching_and_runoff(
1713
+ growing_season_precipitation=growing_season_precipitation,
1714
+ growing_season_evapotranspiration=growing_season_evapotranspiration)
1715
+
1716
+ return factors
1717
+
1718
+
1719
+ def get_manure_emission_factors(
1720
+ manure_state_type: ManureStateType,
1721
+ mean_annual_precipitation: float,
1722
+ mean_annual_temperature: float,
1723
+ mean_annual_evapotranspiration: float,
1724
+ growing_season_precipitation: float,
1725
+ growing_season_evapotranspiration: float,
1726
+ animal_type: AnimalType,
1727
+ province: CanadianProvince,
1728
+ year: int,
1729
+ soil_texture: SoilTexture
1730
+ ) -> LivestockEmissionConversionFactorsData:
1731
+ """Sets the emission factors for manure
1732
+
1733
+ Args:
1734
+ manure_state_type: ManureStateType class instance
1735
+ mean_annual_precipitation: (mm) mean annual precipitation
1736
+ mean_annual_temperature: (degrees Celsius) mean annual air temperature
1737
+ mean_annual_evapotranspiration: (mm) mean annual potential evapotranspiration
1738
+ growing_season_precipitation: (mm) total amount of precipitations during the growing season (e.g. may to oct.)
1739
+ growing_season_evapotranspiration: (mm) total amount of evapotranspiration during the growing season (e.g. may to oct.)
1740
+ animal_type: animal type class
1741
+ province: CanadianProvince class instance
1742
+ year: year
1743
+ soil_texture: soil texture as set in Holos
1744
+
1745
+ Returns:
1746
+
1747
+ Holos Source Code:
1748
+ https://github.com/RamiALBASHA/Holos/blob/71638efd97c84c6ded45e342ce664477df6f803f/H.Core/Providers/Animals/Table_36_Livestock_Emission_Conversion_Factors_Provider.cs#L117
1749
+ """
1750
+ climate_dependent_methane_conversion_factor = get_methane_conversion_factor(
1751
+ manure_state_type=manure_state_type,
1752
+ climate_zone=get_climate_zone(
1753
+ mean_annual_temperature=mean_annual_temperature,
1754
+ mean_annual_precipitation=mean_annual_precipitation,
1755
+ mean_annual_potential_evapotranspiration=mean_annual_evapotranspiration))
1756
+
1757
+ climate_dependent_emission_factor_for_volatilization = get_emission_factor_for_volatilization_based_on_climate(
1758
+ mean_annual_precipitation=mean_annual_precipitation,
1759
+ mean_annual_potential_evapotranspiration=mean_annual_evapotranspiration)
1760
+
1761
+ # All factors are the same when considering any manure on pasture
1762
+ if any([
1763
+ manure_state_type == ManureStateType.pasture,
1764
+ manure_state_type == ManureStateType.paddock,
1765
+ manure_state_type == ManureStateType.range
1766
+ ]):
1767
+ return get_land_application_factors(
1768
+ province=province,
1769
+ mean_annual_precipitation=mean_annual_precipitation,
1770
+ mean_annual_evapotranspiration=mean_annual_evapotranspiration,
1771
+ growing_season_precipitation=growing_season_precipitation,
1772
+ growing_season_evapotranspiration=growing_season_evapotranspiration,
1773
+ animal_type=animal_type,
1774
+ year=year,
1775
+ soil_texture=soil_texture)
1776
+
1777
+ # The following factors are for animals not on pasture.
1778
+ category = animal_type.get_component_category_from_animal_type()
1779
+
1780
+ match category:
1781
+ case ComponentCategory.BeefProduction:
1782
+ match manure_state_type:
1783
+ case ManureStateType.solid_storage:
1784
+ return LivestockEmissionConversionFactorsData(
1785
+ methane_conversion_factor=climate_dependent_methane_conversion_factor,
1786
+ n2o_direct_emission_factor=0.01,
1787
+ volatilization_fraction=0.45,
1788
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1789
+ leaching_fraction=0.02,
1790
+ emission_factor_leach=0.011)
1791
+
1792
+ case ManureStateType.compost_intensive:
1793
+ return LivestockEmissionConversionFactorsData(
1794
+ methane_conversion_factor=climate_dependent_methane_conversion_factor,
1795
+ n2o_direct_emission_factor=0.005,
1796
+ volatilization_fraction=0.65,
1797
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1798
+ leaching_fraction=0.06,
1799
+ emission_factor_leach=0.011)
1800
+
1801
+ case ManureStateType.compost_passive:
1802
+ return LivestockEmissionConversionFactorsData(
1803
+ methane_conversion_factor=climate_dependent_methane_conversion_factor,
1804
+ n2o_direct_emission_factor=0.005,
1805
+ volatilization_fraction=0.60,
1806
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1807
+ leaching_fraction=0.04,
1808
+ emission_factor_leach=0.011)
1809
+
1810
+ case ManureStateType.deep_bedding:
1811
+ return LivestockEmissionConversionFactorsData(
1812
+ methane_conversion_factor=climate_dependent_methane_conversion_factor,
1813
+ n2o_direct_emission_factor=0.01,
1814
+ volatilization_fraction=0.25,
1815
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1816
+ leaching_fraction=0.035,
1817
+ emission_factor_leach=0.011)
1818
+
1819
+ case ManureStateType.anaerobic_digester:
1820
+ return LivestockEmissionConversionFactorsData(
1821
+ methane_conversion_factor=0.01, # Footnote 4
1822
+ n2o_direct_emission_factor=0.0006,
1823
+ volatilization_fraction=0.1,
1824
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1825
+ leaching_fraction=0.0,
1826
+ emission_factor_leach=0.011)
1827
+
1828
+ case _:
1829
+ # raise ValueError(
1830
+ # f"Unable to get data for manure state type: {manure_state_type}. Returning default value.")
1831
+ return LivestockEmissionConversionFactorsData()
1832
+
1833
+ case ComponentCategory.Dairy:
1834
+ match manure_state_type:
1835
+ case ManureStateType.daily_spread:
1836
+ return LivestockEmissionConversionFactorsData(
1837
+ methane_conversion_factor=climate_dependent_methane_conversion_factor,
1838
+ n2o_direct_emission_factor=0.0,
1839
+ volatilization_fraction=0.07,
1840
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1841
+ leaching_fraction=0,
1842
+ emission_factor_leach=0.011)
1843
+
1844
+ case ManureStateType.solid_storage:
1845
+ return LivestockEmissionConversionFactorsData(
1846
+ methane_conversion_factor=climate_dependent_methane_conversion_factor,
1847
+ n2o_direct_emission_factor=0.01,
1848
+ volatilization_fraction=0.3,
1849
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1850
+ leaching_fraction=0.02,
1851
+ emission_factor_leach=0.011)
1852
+
1853
+ case ManureStateType.compost_intensive:
1854
+ return LivestockEmissionConversionFactorsData(
1855
+ methane_conversion_factor=climate_dependent_methane_conversion_factor,
1856
+ n2o_direct_emission_factor=0.005,
1857
+ volatilization_fraction=0.5,
1858
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1859
+ leaching_fraction=0.06,
1860
+ emission_factor_leach=0.011)
1861
+
1862
+ case ManureStateType.compost_passive:
1863
+ return LivestockEmissionConversionFactorsData(
1864
+ methane_conversion_factor=climate_dependent_methane_conversion_factor,
1865
+ n2o_direct_emission_factor=0.005,
1866
+ volatilization_fraction=0.45,
1867
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1868
+ leaching_fraction=0.04,
1869
+ emission_factor_leach=0.011)
1870
+
1871
+ case ManureStateType.deep_bedding:
1872
+ return LivestockEmissionConversionFactorsData(
1873
+ methane_conversion_factor=climate_dependent_methane_conversion_factor,
1874
+ n2o_direct_emission_factor=0.01,
1875
+ volatilization_fraction=0.25,
1876
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1877
+ leaching_fraction=0.035,
1878
+ emission_factor_leach=0.011)
1879
+
1880
+ case ManureStateType.liquid_with_natural_crust:
1881
+ return LivestockEmissionConversionFactorsData(
1882
+ n2o_direct_emission_factor=0.005,
1883
+ volatilization_fraction=0.3,
1884
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1885
+ leaching_fraction=0,
1886
+ emission_factor_leach=0.011)
1887
+
1888
+ case ManureStateType.liquid_no_crust:
1889
+ return LivestockEmissionConversionFactorsData(
1890
+ n2o_direct_emission_factor=0.0,
1891
+ volatilization_fraction=0.48,
1892
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1893
+ leaching_fraction=0,
1894
+ emission_factor_leach=0.011)
1895
+
1896
+ case ManureStateType.liquid_with_solid_cover:
1897
+ return LivestockEmissionConversionFactorsData(
1898
+ n2o_direct_emission_factor=0.005,
1899
+ volatilization_fraction=0.1,
1900
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1901
+ leaching_fraction=0,
1902
+ emission_factor_leach=0.011)
1903
+
1904
+ case ManureStateType.deep_pit:
1905
+ return LivestockEmissionConversionFactorsData(
1906
+ methane_conversion_factor=climate_dependent_methane_conversion_factor,
1907
+ n2o_direct_emission_factor=0.002,
1908
+ volatilization_fraction=0.28,
1909
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1910
+ leaching_fraction=0,
1911
+ emission_factor_leach=0.011)
1912
+
1913
+ case ManureStateType.anaerobic_digester:
1914
+ return LivestockEmissionConversionFactorsData(
1915
+ methane_conversion_factor=0.01, # Footnote 4
1916
+ n2o_direct_emission_factor=0.0006,
1917
+ volatilization_fraction=0.1,
1918
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1919
+ emission_factor_leach=0.011)
1920
+
1921
+ case _:
1922
+ raise ValueError(
1923
+ f": Unable to get data for manure state type: {manure_state_type}. Returning default value.")
1924
+
1925
+ # return Table_36_Livestock_Emission_Conversion_Factors_Data()
1926
+
1927
+ case ComponentCategory.Swine:
1928
+ match manure_state_type:
1929
+ case ManureStateType.composted_in_vessel:
1930
+ return LivestockEmissionConversionFactorsData(
1931
+ methane_conversion_factor=0.005,
1932
+ n2o_direct_emission_factor=0.006,
1933
+ volatilization_fraction=0.6,
1934
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1935
+ leaching_fraction=0,
1936
+ emission_factor_leach=0.011)
1937
+
1938
+ case ManureStateType.liquid_with_natural_crust:
1939
+ return LivestockEmissionConversionFactorsData(
1940
+ methane_conversion_factor=0.0,
1941
+ n2o_direct_emission_factor=0.005,
1942
+ volatilization_fraction=0.3,
1943
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1944
+ leaching_fraction=0,
1945
+ emission_factor_leach=0.011)
1946
+
1947
+ case ManureStateType.liquid_no_crust:
1948
+ return LivestockEmissionConversionFactorsData(
1949
+ methane_conversion_factor=0.0,
1950
+ n2o_direct_emission_factor=0.0,
1951
+ volatilization_fraction=0.48,
1952
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1953
+ leaching_fraction=0,
1954
+ emission_factor_leach=0.011)
1955
+
1956
+ case ManureStateType.liquid_with_solid_cover:
1957
+ return LivestockEmissionConversionFactorsData(
1958
+ methane_conversion_factor=0.0,
1959
+ n2o_direct_emission_factor=0.005,
1960
+ volatilization_fraction=0.1,
1961
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1962
+ leaching_fraction=0,
1963
+ emission_factor_leach=0.011)
1964
+
1965
+ case ManureStateType.deep_pit:
1966
+ return LivestockEmissionConversionFactorsData(
1967
+ methane_conversion_factor=climate_dependent_methane_conversion_factor,
1968
+ n2o_direct_emission_factor=0.002,
1969
+ volatilization_fraction=0.25,
1970
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1971
+ emission_factor_leach=0.011)
1972
+
1973
+ case ManureStateType.anaerobic_digester:
1974
+ return LivestockEmissionConversionFactorsData(
1975
+ methane_conversion_factor=0.01, # Footnote 4
1976
+ n2o_direct_emission_factor=0.0006,
1977
+ volatilization_fraction=0.1, # Footnote 5
1978
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1979
+ emission_factor_leach=0.011)
1980
+
1981
+ case _:
1982
+ raise ValueError(
1983
+ f"Unable to get data for manure state type: {manure_state_type}. Returning default value.")
1984
+ # return Table_36_Livestock_Emission_Conversion_Factors_Data()
1985
+
1986
+ case ComponentCategory.Sheep:
1987
+ match manure_state_type:
1988
+ case ManureStateType.solid_storage:
1989
+ return LivestockEmissionConversionFactorsData(
1990
+ methane_conversion_factor=climate_dependent_methane_conversion_factor,
1991
+ n2o_direct_emission_factor=0.01,
1992
+ volatilization_fraction=0.12,
1993
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
1994
+ leaching_fraction=0.02,
1995
+ emission_factor_leach=0.011)
1996
+
1997
+ case _:
1998
+ raise ValueError(
1999
+ f"Unable to get data for manure state type: {manure_state_type}. Returning default value.")
2000
+ # return Table_36_Livestock_Emission_Conversion_Factors_Data();
2001
+
2002
+ case ComponentCategory.Poultry:
2003
+ if manure_state_type == ManureStateType.anaerobic_digester:
2004
+ return LivestockEmissionConversionFactorsData(
2005
+ methane_conversion_factor=0.01, # Footnote 7
2006
+ n2o_direct_emission_factor=0.0006,
2007
+ volatilization_fraction=0.1,
2008
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
2009
+ leaching_fraction=0,
2010
+ emission_factor_leach=0.011)
2011
+
2012
+ if manure_state_type == ManureStateType.solid_storage_with_or_without_litter:
2013
+ # Bedding with litter
2014
+ return LivestockEmissionConversionFactorsData(
2015
+ methane_conversion_factor=0.015, # Footnote 7
2016
+ n2o_direct_emission_factor=0.001, # Footnote 7
2017
+ volatilization_fraction=0.4,
2018
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
2019
+ leaching_fraction=0,
2020
+ emission_factor_leach=0.011)
2021
+
2022
+ raise ValueError(
2023
+ f"Unable to get data for manure state type: {manure_state_type}. Returning default value.")
2024
+
2025
+ # return Table_36_Livestock_Emission_Conversion_Factors_Data()
2026
+
2027
+ case ComponentCategory.OtherLivestock:
2028
+ match manure_state_type:
2029
+ case ManureStateType.solid_storage:
2030
+ return LivestockEmissionConversionFactorsData(
2031
+ methane_conversion_factor=climate_dependent_methane_conversion_factor,
2032
+ n2o_direct_emission_factor=0.01,
2033
+ volatilization_fraction=0.12,
2034
+ emission_factor_volatilization=climate_dependent_emission_factor_for_volatilization,
2035
+ leaching_fraction=0.02,
2036
+ emission_factor_leach=0.011)
2037
+
2038
+ case _:
2039
+ raise ValueError(
2040
+ f"Unable to get data for manure state type: {manure_state_type}. Returning default value.")
2041
+ # return Table_36_Livestock_Emission_Conversion_Factors_Data();
2042
+
2043
+ # Unknown component category (or no values for category yet)
2044
+ case _:
2045
+ raise ValueError(
2046
+ ' '.join([
2047
+ f"Unable to get data for manure state type '{manure_state_type}'",
2048
+ f"and component category '{category}'.",
2049
+ "Returning default value."
2050
+ ]))
2051
+ # return Table_36_Livestock_Emission_Conversion_Factors_Data();
2052
+
2053
+
2054
+ def get_manure_excretion_rate(
2055
+ animal_type: AnimalType
2056
+ ) -> float:
2057
+ """Returns the manure excretion rate of animals
2058
+
2059
+ Args:
2060
+ animal_type: AnimalType class instance
2061
+
2062
+ Returns:
2063
+ (kg head-1 day-1) animal excretion rate
2064
+
2065
+ Holos Source Code:
2066
+ https://github.com/holos-aafc/Holos/blob/97331845af308fe8aab6267edad4bbda6f5938b6/H.Core/Providers/Animals/Table_29_Default_Manure_Excreted_Provider.cs#L100
2067
+
2068
+ """
2069
+ _excretionRates = HolosTables.Table_29_Percentage_Total_Manure_Produced_In_Systems
2070
+
2071
+ animal_type_lookup = animal_type
2072
+ if animal_type.is_beef_cattle_type():
2073
+ animal_type_lookup = AnimalType.beef
2074
+ elif animal_type.is_dairy_cattle_type():
2075
+ animal_type_lookup = AnimalType.dairy
2076
+ elif animal_type.is_sheep_type():
2077
+ animal_type_lookup = AnimalType.sheep
2078
+ elif animal_type.is_swine_type():
2079
+ animal_type_lookup = AnimalType.swine
2080
+ elif animal_type.is_turkey_type():
2081
+ animal_type_lookup = AnimalType.turkeys
2082
+ elif animal_type.is_poultry_type():
2083
+ if animal_type == AnimalType.chicken_hens:
2084
+ animal_type_lookup = AnimalType.layers
2085
+
2086
+ return _excretionRates.loc[animal_type_lookup, 'manure_excreted_rate']
2087
+
2088
+
2089
+ def convert_manure_state_type_name(name: str) -> ManureStateType:
2090
+ cleaned_input = name.lower().strip().replace(' ', '').replace('-', '').replace('/', '')
2091
+ match cleaned_input:
2092
+ case "pasture" | "pasturerangepaddock":
2093
+ return ManureStateType.pasture
2094
+
2095
+ case "deepbedding":
2096
+ return ManureStateType.deep_bedding
2097
+
2098
+ case "solidstorage" | "solidstoragestockpiled":
2099
+ return ManureStateType.solid_storage
2100
+
2101
+ case "solidstoragewithorwithoutlitter":
2102
+ return ManureStateType.solid_storage_with_or_without_litter
2103
+
2104
+ case "compostedpassive" | "compostpassive" | "compostpassivewindrow":
2105
+ return ManureStateType.compost_passive
2106
+
2107
+ case "compostedintensive" | "compostintensive" | "compostintensivewindrow":
2108
+ return ManureStateType.compost_intensive
2109
+
2110
+ case "compostedinvessel":
2111
+ return ManureStateType.composted_in_vessel
2112
+
2113
+ case "composted":
2114
+ return ManureStateType.composted
2115
+
2116
+ case "anaerobicdigestion" | "anaerobicdigestor":
2117
+ return ManureStateType.anaerobic_digester
2118
+
2119
+ case "deeppit" | "deeppitunderbarn":
2120
+ return ManureStateType.deep_pit
2121
+
2122
+ case "liquidsolidcover" | "liquidwithsolidcover" | "liquidslurrywithsolidcover":
2123
+ return ManureStateType.liquid_with_solid_cover
2124
+
2125
+ case "liquidnaturalcrust" | "liquidwithnaturalcrust" | "liquidslurrywithnaturalcrust":
2126
+ return ManureStateType.liquid_with_natural_crust
2127
+
2128
+ case "liquidnocrust" | "liquidwithnocrust" | "liquidslurrywithnonaturalcrust":
2129
+ return ManureStateType.liquid_no_crust
2130
+
2131
+ case "dailyspread":
2132
+ return ManureStateType.daily_spread
2133
+
2134
+ case _:
2135
+ # raise ValueError(f"was not able to convert {name}. Returning {ManureStateType.not_selected}")
2136
+ return ManureStateType.not_selected
2137
+
2138
+
2139
+ class ManureComposition:
2140
+ def __init__(
2141
+ self,
2142
+ moisture_content: float,
2143
+ nitrogen_content: float,
2144
+ carbon_content: float,
2145
+ phosphorus_content: float,
2146
+ carbon_to_nitrogen_ratio: float,
2147
+ volatile_solid_content: float
2148
+ ):
2149
+ self.moisture_content = moisture_content
2150
+ self.nitrogen_content = nitrogen_content
2151
+ self.carbon_content = carbon_content
2152
+ self.phosphorus_content = phosphorus_content
2153
+ self.carbon_to_nitrogen_ratio = carbon_to_nitrogen_ratio
2154
+ self.volatile_solid_content = volatile_solid_content
2155
+
2156
+
2157
+ def get_default_manure_composition_data(
2158
+ animal_type: AnimalType,
2159
+ manure_state_type: ManureStateType
2160
+ ) -> ManureComposition:
2161
+ """Returns the default manure composition values depending on animal type and manure state (handling system) type
2162
+
2163
+ Args:
2164
+ animal_type: AnimalType class instance
2165
+ manure_state_type: ManureStateType class instance
2166
+
2167
+ Returns:
2168
+ ManureComposition class instance
2169
+
2170
+ Holos Source Code:
2171
+ https://github.com/holos-aafc/Holos/blob/97331845af308fe8aab6267edad4bbda6f5938b6/H.Core/Models/Farm.Manure.cs#L34
2172
+ """
2173
+
2174
+ # var defaultValue = new DefaultManureCompositionData();
2175
+
2176
+ if animal_type.is_beef_cattle_type():
2177
+ animal_lookup_type = AnimalType.beef
2178
+ elif animal_type.is_dairy_cattle_type():
2179
+ animal_lookup_type = AnimalType.dairy
2180
+ elif animal_type.is_sheep_type():
2181
+ animal_lookup_type = AnimalType.sheep
2182
+ elif animal_type.is_swine_type():
2183
+ animal_lookup_type = AnimalType.swine
2184
+ elif animal_type.is_poultry_type():
2185
+ animal_lookup_type = AnimalType.poultry
2186
+ else:
2187
+ # Other animals have a value for animal group (Horses, Goats, etc.)
2188
+ animal_lookup_type = animal_type
2189
+
2190
+ return ManureComposition(
2191
+ **HolosTables.Table_6_Manure_Types_And_Default_Composition.loc[(animal_lookup_type, manure_state_type)])
2192
+
2193
+
2194
+ def get_beef_and_dairy_cattle_coefficient_data(
2195
+ animal_type: str
2196
+ ) -> AnimalCoefficientData:
2197
+ df = HolosTables.Table_16_Livestock_Coefficients_BeefAndDairy_Cattle_Provider
2198
+
2199
+ if animal_type in df.index:
2200
+ _df = df.loc[animal_type]
2201
+ res = AnimalCoefficientData(
2202
+ baseline_maintenance_coefficient=_df['BaselineMaintenanceCoefficient'],
2203
+ gain_coefficient=_df['GainCoefficient'],
2204
+ default_initial_weight=_df['DefaultInitialWeight'],
2205
+ default_final_weight=_df['DefaultFinalWeight'])
2206
+ else:
2207
+ res = AnimalCoefficientData()
2208
+ return res
2209
+
2210
+
2211
+ def get_beef_and_dairy_cattle_feeding_activity_coefficient(
2212
+ housing_type: HousingType
2213
+ ) -> float:
2214
+ """Returns the coefficient corresponding to animal’s feeding situation (Ca in IPCC's tables)
2215
+
2216
+ Args:
2217
+ housing_type: HousingType class instance
2218
+
2219
+ Returns:
2220
+ (MJ day-1 kg-1) coefficient corresponding to animal’s feeding situation (Ca)
2221
+
2222
+ References:
2223
+ Table 10.5 in https://www.ipcc-nggip.iges.or.jp/public/2006gl/pdf/4_Volume4/V4_10_Ch10_Livestock.pdf
2224
+
2225
+ Holos source code:
2226
+ https://github.com/holos-aafc/Holos/blob/a84060af0e699de25158a1a9030dc9d78edd0e00/H.Core/Providers/Animals/Table_17_Beef_Dairy_Cattle_Feeding_Activity_Coefficient_Provider.cs#L21
2227
+ """
2228
+ match housing_type:
2229
+ case HousingType.housed_in_barn | HousingType.confined | HousingType.confined_no_barn:
2230
+ res = 0
2231
+
2232
+ case HousingType.pasture | HousingType.flat_pasture | HousingType.enclosed_pasture:
2233
+ res = 0.17
2234
+
2235
+ case HousingType.open_range_or_hills:
2236
+ res = 0.36
2237
+
2238
+ case _:
2239
+ res = 0
2240
+
2241
+ return res
2242
+
2243
+
2244
+ def get_average_milk_production_for_dairy_cows_value(
2245
+ year: int,
2246
+ province: CanadianProvince
2247
+ ):
2248
+ """returns the average milk production value for a given Canadian Province.
2249
+
2250
+ Args:
2251
+ year: year for which the average milk production will be returned
2252
+ province: Canadian Province object
2253
+
2254
+ Returns:
2255
+ (kg head-1 day-1): the average milk production value
2256
+
2257
+ References:
2258
+ Holos source code: https://github.com/holos-aafc/Holos/blob/396f1ab9bc7247e6d78766f9445c14d2eb7c0d9d/H.Core/Providers/Animals/Table_21_Average_Milk_Production_Dairy_Cows_Provider.cs#L56
2259
+ """
2260
+ df = HolosTables.Table_21_Average_Milk_Production_For_Dairy_Cows_By_Province
2261
+ year_min = min(df.index)
2262
+ year_max = max(df.index)
2263
+
2264
+ df = df.merge(DataFrame(index=range(year_min, year_max + 1)), right_index=True, left_index=True, how="right")
2265
+ df.interpolate(method="linear", inplace=True)
2266
+
2267
+ return df.loc[max(year_min, min(year_max, year)), province.value.abbreviation]
2268
+
2269
+
2270
+ def read_table_6():
2271
+ manure_composition_data = read_holos_resource_table(
2272
+ path_file=PathsHolosResources.Table_6_Manure_Types_And_Default_Composition)
2273
+ manure_composition_data['animal_type'] = manure_composition_data['animal_type'].apply(
2274
+ lambda x: convert_animal_type_name(name=x))
2275
+ manure_composition_data['manure_state_type'] = manure_composition_data['manure_state_type'].apply(
2276
+ lambda x: convert_manure_state_type_name(name=x))
2277
+ return manure_composition_data.set_index(['animal_type', 'manure_state_type'])
2278
+
2279
+
2280
+ def read_table_29():
2281
+ excretion_rates = read_holos_resource_table(
2282
+ path_file=PathsHolosResources.Table_29_Percentage_Total_Manure_Produced_In_Systems)
2283
+ excretion_rates.index = excretion_rates.pop('Animal group').apply(lambda x: convert_animal_type_name(name=x))
2284
+ return excretion_rates
2285
+
2286
+
2287
+ class HolosTables:
2288
+ Table_6_Manure_Types_And_Default_Composition: DataFrame = read_table_6()
2289
+ Table_16_Livestock_Coefficients_BeefAndDairy_Cattle_Provider = read_holos_resource_table(
2290
+ path_file=PathsHolosResources.Table_16_Livestock_Coefficients_BeefAndDairy_Cattle_Provider,
2291
+ index_col="AnimalType")
2292
+ Table_21_Average_Milk_Production_For_Dairy_Cows_By_Province = utils.read_holos_resource_table(
2293
+ path_file=PathsHolosResources.Table_21_Average_Milk_Production_For_Dairy_Cows_By_Province,
2294
+ index_col='Year')
2295
+ Table_29_Percentage_Total_Manure_Produced_In_Systems = read_table_29()
2296
+ Table_30_Default_Bedding_Material_Composition_Provider = read_holos_resource_table(
2297
+ path_file=PathsHolosResources.Table_30_Default_Bedding_Material_Composition_Provider)
2298
+ Table_61_Fractions_of_dairy_cattle_N_volatilized = read_holos_resource_table(
2299
+ path_file=PathsHolosResources.Table_61_Fractions_of_dairy_cattle_N_volatilized)
2300
+ Table_62_Fractions_of_swine_N_volatilized = read_holos_resource_table(
2301
+ path_file=PathsHolosResources.Table_62_Fractions_of_swine_N_volatilized)