/// <summary> /// Return the removal /// </summary> /// <param name="forage">The forage</param> /// <param name="units">The units</param> /// <returns>The grazing outputs/consumed</returns> public GrazType.GrazingOutputs ReturnRemoval(ForageInfo forage, string units) { double area; double scale; int idxClass; int idxSpecies; int idxRipe; GrazType.GrazingOutputs result = new GrazType.GrazingOutputs(); if (forage != null) { result = forage.RemovalKG; area = forage.InPaddock.Area; } else { result = new GrazType.GrazingOutputs(); area = 0.0; } if (area > 0.0) { if (units == "kg") { scale = 1.0; } else if (units == "g/m^2") { scale = 0.10 / area; } else if (units == "kg/ha") { scale = 1.0 / area; } else { throw new Exception("Stock: Unit (" + units + ") not recognised"); } if (scale != 1.0) { for (idxClass = 1; idxClass <= GrazType.DigClassNo; idxClass++) { result.Herbage[idxClass] = scale * result.Herbage[idxClass]; } for (idxSpecies = 1; idxSpecies <= GrazType.MaxPlantSpp; idxSpecies++) { for (idxRipe = GrazType.UNRIPE; idxRipe <= GrazType.RIPE; idxRipe++) { result.Seed[idxSpecies, idxRipe] = scale * result.Seed[idxSpecies, idxRipe]; } } } } return(result); }
/// <summary> /// The herbage is removed from the plant/agpasture /// </summary> public void RemoveHerbageFromPlant() { string chemType = string.Empty; int forageIdx = 0; ForageInfo forage = this.ForageByIndex(forageIdx); while (forage != null) { double area = forage.InPaddock.Area; GrazType.GrazingOutputs removed = forage.RemovalKG; // total the amount removed kg/ha double totalRemoved = 0.0; for (int i = 0; i < removed.Herbage.Length; i++) { totalRemoved += removed.Herbage[i]; } double propnRemoved = Math.Min(1.0, (totalRemoved / area) / (forage.TotalLive + forage.TotalDead + GrazType.Ungrazeable * 10.0)); // calculations in kg /ha, needs more checking, would be good to use a variable for the unit conversion on ungrazeable // calculations of proportions each organ of the total plant removed (in the native units) double totalDM = 0; foreach (IOrganDamage organ in ForageObj.Organs) { if (organ.IsAboveGround && (organ.Live.Wt + organ.Dead.Wt) > 0) { totalDM += organ.Live.Wt + organ.Dead.Wt; } } double amountRemoved = 0; double amountToRemove = propnRemoved * totalDM; foreach (IOrganDamage organ in ForageObj.Organs) { if (organ.IsAboveGround && (organ.Live.Wt + organ.Dead.Wt) > 0) { double propnOfPlantDM = (organ.Live.Wt + organ.Dead.Wt) / totalDM; double amountOfOrganToRemove = propnOfPlantDM * amountToRemove; double prpnOfOrganToRemove = amountOfOrganToRemove / (organ.Live.Wt + organ.Dead.Wt); prpnOfOrganToRemove = Math.Min(prpnOfOrganToRemove, 1.0); PMF.OrganBiomassRemovalType removal = new PMF.OrganBiomassRemovalType(); removal.FractionDeadToRemove = prpnOfOrganToRemove; removal.FractionLiveToRemove = prpnOfOrganToRemove; ForageObj.RemoveBiomass(organ.Name, "Graze", removal); amountRemoved += amountOfOrganToRemove; } } if (!APSIM.Shared.Utilities.MathUtilities.FloatsAreEqual(amountRemoved, amountToRemove)) { throw new Exception("Mass balance check fail in Stock. The amount of biomass removed from the plant does not equal the amount of forage the animals consumed."); } forageIdx++; forage = this.ForageByIndex(forageIdx); } }
/// <summary> /// The herbage is removed from the plant/agpasture /// </summary> public void RemoveHerbageFromPlant() { string chemType = string.Empty; int forageIdx = 0; ForageInfo forage = this.ForageByIndex(forageIdx); while (forage != null) { double area = forage.InPaddock.Area; GrazType.GrazingOutputs removed = forage.RemovalKG; // total the amount removed kg/ha double totalRemoved = 0.0; for (int i = 0; i < removed.Herbage.Length; i++) { totalRemoved += removed.Herbage[i]; } double propnRemoved = Math.Min(1.0, (totalRemoved / area) / (forage.TotalLive + forage.TotalDead + GrazType.Ungrazeable * 10.0)); // calculations in kg /ha, needs more checking, would be good to use a variable for the unit conversion on ungrazeable // calculations of proportions each organ of the total plant removed (in the native units) double totalDM = 0; foreach (IOrganDamage organ in ForageObj.Organs) { if (organ.IsAboveGround && (organ.Live.Wt + organ.Dead.Wt) > 0) { totalDM += organ.Live.Wt + organ.Dead.Wt; } } foreach (IOrganDamage organ in ForageObj.Organs) { if (organ.IsAboveGround && (organ.Live.Wt + organ.Dead.Wt) > 0) { double propnOfPlantDM = (organ.Live.Wt + organ.Dead.Wt) / totalDM; double prpnToRemove = propnRemoved * propnOfPlantDM; prpnToRemove = Math.Min(prpnToRemove, 1.0); PMF.OrganBiomassRemovalType removal = new PMF.OrganBiomassRemovalType(); removal.FractionDeadToRemove = prpnToRemove; removal.FractionLiveToRemove = prpnToRemove; ForageObj.RemoveBiomass(organ.Name, "Graze", removal); } } forageIdx++; forage = this.ForageByIndex(forageIdx); } }
/// <summary> /// The herbage is removed from the plant/agpasture /// </summary> public void RemoveHerbageFromPlant() { string chemType = string.Empty; int forageIdx = 0; ForageInfo forage = this.ForageByIndex(forageIdx); while (forage != null) { double area = forage.InPaddock.Area; GrazType.GrazingOutputs removed = forage.RemovalKG; // total the amount removed kg/ha double totalRemoved = 0.0; for (int i = 0; i < removed.Herbage.Length; i++) { totalRemoved += removed.Herbage[i]; } double propnRemoved = Math.Min(1.0, (totalRemoved / area) / (forage.TotalLive + forage.TotalDead + GrazType.Ungrazeable * 10.0)); // calculations in kg /ha, needs more checking, would be good to use a variable for the unit conversion on ungrazeable // calculations of proportions each organ of the total plant removed (in the native units) double totalDM = ForageObj.Material.Sum(m => m.Total.Wt); double consumableDM = ForageObj.Material.Sum(m => m.Consumable.Wt); double amountRemoved = 0; double amountToRemove = propnRemoved * consumableDM; var liveMaterial = ForageObj.Material.Where(m => m.IsLive).ToList(); foreach (var live in liveMaterial) { // Find corresponding dead material var dead = ForageObj.Material.FirstOrDefault(m => !m.IsLive && m.Name == live.Name); if (dead == null) { throw new Exception($"Cannot find dead material for {live.Name}."); } if (live.Total.Wt + dead.Total.Wt > 0) { double propnOfPlantDM = (live.Total.Wt + dead.Total.Wt) / totalDM; double amountOfOrganToRemove = propnOfPlantDM * amountToRemove; double prpnOfOrganToRemove = amountOfOrganToRemove / (live.Total.Wt + dead.Total.Wt); prpnOfOrganToRemove = Math.Min(prpnOfOrganToRemove, 1.0); PMF.OrganBiomassRemovalType removal = new PMF.OrganBiomassRemovalType(); removal.FractionDeadToRemove = prpnOfOrganToRemove; removal.FractionLiveToRemove = prpnOfOrganToRemove; ForageObj.RemoveBiomass(live.Name, removal); amountRemoved += amountOfOrganToRemove; } } if (liveMaterial.Count == 0) { var deadMaterial = ForageObj.Material.Where(m => !m.IsLive).ToList(); foreach (var dead in deadMaterial) { // This can happen for surface organic matter which only has dead material. double propnOfPlantDM = dead.Total.Wt / totalDM; double amountOfOrganToRemove = propnOfPlantDM * amountToRemove; double prpnOfOrganToRemove = MathUtilities.Divide(amountOfOrganToRemove, dead.Total.Wt, 0); prpnOfOrganToRemove = Math.Min(prpnOfOrganToRemove, 1.0); PMF.OrganBiomassRemovalType removal = new PMF.OrganBiomassRemovalType(); removal.FractionDeadToRemove = prpnOfOrganToRemove; ForageObj.RemoveBiomass(dead.Name, removal); amountRemoved += amountOfOrganToRemove; } } if (!APSIM.Shared.Utilities.MathUtilities.FloatsAreEqual(amountRemoved, amountToRemove)) { throw new Exception("Mass balance check fail in Stock. The amount of biomass removed from the plant does not equal the amount of forage the animals consumed."); } forageIdx++; forage = this.ForageByIndex(forageIdx); } }