Beispiel #1
0
        /// <summary>Add in reset management events to the APSIM spec for the specified paddock.</summary>
        /// <param name="paddock">The paddock.</param>
        /// <param name="simulation">The simulation to add the management operations to.</param>
        /// <exception cref="System.Exception">Cannot find soil water reset date</exception>
        /// <exception cref="Exception">Cannot find soil water reset date</exception>
        private static void AddResetDatesToManagement(Paddock paddock, APSIMSpecification simulation)
        {
            // Reset
            if (paddock.SoilWaterSampleDate != DateTime.MinValue)
            {
                if (paddock.SoilNitrogenSampleDate == DateTime.MinValue)
                {
                    paddock.SoilNitrogenSampleDate = paddock.SoilWaterSampleDate;
                }

                Sow sowing = YieldProphetUtility.GetCropBeingSown(paddock.Management);
                if (sowing != null && sowing.Date != DateTime.MinValue)
                {
                    List <Management> resetActions = new List <Management>();

                    // reset at sowing if the sample dates are after sowing.
                    if (paddock.SoilWaterSampleDate > sowing.Date)
                    {
                        resetActions.Add(new ResetWater()
                        {
                            Date = sowing.Date
                        });
                        resetActions.Add(new ResetSurfaceOrganicMatter()
                        {
                            Date = sowing.Date
                        });
                    }
                    if (paddock.SoilNitrogenSampleDate > sowing.Date)
                    {
                        resetActions.Add(new ResetNitrogen()
                        {
                            Date = sowing.Date
                        });
                    }

                    // reset on the sample dates.
                    resetActions.Add(new ResetWater()
                    {
                        Date = paddock.SoilWaterSampleDate
                    });
                    resetActions.Add(new ResetSurfaceOrganicMatter()
                    {
                        Date = paddock.SoilWaterSampleDate
                    });
                    resetActions.Add(new ResetNitrogen()
                    {
                        Date = paddock.SoilNitrogenSampleDate
                    });

                    simulation.Management.InsertRange(0, resetActions);
                }
            }
        }
Beispiel #2
0
        /// <summary>Checks the soil sample.</summary>
        /// <param name="parentSoil">The parent soil.</param>
        /// <param name="sample">The sample.</param>
        /// <param name="sowing">The sowing rule</param>
        private static void CheckSample(Soil parentSoil, Sample sample, Sow sowing)
        {
            // Do some checking of NO3 / NH4
            CheckMissingValuesAreNaN(sample.NO3);
            CheckMissingValuesAreNaN(sample.NH4);
            CheckMissingValuesAreNaN(sample.OC);
            CheckMissingValuesAreNaN(sample.EC);
            CheckMissingValuesAreNaN(sample.PH);

            if (sample.SW != null && sample.SW.Length > 0)
            {
                // Check to make sure SW is >= CLL for layers below top layer
                int cropIndex = parentSoil.Water.Crops.FindIndex(crop => crop.Name.Equals(sowing.Crop, StringComparison.CurrentCultureIgnoreCase));
                if (cropIndex != -1)
                {
                    double[] CLLVol       = parentSoil.Water.Crops[cropIndex].LL;
                    double[] CLLVolMapped = LayerStructure.MapConcentration(CLLVol, parentSoil.Water.Thickness,
                                                                            sample.Thickness, 0);

                    if (sample.SWUnits == Sample.SWUnitsEnum.Gravimetric)
                    {
                        // Sample SW is in gravimetric
                        double[] BDMapped = LayerStructure.MapConcentration(parentSoil.Water.BD, parentSoil.Water.Thickness,
                                                                            sample.Thickness, parentSoil.Water.BD.Last());
                        double[] CLLGrav = MathUtilities.Divide(CLLVolMapped, BDMapped); // vol to grav
                        double[] SWVol   = MathUtilities.Multiply(sample.SW, BDMapped);  // grav to vol
                        for (int i = 1; i < sample.Thickness.Length; i++)
                        {
                            if (SWVol[i] < CLLVolMapped[i])
                            {
                                sample.SW[i] = CLLGrav[i];
                            }
                        }
                    }
                    else
                    {
                        // Sample SW is in volumetric
                        for (int i = 1; i < sample.Thickness.Length; i++)
                        {
                            if (sample.SW[i] < CLLVolMapped[i])
                            {
                                sample.SW[i] = CLLVolMapped[i];
                            }
                        }
                    }
                }
            }
        }
Beispiel #3
0
        /// <summary>Do all soil related settings.</summary>
        /// <param name="simulation">The specification to use</param>
        /// <param name="workingFolder">The folder where files shoud be created.</param>
        private static void DoSoil(APSIMSpecification simulation, string workingFolder)
        {
            Soil soil;

            if (simulation.Soil == null)
            {
                if (simulation.SoilPath.StartsWith("<Soil"))
                {
                    // Soil and Landscape grid
                    XmlDocument doc = new XmlDocument();
                    doc.LoadXml(simulation.SoilPath);
                    soil = XmlUtilities.Deserialise(doc.DocumentElement, typeof(Soil)) as Soil;
                }
                else if (simulation.SoilPath.StartsWith("http"))
                {
                    // Soil and Landscape grid
                    string xml;
                    using (var client = new WebClient())
                    {
                        xml = client.DownloadString(simulation.SoilPath);
                    }
                    XmlDocument doc = new XmlDocument();
                    doc.LoadXml(xml);
                    List <XmlNode> soils = XmlUtilities.ChildNodes(doc.DocumentElement, "Soil");
                    if (soils.Count == 0)
                    {
                        throw new Exception("Cannot find soil in Soil and Landscape Grid");
                    }
                    soil = XmlUtilities.Deserialise(soils[0], typeof(Soil)) as Soil;
                }
                else
                {
                    // Apsoil web service.
                    APSOIL.Service apsoilService = new APSOIL.Service();
                    string         soilXml       = apsoilService.SoilXML(simulation.SoilPath.Replace("\r\n", ""));
                    if (soilXml == string.Empty)
                    {
                        throw new Exception("Cannot find soil: " + simulation.SoilPath);
                    }
                    soil = SoilUtilities.FromXML(soilXml);
                }
            }
            else
            {
                // Just use the soil we already have
                soil = simulation.Soil;
            }

            // Make sure we have a soil crop parameterisation. If not then try creating one
            // based on wheat.
            Sow sowing = YieldProphetUtility.GetCropBeingSown(simulation.Management);

            string[] cropNames = soil.Water.Crops.Select(c => c.Name).ToArray();
            if (cropNames.Length == 0)
            {
                throw new Exception("Cannot find any crop parameterisations in soil: " + simulation.SoilPath);
            }

            if (sowing != null && !StringUtilities.Contains(cropNames, sowing.Crop))
            {
                SoilCrop wheat = soil.Water.Crops.Find(c => c.Name.Equals("wheat", StringComparison.InvariantCultureIgnoreCase));
                if (wheat == null)
                {
                    // Use the first crop instead.
                    wheat = soil.Water.Crops[0];
                }

                SoilCrop newSoilCrop = new SoilCrop();
                newSoilCrop.Name      = sowing.Crop;
                newSoilCrop.Thickness = wheat.Thickness;
                newSoilCrop.LL        = wheat.LL;
                newSoilCrop.KL        = wheat.KL;
                newSoilCrop.XF        = wheat.XF;
                soil.Water.Crops.Add(newSoilCrop);
            }

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

            // Transfer the simulation samples to the soil
            if (simulation.Samples != null)
            {
                soil.Samples = simulation.Samples;
            }

            if (simulation.InitTotalWater != 0)
            {
                soil.InitialWater = new InitialWater();
                soil.InitialWater.PercentMethod = InitialWater.PercentMethodEnum.FilledFromTop;

                double pawc;
                if (sowing == null || sowing.Crop == null)
                {
                    pawc = MathUtilities.Sum(PAWC.OfSoilmm(soil));
                    soil.InitialWater.RelativeTo = "LL15";
                }
                else
                {
                    SoilCrop crop = soil.Water.Crops.Find(c => c.Name.Equals(sowing.Crop, StringComparison.InvariantCultureIgnoreCase));
                    pawc = MathUtilities.Sum(PAWC.OfCropmm(soil, crop));
                    soil.InitialWater.RelativeTo = crop.Name;
                }

                soil.InitialWater.FractionFull = Convert.ToDouble(simulation.InitTotalWater) / pawc;
            }

            if (simulation.InitTotalNitrogen != 0)
            {
                // Add in a sample.
                Sample nitrogenSample = new Sample();
                nitrogenSample.Name = "NitrogenSample";
                soil.Samples.Add(nitrogenSample);
                nitrogenSample.Thickness = new double[] { 150, 150, 3000 };
                nitrogenSample.NO3Units  = Nitrogen.NUnitsEnum.kgha;
                nitrogenSample.NH4Units  = Nitrogen.NUnitsEnum.kgha;
                nitrogenSample.NO3       = new double[] { 6.0, 2.1, 0.1 };
                nitrogenSample.NH4       = new double[] { 0.5, 0.1, 0.1 };
                nitrogenSample.OC        = new double[] { double.NaN, double.NaN, double.NaN };
                nitrogenSample.EC        = new double[] { double.NaN, double.NaN, double.NaN };
                nitrogenSample.PH        = new double[] { double.NaN, double.NaN, double.NaN };

                double Scale = Convert.ToDouble(simulation.InitTotalNitrogen) / MathUtilities.Sum(nitrogenSample.NO3);
                nitrogenSample.NO3 = MathUtilities.Multiply_Value(nitrogenSample.NO3, Scale);
            }

            // Add in soil temperature. Needed for Aflatoxin risk.
            soil.SoilTemperature = new SoilTemperature();
            soil.SoilTemperature.BoundaryLayerConductance = 15;
            soil.SoilTemperature.Thickness = new double[] { 2000 };
            soil.SoilTemperature.InitialSoilTemperature = new double[] { 22 };
            if (soil.Analysis.ParticleSizeClay == null)
            {
                soil.Analysis.ParticleSizeClay = MathUtilities.CreateArrayOfValues(60, soil.Analysis.Thickness.Length);
            }
            InFillMissingValues(soil.Analysis.ParticleSizeClay);

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

            Defaults.FillInMissingValues(soil);

            // Correct the CONA / U parameters depending on LAT/LONG
            CorrectCONAU(simulation, soil, workingFolder);

            // 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 = null;

            // Set the soil name to 'soil'
            soil.Name = "Soil";

            simulation.Soil = soil;
        }
Beispiel #4
0
        /// <summary>Converts the paddock XML.</summary>
        /// <param name="paddock">The paddock.</param>
        /// <exception cref="System.Exception">Bad paddock name:  + name</exception>
        private static Paddock CreateSimulationSpec(XmlNode paddock, string baseFolder)
        {
            Paddock simulation = new Paddock();

            string name      = XmlUtilities.NameAttr(paddock);
            string delimiter = "^";
            int    posCaret  = name.IndexOf(delimiter);

            if (posCaret == -1)
            {
                throw new Exception("Bad paddock name: " + name);
            }

            string remainder = StringUtilities.SplitOffAfterDelimiter(ref name, delimiter);
            string growerName;
            string paddockName = StringUtilities.SplitOffAfterDelimiter(ref remainder, delimiter);

            if (paddockName == string.Empty)
            {
                growerName  = name;
                paddockName = remainder;
            }
            else
            {
                growerName = remainder;
            }

            // Give the paddock a name.
            string fullName = string.Format("{0}^{1}^{2}", GetDate(paddock, "SowDateFull").Year, growerName, paddockName);

            simulation.Name = fullName;

            // Set the report date.
            simulation.NowDate = GetDate(paddock.ParentNode, "TodayDateFull");
            if (simulation.NowDate == DateTime.MinValue)
            {
                simulation.NowDate = DateTime.Now;
            }

            // Store any rainfall data in the simulation.
            string rainfallSource = GetString(paddock, "RainfallSource");

            if (rainfallSource != "Weather station")
            {
                string rainFileName = GetString(paddock, "RainfallFilename");
                if (rainFileName != string.Empty)
                {
                    string fullFileName = Path.Combine(baseFolder, rainFileName);
                    if (!File.Exists(fullFileName))
                    {
                        throw new Exception("Cannot find file: " + fullFileName);
                    }
                    simulation.ObservedData           = ApsimTextFile.ToTable(fullFileName);
                    simulation.ObservedData.TableName = rainfallSource;
                    if (simulation.ObservedData.Rows.Count == 0)
                    {
                        simulation.ObservedData = null;
                    }
                }
            }
            // Set the reset dates
            simulation.SoilWaterSampleDate    = GetDate(paddock, "ResetDateFull");
            simulation.SoilNitrogenSampleDate = GetDate(paddock, "SoilNitrogenSampleDateFull");

            simulation.StationNumber = GetInteger(paddock, "StationNumber");
            simulation.StationName   = GetString(paddock, "StationName");

            // Create a sowing management
            Sow sowing = new Sow();

            simulation.Management.Add(sowing);
            sowing.Date          = GetDate(paddock, "SowDateFull");
            sowing.EmergenceDate = GetDate(paddock, "EmergenceDateFull");
            sowing.Crop          = GetString(paddock, "Crop");
            sowing.Cultivar      = GetString(paddock, "Cultivar");
            sowing.SkipRow       = GetString(paddock, "SkipRow");
            sowing.SowingDensity = GetInteger(paddock, "SowingDensity");
            sowing.MaxRootDepth  = GetInteger(paddock, "MaxRootDepth") * 10; // cm to mm
            sowing.BedWidth      = GetInteger(paddock, "BedWidth");
            sowing.BedRowSpacing = GetDouble(paddock, "BedRowSpacing");

            // Make sure we have a stubbletype
            simulation.StubbleType = GetString(paddock, "StubbleType");
            if (simulation.StubbleType == string.Empty || simulation.StubbleType == "None")
            {
                simulation.StubbleType = "Wheat";
            }
            simulation.StubbleMass = GetDouble(paddock, "StubbleMass");
            simulation.Slope       = GetDouble(paddock, "Slope");
            simulation.SlopeLength = GetDouble(paddock, "SlopeLength");
            simulation.UseEC       = GetBoolean(paddock, "UseEC");

            // Fertilise nodes.
            List <XmlNode> fertiliserNodes = XmlUtilities.ChildNodes(paddock, "Fertilise");

            for (int f = 0; f < fertiliserNodes.Count; f++)
            {
                Fertilise fertilise = new Fertilise();
                simulation.Management.Add(fertilise);
                fertilise.Date   = GetDate(fertiliserNodes[f], "FertDateFull");
                fertilise.Amount = GetDouble(fertiliserNodes[f], "FertAmount");
            }

            // Irrigate nodes.
            List <XmlNode> irrigateNodes = XmlUtilities.ChildNodes(paddock, "Irrigate");

            for (int i = 0; i < irrigateNodes.Count; i++)
            {
                Irrigate irrigate = new Irrigate();
                simulation.Management.Add(irrigate);
                irrigate.Date       = GetDate(irrigateNodes[i], "IrrigateDateFull");
                irrigate.Amount     = GetDouble(irrigateNodes[i], "IrrigateAmount");
                irrigate.Efficiency = GetDouble(irrigateNodes[i], "IrrigateEfficiency");
            }

            // Tillage nodes.
            foreach (XmlNode tillageNode in XmlUtilities.ChildNodes(paddock, "Tillage"))
            {
                Tillage tillage = new Tillage();
                simulation.Management.Add(tillage);
                tillage.Date = GetDate(tillageNode, "TillageDateFull");
                string disturbance = GetString(tillageNode, "Disturbance");
                if (disturbance == "Low")
                {
                    tillage.Disturbance = Tillage.DisturbanceEnum.Low;
                }
                else if (disturbance == "Medium")
                {
                    tillage.Disturbance = Tillage.DisturbanceEnum.Medium;
                }
                else
                {
                    tillage.Disturbance = Tillage.DisturbanceEnum.High;
                }
            }

            // Stubble removed nodes.
            foreach (XmlNode stubbleRemovedNode in XmlUtilities.ChildNodes(paddock, "StubbleRemoved"))
            {
                StubbleRemoved stubbleRemoved = new StubbleRemoved();
                simulation.Management.Add(stubbleRemoved);

                stubbleRemoved.Date    = GetDate(stubbleRemovedNode, "StubbleRemovedDateFull");
                stubbleRemoved.Percent = GetDouble(stubbleRemovedNode, "StubbleRemovedAmount");
            }

            // Look for a soil node.
            XmlNode soilNode = XmlUtilities.FindByType(paddock, "Soil");

            if (soilNode != null)
            {
                string testValue = XmlUtilities.Value(soilNode, "Water/Layer/Thickness");
                if (testValue != string.Empty)
                {
                    // old format.
                    soilNode = ConvertSoilNode.Upgrade(soilNode);
                }
            }

            // Fix up soil sample variables.
            Sample sample1 = new Sample
            {
                Name      = "Sample1",
                Thickness = GetArray(paddock, "Sample1Thickness"),
                SW        = GetArray(paddock, "SW")
            };

            if (sample1.SW == null)
            {
                // Really old way of doing samples - they are stored under soil.
                List <XmlNode> sampleNodes = XmlUtilities.ChildNodes(soilNode, "Sample");
                if (sampleNodes.Count > 0)
                {
                    sample1 = XmlUtilities.Deserialise(sampleNodes[0], typeof(Sample)) as Sample;
                }
            }
            else
            {
                sample1.NO3 = GetArray(paddock, "NO3");
                sample1.NH4 = GetArray(paddock, "NH4");
            }

            Sample sample2 = null;

            double[] sample2Thickness = GetArray(paddock, "Sample2Thickness");
            if (sample2Thickness == null)
            {
                // Really old way of doing samples - they are stored under soil.
                List <XmlNode> sampleNodes = XmlUtilities.ChildNodes(soilNode, "Sample");
                if (sampleNodes.Count > 1)
                {
                    sample2 = XmlUtilities.Deserialise(sampleNodes[1], typeof(Sample)) as Sample;
                }
            }
            else
            {
                sample2 = sample1;
                if (!MathUtilities.AreEqual(sample2Thickness, sample1.Thickness))
                {
                    sample2 = new Sample
                    {
                        Name = "Sample2"
                    };
                }
                sample2.OC      = GetArray(paddock, "OC");
                sample2.EC      = GetArray(paddock, "EC");
                sample2.PH      = GetArray(paddock, "PH");
                sample2.CL      = GetArray(paddock, "CL");
                sample2.OCUnits = SoilOrganicMatter.OCUnitsEnum.WalkleyBlack;
                sample2.PHUnits = Analysis.PHUnitsEnum.CaCl2;
            }

            // Make sure we have NH4 values.
            if (sample1.NH4 == null && sample1.NO3 != null)
            {
                string[] defaultValues = StringUtilities.CreateStringArray("0.1", sample1.NO3.Length);
                sample1.NH4 = MathUtilities.StringsToDoubles(defaultValues);
            }

            RemoveNullFieldsFromSample(sample1);
            if (sample2 != null)
            {
                RemoveNullFieldsFromSample(sample2);
            }


            // Fix up <WaterFormat>
            string waterFormatString = GetString(paddock, "WaterFormat");

            if (waterFormatString.Contains("Gravimetric"))
            {
                sample1.SWUnits = Sample.SWUnitsEnum.Gravimetric;
            }
            else
            {
                sample1.SWUnits = Sample.SWUnitsEnum.Volumetric;
            }

            if (MathUtilities.ValuesInArray(sample1.Thickness))
            {
                simulation.Samples.Add(sample1);
            }

            if (sample2 != null && MathUtilities.ValuesInArray(sample2.Thickness) && sample2 != sample1)
            {
                simulation.Samples.Add(sample2);
            }

            // Check for InitTotalWater & InitTotalNitrogen
            simulation.InitTotalWater    = GetDouble(paddock, "InitTotalWater");
            simulation.InitTotalNitrogen = GetDouble(paddock, "InitTotalNitrogen");

            // Check to see if we need to convert the soil structure.
            simulation.SoilPath = GetString(paddock, "SoilName");


            if (soilNode != null)
            {
                // See if there is a 'SWUnits' value. If found then copy it into
                // <WaterFormat>
                string waterFormat = XmlUtilities.Value(paddock, "WaterFormat");
                if (waterFormat == string.Empty)
                {
                    int sampleNumber = 0;
                    foreach (XmlNode soilSample in XmlUtilities.ChildNodes(soilNode, "Sample"))
                    {
                        string swUnits = XmlUtilities.Value(soilSample, "SWUnits");
                        if (swUnits != string.Empty)
                        {
                            XmlUtilities.SetValue(paddock, "WaterFormat", swUnits);
                        }

                        // Also make sure we don't have 2 samples with the same name.
                        string sampleName = "Sample" + (sampleNumber + 1).ToString();
                        XmlUtilities.SetAttribute(soilSample, "name", sampleName);
                        sampleNumber++;
                    }
                }
                simulation.Soil = SoilUtilities.FromXML(soilNode.OuterXml);
                if (simulation.Samples != null)
                {
                    simulation.Soil.Samples = simulation.Samples;
                }
            }
            return(simulation);
        }
        /// <summary>Write a sowing operation to the specified xml.</summary>
        /// <param name="sowing">The sowing.</param>
        /// <returns></returns>
        /// <exception cref="Exception">
        /// Maximum root depth should be specified in mm, not cm
        /// or
        /// Invalid bed width found:  + sowing.BedWidth.ToString()
        /// </exception>
        public string AddSowingOperation(Sow sowing, bool useEC)
        {
            string operationsXML = string.Empty;

            if (sowing.Date != DateTime.MinValue)
            {
                XmlUtilities.SetValue(simulationXML, "Paddock/Management/ui/CropName", sowing.Crop);
                cropBeingSown = sowing.Crop;
                string cropNodePath = "Paddock/" + sowing.Crop;

                string useECValue = "no";
                if (useEC)
                    useECValue = "yes";
                XmlUtilities.SetValue(simulationXML, cropNodePath + "/ModifyKL", useECValue);

                // Maximum rooting depth.
                if (sowing.MaxRootDepth > 0 && sowing.MaxRootDepth < 20)
                    throw new Exception("Maximum root depth should be specified in mm, not cm");
                if (sowing.MaxRootDepth > 0)
                    XmlUtilities.SetValue(simulationXML, cropNodePath + "/MaxRootDepth", sowing.MaxRootDepth.ToString());

                // Make sure we have a row spacing.
                if (sowing.RowSpacing == 0)
                    sowing.RowSpacing = 250;
                if (sowing.SeedDepth == 0)
                    sowing.SeedDepth = 50;

                string sowAction = sowing.Crop + " sow plants = " + sowing.SowingDensity.ToString() +
                                   ", sowing_depth = " + sowing.SeedDepth +
                                   ", cultivar = " + sowing.Cultivar +
                                   ", row_spacing = " + sowing.RowSpacing.ToString() +
                                   ", crop_class = plant" +
                                   ", skip = solid";

                // Allan's furrow irrigation hack.
                if (sowing.BedWidth > 0)
                {
                    double skiprow;
                    if (sowing.BedWidth == 1)
                        skiprow = 0.44;
                    else if (sowing.BedWidth == 2)
                        skiprow = 0.2;
                    else
                        throw new Exception("Invalid bed width found: " + sowing.BedWidth.ToString());

                    sowAction += ", skiprow = " + skiprow.ToString();
                }

                AddOperation(sowing.Date, sowAction);

                // Add a sowing tillage operation
                string tillageAction = "SurfaceOM tillage type = planter, f_incorp = 0.1, tillage_depth = 50";
                AddOperation(sowing.Date, tillageAction);

                // see if an emergence date was specified. If so then write some operations to 
                // specify it and the germination date.
                if (sowing.EmergenceDate != DateTime.MinValue)
                {
                    TimeSpan FiveDays = new TimeSpan(5, 0, 0, 0);
                    TimeSpan OneDay = new TimeSpan(1, 0, 0, 0);
                    DateTime GerminationDate = sowing.EmergenceDate - FiveDays;
                    if (GerminationDate <= sowing.Date)
                        GerminationDate = sowing.Date + OneDay;
                    if (sowing.EmergenceDate <= GerminationDate)
                        sowing.EmergenceDate = GerminationDate + OneDay;
                    int DaysToGermination = (GerminationDate - sowing.Date).Days;
                    int DaysToEmergence = (sowing.EmergenceDate - sowing.Date).Days;
                    AddOperation(sowing.Date, sowing.Crop + " set DaysToGermination = " + DaysToGermination.ToString());
                    AddOperation(sowing.Date, sowing.Crop + " set DaysToEmergence = " + DaysToEmergence.ToString());
                }

                if (sowing.IrrigationAmount > 0)
                    AddOperation(sowing.Date, "Irrigation apply amount = " + sowing.IrrigationAmount.ToString());

                if (sowing.Crop == "Wheat")
                    XmlUtilities.SetAttribute(simulationXML, "Paddock/WheatFrostHeat/enabled", "yes");
                if (sowing.Crop == "Canola")
                    XmlUtilities.SetAttribute(simulationXML, "Paddock/CanolaFrostHeat/enabled", "yes");
            }

            return operationsXML;
        }
Beispiel #6
0
        /// <summary>Write a sowing operation to the specified xml.</summary>
        /// <param name="sowing">The sowing.</param>
        /// <returns></returns>
        /// <exception cref="Exception">
        /// Maximum root depth should be specified in mm, not cm
        /// or
        /// Invalid bed width found:  + sowing.BedWidth.ToString()
        /// </exception>
        public string AddSowingOperation(Sow sowing, bool useEC)
        {
            string operationsXML = string.Empty;

            if (sowing.Date != DateTime.MinValue)
            {
                XmlUtilities.SetValue(simulationXML, "Paddock/Management/ui/CropName", sowing.Crop);
                cropBeingSown = sowing.Crop;
                string cropNodePath = "Paddock/" + sowing.Crop;

                string useECValue = "no";
                if (useEC)
                {
                    useECValue = "yes";
                }
                XmlUtilities.SetValue(simulationXML, cropNodePath + "/ModifyKL", useECValue);

                // Maximum rooting depth.
                if (sowing.MaxRootDepth > 0 && sowing.MaxRootDepth < 20)
                {
                    throw new Exception("Maximum root depth should be specified in mm, not cm");
                }
                if (sowing.MaxRootDepth > 0)
                {
                    XmlUtilities.SetValue(simulationXML, cropNodePath + "/MaxRootDepth", sowing.MaxRootDepth.ToString());
                }

                // Make sure we have a row spacing.
                if (sowing.RowSpacing == 0)
                {
                    sowing.RowSpacing = 250;
                }
                if (sowing.SeedDepth == 0)
                {
                    sowing.SeedDepth = 50;
                }

                string sowAction = sowing.Crop + " sow plants = " + sowing.SowingDensity.ToString() +
                                   ", sowing_depth = " + sowing.SeedDepth +
                                   ", cultivar = " + sowing.Cultivar +
                                   ", row_spacing = " + sowing.RowSpacing.ToString() +
                                   ", crop_class = plant" +
                                   ", skip = solid";

                // Allan's furrow irrigation hack.
                if (sowing.BedWidth > 0)
                {
                    double skiprow;
                    if (sowing.BedWidth == 1)
                    {
                        skiprow = 0.44;
                    }
                    else if (sowing.BedWidth == 2)
                    {
                        skiprow = 0.2;
                    }
                    else
                    {
                        throw new Exception("Invalid bed width found: " + sowing.BedWidth.ToString());
                    }

                    sowAction += ", skiprow = " + skiprow.ToString();
                }

                AddOperation(sowing.Date, sowAction, sowing.IsEveryYear);

                // Add a sowing tillage operation
                string tillageAction = "SurfaceOM tillage type = planter, f_incorp = 0.1, tillage_depth = 50";
                AddOperation(sowing.Date, tillageAction, sowing.IsEveryYear);

                // see if an emergence date was specified. If so then write some operations to
                // specify it and the germination date.
                if (sowing.EmergenceDate != DateTime.MinValue)
                {
                    TimeSpan FiveDays        = new TimeSpan(5, 0, 0, 0);
                    TimeSpan OneDay          = new TimeSpan(1, 0, 0, 0);
                    DateTime GerminationDate = sowing.EmergenceDate - FiveDays;
                    if (GerminationDate <= sowing.Date)
                    {
                        GerminationDate = sowing.Date + OneDay;
                    }
                    if (sowing.EmergenceDate <= GerminationDate)
                    {
                        sowing.EmergenceDate = GerminationDate + OneDay;
                    }
                    int DaysToGermination = (GerminationDate - sowing.Date).Days;
                    int DaysToEmergence   = (sowing.EmergenceDate - sowing.Date).Days;
                    AddOperation(sowing.Date, sowing.Crop + " set DaysToGermination = " + DaysToGermination.ToString(), sowing.IsEveryYear);
                    AddOperation(sowing.Date, sowing.Crop + " set DaysToEmergence = " + DaysToEmergence.ToString(), sowing.IsEveryYear);
                }

                if (sowing.IrrigationAmount > 0)
                {
                    AddOperation(sowing.Date, "Irrigation apply amount = " + sowing.IrrigationAmount.ToString(), sowing.IsEveryYear);
                }

                if (sowing.Crop == "Wheat")
                {
                    XmlUtilities.SetAttribute(simulationXML, "Paddock/WheatFrostHeat/enabled", "yes");
                }
                if (sowing.Crop == "Canola")
                {
                    XmlUtilities.SetAttribute(simulationXML, "Paddock/CanolaFrostHeat/enabled", "yes");
                }
            }

            return(operationsXML);
        }
        /// <summary>Converts the paddock XML.</summary>
        /// <param name="paddock">The paddock.</param>
        /// <exception cref="System.Exception">Bad paddock name:  + name</exception>
        private static Paddock CreateSimulationSpec(XmlNode paddock, string baseFolder)
        {
            Paddock simulation = new Paddock();

            string name = XmlUtilities.NameAttr(paddock);
            string delimiter = "^";
            int posCaret = name.IndexOf(delimiter);

            if (posCaret == -1)
                throw new Exception("Bad paddock name: " + name);

            string remainder = StringUtilities.SplitOffAfterDelimiter(ref name, delimiter);
            string growerName;
            string paddockName = StringUtilities.SplitOffAfterDelimiter(ref remainder, delimiter);
            if (paddockName == string.Empty)
            {
                growerName = name;
                paddockName = remainder;
            }
            else
                growerName = remainder;

            simulation.StartSeasonDate = GetDate(paddock, "StartSeasonDateFull");

            // Give the paddock a name.
            string fullName = string.Format("{0}^{1}^{2}", simulation.StartSeasonDate.Year, growerName, paddockName);
            simulation.Name = fullName;

            // Set the report date.
            simulation.NowDate = GetDate(paddock.ParentNode, "TodayDateFull");
            if (simulation.NowDate == DateTime.MinValue)
                simulation.NowDate = DateTime.Now;

            // Store any rainfall data in the simulation.
            simulation.RainfallSource = GetString(paddock, "RainfallSource");
            if (simulation.RainfallSource != "Weather station")
            {
                string rainFileName = GetString(paddock, "RainfallFilename");
                if (rainFileName != string.Empty)
                {
                    string fullFileName = Path.Combine(baseFolder, rainFileName);
                    if (!File.Exists(fullFileName))
                        throw new Exception("Cannot find file: " + fullFileName);
                    simulation.ObservedData = ApsimTextFile.ToTable(fullFileName);
                    if (simulation.ObservedData.Rows.Count == 0)
                        simulation.ObservedData = null;
                }
            }
            // Set the reset dates
            simulation.SoilWaterSampleDate = GetDate(paddock, "ResetDateFull");
            simulation.SoilNitrogenSampleDate = GetDate(paddock, "SoilNitrogenSampleDateFull");

            simulation.StationNumber = GetInteger(paddock, "StationNumber");
            simulation.StationName = GetString(paddock, "StationName");
            
            // Create a sowing management
            Sow sowing = new Sow();
            simulation.Management.Add(sowing);
            sowing.Date = GetDate(paddock, "SowDateFull");
            sowing.EmergenceDate = GetDate(paddock, "EmergenceDateFull");
            sowing.Crop = GetString(paddock, "Crop");           
            sowing.Cultivar = GetString(paddock, "Cultivar");
            sowing.SkipRow = GetString(paddock, "SkipRow");
            sowing.SowingDensity = GetInteger(paddock, "SowingDensity");
            sowing.MaxRootDepth = GetInteger(paddock, "MaxRootDepth") * 10;  // cm to mm
            sowing.BedWidth = GetInteger(paddock, "BedWidth");
            sowing.BedRowSpacing = GetDouble(paddock, "BedRowSpacing");

            // Make sure we have a stubbletype
            simulation.StubbleType = GetString(paddock, "StubbleType");
            if (simulation.StubbleType == string.Empty || simulation.StubbleType == "None")
                simulation.StubbleType = "Wheat";
            simulation.StubbleMass = GetDouble(paddock, "StubbleMass");
            simulation.Slope = GetDouble(paddock, "Slope");
            simulation.SlopeLength = GetDouble(paddock, "SlopeLength");
            simulation.UseEC = GetBoolean(paddock, "UseEC");

            // Fertilise nodes.
            List<XmlNode> fertiliserNodes = XmlUtilities.ChildNodes(paddock, "Fertilise");
            for (int f = 0; f < fertiliserNodes.Count; f++)
            {
                Fertilise fertilise = new Fertilise();
                simulation.Management.Add(fertilise);
                fertilise.Date = GetDate(fertiliserNodes[f], "FertDateFull");
                fertilise.Amount = GetDouble(fertiliserNodes[f], "FertAmount");
                fertilise.Scenario = GetBoolean(fertiliserNodes[f], "Scenario");
            }

            // Irrigate nodes.
            List<XmlNode> irrigateNodes = XmlUtilities.ChildNodes(paddock, "Irrigate");
            for (int i = 0; i < irrigateNodes.Count; i++)
            {
                Irrigate irrigate = new Irrigate();
                simulation.Management.Add(irrigate);
                irrigate.Date = GetDate(irrigateNodes[i], "IrrigateDateFull");
                irrigate.Amount = GetDouble(irrigateNodes[i], "IrrigateAmount");
                irrigate.Efficiency = GetDouble(irrigateNodes[i], "IrrigateEfficiency");
                irrigate.Scenario = GetBoolean(irrigateNodes[i], "Scenario");
            }

            // Tillage nodes.
            foreach (XmlNode tillageNode in XmlUtilities.ChildNodes(paddock, "Tillage"))
            {
                Tillage tillage = new Tillage();
                simulation.Management.Add(tillage);
                tillage.Date = GetDate(tillageNode, "TillageDateFull");
                string disturbance = GetString(tillageNode, "Disturbance");
                if (disturbance == "Low")
                    tillage.Disturbance = Tillage.DisturbanceEnum.Low;
                else if (disturbance == "Medium")
                    tillage.Disturbance = Tillage.DisturbanceEnum.Medium;
                else
                    tillage.Disturbance = Tillage.DisturbanceEnum.High;
                tillage.Scenario = GetBoolean(tillageNode, "Scenario");
            }

            // Stubble removed nodes.
            foreach (XmlNode stubbleRemovedNode in XmlUtilities.ChildNodes(paddock, "StubbleRemoved"))
            {
                StubbleRemoved stubbleRemoved = new StubbleRemoved();
                simulation.Management.Add(stubbleRemoved);

                stubbleRemoved.Date = GetDate(stubbleRemovedNode, "StubbleRemovedDateFull");
                stubbleRemoved.Percent = GetDouble(stubbleRemovedNode, "StubbleRemovedAmount");
            }

            // Look for a soil node.
            XmlNode soilNode = XmlUtilities.FindByType(paddock, "Soil");

            if (soilNode != null)
            {
                string testValue = XmlUtilities.Value(soilNode, "Water/Layer/Thickness");
                if (testValue != string.Empty)
                {
                    // old format.
                    soilNode = ConvertSoilNode.Upgrade(soilNode);
                }
            }

            // Fix up soil sample variables.
            Sample sample1 = new Sample();
            sample1.Name = "Sample1";
            sample1.Thickness = GetArray(paddock, "Sample1Thickness");
            sample1.SW = GetArray(paddock, "SW");
            if (sample1.SW == null)
            {
                // Really old way of doing samples - they are stored under soil.
                List<XmlNode> sampleNodes = XmlUtilities.ChildNodes(soilNode, "Sample");
                if (sampleNodes.Count > 0)
                    sample1 = XmlUtilities.Deserialise(sampleNodes[0], typeof(Sample)) as Sample;
            }
            else
            {
                sample1.NO3 = GetArray(paddock, "NO3");
                sample1.NH4 = GetArray(paddock, "NH4");
            }

            Sample sample2 = null;
            double[] sample2Thickness = GetArray(paddock, "Sample2Thickness");
            if (sample2Thickness == null)
            {
                // Really old way of doing samples - they are stored under soil.
                List<XmlNode> sampleNodes = XmlUtilities.ChildNodes(soilNode, "Sample");
                if (sampleNodes.Count > 1)
                    sample2 = XmlUtilities.Deserialise(sampleNodes[1], typeof(Sample)) as Sample;
            }
            else
            {
                sample2 = sample1;
                if (!MathUtilities.AreEqual(sample2Thickness, sample1.Thickness))
                {
                    sample2 = new Sample();
                    sample2.Name = "Sample2";
                }
                sample2.OC = GetArray(paddock, "OC");
                sample2.EC = GetArray(paddock, "EC");
                sample2.PH = GetArray(paddock, "PH");
                sample2.CL = GetArray(paddock, "CL");
                sample2.OCUnits = SoilOrganicMatter.OCUnitsEnum.WalkleyBlack;
                sample2.PHUnits = Analysis.PHUnitsEnum.CaCl2;
            }

            // Make sure we have NH4 values.
            if (sample1.NH4 == null && sample1.NO3 != null)
            {
                string[] defaultValues = StringUtilities.CreateStringArray("0.1", sample1.NO3.Length);
                sample1.NH4 = MathUtilities.StringsToDoubles(defaultValues);
            }

            RemoveNullFieldsFromSample(sample1);
            if (sample2 != null)
                RemoveNullFieldsFromSample(sample2);


            // Fix up <WaterFormat>
            string waterFormatString = GetString(paddock, "WaterFormat");
            if (waterFormatString.Contains("Gravimetric"))
                sample1.SWUnits = Sample.SWUnitsEnum.Gravimetric;
            else
                sample1.SWUnits = Sample.SWUnitsEnum.Volumetric;

            if (MathUtilities.ValuesInArray(sample1.Thickness))
                simulation.Samples.Add(sample1);

            if (sample2 != null && MathUtilities.ValuesInArray(sample2.Thickness) && sample2 != sample1)
                simulation.Samples.Add(sample2);

            // Check for InitTotalWater & InitTotalNitrogen
            simulation.InitTotalWater = GetDouble(paddock, "InitTotalWater");
            simulation.InitTotalNitrogen = GetDouble(paddock, "InitTotalNitrogen");

            // Check to see if we need to convert the soil structure.
            simulation.SoilPath = GetString(paddock, "SoilName");

            
            if (soilNode != null)
            {
                // See if there is a 'SWUnits' value. If found then copy it into 
                // <WaterFormat>
                string waterFormat = XmlUtilities.Value(paddock, "WaterFormat");
                if (waterFormat == string.Empty)
                {
                    int sampleNumber = 0;
                    foreach (XmlNode soilSample in XmlUtilities.ChildNodes(soilNode, "Sample"))
                    {
                        string swUnits = XmlUtilities.Value(soilSample, "SWUnits");
                        if (swUnits != string.Empty)
                            XmlUtilities.SetValue(paddock, "WaterFormat", swUnits);

                        // Also make sure we don't have 2 samples with the same name.
                        string sampleName = "Sample" + (sampleNumber + 1).ToString();
                        XmlUtilities.SetAttribute(soilSample, "name", sampleName);
                        sampleNumber++;
                    }
                }
                simulation.Soil = SoilUtilities.FromXML(soilNode.OuterXml);
                if (simulation.Samples != null)
                    simulation.Soil.Samples = simulation.Samples;
            }
            return simulation;
        }
Beispiel #8
0
        /// <summary>Creates a base APSIM simulation spec for the Yield Prophet spec.</summary>
        /// <param name="yieldProphet">The yield prophet specification.</param>
        /// <returns>The created APSIM simulation spec.</returns>
        private static APSIMSpecification CreateBaseSimulation(Paddock paddock)
        {
            Paddock copyOfPaddock = paddock; // XmlUtilities.Clone(paddock) as JobsService.Paddock;

            copyOfPaddock.ObservedData = paddock.ObservedData;

            APSIMSpecification shortSimulation = new APSIMSpecification();

            shortSimulation.Name            = "Base";
            shortSimulation.WeatherFileName = shortSimulation.Name + ".met";

            // Start date of simulation should be the earliest of ResetDate, SowDate and StartSeasonDate
            Sow sow = YieldProphetUtility.GetCropBeingSown(paddock.Management);

            if (sow == null)
            {
                throw new Exception("No sowing specified for paddock: " + paddock.Name);
            }

            if (sow.Date == DateTime.MinValue)
            {
                throw new Exception("No sowing DATE specified for paddock: " + paddock.Name);
            }

            if (sow.Crop == null || sow.Crop == "" || sow.Crop == "None")
            {
                throw new Exception("No sowing CROP specified for paddock: " + paddock.Name);
            }

            shortSimulation.StartDate = DateTime.MaxValue;
            if (paddock.SoilWaterSampleDate != DateTime.MinValue &&
                paddock.SoilWaterSampleDate < shortSimulation.StartDate)
            {
                shortSimulation.StartDate = paddock.SoilWaterSampleDate;
            }
            if (paddock.SoilNitrogenSampleDate != DateTime.MinValue &&
                paddock.SoilNitrogenSampleDate < shortSimulation.StartDate)
            {
                shortSimulation.StartDate = paddock.SoilNitrogenSampleDate;
            }
            if (sow != null && sow.Date < shortSimulation.StartDate && sow.Date != DateTime.MinValue)
            {
                shortSimulation.StartDate = sow.Date;
            }
            if (paddock.StartSeasonDate < shortSimulation.StartDate)
            {
                shortSimulation.StartDate = paddock.StartSeasonDate;
            }

            if (paddock.LongtermStartYear == 0)
            {
                shortSimulation.LongtermStartYear = 1957;
            }
            else
            {
                shortSimulation.LongtermStartYear = paddock.LongtermStartYear;
            }

            if (paddock.RunType == Paddock.RunTypeEnum.SingleSeason)
            {
                shortSimulation.EndDate = copyOfPaddock.NowDate.AddDays(-1);
                if ((shortSimulation.EndDate - shortSimulation.StartDate).Days > 360)
                {
                    shortSimulation.EndDate = shortSimulation.StartDate.AddDays(360);
                }
            }
            else if (paddock.RunType == Paddock.RunTypeEnum.LongTermPatched)
            {
                shortSimulation.EndDate = shortSimulation.StartDate.AddDays(360);
            }
            else if (paddock.RunType == Paddock.RunTypeEnum.LongTerm)
            {
                // Sow opp reports.
                shortSimulation.StartDate = new DateTime(shortSimulation.LongtermStartYear, 1, 1);
                shortSimulation.EndDate   = copyOfPaddock.NowDate.AddDays(-1);
            }
            shortSimulation.NowDate = copyOfPaddock.NowDate.AddDays(-1);
            if (shortSimulation.NowDate == DateTime.MinValue)
            {
                shortSimulation.NowDate = DateTime.Now;
            }
            shortSimulation.DailyOutput   = paddock.DailyOutput;
            shortSimulation.MonthlyOutput = paddock.MonthlyOutput;
            shortSimulation.YearlyOutput  = paddock.YearlyOutput;
            shortSimulation.ObservedData  = copyOfPaddock.ObservedData;
            shortSimulation.Soil          = copyOfPaddock.Soil;
            shortSimulation.SoilPath      = copyOfPaddock.SoilPath;
            shortSimulation.Samples       = new List <APSIM.Shared.Soils.Sample>();
            shortSimulation.Samples.AddRange(copyOfPaddock.Samples);
            shortSimulation.InitTotalWater    = copyOfPaddock.InitTotalWater;
            shortSimulation.InitTotalNitrogen = copyOfPaddock.InitTotalNitrogen;
            shortSimulation.StationNumber     = copyOfPaddock.StationNumber;
            shortSimulation.StubbleMass       = copyOfPaddock.StubbleMass;
            shortSimulation.StubbleType       = copyOfPaddock.StubbleType;
            shortSimulation.Management        = new List <Management>();
            shortSimulation.Management.AddRange(copyOfPaddock.Management);
            shortSimulation.UseEC          = paddock.UseEC;
            shortSimulation.WriteDepthFile = false;
            if (paddock.RunType == Paddock.RunTypeEnum.LongTermPatched)
            {
                shortSimulation.RunType = APSIMSpecification.RunTypeEnum.LongTermPatched;
            }
            else
            {
                shortSimulation.RunType = APSIMSpecification.RunTypeEnum.Normal;
            }
            shortSimulation.DecileDate          = paddock.StartSeasonDate;
            shortSimulation.NUnlimited          = paddock.NUnlimited;
            shortSimulation.NUnlimitedFromToday = paddock.NUnlimitedFromToday;
            shortSimulation.WriteDepthFile      = paddock.WriteDepthFile;
            shortSimulation.Next10DaysDry       = paddock.Next10DaysDry;
            AddResetDatesToManagement(copyOfPaddock, shortSimulation);

            // Do a stable sort on management actions.
            shortSimulation.Management = shortSimulation.Management.OrderBy(m => m.Date).ToList();

            if (paddock.RunType == Paddock.RunTypeEnum.LongTerm)
            {
                foreach (Management man in shortSimulation.Management)
                {
                    man.IsEveryYear = true;
                }
            }
            return(shortSimulation);
        }
Beispiel #9
0
        /// <summary>Write a sowing operation to the specified xml.</summary>
        /// <param name="sowing">The sowing.</param>
        public string AddSowingOperation(Sow sowing, bool useEC)
        {
            string operationsXML = string.Empty;

            if (sowing.Date != DateTime.MinValue)
            {
                cropBeingSown = sowing.Crop;
                string cropNodePath = "Zone/" + sowing.Crop;

                //string useECValue = "no";
                //if (useEC)
                //    useECValue = "yes";
                //XmlUtilities.SetValue(simulationXML, cropNodePath + "/ModifyKL", useECValue);

                // Maximum rooting depth.
                if (sowing.MaxRootDepth > 0 && sowing.MaxRootDepth < 20)
                {
                    throw new Exception("Maximum root depth should be specified in mm, not cm");
                }
                if (sowing.MaxRootDepth > 0)
                {
                    AddOperation(sowing.Date, "[" + sowing.Crop + "].Root.MaximumRootDepth.FixedValue = " + sowing.MaxRootDepth);
                }

                // Make sure we have a row spacing.
                if (sowing.RowSpacing == 0)
                {
                    sowing.RowSpacing = 250;
                }
                if (sowing.SeedDepth == 0)
                {
                    sowing.SeedDepth = 50;
                }

                string sowAction = "[" + sowing.Crop + "].Sow(population: " + sowing.SowingDensity.ToString() +
                                   ", cultivar: " + sowing.Cultivar +
                                   ", depth: " + sowing.SeedDepth +
                                   ", rowSpacing: " + sowing.RowSpacing.ToString() + ")";

                // Allan's furrow irrigation hack.
                //if (sowing.BedWidth > 0)
                //{
                //    double skiprow;
                //    if (sowing.BedWidth == 1)
                //        skiprow = 0.44;
                //    else if (sowing.BedWidth == 2)
                //        skiprow = 0.2;
                //    else
                //        throw new Exception("Invalid bed width found: " + sowing.BedWidth.ToString());

                //    sowAction += ", skiprow = " + skiprow.ToString();
                //}

                AddOperation(sowing.Date, sowAction);

                // Add a sowing tillage operation
                string tillageAction = "[SurfaceOrganicMatter].Incorporate(fraction: 0.1, depth: 50)";
                AddOperation(sowing.Date, tillageAction);

                // see if an emergence date was specified. If so then write some operations to
                // specify it and the germination date.
                if (sowing.EmergenceDate != DateTime.MinValue)
                {
                    DateTime GerminationDate = sowing.EmergenceDate.AddDays(-5);
                    if (GerminationDate <= sowing.Date)
                    {
                        GerminationDate = sowing.Date.AddDays(1);
                    }
                    if (sowing.EmergenceDate <= GerminationDate)
                    {
                        sowing.EmergenceDate = GerminationDate.AddDays(1);
                    }
                    int DaysToGermination = (GerminationDate - sowing.Date).Days;
                    int DaysToEmergence   = (sowing.EmergenceDate - sowing.Date).Days;
                    AddOperation(sowing.Date, "[" + sowing.Crop + "].Phenology.Germinating.DaysFromSowingToEndPhase = " + DaysToGermination);
                    AddOperation(sowing.Date, "[" + sowing.Crop + "].Phenology.Emerging.DaysFromSowingToEndPhase = " + DaysToEmergence);
                }

                if (sowing.IrrigationAmount > 0)
                {
                    AddOperation(sowing.Date, "[Irrigation].Apply(amount: " + sowing.IrrigationAmount.ToString() + ")");
                }

                // Add a crop node.
                XmlNode cropNode = XmlUtilities.EnsureNodeExists(simulationXML, "Zone/Plant");
                XmlUtilities.SetValue(cropNode, "ResourceName", sowing.Crop);
                XmlUtilities.SetValue(cropNode, "Name", sowing.Crop);
                XmlUtilities.SetValue(cropNode, "CropType", sowing.Crop);

                XmlUtilities.SetValue(simulationXML, "Zone/Manager/Script/CropName", sowing.Crop);
                //if (sowing.Crop == "Wheat")
                //    XmlUtilities.SetAttribute(simulationXML, "Paddock/WheatFrostHeat/enabled", "yes");
                //if (sowing.Crop == "Canola")
                //    XmlUtilities.SetAttribute(simulationXML, "Paddock/CanolaFrostHeat/enabled", "yes");
            }

            return(operationsXML);
        }