public void MoveUpDown() { CommandHistory commandHistory = new CommandHistory(); Model modelToMove = simulations.FindByPath("APS14.Factors.Permutation.NRate")?.Value as Model; MoveModelUpDownCommand moveCommand = new MoveModelUpDownCommand(modelToMove, true, null); moveCommand.Do(commandHistory); Model modelToMove2 = simulations.FindByPath("APS14.Factors.NRate")?.Value as Model; Assert.AreEqual(simulations.Children[2].Children[0].Children[0].Children[0].Name, "NRate"); Assert.AreEqual(simulations.Children[2].Children[0].Children[0].Children[0].Children.Count, 4); }
/// <summary> /// Edits a single apsimx file according to the changes specified in the config file. /// </summary> /// <param name="file">An .apsimx file.</param> /// <param name="factors">Factors to apply to the file.</param> public static Simulations ApplyChanges(Simulations file, IEnumerable <CompositeFactor> factors) { foreach (CompositeFactor factor in factors) { IVariable variable = file.FindByPath(factor.Paths[0]); if (variable == null) { throw new Exception($"Invalid path: {factor.Paths[0]}"); } string value = factor.Values[0].ToString(); string absolutePath = null; try { if (!value.Contains(":")) { absolutePath = PathUtilities.GetAbsolutePath(value, Directory.GetCurrentDirectory()); } } catch { } string[] parts = value.Split(';'); if (parts != null && parts.Length == 2) { string fileName = parts[0]; string absoluteFileName = PathUtilities.GetAbsolutePath(fileName, Directory.GetCurrentDirectory()); string modelPath = parts[1]; if (File.Exists(fileName)) { ReplaceModelFromFile(file, factor.Paths[0], fileName, modelPath); } else if (File.Exists(absoluteFileName)) { ReplaceModelFromFile(file, factor.Paths[0], absoluteFileName, modelPath); } else { ChangeVariableValue(variable, value); } } else if (File.Exists(value) && variable.Value is IModel) { ReplaceModelFromFile(file, factor.Paths[0], value, null); } else if (File.Exists(absolutePath) && variable.Value is IModel) { ReplaceModelFromFile(file, factor.Paths[0], absolutePath, null); } else { ChangeVariableValue(variable, value); } } return(file); }
/// <summary> /// Generate the auto-documentation at the given output path. /// </summary> /// <param name="path">Path to which the file will be generated.</param> public void Generate(string path) { // This document instance will be used to write all of the input files' // documentation to a single document. Document document = PdfWriter.CreateStandardDocument(); PdfBuilder builder = new PdfBuilder(document, options); // Read the file. Simulations rootNode = FileFormat.ReadFromFile <Simulations>(filePath, e => throw e, false); // Attempt to resolve the model path inside the file. IVariable variable = rootNode.FindByPath(modelPath); // Ensure that we found a model. object result = variable?.Value; IModel model = result as IModel; if (variable == null) { throw new Exception($"Failed to resolve path {modelPath} in file {filePath}"); } if (result == null) { throw new Exception($"When resolving path {modelPath} in file {filePath}: {modelPath} resolved to null"); } if (model == null) { throw new Exception($"Attempted to read model from path {modelPath} in file {filePath}, but the path resolves to an object of type {result.GetType()}"); } // Attempt to resolve links for the given model. rootNode.Links.Resolve(model, true, true, false); // Document the model. IEnumerable <ITag> tags = model.Document(); // Document the rest of the file afterwards if necessary. if (documentRestOfFile) { tags = tags.AppendMany(rootNode.Document()); } // Write tags to document. foreach (ITag tag in tags) { builder.Write(tag); } // Write bibliography at end of document. builder.WriteBibliography(); // Write to PDF file at the specified path. string outFile = Path.Combine(path, OutputFileName); PdfWriter.Save(document, outFile); }
/// <summary> /// Replace a model with a model from another file. /// </summary> /// <param name="topLevel">The top-level model of the file being modified.</param> /// <param name="modelToReplace">Path to the model which is to be replaced.</param> /// <param name="replacementFile">Path of the .apsimx file containing the model which will be inserted.</param> /// <param name="replacementPath">Path to the model in replacementFile which will be used to replace a model in topLevel.</param> private static void ReplaceModelFromFile(Simulations topLevel, string modelToReplace, string replacementFile, string replacementPath) { IModel toBeReplaced = topLevel.FindByPath(modelToReplace)?.Value as IModel; if (toBeReplaced == null) { throw new Exception($"Unable to find model which is to be replaced ({modelToReplace}) in file {topLevel.FileName}"); } IModel extFile = FileFormat.ReadFromFile <IModel>(replacementFile, out List <Exception> errors); if (errors?.Count > 0) { throw new Exception($"Error reading replacement file {replacementFile}", errors[0]); } IModel replacement; if (string.IsNullOrEmpty(replacementPath)) { replacement = extFile.FindAllDescendants().Where(d => toBeReplaced.GetType().IsAssignableFrom(d.GetType())).FirstOrDefault(); if (replacement == null) { throw new Exception($"Unable to find replacement model of type {toBeReplaced.GetType().Name} in file {replacementFile}"); } } else { replacement = extFile.FindByPath(replacementPath)?.Value as IModel; if (replacement == null) { throw new Exception($"Unable to find model at path {replacementPath} in file {replacementFile}"); } } IModel parent = toBeReplaced.Parent; int index = parent.Children.IndexOf((Model)toBeReplaced); parent.Children.Remove((Model)toBeReplaced); // Need to call Structure.Add to add the model to the parent. Structure.Add(replacement, parent); // Move the new model to the index in the list at which the // old model previously resided. parent.Children.Remove((Model)replacement); parent.Children.Insert(index, (Model)replacement); }
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.Thickness[1] = 500", ".Simulations.Sim1.Field.Soil.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; Soil soil = sims.FindByPath(".Simulations.Sim1.Field.Soil")?.Value as Soil; // 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(soil.Thickness[0], 150); Assert.AreEqual(soil.Thickness[1], 150); // Run Models.exe with /Edit command. sims.Write(apsimxFileName); Utilities.RunModels($"{apsimxFileName} /Edit {configFileName}"); sims = FileFormat.ReadFromFile <Simulations>(apsimxFileName, out errors); if (errors != null && errors.Count > 0) { throw errors[0]; } // 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(); soil = sims.FindByPath(".Simulations.Sim1.Field.Soil")?.Value as Soil; 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(soil.Thickness[0], 500, 1e-8); Assert.AreEqual(soil.Thickness[1], 2500, 1e-8); }
/// <summary> /// Edits a single apsimx file according to the changes specified in the config file. /// </summary> /// <param name="apsimxFileName">Path to an .apsimx file.</param> /// <param name="factors">Factors to apply to the file.</param> private static void ApplyChanges(string apsimxFileName, List <CompositeFactor> factors) { Simulations file = FileFormat.ReadFromFile <Simulations>(apsimxFileName, out List <Exception> errors); if (errors != null && errors.Count > 0) { throw new Exception($"Error reading file ${apsimxFileName}: {errors[0].ToString()}"); } foreach (CompositeFactor factor in factors) { IVariable variable = file.FindByPath(factor.Paths[0]); if (variable == null) { throw new Exception($"Invalid path: {factor.Paths[0]}"); } string value = factor.Values[0].ToString(); string absolutePath = null; try { if (!value.Contains(":")) { absolutePath = PathUtilities.GetAbsolutePath(value, Directory.GetCurrentDirectory()); } } catch { } string[] parts = value.Split(';'); if (parts != null && parts.Length == 2) { string fileName = parts[0]; string absoluteFileName = PathUtilities.GetAbsolutePath(fileName, Directory.GetCurrentDirectory()); string modelPath = parts[1]; if (File.Exists(fileName)) { ReplaceModelFromFile(file, factor.Paths[0], fileName, modelPath); } else if (File.Exists(absoluteFileName)) { ReplaceModelFromFile(file, factor.Paths[0], absoluteFileName, modelPath); } else { ChangeVariableValue(variable, value); } } else if (File.Exists(value) && variable.Value is IModel) { ReplaceModelFromFile(file, factor.Paths[0], value, null); } else if (File.Exists(absolutePath) && variable.Value is IModel) { ReplaceModelFromFile(file, factor.Paths[0], absolutePath, null); } else { ChangeVariableValue(variable, value); } } file.Write(apsimxFileName); }
public void TestManagerParameterChanges() { Manager m = new Manager() { Name = "Manager", Code = "using System; namespace Models { using Core; [Serializable] public class Script : Models.Core.Model { [Description(\"x\")] public string X { get; set; } } }" }; Simulations sims = new Simulations() { Children = new List <IModel>() { new DataStore(), new Experiment() { Name = "expt", Children = new List <IModel>() { new Factors() { Children = new List <IModel>() { new Factor() { Name = "x", Specification = "[Manager].Script.X = 1" } } }, new Simulation() { Name = "sim", Children = new List <IModel>() { new Clock() { StartDate = new DateTime(2020, 1, 1), EndDate = new DateTime(2020, 1, 2), Name = "Clock" }, new Summary(), m } } } } } }; sims.ParentAllDescendants(); m.OnCreated(); Runner runner = new Runner(sims); string temp = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); try { IEnumerable <string> files = GenerateApsimXFiles.Generate(runner, 1, temp, _ => {}); Assert.AreEqual(1, files.Count()); string file = files.First(); sims = FileFormat.ReadFromFile <Simulations>(file, e => throw e, false); Assert.AreEqual("1", sims.FindByPath("[Manager].Script.X").Value); } finally { if (Directory.Exists(temp)) { Directory.Delete(temp, true); } } }