Source code for climag.modvege_consumption

  1"""Functions for computing harvested and ingested biomass
  2
  3References
  4----------
  5.. [#Jouven] Jouven, M., Carrère, P., and Baumont, R. (2006). ‘Model
  6    predicting dynamics of biomass, structure and digestibility of herbage in
  7    managed permanent pastures. 1. Model description’, Grass and Forage
  8    Science, 61(2), pp. 112–124.
  9    https://doi.org/10.1111/j.1365-2494.2006.00515.x.
 10.. [#Kavanagh] Kavanagh, S. (2016). ‘Feeding the Dairy Cow’, in Teagasc Dairy
 11    Manual. Teagasc, pp. 201–212. Available at:
 12    https://www.teagasc.ie/publications/2016/teagasc-dairy-manual.php
 13    (Accessed: 2 November 2022).
 14.. [#Broad] Broad, H. J. and Hough, M. N. (1993). ‘The growing and grazing
 15    season in the United Kingdom’, Grass and Forage Science, 48(1), pp. 26–37.
 16    https://doi.org/10.1111/j.1365-2494.1993.tb01833.x.
 17.. [#Eurostat] Eurostat (2022). Glossary:Livestock unit (LSU). Available at:
 18    https://ec.europa.eu/eurostat/statistics-explained/index.php?title=Glossary:Livestock_unit_(LSU)
 19    (Accessed: 2 November 2022).
 20"""
 21
 22import numpy as np
 23
 24np.seterr("raise")
 25
 26
[docs] 27def organic_matter_digestibility( 28 ts_vals: dict[str, float], params: dict[str, float] 29): 30 """Organic matter digestibility 31 32 Parameters 33 ---------- 34 ts_vals : dict 35 Dictionary with intermediate time series values 36 params : dict 37 Dictionary of model parameters 38 39 Returns 40 ------- 41 dict 42 Updated `ts_vals` dictionary 43 44 Notes 45 ----- 46 Organic matter digestibility of the green vegetative (GV) and green 47 reproductive (GR) compartments. See Equations (9) and (10) in [#Jouven]_. 48 49 Digestibility varies among plant parts, with leaves usually being more 50 digestible than stems. The differing digestibility of plant parts may 51 explain why they are grazed selectively. Digestibility of green 52 compartments decreases linearly with compartment age. 53 54 This function returns an updated `ts_vals` dictionary with: 55 56 - `omd_gv`: Organic matter digestibility of the GV compartment 57 [dimensionless] 58 - `omd_gr`: Organic matter digestibility of the GR compartment 59 [dimensionless] 60 """ 61 ts_vals["omd_gv"] = max( 62 params["max_omd_gv"] 63 - (ts_vals["age_gv"] * (params["max_omd_gv"] - params["min_omd_gv"])) 64 / params["lls"], 65 params["min_omd_gv"], 66 ) 67 68 ts_vals["omd_gr"] = max( 69 params["max_omd_gr"] 70 - (ts_vals["age_gr"] * (params["max_omd_gr"] - params["min_omd_gr"])) 71 / (params["st_2"] - params["st_1"]), 72 params["min_omd_gr"], 73 )
74 75
[docs] 76def biomass_ingestion(ts_vals: dict[str, float], params: dict[str, float]): 77 """Biomass ingestion through grazing 78 79 Parameters 80 ---------- 81 ts_vals : dict 82 Dictionary of intermediate time series values 83 params : dict 84 Dictionary containing of model parameters 85 86 Returns 87 ------- 88 dict 89 Updated `ts_vals` dictionary 90 91 Notes 92 ----- 93 The maximum amount of biomass available for grazing and/or harvesting 94 for each structural compartment. 95 96 - Maintain the height of the residual biomass after harvest to the 97 minimum residual grass height 98 - The bulk density is used to convert this height to the equivalent 99 biomass amount. See [#Jouven]_, sec. "Harvested biomass", 100 Equation (19) 101 102 The maximum amount of biomass ingestible based on the stocking rate 103 104 - Ingestion takes precedence over harvesting 105 - The amount of biomass ingested per livestock unit per day is 106 13 kg DM LU⁻¹ based on average consumption data for dairy cows from 107 [#Kavanagh]_ and the value used by [#Broad]_ 108 - One livestock unit (LU) is equivalent to one dairy cow, based on 109 [#Eurostat]_ 110 111 The amount of biomass ingested in total for each structural compartment 112 113 - This is weighted according to the organic matter digestibility. 114 - Digestibility varies among plant parts, with leaves usually being 115 more digestible than stems 116 - The differing digestibility of plant parts may explain why they are 117 grazed selectively 118 119 **Assumption**: when grazed/harvested, 10% of the available biomass in each 120 structural component is lost. 121 122 This function returns an updated `ts_vals` dictionary with: 123 124 - `i_bm`: The total ingested biomass amount [kg DM ha⁻¹] 125 - `bm_gv`: Updated standing biomass of the green vegetative 126 compartment [kg DM ha⁻¹] 127 - `bm_gr`: Updated standing biomass of the green reproductive 128 compartment [kg DM ha⁻¹] 129 - `bm_dv`: Updated standing biomass of the dead vegetative 130 compartment [kg DM ha⁻¹] 131 - `bm_dr`: Updated standing biomass of the dead reproductive 132 compartment [kg DM ha⁻¹] 133 """ 134 if ( 135 params["sr"] > 0.0 136 and params["h_grass"] >= 0.0 137 and params["st_g1"] <= ts_vals["st"] <= params["st_g2"] 138 ): 139 # max available compartmental biomass 140 available_biomass = {} 141 for key in ["gv", "gr", "dv", "dr"]: 142 residual_biomass = params["h_grass"] * params[f"bd_{key}"] * 10.0 143 if residual_biomass < ts_vals[f"bm_{key}"]: 144 available_biomass[f"bm_{key}"] = ( 145 ts_vals[f"bm_{key}"] - residual_biomass 146 ) * 0.9 147 else: 148 available_biomass[f"bm_{key}"] = 0.0 149 150 # max ingested biomass 151 max_ingested_biomass = params["sr"] * params["i_bm_lu"] 152 153 # ingested compartmental biomass 154 weights = {} 155 ingested = {} 156 157 weights_total = ( 158 ts_vals["omd_gv"] 159 + ts_vals["omd_gr"] 160 + params["omd_dv"] 161 + params["omd_dr"] 162 ) 163 164 weights["bm_gv"] = ts_vals["omd_gv"] / weights_total 165 weights["bm_gr"] = ts_vals["omd_gr"] / weights_total 166 weights["bm_dv"] = params["omd_dv"] / weights_total 167 weights["bm_dr"] = params["omd_dr"] / weights_total 168 169 # sort by weight 170 weights = dict(sorted(weights.items(), key=lambda item: item[1])) 171 172 needed = 0.0 173 174 for key in weights: 175 ingested[key] = max_ingested_biomass * weights[key] 176 ingested[key] += needed 177 if available_biomass[key] < ingested[key]: 178 needed = ingested[key] - available_biomass[key] 179 ingested[key] = available_biomass[key] 180 else: 181 needed = 0.0 182 # update biomass compartments 183 # 10% of biomass is lost during ingestion 184 ts_vals[key] -= ingested[key] / 0.9 185 186 # total ingestion 187 ts_vals["i_bm"] += ( 188 ingested["bm_gv"] 189 + ingested["bm_gr"] 190 + ingested["bm_dv"] 191 + ingested["bm_dr"] 192 ) 193 194 # daily values 195 ts_vals["c_bm"] = ( 196 ingested["bm_gv"] 197 + ingested["bm_gr"] 198 + ingested["bm_dv"] 199 + ingested["bm_dr"] 200 ) 201 202 else: 203 ts_vals["c_bm"] = 0.0
204 205
[docs] 206def biomass_harvest(ts_vals: dict[str, float], params: dict[str, float]): 207 """Harvest biomass through a cutting event 208 209 Parameters 210 ---------- 211 ts_vals : dict 212 A dictionary with intermediate time series values. 213 params : dict 214 A dictionary containing of model parameters 215 216 Returns 217 ------- 218 dict 219 An updated `ts_vals` dictionary 220 221 Notes 222 ----- 223 Harvest biomass through a cutting event at the end of the reproductive 224 period. 225 Maintain the height of the residual biomass after harvest to the minimum 226 cut height. This height is calculated by using the bulk density. 227 See [#Jouven]_, sec. "Harvested biomass", Equation (19). 228 229 **Assumption**: during harvest, 10% of the harvestable biomass in each 230 structural component is lost. 231 232 This function updated `ts_vals` dictionary with: 233 234 - `h_bm`: The total harvested biomass amount [kg DM ha⁻¹] 235 - `bm_gv`: Updated standing biomass of the green vegetative 236 compartment [kg DM ha⁻¹] 237 - `bm_gr`: Updated standing biomass of the green reproductive 238 compartment [kg DM ha⁻¹] 239 - `bm_dv`: Updated standing biomass of the dead vegetative 240 compartment [kg DM ha⁻¹] 241 - `bm_dr`: Updated standing biomass of the dead reproductive 242 compartment [kg DM ha⁻¹] 243 """ 244 if ( 245 params["h_grass"] >= 0.0 246 and params["st_h1"] <= ts_vals["st"] <= params["st_g2"] 247 ): 248 harvested_biomass = {} 249 for key in ["gv", "gr", "dv", "dr"]: 250 # harvested biomass for each compartment 251 residual_biomass = params["h_grass"] * params[f"bd_{key}"] * 10.0 252 harvested_biomass[f"bm_{key}"] = 0.0 253 if residual_biomass < ts_vals[f"bm_{key}"]: 254 harvested_biomass[f"bm_{key}"] += ( 255 ts_vals[f"bm_{key}"] - residual_biomass 256 ) * 0.9 257 # update biomass compartments 258 # 10% of biomass is lost during harvest 259 ts_vals[f"bm_{key}"] -= harvested_biomass[f"bm_{key}"] / 0.9 260 261 # total harvested biomass 262 ts_vals["h_bm"] += ( 263 harvested_biomass["bm_gv"] 264 + harvested_biomass["bm_gr"] 265 + harvested_biomass["bm_dv"] 266 + harvested_biomass["bm_dr"] 267 )