【问题标题】:Loop through year, month, day for netCDF file name循环遍历 netCDF 文件名的年、月、日
【发布时间】:2016-08-01 05:28:01
【问题描述】:

我在 R 中使用 for 循环从文件夹中读取 netCDF 文件并提取给定经度、纬度列表的值。它看起来像工作,除了一个问题。当循环根据日期返回值时,它会在 2 月 28 日之后创建 1 月 29 日到 31 日。像往常一样,我希望在 2 月 28 日或 29 日(闰年)之后的 3 月 1 日。这是我的 R 代码:

# given latitude, longitude list
sb1 <- data.frame(longitude=1:10,latitude =1:10)

# Extracting zonal or sub-basin average rainfall from netCDF file

sb1_r <- c()
date <- c()
rain_month <- c()
rain_year <- c()


for (year in 1998:1998){
  for (month in 1:3){
     for (day in seq_along(1:31)){
        FileName <- paste('3B42_daily',year,sprintf("%02d",month),sprintf("%02d", day),'7.SUB.nc', sep='.')
     if (!file.exists(FileName)){
     next
     } else {

      File <- nc_open(FileName)
      rain <- ncvar_get(File, 'r')

      sb1_r[day] <- mean(apply(sb1,1,function(x)rain[x[1],x[2]]),na.rm = TRUE)
      date[day] <-  paste(year,sprintf("%02d", month),sprintf("%02d", day),sep='-')
      rain_month <- data.frame(date,sb1_r)
      nc_close(File)
      }
    }

    rain_year <- rbind(rain_year,rain_month) 
  }

} 

您可以在此链接中找到三个月的每日 netCDF 数据: https://drive.google.com/open?id=0B8rqKaYt0VEaMWVGc1gzdXI1U28

【问题讨论】:

  • 您在 1 月、2 月和 3 月拥有 for (day in seq_along(1:31))。但是,二月只有28天。这可能是问题吗?如果是这样,您需要自定义循环。
  • @Gandalf 但我没有名称为 3B42_daily.1998.02.29.7.SUB 等的 NetCDF 文件。为了避免这种情况,我在我的代码中加入了“if (!file.exists(FileName)){”。
  • 只是要指出,在使用例如常规纬度/经度网格,因为网格单元的大小不同。因此,每个单元格中的值需要按单元格面积加权。简单地使用 CDO 自动解决这个问题要好得多 - 见下文。

标签: r loops netcdf cdo-climate


【解决方案1】:

请注意,R 中的上述代码正确,除非降雨 netcdf 文件使用等面积网格,这种情况很少发生! (本例中使用的 TRMM 文件并非如此)。这是处理网格数据时的常见错误。

例如,如果您有一个规则的纬度/经度网格,您需要考虑在您向两极移动时经度维度的余弦缩减。如果您的子流域很小,则误差很小,但如果面积很大,则误差会很大。对于某些类型的网格,例如减少的高斯网格,如果您的子域恰好与经度点数的不连续变化相吻合,则误差可能非常大,特别是对于降水等“非光滑”场。

我总是使用 CDO 执行分区和子流域处理,以确保正确执行计算。如果您使用 CDO,则面积平均和区域平均函数会考虑原生网格。

因此我的代码看起来像这样:

#!/bin/bash

# define the lat-lon bounds of your sub area
lat1=20
lat2=30
lon1=0
lon2=20

# merge all the daily files into one file
# do this one month at a time as some system limit number of open files

year=1998 # can make this a loop if you want multiple years
for month in `seq -f "%02g" 1 3`  ; do 
  files=`ls 3B42_daily1998${month}*.nc`
  cdo mergetime $files TRMM_${month}.nc
done
cdo mergetime $TRMM_*.nc TRMM_timeseries.nc

# now extract the subdomain
cdo sellonlatbox,$lon1,$lon2,$lat1,$lat2 TRMM_timeseries.nc TRMM_box.nc

# CORRECT area average 
cdo fldmean TRMM_box.nc TRMM_box_av.nc

# zonal average
cdo zonmean TRMM_box.nc TRMM_box_zon.nc

【讨论】:

    【解决方案2】:

    与其尝试创建文件名,不如执行相反的操作。提取文件名,并为每个文件从文件名中获取日期,并从文件中获取 sb1_r。您可以使用 data.table 包中的 rbindlist 更快地做到这一点(但不是必需的)。

    # 给定纬度、经度列表 sb1

    # Extracting zonal or sub-basin average rainfall from netCDF file
    filenames = list.files(path = ".", pattern = ".nc")
    rain_year = data.frame()
    
    require(ncdf4)
    for(FileName in filenames){
      File <- nc_open(FileName)
      # Create Date
      year <- strsplit(FileName, split = '[.]')[[1]][2]
      month <- strsplit(FileName, split = '[.]')[[1]][3]
      day <- strsplit(FileName, split = '[.]')[[1]][4]
      date = paste(year, month, day, sep = "-")
      # get value
      rain <- ncvar_get(File, 'r')
      sb1_r <- mean(apply(sb1,1,function(x)rain[x[1],x[2]]),na.rm = TRUE)
      # update data.frame
      rain_year = rbind(rain_year, data.frame(date = date, sb1_r = sb1_r))
      nc_close(File)
    }
    
    # Faster using data.table package
    require(data.table)
    temp = rbindlist(
      lapply(X = filenames, function(FileName){
        year <- as.integer( strsplit(FileName, split = '[.]')[[1]][2] )
        month <- as.integer( strsplit(FileName, split = '[.]')[[1]][3] )
        day <- as.integer( strsplit(FileName, split = '[.]')[[1]][4] )
        date = paste(year, month, day, sep = "-")
        File <- nc_open(FileName)
        rain <- ncvar_get(File, 'r')
        sb1_r <- mean(apply(sb1,1,function(x)rain[x[1],x[2]]),na.rm = TRUE)
        return(data.frame(date = date, sb1_r = sb1_r))
      })
    )
    

    【讨论】:

      【解决方案3】:
      #!/usr/bin/env Rscript
      argv<-commandArgs(trailingOnly=TRUE)
      if(length(argv)==2 & argv[1] <= argv[2]) {
        if (is.na(strptime(sprintf("%s",argv[1]),"%Y%m%d"))) {
          cat("arguments valid check error: ", argv[1], "\n")
          stop()
        }
        if (argv[2]!=format(strptime(sprintf("%s",argv[2]),"%Y%m%d"),"%Y%m%d")) {
          cat("arguments valid check error: ", argv[2], "\n")
          stop()
        }
      } else if (length(argv)==2 & argv[1] > argv[2]) {
         print(sprintf("error: %s is greater than %s",argv[1],argv[2]))
         stop()
      } else if (length(argv)!=2) {
         script.name<-basename(strsplit(commandArgs(trailingOnly=FALSE)[4],"=")[[1]][2])
         print(sprintf("Usage: %s startDate endDate",script.name))
         stop()
      }
      
      filelist<-c()
      for (Ymd in format(seq(
         as.POSIXct(sprintf("%s",argv[1]),format="%Y%m%d"),
         as.POSIXct(sprintf("%s",argv[2]),format="%Y%m%d"),
         by="24 hour"),"%Y%m%d")) {
         filelist<-append(filelist, sprintf("%s.%s.%s.%s.%s","3B42_daily",substr(Ymd,1,4),substr(Ymd,5,6),substr(Ymd,7,8),"7.SUB.nc"))
      }
      
      sb1_r <- c()
      date <- c()
      rain_month <- c()
      rain_year <- c()
      
      for (i in 1:length(filelist)) {
      if (!file.exists(filelist[i])){
        next
       } else {
        year <- as.numeric(substr(filelist[i],12,15))
        month <- as.numeric(substr(filelist[i],17,18))
        day <- as.numeric(substr(filelist[i],20,21))
        File <- nc_open(filelist[i])
        rain <- ncvar_get(File, 'r')
      
        sb1_r[day] <- mean(apply(sb1,1,function(x)rain[x[1],x[2]]),na.rm = TRUE)
        date[day] <-  paste(year,sprintf("%02d", month),sprintf("%02d", day),sep='-')
        rain_month <- data.frame(date,sb1_r)
        nc_close(File)
        }
      }
      

      【讨论】:

      • 您能否就与其他问题相比所做的更改添加一些解释?现在很难理解您的解决方案的优势。
      猜你喜欢
      • 2019-01-03
      • 1970-01-01
      • 2021-12-02
      • 2013-09-10
      • 1970-01-01
      • 2021-12-30
      • 2013-09-20
      • 1970-01-01
      • 2011-01-10
      相关资源
      最近更新 更多