преобразование вложенных l oop в foreach - PullRequest
0 голосов
/ 06 августа 2020

Я пытаюсь преобразовать вложенный l oop в foreach, чтобы можно было использовать параллельную обработку. Этот l oop извлекает информацию из файлов netCDF на основе списка векторов, которые обозначают положение элементов в netCDF для извлечения. Вот мой пример:

загрузить необходимые пакеты

# devtools::install_github("BigelowLab/fvcom", force = T)

library(fvcom)
library(ncdf4)
library(raster)
library(rgdal)

У меня есть файлы netCDF, сохраненные на жестком диске, но они доступны здесь: https://www.glerl.noaa.gov/data/chrp/Rowe_etal_2019_data/20170530-2/ Для В этом примере я использовал первые 3 файла на этой странице.

setwd("D:/FADR81 netCDF files/example for parallel processing")

file_list <- list.files(pattern = "*.nc")

Создайте список векторов, указывающих положение элементов, которые я хочу извлечь из каждого файла netCDF. Здесь они присвоены произвольно, но на самом деле совпадают с наблюдениями из другого набора данных.

k1 <- 1:10
k2 <- c(1:5, 12:20, 45:51)
k3 <- 200:213

keep <- list(k1, k2, k3)

Запустите l oop, чтобы извлечь время и создать растры температуры и растворенного кислорода.

system.time({

  times.all <- character(length(keep[[1]]))
  temp.all <- list()
  do.all <- list ()

  for(i in 1:length(keep)) {
    nc <- nc_open(file_list[[i]])
    mesh <- get_mesh_geometry(nc, what = 'lonlat')
    times <- character(length = length(keep[[i]]))
    temp <- list()
    do <- list()

    for(j in 1:length(keep[[i]])) {
      times[j] <- as.character(as.POSIXct(ncvar_get(nc, "Times", start=c(1, keep[[i]][j]), count=c(-1, 1)),
                                      format = "%Y-%m-%dT%H:%M:%S", tz = "UTC"))
  
      temp[[j]] <- get_mesh(nc, vars = "temp", mesh = mesh, time = keep[[i]][j], y = 20)
      temp[[j]] <- raster::stack(sapply('temp', function(f) fvcom::rasterize(temp[[j]], field = f), simplify = FALSE))
  
      do[[j]] <- get_mesh(nc, vars = "Dissolved_oxygen", mesh = mesh, time = keep[[i]][j], y = 20)
      do[[j]] <- raster::stack(sapply('Dissolved_oxygen', function(f) fvcom::rasterize(do[[j]], field = f), simplify = FALSE))
  
    }

    nc_close(nc)

    times.all <- c(times.all, times)
    temp.all <- c(temp.all, temp)
    do.all <- c(do.all, do)

  }

  times.all2 <- times.all[-which(times.all == '')]

})

Мне нужно l oop более сотни файлов netCDF и извлекать различные элементы из каждого файла. Я надеюсь, что смогу использовать foreach для распараллеливания этого l oop и повышения скорости обработки, но мне не очень повезло с пониманием того, как это сделать. Любая помощь приветствуется.

1 Ответ

0 голосов
/ 10 августа 2020

Следуя предложению Роланда, я более внимательно посмотрел на функции apply и смог переписать свой for l oop как функцию и использовать mapply () для дублирования моих предыдущих результатов. Оттуда это был простой переход к mcmapply () в параллельном пакете. Вот моя функция и код, который я использовал для запуска этого с помощью mcmapply () с использованием списка_файлов и придерживаюсь исходного вопроса.

get_dat <- function(x, z){
  nc <- nc_open(x)
  times <- as.character(as.POSIXct(ncvar_get(nc, "Times"), format = "%Y-%m-%dT%H:%M:%S", tz = "UTC"))
  times2 <- times[z]

  mesh <- get_mesh_geometry(nc, what = 'lonlat')
  temp <- list()
  do <- list()

  for(i in 1:length(z)) {

    temp[[i]] <- get_mesh(nc, vars = "temp", mesh = mesh, time = z[[i]], y = 20)
    temp[[i]] <- raster::stack(sapply('temp', function(f) fvcom::rasterize(temp[[i]], field = f), simplify = FALSE))

    do[[i]] <- get_mesh(nc, vars = "Dissolved_oxygen", mesh = mesh, time = z[[i]], y = 20)
    do[[i]] <- raster::stack(sapply('Dissolved_oxygen', function(f) fvcom::rasterize(do[[i]], field = f), simplify = FALSE))

  }


  nc_close(nc)

  exp.dat <- list(times2, temp, do)

  return(exp.dat)
}



system.time({

  new.dat <- mcmapply(get_dat, file_list, keep, mc.cores = 3)

  new.time <- list()
  new.temp <- list()
  new.do <- list()

  for(i in 1:length(file_list)){
    new.time[[i]] <- new.dat[1, i]
    new.temp[[i]] <- new.dat[2, i]
    new.do[[i]] <- new.dat[3, i]

  }

  new.time2 <- unlist(new.time, use.names = F)
  new.temp2 <- unlist(new.temp, use.names = F)
  new.do2 <- unlist(new.do, use.names = F)

})

Вы можете воспроизвести этот пример, загрузив файлы netCDF по ссылке, указанной в исходный вопрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...