m3nc2GIF平行轉檔
Table of contents
背景
- 單一個m3nc檔進行濃度圖的解讀製作,可以使用m3nc2GIF循序(按照檔案時間順序)進行。如果要平行運作,還需要有OS批次腳本來控制,會失去程式的單純性。
- 現因執行多個m3nc檔、任意時間段落的等濃度圖製作,本來就需要有個執行腳本來控制,此時不將其平行化,更待何時。
- 本程式為m3nc2GIF的平行版本,程式差異比較如下表
項目 | 循序版 | 平行版 | 說明 |
---|---|---|---|
批次執行之腳本 | aconc2gif.cs | aconc2gifP.cs | 循序版尚能個別執行,平行版的引數多達5個,建議還是需要批次腳本執行較佳 |
m3nc輸入檔 | 含有所有時間之單一大檔 | 只有個別時間之多個小檔 | 可以提升讀檔的效率 |
濃度範圍 | 單一檔不同時間,在同一個python內即可決定 | 另外讀取決定,將極值輸入每一個小時之作業,才能做出相同濃度範圍的圖形 | 需撰寫新的程式 |
暫存檔 | ${s}_tmp.png | ${s}_tmp${ISEQ}.png | 同時運作時不會被覆蓋 |
GIF製作 | 在python內處理 | 必須確認所有平行作業都完成了才能執行 | 必須在呼叫之批次檔內完成 |
節點之利用 | 只用到1個 | 視小時數而定 | 如果太多,有可能超過工作站的總節點數 |
程式差異
引數
- m3nc檔名:與原本m3nc2GIF相同,以下為新增輸入項目
- 年月日時:指定轉檔的時間點(UTC)
- 輸出png檔案的順序碼:以避免被覆蓋
- 批次作業的極小值:需統一所有等值圖的範圍,避免GIF圖檔跳動。
- 批次作業的極大值
$ 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檔案之轉檔腳本
- aconc2gif.cs與aconc2gifP.cs差異詳述如下
儒略日序列紀錄予更正
因為個別處理nc檔案,需要將nc.SDATE予以更正,因此需將每筆的儒略日記錄起來備用
aconc2gif.cs與aconc2gifP.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[@]})
方式來連接所有小時的片段檔案,這個做法沒有改變。好處是:- 個數不定、保持彈性
- 按照時間順序,不會因檔名排序而造成錯亂
- 絕對不會遺漏檔案
- 不將檔名逐一列出,節省程式篇幅。
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
等待所有作業都完成
- 這段也是新的
- 為了提高判斷機制的獨立性
- 加入
${GRD[$d]}
,如此不同範圍的作業可以同時進行,不致互相干擾。 - 加入第一與最後檔案必須存在的條件。因為即使已有檔案,也會在執行python之前被刪除,因此程式必須產生檔案出來才算完成。
- 所有小時的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=$( /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])