/// <summary>Documents the specified model.</summary> /// <param name="modelNameToDocument">The model name to document.</param> /// <param name="tags">The auto doc tags.</param> /// <param name="headingLevel">The starting heading level.</param> public void DocumentModel(string modelNameToDocument, List <AutoDocumentation.ITag> tags, int headingLevel) { Simulation simulation = Apsim.Find(this, typeof(Simulation)) as Simulation; if (simulation != null) { // Find the model of the right name. IModel modelToDocument = Apsim.Find(simulation, modelNameToDocument); // If not found then find a model of the specified type. if (modelToDocument == null) { modelToDocument = Apsim.Get(simulation, "[" + modelNameToDocument + "]") as IModel; } // If still not found throw an error. if (modelToDocument == null) { throw new ApsimXException(this, "Could not find a model of the name " + modelNameToDocument + ". Simulation file name must match the name of the node to document."); } // Get the path of the model (relative to parentSimulation) to document so that // when replacements happen below we will point to the replacement model not the // one passed into this method. string pathOfSimulation = Apsim.FullPath(simulation) + "."; string pathOfModelToDocument = Apsim.FullPath(modelToDocument).Replace(pathOfSimulation, ""); // Clone the simulation Simulation clonedSimulation = Apsim.Clone(simulation) as Simulation; // Make any substitutions. Simulations.MakeSubstitutions(this, new List <Simulation> { clonedSimulation }); // Now use the path to get the model we want to document. modelToDocument = Apsim.Get(clonedSimulation, pathOfModelToDocument) as IModel; if (modelToDocument == null) { throw new Exception("Cannot find model to document: " + modelNameToDocument); } // resolve all links in cloned simulation. Links links = new Core.Links(); links.Resolve(clonedSimulation); // Document the model. modelToDocument.Document(tags, headingLevel, 0); // Unresolve links. links.Unresolve(clonedSimulation); } }
/// <summary> /// Determine the type of an object and return its name. /// </summary> /// <param name="obj">obj can be either a ModelWrapper or an IModel.</param> /// <returns>The name</returns> private string GetFullName(object obj) { if (obj is IModel) { return(Apsim.FullPath(obj as IModel)); } else { return((obj as ModelWrapper).Name); } }
/// <summary> /// Determine the type of an object and return its name. /// </summary> /// <param name="obj">obj can be either a ModelWrapper or an IModel.</param> /// <returns>The name</returns> private string GetFullName(object obj) { if (obj is IModel) { return(Apsim.FullPath(obj as IModel)); } else { return(obj.GetType().FullName); } }
/// <summary> /// Return a list of models in scope to the one specified. /// </summary> /// <param name="relativeTo">The model to base scoping rules on</param> public IModel[] FindAll(IModel relativeTo) { string relativeToFullPath = Apsim.FullPath(relativeTo); // Try the cache first. List <IModel> modelsInScope; if (cache.TryGetValue(relativeToFullPath, out modelsInScope)) { return(modelsInScope.ToArray()); } // The algorithm is to find the parent Zone of the specified model. // Then return all children of this zone recursively and then recursively // the direct children of the parents of the zone. IModel parentZone = FindScopedParentModel(relativeTo); if (parentZone == null) { throw new Exception("No scoping model found relative to: " + Apsim.FullPath(relativeTo)); } // return all models in zone and all direct children of zones parent. modelsInScope = new List <IModel>(); modelsInScope.Add(parentZone); modelsInScope.AddRange(Apsim.ChildrenRecursively(parentZone)); while (parentZone.Parent != null) { parentZone = parentZone.Parent; modelsInScope.Add(parentZone); foreach (IModel child in parentZone.Children) { if (!modelsInScope.Contains(child)) { modelsInScope.Add(child); if (!IsScopedModel(child)) { modelsInScope.AddRange(Apsim.ChildrenRecursively(child)); } } } } if (!modelsInScope.Contains(parentZone)) { modelsInScope.Add(parentZone); // top level simulation } // add to cache for next time. cache.Add(relativeToFullPath, modelsInScope); return(modelsInScope.ToArray()); }
/// <summary>Documents the specified model.</summary> /// <param name="modelNameToDocument">The model name to document.</param> /// <param name="tags">The auto doc tags.</param> /// <param name="headingLevel">The starting heading level.</param> public void DocumentModel(string modelNameToDocument, List <AutoDocumentation.ITag> tags, int headingLevel) { Simulation simulation = Apsim.Find(this, typeof(Simulation)) as Simulation; if (simulation != null) { // Find the model of the right name. IModel modelToDocument = Apsim.Find(simulation, modelNameToDocument); // Get the path of the model (relative to parentSimulation) to document so that // when replacements happen below we will point to the replacement model not the // one passed into this method. string pathOfSimulation = Apsim.FullPath(simulation) + "."; string pathOfModelToDocument = Apsim.FullPath(modelToDocument).Replace(pathOfSimulation, ""); // Clone the simulation Simulation clonedSimulation = Apsim.Clone(simulation) as Simulation; // Make any substitutions. MakeSubstitutions(new Simulation[] { clonedSimulation }); // Now use the path to get the model we want to document. modelToDocument = Apsim.Get(clonedSimulation, pathOfModelToDocument) as IModel; // resolve all links in cloned simulation. Apsim.ResolveLinks(clonedSimulation); foreach (Model child in Apsim.ChildrenRecursively(clonedSimulation)) { Apsim.ResolveLinks(child); } // Document the model. modelToDocument.Document(tags, headingLevel, 0); // Unresolve links. Apsim.UnresolveLinks(clonedSimulation); foreach (Model child in Apsim.ChildrenRecursively(clonedSimulation)) { Apsim.UnresolveLinks(child); } } }
/// <summary> /// Get all links. Useful for debugging. /// </summary> /// <returns></returns> public static string GetAllLinks(IModel model) { string st = string.Empty; st += "\r\n******" + Apsim.FullPath(model) + "******\r\n"; // Go looking for [Link]s foreach (FieldInfo field in ReflectionUtilities.GetAllFields( model.GetType(), BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.Public)) { var link = ReflectionUtilities.GetAttribute(field, typeof(LinkAttribute), false) as LinkAttribute; if (link != null) { st += field.Name + " = "; object value = field.GetValue(model); if (value == null) { st += "null\r\n"; } else if (value is IModel) { st += Apsim.FullPath(value as IModel) + "\r\n"; } else { st += "??\r\n"; } } } foreach (IModel child in model.Children) { st += GetAllLinks(child); } return(st); }
/// <summary>Documents the specified model.</summary> /// <param name="modelNameToDocument">The model name to document.</param> /// <param name="tags">The auto doc tags.</param> /// <param name="headingLevel">The starting heading level.</param> public void DocumentModel(string modelNameToDocument, List <AutoDocumentation.ITag> tags, int headingLevel) { Simulation simulation = Apsim.Find(this, typeof(Simulation)) as Simulation; if (simulation != null) { // Find the model of the right name. IModel modelToDocument = Apsim.Find(simulation, modelNameToDocument); // If not found then find a model of the specified type. if (modelToDocument == null) { modelToDocument = Apsim.Get(simulation, "[" + modelNameToDocument + "]") as IModel; } // If the simulation has the same name as the model we want to document, dig a bit deeper if (modelToDocument == simulation) { modelToDocument = Apsim.ChildrenRecursivelyVisible(simulation).FirstOrDefault(m => m.Name.Equals(modelNameToDocument, StringComparison.OrdinalIgnoreCase)); } // If still not found throw an error. if (modelToDocument != null) { // Get the path of the model (relative to parentSimulation) to document so that // when replacements happen below we will point to the replacement model not the // one passed into this method. string pathOfSimulation = Apsim.FullPath(simulation) + "."; string pathOfModelToDocument = Apsim.FullPath(modelToDocument).Replace(pathOfSimulation, ""); // Clone the simulation Simulation clonedSimulation = Apsim.Clone(simulation) as Simulation; // Make any substitutions. MakeSubstitutions(clonedSimulation); // Now use the path to get the model we want to document. modelToDocument = Apsim.Get(clonedSimulation, pathOfModelToDocument) as IModel; if (modelToDocument == null) { throw new Exception("Cannot find model to document: " + modelNameToDocument); } // resolve all links in cloned simulation. Links.Resolve(clonedSimulation); modelToDocument.IncludeInDocumentation = true; foreach (IModel child in Apsim.ChildrenRecursively(modelToDocument)) { child.IncludeInDocumentation = true; } // Document the model. AutoDocumentation.DocumentModel(modelToDocument, tags, headingLevel, 0, documentAllChildren: true); // Unresolve links. Links.Unresolve(clonedSimulation); } } }
/// <summary>Compile a c# script.</summary> /// <param name="code">The c# code to compile.</param> /// <param name="model">The model owning the script.</param> /// <param name="referencedAssemblies">Optional referenced assemblies.</param> /// <returns>Compile errors or null if no errors.</returns> public Results Compile(string code, IModel model, IEnumerable <string> referencedAssemblies = null) { string errors = null; if (code != null) { // See if we have compiled the code already. If so then no need to compile again. var compilation = previousCompilations.Find(c => c.Code == code); bool newlyCompiled; if (compilation == null || compilation.Code != code) { newlyCompiled = true; var assemblies = GetReferenceAssemblies(referencedAssemblies, model.Name); // We haven't compiled the code so do it now. var result = CompileTextToAssembly(code, assemblies); if (result.Errors.Count > 0) { // Errors were found. Add then to the return error string. errors = null; foreach (CompilerError err in result.Errors) { errors += $"Line {err.Line}: {err.ErrorText}{Environment.NewLine}"; } // Because we have errors, remove the previous compilation if there is one. if (compilation != null) { previousCompilations.Remove(compilation); } compilation = null; } else { // No errors. // If we don't have a previous compilation, create one. if (compilation == null) { compilation = new PreviousCompilation() { ModelFullPath = Apsim.FullPath(model) }; previousCompilations.Add(compilation); } // Set the compilation properties. compilation.Code = code; compilation.CompiledAssembly = result.CompiledAssembly; } } else { newlyCompiled = false; } if (compilation != null) { // We have a compiled assembly so get the class name. var regEx = new Regex(@"class\s+(\w+)\s"); var match = regEx.Match(code); if (!match.Success) { throw new Exception($"Cannot find a class declaration in script:{Environment.NewLine}{code}"); } var className = match.Groups[1].Value; // Create an instance of the class and give it to the model. var instanceType = compilation.CompiledAssembly.GetTypes().ToList().Find(t => t.Name == className); return(new Results(compilation.CompiledAssembly, instanceType.FullName, newlyCompiled)); } else { return(new Results(errors)); } } return(null); }
/// <summary>Run the simulation. Will throw on error.</summary> /// <param name="sender"></param> /// <param name="e"></param> /// <exception cref="System.Exception"> /// </exception> public void Run(object sender, System.ComponentModel.DoWorkEventArgs e) { try { StartRun(); DoRun(sender); CleanupRun(); } catch (ApsimXException err) { DataStore store = new DataStore(this); string Msg = "ERROR in file: " + FileName + "\r\n" + "Simulation name: " + Name + "\r\n"; Msg += err.Message; if (err.InnerException != null) { Msg += "\r\n" + err.InnerException.Message + "\r\n" + err.InnerException.StackTrace; } else { Msg += "\r\n" + err.StackTrace; } string modelFullPath = string.Empty; if (err.model != null) { modelFullPath = Apsim.FullPath(err.model); } store.WriteMessage(Name, Clock.Today, modelFullPath, err.Message, DataStore.ErrorLevel.Error); store.Disconnect(); CleanupRun(); throw new Exception(Msg); } catch (Exception err) { DataStore store = new DataStore(this); string Msg = "ERROR in file: " + FileName + "\r\n" + "Simulation name: " + Name + "\r\n"; Msg += err.Message; if (err.InnerException != null) { Msg += "\r\n" + err.InnerException.Message + "\r\n" + err.InnerException.StackTrace; } else { Msg += "\r\n" + err.StackTrace; } store.WriteMessage(Name, Clock.Today, "Unknown", err.Message, DataStore.ErrorLevel.Error); store.Disconnect(); CleanupRun(); throw new Exception(Msg); } if (e != null) { e.Result = this; } }
/// <summary>Run the simulation. Will throw on error.</summary> /// <param name="sender"></param> /// <param name="e"></param> /// <exception cref="System.Exception"> /// </exception> public void Run(object sender, System.ComponentModel.DoWorkEventArgs e) { try { StartRun(); DoRun(sender); CleanupRun(null); } catch (ApsimXException err) { DateTime errorDate = Clock.Today; string Msg = "ERROR in file: " + FileName + "\r\n" + "Simulation name: " + Name + "\r\n"; Msg += err.Message; if (err.InnerException != null) { Msg += "\r\n" + err.InnerException.Message + "\r\n" + err.InnerException.StackTrace; } else { Msg += "\r\n" + err.StackTrace; } string modelFullPath = string.Empty; if (err.model != null) { modelFullPath = Apsim.FullPath(err.model); } ErrorMessage = Msg; ISummary summary = Apsim.Find(this, typeof(Summary)) as ISummary; summary.WriteMessage(this, Msg); CleanupRun(Msg); throw new Exception(Msg); } catch (Exception err) { DateTime errorDate = Clock.Today; string Msg = "ERROR in file: " + FileName + "\r\n" + "Simulation name: " + Name + "\r\n"; Msg += err.Message; if (err.InnerException != null) { Msg += "\r\n" + err.InnerException.Message + "\r\n" + err.InnerException.StackTrace; } else { Msg += "\r\n" + err.StackTrace; } ErrorMessage = Msg; ISummary summary = Apsim.Find(this, typeof(Summary)) as ISummary; summary.WriteMessage(this, Msg); CleanupRun(Msg); throw new Exception(Msg); } if (e != null) { e.Result = this; } }