3

現在、海洋モデルの出力を処理しています。各タイム ステップには、42*1800*3600 のグリッド ポイントがあります。

私のプログラムのボトルネックはスライスであり、メソッドで xarray_built を呼び出して値を抽出することがわかりました。さらに興味深いのは、同じ構文でも場合によっては大幅に異なる時間が必要になることです。

ds = xarray.open_dataset(filename, decode_times=False)
vvel0=ds.VVEL.sel(lat=slice(-60,-20),lon=slice(0,40))/100    #in CCSM output, unit is cm/s convert to m/s
uvel0=ds.UVEL.sel(lat=slice(-60,-20),lon=slice(0,40))/100   ## why the speed is that different? now it's regional!!
temp0=ds.TEMP.sel(lat=slice(-60,-20),lon=slice(0,40)) #de

たとえば、VVEL と UVEL の読み取りには約 4 秒かかりましたが、TEMP の読み取りには約 6 ミリ秒しか必要ありませんでした。スライスなしでは、VVEL と UVEL に約 1 秒、TEMP に 120 ナノ秒かかりました。

完全な配列の一部だけを入力すると、必要なメモリが少なくなるため、時間が少なくて済むと常に思っていました。XARRAY は配列全体をロードし、余分なスライスにはさらに時間がかかることが判明しました。しかし、誰かが同じ netcdf ファイルから異なる変数を読み取るのに時間がかかる理由を説明してもらえますか?

このプログラムは、段階的なセクションを抽出し、断面の熱輸送を計算するように設計されているため、UVEL または VVEL のいずれかをセクションに沿って TEMP で掛ける必要があります。となると、TEMPの読み込みが速いのがいいと思われるかもしれませんね。

残念ながら、そうではありません。指定されたセクションに沿って約 250 のグリッド ポイントをループすると...

# Calculate VT flux orthogonal to the chosen grid cells, which is the heat transport across GOODHOPE line
vtflux=[]
utflux=[]
vap = vtflux.append
uap = utflux.append
#for i in range(idx_north,idx_south+1):
for i in range(10):
    yidx=gh_yidx[i]
    xidx=gh_xidx[i]
    lon_next=ds_lon[i+1].values
    lon_current=ds_lon[i].values
    lat_next=ds_lat[i+1].values
    lat_current=ds_lat[i].values
    tt=np.squeeze(temp[:,yidx,xidx].values)  #<< calling values is slow
    if (lon_next<lon_current) and (lat_next==lat_current):   # The condition is incorrect
        dxlon=Re*np.cos(lat_current*np.pi/180.)*0.1*np.pi/180.
        vv=np.squeeze(vvel[:,yidx,xidx].values)  
        vt=vv*tt
        vtdxdz=np.dot(vt[~np.isnan(vt)],layerdp[0:len(vt[~np.isnan(vt)])])*dxlon
        vap(vtdxdz)
        #del  vtdxdz
    elif (lon_next==lon_current) and (lat_next<lat_current):
        #ut=np.array(uvel[:,gh_yidx[i],gh_xidx[i]].squeeze().values*temp[:,gh_yidx[i],gh_xidx[i]].squeeze().values) # slow
        uu=np.squeeze(uvel[:,yidx,xidx]).values  # slow
        ut=uu*tt
        utdxdz=np.dot(ut[~np.isnan(ut)],layerdp[0:len(ut[~np.isnan(ut)])])*dxlat
        uap(utdxdz) #m/s*degC*m*m ## looks fine, something wrong with the sign
        #del utdxdz
total_trans=(np.nansum(vtflux)-np.nansum(utflux))*3996*1026/1e15

特にこの行:

tt=np.squeeze(temp[:,yidx,xidx].values)

~3.65 秒かかりますが、今では ~250 回繰り返さなければなりません。を削除する.valuesと、この時間は約 4 ミリ秒に短縮されます。しかし、 to の時間を計る必要があるttためvt、値を抽出する必要があります。奇妙なのは、同様の式がvv=np.squeeze(vvel[:,yidx,xidx].values)必要とする時間がはるかに短く、約 1.3 ミリ秒しかかからないことです。


私の質問を要約すると:

  1. 同じ netcdf ファイルから異なる変数をロードすると、異なる時間がかかるのはなぜですか?
  2. 多次元配列で単一の列を選択するより効率的な方法はありますか? (xarray 構造は必要ありません。numpy.ndarray も必要です)
  3. まったく同じ構文に対して、Xarray 構造から値を抽出するのに必要な時間が異なるのはなぜですか?

ありがとうございました!

4

1 に答える 1

5

netCDF ファイルからロードされた変数にインデックスを付ける場合、xarray は変数をすぐにメモリにロードしません。代わりに、任意の数のさらに異なるインデックス操作をサポートする遅延配列を作成します。これは、 dask.arrayを使用していない場合でも当てはまります( chunks=inopen_datasetまたは usingの設定によってトリガーされますopen_mfdataset)。

これは、観察した驚くべきパフォーマンスを説明しています。temp0ディスクからデータをロードしないため、計算は高速です。vvel0100 で除算するには、データを numpy 配列としてメモリにロードする必要があるため、低速です。

temp0後で、既にメモリ内にあるnumpy配列にインデックスを付けるのではなく、各操作がディスクからデータをロードするため、インデックスを付けるのが遅くなります。

回避策は、最初にデータセットの必要な部分をメモリに明示的にロードすることですtemp0.load()。xarray ドキュメントのnetCDF セクションにも、このヒントが記載されています。

于 2016-09-01T03:15:22.930 に答える