public static void ConvertSoil() { XmlDocument doc = new XmlDocument(); //StreamReader input = new StreamReader(@"C:\Users\fai04d\Desktop\WI.SOL"); StreamReader input = new StreamReader(@"C:\temp\EB.SOL"); XmlNode soil = null; string line; XmlElement root = doc.CreateElement("Folder"); root.SetAttribute("version", "36"); doc.AppendChild(root); while ((line = input.ReadLine()) != null) { if (line.StartsWith("*")) { soil = XmlHelper.CreateNode(doc, "Soil", ""); try { XmlHelper.SetAttribute(soil, "name", line.Substring(1, 10)); Console.WriteLine("Processing: " + line.Substring(1, 10)); } catch { XmlHelper.SetAttribute(soil, "name", "Soil"); Console.WriteLine("Processing: Soil"); } } else if (line.StartsWith("@SITE")) { SoilProperties sp = new SoilProperties(); line = input.ReadLine(); //line 3 sp.country = line.Substring(13, 10).Trim(); sp.lat = line.Substring(26, 7).Trim(); sp.lon = line.Substring(35, 7).Trim(); sp.name = line.Substring(43).Trim(); input.ReadLine(); //line 4 line = input.ReadLine().Replace("-99", " "); //line 5 sp.scom = line.Substring(0, 7).Trim(); sp.salb = line.Substring(6, 6).Trim(); sp.slu1 = line.Substring(12, 6).Trim(); sp.sldr = line.Substring(18, 6).Trim(); sp.slro = line.Substring(24, 6).Trim(); sp.slnf = line.Substring(30, 6).Trim(); sp.slpf = line.Substring(36, 6).Trim(); input.ReadLine(); //line 6 line = input.ReadLine().Replace("-99", " "); //line 7 int i = 0; do //1st block of layer lines { Layer l = new Layer(); l.depth = line.Substring(0, 6).Trim(); l.slmh = line.Substring(6, 7).Trim(); l.slll = line.Substring(13, 6).Trim(); l.sdul = line.Substring(19, 6).Trim(); l.ssat = line.Substring(25, 6).Trim(); l.srgf = line.Substring(31, 6).Trim(); l.ssks = line.Substring(37, 6).Trim(); l.sbdm = line.Substring(43, 6).Trim(); l.sloc = line.Substring(49, 6).Trim(); l.slcl = line.Substring(55, 6).Trim(); l.slsi = line.Substring(61, 6).Trim(); l.slcf = line.Substring(67, 6).Trim(); l.slni = line.Substring(73, 6).Trim(); l.slhw = line.Substring(79, 6).Trim(); l.slhb = line.Substring(85, 6).Trim(); l.scec = line.Substring(91, 6).Trim(); l.sadc = line.Substring(97).Trim(); sp.layers.Add(l); line = input.ReadLine().Replace("-99.0", " "); } while (line.Length > 0); // (!(line.Contains("@"))); /* line = input.ReadLine().Replace("-99.0", " "); //line 11 do //2nd block of layer lines. No error check. Assumes same number of layers (which is true, if not then the soil data is wrong, but we don't handle that case) { Layer l = sp.layers[i]; l.slpx = line.Substring(6, 7).Trim(); l.slpt = line.Substring(13, 6).Trim(); l.slpo = line.Substring(19, 6).Trim(); l.caco3 = line.Substring(25, 6).Trim(); l.slal = line.Substring(31, 6).Trim(); l.slfe = line.Substring(37, 6).Trim(); l.slmn = line.Substring(43, 6).Trim(); l.slbs = line.Substring(49, 6).Trim(); l.slpa = line.Substring(55, 6).Trim(); l.slpb = line.Substring(61, 6).Trim(); l.slke = line.Substring(67, 6).Trim(); l.slmg = line.Substring(73, 6).Trim(); l.slna = line.Substring(79, 6).Trim(); l.slsu = line.Substring(85, 6).Trim(); l.slec = line.Substring(91, 6).Trim(); l.slca = line.Substring(97).Trim(); i++; line = input.ReadLine(); } while (line.Length > 0);*/ //////read finished XmlHelper.SetValue(soil, "Country", sp.country); XmlHelper.SetValue(soil, "LocalName", ""); XmlHelper.SetValue(soil, "Site", ""); XmlHelper.SetValue(soil, "Region", ""); XmlHelper.SetValue(soil, "SoilType", sp.name); XmlHelper.SetValue(soil, "NearestTown", ""); XmlHelper.SetValue(soil, "NaturalVegetation", ""); XmlHelper.SetValue(soil, "State", ""); XmlHelper.SetValue(soil, "ApsoilNumber", ""); XmlHelper.SetValue(soil, "Latitude", sp.lat); XmlHelper.SetValue(soil, "Longitude", sp.lon); XmlHelper.SetValue(soil, "LocationAccuracy", ""); XmlHelper.SetValue(soil, "DataSource", "Romero, C.C., Hoogenboom, G., Baigorria, G.A., Koo, J., Gijsman, A.J., Wood, S., 2012. Reanalysis of a global soil database for crop and environmental modeling. Environmental Modelling & Software 35, 163-170. https://harvestchoice.wufoo.com/forms/download-wisol."); XmlHelper.SetValue(soil, "Comments", "You will need to add crops to this soil before running simulations."); //Initial Water XmlNode initWater = XmlHelper.CreateNode(doc, "InitialWater", ""); XmlHelper.SetAttribute(initWater, "name", "Initial Water"); XmlHelper.SetValue(initWater, "FractionFull", "1"); XmlHelper.SetValue(initWater, "PercentMethod", "FilledFromTop"); //Water XmlNode water = XmlHelper.CreateNode(doc, "Water", ""); XmlNode attr; int lastLayer = 0; XmlNode thickness = XmlHelper.CreateNode(doc, "Thickness", ""); for (int k = 0; k < sp.layers.Count; k++) //set up layers { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); int layerDepth = (Int32.Parse(sp.layers[k].depth) - lastLayer) * 10; lastLayer = Int32.Parse(sp.layers[k].depth); XmlHelper.SetValue(dbl, "", layerDepth.ToString()); thickness.AppendChild(dbl); } water.AppendChild(thickness); XmlNode bd = XmlHelper.CreateNode(doc, "BD", ""); for (int k = 0; k < sp.layers.Count; k++) //set up layers { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", sp.layers[k].sbdm); bd.AppendChild(dbl); } water.AppendChild(bd); XmlNode airDry = XmlHelper.CreateNode(doc, "AirDry", ""); for (int k = 0; k < sp.layers.Count; k++) //set up layers { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); double airdry = Convert.ToDouble(sp.layers[k].slll) / 3; XmlHelper.SetValue(dbl, "", airdry.ToString("#.##")); airDry.AppendChild(dbl); } water.AppendChild(airDry); XmlNode ll15 = XmlHelper.CreateNode(doc, "LL15", ""); for (int k = 0; k < sp.layers.Count; k++) //set up layers { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", sp.layers[k].slll); ll15.AppendChild(dbl); } water.AppendChild(ll15); XmlNode dul = XmlHelper.CreateNode(doc, "DUL", ""); for (int k = 0; k < sp.layers.Count; k++) //set up layers { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", sp.layers[k].sdul); dul.AppendChild(dbl); } water.AppendChild(dul); XmlNode sat = XmlHelper.CreateNode(doc, "SAT", ""); for (int k = 0; k < sp.layers.Count; k++) //set up layers { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", sp.layers[k].ssat); sat.AppendChild(dbl); } water.AppendChild(sat); XmlNode ks = XmlHelper.CreateNode(doc, "KS", ""); for (int k = 0; k < sp.layers.Count; k++) //set up layers { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", sp.layers[k].ssks); ks.AppendChild(dbl); } water.AppendChild(ks); ///SoilWat XmlNode soilWat = XmlHelper.CreateNode(doc, "SoilWater", ""); XmlHelper.SetValue(soilWat, "SummerCona", "3"); //No value available in WI.SOL XmlHelper.SetValue(soilWat, "SummerU", sp.slu1); //Using SLU1 from WI.SOL. Unsure if this is correct. XmlHelper.SetValue(soilWat, "SummerDate", sp.lat.Contains('-') ? "1-Nov" : "1-Apr"); XmlHelper.SetValue(soilWat, "WinterCona", "3"); XmlHelper.SetValue(soilWat, "WinterU", sp.slu1); XmlHelper.SetValue(soilWat, "WinterDate", sp.lat.Contains('-') ? "1-Apr" : "1-Nov"); XmlHelper.SetValue(soilWat, "DiffusConst", ""); XmlHelper.SetValue(soilWat, "DiffusSlope", ""); XmlHelper.SetValue(soilWat, "Salb", sp.salb); XmlHelper.SetValue(soilWat, "Cn2Bare", sp.slro); XmlHelper.SetValue(soilWat, "CnRed", ""); XmlHelper.SetValue(soilWat, "CnCov", ""); XmlHelper.SetValue(soilWat, "Slope", ""); XmlHelper.SetValue(soilWat, "DischargeWidth", ""); XmlHelper.SetValue(soilWat, "CatchmentArea", ""); XmlHelper.SetValue(soilWat, "MaxPond", ""); lastLayer = 0; thickness = XmlHelper.CreateNode(doc, "Thickness", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); int layerDepth = Int32.Parse(sp.layers[k].depth) - lastLayer; lastLayer = Int32.Parse(sp.layers[k].depth); XmlHelper.SetValue(dbl, "", layerDepth.ToString() + "0"); thickness.AppendChild(dbl); } soilWat.AppendChild(thickness); XmlNode swcon = XmlHelper.CreateNode(doc, "SWCON", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", "0.5"); swcon.AppendChild(dbl); } soilWat.AppendChild(swcon); //SoilOrganicMatter int[] depths = new int[sp.layers.Count]; double[] carbons = new double[sp.layers.Count]; double[] nitrogens = new double[sp.layers.Count]; try //handle case where no OC data { for (int k = 0; k < sp.layers.Count; k++) { depths[k] = Convert.ToInt32(sp.layers[k].depth); carbons[k] = Convert.ToDouble(sp.layers[k].sloc); nitrogens[k] = Convert.ToDouble(sp.layers[k].slni); } } catch (Exception e) { carbons = null; } XmlNode soilOM = XmlHelper.CreateNode(doc, "SoilOrganicMatter", ""); XmlHelper.SetValue(soilOM, "RootCn", ""); XmlHelper.SetValue(soilOM, "RootWt", ""); XmlHelper.SetValue(soilOM, "EnrACoeff", ""); XmlHelper.SetValue(soilOM, "EnrBCoeff", ""); double CNratio = 0; if (carbons != null) //handle case where no OC data { double cOC50 = LogRegression(depths, carbons, 50); double nOC50 = LogRegression(depths, nitrogens, 50); double cErt = carbons[0] - cOC50; double nErt = nitrogens[0] - nOC50; CNratio = cErt / nErt; } XmlHelper.SetValue(soilOM, "SoilCn", CNratio == 0 ? "" : CNratio.ToString("#.##")); //if 0, no carbon data lastLayer = 0; double[] fInert = new double[sp.layers.Count]; double[] fBiom = new double[sp.layers.Count]; for (int k = 0; k < sp.layers.Count; k++) { // Calculate FBIOM and FINERT if (carbons != null) //handle case where no OC data { if (depths[k] > 50) fInert[k] = 1; else { double cOC50 = LogRegression(depths, carbons, 50); double nOC50 = LogRegression(depths, nitrogens, 50); double cErt = carbons[k] - cOC50; double nErt = nitrogens[0] - nOC50; double cFert = cErt / carbons[k]; fInert[k] = 1 - cFert; if (fInert[k] < 0) fInert[k] = 0; else if (fInert[k] > 1) fInert[k] = 1; } } if (Convert.ToInt16(sp.layers[k].depth) <= 15) fBiom[k] = 0.04; else if (Convert.ToInt16(sp.layers[k].depth) <= 60) fBiom[k] = 0.02; else fBiom[k] = 0.01; } lastLayer = 0; thickness = XmlHelper.CreateNode(doc, "Thickness", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); int layerDepth = Int32.Parse(sp.layers[k].depth) - lastLayer; lastLayer = Int32.Parse(sp.layers[k].depth); XmlHelper.SetValue(dbl, "", layerDepth.ToString() + "0"); thickness.AppendChild(dbl); } soilOM.AppendChild(thickness); XmlNode oc = XmlHelper.CreateNode(doc, "OC", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", sp.layers[k].sloc); oc.AppendChild(dbl); } soilOM.AppendChild(oc); XmlNode fbiom = XmlHelper.CreateNode(doc, "FBiom", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", fBiom[k].ToString("#.##")); fbiom.AppendChild(dbl); } soilOM.AppendChild(fbiom); XmlNode fin = XmlHelper.CreateNode(doc, "FInert", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", carbons == null ? "" : fInert[k].ToString("#.##")); fin.AppendChild(dbl); } soilOM.AppendChild(fin); /// Analysis XmlNode analysis = XmlHelper.CreateNode(doc, "Analysis", ""); lastLayer = 0; thickness = XmlHelper.CreateNode(doc, "Thickness", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); int layerDepth = Int32.Parse(sp.layers[k].depth) - lastLayer; lastLayer = Int32.Parse(sp.layers[k].depth); XmlHelper.SetValue(dbl, "", layerDepth.ToString() + "0"); thickness.AppendChild(dbl); } analysis.AppendChild(thickness); XmlNode munsell = XmlHelper.CreateNode(doc, "MunsellColour", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "string", ""); XmlHelper.SetValue(dbl, "", sp.scom); munsell.AppendChild(dbl); } analysis.AppendChild(munsell); XmlNode ec = XmlHelper.CreateNode(doc, "EC", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", sp.layers[k].slec); ec.AppendChild(dbl); } analysis.AppendChild(ec); XmlNode ph = XmlHelper.CreateNode(doc, "PH", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", sp.layers[k].slhw); ph.AppendChild(dbl); } analysis.AppendChild(ph); XmlNode Ca = XmlHelper.CreateNode(doc, "Ca", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", sp.layers[k].slca); Ca.AppendChild(dbl); } analysis.AppendChild(Ca); XmlNode Mg = XmlHelper.CreateNode(doc, "Mg", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", sp.layers[k].slmg); Mg.AppendChild(dbl); } analysis.AppendChild(Mg); XmlNode Na = XmlHelper.CreateNode(doc, "Na", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", sp.layers[k].slna); Na.AppendChild(dbl); } analysis.AppendChild(Na); XmlNode K = XmlHelper.CreateNode(doc, "K", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", sp.layers[k].slke); K.AppendChild(dbl); } analysis.AppendChild(K); XmlNode Mn = XmlHelper.CreateNode(doc, "Mn", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", sp.layers[k].slmn); Mn.AppendChild(dbl); } analysis.AppendChild(Mn); XmlNode Al = XmlHelper.CreateNode(doc, "Al", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", sp.layers[k].slal); Al.AppendChild(dbl); } analysis.AppendChild(Al); XmlNode PSSilt = XmlHelper.CreateNode(doc, "ParticleSizeSilt", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", sp.layers[k].slsi); PSSilt.AppendChild(dbl); } analysis.AppendChild(PSSilt); XmlNode PSClay = XmlHelper.CreateNode(doc, "ParticleSizeClay", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", sp.layers[k].slcl); PSClay.AppendChild(dbl); } analysis.AppendChild(PSClay); XmlNode PSSand = XmlHelper.CreateNode(doc, "ParticleSizeSand", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); int psSilt = 0, psClay = 0, psSand = 0; if (Int32.TryParse(sp.layers[k].slsi, out psSilt) && Int32.TryParse(sp.layers[k].slcl, out psClay)) psSand = 100 - psSilt - psClay; XmlHelper.SetValue(dbl, "", psSand.ToString()); PSSand.AppendChild(dbl); } analysis.AppendChild(PSSand); /// Initial Nitrogen XmlNode initN = XmlHelper.CreateNode(doc, "Sample", ""); XmlHelper.SetAttribute(initN, "name", "Initial nitrogen"); XmlNode date = XmlHelper.CreateNode(doc, "Date", ""); XmlHelper.SetAttribute(date, "type", "date"); XmlHelper.SetAttribute(date, "description", "Sample date:"); lastLayer = 0; thickness = XmlHelper.CreateNode(doc, "Thickness", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); int layerDepth = Int32.Parse(sp.layers[k].depth) - lastLayer; lastLayer = Int32.Parse(sp.layers[k].depth); XmlHelper.SetValue(dbl, "", layerDepth.ToString() + "0"); thickness.AppendChild(dbl); } initN.AppendChild(thickness); XmlNode no3 = XmlHelper.CreateNode(doc, "NO3", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", "0.1"); no3.AppendChild(dbl); } initN.AppendChild(no3); XmlNode nh4 = XmlHelper.CreateNode(doc, "NH4", ""); for (int k = 0; k < sp.layers.Count; k++) { XmlNode dbl = XmlHelper.CreateNode(doc, "double", ""); XmlHelper.SetValue(dbl, "", "0.1"); nh4.AppendChild(dbl); } initN.AppendChild(nh4); attr = XmlHelper.Find(soil, "SoilType"); XmlHelper.SetAttribute(attr, "description", "Classification"); attr = XmlHelper.Find(soil, "NearestTown"); XmlHelper.SetAttribute(attr, "description", "Nearest Town"); attr = XmlHelper.Find(soil, "NaturalVegetation"); XmlHelper.SetAttribute(attr, "description", "Natural Vegetation"); attr = XmlHelper.Find(soil, "ApsoilNumber"); XmlHelper.SetAttribute(attr, "description", "Apsoil Number"); attr = XmlHelper.Find(soil, "Latitude"); XmlHelper.SetAttribute(attr, "description", "Latitude (WGS84)"); attr = XmlHelper.Find(soil, "Longitude"); XmlHelper.SetAttribute(attr, "description", "Longitude (WGS84)"); attr = XmlHelper.Find(soil, "LocationAccuracy"); XmlHelper.SetAttribute(attr, "description", "Location Accuracy"); attr = XmlHelper.Find(soil, "DataSource"); XmlHelper.SetAttribute(attr, "type", "multiedit"); XmlHelper.SetAttribute(attr, "description", "DataSource"); attr = XmlHelper.Find(soil, "Comments"); XmlHelper.SetAttribute(attr, "description", "Comments"); soil.AppendChild(water); soil.AppendChild(soilWat); soil.AppendChild(soilOM); soil.AppendChild(analysis); soil.AppendChild(initWater); soil.AppendChild(initN); root.AppendChild(soil); } } Console.WriteLine("Writing Apsim soil file."); Console.ReadKey(); var remEmpty = XDocument.Parse(doc.InnerXml); remEmpty.Descendants().Where(e => e.IsEmpty || String.IsNullOrWhiteSpace(e.Value)).Remove(); //deserialiser doesn't like empty nodes. Use LINQ to remove them. remEmpty.Save(@"C:\temp\EB2.soils"); }