コード例 #1
0
ファイル: MicroClimate.cs プロジェクト: oseledets/ApsimX
 /// <summary>Perform the overall Canopy Energy Balance</summary>
 private void BalanceCanopyEnergy(MicroClimateZone MCZone)
 {
     ShortWaveRadiation(MCZone);
     EnergyTerms(MCZone);
     LongWaveRadiation(MCZone);
     SoilHeatRadiation(MCZone);
 }
コード例 #2
0
ファイル: MicroClimate.cs プロジェクト: oseledets/ApsimX
        /// <summary>Calculate the interception loss of water from the canopy</summary>
        private void CalculateInterception(MicroClimateZone MCZone)
        {
            double sumLAI    = 0.0;
            double sumLAItot = 0.0;

            for (int i = 0; i <= MCZone.numLayers - 1; i++)
            {
                for (int j = 0; j <= MCZone.Canopies.Count - 1; j++)
                {
                    sumLAI    += MCZone.Canopies[j].LAI[i];
                    sumLAItot += MCZone.Canopies[j].LAItot[i];
                }
            }

            double totalInterception = a_interception * Math.Pow(weather.Rain, b_interception) + c_interception * sumLAItot + d_interception;

            totalInterception = Math.Max(0.0, Math.Min(0.99 * weather.Rain, totalInterception));

            for (int i = 0; i <= MCZone.numLayers - 1; i++)
            {
                for (int j = 0; j <= MCZone.Canopies.Count - 1; j++)
                {
                    MCZone.Canopies[j].interception[i] = MathUtilities.Divide(MCZone.Canopies[j].LAI[i], sumLAI, 0.0) * totalInterception;
                }
            }
        }
コード例 #3
0
ファイル: MicroClimate.cs プロジェクト: oseledets/ApsimX
 /// <summary>Calculate the aerodynamic decoupling for system compartments</summary>
 private void CalculateOmega(MicroClimateZone MCZone)
 {
     for (int i = 0; i <= MCZone.numLayers - 1; i++)
     {
         for (int j = 0; j <= MCZone.Canopies.Count - 1; j++)
         {
             MCZone.Canopies[j].Omega[i] = CalcOmega(weather.MinT, weather.MaxT, weather.AirPressure, MCZone.Canopies[j].Ga[i], MCZone.Canopies[j].Gc[i]);
         }
     }
 }
コード例 #4
0
        /// <summary>
        /// This model is for strip crops where there is verticle overlap of the shortest and tallest crops canopy but no horizontal overlap
        /// </summary>
        /// <param name="tallest"></param>
        /// <param name="shortest"></param>
        private void DoStripCropShortWaveRadiation(ref MicroClimateZone tallest, ref MicroClimateZone shortest)
        {
            if (MathUtilities.Sum(tallest.DeltaZ) > 0)                                               // Don't perform calculations if layers are empty
            {
                double Ht          = MathUtilities.Sum(tallest.DeltaZ);                              // Height of tallest strip
                double Hs          = MathUtilities.Sum(shortest.DeltaZ);                             // Height of shortest strip
                double Wt          = (tallest.Zone as Zones.RectangularZone).Width;                  // Width of tallest strip
                double Ws          = (shortest.Zone as Zones.RectangularZone).Width;                 // Width of shortest strip
                double Ft          = Wt / (Wt + Ws);                                                 // Fraction of space in tallest strip
                double Fs          = Ws / (Wt + Ws);                                                 // Fraction of space in the shortest strip
                double LAIt        = MathUtilities.Sum(tallest.LAItotsum);                           // LAI of tallest strip
                double LAIs        = MathUtilities.Sum(shortest.LAItotsum);                          // LAI of shortest strip
                double Kt          = tallest.Canopies[0].Ktot;                                       // Extinction Coefficient of the tallest strip
                double Ks          = shortest.Canopies[0].Ktot;                                      // Extinction Coefficient of the shortest strip
                double Httop       = Ht - Hs;                                                        // Height of the top layer in tallest strip (ie distance from top of shortest to top of tallest)
                double LAIttop     = Httop / Ht * LAIt;                                              // LAI of the top layer of the tallest strip (ie LAI in tallest strip above height of shortest strip)
                double LAItbot     = LAIt - LAIttop;                                                 // LAI of the bottom layer of the tallest strip (ie LAI in tallest strip below height of the shortest strip)
                double LAIttophomo = Ft * LAIttop;                                                   // LAI of top layer of tallest strip if spread homogeneously across all of the space
                double Ftblack     = (Math.Sqrt(Math.Pow(Httop, 2) + Math.Pow(Wt, 2)) - Httop) / Wt; // View factor for top layer of tallest strip
                double Fsblack     = (Math.Sqrt(Math.Pow(Httop, 2) + Math.Pow(Ws, 2)) - Httop) / Ws; // View factor for top layer of shortest strip
                double Tt          = Ft * (Ftblack * Math.Exp(-Kt * LAIttop)
                                           + Ft * (1 - Ftblack) * Math.Exp(-Kt * LAIttophomo))
                                     + Fs * Ft * (1 - Fsblack) * Math.Exp(-Kt * LAIttophomo); //  Transmission of light to bottom of top layer in tallest strip
                double Ts = Fs * (Fsblack + Fs * (1 - Fsblack) * Math.Exp(-Kt * LAIttophomo))
                            + Ft * Fs * ((1 - Ftblack) * Math.Exp(-Kt * LAIttophomo));        //  Transmission of light to bottom of top layer in shortest strip
                double Intttop            = 1 - Tt - Ts;                                      // Interception by the top layer of the tallest strip (ie light intercepted in tallest strip above height of shortest strip)
                double Inttbot            = (Tt * (1 - Math.Exp(-Kt * LAItbot)));             // Interception by the bottom layer of the tallest strip
                double Soilt              = (Tt * (Math.Exp(-Kt * LAItbot)));                 // Transmission to the soil below tallest strip
                double Ints               = Ts * (1 - Math.Exp(-Ks * LAIs));                  // Interception by the shortest strip
                double Soils              = Ts * (Math.Exp(-Ks * LAIs));                      // Transmission to the soil below shortest strip
                double EnergyBalanceCheck = Intttop + Inttbot + Soilt + Ints + Soils;         // Sum of all light fractions (should equal 1)
                if (Math.Abs(1 - EnergyBalanceCheck) > 0.001)
                {
                    throw (new Exception("Energy Balance not maintained in strip crop light interception model"));
                }

                //tallest.Canopies[0].Rs[0] = weather.Radn * (Intttop + Inttbot) / Ft;
                //tallest.SurfaceRs = weather.Radn * Soilt / Ft;
                CalculateLayeredShortWaveRadiation(tallest, weather.Radn * (Intttop + Inttbot) / Ft);

                // if (shortest.Canopies[0].Rs != null)
                //     if (shortest.Canopies[0].Rs.Length > 0)
                //         shortest.Canopies[0].Rs[0] = weather.Radn * Ints / Fs;
                //shortest.SurfaceRs = weather.Radn * Soils / Fs;
                CalculateLayeredShortWaveRadiation(shortest, weather.Radn * Ints / Fs);
            }
            else
            {
                //tallest.Canopies[0].Rs[0] =0;
                tallest.SurfaceRs = weather.Radn;
                //shortest.Canopies[0].Rs[0] = 0;
                shortest.SurfaceRs = weather.Radn;
            }
        }
コード例 #5
0
ファイル: MicroClimate.cs プロジェクト: oseledets/ApsimX
        /// <summary>
        /// Create a new MicroClimateZone for a given simulation zone
        /// </summary>
        /// <param name="newZone"></param>
        private void CreateMCZone(Zone newZone)
        {
            MicroClimateZone myZone = new MicroClimateZone();

            myZone.zone = newZone;
            myZone.Reset();
            foreach (ICanopy canopy in Apsim.ChildrenRecursively(newZone, typeof(ICanopy)))
            {
                myZone.Canopies.Add(new CanopyType(canopy));
            }
            microClimateZones.Add(myZone);
        }
コード例 #6
0
ファイル: MicroClimate.cs プロジェクト: oseledets/ApsimX
        /// <summary>Calculate the aerodynamic conductance for system compartments</summary>
        private void CalculateGa(MicroClimateZone MCZone)
        {
            double sumDeltaZ = MathUtilities.Sum(MCZone.DeltaZ);
            double sumLAI    = MathUtilities.Sum(MCZone.LAItotsum);
            double totalGa   = AerodynamicConductanceFAO(weather.Wind, refheight, sumDeltaZ, sumLAI);

            for (int i = 0; i <= MCZone.numLayers - 1; i++)
            {
                for (int j = 0; j <= MCZone.Canopies.Count - 1; j++)
                {
                    MCZone.Canopies[j].Ga[i] = totalGa * MathUtilities.Divide(MCZone.Canopies[j].Rs[i], MCZone.sumRs, 0.0);
                }
            }
        }
コード例 #7
0
        /// <summary>
        /// Calculate Radiation loss to soil heating
        /// </summary>
        private void SoilHeatRadiation(MicroClimateZone MCZone)
        {
            double radnint = MCZone.sumRs;   // Intercepted SW radiation

            MCZone.soil_heat = SoilHeatFlux(weather.Radn, radnint, soil_heat_flux_fraction);

            // SoilHeat balance Proportional to Short Wave Balance
            // ====================================================
            for (int i = MCZone.numLayers - 1; i >= 0; i += -1)
            {
                for (int j = 0; j <= MCZone.Canopies.Count - 1; j++)
                {
                    MCZone.Canopies[j].Rsoil[i] = MathUtilities.Divide(MCZone.Canopies[j].Rs[i], weather.Radn, 0.0) * MCZone.soil_heat;
                }
            }
        }
コード例 #8
0
        /// <summary>
        /// Calculates interception of short wave by canopy compartments
        /// </summary>
        private void CalculateShortWaveRadiation(MicroClimateZone MCZone)
        {
            // Perform Top-Down Light Balance
            // ==============================
            double Rin  = weather.Radn;
            double Rint = 0;

            for (int i = MCZone.numLayers - 1; i >= 0; i += -1)
            {
                Rint = Rin * (1.0 - Math.Exp(-MCZone.layerKtot[i] * MCZone.LAItotsum[i]));
                for (int j = 0; j <= MCZone.Canopies.Count - 1; j++)
                {
                    MCZone.Canopies[j].Rs[i] = Rint * MathUtilities.Divide(MCZone.Canopies[j].Ftot[i] * MCZone.Canopies[j].Ktot, MCZone.layerKtot[i], 0.0);
                }
                Rin -= Rint;
            }
        }
コード例 #9
0
ファイル: MicroClimate.cs プロジェクト: oseledets/ApsimX
        /// <summary>Calculate the canopy conductance for system compartments</summary>
        private void CalculateGc(MicroClimateZone MCZone)
        {
            double Rin = weather.Radn;

            for (int i = MCZone.numLayers - 1; i >= 0; i += -1)
            {
                double Rflux = Rin * 1000000.0 / (dayLength * hr2s) * (1.0 - MCZone._albedo);
                double Rint  = 0.0;

                for (int j = 0; j <= MCZone.Canopies.Count - 1; j++)
                {
                    MCZone.Canopies[j].Gc[i] = CanopyConductance(MCZone.Canopies[j].Canopy.Gsmax, MCZone.Canopies[j].Canopy.R50, MCZone.Canopies[j].Canopy.FRGR, MCZone.Canopies[j].Fgreen[i], MCZone.layerKtot[i], MCZone.LAItotsum[i], Rflux);
                    Rint += MCZone.Canopies[j].Rs[i];
                }
                // Calculate Rin for the next layer down
                Rin -= Rint;
            }
        }
コード例 #10
0
        /// <summary>
        /// Calculate Net Long Wave Radiation Balance
        /// </summary>
        private void LongWaveRadiation(MicroClimateZone MCZone)
        {
            double sunshineHours    = CalcSunshineHours(weather.Radn, dayLengthLight, weather.Latitude, Clock.Today.DayOfYear);
            double fractionClearSky = MathUtilities.Divide(sunshineHours, dayLengthLight, 0.0);
            double averageT         = CalcAverageT(weather.MinT, weather.MaxT);

            MCZone.NetLongWaveRadiation = LongWave(averageT, fractionClearSky, emissivity) * dayLength * hr2s / 1000000.0;             // W to MJ

            // Long Wave Balance Proportional to Short Wave Balance
            // ====================================================
            for (int i = MCZone.numLayers - 1; i >= 0; i += -1)
            {
                for (int j = 0; j <= MCZone.Canopies.Count - 1; j++)
                {
                    MCZone.Canopies[j].Rl[i] = MathUtilities.Divide(MCZone.Canopies[j].Rs[i], weather.Radn, 0.0) * MCZone.NetLongWaveRadiation;
                }
            }
        }
コード例 #11
0
        /// <summary>
        /// Calculate the overall system energy terms
        /// </summary>
        private void EnergyTerms(MicroClimateZone MCZone)
        {
            MCZone.sumRs   = 0.0;
            MCZone._albedo = 0.0;
            emissivity     = 0.0;

            for (int i = MCZone.numLayers - 1; i >= 0; i += -1)
            {
                for (int j = 0; j <= MCZone.Canopies.Count - 1; j++)
                {
                    MCZone._albedo += MathUtilities.Divide(MCZone.Canopies[j].Rs[i], weather.Radn, 0.0) * MCZone.Canopies[j].Canopy.Albedo;
                    emissivity     += MathUtilities.Divide(MCZone.Canopies[j].Rs[i], weather.Radn, 0.0) * Emissivity;
                    MCZone.sumRs   += MCZone.Canopies[j].Rs[i];
                }
            }

            MCZone._albedo += (1.0 - MathUtilities.Divide(MCZone.sumRs, weather.Radn, 0.0)) * soil_albedo;
            emissivity     += (1.0 - MathUtilities.Divide(MCZone.sumRs, weather.Radn, 0.0)) * soil_emissivity;
        }
コード例 #12
0
        /// <summary>
        /// Calculates interception of short wave by canopy compartments
        /// </summary>
        private void CalculateLayeredShortWaveRadiation(MicroClimateZone ZoneMC, double Rin)
        {
            // Perform Top-Down Light Balance
            // ==============================
            double Rint = 0;

            for (int i = ZoneMC.numLayers - 1; i >= 0; i += -1)
            {
                if (double.IsNaN(Rint))
                {
                    throw new Exception("Bad Radiation Value in Light partitioning");
                }
                Rint = Rin * (1.0 - Math.Exp(-ZoneMC.layerKtot[i] * ZoneMC.LAItotsum[i]));
                for (int j = 0; j <= ZoneMC.Canopies.Count - 1; j++)
                {
                    ZoneMC.Canopies[j].Rs[i] = Rint * MathUtilities.Divide(ZoneMC.Canopies[j].Ftot[i] * ZoneMC.Canopies[j].Ktot, ZoneMC.layerKtot[i], 0.0);
                }
                Rin -= Rint;
            }
            ZoneMC.SurfaceRs = Rin;
        }
コード例 #13
0
ファイル: MicroClimate.cs プロジェクト: oseledets/ApsimX
 /// <summary>Send an energy balance event</summary>
 private void SetCanopyEnergyTerms(MicroClimateZone MCZone)
 {
     for (int j = 0; j <= MCZone.Canopies.Count - 1; j++)
     {
         if (MCZone.Canopies[j].Canopy != null)
         {
             CanopyEnergyBalanceInterceptionlayerType[] lightProfile = new CanopyEnergyBalanceInterceptionlayerType[MCZone.numLayers];
             double totalPotentialEp  = 0;
             double totalInterception = 0.0;
             for (int i = 0; i <= MCZone.numLayers - 1; i++)
             {
                 lightProfile[i]           = new CanopyEnergyBalanceInterceptionlayerType();
                 lightProfile[i].thickness = MCZone.DeltaZ[i];
                 lightProfile[i].amount    = MCZone.Canopies[j].Rs[i] * MCZone.RadnGreenFraction(j);
                 totalPotentialEp         += MCZone.Canopies[j].PET[i];
                 totalInterception        += MCZone.Canopies[j].interception[i];
             }
             MCZone.Canopies[j].Canopy.PotentialEP  = totalPotentialEp;
             MCZone.Canopies[j].Canopy.LightProfile = lightProfile;
         }
     }
 }
コード例 #14
0
ファイル: MicroClimate.cs プロジェクト: oseledets/ApsimX
        /// <summary>Calculate the Penman-Monteith water demand</summary>
        private void CalculatePM(MicroClimateZone MCZone)
        {
            // zero a few things, and sum a few others
            double sumRl           = 0.0;
            double sumRsoil        = 0.0;
            double sumInterception = 0.0;
            double freeEvapGa      = 0.0;

            for (int j = 0; j <= MCZone.Canopies.Count - 1; j++)
            {
                sumRl           += MathUtilities.Sum(MCZone.Canopies[j].Rl);
                sumRsoil        += MathUtilities.Sum(MCZone.Canopies[j].Rsoil);
                sumInterception += MathUtilities.Sum(MCZone.Canopies[j].interception);
                freeEvapGa      += MathUtilities.Sum(MCZone.Canopies[j].Ga);
            }

            double netRadiation = ((1.0 - MCZone._albedo) * MCZone.sumRs + sumRl + sumRsoil) * 1000000.0;   // MJ/J

            netRadiation = Math.Max(0.0, netRadiation);

            double freeEvapGc = freeEvapGa * 1000000.0; // infinite surface conductance
            double freeEvap   = CalcPenmanMonteith(netRadiation, weather.MinT, weather.MaxT, weather.VP, weather.AirPressure, dayLength, freeEvapGa, freeEvapGc);

            MCZone.dryleaffraction = 1.0 - MathUtilities.Divide(sumInterception * (1.0 - night_interception_fraction), freeEvap, 0.0);
            MCZone.dryleaffraction = Math.Max(0.0, MCZone.dryleaffraction);

            for (int i = 0; i <= MCZone.numLayers - 1; i++)
            {
                for (int j = 0; j <= MCZone.Canopies.Count - 1; j++)
                {
                    netRadiation = 1000000.0 * ((1.0 - MCZone._albedo) * MCZone.Canopies[j].Rs[i] + MCZone.Canopies[j].Rl[i] + MCZone.Canopies[j].Rsoil[i]);
                    netRadiation = Math.Max(0.0, netRadiation);

                    MCZone.Canopies[j].PETr[i] = CalcPETr(netRadiation * MCZone.dryleaffraction, weather.MinT, weather.MaxT, weather.AirPressure, MCZone.Canopies[j].Ga[i], MCZone.Canopies[j].Gc[i]);
                    MCZone.Canopies[j].PETa[i] = CalcPETa(weather.MinT, weather.MaxT, weather.VP, weather.AirPressure, dayLength * MCZone.dryleaffraction, MCZone.Canopies[j].Ga[i], MCZone.Canopies[j].Gc[i]);
                    MCZone.Canopies[j].PET[i]  = MCZone.Canopies[j].PETr[i] + MCZone.Canopies[j].PETa[i];
                }
            }
        }
コード例 #15
0
        /// <summary>
        /// This model is for tree crops where there is no vertical overlap of the shortest and tallest canopy but the tallest canopy can overlap the shortest horzontally
        /// </summary>
        /// <param name="tree"></param>
        /// <param name="alley"></param>
        private void DoTreeRowCropShortWaveRadiation(ref MicroClimateZone tree, ref MicroClimateZone alley)
        {
            if (MathUtilities.Sum(tree.DeltaZ) > 0)          // Don't perform calculations if layers are empty
            {
                double Ht  = MathUtilities.Sum(tree.DeltaZ); // Height of tree canopy
                double CDt = 0;                              //tree.Canopies[0].Canopy.Depth / 1000;         // Depth of tree canopy
                foreach (MicroClimateCanopy c in tree.Canopies)
                {
                    if (c.Canopy.Depth < c.Canopy.Height)
                    {
                        if (CDt > 0.0)
                        {
                            throw new Exception("Can't have two tree canopies");
                        }
                        else
                        {
                            CDt = c.Canopy.Depth / 1000;
                        }
                    }
                }
                double CBHt = Ht - CDt;                                    // Base hight of the tree canopy
                double Ha   = MathUtilities.Sum(alley.DeltaZ);             // Height of alley canopy
                if ((Ha > CBHt) & (tree.DeltaZ.Length > 1))
                {
                    throw (new Exception("Height of the alley canopy must not exceed the base height of the tree canopy"));
                }
                double Wt  = (tree.Zone as Zones.RectangularZone).Width;  // Width of tree zone
                double Wa  = (alley.Zone as Zones.RectangularZone).Width; // Width of alley zone
                double CWt = 0;                                           //Math.Min(tree.Canopies[0].Canopy.Width / 1000, (Wt + Wa));// Width of the tree canopy
                foreach (MicroClimateCanopy c in tree.Canopies)
                {
                    if (c.Canopy.Depth < c.Canopy.Height)
                    {
                        if (CWt > 0.0)
                        {
                            throw new Exception("Can't have two tree canopies");
                        }
                        else
                        {
                            CWt = Math.Min(c.Canopy.Width / 1000, (Wt + Wa));
                        }
                    }
                }
                double WaOl     = Math.Min(CWt - Wt, Wa);                                         // Width of tree canopy that overlap the alley zone
                double WaOp     = Wa - WaOl;                                                      // Width of the open alley zone between tree canopies
                double Ft       = CWt / (Wt + Wa);                                                // Fraction of space in tree canopy
                double Fs       = WaOp / (Wt + Wa);                                               // Fraction of open space in the alley row
                double LAIt     = MathUtilities.Sum(tree.LAItotsum);                              // LAI of trees
                double LAIa     = MathUtilities.Sum(alley.LAItotsum);                             // LAI of alley crop
                double Kt       = tree.Canopies[0].Ktot;                                          // Extinction Coefficient of trees
                double Ka       = alley.Canopies[0].Ktot;                                         // Extinction Coefficient of alley crop
                double LAIthomo = Ft * LAIt;                                                      // LAI of trees if spread homogeneously across row and alley zones
                double Ftbla    = (Math.Sqrt(Math.Pow(CDt, 2) + Math.Pow(CWt, 2)) - CDt) / CWt;   // View factor for the tree canopy if a black body
                double Fabla    = (Math.Sqrt(Math.Pow(CDt, 2) + Math.Pow(WaOp, 2)) - CDt) / WaOp; // View factor for the gap between trees in alley if trees a black body
                if (WaOp == 0)
                {
                    Fabla = 0;
                }
                //All transmission and interception values below are a fraction of the total short wave radiation incident to both the tree and alley rows
                double Tt = Ft * (Ftbla * Math.Exp(-Kt * LAIt)
                                  + Ft * (1 - Ftbla) * Math.Exp(-Kt * LAIthomo))
                            + Fs * Ft * (1 - Fabla) * Math.Exp(-Kt * LAIthomo);   //  Transmission of light to the bottom of the tree canopy
                double Ta = Fs * (Fabla + Fs * (1 - Fabla) * Math.Exp(-Kt * LAIthomo))
                            + Ft * Fs * ((1 - Ftbla) * Math.Exp(-Kt * LAIthomo)); //  Transmission of light to the bottom of the gap in the tree canopy
                double It   = 1 - Tt - Ta;                                        // Interception by the trees
                double St   = Tt * Wt / CWt;                                      // Transmission to the soil in the tree zone
                double IaOl = Tt * WaOl / CWt * (1 - Math.Exp(-Ka * LAIa));       // Interception by the alley canopy below the overlap of the trees
                double IaOp = Ta * (1 - Math.Exp(-Ka * LAIa));                    // Interception by the alley canopy in the gaps between tree canopy
                double Ia   = IaOl + IaOp;                                        // Interception by the alley canopy
                double SaOl = Tt * WaOl / CWt * (Math.Exp(-Ka * LAIa));           // Transmission to the soil beneigth the alley canopy under the tree canopy
                double SaOp = Ta * (Math.Exp(-Ka * LAIa));                        // Transmission to the soil beneigth the alley canopy in the open
                double Sa   = SaOl + SaOp;                                        // Transmission to the soil beneight the alley
                double EnergyBalanceCheck = It + St + Ia + Sa;                    // Sum of all light fractions (should equal 1)
                if (Math.Abs(1 - EnergyBalanceCheck) > 0.001)
                {
                    throw (new Exception("Energy Balance not maintained in strip crop light interception model"));
                }

                Ft = (Wt) / (Wt + Wa);  // Remove overlap so scaling back to zone ground area works
                Fs = (Wa) / (Wt + Wa);  // Remove overlap so scaling back to zone ground area works

                CalculateLayeredShortWaveRadiation(tree, weather.Radn * It / Ft);

                CalculateLayeredShortWaveRadiation(alley, weather.Radn * Ia / Fs);
            }
            else
            {
                tree.SurfaceRs = weather.Radn;
                CalculateLayeredShortWaveRadiation(alley, weather.Radn);
            }
        }
コード例 #16
0
ファイル: MicroClimate.cs プロジェクト: chuankang/ApsimX
        /// <summary>
        /// This model is for strip crops where there is no verticle overlap of the shortest and tallest crops canopy but no horizontal overlap
        /// </summary>
        /// <param name="vine"></param>
        /// <param name="alley"></param>
        private void DoVineStripShortWaveRadiation(ref MicroClimateZone vine, ref MicroClimateZone alley)
        {
            if (MathUtilities.Sum(vine.DeltaZ) > 0)                 // Don't perform calculations if layers are empty
            {
                double Ht = MathUtilities.Sum(vine.DeltaZ);         // Height of tree canopy

                double CDt  = vine.Canopies[0].Canopy.Depth / 1000; // Depth of tree canopy
                double CBHt = Ht - CDt;                             // Base hight of the tree canopy
                double Ha   = MathUtilities.Sum(alley.DeltaZ);      // Height of alley canopy
                if ((Ha > CBHt) & (vine.DeltaZ.Length > 1))
                {
                    throw (new Exception("Height of the alley canopy must not exceed the base height of the tree canopy"));
                }

                double Wt  = (vine.Zone as Zones.RectangularZone).Width;   // Width of tree zone
                double Wa  = (alley.Zone as Zones.RectangularZone).Width;  // Width of alley zone
                double CWt = vine.Canopies[0].Canopy.Width / 1000;         // Width of the tree canopy

                double WaOl = (CWt + Wt) / 2;                              //adjusted Width of tree canopy, because the tree canopy is smaller than the strip width, so there would be a gap between alley and tree
                double WaOp = Wa + Wt - WaOl;                              // Width of the open alley zone between tree canopies
                double Ft   = WaOl / (Wt + Wa);                            // Fraction of space in tree canopy
                double Fs   = WaOp / (Wt + Wa);                            // Fraction of open space in the alley row


                double LAIt = MathUtilities.Sum(vine.LAItotsum);           // LAI of tallest strip
                double LAIs = MathUtilities.Sum(alley.LAItotsum);          // LAI of shortest strip

                double Kt = 0;                                             // Extinction Coefficient of the tallest strip
                if (vine.Canopies.Count > 0)                               // If it exists...
                {
                    Kt = vine.Canopies[0].Ktot;
                }
                double Ka = 0;                                               // Extinction Coefficient of the shortest strip
                if (alley.Canopies.Count > 0)                                // If it exists...
                {
                    Ka = alley.Canopies[0].Ktot;
                }

                double Httop    = Ht - Ha;                                                           // distance from top of shortest to top of tallest
                double LAIthomo = Ft * LAIt;                                                         // LAI of top layer of tallest strip if spread homogeneously across all of the space

                double Ftblack = (Math.Sqrt(Math.Pow(CDt, 2) + Math.Pow(WaOl, 2)) - CDt) / WaOl;     // View factor for top layer of tallest strip
                double Fsblack = (Math.Sqrt(Math.Pow(Httop, 2) + Math.Pow(WaOp, 2)) - Httop) / WaOp; // View factor for top layer of shortest strip
                double Tt      = Ft * (Ftblack * Math.Exp(-Kt * LAIt)
                                       + Ft * (1 - Ftblack) * Math.Exp(-Kt * LAIthomo))
                                 + Fs * Ft * (1 - Fsblack) * Math.Exp(-Kt * LAIthomo); //  Transmission of light to bottom of top layer in tallest strip
                double Ts = Fs * (Fsblack + Fs * (1 - Fsblack) * Math.Exp(-Kt * LAIthomo))
                            + Ft * Fs * ((1 - Ftblack) * Math.Exp(-Kt * LAIthomo));    //  Transmission of light to bottom of top layer in shortest strip
                double Intttop            = 1 - Tt - Ts;                               // Interception by the top layer of the tallest strip (ie light intercepted in tallest strip above height of shortest strip)
                double Inttbot            = (Tt * (1 - Math.Exp(-Kt * 0)));            // Interception by the bottom layer of the tallest strip
                double Soilt              = (Tt * (Math.Exp(-Kt * 0)));                // Transmission to the soil below tallest strip
                double Ints               = Ts * (1 - Math.Exp(-Ka * LAIs));           // Interception by the shortest strip
                double Soils              = Ts * (Math.Exp(-Ka * LAIs));               // Transmission to the soil below shortest strip
                double EnergyBalanceCheck = Intttop + Inttbot + Soilt + Ints + Soils;  // Sum of all light fractions (should equal 1)
                if (Math.Abs(1 - EnergyBalanceCheck) > 0.001)
                {
                    throw (new Exception("Energy Balance not maintained in strip crop light interception model"));
                }

                Ft = (Wt) / (Wt + Wa);  // Remove overlap so scaling back to zone ground area works
                Fs = (Wa) / (Wt + Wa);  // Remove overlap so scaling back to zone ground area works

                if (vine.Canopies.Count > 0)
                {
                    vine.Canopies[0].Rs[0] = weather.Radn * (Intttop + Inttbot) / Ft;
                }
                vine.SurfaceRs = weather.Radn * Soilt / Ft;

                if (alley.Canopies.Count > 0 && alley.Canopies[0].Rs != null)
                {
                    if (alley.Canopies[0].Rs.Length > 0)
                    {
                        alley.Canopies[0].Rs[0] = weather.Radn * Ints / Fs;
                    }
                }
                alley.SurfaceRs = weather.Radn * Soils / Fs;
            }
            else
            {
                //tallest.Canopies[0].Rs[0] =0;
                vine.SurfaceRs = weather.Radn;
                //shortest.Canopies[0].Rs[0] = 0;
                alley.SurfaceRs = weather.Radn;
            }
        }
コード例 #17
0
ファイル: MicroClimate.cs プロジェクト: peter-devoil/ApsimX
        /// <summary>
        /// This model is for strip crops where there is no verticle overlap of the shortest and tallest crops canopy but no horizontal overlap
        /// </summary>
        /// <param name="vine"></param>
        /// <param name="alley"></param>
        private void DoVineStripShortWaveRadiation(ref MicroClimateZone vine, ref MicroClimateZone alley)
        {
            if (vine.DeltaZ.Sum() > 0)                              // Don't perform calculations if layers are empty
            {
                double Ht = vine.DeltaZ.Sum();                      // Height of tree canopy

                double CDt  = vine.Canopies[0].Canopy.Depth / 1000; // Depth of tree canopy
                double CBHt = Ht - CDt;                             // Base hight of the tree canopy
                double Ha   = alley.DeltaZ.Sum();                   // Height of alley canopy
                if ((Ha > CBHt) & (vine.DeltaZ.Length > 1))
                {
                    throw (new Exception("Height of the alley canopy must not exceed the base height of the tree canopy"));
                }

                double Wt  = (vine.Zone as Zones.RectangularZone).Width;  // Width of tree zone
                double Wa  = (alley.Zone as Zones.RectangularZone).Width; // Width of alley zone
                double CWt = vine.Canopies[0].Canopy.Width / 1000;        // Width of the tree canopy

                double WaOp = Wa + Wt - CWt;                              // Width of the open alley zone between tree canopies
                double Ft   = CWt / (Wt + Wa);                            // Fraction of space in tree canopy
                double Fs   = WaOp / (Wt + Wa);                           // Fraction of open space in the alley row


                double LAIt = vine.LAItotsum.Sum() * Wt / CWt;   // adjusting the LAI of tallest strip based on new width
                double LAIs = alley.LAItotsum.Sum() * Wa / WaOp; // adjusting the LAI of shortest strip based on new width

                double Kt = 0;                                   // Extinction Coefficient of the tallest strip
                if (vine.Canopies.Count > 0 & LAIt > 0)          // If it exists...
                {
                    Kt = vine.Canopies[0].Ktot;
                }
                double Ka = 0;                                                // Extinction Coefficient of the shortest strip
                if (alley.Canopies.Count > 0 & LAIs > 0)                      // If it exists...
                {
                    Ka = alley.Canopies[0].Ktot;
                }

                double Httop    = Ht - Ha;                                  // distance from top of shortest to top of tallest
                double LAIthomo = Ft * LAIt;                                // LAI of top layer of tallest strip if spread homogeneously across all of the space

                double fhomo  = 1 - Math.Exp(-Kt * LAIthomo);
                double fcompr = (1 - Math.Exp(-Kt * LAIt)) * CWt / WaOp;

                double IPblackt = (Math.Sqrt(Math.Pow(CDt, 2) + Math.Pow(WaOp, 2)) - CDt) / WaOp;

                double IRblackt = (Math.Sqrt(Math.Pow(CDt, 2) + Math.Pow(CWt, 2)) - CDt) / CWt;  // View factor for top layer of tallest strip

                double SPt = IPblackt + (1 - IPblackt) * Math.Exp(-Kt * LAIthomo);
                double SRt = IRblackt * Math.Exp(-Kt * LAIt) +
                             (1 - IRblackt) * Math.Exp(-Kt * LAIthomo);  // Transmission of light to bottom of top layer in tallest strip
                double W = 0;
                if (vine.Canopies.Count > 0 & LAIt > 0 & Kt > 0)         // If it exists...
                {
                    W = (SPt - SRt) / (1 - Math.Exp(-Kt * LAIt));
                }

                double ftop = fhomo * (1 - W) + fcompr * W;              // light interception by the vine row

                //use different height and LAI distribution for calculating the light penetrate to the interrow
                //this is for accounting the effect of trunk, cordon, and post that shading on the interrow

                double IPblackb = (Math.Sqrt(Math.Pow(Httop, 2) + Math.Pow(WaOp, 2)) - Httop) / WaOp; //bottom part

                double IRblackb = (Math.Sqrt(Math.Pow(Httop, 2) + Math.Pow(CWt, 2)) - Httop) / CWt;   // View factor for top layer of tallest strip

                double SPb = IPblackb + (1 - IPblackb) * Math.Exp(-Kt * LAIthomo);
                double SRb = IRblackb * Math.Exp(-Kt * LAIt) +
                             (1 - IRblackb) * Math.Exp(-Kt * LAIthomo); //  Transmission of light to bottom of top layer in tallest strip
                //double Wb = (SPt - SRt) / (1 - Math.Exp(-Kt * LAIt));

                //double fb = fhomo * (1 - W) + fcompr * W;  //light interception by the vine row

                double Soilt = SRb * Ft;                              // Transmission to the soil below tallest strip

                double Intttop = ftop;                                // Interception by the top layer of the tallest strip (ie light intercepted in tallest strip above height of shortest strip)

                double Ints  = SPb * (1 - Math.Exp(-Ka * LAIs)) * Fs; // Interception by the shortest strip
                double Soils = SPb * (Math.Exp(-Ka * LAIs)) * Fs;     // Transmission to the soil below shortest strip

                Ft = (Wt) / (Wt + Wa);                                // Scaling back to zone ground area works
                Fs = (Wa) / (Wt + Wa);                                // Scaling back to zone ground area works

                // Perform Top-Down Light Balance for tree zone
                // ==============================
                double Rint = 0;
                double Rin  = weather.Radn * Intttop / Ft;
                for (int i = vine.numLayers - 1; i >= 0; i += -1)
                {
                    if (double.IsNaN(Rint))
                    {
                        throw new Exception("Bad Radiation Value in Light partitioning");
                    }
                    Rint = Rin;
                    for (int j = 0; j <= vine.Canopies.Count - 1; j++)
                    {
                        vine.Canopies[j].Rs[i] = Rint * MathUtilities.Divide(vine.Canopies[j].Ftot[i] * vine.Canopies[j].Ktot, vine.layerKtot[i], 0.0);
                    }
                    Rin -= Rint;
                }
                vine.SurfaceRs = weather.Radn * Soilt / Ft;

                // Perform Top-Down Light Balance for alley zone
                // ==============================
                Rint = 0;
                Rin  = weather.Radn * Ints / Fs;
                for (int i = alley.numLayers - 1; i >= 0; i += -1)
                {
                    if (double.IsNaN(Rint))
                    {
                        throw new Exception("Bad Radiation Value in Light partitioning");
                    }
                    Rint = Rin;
                    for (int j = 0; j <= alley.Canopies.Count - 1; j++)
                    {
                        alley.Canopies[j].Rs[i] = Rint * MathUtilities.Divide(alley.Canopies[j].Ftot[i] * alley.Canopies[j].Ktot, alley.layerKtot[i], 0.0);
                    }
                    Rin -= Rint;
                }
                alley.SurfaceRs = weather.Radn * Soils / Fs;
            }
            else
            {
                //tallest.Canopies[0].Rs[0] =0;
                vine.SurfaceRs = weather.Radn;
                //shortest.Canopies[0].Rs[0] = 0;
                alley.SurfaceRs = weather.Radn;
            }
        }