关于遍历netcdf文件并运行计算:遍历netcdf文件并运行计算-Python或R

Loop through netcdf files and run calculations - Python or R

这是我第一次使用netCDF,我正在努力工作。

我有多个版本3的netcdf文件(一整年的NOAA NARR air.200万日均平均值)。每个文件的时间跨度为1979年至2012年。它们是349 x 277网格,分辨率约为32km。数据是从这里下载的。

维度是时间(自1800年1月1日以来的小时数),我感兴趣的变量是air。我需要计算温度<0的累积天数。例如

1
2
3
4
5
6
    Day 1 = +4 degrees, accumulated days = 0
    Day 2 = -1 degrees, accumulated days = 1
    Day 3 = -2 degrees, accumulated days = 2
    Day 4 = -4 degrees, accumulated days = 3
    Day 5 = +2 degrees, accumulated days = 0
    Day 6 = -3 degrees, accumulated days = 1

我需要将此数据存储在新的netcdf文件中。我对Python有点熟悉,对R也很熟悉。每天循环浏览,检查前几天的值的最佳方法是什么,然后根据此值将值输出到新的netcdf文件,其尺寸和变量完全相同... 。或只是将另一个变量添加到我正在寻找的输出中的原始netcdf文件中。

最好将所有文件分开或合并吗?我将它们与ncrcat结合使用,效果很好,但文件大小为2.3gb。

感谢您的输入。

我目前在python中的进展:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import numpy
import netCDF4
#Change my working DIR
f = netCDF4.Dataset('air7912.nc', 'r')
for a in f.variables:
  print(a)

#output =
     lat
     long
     x
     y
     Lambert_Conformal
     time
     time_bnds
     air

f.variables['air'][1, 1, 1]
#Output
     298.37473

为了帮助我更好地理解这一点,我正在使用哪种类型的数据结构?上例中的['air']键是键,[1,1,1]还是键吗?得到298.37473的值。然后如何遍历[1,1,1]?


您可以使用netCDF4中非常好的MFDataset功能将一堆文件视为一个聚合文件,而无需使用ncrcat。因此,您的代码应如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pylab import *
import netCDF4

f = netCDF4.MFDataset('/usgs/data2/rsignell/models/ncep/narr/air.2m.19??.nc')
# print variables
f.variables.keys()

atemp = f.variables['air']
print atemp

ntimes, ny, nx = shape(atemp)
cold_days = zeros((ny,nx),dtype=int)

for i in xrange(ntimes):
    cold_days += atemp[i,:,:].data-273.15 < 0

pcolormesh(cold_days)
colorbar()

generated image of cold days

这是一种写入文件的方法(可能有更简单的方法):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# create NetCDF file
nco = netCDF4.Dataset('/usgs/data2/notebook/cold_days.nc','w',clobber=True)
nco.createDimension('x',nx)
nco.createDimension('y',ny)

cold_days_v = nco.createVariable('cold_days', 'i4',  ( 'y', 'x'))
cold_days_v.units='days'
cold_days_v.long_name='total number of days below 0 degC'
cold_days_v.grid_mapping = 'Lambert_Conformal'

lono = nco.createVariable('lon','f4',('y','x'))
lato = nco.createVariable('lat','f4',('y','x'))
xo = nco.createVariable('x','f4',('x'))
yo = nco.createVariable('y','f4',('y'))
lco = nco.createVariable('Lambert_Conformal','i4')

# copy all the variable attributes from original file
for var in ['lon','lat','x','y','Lambert_Conformal']:
    for att in f.variables[var].ncattrs():
        setattr(nco.variables[var],att,getattr(f.variables[var],att))

# copy variable data for lon,lat,x and y
lono[:]=f.variables['lon'][:]
lato[:]=f.variables['lat'][:]
xo[:]=f.variables['x'][:]
yo[:]=f.variables['y'][:]

#  write the cold_days data
cold_days_v[:,:]=cold_days

# copy Global attributes from original file
for att in f.ncattrs():
    setattr(nco,att,getattr(f,att))

nco.Conventions='CF-1.6'
nco.close()

如果我尝试在Unidata NetCDF-Java Tools-UI GUI中查看生成的文件,那似乎还可以:
enter image description here
还要注意,这里我只是下载了两个数据集进行测试,所以我使用了

1
f = netCDF4.MFDataset('/usgs/data2/rsignell/models/ncep/narr/air.2m.19??.nc')

举个例子。对于所有数据,您可以使用

1
f = netCDF4.MFDataset('/usgs/data2/rsignell/models/ncep/narr/air.2m.????.nc')

要么

1
f = netCDF4.MFDataset('/usgs/data2/rsignell/models/ncep/narr/air.2m.*.nc')


这是一个R解决方案。

1
2
3
4
5
6
7
8
9
10
infiles <- list.files("data", pattern ="nc", full.names = TRUE, include.dirs = TRUE)

outfile <-"data/air.colddays.nc"    

library(raster)

r <- raster::stack(infiles)
r <- sum((r - 273.15) < 0)

plot(r)

enter image description here


我知道对于从2013年开始的该主题来说,这已经很晚了,但是我只想指出,公认的解决方案并不能为提出的确切问题提供解决方案。问题似乎是希望温度的每个连续周期的长度都低于零(请注意问题,如果温度超过零,计数器将重置),这对于气候应用(例如,对于农业)可能很重要,而公认的解决方案仅给出了总和一年中温度低于零的天数。如果这确实是mkmitchell想要的(已被接受为答案),则可以从cdo的命令行中完成它,而不必担心NETCDF输入/输出:

1
 cdo timsum -lec,273.15 in.nc out.nc

因此循环脚本将是:

1
2
3
4
5
files=`ls *.nc` # pick up all the netcdf files in a directory
for file in $files ; do
    # I use 273.15 as from the question seems T is in Kelvin
    cdo timsum -lec,273.15 $file ${file%???}_numdays.nc
done

如果您想要整个期间的总数,则可以为_numdays文件设置目录,而不是较小的文件:

1
2
cdo cat *_numdays.nc total.nc
cdo timsum total.nc total_below_zero.nc

但是同样,该问题似乎想要每个事件的累积天数,这是不同的,但不是由公认的答案提供的。