/// <summary> /// Return the base R script for running morris. /// </summary> private string GetMorrisRScript() { string paramNames = StringUtilities.Build(Parameters.Select(p => p.Name), ",", "\"", "\""); string lowerBounds = StringUtilities.Build(Parameters.Select(p => p.LowerBound), ","); string upperBounds = StringUtilities.Build(Parameters.Select(p => p.UpperBound), ","); string script = string.Format ("library('sensitivity')" + Environment.NewLine + "params <- c({0})" + Environment.NewLine + "apsimMorris<-morris(model=NULL" + Environment.NewLine + " ,params #string vector of parameter names" + Environment.NewLine + " ,{1} #no of paths within the total parameter space" + Environment.NewLine + " ,design=list(type=\"oat\",levels={2},grid.jump={3})" + Environment.NewLine + " ,binf=c({4}) #min for each parameter" + Environment.NewLine + " ,bsup=c({5}) #max for each parameter" + Environment.NewLine + " ,scale=T" + Environment.NewLine + " )" + Environment.NewLine, paramNames, NumPaths, NumIntervals + 1, Jump, lowerBounds, upperBounds); return(script); }
/// <summary> /// Get a list of parameter values that we are to run. Call R to do this. /// </summary> private void RunRPostSimulation(DataTable predictedValues, out DataTable eeDataRaw, out DataTable statsDataRaw) { string morrisParametersFileName = GetTempFileName("parameters", ".csv"); string apsimVariableFileName = GetTempFileName("apsimvariable", ".csv"); string rFileName = GetTempFileName("morrisscript", ".r"); string eeFileName = GetTempFileName("ee", ".csv"); string statsFileName = GetTempFileName("stats", ".csv"); // write predicted values file using (StreamWriter writer = new StreamWriter(apsimVariableFileName)) DataTableUtilities.DataTableToText(predictedValues, 0, ",", true, writer); // Write parameters using (StreamWriter writer = new StreamWriter(morrisParametersFileName)) DataTableUtilities.DataTableToText(ParameterValues, 0, ",", true, writer); string paramNames = StringUtilities.Build(Parameters.Select(p => p.Name), ",", "\"", "\""); string lowerBounds = StringUtilities.Build(Parameters.Select(p => p.LowerBound), ","); string upperBounds = StringUtilities.Build(Parameters.Select(p => p.UpperBound), ","); string script = GetMorrisRScript(); script += string.Format ("apsimMorris$X <- read.csv(\"{0}\")" + Environment.NewLine + "values = read.csv(\"{1}\", check.names = F)" + Environment.NewLine + "allEE <- data.frame()" + Environment.NewLine + "allStats <- data.frame()" + Environment.NewLine + "for (columnName in colnames(values))" + Environment.NewLine + "{{" + Environment.NewLine + " apsimMorris$y <- values[[columnName]]" + Environment.NewLine + " tell(apsimMorris)" + Environment.NewLine + " ee <- data.frame(apsimMorris$ee)" + Environment.NewLine + " ee$variable <- columnName" + Environment.NewLine + " ee$path <- c(1:{2})" + Environment.NewLine + " allEE <- rbind(allEE, ee)" + Environment.NewLine + " mu <- apply(apsimMorris$ee, 2, mean)" + Environment.NewLine + " mustar <- apply(apsimMorris$ee, 2, function(x) mean(abs(x)))" + Environment.NewLine + " sigma <- apply(apsimMorris$ee, 2, sd)" + Environment.NewLine + " stats <- data.frame(mu, mustar, sigma)" + Environment.NewLine + " stats$param <- params" + Environment.NewLine + " stats$variable <- columnName" + Environment.NewLine + " allStats <- rbind(allStats, stats)" + Environment.NewLine + "}}" + Environment.NewLine + "write.csv(allEE,\"{3}\", row.names=FALSE)" + Environment.NewLine + "write.csv(allStats, \"{4}\", row.names=FALSE)" + Environment.NewLine, morrisParametersFileName.Replace("\\", "/"), apsimVariableFileName.Replace("\\", "/"), NumPaths, eeFileName.Replace("\\", "/"), statsFileName.Replace("\\", "/")); File.WriteAllText(rFileName, script); // Run R R r = new R(); r.RunToTable(rFileName); eeDataRaw = ApsimTextFile.ToTable(eeFileName); statsDataRaw = ApsimTextFile.ToTable(statsFileName); }
/// <summary>Main run method for performing our calculations and storing data.</summary> public void Run() { if (dataStore?.Writer != null && !dataStore.Writer.TablesModified.Contains("Report")) { return; } DataTable predictedData = dataStore.Reader.GetData("Report", filter: "SimulationName LIKE '" + Name + "%'", orderBy: "SimulationID"); if (predictedData != null) { IndexedDataTable variableValues = new IndexedDataTable(null); // Determine how many years we have per simulation DataView view = new DataView(predictedData); view.RowFilter = "SimulationName='" + Name + "Simulation1'"; var Years = DataTableUtilities.GetColumnAsIntegers(view, "Clock.Today.Year"); // Create a results table. IndexedDataTable results; if (Years.Count() > 1) { results = new IndexedDataTable(new string[] { "Year" }); } else { results = new IndexedDataTable(null); } // Loop through all years and perform analysis on each. List <string> errorsFromR = new List <string>(); foreach (double year in Years) { view.RowFilter = "Clock.Today.Year=" + year; foreach (DataColumn predictedColumn in predictedData.Columns) { if (predictedColumn.DataType == typeof(double)) { var values = DataTableUtilities.GetColumnAsDoubles(view, predictedColumn.ColumnName); if (values.Distinct().Count() > 1) { variableValues.SetValues(predictedColumn.ColumnName, values); } } } string paramNames = StringUtilities.Build(Parameters.Select(p => p.Name), ",", "\"", "\""); string sobolx1FileName = GetTempFileName("sobolx1", ".csv"); string sobolx2FileName = GetTempFileName("sobolx2", ".csv"); string sobolVariableValuesFileName = GetTempFileName("sobolvariableValues", ".csv"); // Write variables file using (var writer = new StreamWriter(sobolVariableValuesFileName)) DataTableUtilities.DataTableToText(variableValues.ToTable(), 0, ",", true, writer, excelFriendly: false, decimalFormatString: "F6"); // Write X1 using (var writer = new StreamWriter(sobolx1FileName)) DataTableUtilities.DataTableToText(X1, 0, ",", true, writer, excelFriendly: false, decimalFormatString: "F6"); // Write X2 using (var writer = new StreamWriter(sobolx2FileName)) DataTableUtilities.DataTableToText(X2, 0, ",", true, writer, excelFriendly: false, decimalFormatString: "F6"); string script = string.Format( $".libPaths(c('{R.PackagesDirectory}', .libPaths()))" + Environment.NewLine + $"library('boot', lib.loc = '{R.PackagesDirectory}')" + Environment.NewLine + $"library('sensitivity', lib.loc = '{R.PackagesDirectory}')" + Environment.NewLine + "params <- c({0})" + Environment.NewLine + "n <- {1}" + Environment.NewLine + "nparams <- {2}" + Environment.NewLine + "X1 <- read.csv(\"{3}\")" + Environment.NewLine + "X2 <- read.csv(\"{4}\")" + Environment.NewLine + "sa <- sobolSalt(model = NULL, X1, X2, scheme=\"A\", nboot = 100)" + Environment.NewLine + "variableValues = read.csv(\"{5}\")" + Environment.NewLine + "for (columnName in colnames(variableValues))" + Environment.NewLine + "{{" + Environment.NewLine + " sa$y <- variableValues[[columnName]]" + Environment.NewLine + " tell(sa)" + Environment.NewLine + " sa$S$Parameter <- params" + Environment.NewLine + " sa$T$Parameter <- params" + Environment.NewLine + " sa$S$ColumnName <- columnName" + Environment.NewLine + " sa$T$ColumnName <- columnName" + Environment.NewLine + " sa$S$Indices <- \"FirstOrder\"" + Environment.NewLine + " sa$T$Indices <- \"Total\"" + Environment.NewLine + " if (!exists(\"allData\"))" + Environment.NewLine + " allData <- rbind(sa$S, sa$T)" + Environment.NewLine + " else" + Environment.NewLine + " allData <- rbind(allData, sa$S, sa$T)" + Environment.NewLine + "}}" + Environment.NewLine + "write.table(allData, sep=\",\", row.names=FALSE)" + Environment.NewLine , paramNames, NumPaths, Parameters.Count, sobolx1FileName.Replace("\\", "/"), sobolx1FileName.Replace("\\", "/"), sobolVariableValuesFileName.Replace("\\", "/")); DataTable resultsForYear = null; try { resultsForYear = RunR(script); // Put output from R into results table. if (Years.Count() > 1) { results.SetIndex(new object[] { year.ToString() }); } foreach (DataColumn col in resultsForYear.Columns) { if (col.DataType == typeof(string)) { results.SetValues(col.ColumnName, DataTableUtilities.GetColumnAsStrings(resultsForYear, col.ColumnName)); } else { results.SetValues(col.ColumnName, DataTableUtilities.GetColumnAsDoubles(resultsForYear, col.ColumnName)); } } } catch (Exception err) { string msg = err.Message; if (Years.Count() > 1) { msg = "Year " + year + ": " + msg; } errorsFromR.Add(msg); } } var resultsRawTable = results.ToTable(); resultsRawTable.TableName = Name + "Statistics"; dataStore.Writer.WriteTable(resultsRawTable); if (errorsFromR.Count > 0) { string msg = StringUtilities.BuildString(errorsFromR.ToArray(), Environment.NewLine); throw new Exception(msg); } } }