/// <summary>Deletes the specified model.</summary> /// <param name="model">The model.</param> public static bool Delete(IModel model) { Locator(model.Parent).Clear(); Apsim.ClearCaches(model); return(model.Parent.Children.Remove(model as Model)); }
/// <summary>Add the specified model to the parent.</summary> /// <param name="parent">The parent model</param> /// <param name="modelToAdd">The child model.</param> public static void Add(IModel parent, IModel modelToAdd) { modelToAdd.Parent = parent; Apsim.ParentAllChildren(modelToAdd); parent.Children.Add(modelToAdd as Model); }
/// <summary>Gets a model in scope of the specified type</summary> /// <param name="typeToMatch">The type of the model to return</param> /// <returns>The found model or null if not found</returns> public IModel Get(Type typeToMatch) { return(Apsim.Find(relativeToModel, typeToMatch)); }
/// <summary> /// Get the value of a variable or model. /// </summary> /// <param name="namePath">The name of the object to return</param> /// <param name="ignoreCase">If true, ignore case when searching for the object or property</param> /// <returns>The found object or null if not found</returns> private IVariable GetInternal(string namePath, bool ignoreCase = true) { IModel relativeTo = relativeToModel; string cacheKey = namePath; StringComparison compareType = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; // Look in cache first. object value = null; if (cache.ContainsKey(cacheKey)) { value = cache[cacheKey]; } if (value != null) { return(value as IVariable); } IVariable returnVariable = null; if (namePath == null || namePath.Length == 0) { return(null); } else if (namePath[0] != '.' && (namePath.Replace("()", "").IndexOfAny("+*/".ToCharArray()) != -1 | (namePath.IndexOfAny("(".ToCharArray()) >= 0 && namePath.Substring(0, (namePath.IndexOf('(') >= 0? namePath.IndexOf('(') : 0)).IndexOfAny("[.".ToCharArray()) == -1))) { // expression - need a better way of detecting an expression returnVariable = new VariableExpression(namePath, relativeTo as Model); } else { namePath = namePath.Replace("Value()", "Value()."); // Remove a square bracketed model name and change our relativeTo model to // the referenced model. if (namePath.StartsWith("[")) { int posCloseBracket = namePath.IndexOf(']'); if (posCloseBracket == -1) { return(null); } string modelName = namePath.Substring(1, posCloseBracket - 1); namePath = namePath.Remove(0, posCloseBracket + 1); Model foundModel = Apsim.Find(relativeTo, modelName) as Model; if (foundModel == null) { // Didn't find a model with a name matching the square bracketed string so // now try and look for a model with a type matching the square bracketed string. Type[] modelTypes = GetTypeWithoutNameSpace(modelName); if (modelTypes.Length == 1) { foundModel = Apsim.Find(relativeTo, modelTypes[0]) as Model; } } if (foundModel == null) { return(null); } else { relativeTo = foundModel; } } else if (namePath.StartsWith(".")) { // Absolute path IModel root = relativeTo; while (root.Parent != null) { root = root.Parent as Model; } relativeTo = root; int posPeriod = namePath.IndexOf('.', 1); if (posPeriod == -1) { posPeriod = namePath.Length; } namePath = namePath.Remove(0, posPeriod); if (namePath.StartsWith(".")) { namePath.Remove(1); } } // Now walk the series of '.' separated path bits, assuming the path bits // are child models. Stop when we can't find the child model. string[] namePathBits = namePath.Split(".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); int i; for (i = 0; i < namePathBits.Length; i++) { IModel localModel = relativeTo.Children.FirstOrDefault(m => m.Name.Equals(namePathBits[i], compareType) && m.Enabled); if (localModel == null) { break; } else { relativeTo = localModel as Model; } } // At this point there are only 2 possibilities. We have encountered a // PropertyInfo/MethodInfo or the path is invalid. // We now need to loop through the remaining path bits and keep track of each // section of the path as each section will have to be evaulated everytime a // a get is done for this path. // The variable 'i' will point to the name path that cannot be found as a model. object relativeToObject = relativeTo; List <IVariable> properties = new List <IVariable>(); properties.Add(new VariableObject(relativeTo)); for (int j = i; j < namePathBits.Length; j++) { // look for an array specifier e.g. sw[2] string arraySpecifier = null; if (namePathBits[j].Contains("[")) { arraySpecifier = StringUtilities.SplitOffBracketedValue(ref namePathBits[j], '[', ']'); } // Look for either a property or a child model. IModel localModel = null; if (relativeToObject == null) { return(null); } // Check property info PropertyInfo propertyInfo = relativeToObject.GetType().GetProperty(namePathBits[j]); if (propertyInfo == null && ignoreCase) // If not found, try using a case-insensitive search { propertyInfo = relativeToObject.GetType().GetProperty(namePathBits[j], BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase); } // If not property info // Check method info MethodInfo methodInfo = null; List <object> argumentsList = null; if (propertyInfo == null) { if (namePathBits[j].IndexOf('(') > 0) { relativeToObject.GetType().GetMethod(namePathBits[j].Substring(0, namePathBits[j].IndexOf('('))); if (methodInfo == null && ignoreCase) // If not found, try using a case-insensitive search { methodInfo = relativeToObject.GetType().GetMethod(namePathBits[j].Substring(0, namePathBits[j].IndexOf('(')), BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase); } } if (methodInfo != null) { // get arguments and store in VariableMethod string args = namePathBits[j].Substring(namePathBits[j].IndexOf('(')); args = args.Substring(0, args.IndexOf(')')); args = args.Replace("(", "").Replace(")", ""); if (args.Length > 0) { argumentsList = new List <object>(); args = args.Trim('(').Trim(')'); var argList = args.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); // get arguments ParameterInfo[] pars = methodInfo.GetParameters(); for (int argid = 0; argid < argList.Length; argid++) { var cleanArg = argList[argid].Trim(' ').Trim(new char[] { '(', ')' }).Trim(' ').Trim('"'); switch (Type.GetTypeCode(pars[argid].ParameterType)) { case TypeCode.Double: argumentsList.Add(Convert.ToDouble(cleanArg, CultureInfo.InvariantCulture)); break; case TypeCode.Int32: argumentsList.Add(Convert.ToInt32(cleanArg, CultureInfo.InvariantCulture)); break; case TypeCode.String: argumentsList.Add(cleanArg); break; case TypeCode.Boolean: argumentsList.Add(Convert.ToBoolean(cleanArg, CultureInfo.InvariantCulture)); break; default: throw new ApsimXException(relativeToModel, "The type of argument (" + Type.GetTypeCode(pars[argid].ParameterType) + ") is not currently supported in Report methods"); } } } } } //if (relativeToObject is IFunction && namePathBits[j] == "Value()") //{ // MethodInfo method = relativeTo.GetType().GetMethod("Value"); // properties.Add(new VariableMethod(relativeTo, method)); //} // else if (propertyInfo == null && methodInfo == null && relativeToObject is Model) if (propertyInfo == null && methodInfo == null && relativeToObject is Model) { // Not a property, may be an unchecked method or a child model. localModel = (relativeToObject as IModel).Children.FirstOrDefault(m => m.Name.Equals(namePathBits[j], compareType)); if (localModel == null) { // Not a model return(null); } else { properties.Add(new VariableObject(localModel)); relativeToObject = localModel; } } else if (propertyInfo != null) { VariableProperty property = new VariableProperty(relativeToObject, propertyInfo, arraySpecifier); properties.Add(property); relativeToObject = property.Value; } else if (methodInfo != null) { VariableMethod method = null; if (argumentsList != null) { method = new VariableMethod(relativeToObject, methodInfo, argumentsList.ToArray <object>()); } else { method = new VariableMethod(relativeToObject, methodInfo, null); } // VariableProperty property = new VariableProperty(relativeToObject, propertyInfo, arraySpecifier); properties.Add(method); relativeToObject = method.Value; } else if (relativeToObject is IList) { // Special case: we are trying to get a property of an array(IList). In this case // we want to return the property value for all items in the array. VariableProperty property = new VariableProperty(relativeToObject, namePathBits[j]); properties.Add(property); relativeToObject = property.Value; } else { return(null); } } // We now have a list of IVariable instances that can be evaluated to // produce a return value for the given path. Wrap the list into an IVariable. returnVariable = new VariableComposite(namePath, properties); } // Add variable to cache. cache.Add(cacheKey, returnVariable); return(returnVariable); }
/// <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. modelToDocument.Document(tags, headingLevel, 0); // Unresolve links. Links.Unresolve(clonedSimulation); } } }
/// <summary> /// Get the value of a variable or model. /// </summary> /// <param name="namePath">The name of the object to return</param> /// <param name="ignoreCase">If true, ignore case when searching for the object or property</param> /// <returns>The found object or null if not found</returns> private IVariable GetInternal(string namePath, bool ignoreCase = true) { IModel relativeTo = relativeToModel; string cacheKey = namePath; StringComparison compareType = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; // Look in cache first. object value = null; if (cache.ContainsKey(cacheKey)) { value = cache[cacheKey]; } if (value != null) { return(value as IVariable); } IVariable returnVariable = null; if (namePath == null || namePath.Length == 0) { return(null); } else if (namePath[0] != '.' && namePath.Replace("()", "").IndexOfAny("(+*/".ToCharArray()) != -1) { // expression - need a better way of detecting an expression returnVariable = new VariableExpression(namePath, relativeTo as Model); } else { // Remove a square bracketed model name and change our relativeTo model to // the referenced model. if (namePath.StartsWith("[")) { int posCloseBracket = namePath.IndexOf(']'); if (posCloseBracket == -1) { return(null); } string modelName = namePath.Substring(1, posCloseBracket - 1); namePath = namePath.Remove(0, posCloseBracket + 1); Model foundModel = Apsim.Find(relativeTo, modelName) as Model; if (foundModel == null) { // Didn't find a model with a name matching the square bracketed string so // now try and look for a model with a type matching the square bracketed string. Type[] modelTypes = GetTypeWithoutNameSpace(modelName); if (modelTypes.Length == 1) { foundModel = Apsim.Find(relativeTo, modelTypes[0]) as Model; } } if (foundModel == null) { return(null); } else { relativeTo = foundModel; } } else if (namePath.StartsWith(".")) { // Absolute path IModel root = relativeTo; while (root.Parent != null) { root = root.Parent as Model; } relativeTo = root; int posPeriod = namePath.IndexOf('.', 1); if (posPeriod == -1) { posPeriod = namePath.Length; } namePath = namePath.Remove(0, posPeriod); if (namePath.StartsWith(".")) { namePath.Remove(1); } } // Now walk the series of '.' separated path bits, assuming the path bits // are child models. Stop when we can't find the child model. string[] namePathBits = namePath.Split(".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); int i; for (i = 0; i < namePathBits.Length; i++) { IModel localModel = relativeTo.Children.FirstOrDefault(m => m.Name.Equals(namePathBits[i], compareType)); if (localModel == null) { break; } else { relativeTo = localModel as Model; } } // At this point there are only 2 possibilities. We have encountered a // PropertyInfo or the path is invalid. // We now need to loop through the remaining path bits and keep track of each // section of the path as each section will have to be evaulated everytime a // a get is done for this path. // The variable 'i' will point to the name path that cannot be found as a model. object relativeToObject = relativeTo; List <IVariable> properties = new List <IVariable>(); properties.Add(new VariableObject(relativeTo)); for (int j = i; j < namePathBits.Length; j++) { // look for an array specifier e.g. sw[2] string arraySpecifier = null; if (namePathBits[j].Contains("[")) { arraySpecifier = StringUtilities.SplitOffBracketedValue(ref namePathBits[j], '[', ']'); } // Look for either a property or a child model. IModel localModel = null; if (relativeToObject == null) { return(null); } PropertyInfo propertyInfo = relativeToObject.GetType().GetProperty(namePathBits[j]); if (propertyInfo == null && ignoreCase) // If not found, try using a case-insensitive search { propertyInfo = relativeToObject.GetType().GetProperty(namePathBits[j], BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase); } if (relativeToObject is IFunction && namePathBits[j] == "Value()") { MethodInfo method = relativeTo.GetType().GetMethod("Value"); properties.Add(new VariableMethod(relativeTo, method)); } else if (propertyInfo == null && relativeToObject is Model) { // Not a property, may be a child model. localModel = (relativeToObject as IModel).Children.FirstOrDefault(m => m.Name.Equals(namePathBits[j], compareType)); if (localModel == null) { return(null); } properties.Add(new VariableObject(localModel)); relativeToObject = localModel; } else if (propertyInfo != null) { VariableProperty property = new VariableProperty(relativeToObject, propertyInfo, arraySpecifier); properties.Add(property); relativeToObject = property.Value; } else if (relativeToObject is IList) { // Special case: we are trying to get a property of an array(IList). In this case // we want to return the property value for all items in the array. VariableProperty property = new VariableProperty(relativeToObject, namePathBits[j]); properties.Add(property); relativeToObject = property.Value; } else { return(null); } } // We now have a list of IVariable instances that can be evaluated to // produce a return value for the given path. Wrap the list into an IVariable. returnVariable = new VariableComposite(namePath, properties); } // Add variable to cache. cache.Add(cacheKey, returnVariable); return(returnVariable); }