예제 #1
0
파일: stock_padd.cs 프로젝트: hol353/ApsimX
        /// <summary>
        /// * The providing forage component is specifying a list of quantities of
        ///   forage, each of which has a known mean DMD (denoted by passing DDM and IDM
        ///   sub-pools). That is, the providing module is taking responsibility for
        ///   providing a DMD distribution for each cohort, organ and age class
        /// * The Stock component will place each quantity of forage into (usually 2)
        ///   adjacent DMD classes, so as to preserve the provided mean DMD
        /// </summary>
        /// <param name="dAvailPropn"></param>
        /// <param name="dBulkDensity"></param>
        /// <returns></returns>
        public GrazType.TGrazingInputs convertChemistry_VarDMDClasses(double dAvailPropn, double dBulkDensity)
        {

            double dPoolDM;     // Mass of each sub-pool of forage
            double dPoolDMD;    // Digestibility of sub-pool of forage
            int iDMDClass;
            double dClassPropn;

            int iDMD;           // DMD classes (regularly spaced) in TGrazingInputs
            int iPool;          // DMD classes (irregularly spaced) in the chemistry type
            int iChemDDM;
            int iChemIDM;


            GrazType.TGrazingInputs Result = new GrazType.TGrazingInputs();
            for (iDMD = 1; iDMD <= GrazType.DigClassNo; iDMD++)
                Result.Herbage[iDMD].HeightRatio = 1.0;

            this.dHerbageDMDFract = new double[GrazType.DigClassNo + 1];
            this.dSeedRipeFract = new double[3];

            // Leaf & stem pools
            if (FSeedType == NOT_SEED)
            {
                for (iPool = 1; iPool <= MAX_DDM_CLASSES; iPool++)
                {
                    iChemDDM = 2 * iPool;
                    iChemIDM = 2 * iPool + 1;

                    dPoolDM = FChemData[iChemDDM].dMass_KgHa + FChemData[iChemIDM].dMass_KgHa;

                    if (dPoolDM > 0.0)
                    {
                        dPoolDMD = FChemData[iChemDDM].dMass_KgHa / dPoolDM;

                        if (dPoolDMD >= GrazType.ClassDig[1])
                        {
                            iDMDClass = 1;
                            dClassPropn = 1.0;
                        }
                        else if (dPoolDMD <= GrazType.ClassDig[GrazType.DigClassNo])
                        {
                            iDMDClass = GrazType.DigClassNo;
                            dClassPropn = 1.0;
                        }
                        else
                        {
                            iDMDClass = Convert.ToInt32(Math.Max(1, Math.Min(1 + Math.Truncate((GrazType.ClassDig[1] - dPoolDMD) / CLASSWIDTH), GrazType.DigClassNo - 1)));
                            dClassPropn = Math.Max(0.0, Math.Min((dPoolDMD - GrazType.ClassDig[iDMDClass + 1]) / CLASSWIDTH, 1.0));
                        }

                        if (dClassPropn > 0.0)
                            populateIntakeRecord(ref Result.Herbage[iDMDClass], iDMDClass, (dClassPropn == 1.0),
                                                  dPoolDM, dPoolDMD, dAvailPropn * dClassPropn,
                                                  FChemData[iChemDDM].dNitrogen_KgHa, FChemData[iChemIDM].dNitrogen_KgHa,
                                                  FChemData[iChemDDM].dPhosphorus_KgHa, FChemData[iChemIDM].dPhosphorus_KgHa,
                                                  FChemData[iChemDDM].dSulphur_KgHa, FChemData[iChemIDM].dSulphur_KgHa,
                                                  FChemData[iChemDDM].dAshAlk_MolHa, FChemData[iChemIDM].dAshAlk_MolHa,
                                                  dBulkDensity);
                        if (dClassPropn < 1.0)
                            populateIntakeRecord(ref Result.Herbage[iDMDClass + 1], iDMDClass + 1, false,
                                                  dPoolDM, dPoolDMD, dAvailPropn * (1.0 - dClassPropn),
                                                  FChemData[iChemDDM].dNitrogen_KgHa, FChemData[iChemIDM].dNitrogen_KgHa,
                                                  FChemData[iChemDDM].dPhosphorus_KgHa, FChemData[iChemIDM].dPhosphorus_KgHa,
                                                  FChemData[iChemDDM].dSulphur_KgHa, FChemData[iChemIDM].dSulphur_KgHa,
                                                  FChemData[iChemDDM].dAshAlk_MolHa, FChemData[iChemIDM].dAshAlk_MolHa,
                                                  dBulkDensity);
                    }
                }

                populateHerbageType(ref Result);
            }

            // Seed pools: not permitted
            else if ((FSeedType == GrazType.UNRIPE) || (FSeedType == GrazType.RIPE))
                throw new Exception("Chemistry \"DDMnn\"/\"IDMnn\" may not be used when the organ is seeds, heads or ears");

            return Result;
        }
예제 #2
0
파일: stock_padd.cs 프로젝트: hol353/ApsimX
        /// <summary>
        /// Calculates the TGrazingInputs values from the values stored during addForageData() 
        /// </summary>
        /// <param name="fMaxGH"></param>
        /// <param name="fCurvature"></param>
        /// <param name="fSlope"></param>
        /// <returns></returns>
        public GrazType.TGrazingInputs availForage(double fMaxGH, double fCurvature, double fSlope)
        {
            GrazType.TGrazingInputs Result = new GrazType.TGrazingInputs();

            double fGreenHeight;
            double[] fAvailPropn = new double[2];  // TRUE = green forage, FALSE = dry forage
            double dBulkDensity;
            GrazType.TGrazingInputs fractionData;
            int iDMD;
            int iRipe;

            if (FUseForageData)
                Result.CopyFrom(FForageData);
            else
            {
                if (FGreenMass > 0.0)
                {
                    fGreenHeight = 1.0E-4 * InPaddock.FSummedGreenMass / FGreenBulkDensity;                                                 // Height is in metres here, FSummedGreenMass in kg/ha and BD in kg/m^3
                    fAvailPropn[1] = Math.Max(0.0, 1.0 - GrazType.fGrazingHeight(fGreenHeight, fMaxGH, fCurvature, fSlope) / fGreenHeight); // green
                }
                else
                    fAvailPropn[1] = 0.0;
                fAvailPropn[0] = 1.0;      

                GrazType.zeroGrazingInputs(ref Result);
                dBulkDensity = this.dHerbageBulkDensity();
                switch (FChemistryType)
                {
                    case TForageChemistry.fcDigInDig:
                        fractionData = this.convertChemistry_DigInDig(fAvailPropn[(FIsGreen ? 1 : 0)], dBulkDensity);
                        break;
                    case TForageChemistry.fcMeanDMD:
                        fractionData = this.convertChemistry_MeanDMD(fAvailPropn[(FIsGreen ? 1 : 0)], dBulkDensity);
                        break;
                    case TForageChemistry.fcDMDClasses6:
                        fractionData = this.convertChemistry_DMDClasses6(fAvailPropn[(FIsGreen ? 1 : 0)], dBulkDensity);
                        break;
                    case TForageChemistry.fcVarDMDClasses:
                        fractionData = this.convertChemistry_VarDMDClasses(fAvailPropn[(FIsGreen ? 1 : 0)], dBulkDensity);
                        break;
                    default:
                        throw new Exception("Cannot translate the forage chemistry inputs");
                }

                GrazType.addGrazingInputs(1, fractionData, ref Result);

                // Finish computing the proportion of DMD class that is contributed by each herbage fraction
                // This is used to disaggregate the computed intakes back to the source forages

                for (iDMD = 1; iDMD <= GrazType.DigClassNo; iDMD++)
                {
                    if (Result.Herbage[iDMD].Biomass > 0.0)
                        this.dHerbageDMDFract[iDMD] = this.dHerbageDMDFract[iDMD] / Result.Herbage[iDMD].Biomass;
                    for (iRipe = GrazType.UNRIPE; iRipe <= GrazType.RIPE; iRipe++)
                        if (Result.Seeds[1, iRipe].Biomass > 0.0)
                            this.dSeedRipeFract[iRipe] = this.dSeedRipeFract[iRipe] / Result.Seeds[1, iRipe].Biomass;
                }
            }
            return Result;
        }
예제 #3
0
파일: stock_padd.cs 프로젝트: hol353/ApsimX
        /// <summary>
        /// The providing forage component is specifying a list of quantities of forage,
        ///   each of which is assumed to have DMD uniformly distributed across one of
        ///   the TAnimalGroup DMD pools
        /// </summary>
        /// <param name="dAvailPropn"></param>
        /// <param name="dBulkDensity"></param>
        /// <returns></returns>
        public GrazType.TGrazingInputs convertChemistry_DMDClasses6(double dAvailPropn, double dBulkDensity)
        {
            int iChem;
            int iDMD;

            GrazType.TGrazingInputs Result = new GrazType.TGrazingInputs();
            for (iDMD = 1; iDMD <= GrazType.DigClassNo; iDMD++)
                Result.Herbage[iDMD].HeightRatio = 1.0;

            this.dHerbageDMDFract = new double[GrazType.DigClassNo + 1];
            this.dSeedRipeFract = new double[3];

            // Leaf & stem pools
            if (FSeedType == NOT_SEED)
            {
                for (iChem = 0; iChem <= this.CHEM_COUNT[(int)TForageChemistry.fcDMDClasses6] - 1; iChem++)
                {
                    iDMD = iChem + 1;

                    Result.Herbage[iDMD].Biomass = dAvailPropn * FChemData[iChem].dMass_KgHa;
                    Result.Herbage[iDMD].Digestibility = GrazType.ClassDig[iDMD];
                    Result.Herbage[iDMD].Degradability = Math.Min(0.90, Result.Herbage[iDMD].Digestibility + 0.10);
                    if (Result.Herbage[iDMD].Biomass > 0.0)
                    {
                        Result.Herbage[iDMD].CrudeProtein = FChemData[iChem].dNitrogen_KgHa / FChemData[iChem].dMass_KgHa * GrazType.N2Protein;
                        Result.Herbage[iDMD].PhosContent = FChemData[iChem].dPhosphorus_KgHa / FChemData[iChem].dMass_KgHa;
                        Result.Herbage[iDMD].SulfContent = FChemData[iChem].dSulphur_KgHa / FChemData[iChem].dMass_KgHa;
                        Result.Herbage[iDMD].AshAlkalinity = FChemData[iChem].dAshAlk_MolHa / FChemData[iChem].dMass_KgHa;
                    }
                    Result.Herbage[iDMD].HeightRatio = GrazType.REF_HERBAGE_BD / dBulkDensity;
                    if (FIsGreen)
                        Result.TotalGreen = Result.TotalGreen + Result.Herbage[iDMD].Biomass;
                    else
                        Result.TotalDead = Result.TotalDead + Result.Herbage[iDMD].Biomass;

                    this.dHerbageDMDFract[iDMD] = Result.Herbage[iDMD].Biomass; // for later division by the total for the DMD class
                }

                populateHerbageType(ref Result);
            }

            // Seed pools: not permitted
            else if ((FSeedType == GrazType.UNRIPE) || (FSeedType == GrazType.RIPE))
                throw new Exception("Chemistry \"DMDnn\" may not be used when the organ is seeds, heads or ears");

            return Result;
        }
예제 #4
0
파일: stock_padd.cs 프로젝트: hol353/ApsimX
        /// <summary>
        /// The providing forage component is specifying a quantity of forage with
        ///   a known average digestibility, and is signalling that *this* component
        ///   should distribute the forage across the TAnimalGroup DMD pools
        /// </summary>
        /// <param name="dAvailPropn"></param>
        /// <param name="dBulkDensity"></param>
        /// <returns></returns>
        public GrazType.TGrazingInputs convertChemistry_MeanDMD(double dAvailPropn, double dBulkDensity)
        {
            const int DDM_MEAN = 0;
            const int IDM_MEAN = 1;

            double dTotalDM;
            double dMeanDMD;
            double[] dDMDPropns = new double[GrazType.DigClassNo + 1];
            int iDMD;

            GrazType.TGrazingInputs Result = new GrazType.TGrazingInputs();

            for (iDMD = 1; iDMD <= GrazType.DigClassNo; iDMD++)
                Result.Herbage[iDMD].HeightRatio = 1.0;

            this.dHerbageDMDFract = new double[GrazType.DigClassNo + 1];
            this.dSeedRipeFract = new double[3];

            dTotalDM = FChemData[DDM_MEAN].dMass_KgHa + FChemData[IDM_MEAN].dMass_KgHa;

            // Leaf & stem pools
            if ((FSeedType == NOT_SEED) && (dTotalDM > 0.0))
            {
                dMeanDMD = FChemData[DDM_MEAN].dMass_KgHa / dTotalDM;
                if (FIsGreen)
                    dDMDPropns = this.calcDMDDistribution(dMeanDMD, 0.85, 0.45);    // FIX ME: the DMD ranges should be organ- and development-specific values
                else
                    dDMDPropns = this.calcDMDDistribution(dMeanDMD, 0.70, 0.30);

                for (iDMD = 1; iDMD <= GrazType.DigClassNo; iDMD++)
                {
                    populateIntakeRecord(ref Result.Herbage[iDMD], iDMD, (dDMDPropns[iDMD] == 1.0),
                                          dTotalDM, dMeanDMD, dAvailPropn * dDMDPropns[iDMD],
                                          FChemData[DDM_MEAN].dNitrogen_KgHa, FChemData[IDM_MEAN].dNitrogen_KgHa,
                                          FChemData[DDM_MEAN].dPhosphorus_KgHa, FChemData[IDM_MEAN].dPhosphorus_KgHa,
                                          FChemData[DDM_MEAN].dSulphur_KgHa, FChemData[IDM_MEAN].dSulphur_KgHa,
                                          FChemData[DDM_MEAN].dAshAlk_MolHa, FChemData[IDM_MEAN].dAshAlk_MolHa,
                                          dBulkDensity);

                    if (FIsGreen)
                        Result.TotalGreen = Result.TotalGreen + Result.Herbage[iDMD].Biomass;
                    else
                        Result.TotalDead = Result.TotalDead + Result.Herbage[iDMD].Biomass;

                    this.dHerbageDMDFract[iDMD] = Result.Herbage[iDMD].Biomass; // for later division by the total for the DMD class
                }  // for iDMD = 1 to DigClassNo

                populateHerbageType(ref Result);
            }

            // Seed pools
            else if (((FSeedType == GrazType.UNRIPE) || (FSeedType == GrazType.RIPE)) && (dTotalDM > 0.0))
            {
                populateSeedRecord(ref Result, dAvailPropn, DDM_MEAN, DDM_MEAN);
                this.dSeedRipeFract[FSeedType] = Result.Seeds[1, FSeedType].Biomass; // for later division by the total for the seed ripeness class
            }
            return Result;
        }
예제 #5
0
파일: stock_padd.cs 프로젝트: hol353/ApsimX
        /// <summary>
        /// * The providing forage component is specifying a quantity of forage with
        ///   a single digestibility, as part of a distribution of digestibilities
        ///   *provided by the source component*.
        /// * We therefore calculate the DMD and then place all foage mass in the
        ///   TAnimalGroup DMD class that contains that DMD value
        /// </summary>
        /// <param name="dAvailPropn"></param>
        /// <param name="dBulkDensity"></param>
        /// <returns></returns>
        public GrazType.TGrazingInputs convertChemistry_DigInDig(double dAvailPropn, double dBulkDensity)
        {
            const int DDM = 0;
            const int IDM = 1;

            double dTotalDM;
            double dMeanDMD;
            int iDMD;

            GrazType.TGrazingInputs Result = new GrazType.TGrazingInputs();
            GrazType.zeroGrazingInputs(ref Result);
            for (iDMD = 1; iDMD <= GrazType.DigClassNo; iDMD++)
                Result.Herbage[iDMD].HeightRatio = 1.0;

            this.dHerbageDMDFract = new double[GrazType.DigClassNo + 1];
            this.dSeedRipeFract = new double[3];

            dTotalDM = this.FChemData[DDM].dMass_KgHa + this.FChemData[IDM].dMass_KgHa;
            // Leaf & stem pools
            if ((FSeedType == NOT_SEED) && (dTotalDM > 0.0))
            {
                dMeanDMD = this.FChemData[DDM].dMass_KgHa / dTotalDM;
                iDMD = Convert.ToInt32(Math.Min(1, Math.Max(1 + Math.Truncate((HIGHEST_DMD - dMeanDMD) / CLASSWIDTH), GrazType.DigClassNo)));  // TODO: may need testing

                populateIntakeRecord(ref Result.Herbage[iDMD], iDMD, true,
                                      dTotalDM, dMeanDMD, dAvailPropn,
                                      this.FChemData[DDM].dNitrogen_KgHa, this.FChemData[IDM].dNitrogen_KgHa,
                                      this.FChemData[DDM].dPhosphorus_KgHa, this.FChemData[IDM].dPhosphorus_KgHa,
                                      this.FChemData[DDM].dSulphur_KgHa, this.FChemData[IDM].dSulphur_KgHa,
                                      this.FChemData[DDM].dAshAlk_MolHa, this.FChemData[IDM].dAshAlk_MolHa,
                                      dBulkDensity);

                if (FIsGreen)
                    Result.TotalGreen = Result.Herbage[iDMD].Biomass;
                else
                    Result.TotalDead = Result.Herbage[iDMD].Biomass;

                populateHerbageType(ref Result);

                this.dHerbageDMDFract[iDMD] = Result.Herbage[iDMD].Biomass; // for later division by the total for the DMD class
            }

            // Seed pools
            else if (((FSeedType == GrazType.UNRIPE) || (FSeedType == GrazType.RIPE)) && (dTotalDM > 0.0))
            {
                populateSeedRecord(ref Result, dAvailPropn, DDM, IDM);
                this.dSeedRipeFract[FSeedType] = Result.Seeds[1, FSeedType].Biomass; // for later division by the total for the seed ripeness class
            }
            return Result;
        }
예제 #6
0
파일: stock_padd.cs 프로젝트: hol353/ApsimX
        /// <summary>
        /// 
        /// </summary>
        /// <param name="aValue"></param>
        /// <returns></returns>
        private GrazType.TGrazingInputs Value2GrazingInputs(TTypedValue aValue)
        {
            double fTotalDM;
            int Idx;

            GrazType.TGrazingInputs Result = new GrazType.TGrazingInputs();
            GrazType.zeroGrazingInputs(ref Result);

            for (Idx = 1; Idx <= Math.Min(GrazType.DigClassNo, aValue.item(1).count()); Idx++)      // Item[1]="herbage"                     
                Value2IntakeRecord(aValue.item(1).item((uint)Idx), ref Result.Herbage[Idx]);

            fTotalDM = 0.0;
            for (Idx = 1; Idx <= GrazType.DigClassNo; Idx++)
                fTotalDM = fTotalDM + Result.Herbage[Idx].Biomass;
            Result.TotalGreen = fTotalDM * aValue.item(2).asDouble();                               // Item[2]="propn_green"                 
            Result.TotalDead = fTotalDM - Result.TotalGreen;

            Result.LegumePropn = aValue.item(3).asDouble();                                         // Item[3]="legume"                      
            Result.SelectFactor = aValue.item(4).asDouble();                                        // Item[4]="select_factor"               

            for (Idx = 1; Idx <= Math.Min(2, aValue.item(5).count()); Idx++)                        // Item[5]="seed"                        
            {
                Value2IntakeRecord(aValue.item(5).item((uint)Idx), ref Result.Seeds[1, Idx]);
                Result.SeedClass[1, Idx] = aValue.item(6).item((uint)Idx).asInteger();              // Item[6]="seed_class"                  
            }
            return Result;
        }
예제 #7
0
파일: stock_intf.cs 프로젝트: hol353/ApsimX
        private double getPaddockRank(TPaddockInfo aPaddock,
                                      TAnimalGroup aGroup)
        {
            double Result;
            GrazType.TGrazingInputs forageInputs;
            GrazType.TGrazingInputs paddockInputs;
            double[] fHerbageRI = new double[GrazType.DigClassNo + 1];
            double[,] fSeedRI = new double[GrazType.MaxPlantSpp + 1, GrazType.RIPE + 1];
            double fDummy = 0.0;
            int Jdx;
            int iClass;

            aGroup.PaddSteep = aPaddock.Steepness;
            aGroup.WaterLogging = aPaddock.fWaterlog;
            aGroup.RationFed.Assign(aPaddock.SuppInPadd);
            aGroup.RationFed.TotalAmount = 0.0;                                        // No supplementary feed here

            paddockInputs = new GrazType.TGrazingInputs();
            for (Jdx = 0; Jdx <= aPaddock.Forages.Count() - 1; Jdx++)
            {
                forageInputs = aPaddock.Forages.byIndex(Jdx).availForage(aGroup.Genotype.GrazeC[17],
                                                                           aGroup.Genotype.GrazeC[18],
                                                                           aGroup.Genotype.GrazeC[19]);
                GrazType.addGrazingInputs(Jdx + 1, forageInputs, ref paddockInputs);
            }
            aGroup.Herbage = paddockInputs;

            aGroup.CalculateRelIntake(aGroup, 1.0, false, 1.0, ref fHerbageRI, ref fSeedRI, ref fDummy);

            Result = 0.0;
            for (iClass = 1; iClass <= GrazType.DigClassNo; iClass++)                                             // Function result is DMDI/pot. intake
                Result = Result + fHerbageRI[iClass] * GrazType.ClassDig[iClass];
            return Result;
        }