Example #1
0
        public void TestUnsaturatedFlow()
        {
            SoilModel soil = new SoilModel();

            APSIM.Shared.Soils.Soil soilProperties = Setup();
            APSIMReadySoil.Create(soilProperties);

            UnsaturatedFlowModel unsaturatedFlow = new UnsaturatedFlowModel();

            SetLink(soil, "properties", soilProperties);
            SetLink(unsaturatedFlow, "soil", soil);

            unsaturatedFlow.DiffusConst = 88;
            unsaturatedFlow.DiffusSlope = 35.4;

            // Profile at DUL.
            soil.Water = MathUtilities.Multiply(soilProperties.Water.DUL, soilProperties.Water.Thickness);
            double[] flow = unsaturatedFlow.Values;
            Assert.IsTrue(MathUtilities.AreEqual(flow, new double[] { 0, 0, 0, 0, 0, 0 }));

            // Profile at SAT.
            soil.Water = MathUtilities.Multiply(soilProperties.Water.SAT, soilProperties.Water.Thickness);
            flow       = unsaturatedFlow.Values;
            Assert.IsTrue(MathUtilities.AreEqual(flow, new double[] { 0, 0, 0, 0, 0, 0 }));

            // Force some unsaturated flow by reducing the water to 0.8 of SAT.
            soil.Water = MathUtilities.Multiply_Value(soil.Water, 0.8);
            flow       = unsaturatedFlow.Values;
            Assert.IsTrue(MathUtilities.AreEqual(flow, new double[] { 0.52148, -0.38359, -0.16771, -0.07481, 0, 0 }));
        }
Example #2
0
        public void TestPredictedCrops()
        {
            APSIM.Shared.Soils.Soil soil = Setup();
            soil.SoilType = "Black vertosol";

            APSIMReadySoil.Create(soil);

            // Make sure that predicted crops have been added.
            Assert.AreEqual(soil.Water.Crops.Count, 3);
            Assert.AreEqual(soil.Water.Crops[0].Name, "Wheat");
            Assert.AreEqual(soil.Water.Crops[1].Name, "Sorghum");
            Assert.AreEqual(soil.Water.Crops[2].Name, "Cotton");

            // Change soil type to a grey vertosol and examine the predicted crops.

            soil.SoilType = "Grey vertosol";
            soil.Water.Crops.Clear();
            APSIMReadySoil.Create(soil);
            Assert.AreEqual(soil.Water.Crops.Count, 7);
            Assert.AreEqual(soil.Water.Crops[0].Name, "Wheat");
            Assert.AreEqual(soil.Water.Crops[1].Name, "Sorghum");
            Assert.AreEqual(soil.Water.Crops[2].Name, "Cotton");
            Assert.AreEqual(soil.Water.Crops[3].Name, "Barley");
            Assert.AreEqual(soil.Water.Crops[4].Name, "Chickpea");
            Assert.AreEqual(soil.Water.Crops[5].Name, "Fababean");
            Assert.AreEqual(soil.Water.Crops[6].Name, "Mungbean");
        }
Example #3
0
        public void TestLayerStructure()
        {
            APSIM.Shared.Soils.Soil soil = Setup();

            // convert sw from gravimetric to volumetric.
            APSIMReadySoil.Create(soil);

            // Make sure the samples have been removed.
            Assert.AreEqual(soil.Samples.Count, 0);

            // Check the SW values have been converted and that the bottom two layers are at CLL (0.402)
            MathUtilities.AreEqual(soil.Water.SW, new double[] { 0.140, 0.289, 0.314, 0.326, 0.402, 0.402 });

            // Check the NO3 values haven't been converted and that the bottom layers have default values
            MathUtilities.AreEqual(soil.Nitrogen.NO3, new double[] { 23, 7, 2, 1, 0.01, 0.01 });

            // Check that the OC sample values have been put on top of the SoilOrganicMatter OC values.
            MathUtilities.AreEqual(soil.SoilOrganicMatter.OC, new double[] { 1.35, 1, 0.5, 0.4, 0.3, 0.2 });

            // Make sure the analysis missing value has been replaced with zero.
            MathUtilities.AreEqual(soil.Analysis.CL, new double[] { 38, 0.0, 500, 490, 500, 500 });

            // Make sure that no predicted crops have been added.
            string[] cropNames = soil.Water.Crops.Select(c => c.Name).ToArray();
            Assert.AreEqual(cropNames.Length, 1);
        }
Example #4
0
        public void TestWaterTable()
        {
            SoilModel soil = new SoilModel();

            APSIM.Shared.Soils.Soil soilProperties = Setup();
            APSIMReadySoil.Create(soilProperties);

            WaterTableModel waterTable = new WaterTableModel();

            SetLink(soil, "properties", soilProperties);
            SetLink(waterTable, "soil", soil);

            double[] DUL = MathUtilities.Multiply(soilProperties.Water.DUL, soilProperties.Water.Thickness);
            double[] SAT = MathUtilities.Multiply(soilProperties.Water.SAT, soilProperties.Water.Thickness);

            // Profile at DUL. Essentially water table is below profile.
            soil.Water = DUL;
            Assert.AreEqual(waterTable.Value(), 1600);

            // Put a saturated layer at index 3.
            soil.Water[3] = SAT[3];
            Assert.AreEqual(waterTable.Value(), 700);

            // Put a saturated layer at index 3 and a drainable layer at index 2.
            soil.Water[2] = (DUL[2] + SAT[2]) / 2;
            soil.Water[3] = SAT[3];
            Assert.AreEqual(waterTable.Value(), 250);
        }
Example #5
0
        /// <summary>Calculate a layered soil water. Units: mm/mm</summary>
        public double[] SW(Soil soil)
        {
            string[] cropNames = soil.Water.Crops.Select(c => c.Name).ToArray();

            // Get the correct LL and XF
            int cropIndex = -1;
            if (RelativeTo != null)
                cropIndex = StringUtilities.IndexOfCaseInsensitive(cropNames, RelativeTo);
            double[] ll;
            double[] xf = null;
            double[] PAWCmm;
            if (cropIndex == -1)
            {
                ll = soil.Water.LL15;
                PAWCmm = PAWC.OfSoilmm(soil);
            }
            else 
            {
                SoilCrop crop = soil.Water.Crops[cropIndex];
                ll = crop.LL;
                xf = crop.XF;
                PAWCmm = PAWC.OfCropmm(soil, crop);
            }

            if (double.IsNaN(DepthWetSoil))
            {
                if (PercentMethod == InitialWater.PercentMethodEnum.FilledFromTop)
                    return SWFilledFromTop(PAWCmm, ll, soil.Water.DUL, xf);
                else
                    return SWEvenlyDistributed(ll, soil.Water.DUL);
            }
            else
                return SWDepthWetSoil(soil.Water.Thickness, ll, soil.Water.DUL);
        }
Example #6
0
        /// <summary>Sets the water thickness.</summary>
        /// <param name="water">The water.</param>
        /// <param name="toThickness">To thickness.</param>
        /// <param name="soil">Soil</param>
        private static void SetWaterThickness(Water water, double[] toThickness, Soil soil)
        {
            if (!MathUtilities.AreEqual(toThickness, water.Thickness))
            {
                water.BD = MapConcentration(water.BD, water.Thickness, toThickness, MathUtilities.LastValue(water.BD));
                water.SW = MapSW(water.SW, water.Thickness, toThickness, soil);
                water.AirDry = MapConcentration(water.AirDry, water.Thickness, toThickness, MathUtilities.LastValue(water.AirDry));
                water.LL15 = MapConcentration(water.LL15, water.Thickness, toThickness, MathUtilities.LastValue(water.LL15));
                water.DUL = MapConcentration(water.DUL, water.Thickness, toThickness, MathUtilities.LastValue(water.DUL));
                water.SAT = MapConcentration(water.SAT, water.Thickness, toThickness, MathUtilities.LastValue(water.SAT));
                water.KS = MapConcentration(water.KS, water.Thickness, toThickness, MathUtilities.LastValue(water.KS));
                water.Thickness = toThickness;
            }

            if (water.Crops != null)
            {
                foreach (SoilCrop crop in water.Crops)
                {
                    if (!MathUtilities.AreEqual(toThickness, crop.Thickness))
                    {
                        crop.LL = MapConcentration(crop.LL, crop.Thickness, toThickness, MathUtilities.LastValue(crop.LL));
                        crop.KL = MapConcentration(crop.KL, crop.Thickness, toThickness, MathUtilities.LastValue(crop.KL));
                        crop.XF = MapConcentration(crop.XF, crop.Thickness, toThickness, MathUtilities.LastValue(crop.XF));
                        crop.Thickness = toThickness;

                        // Ensure crop LL are between Airdry and DUL.
                        for (int i = 0; i < crop.LL.Length; i++)
                            crop.LL = MathUtilities.Constrain(crop.LL, soil.Water.AirDry, soil.Water.DUL);
                    }
                }
            }
        }
Example #7
0
        public void TestInitialWater()
        {
            APSIM.Shared.Soils.Soil soil = Setup();
            soil.Samples[0].SW = null;
            soil.InitialWater  = new InitialWater();
            soil.InitialWater.PercentMethod = InitialWater.PercentMethodEnum.FilledFromTop;
            soil.InitialWater.RelativeTo    = "LL15";
            soil.InitialWater.FractionFull  = 0.5;

            APSIMReadySoil.Create(soil);

            // Make sure the initial water has been removed.
            Assert.IsNull(soil.InitialWater);

            // Check the SW values.
            MathUtilities.AreEqual(soil.Water.SW, new double[] { 0.365, 0.461, 0.43, 0.281, 0.261, 0.261 });

            // check evenly distributed method.
            soil.InitialWater = new InitialWater();
            soil.InitialWater.PercentMethod = InitialWater.PercentMethodEnum.EvenlyDistributed;
            soil.InitialWater.RelativeTo    = "LL15";
            soil.InitialWater.FractionFull  = 0.5;
            APSIMReadySoil.Create(soil);
            MathUtilities.AreEqual(soil.Water.SW, new double[] { 0.318, 0.364, 0.345, 0.336, 0.332, 0.333 });
        }
Example #8
0
        public void TestLateralFlow()
        {
            APSIM.Shared.Soils.Soil soilProperties = Setup();
            soilProperties.Samples.Clear();

            // Setup our objects with links.
            SoilModel        soil        = new SoilModel();
            LateralFlowModel lateralFlow = new LateralFlowModel();

            SetLink(soil, "properties", soilProperties);
            SetLink(soil, "lateralFlowModel", lateralFlow);
            SetLink(lateralFlow, "soil", soil);

            // Set initial water to full.
            soilProperties.InitialWater = new InitialWater();
            soilProperties.InitialWater.FractionFull = 1.0;
            APSIMReadySoil.Create(soilProperties);
            soil.Water = MathUtilities.Multiply(soilProperties.Water.SW, soilProperties.Water.Thickness);

            // No inflow, so there should be no outflow.
            lateralFlow.InFlow = null;
            Assert.AreEqual(lateralFlow.Values.Length, 0);

            // Profile is full so adding in flow will produce out flow.
            lateralFlow.InFlow = new double[] { 9, 9, 9, 9, 9, 9 };
            lateralFlow.KLAT   = MathUtilities.CreateArrayOfValues(8.0, soilProperties.Water.Thickness.Length);
            Assert.IsTrue(MathUtilities.AreEqual(lateralFlow.Values, new double[] { 0.45999, 0.80498, 0.80498, 0.80498, 0.80498, 0.80498 }));

            // Set initial water to empty. Out flow should be zeros.
            soilProperties.InitialWater = new InitialWater();
            soilProperties.InitialWater.FractionFull = 0.0;
            APSIMReadySoil.Create(soilProperties);
            soil.Water = MathUtilities.Multiply(soilProperties.Water.SW, soilProperties.Water.Thickness);
            Assert.IsTrue(MathUtilities.AreEqual(lateralFlow.Values, new double[] { 0, 0, 0, 0, 0, 0 }));
        }
Example #9
0
        /// <summary>Creates an apsim ready soil.</summary>
        /// <param name="soil">The soil.</param>
        /// <returns>A newly created soil ready to be run in APSIM.</returns>
        public static Soil Create(Soil soil)
        {
            Unit.Convert(soil);
            RemoveInitialWater(soil);
            LayerStructure.Standardise(soil);
            Defaults.FillInMissingValues(soil);
            RemoveSamples(soil);

            return soil;
        }
Example #10
0
        public void CheckUserLayerStructure()
        {
            APSIM.Shared.Soils.Soil soil = Setup();
            soil.LayerStructure           = new LayerStructure();
            soil.LayerStructure.Thickness = new double[]  { 200, 200, 200, 200 };

            APSIMReadySoil.Create(soil);

            MathUtilities.AreEqual(soil.Water.Thickness, new double[] { 200, 200, 200, 200 });
        }
Example #11
0
        /// <summary>Standardise the specified soil with a uniform thickness.</summary>
        /// <param name="soil">The soil.</param>
        /// <returns>A standardised soil.</returns>
        public static void Standardise(Soil soil)
        {
            double[] toThickness = soil.Water.Thickness;
            if (soil.LayerStructure != null)
                toThickness = soil.LayerStructure.Thickness;

            SetWaterThickness(soil.Water, toThickness, soil);
            SetSoilWaterThickness(soil.SoilWater, toThickness);
            SetAnalysisThickness(soil.Analysis, toThickness);
            SetSoilOrganicMatterThickness(soil.SoilOrganicMatter, toThickness);
            SetPhosphorus(soil.Phosphorus, toThickness);
            SetSWIM(soil.Swim, toThickness);
            SetSoilTemperature(soil.SoilTemperature, toThickness);

            foreach (Sample sample in soil.Samples)
                SetSampleThickness(sample, toThickness, soil);
        }
Example #12
0
        /// <summary>Sets the sample thickness.</summary>
        /// <param name="sample">The sample.</param>
        /// <param name="thickness">The thickness to change the sample to.</param>
        /// <param name="soil">The soil</param>
        private static void SetSampleThickness(Sample sample, double[] thickness, Soil soil)
        {
            if (!MathUtilities.AreEqual(thickness, sample.Thickness))
            {
                sample.Name = sample.Name;
                sample.Date = sample.Date;

                if (sample.SW != null)
                {
                    sample.SW = MapSW(sample.SW, sample.Thickness, thickness, soil);
                }
                if (sample.NH4 != null)
                {
                    sample.NH4 = MapConcentration(sample.NH4, sample.Thickness, thickness, 0.01);
                }
                if (sample.NO3 != null)
                {
                    sample.NO3 = MapConcentration(sample.NO3, sample.Thickness, thickness, 0.01);
                }

                // The elements below will be overlaid over other arrays of values so we want
                // to have missing values (double.NaN) used at the bottom of the profile.

                if (sample.CL != null)
                {
                    sample.CL = MapConcentration(sample.CL, sample.Thickness, thickness, double.NaN, allowMissingValues: true);
                }
                if (sample.EC != null)
                {
                    sample.EC = MapConcentration(sample.EC, sample.Thickness, thickness, double.NaN, allowMissingValues: true);
                }
                if (sample.ESP != null)
                {
                    sample.ESP = MapConcentration(sample.ESP, sample.Thickness, thickness, double.NaN, allowMissingValues: true);
                }
                if (sample.OC != null)
                {
                    sample.OC = MapConcentration(sample.OC, sample.Thickness, thickness, double.NaN, allowMissingValues: true);
                }
                if (sample.PH != null)
                {
                    sample.PH = MapConcentration(sample.PH, sample.Thickness, thickness, double.NaN, allowMissingValues: true);
                }
                sample.Thickness = thickness;
            }
        }
Example #13
0
        /// <summary>Write soil to XML</summary>
        /// <param name="soil">The soil.</param>
        /// <returns></returns>
        public static string ToXML(Soil soil)
        {
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add("", "");
            XmlSerializer x = new XmlSerializer(typeof(Soil));

            StringWriter Out = new StringWriter();
            x.Serialize(Out, soil, ns);
            string st = Out.ToString();
            if (st.Length > 5 && st.Substring(0, 5) == "<?xml")
            {
                // remove the first line: <?xml version="1.0"?>/n
                int posEol = st.IndexOf("\n");
                if (posEol != -1)
                    return st.Substring(posEol + 1);
            }
            return st;
        }
Example #14
0
 /// <summary>Checks the crop for missing values.</summary>
 /// <param name="crop">The crop.</param>
 /// <param name="soil">The soil.</param>
 private static void CheckCropForMissingValues(SoilCrop crop, Soil soil)
 {
     for (int i = 0; i < crop.Thickness.Length; i++)
     {
         if (crop.LL != null && double.IsNaN(crop.LL[i]))
         {
             crop.LL[i] = soil.Water.LL15[i];
         }
         if (crop.KL != null && double.IsNaN(crop.KL[i]))
         {
             crop.KL[i] = 0;
         }
         if (crop.XF != null && double.IsNaN(crop.XF[i]))
         {
             crop.XF[i] = 0;
         }
     }
 }
Example #15
0
        /// <summary>Test setup routine. Returns a soil properties that can be used for testing.</summary>
        public static APSIM.Shared.Soils.Soil Setup()
        {
            APSIM.Shared.Soils.Soil soil = new APSIM.Shared.Soils.Soil();
            soil.Water           = new Water();
            soil.Water.Thickness = new double[] { 100, 300, 300, 300, 300, 300 };
            soil.Water.BD        = new double[] { 1.36, 1.216, 1.24, 1.32, 1.372, 1.368 };
            soil.Water.AirDry    = new double[] { 0.135, 0.214, 0.261, 0.261, 0.261, 0.261 };
            soil.Water.LL15      = new double[] { 0.27, 0.267, 0.261, 0.261, 0.261, 0.261 };
            soil.Water.DUL       = new double[] { 0.365, 0.461, 0.43, 0.412, 0.402, 0.404 };
            soil.Water.SAT       = new double[] { 0.400, 0.481, 0.45, 0.432, 0.422, 0.424 };

            // Add a wheat crop.
            SoilCrop crop = new SoilCrop();

            crop.Thickness   = soil.Water.Thickness;
            crop.Name        = "Wheat";
            crop.KL          = new double[] { 0.06, 0.060, 0.060, 0.060, 0.060, 0.060 };
            crop.LL          = new double[] { 0.27, 0.267, 0.261, 0.315, 0.402, 0.402 };
            soil.Water.Crops = new List <SoilCrop>();
            soil.Water.Crops.Add(crop);

            // Add OC values into SoilOrganicMatter.
            soil.SoilOrganicMatter           = new SoilOrganicMatter();
            soil.SoilOrganicMatter.Thickness = soil.Water.Thickness;
            soil.SoilOrganicMatter.OC        = new double[] { 2, 1, 0.5, 0.4, 0.3, 0.2 };

            // Add in CL into analysis.
            soil.Analysis           = new Analysis();
            soil.Analysis.Thickness = soil.Water.Thickness;
            soil.Analysis.CL        = new double[] { 38, double.NaN, 500, 490, 500, 500 };

            // Add a sample.
            Sample sample = new Sample();

            sample.Thickness = new double[] { 100, 300, 300, 300 };
            sample.SW        = new double[] { 0.103, 0.238, 0.253, 0.247 };
            sample.NO3       = new double[] { 23, 7, 2, 1 };
            sample.OC        = new double[] { 1.35, double.NaN, double.NaN, double.NaN };
            sample.SWUnits   = Sample.SWUnitsEnum.Gravimetric;
            soil.Samples     = new List <Sample>();
            soil.Samples.Add(sample);
            return(soil);
        }
Example #16
0
        /// <summary>Calculate a layered soil water. Units: mm/mm</summary>
        public double[] SW(Soil soil)
        {
            string[] cropNames = soil.Water.Crops.Select(c => c.Name).ToArray();

            // Get the correct LL and XF
            int cropIndex = -1;

            if (RelativeTo != null)
            {
                cropIndex = StringUtilities.IndexOfCaseInsensitive(cropNames, RelativeTo);
            }
            double[] ll;
            double[] xf = null;
            double[] PAWCmm;
            if (cropIndex == -1)
            {
                ll     = soil.Water.LL15;
                PAWCmm = PAWC.OfSoilmm(soil);
            }
            else
            {
                SoilCrop crop = soil.Water.Crops[cropIndex];
                ll     = crop.LL;
                xf     = crop.XF;
                PAWCmm = PAWC.OfCropmm(soil, crop);
            }

            if (double.IsNaN(DepthWetSoil))
            {
                if (PercentMethod == InitialWater.PercentMethodEnum.FilledFromTop)
                {
                    return(SWFilledFromTop(PAWCmm, ll, soil.Water.DUL, xf));
                }
                else
                {
                    return(SWEvenlyDistributed(ll, soil.Water.DUL));
                }
            }
            else
            {
                return(SWDepthWetSoil(soil.Water.Thickness, ll, soil.Water.DUL));
            }
        }
Example #17
0
        /// <summary>Test setup routine. Returns a soil properties that can be used for testing.</summary>
        public static APSIM.Shared.Soils.Soil Setup()
        {
            APSIM.Shared.Soils.Soil soil = new APSIM.Shared.Soils.Soil();
            soil.Water = new Water();
            soil.Water.Thickness = new double[] { 100, 300, 300, 300, 300, 300 };
            soil.Water.BD = new double[] { 1.36, 1.216, 1.24, 1.32, 1.372, 1.368 };
            soil.Water.AirDry = new double[] { 0.135, 0.214, 0.261, 0.261, 0.261, 0.261 };
            soil.Water.LL15 = new double[] { 0.27, 0.267, 0.261, 0.261, 0.261, 0.261 };
            soil.Water.DUL = new double[] { 0.365, 0.461, 0.43, 0.412, 0.402, 0.404 };
            soil.Water.SAT = new double[] { 0.400, 0.481, 0.45, 0.432, 0.422, 0.424 };

            // Add a wheat crop.
            SoilCrop crop = new SoilCrop();
            crop.Thickness = soil.Water.Thickness;
            crop.Name = "Wheat";
            crop.KL = new double[] { 0.06, 0.060, 0.060, 0.060, 0.060, 0.060 };
            crop.LL = new double[] { 0.27, 0.267, 0.261, 0.315, 0.402, 0.402 };
            soil.Water.Crops = new List<SoilCrop>();
            soil.Water.Crops.Add(crop);

            // Add OC values into SoilOrganicMatter.
            soil.SoilOrganicMatter = new SoilOrganicMatter();
            soil.SoilOrganicMatter.Thickness = soil.Water.Thickness;
            soil.SoilOrganicMatter.OC = new double[] { 2, 1, 0.5, 0.4, 0.3, 0.2 };

            // Add in CL into analysis.
            soil.Analysis = new Analysis();
            soil.Analysis.Thickness = soil.Water.Thickness;
            soil.Analysis.CL = new double[] { 38, double.NaN, 500, 490, 500, 500 };

            // Add a sample.
            Sample sample = new Sample();
            sample.Thickness = new double[] { 100, 300, 300, 300 };
            sample.SW = new double[] { 0.103, 0.238, 0.253, 0.247 };
            sample.NO3 = new double[] { 23, 7, 2, 1 };
            sample.OC = new double[] { 1.35, double.NaN, double.NaN, double.NaN };
            sample.SWUnits = Sample.SWUnitsEnum.Gravimetric;
            soil.Samples = new List<Sample>();
            soil.Samples.Add(sample);
            return soil;
        }
Example #18
0
        /// <summary>Fills in missing values where possible.</summary>
        /// <param name="soil">The soil.</param>
        public static void FillInMissingValues(Soil soil)
        {
            AddPredictedCrops(soil);
            CheckAnalysisForMissingValues(soil);

            foreach (SoilCrop crop in soil.Water.Crops)
            {
                if (crop.XF == null)
                {
                    crop.XF = MathUtilities.CreateArrayOfValues(1.0, crop.Thickness.Length);
                    crop.XFMetadata = StringUtilities.CreateStringArray("Estimated", crop.Thickness.Length);
                }
                if (crop.KL == null)
                    FillInKLForCrop(crop);

                CheckCropForMissingValues(crop, soil);
            }

            foreach (Sample sample in soil.Samples)
                CheckSampleForMissingValues(sample, soil);
        }
Example #19
0
        /// <summary>Standardise the specified soil with a uniform thickness.</summary>
        /// <param name="soil">The soil.</param>
        /// <returns>A standardised soil.</returns>
        public static void Standardise(Soil soil)
        {
            double[] toThickness = soil.Water.Thickness;
            if (soil.LayerStructure != null)
            {
                toThickness = soil.LayerStructure.Thickness;
            }

            SetWaterThickness(soil.Water, toThickness, soil);
            SetSoilWaterThickness(soil.SoilWater, toThickness);
            SetAnalysisThickness(soil.Analysis, toThickness);
            SetSoilOrganicMatterThickness(soil.SoilOrganicMatter, toThickness);
            SetPhosphorus(soil.Phosphorus, toThickness);
            SetSWIM(soil.Swim, toThickness);
            SetSoilTemperature(soil.SoilTemperature, toThickness);

            foreach (Sample sample in soil.Samples)
            {
                SetSampleThickness(sample, toThickness, soil);
            }
        }
Example #20
0
        /// <summary>Calculates volumetric soil water for the given sample.</summary>
        /// <param name="sample">The sample.</param>
        /// <param name="soil">The soil.</param>
        /// <returns>Volumetric water (mm/mm)</returns>
        private static double[] SWVolumetric(Sample sample, Soil soil)
        {
            if (sample.SWUnits == Sample.SWUnitsEnum.Volumetric || sample.SW == null)
            {
                return(sample.SW);
            }
            else
            {
                // convert the numbers
                if (sample.SWUnits == Sample.SWUnitsEnum.Gravimetric)
                {
                    double[] bd = LayerStructure.BDMapped(soil, sample.Thickness);

                    return(MathUtilities.Multiply(sample.SW, bd));
                }
                else
                {
                    return(MathUtilities.Divide(sample.SW, sample.Thickness)); // from mm to mm/mm
                }
            }
        }
Example #21
0
        /// <summary>Map soil variables (using BD) from one layer structure to another.</summary>
        /// <param name="fromValues">The from values.</param>
        /// <param name="fromThickness">The from thickness.</param>
        /// <param name="toThickness">To thickness.</param>
        /// <param name="soil">The soil.</param>
        /// <param name="defaultValueForBelowProfile">The default value for below profile.</param>
        /// <returns></returns>
        private static double[] MapUsingBD(double[] fromValues, double[] fromThickness,
                                           double[] toThickness,
                                           Soil soil,
                                           double defaultValueForBelowProfile)
        {
            if (fromValues == null || fromThickness == null)
            {
                return(null);
            }

            // create an array of values with a dummy bottom layer.
            List <double> values = new List <double>();

            values.AddRange(fromValues);
            values.Add(defaultValueForBelowProfile);
            List <double> thickness = new List <double>();

            thickness.AddRange(fromThickness);
            thickness.Add(3000);

            // convert fromValues to a mass basis
            double[] BD = BDMapped(soil, fromThickness);
            for (int Layer = 0; Layer < values.Count; Layer++)
            {
                values[Layer] = values[Layer] * BD[Layer] * fromThickness[Layer] / 100;
            }

            // change layer structure
            double[] newValues = MapMass(values.ToArray(), thickness.ToArray(), toThickness);

            // convert newValues back to original units and return
            BD = BDMapped(soil, toThickness);
            for (int Layer = 0; Layer < newValues.Length; Layer++)
            {
                newValues[Layer] = newValues[Layer] * 100.0 / BD[Layer] / toThickness[Layer];
            }
            return(newValues);
        }
Example #22
0
        /// <summary>Write soil to XML</summary>
        /// <param name="soil">The soil.</param>
        /// <returns></returns>
        public static string ToXML(Soil soil)
        {
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();

            ns.Add("", "");
            XmlSerializer x = new XmlSerializer(typeof(Soil));

            StringWriter Out = new StringWriter();

            x.Serialize(Out, soil, ns);
            string st = Out.ToString();

            if (st.Length > 5 && st.Substring(0, 5) == "<?xml")
            {
                // remove the first line: <?xml version="1.0"?>/n
                int posEol = st.IndexOf("\n");
                if (posEol != -1)
                {
                    return(st.Substring(posEol + 1));
                }
            }
            return(st);
        }
Example #23
0
        public void TestSaturatedFlow()
        {
            SoilModel soil = new SoilModel();

            APSIM.Shared.Soils.Soil soilProperties = Setup();
            APSIMReadySoil.Create(soilProperties);

            SaturatedFlowModel saturatedFlow = new SaturatedFlowModel();

            SetLink(soil, "properties", soilProperties);
            SetLink(saturatedFlow, "soil", soil);

            saturatedFlow.SWCON = new double[] { 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 };

            // Profile at DUL.
            soil.Water = MathUtilities.Multiply(soilProperties.Water.DUL, soilProperties.Water.Thickness);
            double[] flux = saturatedFlow.Values;
            Assert.IsTrue(MathUtilities.AreEqual(flux, new double[] { 0, 0, 0, 0, 0, 0 }));

            // Profile at SAT.
            soil.Water = MathUtilities.Multiply(soilProperties.Water.SAT, soilProperties.Water.Thickness);
            flux       = saturatedFlow.Values;
            Assert.IsTrue(MathUtilities.AreEqual(flux, new double[] { 1.05, 2.85, 4.64999, 6.45, 8.25, 10.05 }));

            // Use the KS method
            soilProperties.Water.KS = new double[] { 1000, 300, 20, 100, 100, 100 };
            flux = saturatedFlow.Values;
            Assert.IsTrue(MathUtilities.AreEqual(flux, new double[] { 1.05, 1.8000, 1.8000, 1.8000, 1.8000, 1.8000 }));
            Assert.AreEqual(saturatedFlow.backedUpSurface, 0);

            // Use the KS method, water above SAT.
            soilProperties.Water.KS = new double[] { 1000, 300, 20, 100, 100, 100 };
            MathUtilities.AddValue(soil.Water, 10); // add 5 mm of water into each layer.
            flux = saturatedFlow.Values;
            Assert.IsTrue(MathUtilities.AreEqual(flux, new double[] { 1.05, 1.8000, 1.8000, 1.8000, 1.8000, 1.8000 }));
        }
        /// <summary>
        /// Set the soilwat, soiln, surfaceom components
        /// </summary>
        /// <param name="defaultPaddock"></param>
        /// <param name="soilConfig"></param>
        /// <param name="paddocknode"></param>
        private void SetSoilComponents(FarmPaddockType defaultPaddock, Soil soilConfig, XmlNode paddocknode)
        {
            XmlNode apsimCompNode;
            XmlNode translatorNode;

            //set soilwat
            apsimCompNode = paddocknode.SelectSingleNode("system/component[@class=\"SoilWat\"]");
            initSoilWat(apsimCompNode, soilConfig);
            if (apsimCompNode != null)
            {
                translatorNode = apsimCompNode.ParentNode;
                initSoilWat_Trans(translatorNode, soilConfig, defaultPaddock.SoilType);
            }

            //set soiln
            apsimCompNode = paddocknode.SelectSingleNode("system/component[@class=\"SoilN\"]");
            initSoilN(apsimCompNode, soilConfig, defaultPaddock);
            if (apsimCompNode != null)
            {
                translatorNode = apsimCompNode.ParentNode;
                initSoilN_Trans(translatorNode, soilConfig);
            }

            //set surfaceOM
            apsimCompNode = paddocknode.SelectSingleNode("system/component[@class=\"SurfaceOM\"]");
            initSOM(apsimCompNode, soilConfig);
            if (apsimCompNode != null)
            {
                translatorNode = apsimCompNode.ParentNode;
                initSOM_Trans(translatorNode, soilConfig, defaultPaddock.SoilType);

                //if there is a paddock with init residue data and new crops in the rotation then set here 
                setSurfaceOMPaddockInits(apsimCompNode, defaultPaddock);
            }
        }
Example #25
0
 /// <summary>Drained upper limit - mapped to the specified layer structure. Units: mm/mm        /// </summary>
 /// <param name="soil">The soil.</param>
 /// <param name="ToThickness">To thickness.</param>
 /// <returns></returns>
 internal static double[] DULMapped(Soil soil, double[] ToThickness)
 {
     return MapConcentration(soil.Water.DUL, soil.Water.Thickness, ToThickness, soil.Water.DUL.Last());
 }
Example #26
0
 /// <summary>Convert the crop to the specified thickness. Ensures LL is between AirDry and DUL.</summary>
 /// <param name="crop">The crop to convert</param>
 /// <param name="thickness">The thicknesses to convert the crop to.</param>
 /// <param name="soil">The soil the crop belongs to.</param>
 private static void SetCropThickness(SoilCrop crop, double[] thickness, Soil soil)
 {
     if (!MathUtilities.AreEqual(thickness, crop.Thickness))
     {
         crop.LL = MapConcentration(crop.LL, crop.Thickness, thickness, MathUtilities.LastValue(crop.LL));
         crop.KL = MapConcentration(crop.KL, crop.Thickness, thickness, MathUtilities.LastValue(crop.KL));
         crop.XF = MapConcentration(crop.XF, crop.Thickness, thickness, MathUtilities.LastValue(crop.XF));
         crop.Thickness = thickness;
         
         crop.LL = MathUtilities.Constrain(crop.LL, AirDryMapped(soil, thickness), DULMapped(soil, thickness));
     }
 }
Example #27
0
        /// <summary>Map soil variables (using BD) from one layer structure to another.</summary>
        /// <param name="fromValues">The from values.</param>
        /// <param name="fromThickness">The from thickness.</param>
        /// <param name="toThickness">To thickness.</param>
        /// <param name="soil">The soil.</param>
        /// <param name="defaultValueForBelowProfile">The default value for below profile.</param>
        /// <returns></returns>
        private static double[] MapUsingBD(double[] fromValues, double[] fromThickness,
                                           double[] toThickness,
                                           Soil soil,
                                           double defaultValueForBelowProfile)
        {
            if (fromValues == null || fromThickness == null)
                return null;

            // create an array of values with a dummy bottom layer.
            List<double> values = new List<double>();
            values.AddRange(fromValues);
            values.Add(defaultValueForBelowProfile);
            List<double> thickness = new List<double>();
            thickness.AddRange(fromThickness);
            thickness.Add(3000);

            // convert fromValues to a mass basis
            double[] BD = BDMapped(soil, fromThickness);
            for (int Layer = 0; Layer < values.Count; Layer++)
                values[Layer] = values[Layer] * BD[Layer] * fromThickness[Layer] / 100;

            // change layer structure
            double[] newValues = MapMass(values.ToArray(), thickness.ToArray(), toThickness);

            // convert newValues back to original units and return
            BD = BDMapped(soil, toThickness);
            for (int Layer = 0; Layer < newValues.Length; Layer++)
                newValues[Layer] = newValues[Layer] * 100.0 / BD[Layer] / toThickness[Layer];
            return newValues;
        }
Example #28
0
 /// <summary>Return the plant available water CAPACITY of the soil. Units: mm/mm</summary>
 /// <param name="soil">The soil to calculate PAWC for.</param>
 public static double[] OfSoil(Soil soil)
 {
     return(PAWCInternal(soil.Water.Thickness, soil.Water.LL15, soil.Water.DUL, null));
 }
Example #29
0
 /// <summary>Return the index of the layer that contains the specified depth.</summary>
 /// <param name="soil">The soil</param>
 /// <param name="depth">The depth to search for.</param>
 /// <returns></returns>
 static public int FindLayerIndex(Soil soil, double depth)
 {
     return(Array.FindIndex(ToCumThickness(soil.Water.Thickness), d => d > depth));
 }
        private void initSoilN_Trans(XmlNode compNode, Soil aSoil)
        {
            TSDMLValue init = GetTypedInit(compNode, "excrete_params");
            if (init.count() < 3)
            {
                init.setElementCount(3);
                init.item(1).setValue(0.3);     //depositied in camp areas
                init.item(2).setValue(0.25);    //urine that volatizes
                init.item(3).setValue(0.035);   //surface faecal breakdown
                SetTypedInit(compNode, "excrete_params", init);
            }

            //may not need to do this in an already configured simulation
            init = GetTypedInit(compNode, "published_events");
            if (init.count() < 1)
            {
                init.setElementCount(2);
                init.item(1).member("name").setValue(".model.new_solute");
                init.item(1).member("connects").setElementCount(1);
                init.item(1).member("connects").item(1).setValue("..water.model.new_solute");
                init.item(2).member("name").setValue(".model.actualresiduedecompositioncalculated");
                init.item(2).member("connects").setElementCount(1);
                init.item(2).member("connects").item(1).setValue("..surfaceom.model.actualresiduedecompositioncalculated");
                SetTypedInit(compNode, "published_events", init);
            }
        }
Example #31
0
        /// <summary>Checks the sample for missing values.</summary>
        /// <param name="sample">The sample.</param>
        /// <param name="soil">The soil.</param>
        private static void CheckSampleForMissingValues(Sample sample, Soil soil)
        {
            if (!MathUtilities.ValuesInArray(sample.SW))
            {
                sample.SW = null;
            }
            if (!MathUtilities.ValuesInArray(sample.NO3))
            {
                sample.NO3 = null;
            }
            if (!MathUtilities.ValuesInArray(sample.CL))
            {
                sample.CL = null;
            }
            if (!MathUtilities.ValuesInArray(sample.EC))
            {
                sample.EC = null;
            }
            if (!MathUtilities.ValuesInArray(sample.ESP))
            {
                sample.ESP = null;
            }
            if (!MathUtilities.ValuesInArray(sample.PH))
            {
                sample.PH = null;
            }
            if (!MathUtilities.ValuesInArray(sample.OC))
            {
                sample.OC = null;
            }

            if (sample.SW != null)
            {
                sample.SW = MathUtilities.FixArrayLength(sample.SW, sample.Thickness.Length);
            }
            if (sample.NO3 != null)
            {
                sample.NO3 = MathUtilities.FixArrayLength(sample.NO3, sample.Thickness.Length);
            }
            if (sample.NH4 != null)
            {
                sample.NH4 = MathUtilities.FixArrayLength(sample.NH4, sample.Thickness.Length);
            }
            if (sample.CL != null)
            {
                sample.CL = MathUtilities.FixArrayLength(sample.CL, sample.Thickness.Length);
            }
            if (sample.EC != null)
            {
                sample.EC = MathUtilities.FixArrayLength(sample.EC, sample.Thickness.Length);
            }
            if (sample.ESP != null)
            {
                sample.ESP = MathUtilities.FixArrayLength(sample.ESP, sample.Thickness.Length);
            }
            if (sample.PH != null)
            {
                sample.PH = MathUtilities.FixArrayLength(sample.PH, sample.Thickness.Length);
            }
            if (sample.OC != null)
            {
                sample.OC = MathUtilities.FixArrayLength(sample.OC, sample.Thickness.Length);
            }

            double[] ll15 = LayerStructure.LL15Mapped(soil, sample.Thickness);
            for (int i = 0; i < sample.Thickness.Length; i++)
            {
                if (sample.SW != null && double.IsNaN(sample.SW[i]))
                {
                    sample.SW[i] = ll15[i];
                }
                if (sample.NO3 != null && double.IsNaN(sample.NO3[i]))
                {
                    sample.NO3[i] = 1.0;
                }
                if (sample.NH4 != null && double.IsNaN(sample.NH4[i]))
                {
                    sample.NH4[i] = 0.1;
                }
                if (sample.CL != null && double.IsNaN(sample.CL[i]))
                {
                    sample.CL[i] = 0;
                }
                if (sample.EC != null && double.IsNaN(sample.EC[i]))
                {
                    sample.EC[i] = 0;
                }
                if (sample.ESP != null && double.IsNaN(sample.ESP[i]))
                {
                    sample.ESP[i] = 0;
                }
                if (sample.PH != null && (double.IsNaN(sample.PH[i]) || sample.PH[i] == 0.0))
                {
                    sample.PH[i] = 7.0;
                }
                if (sample.OC != null && (double.IsNaN(sample.OC[i]) || sample.OC[i] == 0.0))
                {
                    sample.OC[i] = 0.5;
                }
            }
        }
Example #32
0
    private static string ReplaceSoilMacros(XmlNode SoilNode, string ApsimToSimContents)
    {
        // Get rid of nodes under <soil> that are disabled.
        RemoveDisabledNodes(SoilNode);

        APSIM.Shared.Soils.Soil mySoil = APSIM.Shared.Soils.SoilUtilities.FromXML(SoilNode.OuterXml);
        mySoil = APSIM.Shared.Soils.APSIMReadySoil.Create(mySoil);
        if (mySoil.Name == null)
        {
            mySoil.Name = "Soil";
        }

        // Loop through all soil macros.
        int PosMacro = 0;

        PosMacro = ApsimToSimContents.IndexOf("[soil.", PosMacro);
        while (PosMacro != -1)
        {
            int PosEndMacro = ApsimToSimContents.IndexOf(']', PosMacro);
            if (PosEndMacro == -1)
            {
                throw new Exception("Invalid soil macro found: " + ApsimToSimContents.Substring(PosMacro));
            }

            // Get macro name e.g. soil.thickness
            string MacroName = ApsimToSimContents.Substring(PosMacro + 1, PosEndMacro - PosMacro - 1);

            //if (MacroName.Contains("soil."))
            {
                // remove the soil. prefix from the MacroName.
                MacroName = MacroName.Substring(MacroName.IndexOf('.') + 1);

                // Is it a crop macro i.e. wheat ll
                object Obj = null;
                if (MacroName.Contains(" "))
                {
                    string CropName     = MacroName.Substring(0, MacroName.IndexOf(' '));
                    string VariableName = MacroName.Substring(MacroName.IndexOf(' ') + 1);
                    APSIM.Shared.Soils.SoilCrop crop = mySoil.Water.Crops.Find(c => c.Name.Equals(CropName, StringComparison.InvariantCultureIgnoreCase));
                    if (crop == null)
                    {
                        throw new Exception("Cannot find soil water information for crop '" + CropName + "'. " +
                                            "You likely need to \"Manage Crops\" in the Water node of your soil, and set the water properties of this crop");
                    }
                    if (VariableName.Equals("ll", StringComparison.CurrentCultureIgnoreCase))
                    {
                        Obj = crop.LL;
                    }
                    else if (VariableName.Equals("kl", StringComparison.CurrentCultureIgnoreCase))
                    {
                        Obj = crop.KL;
                    }
                    else if (VariableName.Equals("xf", StringComparison.CurrentCultureIgnoreCase))
                    {
                        Obj = crop.XF;
                    }
                }
                else
                {
                    Obj = Utility.GetValueOfFieldOrProperty(MacroName, mySoil);
                }

                if (Obj != null)
                {
                    string MacroValue = "";
                    if (Obj is IList)
                    {
                        foreach (object I in Obj as IList)
                        {
                            if (I is double)
                            {
                                MacroValue += ((double)I).ToString("f3", CultureInfo.CreateSpecificCulture("en-AU")) + " ";
                            }
                            else
                            {
                                MacroValue += I.ToString() + " ";
                            }
                        }
                    }
                    else if (Obj is double)
                    {
                        if (double.IsNaN(Convert.ToDouble(Obj)))
                        {
                            MacroValue = "";
                        }
                        else
                        {
                            MacroValue = ((Double)Obj).ToString("f3", CultureInfo.CreateSpecificCulture("en-AU"));
                        }
                    }
                    else
                    {
                        MacroValue = Obj.ToString();
                    }

                    ApsimToSimContents = ApsimToSimContents.Remove(PosMacro, PosEndMacro - PosMacro + 1);
                    ApsimToSimContents = ApsimToSimContents.Insert(PosMacro, MacroValue);
                }
                PosMacro = ApsimToSimContents.IndexOf("[soil.", PosMacro + 1);
            }
        }

        return(ApsimToSimContents);
    }
Example #33
0
 /// <summary>AirDry - mapped to the specified layer structure. Units: mm/mm        /// </summary>
 /// <param name="soil">The soil.</param>
 /// <param name="ToThickness">To thickness.</param>
 /// <returns></returns>
 private static double[] AirDryMapped(Soil soil, double[] ToThickness)
 {
     return(MapConcentration(soil.Water.AirDry, soil.Water.Thickness, ToThickness, soil.Water.AirDry.Last()));
 }
Example #34
0
        /// <summary>Checks the sample for missing values.</summary>
        /// <param name="sample">The sample.</param>
        /// <param name="soil">The soil.</param>
        private static void CheckSampleForMissingValues(Sample sample, Soil soil)
        {
            if (!MathUtilities.ValuesInArray(sample.SW))
                sample.SW = null;
            if (!MathUtilities.ValuesInArray(sample.NO3))
                sample.NO3 = null;
            if (!MathUtilities.ValuesInArray(sample.CL))
                sample.CL = null;
            if (!MathUtilities.ValuesInArray(sample.EC))
                sample.EC = null;
            if (!MathUtilities.ValuesInArray(sample.ESP))
                sample.ESP = null;
            if (!MathUtilities.ValuesInArray(sample.PH))
                sample.PH = null;
            if (!MathUtilities.ValuesInArray(sample.OC))
                sample.OC = null;

            if (sample.SW != null)
                sample.SW = MathUtilities.FixArrayLength(sample.SW, sample.Thickness.Length);
            if (sample.NO3 != null)
                sample.NO3 = MathUtilities.FixArrayLength(sample.NO3, sample.Thickness.Length);
            if (sample.NH4 != null)
                sample.NH4 = MathUtilities.FixArrayLength(sample.NH4, sample.Thickness.Length);
            if (sample.CL != null)
                sample.CL = MathUtilities.FixArrayLength(sample.CL, sample.Thickness.Length);
            if (sample.EC != null)
                sample.EC = MathUtilities.FixArrayLength(sample.EC, sample.Thickness.Length);
            if (sample.ESP != null)
                sample.ESP = MathUtilities.FixArrayLength(sample.ESP, sample.Thickness.Length);
            if (sample.PH != null)
                sample.PH = MathUtilities.FixArrayLength(sample.PH, sample.Thickness.Length);
            if (sample.OC != null)
                sample.OC = MathUtilities.FixArrayLength(sample.OC, sample.Thickness.Length);

            double[] ll15 = LayerStructure.LL15Mapped(soil, sample.Thickness);
            for (int i = 0; i < sample.Thickness.Length; i++)
            {
                if (sample.SW != null && double.IsNaN(sample.SW[i]))
                    sample.SW[i] = ll15[i];
                if (sample.NO3 != null && double.IsNaN(sample.NO3[i]))
                    sample.NO3[i] = 1.0;
                if (sample.NH4 != null && double.IsNaN(sample.NH4[i]))
                    sample.NH4[i] = 0.1;
                if (sample.CL != null && double.IsNaN(sample.CL[i]))
                    sample.CL[i] = 0;
                if (sample.EC != null && double.IsNaN(sample.EC[i]))
                    sample.EC[i] = 0;
                if (sample.ESP != null && double.IsNaN(sample.ESP[i]))
                    sample.ESP[i] = 0;
                if (sample.PH != null && (double.IsNaN(sample.PH[i]) || sample.PH[i] == 0.0))
                    sample.PH[i] = 7.0;
                if (sample.OC != null && (double.IsNaN(sample.OC[i]) || sample.OC[i] == 0.0))
                    sample.OC[i] = 0.5;
            }
        }
Example #35
0
 /// <summary>Checks the crop for missing values.</summary>
 /// <param name="crop">The crop.</param>
 /// <param name="soil">The soil.</param>
 private static void CheckCropForMissingValues(SoilCrop crop, Soil soil)
 {
     for (int i = 0; i < crop.Thickness.Length; i++)
     {
         if (crop.LL != null && double.IsNaN(crop.LL[i]))
             crop.LL[i] = soil.Water.LL15[i];
         if (crop.KL != null && double.IsNaN(crop.KL[i]))
             crop.KL[i] = 0;
         if (crop.XF != null && double.IsNaN(crop.XF[i]))
             crop.XF[i] = 0;
     }
 }
Example #36
0
        /// <summary>Checks the analysis for missing values.</summary>
        /// <param name="soil">The soil.</param>
        private static void CheckAnalysisForMissingValues(Soil soil)
        {
            for (int i = 0; i < soil.Analysis.Thickness.Length; i++)
            {
                if (soil.Analysis.CL != null && double.IsNaN(soil.Analysis.CL[i]))
                    soil.Analysis.CL[i] = 0;

                if (soil.Analysis.EC != null && double.IsNaN(soil.Analysis.EC[i]))
                    soil.Analysis.EC[i] = 0;

                if (soil.Analysis.ESP != null && double.IsNaN(soil.Analysis.ESP[i]))
                    soil.Analysis.ESP[i] = 0;

                if (soil.Analysis.PH != null && double.IsNaN(soil.Analysis.PH[i]))
                    soil.Analysis.PH[i] = 7;
            }
        }
Example #37
0
        /// <summary>Convert soil units to APSIM standard.</summary>
        /// <param name="soil">The soil.</param>
        public static void Convert(Soil soil)
        {
            // Convert soil organic matter OC to total %
            if (soil.SoilOrganicMatter != null)
            {
                soil.SoilOrganicMatter.OC = OCTotalPercent(soil.SoilOrganicMatter.OC, soil.SoilOrganicMatter.OCUnits);
                soil.SoilOrganicMatter.OCUnits = SoilOrganicMatter.OCUnitsEnum.Total;
            }

            // Convert nitrogen to ppm.
            if (soil.Nitrogen != null)
            {
                double[] bd = LayerStructure.BDMapped(soil, soil.Nitrogen.Thickness);
                soil.Nitrogen.NO3 = Nppm(soil.Nitrogen.NO3, soil.Nitrogen.Thickness, soil.Nitrogen.NO3Units, bd);
                soil.Nitrogen.NO3Units = Nitrogen.NUnitsEnum.ppm;

                soil.Nitrogen.NH4 = Nppm(soil.Nitrogen.NH4, soil.Nitrogen.Thickness, soil.Nitrogen.NH4Units, bd);
                soil.Nitrogen.NH4Units = Nitrogen.NUnitsEnum.ppm;
            }

            // Convert analysis.
            if (soil.Analysis != null)
            {
                soil.Analysis.PH = PHWater(soil.Analysis.PH, soil.Analysis.PHUnits);
                soil.Analysis.PHUnits = Analysis.PHUnitsEnum.Water;
            }

            // Convert all samples.
            if (soil.Samples != null)
            {
                foreach (Sample sample in soil.Samples)
                {
                    // Convert sw units to volumetric.
                    if (sample.SW != null)
                        sample.SW = SWVolumetric(sample, soil);
                    sample.SWUnits = Sample.SWUnitsEnum.Volumetric;

                    // Convert no3 units to ppm.
                    if (sample.NO3 != null)
                    {
                        double[] bd = LayerStructure.BDMapped(soil, sample.Thickness);
                        sample.NO3 = Nppm(sample.NO3, sample.Thickness, sample.NO3Units, bd);
                    }
                    sample.NO3Units = Nitrogen.NUnitsEnum.ppm;

                    // Convert nh4 units to ppm.
                    if (sample.NH4 != null)
                    {
                        double[] bd = LayerStructure.BDMapped(soil, sample.Thickness);
                        sample.NH4 = Nppm(sample.NH4, sample.Thickness, sample.NH4Units, bd);
                    }
                    sample.NH4Units = Nitrogen.NUnitsEnum.ppm;

                    // Convert OC to total (%)
                    if (sample.OC != null)
                        sample.OC = OCTotalPercent(sample.OC, sample.OCUnits);
                    sample.OCUnits = SoilOrganicMatter.OCUnitsEnum.Total;

                    // Convert PH to water.
                    if (sample.PH != null)
                        sample.PH = PHWater(sample.PH, sample.PHUnits);
                    sample.PHUnits = Analysis.PHUnitsEnum.Water;
                }
            }

        }
Example #38
0
        /// <summary>
        /// Calculate and return a predicted LL from the specified A and B values.
        /// </summary>
        /// <param name="soil">The soil.</param>
        /// <param name="A">a.</param>
        /// <param name="B">The b.</param>
        /// <returns></returns>
        private static double[] PredictedLL(Soil soil, double[] A, double B)
        {
            double[] LL15 = LayerStructure.LL15Mapped(soil, PredictedThickness);
            double[] DUL = LayerStructure.DULMapped(soil, PredictedThickness);
            double[] LL = new double[PredictedThickness.Length];
            for (int i = 0; i != PredictedThickness.Length; i++)
            {
                double DULPercent = DUL[i] * 100.0;
                LL[i] = DULPercent * (A[i] + B * DULPercent);
                LL[i] /= 100.0;

                // Bound the predicted LL values.
                LL[i] = Math.Max(LL[i], LL15[i]);
                LL[i] = Math.Min(LL[i], DUL[i]);
            }

            //  make the top 3 layers the same as the top 3 layers of LL15
            if (LL.Length >= 3)
            {
                LL[0] = LL15[0];
                LL[1] = LL15[1];
                LL[2] = LL15[2];
            }
            return LL;
        }
Example #39
0
 /// <summary>Return the plant available water CAPACITY of the soil. Units: mm</summary>
 /// <param name="soil">The soil to calculate PAWC for.</param>
 public static double[] OfSoilmm(Soil soil)
 {
     double[] pawc = OfSoil(soil);
     return(MathUtilities.Multiply(pawc, soil.Water.Thickness));
 }
Example #40
0
        /// <summary>Removes the samples from the specified soil, copying data to other soil components.</summary>
        /// <param name="soil">The soil.</param>
        /// <exception cref="System.Exception">Cannot fold a sample into the Water component. Thicknesses are different.</exception>
        private static void RemoveSamples(Soil soil)
        {
            foreach (Sample sample in soil.Samples)
            {
                // Make sure the thicknesses are the same.
                if (!MathUtilities.AreEqual(sample.Thickness, soil.Water.Thickness))
                    throw new Exception("Cannot fold a sample into the Water component. Thicknesses are different.");

                if (sample.SW != null)
                    soil.Water.SW = sample.SW;

                if (sample.NO3 != null)
                {
                    if (soil.Nitrogen == null)
                    {
                        soil.Nitrogen = new Nitrogen();
                        soil.Nitrogen.Thickness = sample.Thickness;
                    }
                    soil.Nitrogen.NO3 = sample.NO3;
                    MathUtilities.ReplaceMissingValues(soil.Nitrogen.NO3, 0.01);
                }

                if (sample.NH4 != null)
                {
                    if (soil.Nitrogen == null)
                    {
                        soil.Nitrogen = new Nitrogen();
                        soil.Nitrogen.Thickness = sample.Thickness;
                    }
                    soil.Nitrogen.NH4 = sample.NH4;
                    MathUtilities.ReplaceMissingValues(soil.Nitrogen.NH4, 0.01);
                }

                if (sample.OC != null)
                {
                    double[] values = soil.SoilOrganicMatter.OC;
                    double[] thickness = soil.SoilOrganicMatter.Thickness;
                    OverlaySampleOnTo(sample.OC, sample.Thickness, ref values, ref thickness, 
                                      MathUtilities.LastValue(sample.OC));
                    soil.SoilOrganicMatter.OC = values;
                    soil.SoilOrganicMatter.Thickness = thickness;
                    MathUtilities.ReplaceMissingValues(soil.SoilOrganicMatter.OC, 0.01);
                }
                if (sample.PH != null)
                {
                    double[] values = soil.Analysis.PH;
                    double[] thickness = soil.Analysis.Thickness;
                    OverlaySampleOnTo(sample.PH, sample.Thickness, ref values, ref thickness,
                                      MathUtilities.LastValue(sample.PH));
                    soil.Analysis.PH = values;
                    soil.Analysis.Thickness = thickness;
                    MathUtilities.ReplaceMissingValues(soil.Analysis.PH, 7);
                }

                if (sample.ESP != null)
                {
                    double[] values = soil.Analysis.ESP;
                    double[] thickness = soil.Analysis.Thickness;
                    OverlaySampleOnTo(sample.ESP, sample.Thickness, ref values, ref thickness,
                                      MathUtilities.LastValue(sample.ESP));
                    soil.Analysis.ESP = values;
                    soil.Analysis.Thickness = thickness;
                    MathUtilities.ReplaceMissingValues(soil.Analysis.ESP, 0);
                }

                if (sample.EC != null)
                {
                    double[] values = soil.Analysis.EC;
                    double[] thickness = soil.Analysis.Thickness;
                    OverlaySampleOnTo(sample.EC, sample.Thickness, ref values, ref thickness,
                                      MathUtilities.LastValue(sample.EC));
                    soil.Analysis.EC = values;
                    soil.Analysis.Thickness = thickness;
                    MathUtilities.ReplaceMissingValues(soil.Analysis.EC, 0);
                }

                if (sample.CL != null)
                {
                    double[] values = soil.Analysis.CL;
                    double[] thickness = soil.Analysis.Thickness;
                    OverlaySampleOnTo(sample.CL, sample.Thickness, ref values, ref thickness,
                                      0.0);
                    soil.Analysis.CL = values;
                    soil.Analysis.Thickness = thickness;
                    MathUtilities.ReplaceMissingValues(soil.Analysis.CL, 0);
                }
            }

            soil.Samples.Clear();
        }
Example #41
0
        /// <summary>
        /// Return a predicted SoilCrop for the specified crop name or null if not found.
        /// </summary>
        /// <param name="soil">The soil.</param>
        /// <param name="CropName">Name of the crop.</param>
        /// <returns></returns>
        private static SoilCrop PredictedCrop(Soil soil, string CropName)
        {
            double[] A = null;
            double   B = double.NaN;

            double[] KL = null;

            if (soil.SoilType == null)
            {
                return(null);
            }

            if (soil.SoilType.Equals("Black Vertosol", StringComparison.CurrentCultureIgnoreCase))
            {
                if (CropName.Equals("Cotton", StringComparison.CurrentCultureIgnoreCase))
                {
                    A  = BlackVertosol.CottonA;
                    B  = BlackVertosol.CottonB;
                    KL = CottonKL;
                }
                else if (CropName.Equals("Sorghum", StringComparison.CurrentCultureIgnoreCase))
                {
                    A  = BlackVertosol.SorghumA;
                    B  = BlackVertosol.SorghumB;
                    KL = SorghumKL;
                }
                else if (CropName.Equals("Wheat", StringComparison.CurrentCultureIgnoreCase))
                {
                    A  = BlackVertosol.WheatA;
                    B  = BlackVertosol.WheatB;
                    KL = WheatKL;
                }
            }
            else if (soil.SoilType.Equals("Grey Vertosol", StringComparison.CurrentCultureIgnoreCase))
            {
                if (CropName.Equals("Cotton", StringComparison.CurrentCultureIgnoreCase))
                {
                    A  = GreyVertosol.CottonA;
                    B  = GreyVertosol.CottonB;
                    KL = CottonKL;
                }
                else if (CropName.Equals("Sorghum", StringComparison.CurrentCultureIgnoreCase))
                {
                    A  = GreyVertosol.SorghumA;
                    B  = GreyVertosol.SorghumB;
                    KL = SorghumKL;
                }
                else if (CropName.Equals("Wheat", StringComparison.CurrentCultureIgnoreCase))
                {
                    A  = GreyVertosol.WheatA;
                    B  = GreyVertosol.WheatB;
                    KL = WheatKL;
                }
                else if (CropName.Equals("Barley", StringComparison.CurrentCultureIgnoreCase))
                {
                    A  = GreyVertosol.BarleyA;
                    B  = GreyVertosol.BarleyB;
                    KL = BarleyKL;
                }
                else if (CropName.Equals("Chickpea", StringComparison.CurrentCultureIgnoreCase))
                {
                    A  = GreyVertosol.ChickpeaA;
                    B  = GreyVertosol.ChickpeaB;
                    KL = ChickpeaKL;
                }
                else if (CropName.Equals("Fababean", StringComparison.CurrentCultureIgnoreCase))
                {
                    A  = GreyVertosol.FababeanA;
                    B  = GreyVertosol.FababeanB;
                    KL = FababeanKL;
                }
                else if (CropName.Equals("Mungbean", StringComparison.CurrentCultureIgnoreCase))
                {
                    A  = GreyVertosol.MungbeanA;
                    B  = GreyVertosol.MungbeanB;
                    KL = MungbeanKL;
                }
            }


            if (A == null)
            {
                return(null);
            }

            double[] LL = PredictedLL(soil, A, B);
            LL = LayerStructure.MapConcentration(LL, PredictedThickness, soil.Water.Thickness, LL.Last());
            KL = LayerStructure.MapConcentration(KL, PredictedThickness, soil.Water.Thickness, KL.Last());
            double[] XF       = LayerStructure.MapConcentration(PredictedXF, PredictedThickness, soil.Water.Thickness, PredictedXF.Last());
            string[] Metadata = StringUtilities.CreateStringArray("Estimated", soil.Water.Thickness.Length);

            return(new SoilCrop()
            {
                Name = CropName,
                Thickness = soil.Water.Thickness,
                LL = LL,
                LLMetadata = Metadata,
                KL = KL,
                KLMetadata = Metadata,
                XF = XF,
                XFMetadata = Metadata
            });
        }
Example #42
0
 /// <summary>Return the index of the layer that contains the specified depth.</summary>
 /// <param name="soil">The soil</param>
 /// <param name="depth">The depth to search for.</param>
 /// <returns></returns>
 static public int FindLayerIndex(Soil soil, double depth)
 {
     return Array.FindIndex(ToCumThickness(soil.Water.Thickness), d => d > depth);
 }
Example #43
0
        public void TestRunoff()
        {
            SoilModel soil = new SoilModel();

            APSIM.Shared.Soils.Soil soilProperties = Setup();
            APSIMReadySoil.Create(soilProperties);

            MockWeather weather = new MockWeather();

            weather.Rain = 100;

            MockIrrigation irrigation = new MockIrrigation();

            irrigation.IrrigationApplied = 0;

            MockSurfaceOrganicMatter surfaceOrganicMatter = new MockSurfaceOrganicMatter();

            surfaceOrganicMatter.Cover = 0.1;

            CNReductionForCover reductionForCover = new CNReductionForCover();
            List <ICanopy>      canopies          = new List <ICanopy>();

            CNReductionForTillage reductionForTillage = new CNReductionForTillage();

            RunoffModel runoff = new RunoffModel();

            runoff.CN2Bare = 70;

            // setup links
            SetLink(soil, "properties", soilProperties);
            SetLink(soil, "runoffModel", runoff);
            SetLink(soil, "weather", weather);
            SetLink(soil, "irrigation", irrigation);
            SetLink(runoff, "soil", soil);
            SetLink(runoff, "reductionForCover", reductionForCover);
            SetLink(runoff, "reductionForTillage", reductionForTillage);
            SetLink(reductionForCover, "surfaceOrganicMatter", surfaceOrganicMatter);
            SetLink(reductionForCover, "canopies", canopies);
            SetLink(reductionForTillage, "weather", weather);

            // Empty profile.
            soil.Water = MathUtilities.Multiply(soilProperties.Water.LL15, soilProperties.Water.Thickness);

            // Profile is empty - should be small amount of runoff.
            Assert.IsTrue(MathUtilities.FloatsAreEqual(runoff.Value(), 5.60815));

            // Full profile - should be a lot more runoff.
            soil.Water = MathUtilities.Multiply(soilProperties.Water.DUL, soilProperties.Water.Thickness);
            Assert.IsTrue(MathUtilities.FloatsAreEqual(runoff.Value(), 58.23552));

            // Test CN reduction due to canopy. Tests the Curve Number vs Cover graph.
            // Cover is 10%, reduction is 2.5
            surfaceOrganicMatter.Cover = 0.1;
            Assert.IsTrue(MathUtilities.FloatsAreEqual(reductionForCover.Value(), 2.49999));

            // Cover is 80%, reduction is 20
            surfaceOrganicMatter.Cover = 0.8;
            Assert.IsTrue(MathUtilities.FloatsAreEqual(reductionForCover.Value(), 20.0));

            // Test Runoff vs Rainfall graph i.e. effect of different curve numbers.
            surfaceOrganicMatter.Cover = 0.0;
            runoff.CN2Bare             = 60;
            Assert.IsTrue(MathUtilities.FloatsAreEqual(runoff.Value(), 48.18584));

            runoff.CN2Bare = 75;
            Assert.IsTrue(MathUtilities.FloatsAreEqual(runoff.Value(), 68.16430));

            runoff.CN2Bare = 85;
            Assert.IsTrue(MathUtilities.FloatsAreEqual(runoff.Value(), 81.15006));
        }
Example #44
0
        /// <summary>Removes the initial water.</summary>
        /// <param name="soil">The soil.</param>
        private static void RemoveInitialWater(Soil soil)
        {
            if (soil.InitialWater != null)
            {
                soil.Water.SW = soil.InitialWater.SW(soil);

                // If any sample also has SW then get rid of it. Initial Water takes
                // priority.
                foreach (Sample sample in soil.Samples)
                    sample.SW = null;
            }
            soil.InitialWater = null;            
        }
Example #45
0
        /// <summary>Sets the sample thickness.</summary>
        /// <param name="sample">The sample.</param>
        /// <param name="thickness">The thickness to change the sample to.</param>
        /// <param name="soil">The soil</param>
        private static void SetSampleThickness(Sample sample, double[] thickness, Soil soil)
        {
            if (!MathUtilities.AreEqual(thickness, sample.Thickness))
            {
                sample.Name = sample.Name;
                sample.Date = sample.Date;

                if (sample.SW != null)
                    sample.SW = MapSW(sample.SW, sample.Thickness, thickness, soil);
                if (sample.NH4 != null)
                    sample.NH4 = MapConcentration(sample.NH4, sample.Thickness, thickness, 0.01);
                if (sample.NO3 != null)
                    sample.NO3 = MapConcentration(sample.NO3, sample.Thickness, thickness, 0.01);

                // The elements below will be overlaid over other arrays of values so we want 
                // to have missing values (double.NaN) used at the bottom of the profile.
                
                if (sample.CL != null)
                    sample.CL = MapConcentration(sample.CL, sample.Thickness, thickness, double.NaN, allowMissingValues:true);
                if (sample.EC != null)
                    sample.EC = MapConcentration(sample.EC, sample.Thickness, thickness, double.NaN, allowMissingValues: true);
                if (sample.ESP != null)
                    sample.ESP = MapConcentration(sample.ESP, sample.Thickness, thickness, double.NaN, allowMissingValues: true);
                if (sample.OC != null)
                    sample.OC = MapConcentration(sample.OC, sample.Thickness, thickness, double.NaN, allowMissingValues: true);
                if (sample.PH != null)
                    sample.PH = MapConcentration(sample.PH, sample.Thickness, thickness, double.NaN, allowMissingValues: true);
                sample.Thickness = thickness;
            }
        }
Example #46
0
        /// <summary>Convert soil units to APSIM standard.</summary>
        /// <param name="soil">The soil.</param>
        public static void Convert(Soil soil)
        {
            // Convert soil organic matter OC to total %
            if (soil.SoilOrganicMatter != null)
            {
                soil.SoilOrganicMatter.OC      = OCTotalPercent(soil.SoilOrganicMatter.OC, soil.SoilOrganicMatter.OCUnits);
                soil.SoilOrganicMatter.OCUnits = SoilOrganicMatter.OCUnitsEnum.Total;
            }

            // Convert nitrogen to ppm.
            if (soil.Nitrogen != null)
            {
                double[] bd = LayerStructure.BDMapped(soil, soil.Nitrogen.Thickness);
                soil.Nitrogen.NO3      = Nppm(soil.Nitrogen.NO3, soil.Nitrogen.Thickness, soil.Nitrogen.NO3Units, bd);
                soil.Nitrogen.NO3Units = Nitrogen.NUnitsEnum.ppm;

                soil.Nitrogen.NH4      = Nppm(soil.Nitrogen.NH4, soil.Nitrogen.Thickness, soil.Nitrogen.NH4Units, bd);
                soil.Nitrogen.NH4Units = Nitrogen.NUnitsEnum.ppm;
            }

            // Convert analysis.
            if (soil.Analysis != null)
            {
                soil.Analysis.PH      = PHWater(soil.Analysis.PH, soil.Analysis.PHUnits);
                soil.Analysis.PHUnits = Analysis.PHUnitsEnum.Water;
            }

            // Convert all samples.
            if (soil.Samples != null)
            {
                foreach (Sample sample in soil.Samples)
                {
                    // Convert sw units to volumetric.
                    if (sample.SW != null)
                    {
                        sample.SW = SWVolumetric(sample, soil);
                    }
                    sample.SWUnits = Sample.SWUnitsEnum.Volumetric;

                    // Convert no3 units to ppm.
                    if (sample.NO3 != null)
                    {
                        double[] bd = LayerStructure.BDMapped(soil, sample.Thickness);
                        sample.NO3 = Nppm(sample.NO3, sample.Thickness, sample.NO3Units, bd);
                    }
                    sample.NO3Units = Nitrogen.NUnitsEnum.ppm;

                    // Convert nh4 units to ppm.
                    if (sample.NH4 != null)
                    {
                        double[] bd = LayerStructure.BDMapped(soil, sample.Thickness);
                        sample.NH4 = Nppm(sample.NH4, sample.Thickness, sample.NH4Units, bd);
                    }
                    sample.NH4Units = Nitrogen.NUnitsEnum.ppm;

                    // Convert OC to total (%)
                    if (sample.OC != null)
                    {
                        sample.OC = OCTotalPercent(sample.OC, sample.OCUnits);
                    }
                    sample.OCUnits = SoilOrganicMatter.OCUnitsEnum.Total;

                    // Convert PH to water.
                    if (sample.PH != null)
                    {
                        sample.PH = PHWater(sample.PH, sample.PHUnits);
                    }
                    sample.PHUnits = Analysis.PHUnitsEnum.Water;
                }
            }
        }
        /// <summary>
        /// Sets the soil parameters for the crop types in this paddock
        /// </summary>
        /// <param name="soilConfig">Soil crop parameters</param>
        /// <param name="paddocknode">The paddock node for the paddock</param>
        /// <param name="maxRootDepth">The maximum root depth for any plant allowed on this soil type. mm</param>
        /// <returns></returns>
        private void SetSoilCrops(Soil soilConfig, XmlNode paddocknode, FarmSoilType soilArea)
        {
            XmlNode apsimCompNode;
            CropSpec crop;

            //set the ll, kl, xf values of the crop
            apsimCompNode = paddocknode.SelectSingleNode("system/component[@class=\"Plant.Wheat\"]");
            crop = soilArea.CropRotationList.Find(c => c.Name.Equals("wheat", StringComparison.InvariantCultureIgnoreCase));
            setSoilCrop(apsimCompNode, "wheat", soilConfig, crop);

            apsimCompNode = paddocknode.SelectSingleNode("system/component[@class=\"Plant.Barley\"]");
            crop = soilArea.CropRotationList.Find(c => c.Name.Equals("barley", StringComparison.InvariantCultureIgnoreCase));
            setSoilCrop(apsimCompNode, "barley", soilConfig, crop);

            apsimCompNode = paddocknode.SelectSingleNode("system/component[@class=\"Plant.Canola\"]");
            crop = soilArea.CropRotationList.Find(c => c.Name.Equals("canola", StringComparison.InvariantCultureIgnoreCase));
            setSoilCrop(apsimCompNode, "canola", soilConfig, crop);

            apsimCompNode = paddocknode.SelectSingleNode("system/component[@class=\"Plant.Oats\"]");
            crop = soilArea.CropRotationList.Find(c => c.Name.Equals("oats", StringComparison.InvariantCultureIgnoreCase));
            setSoilCrop(apsimCompNode, "oats", soilConfig, crop);

            apsimCompNode = paddocknode.SelectSingleNode("system/component[@class=\"Plant.ChickPea\"]");
            crop = soilArea.CropRotationList.Find(c => c.Name.Equals("chickpea", StringComparison.InvariantCultureIgnoreCase));
            setSoilCrop(apsimCompNode, "chickpea", soilConfig, crop);

            apsimCompNode = paddocknode.SelectSingleNode("system/component[@class=\"Plant.FieldPea\"]");
            crop = soilArea.CropRotationList.Find(c => c.Name.Equals("fieldpea", StringComparison.InvariantCultureIgnoreCase));
            setSoilCrop(apsimCompNode, "fieldpea", soilConfig, crop);

            apsimCompNode = paddocknode.SelectSingleNode("system/component[@class=\"Plant.Fababean\"]");
            crop = soilArea.CropRotationList.Find(c => c.Name.Equals("fababean", StringComparison.InvariantCultureIgnoreCase));
            setSoilCrop(apsimCompNode, "fababean", soilConfig, crop);

            apsimCompNode = paddocknode.SelectSingleNode("system/component[@class=\"Plant.Lupin\"]");
            crop = soilArea.CropRotationList.Find(c => c.Name.Equals("lupin", StringComparison.InvariantCultureIgnoreCase));
            setSoilCrop(apsimCompNode, "lupin", soilConfig, crop);
            //sorghum
        }
        /// <summary>
        /// Initialise the SOM translator
        /// </summary>
        /// <param name="compNode"></param>
        /// <param name="aSoil"></param>
        private void initSOM_Trans(XmlNode compNode, Soil aSoil, FarmSoilType farmSoil)
        {
            TSDMLValue init = GetTypedInit(compNode, "surfaceom_types");
            bool found;

            // for each crop type in the rotation list there should be a residue item in the translator
            for (int res = 0; res < farmSoil.CropRotationList.Count; res++)
            {
                string cropName = CropPhases.CropFromLanduse(farmSoil.CropRotationList[res].Name);
                if (CropPhases.IsValidCropName(cropName))
                {
                    uint i = 1;
                    found = false;
                    while (!found && (i <= init.count()))
                    {
                        if (init.item(i).asStr() == cropName)
                            found = true;
                        i++;
                    }
                    if (!found)
                    {
                        init.setElementCount(init.count() + 1);
                        init.item(init.count()).setValue(cropName);
                    }
                }
            }
            SetTypedInit(compNode, "surfaceom_types", init);

            //may not need to do this in an already configured simulation
            init = GetTypedInit(compNode, "published_events");
            if (init.count() < 1)
            {
                init.setElementCount(2);
                init.item(1).member("name").setValue(".model.potentialresiduedecompositioncalculated");
                init.item(1).member("connects").setElementCount(1);
                init.item(1).member("connects").item(1).setValue("..nitrogen.model.potentialresiduedecompositioncalculated");
                init.item(2).member("name").setValue(".model.incorpfompool");
                init.item(2).member("connects").setElementCount(1);
                init.item(2).member("connects").item(1).setValue("..nitrogen.model.incorpfompool");
                SetTypedInit(compNode, "published_events", init);
            }
        }
Example #49
0
        /// <summary>Map soil water from one layer structure to another.</summary>
        /// <param name="fromValues">The from values.</param>
        /// <param name="fromThickness">The from thickness.</param>
        /// <param name="toThickness">To thickness.</param>
        /// <param name="soil">The soil.</param>
        /// <returns></returns>
        private static double[] MapSW(double[] fromValues, double[] fromThickness, double[] toThickness, Soil soil)
        {
            if (fromValues == null || fromThickness == null)
                return null;

            // convert from values to a mass basis with a dummy bottom layer.
            List<double> values = new List<double>();
            values.AddRange(fromValues);
            values.Add(MathUtilities.LastValue(fromValues) * 0.8);
            values.Add(MathUtilities.LastValue(fromValues) * 0.4);
            values.Add(0.0);
            List<double> thickness = new List<double>();
            thickness.AddRange(fromThickness);
            thickness.Add(MathUtilities.LastValue(fromThickness));
            thickness.Add(MathUtilities.LastValue(fromThickness));
            thickness.Add(3000);

            // Get the first crop ll or ll15.
            double[] LowerBound;
            if (soil.Water.Crops.Count > 0)
                LowerBound = LLMapped(soil.Water.Crops[0], thickness.ToArray());
            else
                LowerBound = LL15Mapped(soil, thickness.ToArray());
            if (LowerBound == null)
                throw new Exception("Cannot find crop lower limit or LL15 in soil");

            // Make sure all SW values below LastIndex don't go below CLL.
            int bottomLayer = fromThickness.Length - 1;
            for (int i = bottomLayer + 1; i < thickness.Count; i++)
                values[i] = Math.Max(values[i], LowerBound[i]);

            double[] massValues = MathUtilities.Multiply(values.ToArray(), thickness.ToArray());

            // Convert mass back to concentration and return
            double[] newValues = MathUtilities.Divide(MapMass(massValues, thickness.ToArray(), toThickness), toThickness);



            return newValues;
        }
Example #50
0
        public void TestEvaporation()
        {
            MockSoil soil = new MockSoil();

            APSIM.Shared.Soils.Soil soilProperties = Setup();
            APSIMReadySoil.Create(soilProperties);

            MockClock clock = new MockClock();

            clock.Today = new DateTime(2015, 6, 1);

            MockWeather weather = new MockWeather();

            weather.MaxT = 30;
            weather.MinT = 10;
            weather.Rain = 100;
            weather.Radn = 25;

            MockSurfaceOrganicMatter surfaceOrganicMatter = new MockSurfaceOrganicMatter();

            surfaceOrganicMatter.Cover = 0.8;

            List <ICanopy> canopies = new List <ICanopy>();

            EvaporationModel evaporation = new EvaporationModel();

            SetLink(soil, "properties", soilProperties);
            SetLink(evaporation, "soil", soil);
            SetLink(evaporation, "clock", clock);
            SetLink(evaporation, "weather", weather);
            SetLink(evaporation, "canopies", canopies);
            SetLink(evaporation, "surfaceOrganicMatter", surfaceOrganicMatter);

            // Empty profile.
            soil.Water = MathUtilities.Multiply(soilProperties.Water.LL15, soilProperties.Water.Thickness);

            evaporation.Calculate();
            Assert.IsTrue(MathUtilities.FloatsAreEqual(evaporation.Es, 3.00359));

            soil.Infiltration = 0;
            evaporation.Calculate();
            Assert.IsTrue(MathUtilities.FloatsAreEqual(evaporation.Es, 2.20072));

            soil.Infiltration = 0;
            evaporation.Calculate();
            Assert.IsTrue(MathUtilities.FloatsAreEqual(evaporation.Es, 1.57064));

            soil.Infiltration = 0;
            evaporation.Calculate();
            Assert.IsTrue(MathUtilities.FloatsAreEqual(evaporation.Es, 0.96006));

            soil.Infiltration = 0;
            evaporation.Calculate();
            Assert.IsTrue(MathUtilities.FloatsAreEqual(evaporation.Es, 0.75946));

            soil.Infiltration = 0;
            evaporation.Calculate();
            Assert.IsTrue(MathUtilities.FloatsAreEqual(evaporation.Es, 0.64851));

            soil.Infiltration = 100;
            evaporation.Calculate();
            Assert.IsTrue(MathUtilities.FloatsAreEqual(evaporation.Es, 3.00359));

            soil.Infiltration = 0;
            evaporation.Calculate();
            Assert.IsTrue(MathUtilities.FloatsAreEqual(evaporation.Es, 2.20072));
        }
Example #51
0
 /// <summary>AirDry - mapped to the specified layer structure. Units: mm/mm        /// </summary>
 /// <param name="soil">The soil.</param>
 /// <param name="ToThickness">To thickness.</param>
 /// <returns></returns>
 private static double[] AirDryMapped(Soil soil, double[] ToThickness)
 {
     return MapConcentration(soil.Water.AirDry, soil.Water.Thickness, ToThickness, soil.Water.AirDry.Last());
 }
 /// <summary>Sets the soil.</summary>
 /// <param name="soil">The soil.</param>
 public void SetSoil(Soil soil)
 {
     XmlDocument soilDoc = new XmlDocument();
     soilDoc.LoadXml(SoilUtilities.ToXML(soil));
     XmlNode paddockNode = XmlUtilities.Find(simulationXML, "Paddock");
     paddockNode.AppendChild(paddockNode.OwnerDocument.ImportNode(soilDoc.DocumentElement, true));
 }
Example #53
0
        /// <summary>Removes the samples from the specified soil, copying data to other soil components.</summary>
        /// <param name="soil">The soil.</param>
        /// <exception cref="System.Exception">Cannot fold a sample into the Water component. Thicknesses are different.</exception>
        private static void RemoveSamples(Soil soil)
        {
            foreach (Sample sample in soil.Samples)
            {
                // Make sure the thicknesses are the same.
                if (!MathUtilities.AreEqual(sample.Thickness, soil.Water.Thickness))
                {
                    throw new Exception("Cannot fold a sample into the Water component. Thicknesses are different.");
                }

                if (sample.SW != null)
                {
                    soil.Water.SW = sample.SW;
                }

                if (sample.NO3 != null)
                {
                    if (soil.Nitrogen == null)
                    {
                        soil.Nitrogen           = new Nitrogen();
                        soil.Nitrogen.Thickness = sample.Thickness;
                    }
                    soil.Nitrogen.NO3 = sample.NO3;
                    MathUtilities.ReplaceMissingValues(soil.Nitrogen.NO3, 0.01);
                }

                if (sample.NH4 != null)
                {
                    if (soil.Nitrogen == null)
                    {
                        soil.Nitrogen           = new Nitrogen();
                        soil.Nitrogen.Thickness = sample.Thickness;
                    }
                    soil.Nitrogen.NH4 = sample.NH4;
                    MathUtilities.ReplaceMissingValues(soil.Nitrogen.NH4, 0.01);
                }

                if (sample.OC != null)
                {
                    double[] values    = soil.SoilOrganicMatter.OC;
                    double[] thickness = soil.SoilOrganicMatter.Thickness;
                    OverlaySampleOnTo(sample.OC, sample.Thickness, ref values, ref thickness,
                                      MathUtilities.LastValue(sample.OC));
                    soil.SoilOrganicMatter.OC        = values;
                    soil.SoilOrganicMatter.Thickness = thickness;
                    MathUtilities.ReplaceMissingValues(soil.SoilOrganicMatter.OC, 0.01);
                }
                if (sample.PH != null)
                {
                    double[] values    = soil.Analysis.PH;
                    double[] thickness = soil.Analysis.Thickness;
                    OverlaySampleOnTo(sample.PH, sample.Thickness, ref values, ref thickness,
                                      MathUtilities.LastValue(sample.PH));
                    soil.Analysis.PH        = values;
                    soil.Analysis.Thickness = thickness;
                    MathUtilities.ReplaceMissingValues(soil.Analysis.PH, 7);
                }

                if (sample.ESP != null)
                {
                    double[] values    = soil.Analysis.ESP;
                    double[] thickness = soil.Analysis.Thickness;
                    OverlaySampleOnTo(sample.ESP, sample.Thickness, ref values, ref thickness,
                                      MathUtilities.LastValue(sample.ESP));
                    soil.Analysis.ESP       = values;
                    soil.Analysis.Thickness = thickness;
                    MathUtilities.ReplaceMissingValues(soil.Analysis.ESP, 0);
                }

                if (sample.EC != null)
                {
                    double[] values    = soil.Analysis.EC;
                    double[] thickness = soil.Analysis.Thickness;
                    OverlaySampleOnTo(sample.EC, sample.Thickness, ref values, ref thickness,
                                      MathUtilities.LastValue(sample.EC));
                    soil.Analysis.EC        = values;
                    soil.Analysis.Thickness = thickness;
                    MathUtilities.ReplaceMissingValues(soil.Analysis.EC, 0);
                }

                if (sample.CL != null)
                {
                    double[] values    = soil.Analysis.CL;
                    double[] thickness = soil.Analysis.Thickness;
                    OverlaySampleOnTo(sample.CL, sample.Thickness, ref values, ref thickness,
                                      0.0);
                    soil.Analysis.CL        = values;
                    soil.Analysis.Thickness = thickness;
                    MathUtilities.ReplaceMissingValues(soil.Analysis.CL, 0);
                }
            }

            soil.Samples.Clear();
        }
Example #54
0
        /// <summary>Calculates volumetric soil water for the given sample.</summary>
        /// <param name="sample">The sample.</param>
        /// <param name="soil">The soil.</param>
        /// <returns>Volumetric water (mm/mm)</returns>
        private static double[] SWVolumetric(Sample sample, Soil soil)
        {
            if (sample.SWUnits == Sample.SWUnitsEnum.Volumetric || sample.SW == null)
                return sample.SW;
            else
            {
                // convert the numbers
                if (sample.SWUnits == Sample.SWUnitsEnum.Gravimetric)
                {
                    double[] bd = LayerStructure.BDMapped(soil, sample.Thickness);

                    return MathUtilities.Multiply(sample.SW, bd);
                }
                else
                    return MathUtilities.Divide(sample.SW, sample.Thickness); // from mm to mm/mm
            }
        }
Example #55
0
        /// <summary>
        /// Return a list of predicted crop names or an empty string[] if none found.
        /// </summary>
        /// <param name="soil">The soil.</param>
        /// <returns></returns>
        private static void AddPredictedCrops(Soil soil)
        {
            if (soil.SoilType != null)
            {
                string[] predictedCropNames = null;
                if (soil.SoilType.Equals("Black Vertosol", StringComparison.CurrentCultureIgnoreCase))
                    predictedCropNames = BlackVertosolCropList;
                else if (soil.SoilType.Equals("Grey Vertosol", StringComparison.CurrentCultureIgnoreCase))
                    predictedCropNames = GreyVertosolCropList;

                if (predictedCropNames != null)
                {
                    foreach (string cropName in predictedCropNames)
                    {
                        // if a crop parameterisation already exists for this crop then don't add a predicted one.
                        if (soil.Water.Crops.Find(c => c.Name.Equals(cropName, StringComparison.InvariantCultureIgnoreCase)) == null)
                            soil.Water.Crops.Add(PredictedCrop(soil, cropName));
                    }
                }
            }
        }
Example #56
0
 /// <summary>Return the plant available water CAPACITY for the specified crop. Units: mm</summary>
 /// <param name="soil">The soil to calculate PAWC for.</param>
 /// <param name="crop">The crop.</param>
 /// <returns></returns>
 public static double[] OfCropmm(Soil soil, SoilCrop crop)
 {
     double[] pawc = PAWC.OfCrop(soil, crop);
     return(MathUtilities.Multiply(pawc, soil.Water.Thickness));
 }
Example #57
0
        /// <summary>Map soil water from one layer structure to another.</summary>
        /// <param name="fromValues">The from values.</param>
        /// <param name="fromThickness">The from thickness.</param>
        /// <param name="toThickness">To thickness.</param>
        /// <param name="soil">The soil.</param>
        /// <returns></returns>
        private static double[] MapSW(double[] fromValues, double[] fromThickness, double[] toThickness, Soil soil)
        {
            if (fromValues == null || fromThickness == null)
            {
                return(null);
            }

            // convert from values to a mass basis with a dummy bottom layer.
            List <double> values = new List <double>();

            values.AddRange(fromValues);
            values.Add(MathUtilities.LastValue(fromValues) * 0.8);
            values.Add(MathUtilities.LastValue(fromValues) * 0.4);
            values.Add(0.0);
            List <double> thickness = new List <double>();

            thickness.AddRange(fromThickness);
            thickness.Add(MathUtilities.LastValue(fromThickness));
            thickness.Add(MathUtilities.LastValue(fromThickness));
            thickness.Add(3000);

            // Get the first crop ll or ll15.
            double[] LowerBound;
            if (soil.Water.Crops.Count > 0)
            {
                LowerBound = LLMapped(soil.Water.Crops[0], thickness.ToArray());
            }
            else
            {
                LowerBound = LL15Mapped(soil, thickness.ToArray());
            }
            if (LowerBound == null)
            {
                throw new Exception("Cannot find crop lower limit or LL15 in soil");
            }

            // Make sure all SW values below LastIndex don't go below CLL.
            int bottomLayer = fromThickness.Length - 1;

            for (int i = bottomLayer + 1; i < thickness.Count; i++)
            {
                values[i] = Math.Max(values[i], LowerBound[i]);
            }

            double[] massValues = MathUtilities.Multiply(values.ToArray(), thickness.ToArray());

            // Convert mass back to concentration and return
            double[] newValues = MathUtilities.Divide(MapMass(massValues, thickness.ToArray(), toThickness), toThickness);



            return(newValues);
        }
Example #58
0
        /// <summary>
        /// Return a predicted SoilCrop for the specified crop name or null if not found.
        /// </summary>
        /// <param name="soil">The soil.</param>
        /// <param name="CropName">Name of the crop.</param>
        /// <returns></returns>
        private static SoilCrop PredictedCrop(Soil soil, string CropName)
        {
            double[] A = null;
            double B = double.NaN;
            double[] KL = null;

            if (soil.SoilType == null)
                return null;

            if (soil.SoilType.Equals("Black Vertosol", StringComparison.CurrentCultureIgnoreCase))
            {
                if (CropName.Equals("Cotton", StringComparison.CurrentCultureIgnoreCase))
                {
                    A = BlackVertosol.CottonA;
                    B = BlackVertosol.CottonB;
                    KL = CottonKL;
                }
                else if (CropName.Equals("Sorghum", StringComparison.CurrentCultureIgnoreCase))
                {
                    A = BlackVertosol.SorghumA;
                    B = BlackVertosol.SorghumB;
                    KL = SorghumKL;
                }
                else if (CropName.Equals("Wheat", StringComparison.CurrentCultureIgnoreCase))
                {
                    A = BlackVertosol.WheatA;
                    B = BlackVertosol.WheatB;
                    KL = WheatKL;
                }
            }
            else if (soil.SoilType.Equals("Grey Vertosol", StringComparison.CurrentCultureIgnoreCase))
            {
                if (CropName.Equals("Cotton", StringComparison.CurrentCultureIgnoreCase))
                {
                    A = GreyVertosol.CottonA;
                    B = GreyVertosol.CottonB;
                    KL = CottonKL;
                }
                else if (CropName.Equals("Sorghum", StringComparison.CurrentCultureIgnoreCase))
                {
                    A = GreyVertosol.SorghumA;
                    B = GreyVertosol.SorghumB;
                    KL = SorghumKL;
                }
                else if (CropName.Equals("Wheat", StringComparison.CurrentCultureIgnoreCase))
                {
                    A = GreyVertosol.WheatA;
                    B = GreyVertosol.WheatB;
                    KL = WheatKL;
                }
                else if (CropName.Equals("Barley", StringComparison.CurrentCultureIgnoreCase))
                {
                    A = GreyVertosol.BarleyA;
                    B = GreyVertosol.BarleyB;
                    KL = BarleyKL;
                }
                else if (CropName.Equals("Chickpea", StringComparison.CurrentCultureIgnoreCase))
                {
                    A = GreyVertosol.ChickpeaA;
                    B = GreyVertosol.ChickpeaB;
                    KL = ChickpeaKL;
                }
                else if (CropName.Equals("Fababean", StringComparison.CurrentCultureIgnoreCase))
                {
                    A = GreyVertosol.FababeanA;
                    B = GreyVertosol.FababeanB;
                    KL = FababeanKL;
                }
                else if (CropName.Equals("Mungbean", StringComparison.CurrentCultureIgnoreCase))
                {
                    A = GreyVertosol.MungbeanA;
                    B = GreyVertosol.MungbeanB;
                    KL = MungbeanKL;
                }
            }


            if (A == null)
                return null;

            double[] LL = PredictedLL(soil, A, B);
            LL = LayerStructure.MapConcentration(LL, PredictedThickness, soil.Water.Thickness, LL.Last());
            KL = LayerStructure.MapConcentration(KL, PredictedThickness, soil.Water.Thickness, KL.Last());
            double[] XF = LayerStructure.MapConcentration(PredictedXF, PredictedThickness, soil.Water.Thickness, PredictedXF.Last());
            string[] Metadata = StringUtilities.CreateStringArray("Estimated", soil.Water.Thickness.Length);

            return new SoilCrop()
            {
                Name = CropName,
                Thickness = soil.Water.Thickness,
                LL = LL,
                LLMetadata = Metadata,
                KL = KL,
                KLMetadata = Metadata,
                XF = XF,
                XFMetadata = Metadata
            };
        }
Example #59
0
 /// <summary>Drained upper limit - mapped to the specified layer structure. Units: mm/mm        /// </summary>
 /// <param name="soil">The soil.</param>
 /// <param name="ToThickness">To thickness.</param>
 /// <returns></returns>
 internal static double[] DULMapped(Soil soil, double[] ToThickness)
 {
     return(MapConcentration(soil.Water.DUL, soil.Water.Thickness, ToThickness, soil.Water.DUL.Last()));
 }
        /// <summary>
        /// Initialise the Soil water translator
        /// </summary>
        /// <param name="compNode"></param>
        /// <param name="aSoil"></param>
        private void initSoilWat_Trans(XmlNode compNode, Soil aSoil, FarmSoilType farmSoil)
        {
            TSDMLValue init = GetTypedInit(compNode, "psd");
            init.member("sand").setElementCount((uint)aSoil.SoilWater.Thickness.Length);
            init.member("clay").setElementCount((uint)aSoil.SoilWater.Thickness.Length);
            double value;
            for (uint x = 0; x <= aSoil.SoilWater.Thickness.Length - 1; x++)
            {
                if ((aSoil.Analysis.ParticleSizeSand != null) && (aSoil.Analysis.ParticleSizeSand.Length > x))
                {
                    value = aSoil.Analysis.ParticleSizeSand[x];
                    if (value.Equals(double.NaN))
                        value = 0.0;                            // probably should be interpolated from any existing values
                    init.member("sand").item(x + 1).setValue(value * 0.01);

                    value = aSoil.Analysis.ParticleSizeClay[x];
                    if (value.Equals(double.NaN))
                        value = 0.0;
                    init.member("clay").item(x + 1).setValue(value * 0.01);
                }
                else
                {
                    // ## not suitable but it will allow the simulation to run
                    init.member("sand").item(x + 1).setValue(0.0);
                    init.member("clay").item(x + 1).setValue(0.0);
                }
            }
            SetTypedInit(compNode, "psd", init);

            // configure the published events for this translator so each crop component in the rotation is supported
            init = GetTypedInit(compNode, "published_events");
            
            // if not the correct number of published events
            if (init.count() < 2)
            {
                init.setElementCount(2);
                init.item(1).member("name").setValue(".model.new_profile");
                init.item(1).member("connects").setElementCount(1);
                init.item(1).member("connects").item(1).setValue("..nitrogen.model.new_profile");

                init.item(2).member("name").setValue(".model.nitrogenchanged");
                init.item(2).member("connects").setElementCount(1);
                init.item(2).member("connects").item(1).setValue("..nitrogen.model.nitrogenchanged");
            }

            // now ensure that the connections go to each crop component
            // there should be a connection item for every plant component in the paddock
            TTypedValue connects = null;
            uint idx = 1;
            // find the correct item in the published events array
            while ((connects == null) && idx <= 2)
            {
                if (init.item(idx).member("name").asStr() == ".model.new_profile")
                    connects = init.item(idx).member("connects");                       
                idx++;
            }

            string connectionName;
            // for each item in the crop rotation list
            for (int crop = 0; crop < farmSoil.CropRotationList.Count; crop++)
            {
                string landuse = farmSoil.CropRotationList[crop].Name;
                string cropName = CropPhases.CropFromLanduse(landuse);
                if (CropPhases.IsValidCropName(cropName))
                {
                    idx = 1;
                    bool found = false;
                    while (!found && (idx <= connects.count()))
                    {
                        connectionName = connects.item(idx).asStr().ToLower();
                        if (connectionName.Contains(cropName.ToLower()))
                            found = true;
                        idx++;
                    }

                    //if not found int the connections then add it to the list
                    if (!found)
                    {
                        connects.setElementCount(connects.count() + 1);
                        connects.item(connects.count()).setValue(".." + cropName + ".model.new_profile");
                    }
                }
            }
            SetTypedInit(compNode, "published_events", init);
        }