2014.08.06
Squall line เป็นแนวฝนแบบ Convective
ที่จัดเรียงตัวกันในมาตราส่วน Meso scale คิดง่ายคือ
ประมาณหลักร้อยกิโลเมตรนั่นคือ
พื้นที่เรดาร์ตรวจอากาศภาคพื้นดินสามารถตรวจจับรูปแบบการเคลื่อนที่ของฝนนี้ได้
ในแถบอินโดจีนมีโปรเฟสเซอร์ Prof.Takehiko Satomura ได้ทำการอธิบายและเสนอกลไกการกำเนิดรูปแบบฝนชนิดไว้แล้ว
ในปี2000 น่าเสียดายที่ท่านได้จากโลกนี้ไปแล้วเมื่อเดือนมีนาคม 2014 ท่านเป็นอาจารย์ของผมเอง
หากแต่ไอเดียท่านยังอยู่กับพวกเรา 
 แนวคิดภาพตัดขวางแนวดิ่ง RHI 
ผมได้ทดลองทำการนำการประมาณค่าแบบ
Inverse
Distance Weighted IDW มาใช้กับข้อมูลเรดาห์ที่ตรวจอากาศแบบหลายมุม (เหมือนจะง่ายแต่ใช้เวลาพอควรเลยครับ ตอนใช้พวกGIS เนี่ยแค่คลิกไม่กี่ที 555 )ข้อมูลนำเข้าได้จากการ extract ข้อมูลเรดาร์ด้วย Library แล้วเก็บในรูปของไบนารี่ที่เป็นฟอร์แมทของผมเอง
ผมใช้ข้อมูลไบนารี่ตัวนี้ในการทดลองทำภาพที่ชื่อว่า Range-Height-Indicator (RHI) เป็นภาพแนวดิ่งของเรดาร์ขณะที่ Squall กำลังเคลื่อนตัวผ่านที่ตั้งของเรดาร์ โดยผมเขียนโปรแกรมเลือกข้อมูลหนึ่งมุมอซิมุธ
หลายมุมยก แต่ละมุมยกจะมีความละเอียดที่เราเรียกว่า  Bin size โดยภาพที่ได้ข้างล่างเป็นการประมาณค่า dBZ ของฝนแบบ Squall ในตอนเย็น
โปรแกรมยังมี Bug อยู่
ต้องแก้นิดหน่อยเลยโพสบางส่วนให้เป็นไอเดียครับ ขั้นตอนในโปรแกรมFortran คือ 
1.       
อ่านเรดาร์แบบ Volume  ไฟล์ และเลือกมุมอซิมุทที่ต้องการ Plot เลือกความสูง
ระยะทางของเรดาร์บีม 
2.       
คำนวนความสูงและระยะทาง ของแต่ละจุดที่เรดาห์ได้ทำการบันทึกข้อมูล
3.       
เรียกซับโปรแกรมเพื่อประมาณค่าจุดเรดาร์ในแต่ละมุมยก ด้วย IDW
ตัวอย่างฝนชนิด Squalline
program
create_RHI
!-------------------------------------------------------------
! 2014.08.06 NATAPON MAHAVIK
! to create data for plotting Range-Height-Indicator [RHI]
! from extracted radar of
Phetchabun by Gematronik library
! data stor at
/home/mnattapon/RAID3storage4/research_icp/
!
analysis_phb_alg/radar_ans/cal_RHI_PPI_CAPPI_rad/cal_RHI
! data of selected azimuth will be
interpolate by IDW
!-------------------------------------------------------------
implicit none
integer,parameter ::
sizeofreal=4           !-record size  
integer :: i,j,m,n
real, parameter :: pi =
4*atan(1.0)         !- exploit intrinsic
atan to generate pi
real,parameter ::
d2r=pi/180.0              !- radian
conversion degree to radian
real,parameter :: k2m=1000.0                !- km to meters
real,parameter :: NA=-9999.0                !- no radar data    
!-radar variables
integer :: rn                                !-record number
integer :: maxelv                            !-max number of
elevations
real :: elv_rad                                   ! elevation
angle in radian
character*10 :: path
real :: rgate          ! real(igate) = gate "km"
real :: rbin          ! real(irbin) = rbin  "km"
integer :: ielv, iazm, ibin
integer :: maxazmt                            !-Max number of
rays as temp var
integer:: maxbin                              ! Max number of
range
integer,parameter ::
maxazmf=1000              !-Max number of
rays as my asssumption!!!
real, dimension(:,:,:), allocatable
:: rdata  !-Radar data
real, dimension(:,:),
allocatable   :: elv    !-Elevation angles 
real, dimension(:,:),
allocatable   :: azmth  !-Angles [ in mathematic in degree]
real,dimension(:,:), allocatable
:: azmth_rad  !-Angles [in azimuth in
radian]
integer,dimension(:),allocatable
:: maxazm    !-Max number of rays
depending on sweeps
real,dimension(:,:,:),allocatable
::beam_dist_hz  !-beam distance in
horizontal plain in m.
real,dimension(:,:,:),allocatable
::beam_height   !-beam height by reinhart
p62 in m.
integer,parameter::re=6374000.                    !-earth radius in m.
real,parameter ::rr=4./3.*re                      !-reinhart p62 as R' in
m.
real,parameter :: rad_alt=97.                    !-radar altitude above MSL
from calculation DEM.(GG~73)
real :: h_rd=30.                                 !-height of
radar antenna   by estimate TMD using 30m
integer :: az_int                                !-round up real azimuth to interger [degree]
real,parameter :: sel_az=225.0                   !-selected azimuth degree
real,parameter ::
min_dbz=10.0,max_dbz=100.0   !-max and
min dbz
real,parameter :: max_dist=200.0            !-max distance for RHI in km
real,parameter :: max_high=15.0             !-max hight for RHI in km
!-output var for interpolation
real, dimension(:,:), allocatable
:: dbz          !-dbz   at elevation(i) & bin number(i) [dBZ] 
real, dimension(:,:), allocatable
:: height       !-height from ellipsoid
at elevation(i) & bin number(i) [km] 
real, dimension(:,:), allocatable
:: dist_x       !-distance from radar
site at elevation(i) & bin number(i)[km]
real, parameter :: res=1.0                        !- unit in km
integer,parameter :: nx=max_dist/res              !- number of x pixels
integer,parameter ::
ny=max_high/res              !- number of
y pixels
real, dimension(nx,ny)::
outp_intp                !- interpolated
output
real, parameter :: radi=2.0                      !-radius of interpolation
in idw [km]
  
!-read radar binary
!-cut 
rn=1
open(10,file=trim(path)//'PHB1008102100.dat',form='unformatted',access='direct',recl=sizeofreal)
read(10,rec=rn) maxelv
!-cut 
!-initialize output 
dbz=NA;height=NA;dist_x=NA
do ielv = 1, maxelv
   
maxazmt=maxazm(ielv)
     do
iazm = 1, maxazmt
      read(10,rec=rn) azmth(iazm,ielv)
      rn = rn + 1
      !--- convert azmuth to be mathematic angle 
!-cut 
      read(10,rec=rn) elv(iazm,ielv)
      rn = rn + 1
      do ibin = 1, maxbin
        read(10,rec=rn) rdata(ibin,iazm,ielv)
        rn = rn + 1
     
        !-cal beam position in horizontal plain                
!-cut 
        !-cal beam height + rad altitude in meter.           
!-cut 
       endif 
      end do
   
end do
 
end do
close(10)
!-call sub IDW interpolate_idw(dbz(height,dist))
print*,'interpolate dbz to idw of
range-height radar ...'
call interpolate_idw(dbz,height,dist_x,maxelv,maxbin,res,nx,ny,radi,max_dbz,outp_intp)
print*,'infos for GRADS ;)
xdef:',nx,'ydef: ',ny,'resolution: ',res
!-write interpolated radar RHI to binary for checking in grads
open
(20,file='rs_interpolated_RHI_radar.bin',form='unformatted',access='direct',
recl=nx*ny*sizeofreal)
write(20,rec=1)outp_intp
close(20)
open
(30,file='rs_interpolated_RHI_radar_ncl.bin',form='unformatted')
write(30)outp_intp
close(30)
deallocate(beam_dist_hz,beam_height);deallocate(rdata,elv,azmth,azmth_rad)
deallocate(maxazm);deallocate(dbz,height,dist_x)
end
program create_RHI
Subroutine
interpolate_idw(dbz,height,dist_x,maxelv,maxbin,res,nx,ny,radi,max_dbz,outp_intp)
implicit none
!-external
integer,intent(in) ::
maxelv,maxbin
real,dimension(maxelv,maxbin),intent(in)
:: dbz,height,dist_x
real,intent(in) :: max_dbz
real,intent(in) :: res           !-defined resolution of output grid
[km]
integer :: nx,ny
real,dimension(nx,ny),intent(out)
:: outp_intp 
real :: radi                     !-defined radius for interpolation [km]
!-internal variables
real :: dist                 !-distance between output grid
and input grid
integer :: sx,ex,sy,ey       !-start and end grid of considering box
respected to radius
integer :: i,j,m,n 
real,parameter :: NA=-9999.0 !-not
available data
real,parameter :: p=-2       !-power for idw
integer :: x,y               !-coordinate of output grid in
input data grid
real :: inv_d                !-inverse distance
real :: nw                   !-normalized weight  
real,dimension(nx,ny) ::
sum_invd      !-sum inverse distance  
real,dimension(nx,ny) ::
sum_nw        !-sum normalized weight
!-loop elvation and bin of input data to be fast calculate
 !outp_intp=NA
!-1st loop for find summation of inverse distance in output grid
do i=1,maxelv
 
do j=1,maxbin
     if (dbz(i,j)==NA)cycle
     
     !-find box of considering interpolation respected to defined radius
     sx=((int(dist_x(i,j))-radi)/res)-res;     ex=((int(dist_x(i,j))+radi)/res)+res  
     sy=((int(height(i,j))-radi)/res)-res;    ey=((int(height(i,j))+radi)/res)+res
        
     !-here to avoid error outbound otherwise
segmentation fault
     if (sx<=0) sx=1;    if (ex>nx) ex=nx;     if (sy<=0) sy=1;     if (ey>ny) ey=ny
     !-loop inside box for calculate summation of inverse distance
     do m=sx,ex
        do n=sy,ey
            
           !-convert coordinate considering
grid to be same input coordinates
           x=(m*res)-res+1;   y=(n*res)-res+1
           
           !-calculate euclidean distance
          
dist=sqrt(abs(x-dist_x(i,j))+abs(y-height(i,j)))
           !print*,x,y,dist        
           !-cal inverse distance and sum all
inverse distance            
           inv_d=dist**p
           sum_invd(m,n)=sum_invd(m,n)+inv_d
         enddo
     enddo          
  
enddo
enddo  
!-2nd loop apply normalized weight to dbz and sum all results of each
ouput grid
do i=1,maxelv
 
do j=1,maxbin
     if (dbz(i,j)==NA)cycle
     !-find box of considering interpolation
respected to defined radius
     sx=((int(dist_x(i,j))-radi)/res)-res;     ex=((int(dist_x(i,j))+radi)/res)+res
     sy=((int(height(i,j))-radi)/res)-res;    ey=((int(height(i,j))+radi)/res)+res 
     !-here to avoid error outbound otherwise segmentation fault
     if (sx<=0) sx=1;    if (ex>nx) ex=nx;     if (sy<=0) sy=1;     if (ey>ny) ey=ny
     !-loop inside box for calculate weight, then apply it 
     do m=sx,ex
        do n=sy,ey
          !-convert coordinate considering grid to be same input
coordinates
           x=(m*res)-res+1;   y=(n*res)-res+1
  
           !-calculate euclidean distance
          
dist=sqrt(abs(x-dist_x(i,j))+abs(y-height(i,j)))
           !-cal inverse distance, normalize and sum all weighted
dbz
           inv_d=dist**p
           nw=inv_d/sum_invd(m,n)
           sum_nw(m,n)=sum_nw(m,n)+nw                    !-it must be 1.0 in every
grid
          
outp_intp(m,n)=outp_intp(m,n)+(nw*dbz(i,j))
         enddo
      enddo
  
  enddo
enddo
!-replace values for grads or NCL plot
where (outp_intp>max_dbz)
 
outp_intp=0
endwhere
End subroutine interpolate_idw
5.       
ตัวอย่างโค้ดของ NCL .ในการ Plot  ภาพ RHI โปรแกรมนี้มีอะไรน่าตื่นเต้นเยอะนะครับ
ช่วยในงานวิจัยได้ไม่น้อยเลยครับ 
;**********************************************************************
; color_1.ncl
; NATTAPON MAHAVIK
; Concepts illustrated:
;  
- Drawing color filled contours using the default color map
; how to read and write data from
f90 to ncl
;
https://www.ncl.ucar.edu/Document/Functions/Built-in/fbinread.shtml
;
;**********************************************************************
load
"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl"
load
"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl"  
;************************************************
begin
;************************************************
; read in binary
;************************************************
 
fili="rs_interpolated_RHI_radar_ncl.bin"
 
recl=200*15
 
;rad =
fbindirread("rs_interpolated_RHI_radar_ncl.bin",rec,(/15,200/),"float")
 
r=fbinread (fili, recl , "float")
 
rad=onedtond(r,(/15,200/))
 
rad@_FillValue = -9999 ;missing values
;************************************************
; create plot
;************************************************
 
wks = gsn_open_wks("ps","ps_RHI_radar_PHB")              ; open a ps file
 
gsn_define_colormap(wks,"prcp_1")        ; choose color map
 
res                      =
True               ; plot mods desired
 
res@vpWidthF         = 0.8                      ; set width and height
 
res@vpHeightF        = 0.5
 
res@cnFillOn             =
True               ; turn on color fill
 
res@gsnMaximize       = True
 
res@gsnDraw            =
False                        ; don't draw
yet
 
res@gsnFrame           =
False                        ; don't
advance frame yet
 
res@cnInfoLabelOn      =
False                     ; not show infomation height
 
res@cnLineLabelsOn     =
False                    ; not show label
of contour line
 
res@cnConstFLabelOn    = False
 
res@cnLineThicknessF   = 0            ; change line thickness
 
res@cnLinesOn   = False
 
res@tiMainString       =
"Range Height Indicator of Squallline in Thailand"
 
res@tiXAxisString      =
"Distance [km]"
 
res@tiYAxisString      =
"Height[km]"
 
 
res@cnLevelSelectionMode = "ManualLevels"      ; manually set the contour levels with
the following 3 resources
 
res@cnMinLevelValF     = 10.0                   ; set the minimum contour
level
 
res@cnMaxLevelValF     = 60.0                  ; set the maximum contour
level
 
res@cnLevelSpacingF    = 5.0                      ; contour interval
 
res@lbOrientation      =   "vertical"          ; vertical label bar
 
res@lbLabelStride      = 2.0
 
res@gsnSpreadColors=True
 
plot = gsn_csm_contour(wks,rad,res)
 
draw(plot)                                       ; note
we are drawing the first one!
 
frame(wks)
          end
     สิ่งที่ต้องทำต่อไปคือ แก้โปรแกรมให้ยืดหยุ่น ใช้กับข้อมูลหลายช่วงเวลา นำวิธีการประมาณค่าแบบอื่นๆมาใช้