m3nc2GIF平行轉檔

Table of contents

背景

  • 單一個m3nc檔進行濃度圖的解讀製作,可以使用m3nc2GIF循序(按照檔案時間順序)進行。如果要平行運作,還需要有OS批次腳本來控制,會失去程式的單純性。
  • 現因執行多個m3nc檔、任意時間段落的等濃度圖製作,本來就需要有個執行腳本來控制,此時不將其平行化,更待何時。
  • 本程式為m3nc2GIF的平行版本,程式差異比較如下表
項目循序版平行版說明
批次執行之腳本aconc2gif.csaconc2gifP.cs循序版尚能個別執行,平行版的引數多達5個,建議還是需要批次腳本執行較佳
m3nc輸入檔含有所有時間之單一大檔只有個別時間之多個小檔可以提升讀檔的效率
濃度範圍單一檔不同時間,在同一個python內即可決定另外讀取決定,將極值輸入每一個小時之作業,才能做出相同濃度範圍的圖形需撰寫新的程式
暫存檔${s}_tmp.png${s}_tmp${ISEQ}.png同時運作時不會被覆蓋
GIF製作在python內處理必須確認所有平行作業都完成了才能執行必須在呼叫之批次檔內完成
節點之利用只用到1個視小時數而定如果太多,有可能超過工作站的總節點數

程式差異

引數

  1. m3nc檔名:與原本m3nc2GIF相同,以下為新增輸入項目
  2. 年月日時:指定轉檔的時間點(UTC)
  3. 輸出png檔案的順序碼:以避免被覆蓋
  4. 批次作業的極小值:需統一所有等值圖的範圍,避免GIF圖檔跳動。
  5. 批次作業的極大值
$ diff m3nc2gif.py m3nc2gifP.py
37c37
< fname=sys.argv[1]
---
> fname,ymdh,iseq=sys.argv[1] ,sys.argv[2], int(sys.argv[3])
65,70c65,66
<   a=nc[v][:,0,:,:]
<   a=np.where(a==a,a,-1)
<   a=np.where(a>0,a,0)
<   mxv=np.percentile(a,99.99)
<   print (mxv)
<   mnv=np.max([np.percentile(a,0.01),mxv/100])
---
>   mnv=float(sys.argv[4])
>   mxv=float(sys.argv[5])

確認時間點

76a73,75
>     sdate=(bdate+timedelta(hours=t)).strftime("%Y%m%d%H")
>     if sdate != ymdh :continue
>     sdate=(bdate+timedelta(hours=t)).strftime("%Y-%m-%d_%H:00Z")
111d109
<     sdate=(bdate+timedelta(hours=t)).strftime("%Y-%m-%d_%H:00Z")

輸出檔案名稱與後處理

  • 暫存檔
    • 平行作業的暫存檔必須有獨特的檔名,以避免被覆蓋。
    • 個別產生、也個別刪除
  • GIF檔案製作
    • 取消在python階段製作,改在批次檔中統一製作
123c121,122
<     png=v+'_'+'{:03d}'.format(t)+'.png'
---
>     png=v+'_'+'{:03d}'.format(iseq)+'.png'
>     pngt=png.replace('.png', 'tmp.png')
126,129c125,127
<     os.system(CVT+' -bordercolor white -trim '+png+' tmp.png')
<     os.system(CVT+' -bordercolor white -border 5%x5% tmp.png '+png)
<   size=subprocess.check_output(CVT+' '+v+'_000.png -format "%wx%h" info:',shell=True).decode('utf8').strip('\n')
<   os.system(CVT+' -dispose 2 -coalesce +repage -background none '+v+'_*.png -size '+size+' '+v+'.gif')
---
>     os.system(CVT+' -bordercolor white -trim '+png+' '+pngt)
>     os.system(CVT+' -bordercolor white -border 5%x5% '+pngt+' '+png)
>     os.system('rm -f '+pngt)

CCTM_ACONC檔案之轉檔腳本

儒略日序列紀錄予更正

  • 因為個別處理nc檔案,需要將nc.SDATE予以更正,因此需將每筆的儒略日記錄起來備用

  • aconc2gif.csaconc2gifP.cs差異詳述如下

儒略日序列紀錄與更正

  • 因為個別處理nc檔案,需要將nc.SDATE予以更正,因此需將每筆的儒略日記錄起來備用
30a31
> datej=();for i in $(seq $bj $ej);do datej=( ${datej[@]} $i );done
  • 每一個小時之片段檔案都需要更正nc.STIME與nc.SDATE,這樣才會有正確的時間標記。
57a64,67
>     if ! [ -e $fnameo ];then echo $fname fnameo; exit;fi
>     STIME=${jh}0000.;if [[ $jh -eq 0 ]];then STIME=0;fi
>     $NCATTED -a STIME,global,o,f,${STIME} $fnameo
>     $NCATTED -a SDATE,global,o,f,${datej[$jd1]} $fnameo
65,66c74,92
< test $bh -gt 0 && $NCATTED -a STIME,global,o,f,${bh}0000. $s.nc

每個nc檔之命名方式

  • 雖然不會影響ncrcat的執行,此處還是將其改成2碼整數(00~23)

    • 只是整合檔的用途改變了,只用來讀取濃度的極大與極小值範圍。
56c61,62
<     fnameo=${root}/${s}${dates[$jd1]}_$jh
---
>     jhh=$( printf "%02d" ${jh} )
>     fnameo=${root}/${s}${dates[$jd1]}_$jhh

序列環境變數作為檔名串列輸入

  • ncrcat使用$(echo ${fnames[@]})方式來連接所有小時的片段檔案,這個做法沒有改變。好處是:
    1. 個數不定、保持彈性
    2. 按照時間順序,不會因檔名排序而造成錯亂
    3. 絕對不會遺漏檔案
    4. 不將檔名逐一列出,節省程式篇幅。
a='$NCRCAT -O '$(echo ${fnames[@]})' $s.nc'
eval $a

png與片段nc檔的去除

  • convert轉檔時所讀取的png檔案,也可以使用$(echo ${pngs[@]})方式來建立清單,不必以${s}_*.png這種不明確的方式,因此,似乎沒有必要全部刪除,反而平行作業時太快刪除檔案將會造成錯誤。
> if compgen -G "${s}_*.png" > /dev/null; then rm ${s}_*.png;fi;
---
< if compgen -G "${s}_*.png" > /dev/null; then rm ${s}_*.png;fi;for i in $( seq 0 $len);do if [[ -e ${fnames[$i]} ]];then rm ${fnames[$i]};fi;done

濃度範圍之求取

  • 循序版程式的濃度範圍,並非真正的極大與極小值,而是一定累積頻率的範圍。沒有現成的程式(如mxNC,mnNC等等)可用,需要另外寫一個。(mnxNC)
  • 程式的執行結果會輸出2個實數,就是整個時段的濃度範圍。將其儲存成字串$mnmx備用。
> mnmx=$(~/bin/mnxNC /nas2/cmaqruns/2022fcst/grid03/cctm.fcst/daily/${s}.nc )

各小時平行製圖

  • 這段程式碼是新的。
    • 迴圈與前述產生各小時nc檔片段相同。
    • 如果png檔名已經有舊檔,先將其刪除,避免發生錯誤。
    • 呼叫m3nc2gifP,輸入5個引數。因2個極值存在一個變數($mnmx)裡,所以看起來只有4個引數。
    • 等候1秒的考量:讓OS可以依序開啟檔案。太快開啟python及檔案、系統似乎有些吃不消。
    • 累積${pngs[@]}檔名序列備用(convert時需要)。
  • 相較m3nc2gif做法只有一個引數,直接產生gif檔案。
< ~/bin/m3nc2gif.py $s.nc
< mv $s.gif ${s}_${b}.gif
---
>
> pngs=()
> iii=0
> for jd in $(seq 1 $nd);do
>   jd1=$(( $jd - 1))
>   jbh=0; test $bd == ${dates[$jd1]} && jbh=$bh
>   jeh=23; test $ed == ${dates[$jd1]} && jeh=$eh
>   for jh in $(seq $jbh $jeh);do
>     jhh=$( printf "%02d" ${jh} );fnameo=${fnames[$iii]}
>     i=$( printf "%03d" ${iii} );png=${s}_$i.png;
>     pngs=( ${pngs[@]} $png )
>     if [[ -e $png ]];then rm -f $png;fi
>     ~/bin/sub ~/bin/m3nc2gifP.py $fnameo ${dates[$jd1]}${jhh} $iii $mnmx
>     sleep 1
>     iii=$(( $iii + 1 ))
>   done
> done

等待所有作業都完成

  • 這段也是新的
  • 為了提高判斷機制的獨立性
    1. 加入${GRD[$d]},如此不同範圍的作業可以同時進行,不致互相干擾。
    2. 加入第一與最後檔案必須存在的條件。因為即使已有檔案,也會在執行python之前被刪除,因此程式必須產生檔案出來才算完成。
    3. 所有小時的python程式都必須停下來。
> while true;do
>   n=$(ps -ef|grep m3nc2gifP.py|grep ${GRD[$d]} |wc -l)
>   if [[ $n -eq 0 ]] && [[ -e ${pngs[0]} ]] && [[ -e ${pngs[$len]} ]];then
>     break
>   else
>     sleep 1
>   fi
> done
>
> #for i in $( seq 0 $len);do if [[ -e ${fnames[$i]} ]];then rm -f ${fnames[$i]};fi;done
> #rm -f $root/${s}.nc

執行conver將pngs連結稱為gif檔

  • size的取法:與m3nc2gif做法相同,只是改成OS版本。
  • png檔案的串連:與前述ncrcat一樣,採用echo ${pngs[@]}方式。好處同
  • 執行一個環境變數的內容,使用eval指令。
> size=$( /usr/bin/convert ${s}_000.png -format "%wx%h" info: )
> a='/usr/bin/convert -dispose 2 -coalesce +repage -background none '$(echo ${pngs[@]})' -size $size ${s}_${b}.gif'
> eval $a

mnxNC

  • 這支小程式,就是原本m3nc2gif求取極值的程式碼。將其獨立出來運作就是了。
    • 最大值:取累積頻率99.99%
    • 最小值:取0.01%、或mxv的1/100(2取大),差2個數量級就非常足夠了,不必太小。
  • 引數、也是輸入檔:單一m3nc檔
  • 輸出:print(mnv,mxv)
  mxv=np.percentile(a,99.99)
  mnv=np.max([np.percentile(a,0.01),mxv/100])