/// <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>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; }