/// <summary> /// Create a one year APSIM simulation for the specified yield prophet specification /// and paddock /// </summary> /// <param name="paddock">The paddock.</param> /// <param name="todayDate">The today date.</param> /// <param name="apsoilService">The apsoil service.</param> /// <returns>The XML node of the APSIM simulation.</returns> private static XmlNode CreateSimulationXML(AusFarmSpec simulation, string workingFolder) { AusFarmFileWriter ausfarmWriter; // determine which type of simulation this is based on stock, paddocks, crops if ((simulation.LiveStock.Flocks.Count == 0) && (simulation.LiveStock.TradeLambCount == 0)) { ausfarmWriter = new AusFarmFileWriter(SimulationType.stCropOnly); simulation.SimTemplateType = SimulationType.stCropOnly; // ensure that the simulation type is alway correct } else { if (simulation.LiveStock.Flocks.Count == 1) { ausfarmWriter = new AusFarmFileWriter(SimulationType.stSingleFlock); simulation.SimTemplateType = SimulationType.stSingleFlock; // ensure that the simulation type is alway correct } else if (simulation.LiveStock.Flocks.Count == 2) { ausfarmWriter = new AusFarmFileWriter(SimulationType.stDualFlock); simulation.SimTemplateType = SimulationType.stDualFlock; // ensure that the simulation type is alway correct } else { throw new Exception(); } } // Name the simulation ausfarmWriter.NameSimulation(simulation.Name); // Set the clock start and end dates. ausfarmWriter.SetStartEndDate(simulation.StartDate, simulation.EndDate); //set the path for output files ausfarmWriter.OutputPath(workingFolder); ausfarmWriter.ReportName(simulation.ReportName); // Set the weather file ausfarmWriter.SetWeatherFile(FMetFile); ausfarmWriter.SetRainDeciles(simulation.RainDeciles); ausfarmWriter.SetCroppingRegion(simulation.CroppingRegion); ausfarmWriter.SetArea(simulation.Area); for (int i = 0; i < simulation.OnFarmSoilTypes.Count; i++) { ausfarmWriter.SetCropRotation(i + 1, simulation.OnFarmSoilTypes[i].CropRotationList); } // Do soil stuff. DoSoils(simulation); ausfarmWriter.SetSoils(simulation); if (simulation.SimTemplateType != SimulationType.stCropOnly) { // Set the Livestock data ausfarmWriter.WriteStockEnterprises(simulation.LiveStock); } return(ausfarmWriter.ToXML()); }
/// <summary>Creates the weather files for all simulations.</summary> /// <param name="simulations">The simulations.</param> /// <param name="workingFolder">The working folder to create the files in.</param> /// <param name="ausfarmNode"></param> private static void CreateWeatherFileForSimulation(AusFarmSpec simulation, string workingFolder) { // Write the .met file for the simulation DateTime earliestStartDate = DateTime.MaxValue; DateTime latestEndDate = DateTime.MinValue; DateTime nowDate = DateTime.MaxValue; DataTable observedData = null; int stationNumber = 0; stationNumber = simulation.StationNumber; if (simulation.StartDate < earliestStartDate) { earliestStartDate = simulation.StartDate; } if (simulation.EndDate > latestEndDate) { latestEndDate = simulation.EndDate; } // Create the weather files. FMetFile = Path.Combine(workingFolder, stationNumber.ToString()) + ".met"; // Create a weather file. Weather.Data weatherFile = Weather.ExtractDataFromSILO(stationNumber, earliestStartDate, nowDate); Weather.OverlayData(observedData, weatherFile.Table); Weather.WriteWeatherFile(weatherFile.Table, FMetFile, weatherFile.Latitude, weatherFile.Longitude, weatherFile.TAV, weatherFile.AMP); // ensure that the run period doesn't exceed the data retrieved if (simulation.EndDate > weatherFile.LastDate) { simulation.EndDate = weatherFile.LastDate; } // calculate the rain deciles from April from the year of the start of the simulation. // this could be improved to use more than a few decades of weather. simulation.RainDeciles = new double[12, 10]; // 12 months, 10 deciles DateTime accumStartDate = new DateTime(simulation.StartDate.Year, 4, 1); if (simulation.StartDate > accumStartDate) // ensure that the start date for decile accum exists in the weather { accumStartDate.AddYears(1); } simulation.RainDeciles = Weather.CalculateRainDeciles(stationNumber, accumStartDate, simulation.EndDate); }
/// <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>Create a .sdml file for the job</summary> /// <param name="AusFarmSpec">The specification to use</param> /// <returns>The root XML node for the file</returns> private static XmlNode CreateAusFarmFile(AusFarmSpec simulation, string workingFolder) { XmlDocument doc = new XmlDocument(); try { XmlNode simulationXML = CreateSimulationXML(simulation, workingFolder); if (simulationXML != null) { doc.AppendChild(doc.ImportNode(simulationXML, true)); } } catch (Exception err) { throw new Exception(err.Message + "\r\nSimulation name: " + simulation.Name); } return(doc.DocumentElement); }
/// <summary> /// Sets the soil values in every paddock that has the soil type. /// The valid configuration is: /// - One to three soil types. Currently there are four phases/paddocks for each soil type. /// This means that up to four different crops will be sown on a soil type in any year. /// To sow only one crop type on a soil type for the year, specifiy four crops with the same name. /// More than four names can be in the rotation list. /// Each paddock in the soil type uses the same paddock initialisation /// The .AreaPoportion value is useful to dividing the farm. Any soil type that has /// zero proportion will have no area and will not be sown. /// If only one soil type is found then the remaining two will be set to zero proportion area. /// </summary> /// <param name="simulation">The AusFarm simulation object</param> public void SetSoils(AusFarmSpec simulation) { double areaPropnTotal = 0.0; int soilIdx = 0; // find every paddock XmlNodeList paddocks = simulationXMLNode.SelectNodes("//system[attribute::class=\"Paddock\"]"); // work through the 3 possible soil types while (soilIdx < 3) { if (soilIdx < simulation.OnFarmSoilTypes.Count) { // for every soil type that has been defined FarmSoilType soilArea = simulation.OnFarmSoilTypes[soilIdx]; areaPropnTotal += soilArea.AreaProportion; SetGenericCompStateVar("Params", "F4P_AREAPROPN_ROT" + (soilIdx + 1).ToString(), soilArea.AreaProportion.ToString()); SetGenericCompStateVar("Params", "F4P_SOIL_FERT" + (soilIdx + 1).ToString(), soilArea.SeasonFertiliser.ToString()); if (soilArea.AreaProportion > 0) { FarmPaddockType defaultPaddock = simulation.OnFarmPaddocks[soilIdx]; //this paddock is applied to this soil type Soil soilConfig = soilArea.SoilDescr; // determine the soil depth so the pasture components can be initialised double depth = 0; for (int i = 0; i < soilConfig.Water.Thickness.Length; i++) depth += soilConfig.Water.Thickness[i]; int paddIdx = 0; // for each paddock foreach (XmlNode paddocknode in paddocks) { // parse the name of the paddock to see if this soil applies to it- Expect "Soil1_01" int soilNo, paddNo; ParsePaddockName(paddocknode, out soilNo, out paddNo); // if this soil should be applied to this paddock if (soilNo == soilIdx + 1) { SetSoilComponents(defaultPaddock, soilConfig, paddocknode); SetSoilCrops(soilConfig, paddocknode, soilArea); SetPastureComponents(defaultPaddock, depth, paddocknode, soilArea); paddIdx++; } } } } else { SetGenericCompStateVar("Params", "F4P_AREAPROPN_ROT" + (soilIdx + 1).ToString(), "0.0"); } soilIdx++; } }