参考致谢:
ERA5基本态驱动LBM-专业气象研究-气象家园_气象人自己的家园
0.安装nc库
cd ~/lbm
# 新建存放库的总文件夹
mkdir -p libs/src libs/netcdf_install
sudo apt update
sudo apt install -y build-essential gfortran libz-dev libhdf5-dev wget make
# 验证gfortran版本,确认是9.4.0
gfortran --version
# 复制主模型目录下的intp.f到util
cp /home/accept7/lbm/ln_solver/solver/custom/intp.f ~/lbm/ln_solver/solver/util/
1.准备ERA5资料
下载ERA5月尺度的资料,主要资料为23层的u,v,t,z,q,和单层的slp

2.原始的ERA5数据从0.25°插值到2.5度,每个变量对应输出一个nc
import xarray as xr
import numpy as np
from pathlib import Path
# ======================
# 配置(和你原来完全一样)
# ======================
data_dir = Path("I:/LBM/Data2")
out_dir = Path("I:/LBM/Data2")
lon_target = np.arange(0, 360, 2.5)
lat_target = np.arange(-90, 90.1, 2.5)
var_config = [
# ("t", "t"),
# ("z", "z"),
("q", "q"),
# ("u", "u"),
# ("v", "v"),
# ("slp", "slp")
]
# ======================
# 逐变量处理
# ======================
for var_orig, out_suffix in var_config:
in_file = data_dir / f"ERA5_{var_orig}.nc"
out_file = out_dir / f"ERA5_{out_suffix}_res2.5.nc"
print(f"\n处理变量: {var_orig}")
print(f"输入: {in_file.name}")
ds = xr.open_dataset(in_file)
ds = ds.rename({"valid_time": "time"})
nt = len(ds.time)
result = []
# ======================
# 逐时间步插值(绝不爆内存)
# ======================
for tidx in range(nt):
print(f" 时间步 {tidx + 1}/{nt}")
# 只取当前时间片
ds_t = ds.isel(time=tidx)
# 插值到 2.5°
if var_orig == "slp":
di = ds_t.interp(
longitude=lon_target,
latitude=lat_target,
method="linear"
)
else:
di = ds_t.interp(
longitude=lon_target,
latitude=lat_target,
pressure_level=ds.pressure_level,
method="linear"
)
# ======================
# 填补 NaN:0°经线 + 两极
# ======================
di = di.fillna(0.0)
result.append(di)
# 合并时间
ds_out = xr.concat(result, dim="time")
# 位势高度单位转换
if var_orig == "z":
ds_out["z"] = ds_out["z"] / 9.80665
ds_out["z"].attrs["units"] = "m"
ds_out["z"].attrs["long_name"] = "Geopotential Height"
# 保存(经典格式,不压缩、不报错)
ds_out.to_netcdf(out_file, format="NETCDF4_CLASSIC")
print(f"✅ 已保存: {out_file.name}")
3.因为层数不同,所以将平均态时段的所有数据转换为slp_for_fortran.nc的和upper_for_fortran.nc两个文件
import xarray as xr
import numpy as np
import xarray as xr
data_dir = "I:/LBM/Data2/"
# 读取 2.5° 数据
ds_air = xr.open_dataset(data_dir + "ERA5_t_res2.5.nc")
ds_hgt = xr.open_dataset(data_dir + "ERA5_z_res2.5.nc")
ds_shum = xr.open_dataset(data_dir + "ERA5_q_res2.5.nc")
ds_uwnd = xr.open_dataset(data_dir + "ERA5_u_res2.5.nc")
ds_vwnd = xr.open_dataset(data_dir + "ERA5_v_res2.5.nc")
ds_slp = xr.open_dataset(data_dir + "ERA5_slp_res2.5.nc")
def select_period(ds,start_time,end_time):
return ds.sel(time=slice(start_time, end_time))
# start_time='2000-01-01'
# end_time='2025-12-31'
# nc_name="era520002025.nc"
start_time='1970-01-01'
end_time='2000-12-31'
nc_name="era519702000.nc"
ds_air = select_period(ds_air,start_time, end_time)
ds_hgt = select_period(ds_hgt,start_time, end_time)
ds_shum = select_period(ds_shum,start_time, end_time)
ds_uwnd = select_period(ds_uwnd,start_time, end_time)
ds_vwnd = select_period(ds_vwnd,start_time, end_time)
ds_slp = select_period(ds_slp,start_time, end_time)
# 变量名严格匹配 Fortran
air = ds_air['t'].rename('air')
hgt = ds_hgt['z'].rename('hgt')
shum = ds_shum['q'].rename('shum')
uwnd = ds_uwnd['u'].rename('uwnd')
vwnd = ds_vwnd['v'].rename('vwnd')
slp = ds_slp['msl'].rename('slp')
# 月平均
air_clim = air.groupby('time.month').mean(dim='time')
hgt_clim = hgt.groupby('time.month').mean(dim='time')
shum_clim = shum.groupby('time.month').mean(dim='time')
uwnd_clim = uwnd.groupby('time.month').mean(dim='time')
vwnd_clim = vwnd.groupby('time.month').mean(dim='time')
slp_clim = slp.groupby('time.month').mean(dim='time')
# 高层场:4维 (lon, lat, pressure_level(23), month)
air_out = air_clim.transpose("longitude", "latitude", "pressure_level", "month")
hgt_out = hgt_clim.transpose("longitude", "latitude", "pressure_level", "month")
shum_out = shum_clim.transpose("longitude", "latitude", "pressure_level", "month")
uwnd_out = uwnd_clim.transpose("longitude", "latitude", "pressure_level", "month")
vwnd_out = vwnd_clim.transpose("longitude", "latitude", "pressure_level", "month")
# ===================== SLP 关键正确写法 =====================
# 变成 4 维,第三维长度=1,名字随便叫一个,不和 pressure_level 冲突
slp_out = slp_clim.expand_dims(dim='lev', axis=2)
slp_out = slp_out.transpose("longitude", "latitude", "lev", "month")
slp_out = slp_out / 100.0
slp_out.attrs['units'] = 'hPa'
# ==============================================================
# 合成输出
ds_out = xr.Dataset({
'air' : air_out,
'hgt' : hgt_out,
'shum' : shum_out,
'uwnd' : uwnd_out,
'vwnd' : vwnd_out,
'slp' : slp_out, # 4 维:(144,73,1,12)
})
# 保存
ds_out.to_netcdf(data_dir + nc_name, format="NETCDF4_CLASSIC")
print("✅ 生成完成!")
print("✅ pressure_level 保持 23 层不变")
print("✅ slp 是 4 维,第三维长度=1,完全匹配 PRES(nx,ny,1,nt)")
#=================================分成两个文件
ds = xr.open_dataset(data_dir + 'era520002025.nc')
# 👇 核心:把 (month, pressure_level, latitude, longitude) 转成 (longitude, latitude, pressure_level, month)
ds['hgt'] = ds['hgt'].transpose("longitude", "latitude", "pressure_level", "month")
ds['air'] = ds['air'].transpose("longitude", "latitude", "pressure_level", "month")
ds['uwnd'] = ds['uwnd'].transpose("longitude", "latitude", "pressure_level", "month")
ds['vwnd'] = ds['vwnd'].transpose("longitude", "latitude", "pressure_level", "month")
ds['shum'] = ds['shum'].transpose("longitude", "latitude", "pressure_level", "month")
# 清空 coordinates 属性(保险)
for var in ds.data_vars:
if "coordinates" in ds[var].attrs:
del ds[var].attrs["coordinates"]
# 保存
ds[["hgt","air","uwnd","vwnd","shum"]].to_netcdf(
"I:\\LBM\\Data2\\upper_for_fortran_0025.nc",
format="NETCDF3_CLASSIC"
)
# ======================
# 3. 拆分并清理 SLP(关键!这里要删 number)
# ======================
ds_slp = ds[["slp"]].squeeze(drop=True) # 去掉 lev=1 维
if "number" in ds_slp:
ds_slp = ds_slp.drop_vars("number")
# 再确认清理 coordinates
if "coordinates" in ds_slp["slp"].attrs:
del ds_slp["slp"].attrs["coordinates"]
ds_slp.to_netcdf(
"I:\\LBM\\Data2\\slp_for_fortran_0025.nc",
format="NETCDF3_CLASSIC"
)
4.用create_lbm_era5_bs_T42.f90将nc文件转为模型需要的grd格式
cp /mnt/hgfs/Data/upper_for_fortran_0025.nc ~/lbm/ln_solver/solver/util/
cp /mnt/hgfs/Data/slp_for_fortran_0025.nc ~/lbm/ln_solver/solver/util/
cp /mnt/hgfs/Data/upper_for_fortran_7000.nc ~/lbm/ln_solver/solver/util/
cp /mnt/hgfs/Data/slp_for_fortran_7000.nc ~/lbm/ln_solver/solver/util/
58行 filepath = "/home/accept7/lbm/ln_solver/solver/util/upper_for_fortran_final.nc"
90行 filepath = "/home/accept7/lbm/ln_solver/solver/util/slp_for_fortran.nc"
104行 filepath = "/home/accept7/lbm/ln_solver/solver/util/upper_for_fortran_final.nc"
147行 为输出的grd的名称
OPEN(UNIT=1,FILE='era5.clim.y70-00.t42.grd',FORM='unformatted',CONVERT='big_endian')
编译运行create_lbm_era5_bs_T42.f90
gfortran \
-I/usr/include \
-L/usr/lib/x86_64-linux-gnu \
create_lbm_era5_bs_T42.f90 \
-o create_lbm_era5_bs_T42 \
-lnetcdff -lnetcdf
./create_lbm_era5_bs_T42
检查输出的grd数据是否合理
DSET ^era5.clim.y70-00.t42.grd
OPTIONS SEQUENTIAL YREV BIG_ENDIAN
undef -9.9e8
title ERA5 T42 L23 Climatology for LBM ecmsbs
XDEF 128 LINEAR 0.0 2.8125
YDEF 64 levels
-87.8638 -85.0965 -82.3129 -79.5256 -76.7369 -73.9475 -71.1577
-68.3678 -65.5776 -62.7873 -59.9970 -57.2066 -54.4162 -51.6257 -48.8352 -46.0447 -43.2542 -40.4636 -37.6731 -34.8825 -32.0919 -29.3014 -26.5108 -23.7202 -20.9296 -18.1390 -15.3484 -12.5578 -9.76715 -6.97653 -4.18592 -1.39531 1.39531 4.18592 6.97653 9.76715 12.5578 15.3484 18.1390 20.9296 23.7202 26.5108 29.3014 32.0919 34.8825 37.6731 40.4636 43.2542 46.0447 48.8352 51.6257 54.4162 57.2066 59.9970 62.7873 65.5776 68.3678 71.1577 73.9475 76.7369 79.5256 82.3129 85.0965 87.8638
ZDEF 23 levels
1000 925 850 775 700 600 500 400 300 250 200 150 100 70 50
30 20 10 7 5 3 2 1
TDEF 12 LINEAR 00Z01jan1970 1mon
VARS 6
u 23 99 Zonal Wind (m/s)
v 23 99 Meridional Wind (m/s)
t 23 99 Temperature (K)
z 23 99 Geopotential Height (gpm)
q 23 99 Specific Humidity (kg/kg)
slp 0 99 Sea Level Pressure (hPa)
ENDVARS
grads -l
open era5.clim.y00-25.t42.ctl
set t 1 last
set z 1 last
d u
d v
d t
d z
d q
d slp
检查数值范围是否合适