【问题标题】:converting an accumulated variable to timestep values in a netcdf file with CDO使用 CDO 将累积变量转换为 netcdf 文件中的时间步长值
【发布时间】:2016-12-20 13:57:51
【问题描述】:

我有一个 netcdf 文件,在一个网格上有大约 100 个时间步长,其中一个变量是在时间步长上累积的。我现在有兴趣计算每个时间步对变量值的贡献(即连续时间步的差异)。

目前我使用以下顺序:

  1. 要将每个时间步提取到一个新文件中,我使用cdo seltimestep,$i ...
  2. cdo sub $i ${i-1} ...将每个差异计算到一个新文件中
  3. 最后将这些新文件与cdo mergetime ... 合并到一个结果文件中。

在我看来,这似乎很麻烦,而且在性能方面并不理想。由于时间步长,我无法使用 cdo 管道,因此需要同时创建许多文件。

有没有更好的解决方案来使用 cdo(或其他类似 nco/ncl 的东西)将累积变量转换为时间步长值?

【问题讨论】:

  • 您只对cdo 解决方案感兴趣吗?我在 Python 中有一个 1-liner 可以为你做这件事。
  • @jhamman 我很感兴趣看到这个1-liner,我不限于cdo

标签: python netcdf nco cdo-climate


【解决方案1】:

如果你想使用cdo,不需要那些循环和写很多文件,只需使用函数deltat

cdo deltat in.nc diff.nc 

与 python 解决方案一样,这将比您使用的循环快几个数量级,并且具有命令行单行的优势。

或者,如果你知道长度,你可以区分这两个系列,而且不那么简洁(我展示了这一点,因为这种技术在其他情况下也很有用):

# calculate number of steps in the file:
nstep=$(cdo -s ntime in.nc)

# do difference between steps 2:n and steps 1:(n-1)
cdo sub -seltimestep,2/$nstep in.nc -seltimestep,1/`expr $nstep - 1` in.nc diff.nc

关于累积字段的后记! 请注意,上述解决方案和此页面上发布的两个 python 解决方案都会产生比输入少一个时间步长的输出,即他们抛弃了第一个时间步。在某些情况下,例如,如果您有一个在预测中累积的模型通量场,似乎是这种情况,您不想丢弃第一个时间步长(因为这是从预测开始时从零到第一步)。在这种情况下,您可以提取第一步并将其插入到文件的“前面”,如下所示:

cdo mergetime -seltimestep,1 in.nc diff.nc diff_with_step1.nc 

您还应该确保对 python 解决方案也这样做。

您可以将整个事情作为一个单线器进行管道传输(有时管道可能会导致总线错误或段错误,这些通常可以使用“-L”选项来解决以强制执行顺序操作)。

cdo mergetime -seltimestep,1 in.nc -deltat in.nc diff_with_step1.nc

如果遇到段错误,请尝试此操作

cdo -L mergetime -seltimestep,1 in.nc -deltat in.nc diff_with_step1.nc

如果您有打包数据(即键入 NC_SHORT),这是为了防止舍入和准确性问题:

cdo -L -b f32 mergetime -seltimestep,1 in.nc -deltat in.nc diff_with_step1.nc

【讨论】:

    【解决方案2】:

    numpy's diff 计算连续条目的差异。

    我怀疑你的文件中有一个多维变量,所以这里有一个通用的例子来说明如何做到这一点:

    import netCDF4
    import numpy as np
    
    ncfile = netCDF4.Dataset('./myfile.nc', 'r')
    var = ncfile.variables['variable'][:,:,:] # [time x lat x lon]
    
    # Differences with a step of 1 along the 'time' axis (0) 
    var_diff = np.diff(var, n=1, axis=0) 
    ncfile.close()
    
    # Write out the new variable to a new file     
    ntim, nlat, nlon = np.shape(var_diff)
    
    ncfile_out = netCDF4.Dataset('./outfile.nc', 'w')
    ncfile_out.createDimension('time', ntim)
    ncfile_out.createDimension('lat', nlat)
    ncfile_out.createDimension('lon', nlon)
    var_out = ncfile_out.createVariable('variable', 'f4', ('time', 'lat', 'lon',))
    var_out[:,:,:] = var_diff[:,:,:]
    ncfile_out.close()
    

    【讨论】:

    • 是否有一种简单的方法可以覆盖现有文件中的旧值或将新值写入文件副本?我以前从未使用过 Python NetCDF4...
    • 感谢您指出 variable 错字 - 已修复!我已经更新了我的答案,以展示如何将新变量写入新的 netcdf 文件。有关更多示例,请在此处查看文档:unidata.github.io/netcdf4-python
    • 与我的 cdo 解决方案相比,这个版本的速度之快让我印象深刻
    • 请注意,此解决方案会丢弃第一个时间步,如果您要对模型预测输出进行差分,通常您会希望在输出的开头插入该开始。
    【解决方案3】:

    xarray 是我处理这类事情的首选工具:

    import xarray as xr
    
    # Open the netCDF file
    ds = xr.open_dataset('./myfile.nc')
    
    # Take the diff along the time dimension
    ds['new_variable'] = ds['variable'].diff(dim='time')
    
    # Write a new file
    ds.to_netcdf('outfile.nc')
    

    【讨论】:

    • 我喜欢这个解决方案,但至少对于我的用例 xarray 比 numpy 慢
    • 与上述相同的注释,此解决方案还丢弃第一个时间步,如果您正在区分模型预测输出,通常您希望在输出的开头插入该开始。
    猜你喜欢
    • 2019-08-20
    • 2021-09-07
    • 2018-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-25
    • 1970-01-01
    相关资源
    最近更新 更多