/// <summary> /// Use the GrazingInputs to initialise the forage object /// </summary> /// <param name="forage">The forage object</param> /// <param name="grazingInput">The grazing inputs</param> /// <param name="units">The units</param> public void PassGrazingInputs(ForageInfo forage, GrazType.GrazingInputs grazingInput, string units) { double scaleInput; if (units == "kg/ha") // Convert to kg/ha { scaleInput = 1.0; } else if (units == "g/m^2") { scaleInput = 10.0; } else { throw new Exception("Stock: Unit (" + units + ") not recognised"); } if (forage != null) { forage.SetAvailForage(GrazType.ScaleGrazingInputs(grazingInput, scaleInput)); } else { throw new Exception("Stock: Forage not recognised"); } }
/// <summary> /// Populate the dry matter pool /// </summary> /// <param name="model">The stock model</param> /// <param name="propCode">The property code</param> /// <param name="useYoung">For young</param> /// <param name="useAll">For all groups</param> /// <param name="useTag">For tag number</param> /// <param name="poolValues">The DM pool value returned</param> /// <returns>True if the propCode is valid</returns> public static bool PopulateDMPoolValue(StockList model, int propCode, bool useYoung, bool useAll, bool useTag, ref DMPoolHead[] poolValues) { int numPasses; AnimalGroup animalGroup; GrazType.DM_Pool pool = new GrazType.DM_Pool(); GrazType.DM_Pool totalPool = new GrazType.DM_Pool(); int denom; int passIdx, idx; bool result = true; for (int i = 0; i < poolValues.Length; i++) { poolValues[i] = new DMPoolHead(); } if (useTag) { numPasses = poolValues.Length; } else { numPasses = 1; } for (passIdx = 1; passIdx <= numPasses; passIdx++) { GrazType.ZeroDMPool(ref totalPool); denom = 0; for (idx = 1; idx <= model.Count(); idx++) { if (!useTag || (model.GetTag(idx) == passIdx)) { if (!useYoung) { animalGroup = model.At(idx); } else { animalGroup = model.At(idx).Young; } GrazType.ZeroDMPool(ref pool); if (animalGroup != null) { int n = (int)GrazType.TOMElement.n; int p = (int)GrazType.TOMElement.p; int s = (int)GrazType.TOMElement.s; switch (propCode) { case StockProps.prpINTAKE: pool.DM = animalGroup.AnimalState.DM_Intake.Total; pool.Nu[n] = animalGroup.AnimalState.CP_Intake.Total / GrazType.N2Protein; pool.Nu[p] = animalGroup.AnimalState.Phos_Intake.Total; pool.Nu[s] = animalGroup.AnimalState.Sulf_Intake.Total; pool.AshAlk = (animalGroup.AnimalState.PaddockIntake.AshAlkalinity * animalGroup.AnimalState.PaddockIntake.Biomass) + (animalGroup.AnimalState.SuppIntake.AshAlkalinity * animalGroup.AnimalState.SuppIntake.Biomass); break; case StockProps.prpINTAKE_PAST: pool.DM = animalGroup.AnimalState.DM_Intake.Herbage; pool.Nu[n] = animalGroup.AnimalState.CP_Intake.Herbage / GrazType.N2Protein; pool.Nu[p] = animalGroup.AnimalState.Phos_Intake.Herbage; pool.Nu[s] = animalGroup.AnimalState.Sulf_Intake.Herbage; pool.AshAlk = animalGroup.AnimalState.PaddockIntake.AshAlkalinity * animalGroup.AnimalState.PaddockIntake.Biomass; break; case StockProps.prpINTAKE_SUPP: pool.DM = animalGroup.AnimalState.DM_Intake.Supp; pool.Nu[n] = animalGroup.AnimalState.CP_Intake.Supp / GrazType.N2Protein; pool.Nu[p] = animalGroup.AnimalState.Phos_Intake.Supp; pool.Nu[s] = animalGroup.AnimalState.Sulf_Intake.Supp; pool.AshAlk = animalGroup.AnimalState.SuppIntake.AshAlkalinity * animalGroup.AnimalState.SuppIntake.Biomass; break; case StockProps.prpFAECES: GrazType.AddDMPool(animalGroup.AnimalState.OrgFaeces, pool); GrazType.AddDMPool(animalGroup.AnimalState.InOrgFaeces, pool); break; case StockProps.prpINORG_FAECES: GrazType.AddDMPool(animalGroup.AnimalState.InOrgFaeces, pool); break; default: result = false; break; } } if (!useTag && !useAll) { DMPool2Value(pool, ref poolValues[idx - 1], (propCode == StockProps.prpINORG_FAECES)); } else if (animalGroup != null) { GrazType.AddDMPool(GrazType.MultiplyDMPool(pool, animalGroup.NoAnimals), totalPool); denom = denom + animalGroup.NoAnimals; } } } // _ loop over animal groups _ if (useTag || useAll) { if (denom > 0) { totalPool = GrazType.PoolFraction(totalPool, 1.0 / denom); } if (useAll) { DMPool2Value(totalPool, ref poolValues[0], (propCode == StockProps.prpINORG_FAECES)); } else { DMPool2Value(totalPool, ref poolValues[passIdx - 1], (propCode == StockProps.prpINORG_FAECES)); } } } return(result); }
/// <summary> /// Populate the dry matter pool /// </summary> /// <param name="Model"></param> /// <param name="iCode"></param> /// <param name="bUseYoung"></param> /// <param name="bUseAll"></param> /// <param name="bUseTag"></param> /// <param name="aValue"></param> /// <returns></returns> public static bool PopulateDMPoolValue(TStockList Model, int iCode, bool bUseYoung, bool bUseAll, bool bUseTag, ref TDMPoolHead[] aValue) { int iNoPasses; TAnimalGroup aGroup; GrazType.DM_Pool Pool = new GrazType.DM_Pool(); GrazType.DM_Pool TotalPool = new GrazType.DM_Pool(); int iDenom; int iPass, Idx; bool Result = true; for (int i = 0; i < aValue.Length; i++) { aValue[i] = new TDMPoolHead(); } if (bUseTag) { iNoPasses = aValue.Length; } else { iNoPasses = 1; } for (iPass = 1; iPass <= iNoPasses; iPass++) { GrazType.ZeroDMPool(ref TotalPool); iDenom = 0; for (Idx = 1; Idx <= Model.Count(); Idx++) { if (!bUseTag || (Model.getTag(Idx) == iPass)) { if (!bUseYoung) { aGroup = Model.At(Idx); } else { aGroup = Model.At(Idx).Young; } GrazType.ZeroDMPool(ref Pool); if (aGroup != null) { int N = (int)GrazType.TOMElement.N; int P = (int)GrazType.TOMElement.P; int S = (int)GrazType.TOMElement.S; switch (iCode) { case StockProps.prpINTAKE: Pool.DM = aGroup.AnimalState.DM_Intake.Total; Pool.Nu[N] = aGroup.AnimalState.CP_Intake.Total / GrazType.N2Protein; Pool.Nu[P] = aGroup.AnimalState.Phos_Intake.Total; Pool.Nu[S] = aGroup.AnimalState.Sulf_Intake.Total; Pool.AshAlk = aGroup.AnimalState.PaddockIntake.AshAlkalinity * aGroup.AnimalState.PaddockIntake.Biomass + aGroup.AnimalState.SuppIntake.AshAlkalinity * aGroup.AnimalState.SuppIntake.Biomass; break; case StockProps.prpINTAKE_PAST: Pool.DM = aGroup.AnimalState.DM_Intake.Herbage; Pool.Nu[N] = aGroup.AnimalState.CP_Intake.Herbage / GrazType.N2Protein; Pool.Nu[P] = aGroup.AnimalState.Phos_Intake.Herbage; Pool.Nu[S] = aGroup.AnimalState.Sulf_Intake.Herbage; Pool.AshAlk = aGroup.AnimalState.PaddockIntake.AshAlkalinity * aGroup.AnimalState.PaddockIntake.Biomass; break; case StockProps.prpINTAKE_SUPP: Pool.DM = aGroup.AnimalState.DM_Intake.Supp; Pool.Nu[N] = aGroup.AnimalState.CP_Intake.Supp / GrazType.N2Protein; Pool.Nu[P] = aGroup.AnimalState.Phos_Intake.Supp; Pool.Nu[S] = aGroup.AnimalState.Sulf_Intake.Supp; Pool.AshAlk = aGroup.AnimalState.SuppIntake.AshAlkalinity * aGroup.AnimalState.SuppIntake.Biomass; break; case StockProps.prpFAECES: GrazType.AddDMPool(aGroup.AnimalState.OrgFaeces, Pool); GrazType.AddDMPool(aGroup.AnimalState.InOrgFaeces, Pool); break; case StockProps.prpINORG_FAECES: GrazType.AddDMPool(aGroup.AnimalState.InOrgFaeces, Pool); break; default: Result = false; break; } } if (!bUseTag && !bUseAll) { DMPool2Value(Pool, aValue[Idx - 1], (iCode == StockProps.prpINORG_FAECES)); } else if (aGroup != null) { GrazType.AddDMPool(GrazType.MultiplyDMPool(Pool, aGroup.NoAnimals), TotalPool); iDenom = iDenom + aGroup.NoAnimals; } } } //_ loop over animal groups _ if (bUseTag || bUseAll) { if (iDenom > 0) { TotalPool = GrazType.PoolFraction(TotalPool, 1.0 / iDenom); } if (bUseAll) { DMPool2Value(TotalPool, aValue[0], (iCode == StockProps.prpINORG_FAECES)); } else { DMPool2Value(TotalPool, aValue[iPass - 1], (iCode == StockProps.prpINORG_FAECES)); } } } return(Result); }
/// <summary> /// Copies a Plant/AgPasture object biomass organs into GrazingInputs object /// This object may then get scaled to kg/ha /// </summary> /// <param name="forageObj">The forage object - a Plant/AgPasture component</param> /// <returns>The grazing inputs</returns> private GrazType.GrazingInputs Crop2GrazingInputs(IPlantDamage forageObj) { GrazType.GrazingInputs result = new GrazType.GrazingInputs(); GrazType.zeroGrazingInputs(ref result); result.TotalGreen = 0; result.TotalDead = 0; double totalDMD = 0; double totalN = 0; double nConc; double meanDMD; double dmd; // calculate the green available based on the total green in this paddock double greenPropn = 0; // ** should really take into account the height ratio here e.g. Params.HeightRatio if (this.PastureGreenDM > GrazType.Ungrazeable) { greenPropn = 1.0 - (GrazType.Ungrazeable / this.PastureGreenDM); } // calculate the total live and dead biomass foreach (IOrganDamage biomass in forageObj.Organs) { if (biomass.IsAboveGround) { if (biomass.Live.Wt > 0 || biomass.Dead.Wt > 0) { result.TotalGreen += (greenPropn * biomass.Live.Wt); // g/m^2 result.TotalDead += biomass.Dead.Wt; // we can find the dmd of structural, assume storage and metabolic are 100% digestible dmd = (biomass.Live.DMDOfStructural * greenPropn * biomass.Live.StructuralWt) + (1 * greenPropn * biomass.Live.StorageWt) + (1 * greenPropn * biomass.Live.MetabolicWt); // storage and metab are 100% dmd dmd += ((biomass.Dead.DMDOfStructural * biomass.Dead.StructuralWt) + (1 * biomass.Dead.StorageWt) + (1 * biomass.Dead.MetabolicWt)); totalDMD += dmd; totalN += (greenPropn * biomass.Live.N) + (biomass.Dead.Wt > 0 ? biomass.Dead.N : 0); // g/m^2 } } } // TODO: Improve this routine double availDM = result.TotalGreen + result.TotalDead; if (availDM > 0) { meanDMD = totalDMD / availDM; // calc the average dmd for the plant nConc = totalN / availDM; // N conc // get the dmd distribution double[] dmdPropns; // = new double[GrazType.DigClassNo + 1]; // green 0.85-0.45, dead 0.70-0.30 dmdPropns = ForageInfo.CalcDMDDistribution(meanDMD, 0.85, 0.45); // FIX ME: the DMD ranges should be organ- and development-specific values for (int idx = 1; idx <= GrazType.DigClassNo; idx++) { result.Herbage[idx].Biomass = dmdPropns[idx] * availDM; result.Herbage[idx].CrudeProtein = nConc * GrazType.N2Protein; result.Herbage[idx].Digestibility = GrazType.ClassDig[idx]; result.Herbage[idx].Degradability = Math.Min(0.90, result.Herbage[idx].Digestibility + 0.10); result.Herbage[idx].HeightRatio = 1; result.Herbage[idx].PhosContent = 0; // N * 0.05? result.Herbage[idx].SulfContent = 0; // N * 0.07? result.Herbage[idx].AshAlkalinity = 0.70; // TODO: use a modelled value } if (forageObj is IPlant plant) { switch (plant.PlantType) { case "AGPLucerne": case "AGPRedClover": case "AGPWhiteClover": result.LegumePropn = 1; break; default: result.LegumePropn = 0; break; } } result.SelectFactor = 0; // TODO: set from Plant model value // TODO: Store any seed pools } return(result); }