使用parApply运行NetLogo模型时只使用一个处理器

时间:2017-02-13 05:29:33

标签: r parallel-processing netlogo

我正在使用'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'有关的东西。任何见解都会非常感激!

提前致谢!

1 个答案:

答案 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")})