tutorials:sensitivity-analysis-using-grolink-and-gror
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
tutorials:sensitivity-analysis-using-grolink-and-gror [2024/06/25 14:24] – [Sensitivity analysis on GroIMP models using GroR] thomas | tutorials:sensitivity-analysis-using-grolink-and-gror [2024/07/01 12:39] (current) – [Example: Morris Screening using the sensitivity package] thomas | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== Sensitivity analysis on GroIMP models using GroR ====== | ====== Sensitivity analysis on GroIMP models using GroR ====== | ||
- | This wiki explains how to do a sensitivity analysis on GroIMP models using the GroR interface using a Morris screening over input parameters of the [[https://wwwuser.gwdguser.de/ | + | This wiki explains how to do a sensitivity analysis on GroIMP models using the GroR interface using a Morris screening over input parameters of the [[http://134.76.18.36/wordpress/courses-and-tutorials/simplefspm/ | " |
===== Prerequisites ===== | ===== Prerequisites ===== | ||
+ | Make sure to [[: | ||
+ | |||
+ | ==== Downloads ==== | ||
+ | * {{ : | ||
+ | * {{ : | ||
+ | |||
===== Prepare your model===== | ===== Prepare your model===== | ||
+ | In any sensitivity analysis, you will need three things: | ||
+ | * Some way of pushing parameter settings to the model | ||
+ | * Some way of knowing that your model has finished or reached a point of interest | ||
+ | * Some way of grabbing the model output at that point of interest | ||
+ | |||
+ | The approach presented here is built on the idea of being able to do all of these things from within R. | ||
+ | Therefore, your model will likely have to be adapted so you can feed all of this information easily through GroR. | ||
+ | |||
+ | ==== Parameter File ==== | ||
+ | Parameters will be pushed to the model by modifying a special RGG file which contains only the Parameter definitions, | ||
+ | |||
+ | <code java> | ||
+ | protected void run () | ||
+ | [ Bud(r, | ||
+ | Bud(r, | ||
+ | RV(-0.1) Internode(parameters.NormalInternodeLength, | ||
+ | [RL(70) Leaf(parameters.LeafLength, | ||
+ | Bud(r, | ||
+ | |||
+ | nf: | ||
+ | nf: | ||
+ | ] | ||
+ | |||
+ | protected void la () | ||
+ | [ | ||
+ | lf:Leaf ::> { | ||
+ | lf[al] = lm.getAbsorbedPower3d(lf).integrate()*2.25; | ||
+ | lf.(setShader(new AlgorithmSwitchShader(new RGBAShader((float) lf[al]/ | ||
+ | lf[as] = (lf[al]*86400*2)/ | ||
+ | lf[age]++; | ||
+ | float lfas = sum((* Leaf *)[as]); | ||
+ | if (lfas>0) {lf[length] += logistic(2, | ||
+ | lf[width] = lf[length]*parameters.LeafAspectRatio; | ||
+ | } | ||
+ | ... | ||
+ | ] | ||
+ | |||
+ | </ | ||
+ | The parameter values are defined in a seperate file, '' | ||
+ | |||
+ | {{: | ||
+ | |||
+ | The folder and file can be created via < | ||
+ | The file only contains the parameter definitions (the values are what they were in the original gallery model): | ||
+ | |||
+ | <code java> | ||
+ | static float NormalInternodeLength = 0.1; | ||
+ | static float FlowerInternodeLength = 0.05; | ||
+ | static float LeafLength = 0.1; | ||
+ | static float LeafAspectRatio = 0.7; | ||
+ | static float PlantWideness = 0.1; | ||
+ | </ | ||
+ | |||
+ | '' | ||
+ | |||
+ | <code java> | ||
+ | import parameters.*; | ||
+ | </ | ||
+ | |||
+ | ==== POI definition and output communication ==== | ||
+ | The '' | ||
+ | For this example, I decided that the interesting output would be the total absorbed light by the leaves at the point when the first flower emerges. Because you can conveniently grab the output on the console in GroR, I added some code in the '' | ||
+ | |||
+ | <code java> | ||
+ | if(count((*NiceFlower*)) > 0){ | ||
+ | println(sum((* Leaf *)[al])); | ||
+ | } else { | ||
+ | println(" | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | So, after every '' | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
===== Model execution and output gathering in R===== | ===== Model execution and output gathering in R===== | ||
+ | I will first demonstrate the concept by gathering the output (the amount of absorbed light) from just one model execution (run). | ||
+ | |||
+ | First, load some libraries and set up the workbench with the prepared model: | ||
+ | |||
<code R> | <code R> | ||
- | source(" | + | source(" |
- | ... | + | |
+ | library(future) | ||
+ | library(future.apply) | ||
+ | library(sensitivity) | ||
+ | |||
+ | wb1 <- GroLink.open(" | ||
</ | </ | ||
+ | |||
+ | You can make sure that everything works by looking up the available model functions or reading the parameter file: | ||
+ | |||
+ | <code R> | ||
+ | (functions <- WBRef.listRGGFunctions(wb1)) | ||
+ | WBRef.getFile(wb1, | ||
+ | </ | ||
+ | |||
+ | Now here is the code that gets the model output. It executes the '' | ||
+ | |||
+ | <code R> | ||
+ | model_output <- "" | ||
+ | n_grows <- 0 | ||
+ | while (!(is.numeric(model_output)) && (n_grows < 200)) { | ||
+ | result <- WBRef.runRGGFunction(wb1," | ||
+ | model_output <- unlist(result$console) | ||
+ | if (model_output != "no flower" | ||
+ | model_output <- as.numeric(model_output) | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
===== Example: Morris Screening using the sensitivity package ===== | ===== Example: Morris Screening using the sensitivity package ===== | ||
+ | The Morris Screening will be used to analyze the 5 structural plant growth parameters with regard to their importance (their main and interaction effect) on the total amount of absorbed light by leaves. This is just a random example out of the plethora of available sensitivity analysis methods. Most of the common ones are implemented in the '' | ||
+ | |||
+ | First, I generate a set of input parameters for the model: | ||
+ | |||
+ | <code R> | ||
+ | m <- morris(model = NULL, factors = c(" | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | r = 20, # 20 repetitions | ||
+ | binf = c(0.05, 0.01, 0.05, 0.1, 0.1), # min value of inputs | ||
+ | bsup = c(0.8, 0.1, 1, 1, 1), # max value of inputs | ||
+ | | ||
+ | # grid.jump is recommended to be levels/2, see ?morris | ||
+ | |||
+ | |||
+ | params <- m$X | ||
+ | </ | ||
+ | |||
+ | '' | ||
+ | |||
+ | <code R> | ||
+ | executeModel <- function(params, | ||
+ | wb1 <- GroLink.open(" | ||
+ | WBRef.updateFile(wb1, | ||
+ | | ||
+ | "; | ||
+ | "; | ||
+ | "; | ||
+ | "; | ||
+ | ";", | ||
+ | sep = "" | ||
+ | |||
+ | WBRef.compile(wb1) | ||
+ | |||
+ | model_output <- "" | ||
+ | n_grows <- 0 | ||
+ | while (!(is.numeric(model_output)) && (n_grows < timeout)) { | ||
+ | result <- WBRef.runRGGFunction(wb1," | ||
+ | model_output <- unlist(result$console) | ||
+ | if (model_output != "no flower" | ||
+ | model_output <- as.numeric(model_output) | ||
+ | } | ||
+ | n_grows <- n_grows + 1 | ||
+ | } | ||
+ | if (n_grows == timeout) { | ||
+ | model_output <- NA | ||
+ | } | ||
+ | WBRef.close(wb1) | ||
+ | return(model_output) | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | This function contains the while-loop from above but also modifies (overrides) the '' | ||
+ | |||
+ | <code R> | ||
+ | plan(multisession, | ||
+ | |||
+ | system.time(model_outputs <- future_apply(params, | ||
+ | |||
+ | saveRDS(model_outputs, | ||
+ | </ | ||
+ | |||
+ | Through the use of '' | ||
+ | |||
+ | The only thing remaining is to analyze the output and plot the results: | ||
+ | |||
+ | <code R> | ||
+ | sensitivity:: | ||
+ | |||
+ | plot(m) | ||
+ | </ | ||
+ | |||
+ | This should now look something like this: | ||
+ | |||
+ | {{: | ||
+ | |||
tutorials/sensitivity-analysis-using-grolink-and-gror.1719318288.txt.gz · Last modified: 2024/06/25 14:24 by thomas