在网格化netCDF文件中计算选择区域中的变量均值

时间:2014-03-15 18:26:09

标签: python csv average area netcdf

假设我们有TRMM降水数据,每个文件代表每个月的数据。例如,文件夹中的文件是:

     3B42.1998.01.01.7A.nc,
     3B42.1998.02.01.7A.nc, 
     3B42.1998.03.01.7A.nc, 
     3B42.1998.04.01.7A.nc, 
     3B42.1998.05.01.7A.nc, 
     ......
     ......
     3B42.2010.11.01.7A.nc,         
     3B42.2010.12.01.7A.nc.

这些文件的尺寸如下:Xsize = 1440,Ysize = 400,Zsize = 1,Tsize = 1。经度设置为0到360,纬度设置为-50到50。 我想计算某个地区的降水量,比如lon=98.5, lon=100 and lat=4, lat=6.5。这意味着,仅在此区域中读取变量 - :

-------------------- |lon:98.5 lat:6.5| | | |lat:4 lon:100 | ---------------------

我曾经在GrADS(网格分析和显示系统)中这样做。在GrADS中,可以这样做:(简化版)

      yy=1998
      while yr < 2011
        'sdfopen f:\data\trmm\3B42.'yy'.12.01.7A.nc'
        'd aave(pcp,lon=98.5,lon=100.0,lat=4.0,lat=6.5)'
         res=subwrd(result,4)
         rec=write('d:\precip.sp.TRMM3B42.1.'yy'.csv',res,append)   
         yy = yy+1
      endwhile

我试图在Python中做同样的事情,但出了点问题。 经过一些建议,我现在在这里:

     import csv
     import netCDF4 as nc 
     import numpy as np

     #calculating december only
     f = nc.MFDataset('d:/data/trmm/3B43.????.12.01.7A.nc')#maybe I shouldn't do MFDataset?
     pcpt = f.variables['pcp']
     lon = f.variables['longitude']
     lat = f.variables['latitude']
     # Determine which longitudes
     latidx1 = (lat >=4.0 ) & (lat <=6.5 ) 
     lonidx1 = (lon >=98.5 ) & (lon <=100.0 ) 

     rainf1 = pcpt[:]
     rainf1 = rainf1[:, latidx1][..., lonidx1]
     rainf_1 = rainf1

     with open('d:/trmmtest.csv', 'wb') as fp:
          a = csv.writer(fp)
          for i in rainf_1:
              a.writerow([i])

此脚本为CSV文件中的15个值生成一个列表(在我的例子中)。 但是,当我试图获取另一个区域的值,并调整我认为必要的值时,请说:

     latidx2 = (lat >=1.0 ) & (lat <=1.5 ) 
     lonidx2 = (lon >=102.75 ) & (lon <=103.25 ) 

     rainf2 = pcpt[:]
     rainf2 = rainf2[:, latidx2][..., lonidx2]
     rainf_2 = rainf2

我得到与第一个相同的值。

firstarea=[0.511935,1.0771,0.613548,1.48839,0.445161,1.39161,1.03548,0.452903, 3.07725,2.84613 0.701613,2.10581,2.47839,3.84097,2.41065,1.38387]

secondarea=[0.511935,1.0771,0.613548,1.48839,0.445161,1.39161,1.03548,0.452903, 3.07725,2.84613,0.701613,2.10581,2.47839,3.84097,2.41065,1.38387]

我在单独的脚本上测试过,它仍然给我相同的值。我确实检查了地图(之前构建的),这两个地区的值不同(12月平均值)。

知道为什么吗?写这个还有其他优雅的方式吗? THX。

3 个答案:

答案 0 :(得分:2)

如果您使用的是Linux,则可以使用nctoolkit(Wikipedia)解决。以下应该做所有事情:

import nctoolkit as nc
ff = '~/data/TRMM3H/3B42.19980101.12.7A.nc'
data = nc.open_data(ff)
data.clip(lon = [98.5, 100], lat = [4, 6.5])
data.spatial_mean()

注意:这使用CDO作为后端,而space_mean将计算每个网格单元的面积加权的平均值。

答案 1 :(得分:1)

过了一会儿,我设法再次看到这个问题,显然上面的方法几乎是正确的。经过一些调整,在单个数据文件上测试,并与GrADS解决方案交叉检查后,我得到了这样的结果:

    f = nc.Dataset('~/data/TRMM3H/3B42.19980101.12.7A.nc')
    pcpt = f.variables['pcp'][:]
    lon = f.variables['longitude'][:]
    lat = f.variables['latitude'][:]

    #select two regions
    latidx1 = (lat >=4. ) & (lat <=6.5 ) 
    lonidx1 = (lon >=100.5 ) & (lon <=101.5 ) 
    latidx2 = (lat >=2.5 ) & (lat <=5.0 ) 
    lonidx2 = (lon >=101. ) & (lon <=102. ) 

    rainf = pcpt[:]
    #these basically listing the values in an array (2 in this case)
    rainf1 = rainf[:, latidx1][..., lonidx1]
    rainf2 = rainf[:, latidx2][..., lonidx2]
    rainf_1 = rainf1
    rainf_2 = rainf2

    #time to get the mean values
    print np.mean(rainf_1)
    print "............."
    print np.mean(rainf_2)
    print "............."

这给了我这些结果:

    >>> execfile('find_percentile.py')
    0.7830327034
    .............
    1.56235361099
    .............

使用GrADS计算结果相同。

建议后编辑:

    f = nc.Dataset('~/data/TRMM3H/3B42.19980101.12.7A.nc')
    pcpt = f.variables['pcp'][:]
    lon = f.variables['longitude'][:]
    lat = f.variables['latitude'][:]

    #select two regions
    latidx1 = (lat >=4. ) & (lat <=6.5 ) 
    lonidx1 = (lon >=100.5 ) & (lon <=101.5 ) 
    latidx2 = (lat >=2.5 ) & (lat <=5.0 ) 
    lonidx2 = (lon >=101. ) & (lon <=102. ) 

    #these basically listing the values in an array (2 in this case)
    rainf1 = pcpt[:, latidx1][..., lonidx1]
    rainf2 = pcpt[:, latidx2][..., lonidx2]
    rainf_1 = rainf1
    rainf_2 = rainf2

    #time to get the mean values
    print np.mean(rainf_1)
    print "............."
    print np.mean(rainf_2)
    print "............."

回到原来的问题,在多个文件中执行此操作并在txt / csv文件中打印它仍在构建中(并测试)。

答案 2 :(得分:0)

我只是想指出Fir Nor的解决方案是不正确的,因为在处理常规lat / lon网格上的空间数据时,你不能简单地使用算术平均值(np.mean)。因为当你向极点移动时网格单元的大小会发生变化,所以这里就是一个例子!

最好不要担心这个并使用CDO进行操作:

cdo fldmean -sellonlatbox,98.5,100,4.5,6 3B42.1998.05.01.7A.nc boxav.nc