我正在使用'RNetLogo'软件包在我的NetLogo模型上运行敏感度分析。我的模型有24个参数我需要改变 - 因此并行化这个过程将是理想的!我一直在跟随Thiele的“Parallel processing with the RNetLogo package”插图中的示例,该插图将“并行”包与“RNetLogo”结合使用。
我已经设法让R在我的所有12个处理器中初始化NetLogo模型,我已经使用gui = TRUE进行了验证。当我尝试使用'parApply'在12个处理器上运行模拟代码时出现问题。此行运行时没有错误,但它只在其中一个处理器上运行(占总CPU功率的8%左右)。这是我的R代码文件的模拟 - 我在最后包含了一些注释掉的代码,显示了我如何在不尝试并行化的情况下运行模拟:
### Load packages
library(parallel)
### Set up initialisation function
prepro <- function(dummy, gui, nl.path, model.path) {
library(RNetLogo)
NLStart(nl.path, gui=gui)
NLLoadModel(model.path)
}
### Set up finalisation function
postpro <- function(x) {
NLQuit()
}
### Set paths
# For NetLogo
nl.path <- "C:/Program Files/NetLogo 6.0/app"
nl.jarname <- "netlogo-6.0.0.jar"
# For the model
model.path <- "E:/Model.nlogo"
# For the function "sim" code
sim.path <- "E:/sim.R"
### Set base values for parameters
base.param <- c('prey-max-velocity' = 25,
'prey-agility' = 3.5,
'prey-acceleration' = 20,
'prey-deceleration' = 25,
'prey-vision-distance' = 10,
'prey-vision-angle' = 240,
'time-to-turn' = 5,
'time-to-return-to-foraging' = 300,
'time-spent-circling' = 2,
'predator-max-velocity' = 35,
'predator-agility' = 3.5,
'predator-acceleration' = 20,
'predator-deceleration' = 25,
'predator-vision-distance' = 20,
'predator-vision-angle' = 200,
'time-to-give-up' = 120,
'number-of-safe-zones' = 1,
'number-of-target-patches' = 5,
'proportion-obstacles' = 0.05,
'obstacle-radius' = 2.0,
'obstacle-radius-range' = 0.5,
'obstacle-sensitivity-for-prey' = 0.95,
'obstacle-sensitivity-for-predators' = 0.95,
'safe-zone-attractiveness' = 500
)
## Get names of parameters
param.names <- names(base.param)
### Load the code of the simulation function (name: sim)
source(file=sim.path)
### Convert "base.param" to a matrix, as required by parApply
base.param <- matrix(base.param, nrow=1, ncol=24)
### Get the number of simulations we want to run
design.combinations <- length(base.param[[1]])
already.processed <- 0
### Initialise NetLogo
processors <- detectCores()
cl <- makeCluster(processors)
clusterExport(cl, 'sim')
gui <- FALSE
invisible(parLapply(cl, 1:processors, prepro, gui=gui, nl.path=nl.path, model.path=model.path))
### Run the simulation across all processors, using parApply
sim.result.base <- parApply(cl, base.param, 1, sim,
param.names,
no.repeated.sim = 100,
trace.progress = FALSE,
iter.length = design.combinations,
function.name = "base parameters")
### Run the simulation on a single processor
#sim.result.base <- sim(base.param,
# param.names,
# no.repeated.sim = 100,
# my.nl1,
# trace.progress = TRUE,
# iter.length = design.combinations,
# function.name = "base parameters")
这是'sim'功能的模拟(改编自Thiele的论文“促进基于代理的模型的参数估计和灵敏度分析 - 使用NetLogo和R的食谱”):
sim <- function(param.set, parameter.names, no.repeated.sim, trace.progress, iter.length, function.name) {
# Some security checks
if (length(param.set) != length(parameter.names))
{ stop("Wrong length of param.set!") }
if (no.repeated.sim <= 0)
{ stop("Number of repetitions must be > 0!") }
if (length(parameter.names) <= 0)
{ stop("Length of parameter.names must be > 0!") }
# Create an empty list to save the simulation results
eval.values <- NULL
# Run the repeated simulations (to control stochasticity)
for (i in 1:no.repeated.sim)
{
# Create a random-seed for NetLogo from R, based on min/max of NetLogo's random seed
NLCommand("random-seed",runif(1,-2147483648,2147483647))
## This is the stuff for one simulation
cal.crit <- NULL
# Set NetLogo parameters to current parameter values
lapply(seq(1:length(parameter.names)), function(x) {NLCommand("set ",parameter.names[x], param.set[x])})
NLCommand("setup")
# This should run "go" until prey-win =/= 5, i.e. when the pursuit ends
NLDoCommandWhile("prey-win = 5", "go")
# Report a value
prey <- NLReport("prey-win")
# Report another value
pred <- NLReport("predator-win")
## Extract the values we are interested in
cal.crit <- rbind(cal.crit, c(prey, pred))
# append to former results
eval.values <- rbind(eval.values,cal.crit)
}
## Make sure eval.values has column names
names(eval.values) <- c("PreySuccess", "PredSuccess")
# Return the mean of the repeated simulation results
if (no.repeated.sim > 1) {
return(colMeans(eval.values))
}
else {
return(eval.values)
}
}
我认为问题可能在于RNetLogo用来识别你想要运行代码的NetLogo实例的“nl.obj”字符串 - 但是,我已经尝试了几种不同的方法来解决这个问题,而且我还没有能够提出一个有效的解决方案。当我使用Thiele示例中提供的代码在所有处理器上初始化NetLogo时,我没有为每个实例设置“nl.obj”值,所以我猜RNetLogo使用某种默认列表?然而,在蒂勒的原代码,在“SIM卡”的功能需要指定要运行它其中的NetLogo实例 - 所以R将吐出一个错误,当我尝试运行checkForRemoteErrors最后一行(错误(VAL):一个节点产生错误:参数“nl.obj”丢失,没有默认值)。我已经修改了“sim”功能代码,因此它不需要这个参数,只接受nl.obj的默认设置 - 但是我的模拟只运行在一个处理器上。所以,我认为默认情况下,“sim”只能在NetLogo的单个实例上运行代码。我不确定如何解决它。
这也是我第一次使用'并行'软件包,所以我可能会遗漏一些明显与'parApply'有关的东西。任何见解都会非常感激!
提前致谢!
答案 0 :(得分:0)
我仍然在使用类似的技术来使用我的NetLogo模型执行Morris基本效果筛选。对我来说,并行执行工作正常。我将你的脚本与我的脚本进行了比较,并注意到在我的版本中,模拟函数(simfun)的'parApply'调用嵌入在函数语句中(见下文)。也许包括该功能已经解决了你的问题。
sim.results.morris <- parApply(cl, mo$X, 1, function(x) {simfun(param.set=x,
no.repeated.sim=no.repeated.sim,
parameter.names=input.names,
iter.length=iter.length,
fixed.values=fixed.values,
model.seed=new.model.seed,
function.name="Morris")})