liblsm.sh 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  1. # liblsm.sh is a library of shell script functions required for the osm and lpjg-offline runscripts
  2. #
  3. # Usage: source ./liblsm.sh
  4. # Function to create and ICMCL* file with daily veg from an IFS experiment
  5. # Usage: osm_gen_icmcl_from_ifs
  6. function osm_gen_icmcl_from_ifs()
  7. {
  8. ## For stand-alone testing only: variables required
  9. # export GRIB_BIN_PATH=/usr/local/apps/grib_api/1.12.3/INTEL/140/bin
  10. # grib_copy=${GRIB_BIN_PATH}${GRIB_BIN_PATH:+/}grib_copy
  11. # run_start_date="1990-01-01"
  12. # osm_ifs_output_dir="${SCRATCH}/ECEARTH-RUNS/esma/output/ifs/"
  13. FYEAR=$1
  14. #grib codes 66/67/27/28/29/30
  15. snameGG="lai_lv/lai_hv/cvl/cvh/tvl/tvh"
  16. if [ $FYEAR = $(date -u -d "$run_start_date" +%Y) ]
  17. then
  18. ## first year, we need the +000000 file
  19. ff0=$(find ${osm_ifs_output_dir} | grep "ICMGG....+000000")
  20. else
  21. ## do we really need the entire previous month? the last day or timestep should be enough, can add a (-w dataDate) condition
  22. ff0=$(find ${osm_ifs_output_dir} | grep "ICMGG....+$(( $FYEAR -1 ))12")
  23. fi
  24. [[ "$ff0" == "" ]] && error "Cannot find forcing for year $FYEAR!"
  25. rm -f osm_veg.grb
  26. ${grib_copy} -w shortName=$snameGG,dataTime=0000,day=1 $ff0 osm_veg.grb
  27. ffs=$(find ${osm_ifs_output_dir} | grep "ICMGG....+${FYEAR}.." | sort)
  28. [[ "$ffs" == "" ]] && error "Cannot find forcing for year $FYEAR!"
  29. for ff in $ffs
  30. do
  31. ${grib_copy} -w shortName=$snameGG,dataTime=0000 $ff osm_tmp.grb
  32. cat osm_tmp.grb >> osm_veg.grb
  33. # break
  34. done
  35. rm -f osm_tmp.grb
  36. if [[ -r ICMCL${exp_name}INIT ]]
  37. then
  38. mv ICMCL${exp_name}INIT ICMCL${exp_name}INIT_ORI
  39. fi
  40. mv osm_veg.grb ICMCL${exp_name}INIT
  41. }
  42. # Function to create time varying vegetation for OSM run
  43. # Usage: osm_gen_veg
  44. function osm_gen_veg()
  45. {
  46. cp ${ecearth_src_dir}/ifs-${ifs_version}/src/surf/offline/scripts/init_clim.py .
  47. cp ${ecearth_src_dir}/ifs-${ifs_version}/src/surf/offline/scripts/pyfunc.py .
  48. cat > pyrun.py << EOF
  49. from init_clim import *
  50. from pyfunc import *
  51. FVEGgrb='ICMCL${exp_name}INIT'
  52. CFSURF='osm/init/surfclim'
  53. ## Generate netcdf files (empty)
  54. ginfo = get_grib_grid(FVEGgrb,retbounds=True)
  55. gen_file(FOUT='surfveg_all',FTYPE='veg',ginfo=ginfo)
  56. ## Convert grib to netcdf
  57. grib2nc(FNC='surfveg_all',FGRB=FVEGgrb,gb2NC=gb2NCveg,FTYPE='veg')
  58. ## get mask
  59. ncCLM = Dataset(CFSURF,'r')
  60. JPOINTS = ncCLM.variables['x'][:]
  61. ncCLM.close()
  62. Xmask = np.zeros((ginfo['nptot']))
  63. Xmask[JPOINTS-1]=1
  64. mask = Xmask == 1
  65. ## Create final files cutting down mask
  66. cut_mask(mask=mask,FIN='surfveg_all',FOUT='surfveg')
  67. EOF
  68. # Run python in a sub-shell to handle different environment
  69. ( configure_python ; python pyrun.py )
  70. rm -f pyfunc.p* init_clim.p* pyrun.py surfveg_all
  71. }
  72. # Function to create initial and climatological files for OSM run
  73. # Usage: osm_gen_init_clim
  74. function osm_gen_init_clim()
  75. {
  76. if ! [ -r osm/init/surfclim ]
  77. then
  78. # assumes that is it running in the running directory where previous data has been already linked
  79. # make sure we remove existing files
  80. rm -f osm_init.grb osm_clim.grb
  81. #---------------------------------------------
  82. #1. Initial conditions
  83. #--------------------------------------------
  84. ${grib_copy} -w shortName=swvl1/swvl2/swvl3/swvl4/stl1/stl2/stl3/stl4/skt/asn/rsn/sd/tsn ICMGG${exp_name}INIT osm_init.grb
  85. #--------------------------------------------
  86. # 2. Climatological conditions
  87. #--------------------------------------------
  88. ${grib_copy} -w shortName=lsm/sdor/z/slt/cvl/cvh/tvl/tvh ICMGG${exp_name}INIT osm_clim.grb
  89. ${grib_copy} -w parameter=117/118/119/120 ICMGG${exp_name}INIT osm_tmp.grb
  90. cat osm_tmp.grb >> osm_clim.grb ; rm -f osm_tmp.grb
  91. ## No need for this if we have LRDVEG=TRUE and LRDALB=FALSE
  92. # montly albedo, lai
  93. rm -f osm_mon_alb osm_mon_alnid osm_mon_aluvd osm_mon_lai_lv osm_mon_lai_hv osm_tmp.grb
  94. for im in 01 02 03 04 05 06 07 08 09 10 11 12
  95. do
  96. for sn in lai_lv lai_hv
  97. do
  98. ${grib_copy} -w shortName=$sn,month=$im,year=$leg_start_date_yyyy ICMCL${exp_name}INIT osm_tmp.grb
  99. cat osm_tmp.grb >> osm_mon_${sn}
  100. rm -f osm_tmp.grb
  101. done
  102. for sn in alnid aluvd
  103. do
  104. ${grib_copy} -w shortName=$sn ${ini_data_dir}/ifs/${ifs_grid}/climate/ICMCL-$im osm_tmp.grb
  105. cat osm_tmp.grb >> osm_mon_${sn}
  106. rm -f osm_tmp.grb
  107. done
  108. done
  109. cdo -add -mulc,0.45976 osm_mon_aluvd -mulc,0.54024 osm_mon_alnid osm_mon_alb
  110. ${grib_set} -s shortName=al osm_mon_alb osm_tmp.grb ; mv osm_tmp.grb osm_mon_alb
  111. cat osm_mon_alb >> osm_clim.grb
  112. cat osm_mon_lai_hv >> osm_clim.grb
  113. cat osm_mon_lai_lv >> osm_clim.grb
  114. case "${ifs_grid}" in
  115. T159L*) ifs_gauss_grid=80 ;;
  116. T255L*) ifs_gauss_grid=128 ;;
  117. T511L*) ifs_gauss_grid=256 ;;
  118. *) error "Can't set gauss grid for unknown horizontal grid: ${ifs_grid}" ;;
  119. esac
  120. ## For model orography we need to interpolate the spectral Z to grid-point space
  121. # if emos_tool is not available on the platform, use existing files
  122. if [ ! -z "${emos_tool-}" ]; then
  123. ${grib_copy} -w shortName=z ICMSH${exp_name}INIT z_spec.grb
  124. (configure_python ;${emos_tool} --reduced=${ifs_gauss_grid} z_spec.grb z_gp.grb)
  125. cat z_gp.grb >> osm_clim.grb
  126. rm -f z_spec.grb z_gp.grb CF_????_????
  127. else
  128. cat ${ini_data_dir}/osm/z_n${ifs_gauss_grid}.grb >> osm_clim.grb
  129. fi
  130. rm -f osm_mon_alb osm_mon_alnid osm_mon_aluvd osm_mon_lai_lv osm_mon_lai_hv osm_tmp.grb
  131. #--------------------------------------------
  132. # 3. Generate netcdf files
  133. #--------------------------------------------
  134. cp ${ecearth_src_dir}/ifs-${ifs_version}/src/surf/offline/scripts/init_clim.py .
  135. cp ${ecearth_src_dir}/ifs-${ifs_version}/src/surf/offline/scripts/pyfunc.py .
  136. cat > pyrun.py << EOF
  137. from init_clim import *
  138. from pyfunc import *
  139. FCLIMgrb='osm_clim.grb'
  140. FINITgrb='osm_init.grb'
  141. ## Generate netcdf files (empty)
  142. ginfo = get_grib_grid(FCLIMgrb,retbounds=True)
  143. gen_file(FOUT='surfclim_all',FTYPE='clm',ginfo=ginfo,nlevs=${NCSS:-4})
  144. gen_file(FOUT='soilinit_all',FTYPE='ini',ginfo=ginfo,nlevs=${NCSS:-4})
  145. ## Convert grib to netcdf
  146. grib2nc(FNC='soilinit_all',FGRB=FINITgrb)
  147. grib2nc(FNC='surfclim_all',FGRB=FCLIMgrb)
  148. ### Defaults defining points
  149. LLAND=True
  150. LLAKE=False
  151. LOCEAN=False
  152. BBOX=[-190,190,-91,91]
  153. ## find mask, i.e. point where we'll ran the model
  154. mask = get_mask('surfclim_all',LLAND,LLAKE,LOCEAN,BBOX)
  155. ## Create final files cutting down mask
  156. cut_mask(mask=mask,FIN='surfclim_all',FOUT='surfclim')
  157. cut_mask(mask=mask,FIN='soilinit_all',FOUT='soilinit')
  158. ## finally set Mask to 1
  159. nc = Dataset('surfclim','r+')
  160. nc.variables['Mask'][:] = 1
  161. nc.close()
  162. EOF
  163. # Run python in a sub-shell to handle different environment
  164. ( configure_python ; python pyrun.py )
  165. mkdir -p osm/init
  166. mv osm_init.grb osm_clim.grb surfclim_all soilinit_all osm/init
  167. cp surfclim soilinit osm/init
  168. rm -f pyfunc.p* init_clim.p* pyrun.py
  169. else # osm/init/surfclim exists
  170. cp osm/init/surfclim .
  171. cp osm/init/soilinit .
  172. fi
  173. }
  174. function osm_gen_forcing1()
  175. {
  176. # generic script to create/prepare forcing
  177. FYEAR=$1 # year to process forcing
  178. # ${osm_forcing_dir} : must be defined as where the forcing is present or created
  179. # ${osm_ifs_output_dir} : must be defined, in case of forcing from IFS, location of raw output
  180. # ${osm_forcing_type} : must be defined, only 'ifs' is supported, in the future could take other values like gswp3, etc...
  181. if ! [ -r ${osm_forcing_dir}/$FYEAR/Rainf.nc ]
  182. then
  183. # file not available, will need to be created
  184. if [ $osm_forcing_type = 'ifs' ]
  185. then
  186. # forcing from an IFS experiment
  187. osm_gen_forcing_ifs $FYEAR
  188. else
  189. error "Forcing year $FYEAR is unavailable, only osm_forcing_type=ifs is supported in osm_gen_forcing (using $osm_forcing_type)"
  190. fi
  191. fi # end of forcing processing
  192. }
  193. function osm_gen_forcing()
  194. {
  195. ## generic script to create/prepare forcing
  196. FYEAR1=$1 # first year to process forcing
  197. FYEAR2=$2 # last year to process forcing
  198. osm_forcing_dir_merged=${FYEAR1}-${FYEAR2}
  199. # if only 1 year is required, generate forcing for that year
  200. if [ $FYEAR1 == $FYEAR2 ]
  201. then
  202. osm_gen_forcing1 $FYEAR1
  203. return
  204. fi
  205. ## skip if data already there
  206. [[ -r ${osm_forcing_dir}/${osm_forcing_dir_merged}/Rainf.nc ]] && return 0
  207. ## generate forcing for each year
  208. for (( yr=FYEAR1 ; yr<=FYEAR2 ; yr+=1 ))
  209. do
  210. osm_gen_forcing1 $yr
  211. done
  212. ## merge yearly files into multi-year files
  213. for f in LWdown.nc PSurf.nc Qair.nc Rainf.nc Snowf.nc SWdown.nc Tair.nc Wind.nc
  214. do
  215. cdo_str="cdo -O -f nc4c -z zip_2 mergetime"
  216. for (( yr=FYEAR1; yr<=FYEAR2 ; yr+=1 ))
  217. do
  218. cdo_str+=" ${yr}/$f "
  219. done
  220. cdo_str+=" ${osm_forcing_dir_merged}/$f "
  221. mkdir -p ${osm_forcing_dir}/${osm_forcing_dir_merged}
  222. ( cd ${osm_forcing_dir} && export SKIP_SAME_TIME=1 && $cdo_str )
  223. done
  224. }
  225. function osm_gen_forcing_ifs()
  226. {
  227. FYEAR=$1
  228. #grib codes 134/167/168/165/166/169/175/142/143/144/228
  229. snameGG="sp/2t/2d/10u/10v/ssrd/strd/lsp/cp/sf/tp"
  230. if [ $FYEAR = $(date -u -d "$run_start_date" +%Y) ]
  231. then
  232. ## first year, we need the +000000 file
  233. ff0=$(find ${osm_ifs_output_dir} -name "ICMGG????+000000.grb")
  234. [[ "$ff0" == "" ]] && ff0=$(find ${osm_ifs_output_dir} -name "ICMGG????+000000")
  235. ## we might have output from a run which started earlier
  236. [[ "$ff0" == "" ]] && ff0=$(find ${osm_ifs_output_dir} -name "ICMGG????+$(( $FYEAR -1 ))12.grb")
  237. [[ "$ff0" == "" ]] && ff0=$(find ${osm_ifs_output_dir} -name "ICMGG????+$(( $FYEAR -1 ))12")
  238. else
  239. ## do we really need the entire previous month? the last day or timestep should be enough, can add a (-w dataDate) condition
  240. ff0=$(find ${osm_ifs_output_dir} -name "ICMGG????+$(( $FYEAR -1 ))12.grb")
  241. [[ "$ff0" == "" ]] && ff0=$(find ${osm_ifs_output_dir} -name "ICMGG????+$(( $FYEAR -1 ))12")
  242. fi
  243. [[ "$ff0" == "" ]] && error "Cannot find forcing for year $FYEAR!"
  244. rm -f osm_for.grb
  245. ${grib_copy} -w shortName=$snameGG $ff0 osm_for.grb
  246. ffs=$(find ${osm_ifs_output_dir} -name "ICMGG????+${FYEAR}??.grb" | sort)
  247. [[ "$ffs" == "" ]] && ffs=$(find ${osm_ifs_output_dir} -name "ICMGG????+${FYEAR}??" | sort)
  248. [[ "$ffs" == "" ]] && error "Cannot find forcing for year $FYEAR!"
  249. for ff in $ffs
  250. do
  251. ${grib_copy} -w shortName=$snameGG $ff osm_tmp.grb
  252. cat osm_tmp.grb >> osm_for.grb
  253. done
  254. ${grib_copy} osm_for.grb osm_for_[shortName].grb
  255. rm -f osm_for.grb
  256. cp ${ecearth_src_dir}/ifs-${ifs_version}/src/surf/offline/scripts/create_forcing.py .
  257. cat > pyrun.py << EOF
  258. from create_forcing import *
  259. SURFCLIM="surfclim"
  260. INPUTGRB="osm_for_[shortName].grb"
  261. FTYPE='SFC'
  262. tunits="seconds since $FYEAR-01-01 00:00:00"
  263. process(SURFCLIM,INPUTGRB,FTYPE,tunits)
  264. EOF
  265. ( configure_python ; python pyrun.py )
  266. # TODO check if we have to re-enable Ctpf, it was disabled some time ago
  267. #cdo -L -merge -selvar,Ctpf Ctpf.nc Rainf.nc tmp.nc; mv tmp.nc Rainf.nc
  268. #rm -f Ctpf.nc
  269. mkdir -p ${osm_forcing_dir}/$FYEAR/
  270. mv Tair.nc Qair.nc PSurf.nc Wind.nc SWdown.nc LWdown.nc Snowf.nc Rainf.nc ${osm_forcing_dir}/$FYEAR/
  271. rm -f osm_tmp.grb osm_for_*.grb create_forcing.p* pyrun.py
  272. }
  273. function osm_post_all()
  274. {
  275. # do basic OSM output post-processing
  276. osm_post_output $1
  277. # save icmcl files
  278. osm_post_icmcl $1
  279. # save era-land surface fields
  280. mkdir -p $2
  281. osm_post_land_param $1 $2
  282. # generate lpjg_forcing
  283. mkdir -p $3
  284. config=lpjg_forcing
  285. lpjg_gen_forcing $leg_start_date_yyyy $leg_end_date_yyyy_full
  286. }
  287. function osm_post_output()
  288. {
  289. DATADIR=$1 # location where the output was saved
  290. local t1=$(date +%s)
  291. ofreqh=$(( ($ifs_output_freq * $ifs_time_step_sec) / 3600 ))
  292. #cd ${run_dir}/$DATADIR
  293. mkdir -p $TMPDIR/$$/osm/post_$$
  294. cd $TMPDIR/$$/osm/post_$$
  295. # convert the netcdf files to one big grib file - or use the one generated previously if found
  296. if [ -f ${run_dir}/$DATADIR/out.grb1 ]
  297. then
  298. cp ${run_dir}/$DATADIR/out.grb1 .
  299. else
  300. cp ${ecearth_src_dir}/ifs-${ifs_version}/src/surf/offline/scripts/convNc2Grb.py .
  301. ${grib_copy} -w shortName=skt ${run_dir}/osm/init/osm_init.grb grib_template.grb
  302. cat > pyrun.py << EOFPY
  303. from convNc2Grb import *
  304. pp_gg=['39.128','40.128','41.128','42.128','139.128','170.128','183.128','236.128','235.128','238.128','141.128','33.128','32.128','198.128']
  305. pp_d2m=['167.128','168.128']
  306. pp_sus=['243.128','66.128','67.128','27.128','28.128','29.128','30.128']
  307. pp_efl=['176.128','177.128','147.128','146.128','169.128','175.128']
  308. pp_wat=['182.128','205.128','144.128','45.128','228.128','8.128','9.128']
  309. pp_cld=['260038','3066']
  310. pp_eva=['228100','228101','228102','44.128']
  311. pp=pp_gg+pp_d2m+pp_sus+pp_efl+pp_wat
  312. # TODO add a flag for this, when LPROD2=.TRUE. in osm namelist
  313. #pp=pp+pp_cld+pp_eva
  314. print(str(pp))
  315. write2grb(CFSURF="${run_dir}/osm/init/surfclim",
  316. #write2grb(CFSURF="osm/init/surfclim",
  317. CFTEMP="grib_template.grb",
  318. CFBASE="${run_dir}/${DATADIR}/",
  319. # CFBASE="./",
  320. # CFBASE="$DATADIR",
  321. ZMISS=9999,
  322. FCTYPE='AN',
  323. FGOUT='out.grb',
  324. # FGOUT='$DATADIR/out.grb',
  325. PARAMS=pp,
  326. LACUM=False,LRESET=-1,DATE0=None,TIME0=0)
  327. EOFPY
  328. ( configure_python ; python -u pyrun.py)
  329. ## split grib1 from grib2 (otherwise cdo gets a bit confused) and order by date/time
  330. ${grib_copy} -B "date:i asc, time asc, paramId:i asc" out.grb 'out.grb[editionNumber]'
  331. rm -f out.grb convNc2Grb.p* pyrun.py grib_template.grb
  332. cp out.grb? ${run_dir}/$DATADIR
  333. fi
  334. ## Now split the files per monthly chuncks as the IFS output
  335. mdate=$leg_start_date
  336. while [[ $mdate != $leg_end_date ]];
  337. do
  338. d0=$(date -u -d "$mdate + $ofreqh hours" +"%Y-%m-%dT%H:%M:%S")
  339. d1=$(date -u -d "$mdate + 1 month" +"%Y-%m-%dT%H:%M:%S")
  340. dtag=$(date -u -d "$mdate" +"%Y%m")
  341. FGOUT=ICMGG${exp_name}+$dtag
  342. # skip this file if already generated
  343. if [ ! -f ${run_dir}/$DATADIR/$FGOUT ]
  344. then
  345. # grb2 output disabled, to enable set LWRWAT=.TRUE. in osm namelist
  346. for ff in grb1 #grb2
  347. do
  348. #(
  349. [ -f out.$ff ] && cdo seldate,$d0,$d1 out.$ff ICMGG${exp_name}+$dtag.$ff || echo "file out.$ff not found!"
  350. [ -f ICMGG${exp_name}+$dtag.$ff ] && cdo timmean ICMGG${exp_name}+$dtag.$ff MEAN_ICMGG${exp_name}+$dtag.$ff
  351. #) &
  352. done
  353. #wait
  354. mv ICMGG${exp_name}+$dtag.grb1 $FGOUT
  355. ## add depthBelowLandLayer to soil moisture/temp to conform to IFS standard (needed for lpjg_forcing)
  356. ${grib_set} -w paramId=39/139 -s indicatorOfTypeOfLevel=112,topLevel=0,bottomLevel=7 $FGOUT temp ; mv temp $FGOUT
  357. ${grib_set} -w paramId=40/170 -s indicatorOfTypeOfLevel=112,topLevel=7,bottomLevel=28 $FGOUT temp ; mv temp $FGOUT
  358. ${grib_set} -w paramId=41/183 -s indicatorOfTypeOfLevel=112,topLevel=28,bottomLevel=100 $FGOUT temp ; mv temp $FGOUT
  359. ${grib_set} -w paramId=42/236 -s indicatorOfTypeOfLevel=112,topLevel=100,bottomLevel=missing $FGOUT temp ; mv temp $FGOUT
  360. #mv MEAN_ICMGG${exp_name}+$dtag.grb1 MEAN_ICMGG${exp_name}+$dtag
  361. gzip -c MEAN_ICMGG${exp_name}+$dtag.grb1 > MML_${exp_name}_3h_GG_$dtag.grb.gz
  362. rm -f MEAN_ICMGG${exp_name}+$dtag.grb1
  363. ## move files from TMPDIR to outdir - comment this if running in ${run_dir}/$DATADIR
  364. mv ${FGOUT}* MML_${exp_name}_3h_GG_$dtag.grb.gz ${run_dir}/$DATADIR
  365. fi
  366. mdate=$(date -uR -d "$mdate + 1 month")
  367. done
  368. rm -f out.grb? ${run_dir}/$DATADIR/out.grb?
  369. ## compress netcdf output to netcdf 4
  370. ## these netcdf files are not much important, could be removed at some point
  371. #for ff in $( ls *.nc )
  372. #do
  373. # (
  374. # #nccopy -4 -d 6 $ff 1_$ff
  375. # nccopy -k 4 -d 6 $ff 1_$ff
  376. # mv 1_$ff $ff
  377. # ) &
  378. #done
  379. #wait
  380. local t2=$(date +%s)
  381. local tr=$(date -d "0 -$t1 sec + $t2 sec" +%T)
  382. echo "Elapsed: $tr"
  383. cd -
  384. }
  385. # save surface fields for an era-land like reanalysis
  386. function osm_post_land_param()
  387. {
  388. DATADIR=$1 # location where the output was saved
  389. OUTDIR=$2 # location where to put era-land files
  390. land_param="39.128/40.128/41.128/42.128/139.128/170.128/183.128/236.128/235.128/238.128/141.128/33.128/32.128"
  391. run_start_date_yyyymm=$(date -u -d "${run_start_date}" +%Y%m)
  392. mkdir -p $OUTDIR
  393. #cd $OUTDIR
  394. mkdir -p $TMPDIR/$$/osm/land_param
  395. cd $TMPDIR/$$/osm/land_param
  396. #rm -f land_param_${exp_name}_*
  397. # save land fields for 1st day of each month
  398. for f in ${run_dir}/$DATADIR/ICMGG${exp_name}+??????
  399. do
  400. # hack to get first timestep of the run which is at 0300h instead of 0000h
  401. # remove this if the OSM post script is fixed to output first timestep
  402. fname=`basename $f`
  403. if [ ${fname: -6:6} == $run_start_date_yyyymm ]
  404. then
  405. ${grib_copy} -w param=${land_param},dataTime=0300,day=1 $f land_param_${exp_name}_[dataDate]00
  406. tmpfile=land_param_${exp_name}_${run_start_date_yyyymm}0100
  407. if [ -f $tmpfile ]
  408. then
  409. ${grib_set} -s dataTime=0000 $tmpfile tmp1
  410. mv tmp1 $tmpfile
  411. fi
  412. fi
  413. ${grib_copy} -w param=${land_param},dataTime=0000,day=1 $f land_param_${exp_name}_[dataDate]00
  414. done
  415. for f in land_param_${exp_name}_?????????? ; do gzip -c $f > ${OUTDIR}/$f.gz ; rm $f ; done
  416. }
  417. # Save icmcl files containing vegetation state
  418. # These files are similar to the "era20c vegetation from an off-line LPJ-Guess run forced with ERA20C"
  419. # files used in the EC-Earth runscripts
  420. # This is only only useful for LPJG runs, in which vegetation is transient
  421. # This function can also be used with IFS output, with some minor changes
  422. function osm_post_icmcl()
  423. {
  424. DATADIR=$1 # location where the output was saved
  425. cd ${run_dir}/$DATADIR
  426. vars="var66,var67,var27,var28,var29,var30"
  427. vars_grib="66/67/27/28/29/30"
  428. vars_mean="var66,var67,var27,var28"
  429. vars_type="var29,var30"
  430. for (( year=leg_start_date_yyyy ; year<=leg_end_date_yyyy_full ; year+=1 ))
  431. do
  432. # process each monthly file
  433. for month in `seq -w 1 12`
  434. do
  435. prefix=ICMGG${exp_name}
  436. rm -f icmcl_${year}${month}.grb icmcl_${year}${month}_{mean,type}.grb tmp.grb
  437. ${grib_copy} -w paramId=${vars_grib},dataTime=0000 ${prefix}+${year}${month} tmp.grb
  438. cdo -O settaxis,${year}-${month}-15,00:00:00 -timmean -selvar,${vars_mean} tmp.grb icmcl_${year}${month}_mean.grb
  439. cdo -O seldate,${year}-${month}-15T00:00:00 -selvar,${vars_type} tmp.grb icmcl_${year}${month}_type.grb
  440. cdo -O merge icmcl_${year}${month}_*.grb icmcl_${year}${month}.grb
  441. rm -f icmcl_${year}${month}_{mean,type}.grb tmp.grb
  442. done
  443. # merge all monthly files into one yearly file
  444. cdo -O mergetime icmcl_${year}??.grb icmcl_${year}.grb
  445. rm -f icmcl_${year}??.grb
  446. # re-order them in the same order as era20c files
  447. cdo -O splitname icmcl_${year}.grb icmcl_${year}_
  448. ifiles=""
  449. IFS=","
  450. for v in $vars ; do ifiles+=" icmcl_${year}_${v}.grb " ; done
  451. unset IFS
  452. cdo -O merge $ifiles icmcl_${year}.grb
  453. # fixes for IFS (set missing data to 0, fix wrong metadata)
  454. cdo setmisstoc,0. icmcl_${year}.grb tmp.grb
  455. ${grib_set} -s gridType=reduced_gg,timeRangeIndicator=10 tmp.grb icmcl_${year}.grb
  456. rm -f icmcl_${year}_* tmp.grb
  457. done
  458. }
  459. function osm_post_gen_script()
  460. {
  461. DATADIR=$1 # location where the output was saved
  462. LEG=$2
  463. has_config osm:post_all && do_post_all=true || do_post_all=false
  464. has_config osm:post_spinup && do_post_spinup=true || do_post_spinup=false
  465. cat > ${exp_name}_osm_post_${LEG}.sh << EOF
  466. #!/usr/bin/env bash
  467. set -ex
  468. # declare essential variables
  469. exp_name="$exp_name"
  470. member="${member:-}"
  471. start_dir="$start_dir"
  472. out_dir="${DATADIR}"
  473. run_start_date="$run_start_date"
  474. run_start_date_as="${run_start_date_as:-}"
  475. leg_start_date="$leg_start_date"
  476. leg_end_date="$leg_end_date"
  477. leg_start_date_yyyy="$leg_start_date_yyyy"
  478. leg_end_date_yyyy_full="$leg_end_date_yyyy_full"
  479. ifs_grid=$ifs_grid
  480. ifs_output_freq="$ifs_output_freq"
  481. ifs_time_step_sec="$ifs_time_step_sec"
  482. ifs_version="$ifs_version"
  483. # setup environment
  484. source $start_dir/ecconf.cfg
  485. source $start_dir/librunscript.sh
  486. source $start_dir/liblsm.sh
  487. configure
  488. [ -z \$TMPDIR ] && error "you must define TMPDIR for your platform in configure()!!!"
  489. # configure_python # NSC-Tetralith: Uncomment to get the correct GRIB_BIN_PATH for grib_set and grib_copy
  490. grib_copy=${GRIB_BIN_PATH}${GRIB_BIN_PATH:+/}grib_copy
  491. grib_set=${GRIB_BIN_PATH}${GRIB_BIN_PATH:+/}grib_set
  492. #configure_python
  493. set -u
  494. #override some defaults set by configure() in ecconf.cfg
  495. run_dir="$run_dir"
  496. land_param_dir=\${run_dir}/output/osm/land_param
  497. lpjg_ifs_output_dir="\$run_dir/\$out_dir"
  498. lpjg_forcing_dir="\${run_dir}/output/osm/lpjg_forcing"
  499. osm_forcing_type="${osm_forcing_type}"
  500. if ${do_post_all}
  501. then
  502. # do osm+land_param+lpjg_forcing+icmcl post-processing
  503. #config=lpjg_forcing
  504. osm_post_all \$out_dir \${land_param_dir} \${lpjg_forcing_dir}
  505. else
  506. # do basic OSM output post-processing, which generates grib output files)
  507. osm_post_output \$out_dir
  508. fi
  509. if ${do_post_spinup}
  510. then
  511. # run lpjg_gen_forcing_spinup to get lpjg_forcing yearly files and lpjg fast files for spinup
  512. config_bak="\${config:-}"
  513. config="lpjg:spinup"
  514. lpjg_gen_forcing_spinup
  515. config="\${config_bak}"
  516. fi
  517. EOF
  518. # # To run sequentially just do:
  519. # chmod +x ${exp_name}_osm_post_${LEG}.sh
  520. # ./${exp_name}_osm_post_${LEG}.sh
  521. ## To submit a job : platform dependent...
  522. #sbatch -n 1 -o ${start_dir}/${exp_name}_osm_post_${LEG}.out -p np16 ${exp_name}_osm_post_${LEG}.sh
  523. #sbatch -n 6 -o ${start_dir}/${exp_name}_osm_post_${LEG}.out -q debug ${exp_name}_osm_post_${LEG}.sh
  524. }
  525. function lpjg_gen_forcing1()
  526. {
  527. # generic script to create/prepare forcing
  528. # IFS/OSM forcing is always implied when usign lpjf_forcing
  529. has_config lpjg_forcing && lpjg_forcing_type='ifs' || error "only IFS forcing supported for LPJG-offline"
  530. FYEAR=$1 # year to process forcing
  531. # ${lpjg_forcing_dir} : must be defined as where the forcing is present or created
  532. # ${lpjg_ifs_output_dir} : must be defined, in case of forcing from IFS, location of raw output
  533. if $(has_config lpjg_forcing:gen_forcing) || ! [ -r ${lpjg_forcing_dir}/var170_${FYEAR}_dayavg.nc ]
  534. then
  535. # file not available, will need to be created
  536. if [ $lpjg_forcing_type = 'ifs' ]
  537. then
  538. echo "generating LPJG forcing in ${lpjg_forcing_dir} from data in ${lpjg_ifs_output_dir}"
  539. # forcing from an IFS experiment
  540. lpjg_gen_forcing_ifs $FYEAR
  541. else
  542. error "only IFS forcing supported for LPJG-offline"
  543. fi
  544. fi # end of forcing processing
  545. }
  546. function lpjg_gen_forcing()
  547. {
  548. ## generic script to create/prepare forcing
  549. FYEAR1=$1 # first year to process forcing
  550. FYEAR2=$2 # last year to process forcing
  551. ## generate forcing for each year
  552. for (( yr=$FYEAR1 ; yr<=$FYEAR2 ; yr+=1 ))
  553. do
  554. lpjg_gen_forcing1 $yr
  555. done
  556. }
  557. function lpjg_gen_forcing_ifs()
  558. {
  559. # set variables required by extract_daily_forcing_ifs
  560. y1=$1
  561. y2=$1
  562. y0=$(date -u -d "$run_start_date" +%Y)
  563. case "${ifs_grid}" in
  564. T159L*) npts=35718 ;;
  565. T255L*) npts=88838 ;;
  566. *) error "Can't set npts for unknown horizontal grid: ${ifs_grid}" ;;
  567. esac
  568. srcdir=$lpjg_ifs_output_dir
  569. #srcext=${lpjg_ifs_output_ext:-}
  570. outdir=$lpjg_forcing_dir
  571. tmpdir=$TMPDIR/$$/lpjg/lpjg_gen_forcing_ifs
  572. #tmpdir=${lpjg_forcing_dir}/tmp
  573. grib_filter=${GRIB_BIN_PATH}${GRIB_BIN_PATH:+/}grib_filter
  574. extract_daily_forcing_ifs
  575. }
  576. # This script creates netcdf files used by sparring to drive LPJG offline from raw IFS output.
  577. #
  578. # Created By Klaus Wyser, some modifications by Etienne Tourigny
  579. # ==============================================================================
  580. # set these variables before calling extract_daily_forcing_ifs()
  581. #expname=a0l3; npts=88838
  582. #expname=AHIL; npts=35718
  583. #y1=1990 ; y2=1990 ; y0=1990
  584. #srcdir=/gpfs/scratch/bsc32/bsc32051/lpjg/a0l3/in/output/ifs
  585. #outdir=/gpfs/scratch/bsc32/bsc32051/lpjg/a0l3/out
  586. #tmpdir=$SNIC_TMP
  587. #grib_filter=grib_filter
  588. # ==============================================================================
  589. function extract_daily_forcing_ifs()
  590. {
  591. mkdir -p $outdir
  592. mkdir -p $tmpdir
  593. pushd .
  594. cd $tmpdir
  595. # create grib_filter script
  596. # add 169 (ssrd) and 175 (strd) for surface downward radiation, LPJG currently uses surface net radiation
  597. # soil moisture (39 40 41 42) and soil temp levels 1 and 4 (139 236) are currently not used by LPJG
  598. # total precipitation tp (228) is output by OSM, instead of lsp and cp (142 and 143)
  599. # leave out 33 (snow density) and 141 (snow depth) since they are not used by LPJG anyway
  600. # removed 144 (sf) since snowfall is included in cp and lsp
  601. sstring=
  602. for c in 39 40 41 42 139 167 170 183 236; do
  603. sstring+=" || marsParam is \"$c.128\""
  604. done
  605. sstring=${sstring:4:${#sstring}}
  606. fstring=
  607. for c in 142 143 228 176 177; do
  608. fstring+=" || marsParam is \"$c.128\""
  609. done
  610. fstring=${fstring:4:${#fstring}}
  611. cat > gf << EOT
  612. if ( $sstring ) { write "x_state" ; }
  613. if ( $fstring ) { write "x_flux" ; }
  614. EOT
  615. # first timestep
  616. # for decadal runs, we start LPJG on Jan 1st but IFS output is available before that,
  617. # so we always use the output of the last timestep of the previous month if it exists
  618. # first look for .grb file, if not found look for file without extension
  619. ff0=$(find $srcdir -name "ICMGG????+$(( y1 -1 ))12.grb")
  620. [[ "$ff0" == "" ]] && ff0=$(find $srcdir -name "ICMGG????+$(( y1 -1 ))12")
  621. [[ "$ff0" == "" ]] && ff0=$(find $srcdir -name "ICMGG????+000000.grb")
  622. [[ "$ff0" == "" ]] && ff0=$(find $srcdir -name "ICMGG????+000000")
  623. ff0=( $ff0 )
  624. #[[ "$ff0" == "" ]] && error "Cannot find forcing for year $y1!"
  625. ym=$((y1-1))12
  626. # if first timestep is not found, continue (this happens with OSM output)
  627. #if [[ "$ff0" == "" ]] ; then
  628. if [ ${#ff0[@]} -eq 0 ] ; then
  629. echo "Cannot find first timestep of forcing for year $y1!"
  630. else
  631. # exit if found multiple files
  632. [ ${#ff0[@]} -gt 1 ] && error "Found ${#ff0[@]} files for first timestep of forcing for year $y1!"
  633. ${grib_filter} gf $ff0
  634. mv x_state x_state_$ym
  635. #cdo shifttime,"-6hour" x_flux x_flux_$ym
  636. mv x_flux x_flux_$ym
  637. rm -f x_flux
  638. fi
  639. for y in $(seq $y1 $y2); do
  640. for m in $(seq 1 12) ; do
  641. ym=$((100*y+m))
  642. mkdir -p $tmpdir/data_$ym
  643. cd $tmpdir/data_$ym
  644. #${grib_filter} ../gf $srcdir/output/ifs/$(printf %03d $((y-$((y0-1)))))/ICMGG????+$ym
  645. ff0=$(find $srcdir -name "ICMGG????+${ym}.grb")
  646. [[ "$ff0" == "" ]] && ff0=$(find $srcdir -name "ICMGG????+${ym}")
  647. ff0=( $ff0 )
  648. [ ${#ff0[@]} -eq 0 ] && error "Cannot find forcing for $ym!"
  649. # exit if found multiple files
  650. [ ${#ff0[@]} -gt 1 ] && error "Found ${#ff0[@]} files for forcing for $ym - ${ff0[@]}"
  651. ${grib_filter} ../gf $ff0
  652. mv x_state ../x_state_$ym
  653. #cdo shifttime,"-6hour" x_flux ../x_flux_$ym
  654. mv x_flux ../x_flux_$ym
  655. cd -
  656. rm -r $tmpdir/data_$ym
  657. done
  658. done
  659. # compute post-processing timestep, used to compute daily fluxes
  660. # TODO check cmip6 output with 3h and 6h output
  661. pptime=$(cdo showtime -seltimestep,1,2 x_flux_$ym | \
  662. tr -s ' ' ':' | awk -F: '{print ($5-$2)*3600+($6-$3)*60+($7-$4)}' )
  663. #pptimeh=$(bc -l <<< "$pptime / 3600")
  664. for y in $(seq $y1 $y2); do
  665. #cdo cat x_state_$((y-1))12 x_state_$y* y_state_$y
  666. #[ ! -f x_state_$((y-1))12 ] && cdo settime,00:00:00 -seltimestep,1 x_state_${y}01 x_state_$((y-1))12
  667. if [ -f x_state_$((y-1))12 ]
  668. then
  669. echo "File x_state_$((y-1))12 exists"
  670. else
  671. echo "Creating file x_state_$((y-1))12 from file x_state_${y}01 ...."
  672. cdo -seltimestep,1 x_state_${y}01 test
  673. cdo settime,00:00:00 test x_state_$((y-1))12
  674. rm -f test
  675. fi
  676. cdo cat x_state_$((y-1))12 x_state_$y* y_state_$y
  677. cdo splitcode -daymean -selyear,$y y_state_$y z_${y}_
  678. cdo cat x_flux_$y* y_flux_$y
  679. #cdo splitcode -daymean -selyear,$y y_flux_$y* z_${y}_
  680. cdo splitcode -daymean -selyear,$y -shifttime,"-${pptime}seconds" y_flux_$y* z_${y}_
  681. done
  682. for f in $(/bin/ls z_*grb ); do
  683. fnew=$(basename $f .grb | cut -d _ -f 3 )
  684. year=$(basename $f .grb | cut -d _ -f 2 )
  685. # set missval to reasonable values, following ifs-36r4/src/surf/offline/driver/cnt31s.F90
  686. case ${fnew} in
  687. "039" | "040" | "041" | "042" ) missval="0.2" ;; # SoilMVeg
  688. "139" | "170" | "183" | "236" ) missval="280" ;; # SoilTVeg
  689. "167" ) missval="280" ;; # T2MVeg
  690. "142" | "143" | "228" | "144" ) missval="0" ;; # TPVeg
  691. "176" | "177" ) missval="0" ;; # SSRVeg SLRVeg
  692. "033" ) missval="330" ;; # SDensVeg
  693. "141" ) missval="0" ;; # SDVeg
  694. * ) missval="" ; ;;
  695. esac
  696. [ $missval != "" ] && setmissval="-setmissval,$missval" || setmissval=""
  697. # convert fluxes to daily values as sent from IFS to LPJG
  698. case ${fnew} in
  699. # convert timestep accumulated J m-2 to daily W m-2
  700. # first multiply daily average of timestep accumulated (z_) by #timesteps in day,
  701. # then divide by sec/day to get W m-2 per day -> (86400/pptime)/86400 = 1/pptime
  702. "176" | "177" ) convert="-divc,${pptime}" ;; # SSRVeg SLRVeg
  703. # precip - convert m to kg m-2 s-1
  704. "142" | "143" | "228" | "144" ) convert="-mulc,"$( bc -l <<< "1000.0 / $pptime" ) ;; # TPVeg
  705. * ) convert="" ; ;;
  706. esac
  707. cdo -f nc4c -z zip_2 setgrid,g${npts}x1 $convert $setmissval $f $outdir/var${fnew}_${year}_dayavg.nc
  708. done
  709. # cleanup
  710. rm -f gf x_state_* x_flux_* y_state_* y_flux_* z_*grb
  711. popd
  712. }
  713. function lpjg_gen_forcing_spinup()
  714. {
  715. if ! $(has_config lpjg:spinup)
  716. then
  717. echo "not doing anything, since lpjg:spinup is not in config"
  718. return
  719. fi
  720. y0=$(date -u -d "${run_start_date}" +%Y)
  721. y1=$(( y0 + 9 ))
  722. fileyears=${y0}-${y1}
  723. vars_depth="39 40 41 42 170 183"
  724. vars_nodepth="167 176 177 228"
  725. if [ -r ${lpjg_forcing_dir}/var170_${fileyears}_fast.nc ]
  726. then
  727. echo "skipping lpjg_gen_forcing_spinup() since forcings have been found in {lpjg_forcing_dir}"
  728. return
  729. fi
  730. # first make sure we have all yearly forcings
  731. local config_bak="${config}"
  732. config=lpjg_forcing
  733. lpjg_gen_forcing $y0 $y1
  734. config="${config_bak}"
  735. cd $lpjg_forcing_dir
  736. # concatenate all files
  737. for var in ${vars_depth} ${vars_nodepth}
  738. do
  739. var0=$(printf %03d $var)
  740. cdo_str=""
  741. #[ -f var${var}_$fileyears.nc ] && continue
  742. for y in `seq $y0 $y1`
  743. do
  744. cdo_str+=var${var0}_${y}_dayavg.nc" "
  745. done
  746. cdo -O -f nc4c -z zip_2 mergetime $cdo_str var${var}_$fileyears.nc
  747. done
  748. # nco module is needed for ncpdq
  749. # adjust this for your platform, this works on marenostrum4
  750. module load gsl/2.4 udunits/2.2.25 nco/4.2.3_netcdf-4.2
  751. # convert to "fast" format
  752. for var in ${vars_depth}
  753. do
  754. #[ ! -f var$var"_"$fileyears"_fast.nc" ] && ncpdq -O -L 2 -a x,time,y,depth var$var"_"$fileyears".nc" var$var"_"$fileyears"_fast.nc"
  755. ncpdq -O -L 2 -a x,time,y,depth var$var"_"$fileyears".nc" var$var"_"$fileyears"_fast.nc"
  756. #ncpdq -O -a x,time,y,depth $var"_"$fileyears".nc" $var"_"$fileyears"_fast.nc"
  757. done
  758. for var in ${vars_nodepth}
  759. do
  760. ncpdq -O -L 2 -a x,time,y var$var"_"$fileyears".nc" var$var"_"$fileyears"_fast.nc"
  761. done
  762. cd -
  763. }