/// <summary>Writes documentation for this function by adding to the list of documentation tags.</summary> /// <param name="tags">The list of tags to add to.</param> /// <param name="headingLevel">The level (e.g. H2) of the headings.</param> /// <param name="indent">The level of indentation 1, 2, 3 etc.</param> public void Document(List <AutoDocumentation.ITag> tags, int headingLevel, int indent) { if (IncludeInDocumentation) { // add a heading. tags.Add(new AutoDocumentation.Heading(Name, headingLevel)); // write memos. foreach (IModel memo in Apsim.Children(this, typeof(Memo))) { AutoDocumentation.DocumentModel(memo, tags, headingLevel + 1, indent); } // add graph and table. if (XYPairs != null) { IVariable xProperty = Apsim.GetVariableObject(this, XProperty); string xName = XProperty; if (xProperty != null && xProperty.UnitsLabel != string.Empty) { xName += " " + xProperty.UnitsLabel; } tags.Add(new AutoDocumentation.Paragraph("<i>" + Name + "</i> is calculated as a function of <i>" + StringUtilities.RemoveTrailingString(XProperty, ".Value()") + "</i>", indent)); tags.Add(new AutoDocumentation.GraphAndTable(XYPairs, string.Empty, xName, LookForYAxisTitle(this), indent)); } } }
/// <summary> /// Apply commands. /// </summary> /// <param name="model">The underlying model to apply the commands to</param> public void Apply(Model model) { if (this.Commands != null) { foreach (string command in this.Commands) { string propertyName = command; string propertyValue = StringUtilities.SplitOffAfterDelimiter(ref propertyName, "="); propertyName = propertyName.TrimEnd(); propertyValue = propertyValue.TrimEnd(); if (propertyName != string.Empty && propertyValue != string.Empty) { IVariable property = Apsim.GetVariableObject(model, propertyName) as IVariable; if (property != null) { this.oldPropertyValues.Add(property.Value); property.Value = propertyValue; this.properties.Add(property); } else { throw new ApsimXException(this, "While applying cultivar '" + Name + "', could not find property name '" + propertyName + "'"); } } } } }
/// <summary> /// Look for an x axis title and units. /// </summary> /// <returns>The x axis title or null if not found.</returns> private string LookForXAxisTitle() { // See if parent has an XProperty property PropertyInfo xProperty = xYPairs.Parent.GetType().GetProperty("XProperty"); if (xProperty != null) { string propertyName = xProperty.GetValue(xYPairs.Parent, null).ToString(); IVariable variable = Apsim.GetVariableObject(xYPairs, propertyName); if (variable != null && variable.UnitsLabel != null) { return(propertyName + " " + variable.UnitsLabel); } return(propertyName); } else if (xYPairs.Parent is AirTemperatureFunction) { return("Mean air temperature (oC)"); } else if (xYPairs.Parent is SoilTemperatureWeightedFunction) { return("Weighted soil temperature (oC)"); } else if (xYPairs.Parent is WeightedTemperatureFunction) { return("Weighted air temperature (oC)"); } else { return(null); } }
/// <summary> /// Constructor for a plain report variable. /// </summary> /// <param name="variableName">The name of the APSIM variable to retrieve</param> /// <param name="columnName">The column name to write to the output</param> /// <param name="frequenciesFromReport">Reporting frequencies</param> /// <param name="parentModel">The parent model</param> private ReportColumn(string variableName, string columnName, string[] frequenciesFromReport, IModel parentModel) { Values = new List <object>(); this.variableName = variableName; this.Name = columnName; this.parentModel = parentModel; this.reportingFrequencies.AddRange(frequenciesFromReport); this.clock = Apsim.Find(parentModel, typeof(Clock)) as Clock; try { IVariable var = Apsim.GetVariableObject(parentModel, variableName); if (var != null) { Units = var.UnitsLabel; } } // Exceptions may arise when we are setting up at the start of simulation, since some of the other model // components might not be fully initialized. If that's the case, we just fail silently and don't // worry about determining units of measurement. catch (Exception) { } foreach (string frequency in this.reportingFrequencies) { Apsim.Subscribe(parentModel, frequency, this.OnReportFrequency); } }
/// <summary>Writes documentation for this function by adding to the list of documentation tags.</summary> /// <param name="tags">The list of tags to add to.</param> /// <param name="headingLevel">The level (e.g. H2) of the headings.</param> /// <param name="indent">The level of indentation 1, 2, 3 etc.</param> public override void Document(List <AutoDocumentation.ITag> tags, int headingLevel, int indent) { // add a heading. tags.Add(new AutoDocumentation.Heading(Name, headingLevel)); // add graph and table. if (XYPairs != null) { IVariable xProperty = Apsim.GetVariableObject(this, XProperty); string xName = XProperty; if (xProperty != null && xProperty.Units != string.Empty) { xName += " (" + xProperty.Units + ")"; } tags.Add(new AutoDocumentation.Paragraph("<i>" + Name + "</i> is calculated as a function of <i>" + xName + "</i>", indent)); // write memos. foreach (IModel memo in Apsim.Children(this, typeof(Memo))) { memo.Document(tags, -1, indent); } tags.Add(new AutoDocumentation.GraphAndTable(XYPairs, string.Empty, xName, Name, indent)); } }
public static ReportColumn Create(string descriptor, IClock clock, IStorageWriter storage, ILocator locator, IEvent events) { string columnName = StringUtilities.RemoveWordAfter(ref descriptor, "as"); object to = StringUtilities.RemoveWordAfter(ref descriptor, "to"); object from = StringUtilities.RemoveWordAfter(ref descriptor, "from"); if (clock is IModel) { if (from != null) { IVariable fromValue = Apsim.GetVariableObject(clock as IModel, from.ToString()); if (fromValue != null) { from = fromValue; } } if (to != null) { IVariable toValue = Apsim.GetVariableObject(clock as IModel, to.ToString()); if (toValue != null) { to = toValue; } } } string aggregationFunction = StringUtilities.RemoveWordBefore(ref descriptor, "of"); string variableName = descriptor; // variable name is what is left over. // specify a column heading if alias was not specified. if (columnName == null) { // Look for an array specification. The aim is to encode the starting // index of the array into the column name. e.g. // for a variableName of [2:4], columnName = [2] // for a variableName of [3:], columnName = [3] // for a variableName of [:5], columnNamne = [0] Regex regex = new Regex("\\[([0-9]):*[0-9]*\\]"); columnName = regex.Replace(variableName.Replace("[:", "[1:"), "($1)"); // strip off square brackets. columnName = columnName.Replace("[", string.Empty).Replace("]", string.Empty); // change any curly brackets back to squares. // columnName = columnName.Replace("{", "[").Replace("}", "]"); } if (aggregationFunction != null) { return(new ReportColumn(aggregationFunction, variableName, columnName, from, to, clock, storage, locator, events)); } else { return(new ReportColumn(variableName, columnName, clock, storage, locator, events)); } }
/// <summary> /// Create and return a new Output object for member /// </summary> /// <param name="typeToDocument">The type of object to inspect.</param> /// <param name="typeofProperties">The type of properties to include in the return table.</param> private List <IVariable> GetParameters(object objectToDocument) { var parameters = new List <IVariable>(); foreach (var parameterName in parameterNames) { var parameter = Apsim.GetVariableObject(objectToDocument as IModel, parameterName); if (parameter != null) { parameters.Add(parameter); } } return(parameters); }
/// <summary> /// Constructor for an aggregated column. /// </summary> /// <param name="aggregationFunction">The aggregation function</param> /// <param name="variableName">The name of the APSIM variable to retrieve</param> /// <param name="columnName">The column name to write to the output</param> /// <param name="from">The beginning of the capture window</param> /// <param name="to">The end of the capture window</param> /// <param name="frequenciesFromReport">Reporting frequencies</param> /// <param name="parentModel">The parent model</param> /// <returns>The newly created ReportColumn</returns> private ReportColumn(string aggregationFunction, string variableName, string columnName, string from, string to, string[] frequenciesFromReport, IModel parentModel) { Values = new List <object>(); this.aggregationFunction = aggregationFunction; this.variableName = variableName; this.Name = columnName; this.parentModel = parentModel; this.inCaptureWindow = false; this.reportingFrequencies.AddRange(frequenciesFromReport); this.clock = Apsim.Find(parentModel, typeof(Clock)) as Clock; try { IVariable var = Apsim.GetVariableObject(parentModel, variableName); if (var != null) { Units = var.UnitsLabel; } } catch (Exception) { } Apsim.Subscribe(parentModel, "[Clock].StartOfDay", this.OnStartOfDay); Apsim.Subscribe(parentModel, "[Clock].DoReportCalculations", this.OnEndOfDay); if (DateTime.TryParse(from, out this.fromDate)) { this.fromHasNoYear = !from.Contains(this.fromDate.Year.ToString()); } else { Apsim.Subscribe(parentModel, from, this.OnBeginCapture); } if (DateTime.TryParse(to, out this.toDate)) { this.toHasNoYear = !to.Contains(this.toDate.Year.ToString()); } else { Apsim.Subscribe(parentModel, to, this.OnEndCapture); } foreach (string frequency in this.reportingFrequencies) { Apsim.Subscribe(parentModel, frequency, this.OnReportFrequency); } }
/// <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 EditFile(string apsimxFileName, List <CompositeFactor> factors) { Simulations file = FileFormat.ReadFromFile <Simulations>(fileName, 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 = Apsim.GetVariableObject(file, factor.Paths[0]); variable.Value = ReflectionUtilities.StringToObject(variable.DataType, factor.Values[0].ToString()); } file.Write(apsimxFileName); }
public static ReportColumn Create(string descriptor, IClock clock, IStorageWriter storage, ILocator locator, IEvent events) { string columnName = RemoveWordAfter(ref descriptor, "as"); object to = RemoveWordAfter(ref descriptor, "to"); object from = RemoveWordAfter(ref descriptor, "from"); if (clock is IModel) { if (from != null) { IVariable fromValue = Apsim.GetVariableObject(clock as IModel, from.ToString()); if (fromValue != null) { from = fromValue; } } if (to != null) { IVariable toValue = Apsim.GetVariableObject(clock as IModel, to.ToString()); if (toValue != null) { to = toValue; } } } string aggregationFunction = RemoveWordBefore(ref descriptor, "of"); string variableName = descriptor; // variable name is what is left over. // specify a column heading if alias was not specified. if (columnName == null) { columnName = variableName.Replace("[", string.Empty).Replace("]", string.Empty); } if (aggregationFunction != null) { return(new ReportColumn(aggregationFunction, variableName, columnName, from, to, clock, storage, locator, events)); } else { return(new ReportColumn(variableName, columnName, clock, storage, locator, events)); } }
/// <summary> /// Apply commands. /// </summary> /// <param name="model">The underlying model to apply the commands to</param> public void Apply(Model model) { if (this.Commands != null) { foreach (string command in this.Commands) { string propertyName = command; string propertyValue = StringUtilities.SplitOffAfterDelimiter(ref propertyName, "="); propertyName = propertyName.TrimEnd(); propertyValue = propertyValue.TrimEnd(); if (propertyName != string.Empty && propertyValue != string.Empty) { IVariable property = Apsim.GetVariableObject(model, propertyName) as IVariable; if (property == null) { throw new Exception("Cannot find cultivar property: " + propertyName); } if (property.GetType() != null) { object oldValue = property.Value; if (oldValue is string || oldValue.GetType().IsArray || !oldValue.GetType().IsClass) { this.oldPropertyValues.Add(oldValue); property.Value = propertyValue; this.properties.Add(property); } else { throw new ApsimXException(this, "Invalid type for setting cultivar parameter: " + propertyName + ". Must be a built-in type e.g. double"); } } else { throw new ApsimXException(this, "While applying cultivar '" + Name + "', could not find property name '" + propertyName + "'"); } } } } }
/// <summary>Perform the actual replacement.</summary> /// <param name="simulation">The simulation to perform the replacements on.</param> public void Replace(IModel simulation) { if (path == null) { throw new Exception("No path specified for property replacement."); } Apsim.Set(simulation, path, replacement); // In a multi-paddock context, we want to attempt to // change the property value in all paddocks. foreach (Zone paddock in Apsim.ChildrenRecursively(simulation, typeof(Zone))) { IVariable variable = Apsim.GetVariableObject(paddock, path); if (variable != null) { variable.Value = replacement; } } }
/// <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 EditFile(string apsimxFileName, List <CompositeFactor> factors) { Simulations file = FileFormat.ReadFromFile <Simulations>(fileName, 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 = Apsim.GetVariableObject(file, factor.Paths[0]); if (variable == null) { throw new Exception($"Invalid path: {factor.Paths[0]}"); } string value = factor.Values[0].ToString(); string absolutePath; try { absolutePath = PathUtilities.GetAbsolutePath(value, Directory.GetCurrentDirectory()); } catch { absolutePath = null; } 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 { variable.Value = ReflectionUtilities.StringToObject(variable.DataType, 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 { variable.Value = ReflectionUtilities.StringToObject(variable.DataType, value); } } file.Write(apsimxFileName); }
/// <summary> /// Initialise the column instance. /// </summary> /// <param name="aggFunction">The aggregation function.</param> /// <param name="varName">The name of the variable to get from APSIM.</param> /// <param name="on">The collection event.</param> /// <param name="alias">The alias.</param> /// <param name="from">The from variable.</param> /// <param name="to">The to variable.</param> private void Initialise(string aggFunction, string varName, string on, string alias, string from, string to) { aggregationFunction = aggFunction; variableName = varName; fromString = from; toString = to; Name = alias; // specify a column heading if alias was not specified. if (string.IsNullOrEmpty(Name)) { // Look for an array specification. The aim is to encode the starting // index of the array into the column name. e.g. // for a variableName of [2:4], columnName = [2] // for a variableName of [3:], columnName = [3] // for a variableName of [:5], columnNamne = [0] Regex regex = new Regex("\\[([0-9]):*[0-9]*\\]"); Name = regex.Replace(variableName.Replace("[:", "[1:"), "($1)"); // strip off square brackets. Name = Name.Replace("[", string.Empty).Replace("]", string.Empty); } // Try and get units. try { IVariable var = locator.GetObject(variableName); if (var != null) { Units = var.UnitsLabel; if (Units != null && Units.StartsWith("(") && Units.EndsWith(")")) { Units = Units.Substring(1, Units.Length - 2); } } } catch (Exception) { } if (string.IsNullOrEmpty(fromString)) { inCaptureWindow = true; } else { // temporarly aggregated variable // subscribe to the capture event var collectionEventName = "[Clock].DoReportCalculations"; if (!string.IsNullOrEmpty(on)) { collectionEventName = on; } events.Subscribe(collectionEventName, OnDoReportCalculations); // subscribe to the start of day event so that we can determine if we're in the capture window. events.Subscribe("[Clock].DoDailyInitialisation", OnStartOfDay); fromVariable = Apsim.GetVariableObject(clock as IModel, fromString); toVariable = Apsim.GetVariableObject(clock as IModel, toString); if (fromVariable != null) { // A from variable name was specified. } else if (DateTime.TryParse(fromString, out DateTime date)) { // The from date is a static, hardcoded date string. ie 1-Jan, 1/1/2012, etc. fromVariable = new VariableObject(date); // If the date string does not contain a year (ie 1-Jan), we ignore year and fromHasNoYear = !fromString.Contains(date.Year.ToString()); } else { // Assume the string is an event name. events.Subscribe(fromString, OnFromEvent); inCaptureWindow = true; } if (toVariable != null) { // A to variable name was specified. } else if (DateTime.TryParse(toString, out DateTime date)) { // The from date is a static, hardcoded date string. ie 1-Jan, 1/1/2012, etc. toVariable = new VariableObject(date); // If the date string does not contain a year (ie 1-Jan), we ignore year and toHasNoYear = !toString.Contains(date.Year.ToString()); } else { // Assume the string is an event name. events.Subscribe(toString, OnToEvent); } } }