public async Task <IActionResult> Edit(int id, [Bind("Id,LakeId,Year,SurfaceFlow,SurfaceOutflow,UndergroundFlow,UndergroundOutflow,Precipitation,Evaporation")] WaterBalance waterBalance) { if (id != waterBalance.Id) { return(NotFound()); } if (ModelState.IsValid) { try { _context.Update(waterBalance); await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!WaterBalanceExists(waterBalance.Id)) { return(NotFound()); } else { throw; } } return(RedirectToAction(nameof(Index))); } return(View(waterBalance)); }
public async Task <IActionResult> Create([Bind("Id,LakeId,Year,SurfaceFlow,SurfaceOutflow,UndergroundFlow,UndergroundOutflow,Precipitation,Evaporation")] WaterBalance waterBalance) { if (ModelState.IsValid) { _context.Add(waterBalance); await _context.SaveChangesAsync(); return(RedirectToAction(nameof(Index))); } return(View(waterBalance)); }
public async Task <IActionResult> Upload(bool FirstRowHeader, IFormFile File) { try { string sContentRootPath = _hostingEnvironment.WebRootPath; sContentRootPath = Path.Combine(sContentRootPath, "Uploads"); DirectoryInfo di = new DirectoryInfo(sContentRootPath); foreach (FileInfo filed in di.GetFiles()) { try { filed.Delete(); } catch { } } string path_filename = Path.Combine(sContentRootPath, Path.GetFileName(File.FileName)); using (var stream = new FileStream(Path.GetFullPath(path_filename), FileMode.Create)) { await File.CopyToAsync(stream); } FileInfo fileinfo = new FileInfo(Path.Combine(sContentRootPath, Path.GetFileName(path_filename))); using (ExcelPackage package = new ExcelPackage(fileinfo)) { int start_row = 1; if (FirstRowHeader) { start_row++; } List <WaterBalance> waterBalances = new List <WaterBalance>(); for (int i = start_row; ; i++) { if (package.Workbook.Worksheets.FirstOrDefault().Cells[i, 1].Value == null) { break; } WaterBalance waterBalance = new WaterBalance(); try { waterBalance.LakeId = Convert.ToInt32(package.Workbook.Worksheets.FirstOrDefault().Cells[i, 1].Value); waterBalance.Year = Convert.ToInt32(package.Workbook.Worksheets.FirstOrDefault().Cells[i, 2].Value); waterBalance.SurfaceFlow = package.Workbook.Worksheets.FirstOrDefault().Cells[i, 3].Value == null ? (decimal?)null : Convert.ToDecimal(package.Workbook.Worksheets.FirstOrDefault().Cells[i, 3].Value); waterBalance.SurfaceOutflow = package.Workbook.Worksheets.FirstOrDefault().Cells[i, 4].Value == null ? (decimal?)null : Convert.ToDecimal(package.Workbook.Worksheets.FirstOrDefault().Cells[i, 4].Value); waterBalance.UndergroundFlow = package.Workbook.Worksheets.FirstOrDefault().Cells[i, 5].Value == null ? (decimal?)null : Convert.ToDecimal(package.Workbook.Worksheets.FirstOrDefault().Cells[i, 5].Value); waterBalance.UndergroundOutflow = package.Workbook.Worksheets.FirstOrDefault().Cells[i, 6].Value == null ? (decimal?)null : Convert.ToDecimal(package.Workbook.Worksheets.FirstOrDefault().Cells[i, 6].Value); waterBalance.Precipitation = Convert.ToDecimal(package.Workbook.Worksheets.FirstOrDefault().Cells[i, 7].Value); waterBalance.Evaporation = Convert.ToDecimal(package.Workbook.Worksheets.FirstOrDefault().Cells[i, 8].Value); } catch (Exception e) { ViewBag.Error = $"{_sharedLocalizer["Row"]} {i.ToString()}: " + e.Message + (e.InnerException == null ? "" : ": " + e.InnerException.Message); break; } waterBalances.Add(waterBalance); _context.Add(waterBalances.LastOrDefault()); } if (string.IsNullOrEmpty(ViewBag.Error)) { _context.SaveChanges(); ViewBag.Report = $"{_sharedLocalizer["UploadedCount"]}: {waterBalances.Count()}"; } } foreach (FileInfo filed in di.GetFiles()) { try { filed.Delete(); } catch { } } } catch (Exception e) { if (File != null) { ViewBag.Error = e.Message + (e.InnerException == null ? "" : ": " + e.InnerException.Message); } } return(View()); }
/// This alternative approach for obtaining ISRIC soil data need a little bit more work, but is largely complete /// There are still bits of the soil organic matter initialisation that should be enhanced. /// We probably don't really need two different ways to get to ISRIC data, but it may be interesting to see how the /// two compare. The initial motiviation was what appears to be an order-of-magnitude problem with soil carbon /// in the World Modellers version. /// <summary> /// Gets and ISRIC soil description directly from SoilGrids /// </summary> /// <returns>True if successful</returns> private IEnumerable <SoilFromDataSource> GetISRICSoils() { var soils = new List <SoilFromDataSource>(); string url = "https://rest.soilgrids.org/query?lon=" + longitudeEditBox.Text + "&lat=" + latitudeEditBox.Text; try { double[] bd = new double[7]; double[] coarse = new double[7]; double[] clay = new double[7]; double[] silt = new double[7]; double[] sand = new double[7]; double[] thetaSat = new double[7]; double[] awc20 = new double[7]; double[] awc23 = new double[7]; double[] awc25 = new double[7]; double[] thetaWwp = new double[7]; double[] ocdrc = new double[7]; double[] phWater = new double[7]; double[] cationEC = new double[7]; double[] texture = new double[7]; string soilType = String.Empty; double maxTemp = 0.0; double minTemp = 0.0; double ppt = 0.0; double bedrock = 2500.0; string[] textureClasses = new string[] { "Clay", "Silty Clay", "Sandy Clay", "Clay Loam", "Silty Clay Loam", "Sandy Clay Loam", "Loam", "Silty Loam", "Sandy Loam", "Silt", "Loamy Sand", "Sand", "NO DATA" }; double[] textureToAlb = new double[] { 0.12, 0.12, 0.13, 0.13, 0.12, 0.13, 0.13, 0.14, 0.13, 0.13, 0.16, 0.19, 0.13 }; double[] textureToCN2 = new double[] { 73.0, 73.0, 73.0, 73.0, 73.0, 73.0, 73.0, 73.0, 68.0, 73.0, 68.0, 68.0, 73.0 }; double[] textureToSwcon = new double[] { 0.25, 0.3, 0.3, 0.4, 0.5, 0.5, 0.5, 0.5, 0.6, 0.5, 0.6, 0.75, 0.5 }; MemoryStream stream = WebUtilities.ExtractDataFromURL(url); stream.Position = 0; JsonTextReader reader = new JsonTextReader(new StreamReader(stream)); while (reader.Read()) { if (reader.TokenType == JsonToken.PropertyName && reader.Value.Equals("properties") && reader.Depth == 1) { reader.Read(); // Read the "start object" token while (reader.Read()) { if (reader.TokenType == JsonToken.PropertyName) { string propName = reader.Value.ToString(); double[] dest = null; double multiplier = 1.0; if (propName == "TAXNWRBMajor") { soilType = reader.ReadAsString(); } else if (propName == "TMDMOD_2011") { maxTemp = 0.0; reader.Read(); while (reader.Read() && reader.TokenType != JsonToken.EndObject) { if (reader.TokenType == JsonToken.PropertyName && reader.Value.Equals("M")) { reader.Read(); // Read start of object token for (int i = 0; i < 12; i++) { reader.Read(); // Read a month name maxTemp += (double)reader.ReadAsDouble(); } maxTemp /= 12.0; } } } else if (propName == "TMNMOD_2011") { minTemp = 0.0; reader.Read(); while (reader.Read() && reader.TokenType != JsonToken.EndObject) { if (reader.TokenType == JsonToken.PropertyName && reader.Value.Equals("M")) { reader.Read(); // Read start of object token for (int i = 0; i < 12; i++) { reader.Read(); // Read a month name minTemp += (double)reader.ReadAsDouble(); } minTemp /= 12.0; } } } else if (propName == "PREMRG") { ppt = 0.0; reader.Read(); while (reader.Read() && reader.TokenType != JsonToken.EndObject) { if (reader.TokenType == JsonToken.PropertyName && reader.Value.Equals("M")) { reader.Read(); // Read start of object token for (int i = 0; i < 12; i++) { reader.Read(); // Read a month name ppt += (double)reader.ReadAsDouble(); } } } } else if (propName == "BDTICM") // Is this the best metric to use for find the "bottom" of the soil? { reader.Read(); while (reader.Read() && reader.TokenType != JsonToken.EndObject) { if (reader.TokenType == JsonToken.PropertyName && reader.Value.Equals("M")) { reader.Read(); // Read start of object token reader.Read(); // Read property name (which ought to be BDTICM_M) bedrock = 10.0 * (double)reader.ReadAsDouble(); reader.Skip(); } } } else if (propName == "AWCh1") { dest = awc20; multiplier = 0.01; } else if (propName == "AWCh2") { dest = awc23; multiplier = 0.01; } else if (propName == "AWCh3") { dest = awc25; multiplier = 0.01; } else if (propName == "AWCtS") { dest = thetaSat; multiplier = 0.01; } else if (propName == "BLDFIE") { dest = bd; multiplier = 0.001; } else if (propName == "CECSOL") { dest = cationEC; multiplier = 1.0; } else if (propName == "CLYPPT") { dest = clay; multiplier = 1.0; } else if (propName == "CRFVOL") { dest = coarse; multiplier = 1.0; } else if (propName == "ORCDRC") { dest = ocdrc; multiplier = 0.1; } else if (propName == "PHIHOX") { dest = phWater; multiplier = 0.1; } else if (propName == "SLTPPT") { dest = silt; multiplier = 1.0; } else if (propName == "SNDPPT") { dest = sand; multiplier = 1.0; } else if (propName == "TEXMHT") { dest = texture; multiplier = 1.0; } else if (propName == "WWP") { dest = thetaWwp; multiplier = 0.01; } if (dest != null) { reader.Read(); while (reader.Read() && reader.TokenType != JsonToken.EndObject) { if (reader.TokenType == JsonToken.PropertyName && reader.Value.Equals("M")) { while (reader.Read() && reader.TokenType != JsonToken.EndObject) { if (reader.TokenType == JsonToken.PropertyName) { string tokenName = reader.Value.ToString(); if (tokenName.StartsWith("sl")) { int index = Int32.Parse(tokenName.Substring(2)) - 1; dest[index] = (double)reader.ReadAsDouble() * multiplier; } } } } } } else { reader.Skip(); } } } } } var newSoil = new Soil(); Chemical analysis = new Chemical(); Physical waterNode = new Physical(); Organic organicMatter = new Organic(); WaterBalance soilWater = new WaterBalance(); InitialWater initialWater = new InitialWater(); Sample initialNitrogen = new Sample(); SoilNitrogen soilN = new SoilNitrogen(); SoilCrop wheat = new SoilCrop(); waterNode.Children.Add(wheat); wheat.Name = "WheatSoil"; waterNode.ParentAllDescendants(); Model nh4 = new SoilNitrogenNH4(); nh4.Name = "NH4"; soilN.Children.Add(nh4); Model no3 = new SoilNitrogenNO3(); no3.Name = "NO3"; soilN.Children.Add(no3); Model urea = new SoilNitrogenUrea(); urea.Name = "Urea"; soilN.Children.Add(urea); Model plantAvailNH4 = new SoilNitrogenPlantAvailableNH4(); plantAvailNH4.Name = "PlantAvailableNH4"; soilN.Children.Add(plantAvailNH4); Model plantAvailNO3 = new SoilNitrogenPlantAvailableNO3(); plantAvailNO3.Name = "PlantAvailableNO3"; soilN.Children.Add(plantAvailNO3); soilN.ParentAllDescendants(); newSoil.Children.Add(waterNode); newSoil.Children.Add(soilWater); newSoil.Children.Add(soilN); newSoil.Children.Add(organicMatter); newSoil.Children.Add(analysis); newSoil.Children.Add(initialWater); newSoil.Children.Add(initialNitrogen); newSoil.Children.Add(new CERESSoilTemperature()); newSoil.ParentAllDescendants(); newSoil.OnCreated(); newSoil.Name = "Synthetic soil derived from ISRIC SoilGrids REST API"; newSoil.DataSource = "ISRIC SoilGrids"; newSoil.SoilType = soilType; newSoil.Latitude = Convert.ToDouble(latitudeEditBox.Text, System.Globalization.CultureInfo.InvariantCulture); newSoil.Longitude = Convert.ToDouble(longitudeEditBox.Text, System.Globalization.CultureInfo.InvariantCulture); // ISRIC values are for "levels", not "intervals", so we need to convert to layers // Following Andrew Moore's lead on layer thickness and weightings. double[] thickness = new double[] { 150.0, 150.0, 150.0, 150.0, 200.0, 200.0, 200.0, 200.0, 300.0, 300.0 }; double[] depth = new double[thickness.Length]; int layerCount = thickness.Length; for (int i = 0; i < thickness.Length; i++) { depth[i] = thickness[i] + (i > 0 ? depth[i - 1] : 0.0); if ((i > 0) && (layerCount == thickness.Length) && (bedrock < depth[i] + 20.0)) { layerCount = i + 1; thickness[i] = Math.Min(thickness[i], Math.Max(0.0, bedrock - (depth[i] - thickness[i]))); if (i == 1) { thickness[i] = Math.Max(50.0, thickness[i]); } Array.Resize(ref thickness, layerCount); } } analysis.Thickness = thickness; waterNode.Thickness = thickness; soilWater.Thickness = thickness; organicMatter.Thickness = thickness; initialWater.Name = "Initial water"; initialWater.PercentMethod = InitialWater.PercentMethodEnum.FilledFromTop; initialWater.FractionFull = 0.0; // Initialise nitrogen to 0.0 initialNitrogen.Name = "Initial nitrogen"; initialNitrogen.NH4 = new double[layerCount]; initialNitrogen.NO3 = new double[layerCount]; double tAvg = (maxTemp + minTemp) / 2.0; soilWater.CNCov = 0.0; soilWater.CNRed = 20.0; soilWater.SummerDate = newSoil.Latitude <= 0.0 ? "1-nov" : "1-may"; soilWater.WinterDate = newSoil.Latitude <= 0.0 ? "1-apr" : "1-oct"; soilWater.SummerCona = 6.0; soilWater.SummerU = 6.0; soilWater.WinterCona = tAvg < 21.0 ? 2.5 : 6.0; soilWater.WinterU = tAvg < 21.0 ? 4.0 : 6.0; soilWater.Salb = textureToAlb[(int)Math.Round(texture[0] - 1)]; soilWater.CN2Bare = textureToCN2[(int)Math.Round(texture[0] - 1)]; double[] swcon = new double[7]; for (int i = 0; i < 7; i++) { swcon[i] = textureToSwcon[(int)Math.Round(texture[i] - 1)]; } soilWater.SWCON = ConvertLayers(swcon, layerCount); waterNode.BD = ConvertLayers(bd, layerCount); waterNode.LL15 = ConvertLayers(thetaWwp, layerCount); waterNode.SAT = ConvertLayers(thetaSat, layerCount); waterNode.AirDry = ConvertLayers(MathUtilities.Divide_Value(thetaWwp, 3.0), layerCount); double[] dul = new double[7]; for (int i = 0; i < 7; i++) { dul[i] = thetaWwp[i] + awc20[i]; // This could be made Moore complex } waterNode.DUL = ConvertLayers(dul, layerCount); waterNode.ParticleSizeSand = ConvertLayers(sand, layerCount); waterNode.ParticleSizeSilt = ConvertLayers(silt, layerCount); waterNode.ParticleSizeClay = ConvertLayers(clay, layerCount); // waterNode.Rocks = ConvertLayers(coarse, layerCount); analysis.PH = ConvertLayers(phWater, layerCount); // Obviously using the averaging in "ConvertLayers" for texture classes is not really correct, but should be OK as a first pass if we don't have sharply contrasting layers double[] classes = ConvertLayers(texture, layerCount); string[] textures = new string[layerCount]; for (int i = 0; i < layerCount; i++) { textures[i] = textureClasses[(int)Math.Round(classes[i]) - 1]; } double[] xf = new double[layerCount]; double[] kl = new double[layerCount]; double[] ll = new double[layerCount]; double p1 = 1.4; double p2 = 1.60 - p1; double p3 = 1.80 - p1; double topEffDepth = 0.0; double klMax = 0.06; double depthKl = 900.0; double depthRoot = 1900.0; for (int i = 0; i < layerCount; i++) { xf[i] = 1.0 - (waterNode.BD[i] - (p1 + p2 * 0.01 * waterNode.ParticleSizeSand[i])) / p3; xf[i] = Math.Max(0.1, Math.Min(1.0, xf[i])); double effectiveThickness = thickness[i] * xf[i]; double bottomEffDepth = topEffDepth + effectiveThickness; double propMaxKl = Math.Max(0.0, Math.Min(bottomEffDepth, depthKl) - topEffDepth) / effectiveThickness; double propDecrKl = Math.Max(Math.Max(0.0, Math.Min(bottomEffDepth, depthRoot) - topEffDepth) / effectiveThickness - propMaxKl, 0.0); double propZeroKl = 1.0 - propMaxKl - propDecrKl; double ratioTopDepth = Math.Max(0.0, Math.Min((depthRoot - topEffDepth) / (depthRoot - depthKl), 1.0)); double ratioBottomDepth = Math.Max(0.0, Math.Min((depthRoot - bottomEffDepth) / (depthRoot - depthKl), 1.0)); double meanDecrRatio = 0.5 * (ratioTopDepth + ratioBottomDepth); double weightedRatio = propMaxKl * 1.0 + propDecrKl * meanDecrRatio + propZeroKl * 0.0; kl[i] = klMax * weightedRatio; ll[i] = waterNode.LL15[i] + (waterNode.DUL[i] - waterNode.LL15[i]) * (1.0 - weightedRatio); if (kl[i] <= 0.0) { xf[i] = 0.0; } topEffDepth = bottomEffDepth; } wheat.XF = xf; wheat.KL = kl; wheat.LL = ll; organicMatter.Carbon = ConvertLayers(ocdrc, layerCount); double rootWt = Math.Max(0.0, Math.Min(3000.0, 2.5 * (ppt - 100.0))); // For AosimX, root wt needs to be distributed across layers. This conversion logic is adapted from that used in UpgradeToVersion52 double[] rootWtFraction = new double[layerCount]; double profileDepth = depth[layerCount - 1]; double cumDepth = 0.0; for (int layer = 0; layer < layerCount; layer++) { double fracLayer = Math.Min(1.0, MathUtilities.Divide(profileDepth - cumDepth, thickness[layer], 0.0)); cumDepth += thickness[layer]; rootWtFraction[layer] = fracLayer * Math.Exp(-3.0 * Math.Min(1.0, MathUtilities.Divide(cumDepth, profileDepth, 0.0))); } // get the actuall FOM distribution through layers (adds up to one) double totFOMfraction = MathUtilities.Sum(rootWtFraction); for (int layer = 0; layer < thickness.Length; layer++) { rootWtFraction[layer] /= totFOMfraction; } organicMatter.FOM = MathUtilities.Multiply_Value(rootWtFraction, rootWt); double[] fBiom = { 0.04, 0.04 - 0.03 * (225.0 - 150.0) / (400.0 - 150.0), (400.0 - 300.0) / (450.0 - 300.0) * (0.04 - 0.03 * (350.0 - 150.0) / (400.0 - 150.0)) + (450.0 - 400.0) / (450.0 - 300.0) * 0.01, 0.01, 0.01,0.01, 0.01, 0.01, 0.01, 0.01 }; Array.Resize(ref fBiom, layerCount); double inert_c = 0.95 * ocdrc[4]; double[] fInert = new double[7]; for (int layer = 0; layer < 7; layer++) { fInert[layer] = Math.Min(0.99, inert_c / ocdrc[layer]); } organicMatter.FInert = ConvertLayers(fInert, layerCount); // Not perfect, but should be good enough organicMatter.FBiom = fBiom; organicMatter.FOMCNRatio = 40.0; organicMatter.SoilCNRatio = Enumerable.Repeat(11.0, layerCount).ToArray(); // Is there any good way to estimate this? ISRIC provides no N data newSoil.Children.Add(new CERESSoilTemperature()); newSoil.OnCreated(); soils.Add(new SoilFromDataSource() { DataSource = "ISRIC", Soil = newSoil }); } catch (Exception) { } return(soils); }
/// <summary>Convert a table of soils data into a list of soils.</summary> public static List <Soil> ToSoils(DataTable table) { var soils = new List <Soil>(); // Loop through all blocks of rows in datatable, create a // soil and store soil in correct location in the AllSoils XML. int row = 0; while (row < table.Rows.Count) { // Find the end of this soil i.e. the row that has a different value for 'Name' // to the current row. int endRow = row + 1; while (endRow < table.Rows.Count && table.Rows[endRow]["Name"].ToString() == table.Rows[row]["Name"].ToString()) { endRow++; } int numLayers = endRow - row; var soil = new Soil(); soil.Name = table.Rows[row]["Name"].ToString(); soil.Country = GetStringValue(table, row, "Country"); soil.State = GetStringValue(table, row, "State"); soil.Region = GetStringValue(table, row, "Region"); soil.NearestTown = GetStringValue(table, row, "NearestTown"); soil.Site = GetStringValue(table, row, "Site"); soil.ApsoilNumber = GetStringValue(table, row, "APSoilNumber"); soil.SoilType = GetStringValue(table, row, "Texture"); soil.LocalName = GetStringValue(table, row, "LocalName"); soil.ASCOrder = GetStringValue(table, row, "ASC_Order"); soil.ASCSubOrder = GetStringValue(table, row, "ASC_Sub-order"); soil.Latitude = GetDoubleValue(table, row, "Latitude"); soil.Longitude = GetDoubleValue(table, row, "Longitude"); soil.LocationAccuracy = GetStringValue(table, row, "LocationAccuracy"); soil.YearOfSampling = GetStringValue(table, row, "YearOfSampling"); soil.DataSource = GetStringValue(table, row, "DataSource"); soil.Comments = GetStringValue(table, row, "Comments"); soil.NaturalVegetation = GetStringValue(table, row, "NaturalVegetation"); soil.RecordNumber = GetIntegerValue(table, row, "RecordNo"); var physical = new Physical(); soil.Children.Add(physical); physical.Thickness = MathUtilities.RemoveMissingValuesFromBottom(GetDoubleValues(table, "Thickness (mm)", row, numLayers)); physical.BD = GetDoubleValues(table, "BD", row, numLayers); physical.BDMetadata = GetCodeValues(table, "BDCode", row, numLayers); physical.SAT = GetDoubleValues(table, "SAT (mm/mm)", row, numLayers); physical.SATMetadata = GetCodeValues(table, "SATCode", row, numLayers); physical.DUL = GetDoubleValues(table, "DUL (mm/mm)", row, numLayers); physical.DULMetadata = GetCodeValues(table, "DULCode", row, numLayers); physical.LL15 = GetDoubleValues(table, "LL15 (mm/mm)", row, numLayers); physical.LL15Metadata = GetCodeValues(table, "LL15Code", row, numLayers); physical.AirDry = GetDoubleValues(table, "Airdry (mm/mm)", row, numLayers); physical.AirDryMetadata = GetCodeValues(table, "AirdryCode", row, numLayers); physical.KS = GetDoubleValues(table, "KS (mm/day)", row, numLayers); physical.KSMetadata = GetCodeValues(table, "KSCode", row, numLayers); physical.Rocks = GetDoubleValues(table, "Rocks (%)", row, numLayers); physical.RocksMetadata = GetCodeValues(table, "RocksCode", row, numLayers); physical.Texture = GetStringValues(table, "Texture", row, numLayers); physical.TextureMetadata = GetCodeValues(table, "TextureCode", row, numLayers); physical.ParticleSizeSand = GetDoubleValues(table, "ParticleSizeSand (%)", row, numLayers); physical.ParticleSizeSandMetadata = GetCodeValues(table, "ParticleSizeSandCode", row, numLayers); physical.ParticleSizeSilt = GetDoubleValues(table, "ParticleSizeSilt (%)", row, numLayers); physical.ParticleSizeSiltMetadata = GetCodeValues(table, "ParticleSizeSiltCode", row, numLayers); physical.ParticleSizeClay = GetDoubleValues(table, "ParticleSizeClay (%)", row, numLayers); physical.ParticleSizeClayMetadata = GetCodeValues(table, "ParticleSizeClayCode", row, numLayers); var soilWater = new WaterBalance(); soilWater.ResourceName = "WaterBalance"; soil.Children.Add(soilWater); soilWater.Thickness = physical.Thickness; soilWater.SummerU = GetDoubleValue(table, row, "SummerU"); soilWater.SummerCona = GetDoubleValue(table, row, "SummerCona"); soilWater.WinterU = GetDoubleValue(table, row, "WinterU"); soilWater.WinterCona = GetDoubleValue(table, row, "WinterCona"); soilWater.SummerDate = GetStringValue(table, row, "SummerDate"); soilWater.WinterDate = GetStringValue(table, row, "WinterDate"); soilWater.Salb = GetDoubleValue(table, row, "Salb"); soilWater.DiffusConst = GetDoubleValue(table, row, "DiffusConst"); soilWater.DiffusSlope = GetDoubleValue(table, row, "DiffusSlope"); soilWater.CN2Bare = GetDoubleValue(table, row, "Cn2Bare"); soilWater.CNRed = GetDoubleValue(table, row, "CnRed"); soilWater.CNCov = GetDoubleValue(table, row, "CnCov"); soilWater.SWCON = GetDoubleValues(table, "SWCON (0-1)", row, numLayers); var organic = new Organic(); soil.Children.Add(organic); organic.Thickness = physical.Thickness; organic.FOMCNRatio = GetDoubleValue(table, row, "RootCN"); organic.FOM = MathUtilities.CreateArrayOfValues(GetDoubleValue(table, row, "RootWt"), numLayers); organic.SoilCNRatio = GetDoubleValues(table, "SoilCN", row, numLayers); organic.FBiom = GetDoubleValues(table, "FBIOM (0-1)", row, numLayers); organic.FInert = GetDoubleValues(table, "FINERT (0-1)", row, numLayers); organic.Carbon = GetDoubleValues(table, "OC", row, numLayers); organic.CarbonMetadata = GetCodeValues(table, "OCCode", row, numLayers); var chemical = new Chemical(); soil.Children.Add(chemical); chemical.Thickness = physical.Thickness; chemical.EC = GetDoubleValues(table, "EC (1:5 dS/m)", row, numLayers); chemical.ECMetadata = GetCodeValues(table, "ECCode", row, numLayers); chemical.PH = GetDoubleValues(table, "PH", row, numLayers); chemical.PHMetadata = GetCodeValues(table, "PHCode", row, numLayers); chemical.CL = GetDoubleValues(table, "CL (mg/kg)", row, numLayers); chemical.CLMetadata = GetCodeValues(table, "CLCode", row, numLayers); chemical.ESP = GetDoubleValues(table, "ESP (%)", row, numLayers); chemical.ESPMetadata = GetCodeValues(table, "ESPCode", row, numLayers); // Add in some necessary models. var soilTemp = new CERESSoilTemperature(); soilTemp.Name = "Temperature"; soil.Children.Add(soilTemp); var nutrient = new Nutrients.Nutrient(); nutrient.ResourceName = "Nutrient"; soil.Children.Add(nutrient); var initialWater = new InitialWater(); soil.Children.Add(initialWater); // crops foreach (DataColumn Col in table.Columns) { if (Col.ColumnName.ToLower().Contains(" ll")) { var nameBits = Col.ColumnName.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); if (nameBits.Length == 3) { string cropName = nameBits[0]; SoilCrop crop = new SoilCrop(); crop.Name = cropName + "Soil"; crop.LL = GetDoubleValues(table, cropName + " ll (mm/mm)", row, numLayers); crop.LLMetadata = GetCodeValues(table, cropName + " llCode", row, numLayers); crop.KL = GetDoubleValues(table, cropName + " kl (/day)", row, numLayers); crop.XF = GetDoubleValues(table, cropName + " xf (0-1)", row, numLayers); if (MathUtilities.ValuesInArray(crop.LL) || MathUtilities.ValuesInArray(crop.KL)) { physical.Children.Add(crop); } } } } soils.Add(soil); row += numLayers; } return(soils); }