/// <summary> /// Called when the user passes the /Edit command line switch. /// Performs pattern matching and edits all specified .apsimx /// files (e.g. *.apsimx /Recurse). /// </summary> private static void ModifyFile(string fileName, bool recurse) { int index = Array.IndexOf(arguments, "/Edit"); if (index < 0) { throw new Exception("Illegal state - this should never happen. /Edit paramter was not specified?"); } if (index + 1 >= arguments.Length) { throw new Exception("/Edit option was provided but no config file argument was given. The config file argument must directly follow the /Edit argument. Use this syntax: Models.exe path/to/apsimXFile.apsimx /Edit path/to/configfile.txt"); } string configFileName = arguments[index + 1]; string dir = Path.GetDirectoryName(fileName); if (!Directory.Exists(dir)) { dir = Directory.GetCurrentDirectory(); } string[] files = Directory.EnumerateFiles(dir, Path.GetFileName(fileName), recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly).ToArray(); foreach (string file in files) { EditFile.Do(file, configFileName); } }
public void TestEditingGenericLists() { string configFile = Path.GetTempFileName(); File.WriteAllLines(configFile, new[] { // Set an entire (string) list. "[StringList].Data = 1, x, y, true, 0.5", // Modify a single element of a (string) list. "[StringList].Data[1] = 6", // Modify multiple elements of a (string) list. "[StringList].Data[3:4] = xyz", // Set an entire (numeric) list. "[DoubleList].Data = 1, 2, 3, 4, 4.5", // Modify a single element of a (numeric) list. "[DoubleList].Data[1] = -13", // Modify multiple elements of a (numeric) list. "[DoubleList].Data[3:4] = 1e9", }); Simulations file = EditFile.Do(fileName, configFile); ListClass <string> stringList = (ListClass <string>)file.Children[1].Children[7]; ListClass <double> doubleList = (ListClass <double>)file.Children[1].Children[8]; List <string> expectedStrings = new List <string>(new[] { "6", "x", "xyz", "xyz", "0.5" }); Assert.AreEqual(expectedStrings, stringList.Data); List <double> expectedNumbers = new List <double>(new[] { -13, 2, 1e9, 1e9, 4.5 }); Assert.AreEqual(expectedNumbers, doubleList.Data); }
public void TestEditOption() { string[] changes = new string[] { "[Clock].StartDate = 2019-1-20", ".Simulations.Sim1.Clock.EndDate = 3/20/2019", ".Simulations.Sim2.Enabled = false", ".Simulations.Sim1.Field.Soil.Physical.Thickness[1] = 500", ".Simulations.Sim1.Field.Soil.Physical.Thickness[2] = 2500", ".Simulations.Sim2.Name = SimulationVariant35", }; string configFileName = Path.GetTempFileName(); File.WriteAllLines(configFileName, changes); string apsimxFileName = Path.ChangeExtension(Path.GetTempFileName(), ".apsimx"); string text = ReflectionUtilities.GetResourceAsString("UnitTests.BasicFile.apsimx"); // Check property values at this point. Simulations sims = FileFormat.ReadFromString <Simulations>(text, out List <Exception> errors); if (errors != null && errors.Count > 0) { throw errors[0]; } Clock clock = sims.FindInScope <Clock>(); Simulation sim1 = sims.FindInScope <Simulation>(); Simulation sim2 = sims.FindInScope("Sim2") as Simulation; IPhysical physical = sims.FindByPath(".Simulations.Sim1.Field.Soil.Physical")?.Value as IPhysical; // Check property values - they should be unchanged at this point. DateTime start = new DateTime(2003, 11, 15); Assert.AreEqual(start.Year, clock.StartDate.Year); Assert.AreEqual(start.DayOfYear, clock.StartDate.DayOfYear); Assert.AreEqual(sim1.Name, "Sim1"); Assert.AreEqual(sim2.Enabled, true); Assert.AreEqual(physical.Thickness[0], 150); Assert.AreEqual(physical.Thickness[1], 150); // Run Models.exe with /Edit command. sims.Write(apsimxFileName); sims = EditFile.Do(apsimxFileName, configFileName); // Get references to the changed models. clock = sims.FindInScope <Clock>(); Clock clock2 = sims.FindByPath(".Simulations.SimulationVariant35.Clock")?.Value as Clock; // Sims should have at least 3 children - data store and the 2 sims. Assert.That(sims.Children.Count > 2); sim1 = sims.Children.OfType <Simulation>().First(); sim2 = sims.Children.OfType <Simulation>().Last(); physical = sims.FindByPath(".Simulations.Sim1.Field.Soil.Physical")?.Value as IPhysical; start = new DateTime(2019, 1, 20); DateTime end = new DateTime(2019, 3, 20); // Check clock. Assert.AreEqual(clock.StartDate.Year, start.Year); Assert.AreEqual(clock.StartDate.DayOfYear, start.DayOfYear); Assert.AreEqual(clock.EndDate.Year, end.Year); Assert.AreEqual(clock.EndDate.DayOfYear, end.DayOfYear); // These changes should not affect the clock in simulation 2. start = new DateTime(2003, 11, 15); end = new DateTime(2003, 11, 15); Assert.AreEqual(clock2.StartDate.Year, start.Year); Assert.AreEqual(clock2.StartDate.DayOfYear, start.DayOfYear); Assert.AreEqual(clock2.EndDate.Year, end.Year); Assert.AreEqual(clock2.EndDate.DayOfYear, end.DayOfYear); // Sim2 should have been renamed to SimulationVariant35 Assert.AreEqual(sim2.Name, "SimulationVariant35"); // Sim1's name should be unchanged. Assert.AreEqual(sim1.Name, "Sim1"); // Sim2 should have been disabled. This should not affect sim1. Assert.That(sim1.Enabled); Assert.That(!sim2.Enabled); // First 2 soil thicknesses have been changed to 500 and 2500 respectively. Assert.AreEqual(physical.Thickness[0], 500, 1e-8); Assert.AreEqual(physical.Thickness[1], 2500, 1e-8); }
public void TestEditing() { string configFile = Path.GetTempFileName(); File.WriteAllLines(configFile, new[] { // Modify an array "[Report].VariableNames = x,y,z", // Modify a date - try a few different formats. "[Clock].StartDate = 2000-01-01", "[Clock].EndDate = 2000-01-10T00:00:00", // Modify a string "[Weather].FileName = fdsa.met", @"[Weather2].FullFileName = jkl.met", // Replace a model with a model from another file. $"[Weather3] = {extFile}", $"[Weather4] = {extFile};[w2]", // Change a property of a resource model. "[Wheat].Leaf.Photosynthesis.RUE.FixedValue = 0.4", // Change a property of a manager script. "[Manager].Script.Amount = 1234", // Set an entire array. "[Physical].BD = 1, 2, 3, 4, 5", // Modify a single element of an array. "[Physical].AirDry[2] = 6", // Modify multiple elements of an array. "[Physical].LL15[3:4] = 7", }); Simulations file = EditFile.Do(fileName, configFile); var report = file.FindInScope <Models.Report>(); string[] variableNames = new[] { "x", "y", "z" }; Assert.AreEqual(variableNames, report.VariableNames); IModel sim = file.FindChild <Simulation>(); // Use an index-based lookup to locate child models. // When we replace an entire model, we want to ensure // that the replacement is inserted at the correct index. Clock clock = sim.Children[0] as Clock; Assert.AreEqual(new DateTime(2000, 1, 1), clock.StartDate); Assert.AreEqual(new DateTime(2000, 1, 10), clock.EndDate); var weather = sim.Children[3] as Models.Climate.Weather; Assert.NotNull(weather); Assert.AreEqual("Weather", weather.Name); Assert.AreEqual("fdsa.met", weather.FileName); var weather2 = sim.Children[4] as Models.Climate.Weather; Assert.NotNull(weather2); Assert.AreEqual("Weather2", weather2.Name); Assert.AreEqual(@"jkl.met", weather2.FileName); // Weather3 and Weather4 should have been // renamed to w1 and w2, respectively. var weather3 = sim.Children[5] as Models.Climate.Weather; Assert.NotNull(weather3); Assert.AreEqual("w1", weather3.Name); Assert.AreEqual("w1.met", weather3.FileName); var weather4 = sim.Children[6] as Models.Climate.Weather; Assert.NotNull(weather4); Assert.AreEqual("w2", weather4.Name); Assert.AreEqual("w2.met", weather4.FileName); // The edit file operation should have changed RUE value to 0.4. var wheat = sim.Children[2].Children[2] as Plant; var rue = wheat.Children[6].Children[4].Children[0] as Constant; Assert.AreEqual(0.4, rue.FixedValue); double amount = (double)sim.FindByPath("[Manager].Script.Amount")?.Value; Assert.AreEqual(1234, amount); Physical physical = sim.Children[2].Children[4] as Physical; Assert.AreEqual(new double[5] { 1, 2, 3, 4, 5 }, physical.BD); Assert.AreEqual(new double[5] { 0, 6, 0, 0, 0 }, physical.AirDry); Assert.AreEqual(new double[5] { 0, 0, 7, 7, 0 }, physical.LL15); }
/// <summary> /// Run Models with the given set of options. /// </summary> /// <param name="options"></param> public static void Run(Options options) { try { string[] files = options.Files.SelectMany(f => DirectoryUtilities.FindFiles(f, options.Recursive)).ToArray(); if (files == null || files.Length < 1) { throw new ArgumentException($"No files were specified"); } if (options.NumProcessors == 0) { throw new ArgumentException($"Number of processors cannot be 0"); } if (options.Upgrade) { foreach (string file in files) { UpgradeFile(file); if (options.Verbose) { Console.WriteLine("Successfully upgraded " + file); } } } else if (options.ListSimulationNames) { foreach (string file in files) { ListSimulationNames(file, options.SimulationNameRegex); } } else if (options.MergeDBFiles) { string[] dbFiles = files.Select(f => Path.ChangeExtension(f, ".db")).ToArray(); string outFile = Path.Combine(Path.GetDirectoryName(dbFiles[0]), "merged.db"); DBMerger.MergeFiles(dbFiles, outFile); } else { Runner runner; if (string.IsNullOrEmpty(options.EditFilePath)) { // Run simulations runner = new Runner(files, options.RunTests, options.RunType, numberOfProcessors: options.NumProcessors, simulationNamePatternMatch: options.SimulationNameRegex); } else { runner = new Runner(files.Select(f => EditFile.Do(f, options.EditFilePath)), true, true, options.RunTests, runType: options.RunType, numberOfProcessors: options.NumProcessors, simulationNamePatternMatch: options.SimulationNameRegex); } runner.SimulationCompleted += OnJobCompleted; if (options.Verbose) { runner.SimulationCompleted += WriteCompleteMessage; } if (options.ExportToCsv) { runner.SimulationGroupCompleted += OnSimulationGroupCompleted; } runner.AllSimulationsCompleted += OnAllJobsCompleted; runner.Run(); // If errors occurred, write them to the console. if (exitCode != 0) { Console.WriteLine("ERRORS FOUND!!"); } if (options.Verbose) { Console.WriteLine("Elapsed time was " + runner.ElapsedTime.TotalSeconds.ToString("F1") + " seconds"); } } } catch (Exception err) { Console.WriteLine(err.ToString()); exitCode = 1; } }