CDO tips cdo (climate data operator)のtipsです。
マニュアルはhttps://code.mpimet.mpg.de/projects/cdo/embedded/cdo.pdfにあります。
Clicのregridding with CDOも参考になります。https://www.climate-cryosphere.org/wiki/index.php?title=Regridding_with_CDO

cdo tutorial -> https://code.mpimet.mpg.de/projects/cdo/wiki/Tutorial

以降の説明はcdo-1.9.8程度のバージョンでの動作を基にしていて、古いバージョンではoperatorがなかったりします. また、座標系変換などいくつかのものはcdo構築時にライブラリがコンパイルされている必要があります. 以下はnetcdf4とproj7.2.1ライブラリを導入するconfigure例.
./configure --prefix=$HOME/cdo-1.9.8 --with-hdf5=/usr/include/ --with-netcdf=/usr/include/ --with-proj=/opt/share/proj/7.2.1 --with-netcdf=/opt/share/NetCDF4/netcdf-c/4.7.2

基本的な考え方

cdo [operator] [infile.nc] [outfile.nc]

netcdfファイルからのある変数データの切り出し

cdo select,name=HDC,timestep=51 TOPicemsk.nc out.nc
51番目の時刻のHDCという変数をout.ncファイルに出力します。ある期間をすべてぬきだすにはtimestep=start/end
cdoの場合は, 最初の時刻番号は1になります. (GMTだと0...)

netcdfファイルの演算(定数)

cdo subc,273.15 T2_kelvin.nc T2_celcius.nc
cdo expr,'evap=evap*31.556926/2.454*0.01' rain_wm2.nc rain_mma.nc
subcの代わりにaddc, mulc, divcで四則演算ができます。

netcdfファイルの演算(複数ファイル)

cdo sub HDC_21ka.nc HDC_0ka.nc HDC_21ka-0ka.nc
HDC_21ka.nc HDC_0ka.ncはそれぞれ(x,y)で定義されており、高さ方向と時間方向にデータは1つしかないとします。HDC_21ka.nc HDC_0ka.ncの差がHDC_21ka-0ka.ncに出力されます。同じようにadd, mul, divができます。

Netcdfファイルの演算(気候値の作成)

cdo select,timestep=1/360 data_1979-2018_monthly.nc data_1981-2010.nc 1番目から360番まで抜き出し
cdo timmean data_1981-2010.nc data_1981-2010_ave.nc 全時刻の平均
cdo zonmean data_1981-2010.nc data_1981-2010_zonmean.nc 東西平均
cdo fldmean T2.nc T2_globalmean.nc 全領域平均
cdo fldmax out.nc out2.nc 領域内最大値
cdo fldmin out.nc out2.nc 領域内最小値
cdo vertavg vo2.nc vo3.nc 鉛直平均
cdo timselmean,10 1yrclimatology.nc 10yrclimatology.nc 10時刻ごとの時間平均(ビン平均。移動平均running meanはまた別のやり方がある)

実はこのような演算は1行でもできる

cdo select,name=T2 -timmean all.nc T2_timmean.nc

netcdfファイルの演算

cdo gtc,1 h.nc mask.nc 1以上=1

ある一部データだけ取り出す

cdo yearmean -selmon,1 data_1981-2010.nc data_1981-2010_jan.nc 1月のみ取り出す
cdo yearmean -selmon,1,2,12 data_1981-2010.nc data_1981-2010_djf.nc DJFのみ取り出す
cdo yearmean -selmon,6,7,8 data_1981-2010.nc data_1981-2010_jja.nc JJAのみ取り出す
cdo select,name=temperature,level=-450 oceantemp.nc out.nc ある鉛直軸のみ切り出す
cdo sellonlatbox,0,360,-90,-60 1.nc 2.nc ある緯度経度領域内のみ切り出す
cdo -remapbil,lon=248_lat=-79.5 T2.nc 1.nc ある緯度経度地点における値をbilinear interpolationを用いて抽出する
cdo selindexbox,96,120,11,17 meridional_overturning_circulation.nc out.nc ある軸の値の範囲のみぬきだす
(AMOCの計算するときに深度方向の幅を決めるのだが、たいていの場合深度方向のgridsizeが違うのでこうやって数値で指定したほうが速い)

アンサンブル平均と分散

cdo ensmean 11.nc 21.nc 31.nc 41.nc 51.nc 101.nc
cdo ensstd 11.nc 21.nc 31.nc 41.nc 51.nc 102.nc

マスクファイルを読んで欠損領域を指定

cdo ifthen ../miroc_util/geo2d_lgm_T.nc to.nc to_masked.nc
ここでgeo2d_lgm_T.ncは海に1, 陸に0が入った2次元配列のファイルです。

欠損値の設定および変更

cdo setmissval,nan 1.nc 2.nc 欠損値の値(たとえば-999の値=欠損と定義されているなど)をnanに変更する
cdo setmisstoc,0 2.nc 3.nc 欠損値に0を代入する
cdo setrtomiss,-2e+32,-1e+31 2.nc 3.nc ある範囲の値を欠損値とする(この場合--2.0e-32〜-1.0e+31の範囲をもつ値領域が欠損値となる)
cdo setvrange,0.5,1.5 gridx01.nc gridx1.nc ある範囲の値以外を欠損値とする

時刻情報の変更

cdo settaxis,-20750,00:00:00,500year 1.nc 21-13ka_every500a.nc  20.75kaから500年ごと
cdo settaxis,2100-01-15,00:00:00,1month 1.nc 2.nc 2100年1月から1月ごと

Netcdf handling

変数名を変更する(netcdf fortranのnf_get_var_だと、次元名と変数名が完全に同一だった場合正常に読めないため)
cdo -chname,to,mask out.nc out1.nc
ncrename -v LATITUDE,lat Radar_SMB_DomeFuji_2018-19.nc

不要な変数の削除

cdo delete,name=age_c,age_t,enh_c,enh_t,enth_c,enth_t,omega_c,omega_t,temp_c,temp_mm,temp_r,vx_c,vx_t,vy_c,vy_t,vz_c,vz_t v5_ant32_b2_future09_ctrl0005.nc 2dvariables.nc

水平方向の内層

cdo remapbil,r360x181 sst_original.nc sst_1x1.nc
cdo remapbil,t42grid sat_original.nc sst_t42.nc
r360x181は1x1 gridになります。r1x145等。t42はgaussian T42になります(128x64)。

鉛直方向の内層

cdo intlevel,1000,925,850,800,750,700,600,500,400,300,250,200,150,100,70,50,30,20,10 1.nc 2.nc
これは気圧面への内層。同様に海洋の水深も内層できます

ascii fileの書き出し

cdo output out.nc 
で、out.ncが配列(1,1)などであれば、単に値だけ出てくるし、(nx, ny)等の配列であればX,Y情報を抜いた値がnx*nyだけ並んで出てくる
cdo outputtab,lat,lev,value 7.nc
はout.ncが配列(lon,lat,lev)の形をしている場合、lat, lev, valueの3次元テキストのテーブルが出力されます.

作図のためのascii fileの書き出し

cdo gmtxyz out.nc | psxy -J -R ...
cdo gmtcells out.nc | psxy -J -R -M ...
GMT ascii table用。古いバージョンだとこのoperatorがない場合があります。gmtのgrd2xyzで対応していない緯度方向可変gridも反映されます!

Grads -> Netcdf

grads binary -> netcdf(.ctlファイルの中に dset ^tmp.grdがある状態で)
cdo -f nc import_binary tmp.ctl out.nc

ascii -> netcdf

ascii -> netcdfを変換
awk -F, '{if(NR>4.5) print $3}' B_TMP2m_ANN.csv > tmp.txt
cat tmp.txt cdo -f nc input,jra55grid.txt B_TMP2m_ANN.nc
cat tmp.txt | cdo -f nc input,grid128x65.txt 1.nc
ここで, jra55grid.txtは
gridtype = lonlat
xsize    = 288
ysize    = 145
xfirst   = 0.0
xinc     = 1.25
yfirst   = 90.0
yinc     = -1.25
のようなファイルです.

ファイルの連結(たとえば1年1ファイルだったり、1変数1ファイルだったものをすべて1つのファイルにする)

cdo mergetime T2_2000.nc T2_2001.nc T2_2002.nc T2_2000-2002.nc
cdo merge out1.nc out2.nc out3.nc out4.nc out5.nc out6.nc out7.nc out8.nc
cdo cat T2_*.nc T2_all.nc
cdo merge s.nc H.nc Ac.nc Acp.nc Tsa.nc b.nc ms.nc 2dvariables.nc

実践編[1]:海氷域(海氷密接度>0.15)の面積を計算するため、(1)軸情報をcdoが認識できるように変更する, (2)各グリッドの面積を計算する, (3)海氷密接度0.15未満の領域をマスクアウトする, (4)海氷密接度×グリッドの面積を計算した途中ファイルを作る, (5)全グリッドの積算を計算し、海氷域面積をice_extent.ncに出力する(標準:単位はm2になる)
ncatted -a units,lon,o,c,"degrees_east" -a units,lat,o,c,"degrees_north" ai.nc ai1.nc
cdo gridarea ai1.nc gridarea.nc グリッド面積の計算
cdo setrtomiss,0,0.15 ai1.nc ai_015.nc ある値以下を持つグリッドを欠損値にする
cdo mul gridarea.nc ai_015.nc ai_015_gridarea.nc 掛け算
cdo fldsum ai_015_gridarea.nc ice_extent.nc 全領域
実践編[2] 大気流線関数(東西平均, ハドレー循環, ハドレーセル)の計算
echo 'zaxistype = generic' > zaxis.txt
echo 'size = 32' >> zaxis.txt
echo 'name = layer' >> zaxis.txt
echo 'units = Pa' >> zaxis.txt
echo 'levels = 1000 2000 3000 5000 7500 10000 12500 15000 17500 20000 22500 25000 30000 35000 40000 45000 50000 55000 60000 65000 70000 75000 77500 80000 82500 85000 87500 90000 92500 95000 97500 100000' >> zaxis.txt
cdo setzaxis,zaxis.txt out.nc v.nc 鉛直軸のセット(単位を"Pa"にしたうえで外挿)
cdo zonmean v.nc v_zm.nc 東西平均
cdo setmisstoc,0 v_zm.nc v_zm2.nc 欠損領域はわるさをしないように0
cdo mastrfu v_zm2.nc streamf.nc 流線関数の計算
cdo divc,1000000000 streamf.nc streamf2.nc 10^9m3/sec
実践編[3] 気候モデル(lat-lonで定義されているclimatemodel.nc)から氷床モデル(南極極投影cartesian)への座標変換
echo gridtype=projection > mygrid.txt
echo xsize=191 >> mygrid.txt
echo ysize=191 >> mygrid.txt
echo xunits="meter" >> mygrid.txt
echo yunits="meter" >> mygrid.txt
echo xfirst=-3040000 >> mygrid.txt
echo xinc=32000 >> mygrid.txt
echo yfirst=-3040000 >> mygrid.txt
echo yinc=32000 >> mygrid.txt
echo grid_mapping=crs >> mygrid.txt
echo grid_mapping_name=polar_stereographic >> mygrid.txt
echo 'proj_params="+proj=stere +lat_0=-90 +lon_0=0 +lat_ts=-71 +ellps=WGS84 +datum=WGS84"' >> mygrid.txt
cdo remapbil,grid.txt climatemodel.nc regridded.nc
これが動作するためには、cdoのインストール時にprojライブラリが参照されている必要があります。./configure --with-hdf5=/usr/include/ --with-netcdf=/usr/include/ --with-proj=/opt/share/proj/7.2.1
実践編[4] gridinfoを作成しながら8km→32kmへの変換
cat << EOF > ingrid.txt
gridtype=projection
xsize=761
ysize=761
xunits=meter
yunits=meter
xfirst=-3040000
xinc=8000
yfirst=-3040000
yinc=8000
grid_mapping=crs
grid_mapping_name=polar_stereographic
proj_params="+proj=stere +lat_0=-90 +lon_0=0 +lat_ts=-71 +ellps=WGS84 +datum=WGS84"
EOF

cat < mygrid.txt
gridtype=projection
xsize=191
ysize=191
xunits=meter
yunits=meter
xfirst=-3040000
xinc=32000
yfirst=-3040000
yinc=32000
grid_mapping=crs
grid_mapping_name=polar_stereographic
proj_params="+proj=stere +lat_0=-90 +lon_0=0 +lat_ts=-71 +ellps=WGS84 +datum=WGS84"
EOF

cdo remapbil,mygrid.txt -setgrid,ingrid.txt 8km.nc 32km.nc
変換前ファイルのgrid情報がgenericとかかれていてcdo remapbilだけだと認識できないばあい、返還前ファイルのgrid情報をingrid.txtに記入してあげます。
実践編[5] まがった座標系(curvilienar)で定義されているnetcdfで、remapbilを使いたいが、gridinfoがgenericになっているためremapbilが効かないときに, gridinfoを作成する
cdo select,name=var infile.nc var.nc
cdo select,name=lon infile.nc lon.nc
cdo select,name=lat infile.nc lat.nc
echo gridtype=curvilinear > ingrid.txt
echo gridsize=4842961 >> ingrid.txt
echo xsize=1681 >> ingrid.txt
echo ysize=2881 >> ingrid.txt
echo "xvals=" >> ingrid.txt
cdo output lon.nc >> ingrid.txt
echo "yvals=" >> ingrid.txt
cdo output lat.nc >> ingrid.txt
として、あとは cdo remapbil,ingrid.txt -setgrid,ingrid.txt infile.nc out.nc
また、gmtxyzはgeneric gridだと対応していなくて、これも単に上の処理をしてから cdo remapbil,ingrid.txt -setgrid,ingrid.txt 1.nc 2.nc とすると同じグリッド情報でcurvilinearになるのでcdo gmtxyzが通ります。cdo gmtcellsはcorner情報をingrid.txtにかかないとエラーになります
netcdfファイルの属性の変更 はNCOのほうがやりやすかった...
ncatted -a units,lon,o,c,"degrees_east" -a units,lat,o,c,"degrees_north" ai.nc ai1.nc 
(cdoのremapbilなどは, "degrees_east""degrees_north"となっていないと正常に動作しないため)
cdo setattribute,iceconc_mm_srf@missing_value=0.0 out.nc a1.nc 欠損値
cdo setattribute,GRIDX@flag_values="0,1,...",GRIDX@flag_meanings="0:ocean, 1:icesheet, 2-10:different land vegetation types" tmp2.nc tmp3.nc

エラー
cdo subc (Warning): Some data values (min=-86630 max=-26095) are outside the
    valid range (-32768 - 32767) of the used output precision!
    Use the CDO option -b 32 or -b 64 to increase the output precision.
cdf_put_vara_double : ncid = 131072 varid = 4 val0 = -86630.000000
cdf_put_vara_double : varname = temp
だとか
cdf_put_vara_double: name=t_dd  type=NC_INT  minval=-31.000000  maxval=100000002004087734272.000000

Error (cdf_put_vara_double): NetCDF: Numeric conversion not representable
netcdfファイルの精度を超えた演算をするとエラーになる。この場合はoptionを1つ加えて
cdo -b 32 subc,273.15 1.nc 2.nc
cdo -b F64 sub ctl.nc obs.nc bias.nc
で通る。

エラー(というよりは描画ツールとの相性?)

cdoで変換したnetcdfがgradsのsdfopenで正常に読めないことがあります。見た範囲では、変数の次元定義が(time, lat, lon)になってないと正常に読めないのではないかと思います(gradsがあまりわからないので要検討。)
back