2017-02-13 9 views
0

Я использую пакет RNetLogo для запуска анализов чувствительности на моей модели NetLogo. Моя модель имеет 24 параметра, которые мне нужно изменить - поэтому параллелизм этого процесса был бы идеальным! Я сопровождал пример с виньеткой «Parallel processing with the RNetLogo package» от Thiele, которая использует пакет «parallel» совместно с «RNetLogo».Только один процессор используется во время работы моделей NetLogo с использованием parApply

Мне удалось получить R, чтобы инициализировать модель NetLogo на всех 12 моих процессорах, которые я проверил с помощью gui = TRUE. Проблема возникает, когда я пытаюсь запустить код моделирования на 12 процессорах, используя «parApply». Эта строка работает без ошибок, но работает только на одном из процессоров (используя около 8% от моей общей мощности процессора). Вот макет из моего файла R коды - я включил некоторый закомментированный код в конце, показывая, как я бег моделирования, не пытаясь parallelise:

### 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") 

Вот макет для «сим» функция (адаптировано из бумаги Тиле в «Облегчение оценки параметров и анализа чувствительности моделей на базе агентов - поваренную книгу, используя 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) 
    } 
} 

Я думаю, что проблема может лежать в «nl.obj» строки, RNetLogo использует для идентификации экземпляра NetLogo, на котором вы хотите запустить код, однако я пробовал несколько разных способов его исправления, и я не смог прийти p с решением, которое работает. Когда я инициализирую NetLogo на всех процессорах, используя код, представленный в примере Тиле, я не устанавливаю значение «nl.obj» для каждого экземпляра, так что я предполагаю, что RNetLogo использует какой-то список по умолчанию? Однако в оригинальном коде Thiele функция «sim» требует, чтобы вы указали, какой экземпляр NetLogo вы хотите запустить, поэтому R будет выплевывать ошибку при попытке запустить финальную строку (Ошибка в checkForRemoteErrors (val): один узел возникла ошибка: отсутствует аргумент «nl.obj», без значения по умолчанию). Я изменил код функции «sim», так что он не требует этого аргумента и просто принимает значение по умолчанию для nl.obj - но тогда моя симуляция работает только на одном процессоре. Поэтому я считаю, что по умолчанию «sim» должен запускать код только в одном экземпляре NetLogo. Я не уверен, как это исправить.

Это также первый раз, когда я использовал пакет «parallel», поэтому я мог бы пропустить что-то очевидное, чтобы сделать с «parApply». Любое понимание было бы высоко оценено!

Заранее благодарен!

ответ

0

Я все еще в процессе применения подобной техники для выполнения скрининга элементарных эффектов Morris с моей моделью NetLogo. Для меня параллельное выполнение работает отлично. Я сравнил ваш сценарий с моим и заметил, что в моей версии вызов функции parApply функции симуляции (simfun) встроен в инструкцию функции (см. Ниже). Возможно, в том числе функция уже решает вашу проблему.

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")}) 
+0

Спасибо за ответ @Tyr! Я попытался изменить свой код, чтобы он соответствовал вашему примеру, но я получаю ошибку: «Ошибка в parApply (cl, base.param, 1, function (x) {: dim (X) должна иметь положительную длину». Но когда Я проверяю длину X (который я предполагаю base.param), это 24. У вас это вообще получилось? – Rebecca

+0

Woops, поцарапайте это @Tyr, я исправил его (перестроил несколько вещей и забыл преобразовать в матрица) .Код работает нормально, но, к сожалению, проблема все еще существует - он использует только один процессор. Если для вас работает один и тот же код для процессоров, мне интересно, есть ли что-то, что мне нужно переопределить в R, чтобы заставить его использовать больше, чем один процессор? Hmmm. – Rebecca

+0

ahh.При этом base.param должен быть матрицей. Я снова проверил ваш код и посмотрел на конструкцию вашей матрицы параметров. Верно ли, что в вашей матрице у вас есть только один эксперимент, то есть одна строка в вашей матрице? Это объясняет, почему используется только одно ядро, потому что есть только один эксперимент.Параллелизация работает только в том случае, если в вашей матрице параметров имеется несколько строк. Затем каждая строка моделируется другим ядром. – Tyr