WRF自动运行脚本/Shell进阶:Shell脚本自动修改namelist.input日期与自动任务提交

由于WRF本身属于中尺度天气模式,其模拟时间尺度不宜过长,当我们想要准确地进行模拟时,时间不宜大于10天,当我们要进行长期模拟时,不宜直接进行长期的时间设定,最好是以一定的时间间隔重新修改namelist.input的开始于end日期。即,若想要模拟一年的数据,则应每隔以段时间(如五天)重新提交任务,即1月1日-1月6日模拟一次,随后1月6日至一月10日模拟。
如果模拟时期较长,则需要反复多次修改namelist.input中的&time_control,重新提交任务。
这种反复重复的操作我们可以使用脚本自动化解决,在linux下,我们有必要学习相关的shell脚本。

sed

在linux中,存在着编辑替换文件内容的命令sed,其命令格式与选项为:

sed的命令格式:sed [options] 'command' file(s);
 
sed的脚本格式:sed [options] -f scriptfile file(s);
 -e :直接在命令行模式上进行sed动作编辑,此为默认选项;
 
 -f :将sed的动作写在一个文件内,用–f filename 执行filename内的sed动作;
 
 -i :直接修改文件内容;
 
 -n :只打印模式匹配的行;
 
 -r :支持扩展表达式;
 
 -h或--help:显示帮助;
 
 -V或--version:显示版本信息。

其替换文件指定内容的命令可以写作:

sed -i 's/Search_String/Replacement_String/g' Input_File

通过该命令,我们可以将指定文件内的指定内容进行替换。

修改namelist.input

namelist.input中,我们需要修改的部分主要是:

start_year = 2019, 2019, 2019,
 start_month = 01, 01, 01,
 start_day = 05, 05, 01,
 start_hour = 00, 00, 00,
 end_year = 2019, 2019, 2019,
 end_month = 01, 01, 01,
 end_day = 08, 08, 04,
 end_hour = 00, 00, 00,

这几部分,通过sed命令,结合正则表达式,我们可以将上述改为我们需要的日期;

sed -i "s/start_year = \s*[0-9]\{4\}, [0-9]\{4\},/start_year = $start_year, $start_year,/" $inputfile
sed -i "s/start_month = \s*[0-9]\{2\}, [0-9]\{2\},/start_month = $start_month, $start_month,/" $inputfile
sed -i "s/start_day = \s*[0-9]\{2\}, [0-9]\{2\},/start_day = $start_day, $start_day,/" $inputfile
sed -i "s/start_hour = \s*[0-9]\{2\}, [0-9]\{2\},/start_hour = $start_hour, $start_hour,/" $inputfile
sed -i "s/end_year = \s*[0-9]\{4\}, [0-9]\{4\},/end_year = $end_year, $end_year,/" $inputfile
sed -i "s/end_month = \s*[0-9]\{2\}, [0-9]\{2\},/end_month = $end_month, $end_month,/" $inputfile
sed -i "s/end_day = \s*[0-9]\{2\}, [0-9]\{2\},/end_day = $end_day, $end_day,/" $inputfile
sed -i "s/end_hour = \s*[0-9]\{2\}, [0-9]\{2\},/end_hour = $end_hour, $end_hour,/" $inputfile

通过指定的年月日,进行替换即可。

查询WRF运行状态

wrf在运行时一般通过MPI运行,会生成对应的rsl文件,当成功时,rsl文件会出现:SUCCESSFUL 的字样。
那么通过grep命令,我们可以判断WRF是否完成运行:

#check if the job is run
   while [ `grep SUCCESS rsl.out.0000 |wc -l` -lt 1 ]; do
      countr=`qstat -r|grep $jobname| wc -l `
      countq=`qstat -i|grep $jobname| wc -l `
      count=$(($countr+$countq))
      until [ $count -ge 1 ];do
        qsub job.pbs
        countr=`qstat -r|grep $jobname| wc -l `
        countq=`qstat -i|grep $jobname| wc -l `
        count=$(($countr+$countq))
        echo $count
        sleep 20
        tail rsl.out.0000
        qstat -r
      done

      echo 'wrf.exe already submited'
      sleep 30
      tail rsl.out.0000
   done

   echo "wrf.exe ended: `date`"

日序与日期转换

将日序与日期转换后,再结合定义的模拟日,不断改变start_date:

##function date2julian, julian2date
_date2julian(){
        d2j_year=$1
        d2j_month=`expr $2 + 0`
        d2j_day=`expr $3 + 0`
        d2j_tmpmonth=$((12*$d2j_year + $d2j_month-3 ))
        d2j_tmpyear=$(( $d2j_tmpmonth/12 ))
        _date2juLIAN=$((
        ( 734*$d2j_tmpmonth + 15)/24 - 2*$d2j_tmpyear +
        $d2j_tmpyear/4 - $d2j_tmpyear/100 + $d2j_tmpyear/400
        + $d2j_day + 1721119 ))
}
date2julian()
{
#       echo 'begin d2j'
        #_date2julian "$1" "$2" "$3" && printf "%d\n" "$_date2juLIAN"
        _date2julian "$1" "$2" "$3" && printf "%s\n" "$_date2juLIAN"
}

#######################################
#ISO date from JD number
_julian2date()
{
 j2d_tmpday=$(( $1 - 1721119 ))
 j2d_centuries=$(( (4 * $j2d_tmpday - 1) / 146097 ))
 j2d_tmpday=$(( $j2d_tmpday + $j2d_centuries - $j2d_centuries / 4 ))
 j2d_year=$(( (4 * $j2d_tmpday -1) / 1461))
 j2d_tmpday=$(( $j2d_tmpday - (1461 * $j2d_year) / 4))
 j2d_month=$(( (10 * $j2d_tmpday - 5) / 306))
 j2d_day=$(( $j2d_tmpday - (306 * $j2d_month + 5) / 10))
 j2d_month=$(( $j2d_month + 2))
 j2d_year=$(( $j2d_year + $j2d_month / 12))
 j2d_month=$(( $j2d_month % 12 + 1))
## pad day and month with zeros if necessary
 case $j2d_day in ?) j2d_day=0$j2d_day;; esac
 case $j2d_month in ?) j2d_month=0$j2d_month;; esac

 _JULIAN2date=$j2d_year-$j2d_month-$j2d_day
}

julian2date()
{
 #echo 'begin j2d' $1
  _julian2date "$1" && printf "%s\n" "$_JULIAN2date"
}
#################################
 #function
 date2sec(){
 #convert date to seconds, to be used +-
 year=$1
 month=$2
 day=$3
 hour=$4
 datestring=$year-$month-$day" "$hour #¡±:00:00¡±
 time1=$(date +%s -d "$datestring UTC")
 echo $time1
 }      
        
 #function
 sec2date(){
 #convert back seconds to date
 time2=$1
 #echo ’t2˙sec2date=’, $ti
 time=$(date +"%Y-%m-%d %H:%M:%S" -u -d "1970-01-01 00:00:00 $time2 seconds")
 echo $time
 }

使用

完成了全部的准备工作后,我们需要所有的工作结合,完成整个提交的任务。
为此撰写了3个sh脚本:有日序日期转换的脚本:fuction.date.sh,自动提交WRF任务的auto_wrf.sh,以及循环提交任务,向auto_wrf,sh传递参数的主程序。
再使用时,再主程序脚本中修改对应年月日与模拟天数即可。

#!/bin/bash

#for iap server

##function date2julian, julian2date
. ./function_date.sh
#################################

#################################
## main
script_dir=`pwd`
#################################

#

##  user defined parameters:
year1=2020
month1=01
day1=25
hour1=00

year2=2020
month2=01
day2=30
hour2=00

days_of_simu=1

#conver hour to string
chour1=`printf "%02d\n" $hour1`
chour2=`printf "%02d\n" $hour2`
#change string to integer, avoid the Octal number:
month1=`expr $month1 + 0 `
day1=`expr $day1 + 0 `
month2=`expr $month2 + 0 `
day2=`expr $day2 + 0 `

echo 'simulation start: ',$year1,$month1,$day1,$hour1
echo 'simulation end  : ',$year2,$month2,$day2,$hour2

numDay_begin=`date2julian $year1 $month1 $day1`
numDay_end=`date2julian $year2 $month2 $day2`

#get the second day, can be used for output dir and decide the season
numDay_day1=($numDay_begin + $days_of_simu)
ymd1_str=`julian2date $numDay_day1`
#year_d1=`echo $ymd1_str|cut -b1-4`
month_d1=`echo $ymd1_str|cut -b6-7`
#output dir
#dir_scheme=${year_d1}${month_d1}
#echo "output dir: " $dir_scheme

jday_start=$numDay_begin
#Flg_initial=1 #use for geogrid.exe, and spinup files
while [ $jday_start -lt $numDay_end ]
do 
  ymd1_str=`julian2date $jday_start`
  start_date_str=$ymd1_str" "$hour1":00:00"
  echo 'this run start:',$start_date_str
  yearstart=`echo $start_date_str|cut -b1-4`
  monthstart=`echo $start_date_str|cut -b6-7`
  daystart=`echo $start_date_str|cut -b9-10`
  #echo $yearstart, $monthstart, $daystart


##the real start and end of this run
  jday_end=$(($jday_start + $days_of_simu))
  if [ $jday_end -gt $numDay_end  ];then
     jday_end=$numDay_end
  fi

  ymd2_str=`julian2date $jday_end`
  end_date_str=$ymd2_str" "$hour2":00:00"
  echo 'this run end:  ',$end_date_str
  yearend=`echo $end_date_str|cut -b1-4`
  monthend=`echo $end_date_str|cut -b6-7`
  dayend=`echo $end_date_str|cut -b9-10`

###calculate run_days, run_hours
  t1=`date +%s -d "${start_date_str}"`
  t2=`date +%s -d "${end_date_str}"`
  t1=$((t2-t1))
  ndays=$((t1/86400))
  t1=$((t1-ndays*86400))
  nhours=$((t1/3600))
  echo "ndays="$ndays,"nhours="$nhours
###############################

  iday_out=$(($jday_start + 1))
  dirout=`julian2date $iday_out`
  echo 'out_dir=', $dirout
  #exit

  start_year=$yearstart
  start_month=$monthstart
  start_day=$daystart
  start_hour=$chour1
  end_year=$yearend
  end_month=$monthend
  end_day=$dayend
  end_hour=$chour2
  echo $start_year,$start_month,$start_day,$start_hour

### for WPS and PWRF
  export start_year start_month start_day start_hour
  export end_year   end_month   end_day   end_hour
  export Flg_initial

  cd $script_dir
  sleep 4s
#if not change schemes accoding season:
#use ERA5+ RDEFT4
#   ./sub_pwrf_ERA5.sh
    #./sub_wps_pwrf_seaice_era5.sh
    ./auto_wrf.sh
#...............................
#use ERA5
  #./sub_wps_ERA5.sh
  #./sub_pwrf_era5.sh
#...............................
exit

  sleep 5s
  date

  echo "END wrf.exe"
  if [ $jday_end -eq $numDay_end ];then
  # has already get the last day, and no need to start another run
     echo "finished all"
     #exit, do not use "exit", because another PBLscheme will run


    #if end hour is 00z, next run starts from yesterday
    #if end hour is 18z, next run starts from today
    if [[ $hour2 -eq "00" || $hour2 -eq "0" ]];then
       jday_start=$(($jday_start + $days_of_simu))
    else
       jday_start=$(($jday_start + $days_of_simu ))
    fi

  fi


#then not the firstrun
  Flg_initial=0

done

  echo 
  echo "finished "
  echo 
  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是你需要的样例配置: namelist.wps: ``` &share wrf_core = 'ARW', max_dom = 1, start_date = '2021-11-01_00:00:00', end_date = '2021-11-02_00:00:00', interval_seconds = 21600, io_form_geogrid = 2, / &geogrid parent_id = 1, parent_grid_ratio = 1, i_parent_start = 1, j_parent_start = 1, e_we = 144, e_sn = 91, geog_data_res = '15m', dx = 0.25, dy = 0.25, map_proj = 'latlong', ref_lat = 0.0, ref_lon = 90.0, truelat1 = 33.0, truelat2 = 45.0, stand_lon = 90.0, geog_data_path = '/path/to/geog_data/', / ``` namelist.input: ``` &time_control run_days = 1, run_hours = 0, run_minutes = 0, run_seconds = 0, start_year = 2021, start_month = 11, start_day = 01, start_hour = 00, start_minute = 00, start_second = 00, end_year = 2021, end_month = 11, end_day = 02, end_hour = 00, end_minute = 00, end_second = 00, interval_seconds = 21600, input_from_file = .true., history_interval = 60, frames_per_outfile = 1, restart = .false., restart_interval = 5000, io_form_history = 2, io_form_restart = 2, io_form_input = 2, io_form_boundary = 2, debug_level = 0, / &domains time_step = 180, max_dom = 1, s_we = 1, e_we = 144, s_sn = 1, e_sn = 91, s_vert = 1, e_vert = 31, dx = 0.25, dy = 0.25, grid_id = 1, parent_id = 0, i_parent_start = 1, j_parent_start = 1, parent_grid_ratio = 1, parent_time_step_ratio = 1, feedback = 1, smooth_option = 0, / &physics mp_physics = 8, ra_lw_physics = 1, ra_sw_physics = 1, radt = 30, sf_sfclay_physics = 5, sf_surface_physics = 2, bl_pbl_physics = 1, bldt = 0, cu_physics = 1, cudt = 5, isfflx = 1, ifsnow = 1, icloud = 1, surface_input_source = 1, num_soil_layers = 4, mp_zero_out = 0, h_mom_adv_order = 5, v_mom_adv_order = 3, use_surface = 1, p_top_requested = 5000, num_metgrid_levels = 32, num_metgrid_soil_levels = 4, dx = 0.25, dy = 0.25, / &fdda / &dynamics w_damping = 0, diff_opt = 1, km_opt = 4, diff_6th_opt = 0, diff_6th_factor = 0.12, base_temp = 290. damp_opt = 0, zdamp = 5000., dampcoef = 0.2, khdif = 0, kvdif = 0, non_hydrostatic = .true., moist_adv_opt = 1, scalar_adv_opt = 1, / &bdy_control spec_bdy_width = 5, spec_zone = 1, relax_zone = 4, specified = .true., nested = .false., / &grib2 / &namelist_quilt nio_tasks_per_group = 0, nio_groups = 1, / ``` 注意:以上配置中的dx和dy都为0.25,这是因为你要使用全球等经纬度投影,分辨率为0.25度的数据。如果你使用其他数据,请根据数据分辨率修改dx和dy的值。另外,如果你没有安装过WRF所需的地理数据,你需要根据实际情况修改namelist.wps中的geog_data_path,指向你的地理数据所在的路径。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值