예제 #1
0
        /// <summary>
        /// Retrieves soil types from ApSoil
        /// Configures any missing crop ll, kl values
        /// </summary>
        /// <param name="simulation"></param>
        /// <param name="apsoilService"></param>
        /// <returns></returns>
        public static void DoSoils(AusFarmSpec simulation)
        {
            APSOIL.Service apsoilService = null;
            Soil           soil;

            for (int i = 0; i < simulation.OnFarmSoilTypes.Count; i++)
            {
                FarmSoilType soilType = simulation.OnFarmSoilTypes[i];
                soil = soilType.SoilDescr;
                if (soil == null)
                {
                    // Look for a <SoilName> and if found go get the soil from the Apsoil web service.
                    if (apsoilService == null)
                    {
                        apsoilService = new APSOIL.Service();
                    }
                    string soilXml = apsoilService.SoilXML(soilType.SoilPath);
                    if (soilXml == string.Empty)
                    {
                        throw new Exception("Cannot find soil: " + soilType.SoilPath);
                    }

                    soil = SoilUtilities.FromXML(soilXml);
                }

                // Other crop types not listed here will have their ll, kll, xf values calculated later

                // Remove any initwater nodes.
                soil.InitialWater = null;

                foreach (Sample sample in soil.Samples)
                {
                    CheckSample(soil, sample);
                }

                // get rid of <soiltype> from the soil
                // this is necessary because NPD uses this field and puts in really long
                // descriptive classifications. Soiln2 bombs with an FString internal error.
                soil.SoilType = "";

                // Set the soil name to 'soil'
                //soil.Name = "Soil";
                soilType.SoilDescr = soil;  //store the changed description
            }
        }
        /// <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>
        /// Configure the pasture components in the paddock. Set the rooting depths.
        /// </summary>
        /// <param name="defaultPaddock"></param>
        /// <param name="depth">The cumulative soil depth</param>
        /// <param name="paddocknode">The padddock to set</param>
        private void SetPastureComponents(FarmPaddockType defaultPaddock, double depth, XmlNode paddocknode, FarmSoilType soilArea)
        {
            XmlNodeList pastureNodes = paddocknode.SelectNodes("component[attribute::class=\"Pasture\"]");
            foreach (XmlNode pastureNode in pastureNodes)
            {
                // get the current rooting depth from the pasture component in the simulation
                string sDepth = GetValue(pastureNode, "max_rtdep");
                double maxRtDep = (sDepth.Length > 0) ? Convert.ToDouble(sDepth) : 0;
                string simCompName = XmlUtilities.NameAttr(pastureNode);

                // find one that matches in the cropping rotation list and see if it specifies a new depth
                CropSpec pastureCrop = soilArea.CropRotationList.Find(c => c.Name.Equals(simCompName, StringComparison.InvariantCultureIgnoreCase));
                if (pastureCrop.MaxRootDepth > 0)
                {
                    maxRtDep = pastureCrop.MaxRootDepth;
                    SetValue(pastureNode, "max_rtdep", Math.Min(maxRtDep, depth * 0.95));       // allow up to 95% of soil depth
                }
                else
                {
                    if (maxRtDep > (depth * 0.95))                                              // this won't need setting if it is less than the limit
                        SetValue(pastureNode, "max_rtdep", Math.Min(maxRtDep, depth * 0.95));   // allow up to 95% of soil depth
                }
            }
        }
        /// <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);
            }
        }
        /// <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);
        }