GRIB笔记:使用 xarray 插值

目录

上一篇文章《xarray指南:插值》中介绍使用 xarray 实现插值,本文介绍如何将该插值应用到 GRIB 2 文件中的要素场。

本文使用 nwpc-oper/nwpc-data 库从本地 GRIB 2 文件中加载要素场。 nwpc-data 库介绍请浏览《nwpc-data 库简介

准备

加载需要的库

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import xarray as xr

from nwpc_data.data_finder import find_local_file
from nwpc_data.grib.eccodes import load_field_from_file

站点插值

获取 850hPa 温度场

data_file = find_local_file(
    "grapes_gfs_gmf/grib2/orig",
    start_time=pd.to_datetime("2020-04-26"),
    forecast_time="24h",
)
data_file
PosixPath('/g1/COMMONDATA/OPER/NWPC/GRAPES_GFS_GMF/Prod-grib/2020042521/ORIG/gmf.gra.2020042600024.grb2')
t850 = load_field_from_file(
    data_file,
    parameter="t",
    level_type="pl",
    level=500,
)
t850
<xarray.DataArray 't' (latitude: 720, longitude: 1440)>
array([[262.26335937, 262.28335938, 262.29335938, ..., 262.26335937,
        262.27335937, 262.30335938],
       ...,
       [243.63335937, 243.48335937, 243.64335938, ..., 243.56335938,
        243.53335938, 243.73335937]])
Coordinates:
    time        datetime64[ns] 2020-04-26
    step        timedelta64[ns] 1 days
    valid_time  datetime64[ns] 2020-04-27
    pl          float64 850.0
  * latitude    (latitude) float64 89.88 89.62 89.38 ... -89.38 -89.62 -89.88
  * longitude   (longitude) float64 0.0 0.25 0.5 0.75 ... 359.2 359.5 359.8
Attributes:
    GRIB_edition:                    2
    ...skip...
    long_name:                       Temperature
    units:                           K

获取北京站温度,[39.8, 116.4667]

索引,最近邻查找,返回距离该点最新的点。 注意观察返回结果的坐标值。

t850.sel(
    latitude=39.8, 
    longitude=116.4667, 
    method="nearest"
)
array(279.25335938)
Coordinates:
    time        datetime64[ns] 2020-04-26
    step        timedelta64[ns] 1 days
    valid_time  datetime64[ns] 2020-04-27
    pl          float64 850.0
    latitude    float64 39.88
    longitude   float64 116.5
Attributes:
    GRIB_edition:                    2
    ...skip...
    long_name:                       Temperature
    units:                           K

插值

t850.interp(
    latitude=39.8, 
    longitude=116.4667,
)
<xarray.DataArray 't' ()>
array(279.34686817)
Coordinates:
    time        datetime64[ns] 2020-04-26
    step        timedelta64[ns] 1 days
    valid_time  datetime64[ns] 2020-04-27
    pl          float64 850.0
    latitude    float64 39.8
    longitude   float64 116.5
Attributes:
    GRIB_edition:                    2
    ...skip
    long_name:                       Temperature
    units:                           K

实际上,两种方法返回的数据不一样。

(t850.sel(
    latitude=39.8, 
    longitude=116.4667, 
    method="nearest"
) - t850.interp(
    latitude=39.8, 
    longitude=116.4667,
)).item()
-0.09350879999999506

同时插值多个站点

获取多个站点的温度:

  • 北京:[39.8, 116.4667]
  • 上海:[31.3908, 121.4447]
  • 广州:[23.21, 113.4822]

构建站点坐标对象,并创建新的维度 location

lat = xr.DataArray(
    [39.8, 31.3908, 23.21],
    dims="location",
    coords={
        "location": ["bj", "sh", "gz"],
    }
)
lon = xr.DataArray(
    [116.4667, 121.4447, 113.4822],
    dims="location",
    coords={
        "location": ["bj", "sh", "gz"],
    }
)

使用新维度插值

t850.interp(
    latitude=lat, 
    longitude=lon
)
<xarray.DataArray 't' (location: 3)>
array([279.34686817, 282.03347057, 285.58804322])
Coordinates:
    time        datetime64[ns] 2020-04-26
    step        timedelta64[ns] 1 days
    valid_time  datetime64[ns] 2020-04-27
    pl          float64 850.0
    latitude    (location) float64 39.8 31.39 23.21
    longitude   (location) float64 116.5 121.4 113.5
  * location    (location) <U2 'bj' 'sh' 'gz'
Attributes:
    GRIB_edition:                    2
    ...skip...
    long_name:                       Temperature
    units:                           K

降尺度

比较使用 xarray 降尺度和目前业务系统中使用 gribpost.exe 生成的降尺度产品的差异。

获取降尺度产品中 850hPa 的温度场

down_data_file = (
    "/g2/nwp_pd/NWP_PST_DATA/GMF_GRAPES_GFS_POST"
    "/togrib2/output_togrib2_downscaling/2020042600/"
    "grapes_downscaling.2020042600024.grb2"
)
down_t850 = load_field_from_file(
    down_data_file,
    parameter="t",
    level_type="pl",
    level=850,
)
down_t850
<xarray.DataArray 't' (latitude: 851, longitude: 1001)>
array([[263.58795313, 263.59595312, 263.60395313, ..., 268.64095313,
        268.70695312, 268.77295313],
       ...,
       [291.28795313, 291.38595313, 291.48395313, ..., 290.36095312,
        290.11695313, 289.87295312]])
Coordinates:
    time        datetime64[ns] 2020-04-26
    step        timedelta64[ns] 1 days
    valid_time  datetime64[ns] 2020-04-27
    pl          float64 850.0
  * latitude    (latitude) float64 70.0 69.9 69.8 69.7 ... -14.8 -14.9 -15.0
  * longitude   (longitude) float64 45.0 45.1 45.2 45.3 ... 144.8 144.9 145.0
Attributes:
    GRIB_edition:                    2
    ...skip...
    long_name:                       Temperature
    units:                           K

使用 interp_likedown_t850 的网格对 t850 进行插值

interpolated = t850.interp_like(down_t850)
interpolated
<xarray.DataArray 't' (latitude: 851, longitude: 1001)>
array([[263.58835937, 263.59635937, 263.60435938, ..., 268.64135938,
        268.70735938, 268.77335938],
       ...,
       [291.28835938, 291.38635938, 291.48435938, ..., 290.36135937,
        290.11735937, 289.87335938]])
Coordinates:
    time        datetime64[ns] 2020-04-26
    step        timedelta64[ns] 1 days
    valid_time  datetime64[ns] 2020-04-27
    pl          float64 850.0
  * latitude    (latitude) float64 70.0 69.9 69.8 69.7 ... -14.8 -14.9 -15.0
  * longitude   (longitude) float64 45.0 45.1 45.2 45.3 ... 144.8 144.9 145.0
Attributes:
    GRIB_edition:                    2
    ...skip...
    long_name:                       Temperature
    units:                           K

计算两者的差值

d = interpolated - down_t850
d
<xarray.DataArray 't' (latitude: 851, longitude: 1001)>
array([[ 4.06250000e-04,  4.06250000e-04,  4.06250000e-04, ...,
         4.06250000e-04,  4.06250000e-04,  4.06250000e-04],
       [ 4.06250000e-04, -1.93750000e-04,  2.06250000e-04, ...,
         6.25000001e-06,  2.06250000e-04,  4.06250000e-04],
       [ 4.06250000e-04, -1.93750000e-04,  2.06250000e-04, ...,
        -1.93750000e-04, -3.93750000e-04,  4.06250000e-04],
       ...,
       [ 4.06250000e-04,  4.06250000e-04,  4.06250000e-04, ...,
         6.24999996e-06,  2.06250000e-04,  4.06250000e-04],
       [ 4.06250000e-04,  2.06250000e-04,  6.25000001e-06, ...,
        -3.93750000e-04,  6.25000001e-06,  4.06250000e-04],
       [ 4.06250000e-04,  4.06250000e-04,  4.06250000e-04, ...,
         4.06250000e-04,  4.06250000e-04,  4.06250000e-04]])
Coordinates:
    time        datetime64[ns] 2020-04-26
    step        timedelta64[ns] 1 days
    valid_time  datetime64[ns] 2020-04-27
    pl          float64 850.0
  * latitude    (latitude) float64 70.0 69.9 69.8 69.7 ... -14.8 -14.9 -15.0
  * longitude   (longitude) float64 45.0 45.1 45.2 45.3 ... 144.8 144.9 145.0

计算所有差值绝对值之和

np.abs(d).sum()
<xarray.DataArray 't' ()>
array(256.68321875)
Coordinates:
    time        datetime64[ns] 2020-04-26
    step        timedelta64[ns] 1 days
    valid_time  datetime64[ns] 2020-04-27
    pl          float64 850.0

查看差值的最大值和最小值

d.min().item()
-0.0003937500001711669
d.max().item()
0.00040625000019645086

可以看到,两者的差值在 0.001 级别,考虑到 JPEG 2000 压缩的精度,误差在可接受范围。

参考

https://github.com/nwpc-oper/nwpc-data