コード例 #1
0
ファイル: stock_padd.cs プロジェクト: hrpasl/ApsimX
        /// <summary>
        /// Test the Removal to determine if there is any quantity of forage removed.
        /// </summary>
        /// <returns>True if some herbage has been removed</returns>
        public bool SomethingRemoved()
        {
            bool result = false;

            // get the removal for each forage
            int        forageIdx = 0;
            ForageInfo forageInf = this.ForageByIndex(forageIdx);

            while ((forageInf != null) && (!result))
            {
                result = forageInf.SomethingRemoved();
                forageIdx++;
                forageInf = this.ForageByIndex(forageIdx);
            }
            return(result);
        }
コード例 #2
0
        /// <summary>
        /// Update the forage data for this crop/agpasture object
        /// </summary>
        /// <param name="forageObj">The crop/pasture object</param>
        public void UpdateForages(IPlantDamage forageObj)
        {
            // ensure this forage is in the list
            // the forage key in this case is component name
            ForageInfo forage = this.forages.ByName(this.ForageHostName);

            if (forage == null)
            {
                // if this cohort doesn't exist in the forage list
                forage      = new ForageInfo();
                forage.Name = this.ForageHostName.ToLower();
                this.owningPaddock.AssignForage(forage);               // the paddock in the model can access this forage
                this.forages.Add(forage);                              // create a new forage for this cohort
            }

            // TODO: just assuming one forage cohort in this component (expand here?)
            this.PassGrazingInputs(forage, this.Crop2GrazingInputs(forageObj), "g/m^2"); // then update it's value
        }
コード例 #3
0
 /// <summary>
 /// Assign a forage to this paddock
 /// </summary>
 /// <param name="forage">The forage object to assign to this paddock</param>
 public void AssignForage(ForageInfo forage)
 {
     this.Forages.Add(forage);
     forage.InPaddock = this;
 }
コード例 #4
0
        /// <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);
        }
コード例 #5
0
        /// <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);
            }
        }