grapesinput2grads.sh
#!/bin/bash
#########################################################################
# Author: 凌科
# Create Time: 2025/10/28
# Description: 从grapesinput提取变量,按照grads的要求再保存到grapesinput.dat中,并生成grapesinput.ctl文件
# Version: 1.0
#########################################################################
set -e
s_we=1
e_we=1163
s_sn=1
e_sn=543
s_vert=1
e_vert=65
num_soil_layers=5
max_i=$(( e_we - s_we + 1 ))
max_j=$(( e_sn - s_sn + 1 ))
var1_max_k=$(( (e_vert+1)-(s_vert-1)+1 ))
var2_max_k=$num_soil_layers
# 平面字节数
ixjx4=$(( max_i * max_j * 4 ))
# 一层大小,加前4字节长度和后4字节长度
layer_size=$(( ixjx4 + 8 ))
output_dir="tmp_output"
layer_seq=0
# 检查参数个数
if [ $# -lt 1 ]; then
echo "usage: $0 grapesinput"
exit 1
fi
input_file=$1
##########################################################
# 读取时间信息,年、月、日、时、分,生成grapesinput.ctl文件是会用到
read_integer() {
input_file=$1
offset=$2
# 读取4个字节的十六进制字符串
hex_string=$(xxd -s "$offset" -l 4 -p "$input_file")
integer_value=$(printf "%d" "0x$hex_string")
echo $integer_value
}
year=$(read_integer $input_file 4)
month=$(read_integer $input_file 8)
day=$(read_integer $input_file 12)
hour=$(read_integer $input_file 16)
minute=$(read_integer $input_file 20)
echo "year: $year"
echo "month: $month"
echo "day: $day"
echo "hour: $hour"
echo "minute: $minute"
##########################################################
# 创建输出目录
mkdir -p $output_dir
##########################################################
# 生成长度信息文件
len_bin_file="$output_dir/len.bin"
# 将整数格式化为 8 位十六进制字符串(4 字节)
hex_string=$(printf "%08X" "$layer_size")
# 将十六进制字符串转换为二进制数据并写入文件
echo -n "$hex_string" | xxd -r -p > $len_bin_file
###########################################################
copy_layer() {
start_pos=$1
k=$2
max_k=$3
layer_seq=$4
# 创建临时目录
tmp_dir="$output_dir/$layer_seq"
mkdir -p $tmp_dir
layer_pids=()
# 由于grapesinput文件中是i k j顺序,提取一层,即i j平面,先提取j个i,再合并
for ((j = 0; j < max_j; j++)); do
# 由于grapesinput里数据最小单元是4字节real类型,所以bs就为4
# 拷贝X轴1维数据,所以叫bar
bar_start_pos=$(( start_pos + k * max_i * 4 + j * max_k * max_i * 4 ))
skip_size=$(( bar_start_pos / 4 ))
count_size=$(( max_i * 4 /4 ))
bar_filename=$(printf "%06d" "$j")
output_file="$tmp_dir/$bar_filename"
dd if="$input_file" of="$output_file" bs=4 skip=$skip_size count=$count_size &
layer_pids+=($!)
done
# 等待执行完成
for pid in "${layer_pids[@]}"; do
wait $pid
done
# 合并
sync
cat $len_bin_file $tmp_dir/* $len_bin_file > $output_dir/LAYER_$(printf "%06d" "$layer_seq")
sync
# 删除
rm -rf $tmp_dir
}
###########################################################
# 从grapesinput文件中提取变量信息
# 19 个三维变量
var1_size=$(( var1_max_k * ixjx4 + 8 ))
for ((n = 0; n < 19; n++)); do
for ((k = 0; k < $var1_max_k; k++)); do
# 三维变量起始位置
start_pos=$(( 28 + n * var1_size + 4 ))
# 并行写入
copy_layer $start_pos $k $var1_max_k $layer_seq &
# 自增1
layer_seq=$(( layer_seq + 1 ))
done
done
###########################################################
# 2 个三维变量
var2_size=$(( var2_max_k * ixjx4 + 8 ))
for ((n = 0; n < 2; n++)); do
for ((k = 0; k < $var2_max_k; k++)); do
# 三维变量起始位置
start_pos=$(( 28 + 19 * var1_size + n * var2_size + 4 ))
# 并行写入
copy_layer $start_pos $k $var2_max_k $layer_seq &
# 自增1
layer_seq=$(( layer_seq + 1 ))
done
done
###########################################################
# 40 个二维变量
output_file=$output_dir/LAYER_$(printf "%06d" "$layer_seq")
start_pos=$(( 28 + 19 * var1_size + 2 * var2_size ))
length=$(( 40 * layer_size ))
skip_size=$(( start_pos / 4 ))
count_size=$(( length / 4 ))
dd if="$input_file" of="$output_file" bs=4 skip=$skip_size count=$count_size
###########################################################
# 等待执行完成
wait
# 合并
cat $output_dir/LAYER_* > $output_dir/grapesinput.dat
sync
# 删除
rm $output_dir/LAYER_*
rm $len_bin_file
cat > ${output_dir}/${input_file}.ctl << EOF
dset ^grapesinput.dat
options template sequential big_endian
title grapesinput
undef -9.99E+33
xdef $e_we linear 110.33 0.005
ydef $e_sn linear 21.65 0.005
zdef $var1_max_k linear 1 1
tdef 1 linear $(printf "%02d" $hour)Z${day}$(date -d "$year-$month-01" +"%b" | tr '[:upper:]' '[:lower:]')${year} 1hr
vars 61
dthdz $var1_max_k 0 dthdz
dpdz $var1_max_k 0 dpdz
dpwdz $var1_max_k 0 dpwdz
thref $var1_max_k 0 potential tempertature
piref $var1_max_k 0 piref
zsx $var1_max_k 0 zsx
zsy $var1_max_k 0 zsy
pzsx $var1_max_k 0 pzsx
pzsy $var1_max_k 0 pzsy
zz $var1_max_k 0 zz
pip $var1_max_k 0 perturbed PI
pi $var1_max_k 0 PI
u $var1_max_k 0 U wind component
v $var1_max_k 0 V wind component
wzet $var1_max_k 0 wzet
thp $var1_max_k 0 perturbed potential tempertature
th $var1_max_k 0 potential tempertature
moist_2 $var1_max_k 0 moist_2
dtdz $var1_max_k 0 dtdz
tslb 5 0 tslb
smois 5 0 smois
zs 0 0 zs
zst 0 0 zst
fisx 0 0 fisx
fisy 0 0 fisy
pfisx 0 0 pfisx
pfisy 0 0 pfisy
tsk 0 0 tsk
ps 0 0 ps
psea 0 0 psea
u10 0 0 u10
v10 0 0 v10
t2 0 0 t2
q2 0 0 q2
ht 0 0 ht
tmn 0 0 tmn
xland 0 0 xland
lu_index 0 0 lu_index
snowc 0 0 snowc
xice 0 0 xice
xlat 0 0 xlat
xlong 0 0 xlong
soil_type 0 0 soil_type
vegfra 0 0 vegfra
uslope 0 0 uslope
vslope 0 0 vslope
wslope 0 0 wslope
albedo 0 0 albedo
oc12d 0 0 oc12d
var2d 0 0 var2d
oa1 0 0 oa1
oa2 0 0 oa2
oa3 0 0 oa3
oa4 0 0 oa4
ol1 0 0 ol1
ol2 0 0 ol2
ol3 0 0 ol3
ol4 0 0 ol4
radd 0 0 radd
radl 0 0 radl
bkdd 0 0 bkdd
endvars
EOF