forked from 3rdparty/wrf-python
commit
85fe02b556
63 changed files with 42916 additions and 0 deletions
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,293 @@
@@ -0,0 +1,293 @@
|
||||
;************************************************************************* |
||||
; Note: several of the functions/procedures are used |
||||
; to invoke old [ugly!] function names. |
||||
;************************************************************************* |
||||
; D. Shea |
||||
; |
||||
; convert WRF character variable "Times" to udunits |
||||
; 2001-06-11_12:00:00 |
||||
; |
||||
; convert WRF character variable "Times" to a coordinate variable "Time" |
||||
; opt can be "integer" or "string" |
||||
; . integer: opt = 0 : hours since initial time: Times(0,:) |
||||
; . opt = 1 : hours since 1901-01-01 00:00:00 |
||||
; . string: opt = 'any udunits compatible string' |
||||
; |
||||
undef ("WRF_Times2Udunits_c") |
||||
function WRF_Times2Udunits_c(Times:character, opt) |
||||
local dimT, rank, year, month, day, hour, minute, sec, units, time |
||||
begin |
||||
|
||||
dimT = dimsizes(Times) |
||||
rank = dimsizes(dimT) |
||||
if (rank.ne.2) then |
||||
print("===> WRF_contributed.ncl: WRF_Times2Udunits_c expects 2D array: rank="+rank) |
||||
exit |
||||
end if |
||||
|
||||
if (.not.(typeof(opt).eq."integer" .or. typeof(opt).eq."string")) then |
||||
print("===> WRF_contributed.ncl: opt must be integer or string: type="+typeof(opt)) |
||||
exit |
||||
end if |
||||
|
||||
year = stringtointeger((/Times(:, 0:3) /)) |
||||
month = stringtointeger((/Times(:, 5:6) /)) |
||||
day = stringtointeger((/Times(:, 8:9) /)) |
||||
hour = stringtointeger((/Times(:,11:12)/)) |
||||
minute = stringtointeger((/Times(:,14:15)/)) |
||||
sec = stringtointeger((/Times(:,17:18)/)) |
||||
|
||||
if (typeof(opt).eq."integer") then |
||||
if (opt.eq.0) then |
||||
units = "hours since "+year(0)+"-" \ |
||||
+sprinti("%0.2i",month(0)) +"-" \ |
||||
+sprinti("%0.2i",day(0)) +" " \ |
||||
+sprinti("%0.2i",hour(0)) +":" \ |
||||
+sprinti("%0.2i",minute(0))+":" \ |
||||
+sprinti("%0.2i",sec(0)) |
||||
else |
||||
units = "hours since 1901-01-01 00:00:00" |
||||
end if |
||||
else |
||||
units = opt ; opt is udunits compatible string |
||||
end if |
||||
|
||||
Time = ut_inv_calendar(year,month,day,hour,minute,sec, units, 0) |
||||
|
||||
Time!0 = "Time" |
||||
Time@long_name = "Time" |
||||
Time@description= "Time" |
||||
Time@units = units |
||||
Time&Time = Time ; make coordinate variable |
||||
return (Time) |
||||
end |
||||
;************************************************************************* |
||||
; D. Shea |
||||
; interface to WRF_Times2Udunits_c |
||||
undef ("WRF_Times_to_udunits") |
||||
function WRF_Times_to_udunits(Times:character, opt) |
||||
begin |
||||
return( WRF_Times2Udunits_c(Times, 0) ) ; old name |
||||
end |
||||
|
||||
;************************************************************************* |
||||
; D. Shea |
||||
; convert WRF character variable "Times" to |
||||
; a coordinate variable of type double |
||||
; time(double) = yyyymmddhhmnss |
||||
; 2001-06-11_12:00:00 ==> 20010611120000 |
||||
; |
||||
; opt: currently not used [dummy] |
||||
; |
||||
undef ("WRF_Times2double_c") |
||||
function WRF_Times2double_c(Times:character, opt) |
||||
local dimT, rank, N, time, i, tmp_c |
||||
begin |
||||
dimT = dimsizes(Times) |
||||
rank = dimsizes(dimT) |
||||
if (rank.ne.2) then |
||||
print("===> WRF_contributed.ncl: WRF_Times2Udunits_c expects 2D array: rank="+rank) |
||||
exit |
||||
end if |
||||
|
||||
N = dimT(0) |
||||
|
||||
Time = new( N ,"double") ; preset to "double" |
||||
delete(Time@_FillValue) ; coord variables should not have a _FillValue |
||||
|
||||
Time = stringtointeger((/Times(:,0:3)/)) *1d10 + \ ; yyyy |
||||
stringtointeger((/Times(:,5:6)/)) *1d8 + \ ; mm |
||||
stringtointeger((/Times(:,8:9)/)) *1d6 + \ ; dd |
||||
stringtointeger((/Times(:,11:12)/))*1d4 + \ ; hh |
||||
stringtointeger((/Times(:,14:15)/))*1d2 + \ ; mn |
||||
stringtointeger((/Times(:,17:18)/))*1d0 ; ss |
||||
|
||||
Time!0 = "Time" |
||||
Time@long_name = "Time" |
||||
Time@description= "Time" |
||||
Time@units = "yyyymmddhhmnss" |
||||
Time&Time = Time ; make coordinate variable |
||||
return (Time) |
||||
end |
||||
;************************************************************************* |
||||
; D. Shea |
||||
; interface to WRF_Times2double_c |
||||
; more explicit function name |
||||
undef ("WRF_Times_to_ymdhms") |
||||
function WRF_Times_to_ymdhms(Times:character, opt) |
||||
begin |
||||
return( WRF_Times2double_c(Times, 0) ) ; old name |
||||
end |
||||
|
||||
;************************************************************************* |
||||
; D. Shea |
||||
; convert WRF character variable "Times" to |
||||
; a coordinate variable of type integer |
||||
; time(integer)= yyyymmddhh [->ymdh] |
||||
; 2001-06-11_12:00:00 ==> 2001061112 |
||||
; |
||||
; Note: mminute and second are not part of the returned time |
||||
; |
||||
; opt: currently not used [dummy] |
||||
; |
||||
undef ("WRF_Times_to_ymdh") |
||||
function WRF_Times_to_ymdh(Times:character, opt) |
||||
local dimT, rank, N, time, i, tmp_c |
||||
begin |
||||
dimT = dimsizes(Times) |
||||
rank = dimsizes(dimT) |
||||
if (rank.ne.2) then |
||||
print("===> WRF_contributed.ncl: WRF_Times2yyyymmddhh expects 2D array: rank="+rank) |
||||
exit |
||||
end if |
||||
|
||||
N = dimT(0) |
||||
|
||||
Time = new( N ,"integer") |
||||
delete(Time@_FillValue) ; coord variables should not have a _FillValue |
||||
|
||||
Time = stringtointeger((/Times(:,0:3)/)) *1000000 + \ ; yyyy |
||||
stringtointeger((/Times(:,5:6)/)) *10000 + \ ; mm |
||||
stringtointeger((/Times(:,8:9)/)) *100 + \ ; dd |
||||
stringtointeger((/Times(:,11:12)/)) ; hh |
||||
|
||||
Time!0 = "Time" |
||||
Time@long_name = "Time" |
||||
Time@description= "Time" |
||||
Time@units = "yyyymmddhh" |
||||
Time&Time = Time ; make coordinate variable |
||||
return (Time) |
||||
end |
||||
|
||||
;************************************************************************* |
||||
; D. Shea |
||||
; This is a driver that selects the appropriate |
||||
; mapping function based upon the file attribute: MAP_PROJ |
||||
; MAP_PROJ=1 [Lambert Conformal]; =2 [Stereographic]; =3 [Mercator] |
||||
; |
||||
; opt: currently not used [potentail use: time counter for XLAT/XLONG] |
||||
; |
||||
; Sample usage: |
||||
; ncdf = addfile("...", r") |
||||
; res = True |
||||
; WRF_map_c (ncdf, res, 0) |
||||
; res = ... |
||||
; |
||||
undef("WRF_map_c") |
||||
procedure WRF_map_c (f:file, res:logical, opt) |
||||
local rank, dimll, nlat, mlon, lat2d, lon2d |
||||
begin |
||||
if (isatt(f,"MAP_PROJ")) then |
||||
if (f@MAP_PROJ.eq.1) then |
||||
res@mpProjection = "LambertConformal" |
||||
end if |
||||
if (f@MAP_PROJ.eq.2) then |
||||
res@mpProjection = "Stereographic" |
||||
end if |
||||
if (f@MAP_PROJ.eq.3) then |
||||
res@mpProjection = "Mercator" |
||||
end if |
||||
else |
||||
print ("WRF_mapProj: no MAP_PROJ attribute") |
||||
end if |
||||
|
||||
rank = dimsizes(filevardimsizes(f,"XLAT")) ; # of dimensions |
||||
if (rank.eq.3) then |
||||
lat2d = f->XLAT(0,:,:) ; opt could bt "nt" f->XLAT(opt,:,:) |
||||
lon2d = f->XLONG(0,:,:) |
||||
else |
||||
if (rank.eq.2) then |
||||
lat2d = f->XLAT |
||||
lon2d = f->XLONG |
||||
else |
||||
print ("WRF_resLamCon_c: unexpected lat/lon rank: rank="+rank) |
||||
exit |
||||
end if |
||||
end if |
||||
|
||||
lat2d@units = "degrees_north" ; not needed |
||||
lon2d@units = "degrees_east" |
||||
|
||||
dimll = dimsizes(lat2d) |
||||
nlat = dimll(0) |
||||
mlon = dimll(1) |
||||
|
||||
res@mpLimitMode = "Corners" |
||||
res@mpLeftCornerLatF = lat2d(0,0) |
||||
res@mpLeftCornerLonF = lon2d(0,0) |
||||
res@mpRightCornerLatF = lat2d(nlat-1,mlon-1) |
||||
res@mpRightCornerLonF = lon2d(nlat-1,mlon-1) |
||||
|
||||
res@mpCenterLonF = f@CEN_LON |
||||
res@mpCenterLatF = f@CEN_LAT ; default |
||||
|
||||
if (res@mpProjection.eq."Mercator") then |
||||
res@mpCenterLatF = 0.0 ; Cindy Bruyere MMM/WRF 24 Mar 2006 |
||||
end if |
||||
|
||||
if (res@mpProjection.eq."LambertConformal") then |
||||
res@mpLambertParallel1F = f@TRUELAT1 |
||||
res@mpLambertParallel2F = f@TRUELAT2 |
||||
if (isatt(f, "STAND_LON") ) then |
||||
res@mpLambertMeridianF = f@STAND_LON ; use if present |
||||
; CB MMM/WRF 4 Aug 2006 |
||||
else |
||||
if (isatt(f, "CEN_LON") ) then |
||||
res@mpLambertMeridianF = f@CEN_LON |
||||
else |
||||
print("WRF_map_c: STAND_LON and CEN_LON missing") |
||||
end if |
||||
end if |
||||
end if |
||||
|
||||
res@mpFillOn = False ; turn off map fill |
||||
res@mpOutlineDrawOrder = "PostDraw" ; draw continental outline last |
||||
res@mpOutlineBoundarySets = "GeophysicalAndUSStates" ; state boundaries |
||||
res@mpPerimDrawOrder = "PostDraw" ; force map perim |
||||
; commented 5/17/2007 |
||||
;;res@tfDoNDCOverlay = True ; True for 'native' grid |
||||
; some WRF are not native |
||||
res@gsnAddCyclic = False ; data are not cyclic |
||||
end |
||||
|
||||
;************************************************************************* |
||||
; D. Shea |
||||
; interface for backward compatibility |
||||
undef("WRF_resLamCon_c") |
||||
procedure WRF_resLamCon_c (f:file, res:logical, opt) |
||||
begin |
||||
WRF_map_c (f, res, opt) |
||||
end |
||||
|
||||
;************************************************************************* |
||||
; D. Shea |
||||
; interface for newly named procedure |
||||
undef("wrf_mapres_c") |
||||
procedure wrf_mapres_c(f:file, res:logical, opt) |
||||
begin |
||||
WRF_map_c (f, res, opt) |
||||
end |
||||
;************************************************************************* |
||||
; D. Shea |
||||
; single interface to convert WRF character variable "Times" |
||||
; to user specified numeric values |
||||
; |
||||
; M. Haley |
||||
; At some point we decided to rename this from WRF_Times to wrf_times_c |
||||
; Also added error check for opt. |
||||
; |
||||
undef ("wrf_times_c") |
||||
function wrf_times_c(Times:character, opt:integer) |
||||
begin |
||||
if (opt.ge.0 .and. opt.le.1) then |
||||
return(WRF_Times2Udunits_c(Times, opt) ) |
||||
end if |
||||
|
||||
if (opt.eq.2) then |
||||
return(WRF_Times2double_c(Times, opt) ) |
||||
end if |
||||
|
||||
if (opt.eq.3) then |
||||
return(WRF_Times_to_ymdh(Times, opt) ) |
||||
end if |
||||
end |
@ -0,0 +1,158 @@
@@ -0,0 +1,158 @@
|
||||
! For NCL graphics: |
||||
! WRAPIT -m64 calc_uh90.stub calc_uh.f90 |
||||
! This should create a shared library named "calc_uh90.so". |
||||
|
||||
!################################################################## |
||||
!################################################################## |
||||
!###### ###### |
||||
!###### SUBROUTINE CALC_UH ###### |
||||
!###### ###### |
||||
!###### Developed by ###### |
||||
!###### Center for Analysis and Prediction of Storms ###### |
||||
!###### University of Oklahoma ###### |
||||
!###### ###### |
||||
!################################################################## |
||||
!################################################################## |
||||
! |
||||
! Calculates updraft helicity (UH) to detect rotating updrafts. |
||||
! Formula follows Kain et al, 2008, Wea. and Forecasting, 931-952, |
||||
! but this version has controls for the limits of integration |
||||
! uhminhgt to uhmxhgt, in m AGL. Kain et al used 2000 to 5000 m. |
||||
! Units of UH are m^2/s^2. |
||||
! |
||||
! Note here that us and vs are at ARPS scalar points. |
||||
! w is at w-point (scalar pt in horiz, staggered vertical) |
||||
! |
||||
! Keith Brewster, CAPS/Univ. of Oklahoma |
||||
! March, 2010 |
||||
! |
||||
! uh = wrf_updraft_helicity(zp,us,vs,w, |
||||
SUBROUTINE dcalcuh(nx,ny,nz,nzp1,zp,mapfct,dx,dy,uhmnhgt,uhmxhgt, & |
||||
us,vs,w,uh,tem1,tem2) |
||||
IMPLICIT NONE |
||||
INTEGER, INTENT(IN) :: nx,ny,nz,nzp1 |
||||
DOUBLE PRECISION, INTENT(IN) :: zp(nx,ny,nzp1) |
||||
DOUBLE PRECISION, INTENT(IN) :: mapfct(nx,ny) |
||||
DOUBLE PRECISION, INTENT(IN) :: dx,dy |
||||
DOUBLE PRECISION, INTENT(IN) :: uhmnhgt,uhmxhgt |
||||
DOUBLE PRECISION, INTENT(IN) :: us(nx,ny,nz) |
||||
DOUBLE PRECISION, INTENT(IN) :: vs(nx,ny,nz) |
||||
DOUBLE PRECISION, INTENT(IN) :: w(nx,ny,nzp1) |
||||
DOUBLE PRECISION, INTENT(OUT) :: uh(nx,ny) |
||||
DOUBLE PRECISION, INTENT(OUT) :: tem1(nx,ny,nz) |
||||
DOUBLE PRECISION, INTENT(OUT) :: tem2(nx,ny,nz) |
||||
! |
||||
! Misc local variables |
||||
! |
||||
INTEGER :: i,j,k,kbot,ktop |
||||
DOUBLE PRECISION :: twodx,twody,wgtlw,sum,wmean,wsum,wavg |
||||
DOUBLE PRECISION :: helbot,heltop,wbot,wtop |
||||
DOUBLE PRECISION :: zbot,ztop |
||||
! |
||||
! Initialize arrays |
||||
! |
||||
uh=0.0 |
||||
tem1=0.0 |
||||
! |
||||
! Calculate vertical component of helicity at scalar points |
||||
! us: u at scalar points |
||||
! vs: v at scalar points |
||||
! |
||||
twodx=2.0*dx |
||||
twody=2.0*dy |
||||
DO k=2,nz-2 |
||||
DO j=2,ny-1 |
||||
DO i=2,nx-1 |
||||
wavg=0.5*(w(i,j,k)+w(i,j,k+1)) |
||||
tem1(i,j,k)=wavg * & |
||||
((vs(i+1,j,k)-vs(i-1,j,k))/(twodx*mapfct(i,j)) - & |
||||
(us(i,j+1,k)-us(i,j-1,k))/(twody*mapfct(i,j))) |
||||
tem2(i,j,k)=0.5*(zp(i,j,k)+zp(i,j,k+1)) |
||||
END DO |
||||
END DO |
||||
END DO |
||||
! |
||||
! Integrate over depth uhminhgt to uhmxhgt AGL |
||||
! |
||||
! WRITE(6,'(a,f12.1,a,f12.1,a)') & |
||||
! 'Calculating UH from ',uhmnhgt,' to ',uhmxhgt,' m AGL' |
||||
DO j=2,ny-2 |
||||
DO i=2,nx-2 |
||||
zbot=zp(i,j,2)+uhmnhgt |
||||
ztop=zp(i,j,2)+uhmxhgt |
||||
! |
||||
! Find wbar, weighted-mean vertical velocity in column |
||||
! Find w at uhmnhgt AGL (bottom) |
||||
! |
||||
DO k=2,nz-3 |
||||
IF(zp(i,j,k) > zbot) EXIT |
||||
END DO |
||||
kbot=k |
||||
wgtlw=(zp(i,j,kbot)-zbot)/(zp(i,j,kbot)-zp(i,j,kbot-1)) |
||||
wbot=(wgtlw*w(i,j,kbot-1))+((1.-wgtlw)*w(i,j,kbot)) |
||||
! |
||||
! Find w at uhmxhgt AGL (top) |
||||
! |
||||
DO k=2,nz-3 |
||||
IF(zp(i,j,k) > ztop) EXIT |
||||
END DO |
||||
ktop=k |
||||
wgtlw=(zp(i,j,ktop)-ztop)/(zp(i,j,ktop)-zp(i,j,ktop-1)) |
||||
wtop=(wgtlw*w(i,j,ktop-1))+((1.-wgtlw)*w(i,j,ktop)) |
||||
! |
||||
! First part, uhmnhgt to kbot |
||||
! |
||||
wsum=0.5*(w(i,j,kbot)+wbot)*(zp(i,j,kbot)-zbot) |
||||
! |
||||
! Integrate up through column |
||||
! |
||||
DO k=(kbot+1),(ktop-1) |
||||
wsum=wsum+0.5*(w(i,j,k)+w(i,j,k-1))*(zp(i,j,k)-zp(i,j,k-1)) |
||||
END DO |
||||
! |
||||
! Last part, ktop-1 to uhmxhgt |
||||
! |
||||
wsum=wsum+0.5*(wtop+w(i,j,ktop-1))*(ztop-zp(i,j,ktop-1)) |
||||
wmean=wsum/(uhmxhgt-uhmnhgt) |
||||
|
||||
IF(wmean > 0.) THEN ! column updraft, not downdraft |
||||
! |
||||
! Find helicity at uhmnhgt AGL (bottom) |
||||
! |
||||
DO k=2,nz-3 |
||||
IF(tem2(i,j,k) > zbot) EXIT |
||||
END DO |
||||
kbot=k |
||||
wgtlw=(tem2(i,j,kbot)-zbot)/(tem2(i,j,kbot)-tem2(i,j,kbot-1)) |
||||
helbot=(wgtlw*tem1(i,j,kbot-1))+((1.-wgtlw)*tem1(i,j,kbot)) |
||||
! |
||||
! Find helicity at uhmxhgt AGL (top) |
||||
! |
||||
DO k=2,nz-3 |
||||
IF(tem2(i,j,k) > ztop) EXIT |
||||
END DO |
||||
ktop=k |
||||
wgtlw=(tem2(i,j,ktop)-ztop)/(tem2(i,j,ktop)-tem2(i,j,ktop-1)) |
||||
heltop=(wgtlw*tem1(i,j,ktop-1))+((1.-wgtlw)*tem1(i,j,ktop)) |
||||
! |
||||
! First part, uhmnhgt to kbot |
||||
! |
||||
sum=0.5*(tem1(i,j,kbot)+helbot)*(tem2(i,j,kbot)-zbot) |
||||
! |
||||
! Integrate up through column |
||||
! |
||||
DO k=(kbot+1),(ktop-1) |
||||
sum=sum+0.5*(tem1(i,j,k)+tem1(i,j,k-1))*(tem2(i,j,k)-tem2(i,j,k-1)) |
||||
END DO |
||||
! |
||||
! Last part, ktop-1 to uhmxhgt |
||||
! |
||||
uh(i,j)=sum+0.5*(heltop+tem1(i,j,ktop-1))*(ztop-tem2(i,j,ktop-1)) |
||||
END IF |
||||
END DO |
||||
END DO |
||||
|
||||
uh = uh * 1000. ! Scale according to Kain et al. (2008) |
||||
|
||||
RETURN |
||||
END SUBROUTINE dcalcuh |
@ -0,0 +1,72 @@
@@ -0,0 +1,72 @@
|
||||
SUBROUTINE DEQTHECALC(QVP,TMK,PRS,ETH,MIY,MJX,MKZH) |
||||
DOUBLE PRECISION EPS |
||||
DOUBLE PRECISION RGAS |
||||
DOUBLE PRECISION RGASMD |
||||
DOUBLE PRECISION CP |
||||
DOUBLE PRECISION CPMD |
||||
DOUBLE PRECISION GAMMA |
||||
DOUBLE PRECISION GAMMAMD |
||||
DOUBLE PRECISION TLCLC1 |
||||
DOUBLE PRECISION TLCLC2 |
||||
DOUBLE PRECISION TLCLC3 |
||||
DOUBLE PRECISION TLCLC4 |
||||
DOUBLE PRECISION THTECON1 |
||||
DOUBLE PRECISION THTECON2 |
||||
DOUBLE PRECISION THTECON3 |
||||
DOUBLE PRECISION Q |
||||
DOUBLE PRECISION T |
||||
DOUBLE PRECISION P |
||||
DOUBLE PRECISION E |
||||
DOUBLE PRECISION TLCL |
||||
c |
||||
c Input variables |
||||
c Qvapor [g/kg] |
||||
DOUBLE PRECISION QVP(MIY,MJX,MKZH) |
||||
c Temperature [K] |
||||
DOUBLE PRECISION TMK(MIY,MJX,MKZH) |
||||
c full pressure (=P+PB) [hPa] |
||||
DOUBLE PRECISION PRS(MIY,MJX,MKZH) |
||||
c |
||||
c Output variable |
||||
c equivalent potential temperature [K] |
||||
DOUBLE PRECISION ETH(MIY,MJX,MKZH) |
||||
c |
||||
c parameters |
||||
PARAMETER (EPS=0.622D0) |
||||
|
||||
c J/K/kg |
||||
RGAS = 287.04D0 |
||||
c rgas_moist=rgas*(1.+rgasmd*qvp) |
||||
RGASMD = .608D0 |
||||
c J/K/kg Note: not using Bolton's value of 1005.7 |
||||
CP = 1004.D0 |
||||
c cp_moist=cp*(1.+cpmd*qvp) |
||||
CPMD = .887D0 |
||||
GAMMA = RGAS/CP |
||||
c gamma_moist=gamma*(1.+gammamd*qvp) |
||||
GAMMAMD = RGASMD - CPMD |
||||
|
||||
TLCLC1 = 2840.D0 |
||||
TLCLC2 = 3.5D0 |
||||
TLCLC3 = 4.805D0 |
||||
TLCLC4 = 55.D0 |
||||
c K |
||||
THTECON1 = 3376.D0 |
||||
THTECON2 = 2.54D0 |
||||
THTECON3 = .81D0 |
||||
c |
||||
DO 1000 K = 1,MKZH |
||||
DO 1000 J = 1,MJX |
||||
DO 1000 I = 1,MIY |
||||
Q = MAX(QVP(I,J,K),1.D-15) |
||||
T = TMK(I,J,K) |
||||
P = PRS(I,J,K)/100. |
||||
E = Q*P/ (EPS+Q) |
||||
TLCL = TLCLC1/ (LOG(T**TLCLC2/E)-TLCLC3) + TLCLC4 |
||||
ETH(I,J,K) = T* (1000.D0/P)** |
||||
+ (GAMMA* (1.D0+GAMMAMD*Q))* |
||||
+ EXP((THTECON1/TLCL-THTECON2)*Q* |
||||
+ (1.D0+THTECON3*Q)) |
||||
1000 CONTINUE |
||||
RETURN |
||||
END |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,215 @@
@@ -0,0 +1,215 @@
|
||||
c ----------------------------------------------------------- |
||||
C NCLFORTSTART |
||||
SUBROUTINE DRCM2POINTS(NGRD,NYI,NXI,YI,XI,FI,NXYO,YO,XO,FO |
||||
+ ,XMSG,OPT,NCRIT,KVAL,IER) |
||||
IMPLICIT NONE |
||||
INTEGER NGRD,NXI,NYI,NXYO,OPT,NCRIT,KVAL,IER |
||||
DOUBLE PRECISION XI(NXI,NYI),YI(NXI,NYI),FI(NXI,NYI,NGRD) |
||||
DOUBLE PRECISION XO(NXYO),YO(NXYO),FO(NXYO,NGRD),XMSG |
||||
C NCLEND |
||||
|
||||
C This is written with GNU f77 acceptable extensions |
||||
c . This could be improved considerably with f90 |
||||
|
||||
c nomenclature: |
||||
c . nxi,nyi - lengths of xi,yi and dimensions of fi (must be >= 2) |
||||
c . xi - coordinates of fi (eg, lon [2D] ) |
||||
c . yi - coordinates of fi (eg, lat [2D] ) |
||||
c . fi - functional input values [2D] |
||||
c . nxyo - number of output points |
||||
c . xo - lon coordinates of fo (eg, lon [1D]) |
||||
c . yo - lat coordinates of fo (eg, lat [1D]) |
||||
c . fo - functional output values [interpolated] |
||||
c . xmsg - missing code |
||||
c . opt - 0/1 = inv distance, 2 = bilinear |
||||
c . ier - error code |
||||
c . =0; no error |
||||
c . =1; not enough points in input/output array |
||||
c . =2/3; xi or yi are not monotonically increasing |
||||
c . =4/5; xo or yo are not monotonically increasing |
||||
c |
||||
c local |
||||
INTEGER NG,NX,NY,NXY,NEXACT,IX,IY,M,N,NW,NER,K |
||||
DOUBLE PRECISION FW(2,2),W(2,2),SUMF,SUMW,CHKLAT(NYI),CHKLON(NXI) |
||||
DOUBLE PRECISION DGCDIST, WX, WY |
||||
DOUBLE PRECISION REARTH, DLAT, PI, RAD, DKM, DIST |
||||
c error checking |
||||
IER = 0 |
||||
IF (NXI.LE.1 .OR. NYI.LE.1 .OR. NXYO.LE.0) THEN |
||||
IER = 1 |
||||
RETURN |
||||
END IF |
||||
IF (IER.NE.0) RETURN |
||||
|
||||
DO NY = 1,NYI |
||||
CHKLAT(NY) = YI(1,NY) |
||||
c c c print *,"chklat: ny=",ny," chklat=",chklat(ny) |
||||
END DO |
||||
CALL DMONOINC(CHKLAT,NYI,IER,NER) |
||||
IF (IER.NE.0) RETURN |
||||
|
||||
DO NX = 1,NXI |
||||
CHKLON(NX) = XI(NX,1) |
||||
c c c print *,"chklon: nx=",nx," chklon=",chklon(nx) |
||||
END DO |
||||
CALL DMONOINC(CHKLAT,NYI,IER,NER) |
||||
IF (IER.NE.0) RETURN |
||||
|
||||
C ORIGINAL (k = op, never implemented) |
||||
IF (KVAL.LE.0) THEN |
||||
K = 1 |
||||
ELSE |
||||
K = KVAL |
||||
END IF |
||||
DO NG = 1,NGRD |
||||
DO NXY = 1,NXYO |
||||
FO(NXY,NG) = XMSG |
||||
END DO |
||||
END DO |
||||
c main loop [exact matches] |
||||
NEXACT = 0 |
||||
DO NXY = 1,NXYO |
||||
|
||||
DO IY = 1,NYI |
||||
DO IX = 1,NXI |
||||
IF (XO(NXY).EQ.XI(IX,IY) .AND. |
||||
+ YO(NXY).EQ.YI(IX,IY)) THEN |
||||
DO NG = 1,NGRD |
||||
FO(NXY,NG) = FI(IX,IY,NG) |
||||
NEXACT = NEXACT + 1 |
||||
END DO |
||||
GO TO 10 |
||||
END IF |
||||
END DO |
||||
END DO |
||||
|
||||
10 CONTINUE |
||||
END DO |
||||
|
||||
c c c print *, "nexact=",nexact |
||||
c main loop [interpolation] |
||||
DO NXY = 1,NXYO |
||||
|
||||
DO IY = 1,NYI - K |
||||
DO IX = 1,NXI - K |
||||
IF (XO(NXY).GE.XI(IX,IY) .AND. |
||||
+ XO(NXY).LE.XI(IX+K,IY) .AND. |
||||
+ YO(NXY).GE.YI(IX,IY) .AND. |
||||
+ YO(NXY).LE.YI(IX,IY+K)) THEN |
||||
|
||||
IF (ABS(OPT).EQ.2) THEN |
||||
WX = (XO(NXY)-XI(IX,IY))/ |
||||
+ (XI(IX+K,IY)-XI(IX,IY)) |
||||
WY = (YO(NXY)-YI(IX,IY))/ |
||||
+ (YI(IX,IY+K)-YI(IX,IY)) |
||||
W(1,1) = (1.D0-WX)*(1.D0-WY) |
||||
W(2,1) = WX*(1.D0-WY) |
||||
W(1,2) = (1.D0-WX)*WY |
||||
W(2,2) = WX*WY |
||||
ELSE |
||||
W(1,1) = (1.D0/DGCDIST(YO(NXY),XO(NXY), |
||||
+ YI(IX,IY),XI(IX,IY),2))**2 |
||||
W(2,1) = (1.D0/DGCDIST(YO(NXY),XO(NXY), |
||||
+ YI(IX+K,IY),XI(IX+K,IY),2))**2 |
||||
W(1,2) = (1.D0/DGCDIST(YO(NXY),XO(NXY), |
||||
+ YI(IX,IY+K),XI(IX,IY+K),2))**2 |
||||
W(2,2) = (1.D0/DGCDIST(YO(NXY),XO(NXY), |
||||
+ YI(IX+K,IY+K),XI(IX+K,IY+K),2))**2 |
||||
END IF |
||||
|
||||
DO NG = 1,NGRD |
||||
IF (FO(NXY,NG).EQ.XMSG) THEN |
||||
|
||||
FW(1,1) = FI(IX,IY,NG) |
||||
FW(2,1) = FI(IX+K,IY,NG) |
||||
FW(1,2) = FI(IX,IY+K,NG) |
||||
FW(2,2) = FI(IX+K,IY+K,NG) |
||||
|
||||
NW = 0 |
||||
SUMF = 0.0D0 |
||||
SUMW = 0.0D0 |
||||
DO N = 1,2 |
||||
DO M = 1,2 |
||||
IF (FW(M,N).NE.XMSG) THEN |
||||
SUMF = SUMF + FW(M,N)*W(M,N) |
||||
SUMW = SUMW + W(M,N) |
||||
NW = NW + 1 |
||||
END IF |
||||
END DO |
||||
END DO |
||||
c nw >=3 arbitrary |
||||
IF (NW.GE.NCRIT .AND. SUMW.GT.0.D0) THEN |
||||
FO(NXY,NG) = SUMF/SUMW |
||||
END IF |
||||
END IF |
||||
END DO |
||||
GO TO 20 |
||||
END IF |
||||
END DO |
||||
END DO |
||||
|
||||
20 CONTINUE |
||||
END DO |
||||
|
||||
C Are all the output points filled in? Check the 1st grid |
||||
C If so, return |
||||
|
||||
DO NG = 1,NGRD |
||||
DO NXY = 1,NXYO |
||||
IF (FO(NXY,NG).EQ.XMSG) GO TO 30 |
||||
END DO |
||||
END DO |
||||
RETURN |
||||
|
||||
C only enter if some points are not interpolated to |
||||
C DLAT is arbitrary. It ould be made an option. |
||||
C DLAT is expressed in terms of degrees of latitude. |
||||
C DKM is DLAT in KILOMETERS |
||||
|
||||
30 REARTH= 6371D0 |
||||
DLAT = 5 |
||||
PI = 4D0*ATAN(1.0D0) |
||||
RAD = PI/180D0 |
||||
DKM = DLAT*(2D0*PI*REARTH)/360D0 |
||||
|
||||
C LOOP OVER EACH GRID ... INEFFICIENT |
||||
C THE RUB IS THAT SOME LEVELS COULD HAVE XMSG. |
||||
|
||||
DO NG = 1,NGRD |
||||
|
||||
DO NXY = 1,NXYO |
||||
IF(FO(NXY,NG).EQ.XMSG) THEN |
||||
|
||||
C FIND ALL GRID POINTS WITHIN 'DKM' KILOMETERS OF PT |
||||
|
||||
NW = 0 |
||||
SUMF = 0.0D0 |
||||
SUMW = 0.0D0 |
||||
|
||||
DO IY = 1,NYI |
||||
DO IX = 1,NXI |
||||
IF ((YI(IX,IY).GE.YO(NXY)-DLAT) .AND. |
||||
+ (YI(IX,IY).LE.YO(NXY)+DLAT)) THEN |
||||
DIST = DGCDIST(YO(NXY),XO(NXY) |
||||
+ ,YI(IX,IY),XI(IX,IY),2) |
||||
IF (DIST.LE.DKM .AND. DIST.GT.0.0D0 .AND. |
||||
+ FI(IX,IY,NG).NE.XMSG) THEN |
||||
DIST = 1.0D0/DIST**2 |
||||
SUMF = SUMF + FI(IX,IY,NG)*DIST |
||||
SUMW = SUMW + DIST |
||||
NW = NW + 1 |
||||
END IF |
||||
END IF |
||||
END DO |
||||
END DO |
||||
|
||||
C C C IF (NW.GE.NCRIT .AND. SUMW.GT. 0.0D0) THEN |
||||
IF (SUMW.GT.0.0D0) THEN |
||||
FO(NXY,NG) = SUMF/SUMW |
||||
END IF |
||||
END IF |
||||
END DO |
||||
END DO |
||||
|
||||
RETURN |
||||
END |
@ -0,0 +1,376 @@
@@ -0,0 +1,376 @@
|
||||
C NCLFORTSTART |
||||
SUBROUTINE DRCM2RGRID(NGRD,NYI,NXI,YI,XI,FI,NYO,YO,NXO,XO,FO |
||||
+ ,XMSG,NCRIT,OPT,IER) |
||||
IMPLICIT NONE |
||||
INTEGER NGRD,NXI,NYI,NXO,NYO,NCRIT,OPT,IER |
||||
DOUBLE PRECISION XI(NXI,NYI),YI(NXI,NYI),FI(NXI,NYI,NGRD) |
||||
DOUBLE PRECISION XO(NXO),YO(NYO),FO(NXO,NYO,NGRD),XMSG |
||||
C NCLEND |
||||
|
||||
C This is written with GNU f77 acceptable extensions |
||||
c . This could be improved considerably with f90 |
||||
|
||||
c NCL: fo = rcm2rgrid (lat2d,lon2d,fi, lat, lon iopt) |
||||
c yi xi fi yo xo |
||||
c |
||||
c fo is the same size xo, yo and same type as "fi" |
||||
c xmsg = fi@_FillValue |
||||
c opt unused option |
||||
c |
||||
c The NCL wrapper should allow for multiple datasets |
||||
c so the user need only make one call to the function. |
||||
|
||||
c perform 2D interpolation allowing for missing data: nothing fancy |
||||
|
||||
c nomenclature: |
||||
c . nxi,nyi - lengths of xi,yi and dimensions of fi (must be >= 2) |
||||
c . xi - coordinates of fi (eg, lon [2D] ) |
||||
c . yi - coordinates of fi (eg, lat [2D] ) |
||||
c . fi - functional input values [2D] |
||||
c . nxo,nyo - lengths of xo,yo and dimensions of fo (must be >= 1) |
||||
c . xo - coordinates of fo (eg, lon [1D]) |
||||
c . must be monotonically increasing |
||||
c . yo - coordinates of fo (eg, lat [1D]) |
||||
c . must be monotonically increasing |
||||
c . fo - functional output values [interpolated] |
||||
c . xmsg - missing code |
||||
c . opt - unused |
||||
c . ier - error code |
||||
c . =0; no error |
||||
c . =1; not enough points in input/output array |
||||
c . =2/3; xi or yi are not monotonically increasing |
||||
c . =4/5; xo or yo are not monotonically increasing |
||||
c |
||||
c local |
||||
INTEGER NG, NX,NY,NEXACT,IX,IY,M,N,NW,NER,K,NCRT |
||||
INTEGER MFLAG, MPTCRT, MKNT |
||||
DOUBLE PRECISION FW(2,2),W(2,2),SUMF,SUMW,CHKLAT(NYI),CHKLON(NXI) |
||||
DOUBLE PRECISION EPS |
||||
DOUBLE PRECISION DGCDIST |
||||
c error checking |
||||
IER = 0 |
||||
IF (NXI.LE.1 .OR. NYI.LE.1 .OR. NXO.LE.1 .OR. NYO.LE.1) THEN |
||||
IER = 1 |
||||
RETURN |
||||
END IF |
||||
IF (IER.NE.0) RETURN |
||||
|
||||
CALL DMONOINC(YO,NYO,IER,NER) |
||||
IF (IER.NE.0) RETURN |
||||
CALL DMONOINC(XO,NXO,IER,NER) |
||||
IF (IER.NE.0) RETURN |
||||
|
||||
DO NY = 1,NYI |
||||
CHKLAT(NY) = YI(1,NY) |
||||
c c c print *,"chklat: ny=",ny," chklat=",chklat(ny) |
||||
END DO |
||||
CALL DMONOINC(CHKLAT,NYI,IER,NER) |
||||
IF (IER.NE.0) RETURN |
||||
|
||||
DO NX = 1,NXI |
||||
CHKLON(NX) = XI(NX,1) |
||||
c c c print *,"chklon: nx=",nx," chklon=",chklon(nx) |
||||
END DO |
||||
CALL DMONOINC(CHKLAT,NYI,IER,NER) |
||||
IF (IER.NE.0) RETURN |
||||
|
||||
K = 2 |
||||
c c c k = opt |
||||
|
||||
IF (NCRIT.LE.1) THEN |
||||
NCRT = 1 |
||||
ELSE |
||||
NCRT = MIN(4,NCRIT) |
||||
END IF |
||||
c initialize to xmsg |
||||
DO NG=1,NGRD |
||||
DO NY = 1,NYO |
||||
DO NX = 1,NXO |
||||
FO(NX,NY,NG) = XMSG |
||||
END DO |
||||
END DO |
||||
END DO |
||||
c main loop [exact matches] |
||||
c people want bit-for-bit match |
||||
EPS = 1.D-04 |
||||
NEXACT = 0 |
||||
|
||||
DO NY = 1,NYO |
||||
DO NX = 1,NXO |
||||
DO IY = 1,NYI |
||||
DO IX = 1,NXI |
||||
IF (XO(NX).GE.(XI(IX,IY)-EPS) .AND. |
||||
+ XO(NX).LE.(XI(IX,IY)+EPS) .AND. |
||||
+ YO(NY).GE.(YI(IX,IY)-EPS) .AND. |
||||
+ YO(NY).LE.(YI(IX,IY)+EPS) ) THEN |
||||
|
||||
DO NG=1,NGRD |
||||
FO(NX,NY,NG) = FI(IX,IY,NG) |
||||
NEXACT = NEXACT + 1 |
||||
END DO |
||||
GO TO 10 |
||||
END IF |
||||
END DO |
||||
END DO |
||||
|
||||
10 CONTINUE |
||||
END DO |
||||
END DO |
||||
|
||||
c c c print *, "nexact=",nexact |
||||
c main loop [interpolation] |
||||
DO NY = 1,NYO |
||||
DO NX = 1,NXO |
||||
|
||||
DO IY = 1,NYI-K |
||||
DO IX = 1,NXI-K |
||||
IF (XO(NX).GE.XI(IX,IY) .AND. |
||||
+ XO(NX).LE.XI(IX+K,IY) .AND. |
||||
+ YO(NY).GE.YI(IX,IY) .AND. |
||||
+ YO(NY).LE.YI(IX,IY+K)) THEN |
||||
|
||||
|
||||
W(1,1) = (1.D0/DGCDIST(YO(NY),XO(NX), |
||||
+ YI(IX,IY),XI(IX,IY),2))**2 |
||||
W(2,1) = (1.D0/DGCDIST(YO(NY),XO(NX), |
||||
+ YI(IX+K,IY),XI(IX+K,IY),2))**2 |
||||
W(1,2) = (1.D0/DGCDIST(YO(NY),XO(NX), |
||||
+ YI(IX,IY+K),XI(IX,IY+K),2))**2 |
||||
W(2,2) = (1.D0/DGCDIST(YO(NY),XO(NX), |
||||
+ YI(IX+K,IY+K),XI(IX+K,IY+K),2))**2 |
||||
DO NG=1,NGRD |
||||
IF (FO(NX,NY,NG).EQ.XMSG) THEN |
||||
FW(1,1) = FI(IX,IY,NG) |
||||
FW(2,1) = FI(IX+K,IY,NG) |
||||
FW(1,2) = FI(IX,IY+K,NG) |
||||
FW(2,2) = FI(IX+K,IY+K,NG) |
||||
|
||||
NW = 0 |
||||
SUMF = 0.0D0 |
||||
SUMW = 0.0D0 |
||||
DO N = 1,2 |
||||
DO M = 1,2 |
||||
IF (FW(M,N).NE.XMSG) THEN |
||||
SUMF = SUMF + FW(M,N)*W(M,N) |
||||
SUMW = SUMW + W(M,N) |
||||
NW = NW + 1 |
||||
END IF |
||||
END DO |
||||
END DO |
||||
c nw >=3 arbitrary |
||||
c c c IF (NW.GE.3 .AND. SUMW.GT.0.D0) THEN |
||||
c nw =1 nearest neighbor |
||||
IF (NW.GE.NCRT .AND. SUMW.GT.0.D0) THEN |
||||
FO(NX,NY,NG) = SUMF/SUMW |
||||
END IF |
||||
END IF |
||||
END DO |
||||
GO TO 20 |
||||
END IF |
||||
END DO |
||||
END DO |
||||
20 CONTINUE |
||||
END DO |
||||
END DO |
||||
|
||||
C Since the RCM grid is curvilinear the above algorithm may not work |
||||
C . for all of the locations on regular grid. Fill via linear interp. |
||||
|
||||
MKNT = 0 |
||||
MFLAG = 0 |
||||
MPTCRT = 2 |
||||
DO NG=1,NGRD |
||||
DO NY=1,NYO |
||||
DO NX=1,NXO |
||||
IF (FO(NX,NY,NG).EQ.XMSG) THEN |
||||
CALL DLINMSG(FO(1,NY,NG),NXO,XMSG,MFLAG,MPTCRT) |
||||
MKNT = MKNT + 1 |
||||
END IF |
||||
END DO |
||||
END DO |
||||
END DO |
||||
|
||||
C C C PRINT *,"MKNT=",MKNT |
||||
|
||||
RETURN |
||||
END |
||||
c ----------------------------------------------------------- |
||||
C NCLFORTSTART |
||||
SUBROUTINE DRGRID2RCM(NGRD,NYI,NXI,YI,XI,FI,NYO,NXO,YO,XO,FO |
||||
+ ,XMSG,NCRIT,OPT,IER) |
||||
IMPLICIT NONE |
||||
INTEGER NGRD,NXI,NYI,NXO,NYO,OPT,NCRIT,IER |
||||
DOUBLE PRECISION XI(NXI),YI(NYI),FI(NXI,NYI,NGRD) |
||||
DOUBLE PRECISION XO(NXO,NYO),YO(NXO,NYO),FO(NXO,NYO,NGRD),XMSG |
||||
C NCLEND |
||||
|
||||
C This is written with GNU f77 acceptable extensions |
||||
c . This could be improved considerably with f90 |
||||
|
||||
c fo is the same size xo, yo and same type as "fi" |
||||
c xmsg = fi@_FillValue |
||||
c opt unused option |
||||
c |
||||
c The NCL wrapper should allow for multiple datasets |
||||
c so the user need only make one call to the function. |
||||
|
||||
c perform 2D interpolation allowing for missing data: nothing fancy |
||||
|
||||
c nomenclature: |
||||
c . nxi,nyi - lengths of xi,yi and dimensions of fi (must be >= 2) |
||||
c . xi - coordinates of fi (eg, lon [1D]) |
||||
c . yi - coordinates of fi (eg, lat [1D]) |
||||
c . fi - functional input values [2D] |
||||
c . nxo,nyo - lengths of xo,yo and dimensions of fo (must be >= 1) |
||||
c . xo - coordinates of fo (eg, lon [2D]) |
||||
c . must be monotonically increasing |
||||
c . yo - coordinates of fo (eg, lat [2D]) |
||||
c . must be monotonically increasing |
||||
c . fo - functional output values [interpolated] |
||||
c . xmsg - missing code |
||||
c . opt - unused |
||||
c . ier - error code |
||||
c . =0; no error |
||||
c . =1; not enough points in input/output array |
||||
c . =2/3; xi or yi are not monotonically increasing |
||||
c . =4/5; xo or yo are not monotonically increasing |
||||
c |
||||
c local |
||||
INTEGER NG,NX,NY,NEXACT,IX,IY,M,N,NW,NER,K |
||||
DOUBLE PRECISION FW(2,2),W(2,2),SUMF,SUMW,EPS |
||||
DOUBLE PRECISION DGCDIST |
||||
|
||||
c in-line functions (bilinear interp) |
||||
DOUBLE PRECISION Z1,Z2,Z3,Z4,SLOPE,SLPX,SLPY,FLI,FBLI |
||||
|
||||
FLI(Z1,Z2,SLOPE) = Z1 + SLOPE* (Z2-Z1) |
||||
FBLI(Z1,Z2,Z3,Z4,SLPX,SLPY) = FLI(Z1,Z2,SLPX) + |
||||
+ SLPY* (FLI(Z3,Z4,SLPX)- |
||||
+ FLI(Z1,Z2,SLPX)) |
||||
|
||||
c error checking |
||||
IER = 0 |
||||
IF (NXI.LE.1 .OR. NYI.LE.1 .OR. NXO.LE.1 .OR. NYO.LE.1) THEN |
||||
IER = 1 |
||||
RETURN |
||||
END IF |
||||
IF (IER.NE.0) RETURN |
||||
|
||||
CALL DMONOINC(YI,NYI,IER,NER) |
||||
IF (IER.NE.0) RETURN |
||||
CALL DMONOINC(XI,NXI,IER,NER) |
||||
IF (IER.NE.0) RETURN |
||||
c Init to missing |
||||
DO NG = 1,NGRD |
||||
DO NY = 1,NYO |
||||
DO NX = 1,NXO |
||||
FO(NX,NY,NG) = XMSG |
||||
END DO |
||||
END DO |
||||
END DO |
||||
c main loop [exact matches] |
||||
EPS = 1.D-03 |
||||
NEXACT = 0 |
||||
|
||||
DO NY = 1,NYO |
||||
DO NX = 1,NXO |
||||
|
||||
DO IY = 1,NYI |
||||
DO IX = 1,NXI |
||||
IF (XO(NX,NY).GE.(XI(IX)-EPS) .AND. |
||||
+ XO(NX,NY).LE.(XI(IX)+EPS) .AND. |
||||
+ YO(NX,NY).GE.(YI(IY)-EPS) .AND. |
||||
+ YO(NX,NY).LE.(YI(IY)+EPS) ) THEN |
||||
|
||||
DO NG=1,NGRD |
||||
FO(NX,NY,NG) = FI(IX,IY,NG) |
||||
NEXACT = NEXACT + 1 |
||||
END DO |
||||
GO TO 10 |
||||
END IF |
||||
END DO |
||||
END DO |
||||
|
||||
10 CONTINUE |
||||
END DO |
||||
END DO |
||||
|
||||
|
||||
c c c print *, "nexact=",nexact |
||||
|
||||
K = 1 |
||||
c c c k = opt |
||||
|
||||
c main loop [interpolation] |
||||
DO NY = 1,NYO |
||||
DO NX = 1,NXO |
||||
|
||||
DO IY = 1,NYI - K |
||||
DO IX = 1,NXI - K |
||||
IF (XO(NX,NY).GE.XI(IX) .AND. |
||||
+ XO(NX,NY).LT.XI(IX+K) .AND. |
||||
+ YO(NX,NY).GE.YI(IY) .AND. |
||||
+ YO(NX,NY).LT.YI(IY+K)) THEN |
||||
|
||||
DO NG = 1,NGRD |
||||
IF (FO(NX,NY,NG).EQ.XMSG) THEN |
||||
IF (FI(IX,IY,NG).NE.XMSG .AND. |
||||
+ FI(IX+K,IY,NG).NE.XMSG .AND. |
||||
+ FI(IX,IY+K,NG).NE.XMSG .AND. |
||||
+ FI(IX+K,IY+K,NG).NE.XMSG) THEN |
||||
|
||||
FO(NX,NY,NG) =FBLI(FI(IX,IY,NG),FI(IX+K,IY,NG), |
||||
+ FI(IX,IY+K,NG),FI(IX+K,IY+K,NG), |
||||
+ (XO(NX,NY)-XI(IX))/ |
||||
+ (XI(IX+K)-XI(IX)), |
||||
+ (YO(NX,NY)-YI(IY))/ |
||||
+ (YI(IY+K)-YI(IY))) |
||||
|
||||
ELSE |
||||
c OVERKILL |
||||
FW(1,1) = FI(IX,IY,NG) |
||||
FW(2,1) = FI(IX+K,IY,NG) |
||||
FW(1,2) = FI(IX,IY+K,NG) |
||||
FW(2,2) = FI(IX+K,IY+K,NG) |
||||
|
||||
W(1,1) = (1.D0/DGCDIST(YO(NX,NY),XO(NX,NY) |
||||
+ ,YI(IY),XI(IX),2))**2 |
||||
W(2,1) = (1.D0/DGCDIST(YO(NX,NY),XO(NX,NY) |
||||
+ ,YI(IY),XI(IX+K),2))**2 |
||||
W(1,2) = (1.D0/DGCDIST(YO(NX,NY),XO(NX,NY) |
||||
+ ,YI(IY+K),XI(IX),2))**2 |
||||
W(2,2) = (1.D0/DGCDIST(YO(NX,NY),XO(NX,NY) |
||||
+ ,YI(IY+K),XI(IX+K),2))**2 |
||||
|
||||
NW = 0 |
||||
SUMF = 0.0D0 |
||||
SUMW = 0.0D0 |
||||
DO N = 1,2 |
||||
DO M = 1,2 |
||||
IF (FW(M,N).NE.XMSG) THEN |
||||
SUMF = SUMF + FW(M,N)*W(M,N) |
||||
SUMW = SUMW + W(M,N) |
||||
NW = NW + 1 |
||||
END IF |
||||
END DO |
||||
END DO |
||||
c nw >=3 arbitrary |
||||
c c c IF (NCRIT.GE.3 .AND. SUMW.GT.0.D0) THEN |
||||
c nw =1 nearest neighbor |
||||
IF (NCRIT.GE.1 .AND. SUMW.GT.0.D0) THEN |
||||
FO(NX,NY,NG) = SUMF/SUMW |
||||
END IF |
||||
END IF |
||||
END IF |
||||
END DO |
||||
GO TO 20 |
||||
END IF |
||||
END DO |
||||
END DO |
||||
|
||||
20 CONTINUE |
||||
END DO |
||||
END DO |
||||
|
||||
RETURN |
||||
END |
@ -0,0 +1,832 @@
@@ -0,0 +1,832 @@
|
||||
#include <stdio.h> |
||||
#include "wrapper.h" |
||||
|
||||
extern void NGCALLF(drcm2rgrid,DRCM2RGRID)(int *,int *,int *,double *,double *, |
||||
double *,int *,double *,int*, |
||||
double *,double *,double*, |
||||
int *,int *,int *); |
||||
|
||||
extern void NGCALLF(drgrid2rcm,DRGRID2RCM)(int *,int *,int *,double *,double *, |
||||
double *,int *,int *,double *, |
||||
double *,double *,double*, |
||||
int *,int *,int *); |
||||
|
||||
extern void NGCALLF(drcm2points,DRCM2POINTS)(int *,int *,int *,double *, |
||||
double *,double *,int *,double *, |
||||
double *,double *,double*, |
||||
int *,int *,int *,int*); |
||||
|
||||
|
||||
NhlErrorTypes rcm2rgrid_W( void ) |
||||
{ |
||||
/*
|
||||
* Input variables |
||||
*/ |
||||
void *lat2d, *lon2d, *fi, *lat1d, *lon1d, *opt; |
||||
double *tmp_lat2d, *tmp_lon2d, *tmp_lat1d, *tmp_lon1d, *tmp_fi; |
||||
int tmp_opt, tmp_ncrit; |
||||
ng_size_t dsizes_lat2d[2]; |
||||
ng_size_t dsizes_lon2d[2]; |
||||
ng_size_t dsizes_lat1d[2]; |
||||
ng_size_t dsizes_lon1d[1]; |
||||
int ndims_fi; |
||||
ng_size_t size_fi; |
||||
ng_size_t dsizes_fi[NCL_MAX_DIMENSIONS]; |
||||
int has_missing_fi; |
||||
NclScalar missing_fi, missing_dfi, missing_rfi; |
||||
NclBasicDataTypes type_lat2d, type_lon2d, type_lat1d, type_lon1d; |
||||
NclBasicDataTypes type_fi, type_opt; |
||||
/*
|
||||
* Output variables. |
||||
*/ |
||||
void *fo; |
||||
double *tmp_fo; |
||||
ng_size_t *dsizes_fo; |
||||
NclBasicDataTypes type_fo; |
||||
NclScalar missing_fo; |
||||
/*
|
||||
* Other variables |
||||
*/ |
||||
ng_size_t nlon2d, nlat2d, nfi, nlat1d, nlon1d, nfo, ngrid, size_fo; |
||||
ng_size_t i; |
||||
int ier, ret; |
||||
int inlon2d, inlat2d, ingrid, inlon1d, inlat1d; |
||||
|
||||
/*
|
||||
* Retrieve parameters |
||||
* |
||||
* Note that any of the pointer parameters can be set to NULL, |
||||
* which implies you don't care about its value. |
||||
*/ |
||||
lat2d = (void*)NclGetArgValue( |
||||
0, |
||||
6, |
||||
NULL, |
||||
dsizes_lat2d, |
||||
NULL, |
||||
NULL, |
||||
&type_lat2d, |
||||
DONT_CARE); |
||||
|
||||
lon2d = (void*)NclGetArgValue( |
||||
1, |
||||
6, |
||||
NULL, |
||||
dsizes_lon2d, |
||||
NULL, |
||||
NULL, |
||||
&type_lon2d, |
||||
DONT_CARE); |
||||
|
||||
fi = (void*)NclGetArgValue( |
||||
2, |
||||
6, |
||||
&ndims_fi, |
||||
dsizes_fi, |
||||
&missing_fi, |
||||
&has_missing_fi, |
||||
&type_fi, |
||||
DONT_CARE); |
||||
|
||||
lat1d = (void*)NclGetArgValue( |
||||
3, |
||||
6, |
||||
NULL, |
||||
dsizes_lat1d, |
||||
NULL, |
||||
NULL, |
||||
&type_lat1d, |
||||
DONT_CARE); |
||||
|
||||
lon1d = (void*)NclGetArgValue( |
||||
4, |
||||
6, |
||||
NULL, |
||||
dsizes_lon1d, |
||||
NULL, |
||||
NULL, |
||||
&type_lon1d, |
||||
DONT_CARE); |
||||
|
||||
opt = (void*)NclGetArgValue( |
||||
5, |
||||
6, |
||||
NULL, |
||||
NULL, |
||||
NULL, |
||||
NULL, |
||||
&type_opt, |
||||
DONT_CARE); |
||||
/*
|
||||
* Check the input lat/lon arrays. They must be the same size, and larger |
||||
* than one element. |
||||
*/ |
||||
if(dsizes_lat2d[0] != dsizes_lon2d[0] || |
||||
dsizes_lat2d[1] != dsizes_lon2d[1]) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rcm2rgrid: The input lat/lon grids must be the same size"); |
||||
return(NhlFATAL); |
||||
} |
||||
|
||||
nlat2d = dsizes_lat2d[0]; |
||||
nlon2d = dsizes_lat2d[1]; /* same as dsizes_lon2d[1] */ |
||||
nlat1d = dsizes_lat1d[0]; |
||||
nlon1d = dsizes_lon1d[0]; |
||||
|
||||
if(nlon2d <= 1 || nlat2d <= 1 || nlat1d <= 1 || nlon1d <= 1) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rcm2rgrid: The input/output lat/lon grids must have at least 2 elements"); |
||||
return(NhlFATAL); |
||||
} |
||||
|
||||
/*
|
||||
* Compute the total number of elements in our arrays. |
||||
*/ |
||||
nfi = nlon2d * nlat2d; |
||||
nfo = nlat1d * nlon1d; |
||||
|
||||
/*
|
||||
* Check dimensions of fi. |
||||
*/ |
||||
if(ndims_fi < 2) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rcm2rgrid: fi must be at least two dimensions"); |
||||
return(NhlFATAL); |
||||
} |
||||
if(dsizes_fi[ndims_fi-2] != nlat2d || dsizes_fi[ndims_fi-1] != nlon2d) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rcm2rgrid: The rightmost dimensions of fi must be nlat2d x nlon2d, where nlat2d and nlon2d are the dimensions of the lat2d/lon2d arrays"); |
||||
return(NhlFATAL); |
||||
} |
||||
/*
|
||||
* Compute the total size of the input/output arrays. |
||||
*/ |
||||
ngrid = 1; |
||||
for( i = 0; i < ndims_fi-2; i++ ) ngrid *= dsizes_fi[i]; |
||||
size_fi = ngrid * nfi; |
||||
size_fo = ngrid * nfo; |
||||
|
||||
/*
|
||||
* Test input dimension sizes. |
||||
*/ |
||||
if((nlon2d > INT_MAX) || (nlat2d > INT_MAX) || (ngrid > INT_MAX) ||
|
||||
(nlon1d > INT_MAX) || (nlat1d > INT_MAX)) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rcm2rgrid: one or more input dimension sizes is greater than INT_MAX"); |
||||
return(NhlFATAL); |
||||
} |
||||
inlon2d = (int) nlon2d; |
||||
inlat2d = (int) nlat2d; |
||||
ingrid = (int) ngrid; |
||||
inlon1d = (int) nlon1d; |
||||
inlat1d = (int) nlat1d; |
||||
|
||||
/*
|
||||
* Coerce missing values. |
||||
*/ |
||||
coerce_missing(type_fi,has_missing_fi,&missing_fi,&missing_dfi, |
||||
&missing_rfi); |
||||
/*
|
||||
* Allocate space for output array. |
||||
*/ |
||||
if(type_fi == NCL_double) { |
||||
fo = (void*)calloc(size_fo,sizeof(double)); |
||||
tmp_fo = &((double*)fo)[0]; |
||||
type_fo = NCL_double; |
||||
missing_fo.doubleval = missing_dfi.doubleval; |
||||
} |
||||
else { |
||||
fo = (void*)calloc(size_fo,sizeof(float)); |
||||
tmp_fo = (double*)calloc(size_fo,sizeof(double)); |
||||
type_fo = NCL_float; |
||||
missing_fo.floatval = missing_rfi.floatval; |
||||
if(tmp_fo == NULL) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rcm2rgrid: Unable to allocate memory for temporary array"); |
||||
return(NhlFATAL); |
||||
} |
||||
} |
||||
dsizes_fo = (ng_size_t*)calloc(ndims_fi,sizeof(ng_size_t)); |
||||
if(fo == NULL || dsizes_fo == NULL) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rcm2rgrid: Unable to allocate memory for output array"); |
||||
return(NhlFATAL); |
||||
} |
||||
for(i = 0; i < ndims_fi-2; i++) dsizes_fo[i] = dsizes_fi[i]; |
||||
dsizes_fo[ndims_fi-2] = nlat1d; |
||||
dsizes_fo[ndims_fi-1] = nlon1d; |
||||
|
||||
/*
|
||||
* Coerce input arrays to double if necessary. |
||||
*/ |
||||
tmp_lat2d = coerce_input_double(lat2d,type_lat2d,nfi,0,NULL,NULL); |
||||
tmp_lon2d = coerce_input_double(lon2d,type_lon2d,nfi,0,NULL,NULL); |
||||
tmp_lat1d = coerce_input_double(lat1d,type_lat1d,nlat1d,0,NULL,NULL); |
||||
tmp_lon1d = coerce_input_double(lon1d,type_lon1d,nlon1d,0,NULL,NULL);
|
||||
tmp_fi = coerce_input_double(fi,type_fi,size_fi,has_missing_fi, |
||||
&missing_fi,&missing_dfi); |
||||
|
||||
if(tmp_lat2d == NULL || tmp_lon2d == NULL || |
||||
tmp_lat1d == NULL || tmp_lon1d == NULL || tmp_fi == NULL) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rcm2rgrid: Unable to coerce input lat/lon arrays to double precision"); |
||||
return(NhlFATAL); |
||||
} |
||||
|
||||
/*
|
||||
* Force opt to zero and ncrit to 1, since they are not used yet. |
||||
*/ |
||||
tmp_opt = 0; |
||||
tmp_ncrit = 1; |
||||
|
||||
NGCALLF(drcm2rgrid,DRCM2RGRID)(&ingrid,&inlat2d,&inlon2d,tmp_lat2d,tmp_lon2d, |
||||
tmp_fi,&inlat1d,tmp_lat1d,&inlon1d, |
||||
tmp_lon1d,tmp_fo,&missing_dfi.doubleval, |
||||
&tmp_ncrit,&tmp_opt,&ier); |
||||
|
||||
if(ier) { |
||||
if(ier == 1) { |
||||
NhlPError(NhlWARNING,NhlEUNKNOWN,"rcm2rgrid: not enough points in input/output array"); |
||||
} |
||||
if(2 <= ier && ier <= 5) { |
||||
NhlPError(NhlWARNING,NhlEUNKNOWN,"rcm2rgrid: lat2d, lon2d, lat1d, lon1d must be monotonically increasing"); |
||||
} |
||||
set_subset_output_missing(fo,0,type_fo,size_fo,missing_dfi.doubleval); |
||||
} |
||||
else { |
||||
if(type_fo != NCL_double) { |
||||
coerce_output_float_only(fo,tmp_fo,size_fo,0); |
||||
} |
||||
} |
||||
/*
|
||||
* Free temp arrays. |
||||
*/ |
||||
if(type_lat2d != NCL_double) NclFree(tmp_lat2d); |
||||
if(type_lon2d != NCL_double) NclFree(tmp_lon2d); |
||||
if(type_lat1d != NCL_double) NclFree(tmp_lat1d); |
||||
if(type_lon1d != NCL_double) NclFree(tmp_lon1d); |
||||
if(type_fi != NCL_double) NclFree(tmp_fi); |
||||
if(type_fo != NCL_double) NclFree(tmp_fo); |
||||
|
||||
/*
|
||||
* Return. |
||||
*/ |
||||
ret = NclReturnValue(fo,ndims_fi,dsizes_fo,&missing_fo,type_fo,0); |
||||
NclFree(dsizes_fo); |
||||
return(ret); |
||||
} |
||||
|
||||
|
||||
NhlErrorTypes rgrid2rcm_W( void ) |
||||
{ |
||||
/*
|
||||
* Input variables |
||||
*/ |
||||
void *lat2d, *lon2d, *fi, *lat1d, *lon1d, *opt; |
||||
double *tmp_lat2d, *tmp_lon2d, *tmp_lat1d, *tmp_lon1d, *tmp_fi; |
||||
int tmp_opt, tmp_ncrit; |
||||
ng_size_t dsizes_lat2d[2]; |
||||
ng_size_t dsizes_lon2d[2]; |
||||
ng_size_t dsizes_lat1d[2]; |
||||
ng_size_t dsizes_lon1d[1]; |
||||
int ndims_fi; |
||||
ng_size_t dsizes_fi[NCL_MAX_DIMENSIONS]; |
||||
int has_missing_fi; |
||||
NclScalar missing_fi, missing_dfi, missing_rfi; |
||||
NclBasicDataTypes type_lat2d, type_lon2d, type_lat1d, type_lon1d; |
||||
NclBasicDataTypes type_fi, type_opt; |
||||
/*
|
||||
* Output variables. |
||||
*/ |
||||
void *fo; |
||||
double *tmp_fo; |
||||
ng_size_t *dsizes_fo; |
||||
NclBasicDataTypes type_fo; |
||||
NclScalar missing_fo; |
||||
/*
|
||||
* Other variables |
||||
*/ |
||||
ng_size_t nlon2d, nlat2d, nfi, nlat1d, nlon1d, nfo, ngrid, size_fi, size_fo; |
||||
ng_size_t i; |
||||
int ier, ret; |
||||
int inlon2d, inlat2d, ingrid, inlon1d, inlat1d; |
||||
/*
|
||||
* Retrieve parameters |
||||
* |
||||
* Note that any of the pointer parameters can be set to NULL, |
||||
* which implies you don't care about its value. |
||||
*/ |
||||
lat1d = (void*)NclGetArgValue( |
||||
0, |
||||
6, |
||||
NULL, |
||||
dsizes_lat1d, |
||||
NULL, |
||||
NULL, |
||||
&type_lat1d, |
||||
DONT_CARE); |
||||
|
||||
lon1d = (void*)NclGetArgValue( |
||||
1, |
||||
6, |
||||
NULL, |
||||
dsizes_lon1d, |
||||
NULL, |
||||
NULL, |
||||
&type_lon1d, |
||||
DONT_CARE); |
||||
|
||||
fi = (void*)NclGetArgValue( |
||||
2, |
||||
6, |
||||
&ndims_fi, |
||||
dsizes_fi, |
||||
&missing_fi, |
||||
&has_missing_fi, |
||||
&type_fi, |
||||
DONT_CARE); |
||||
|
||||
lat2d = (void*)NclGetArgValue( |
||||
3, |
||||
6, |
||||
NULL, |
||||
dsizes_lat2d, |
||||
NULL, |
||||
NULL, |
||||
&type_lat2d, |
||||
DONT_CARE); |
||||
|
||||
lon2d = (void*)NclGetArgValue( |
||||
4, |
||||
6, |
||||
NULL, |
||||
dsizes_lon2d, |
||||
NULL, |
||||
NULL, |
||||
&type_lon2d, |
||||
DONT_CARE); |
||||
|
||||
opt = (void*)NclGetArgValue( |
||||
5, |
||||
6, |
||||
NULL, |
||||
NULL, |
||||
NULL, |
||||
NULL, |
||||
&type_opt, |
||||
DONT_CARE); |
||||
/*
|
||||
* Check the output lat/lon arrays. They must be the same size, and larger |
||||
* than one element. |
||||
*/ |
||||
if(dsizes_lat2d[0] != dsizes_lon2d[0] || |
||||
dsizes_lat2d[1] != dsizes_lon2d[1]) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rgrid2rcm: The output lat/lon grids must be the same size"); |
||||
return(NhlFATAL); |
||||
} |
||||
|
||||
nlat2d = dsizes_lat2d[0]; |
||||
nlon2d = dsizes_lat2d[1]; /* same as dsizes_lon2d[1] */ |
||||
nlat1d = dsizes_lat1d[0]; |
||||
nlon1d = dsizes_lon1d[0]; |
||||
|
||||
if(nlon2d <= 1 || nlat2d <= 1 || nlat1d <= 1 || nlon1d <= 1) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rgrid2rcm: The input/output lat/lon grids must have at least 2 elements"); |
||||
return(NhlFATAL); |
||||
} |
||||
|
||||
/*
|
||||
* Compute the total number of elements in our arrays. |
||||
*/ |
||||
nfi = nlat1d * nlon1d; |
||||
nfo = nlon2d * nlat2d; |
||||
|
||||
/*
|
||||
* Check dimensions of fi. |
||||
*/ |
||||
if(ndims_fi < 2) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rgrid2rcm: fi must be at least two dimensions"); |
||||
return(NhlFATAL); |
||||
} |
||||
if(dsizes_fi[ndims_fi-2] != nlat1d || dsizes_fi[ndims_fi-1] != nlon1d) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rgrid2rcm: The rightmost dimensions of fi must be nlat1d x nlon1d, where nlat1d and nlon1d are the dimensions of the lat1d/lon1d arrays"); |
||||
return(NhlFATAL); |
||||
} |
||||
/*
|
||||
* Compute the total size of the input/output arrays. |
||||
*/ |
||||
ngrid = 1; |
||||
for( i = 0; i < ndims_fi-2; i++ ) ngrid *= dsizes_fi[i]; |
||||
size_fi = ngrid * nfi; |
||||
size_fo = ngrid * nfo; |
||||
/*
|
||||
* Test input dimension sizes. |
||||
*/ |
||||
if((nlon2d > INT_MAX) || (nlat2d > INT_MAX) || (ngrid > INT_MAX) ||
|
||||
(nlon1d > INT_MAX) || (nlat1d > INT_MAX)) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rgrid2rcm: one or more input dimension sizes is greater than INT_MAX"); |
||||
return(NhlFATAL); |
||||
} |
||||
inlon2d = (int) nlon2d; |
||||
inlat2d = (int) nlat2d; |
||||
ingrid = (int) ngrid; |
||||
inlon1d = (int) nlon1d; |
||||
inlat1d = (int) nlat1d; |
||||
|
||||
/*
|
||||
* Coerce missing values. |
||||
*/ |
||||
coerce_missing(type_fi,has_missing_fi,&missing_fi,&missing_dfi, |
||||
&missing_rfi); |
||||
/*
|
||||
* Allocate space for output array. |
||||
*/ |
||||
if(type_fi == NCL_double) { |
||||
fo = (void*)calloc(size_fo,sizeof(double)); |
||||
tmp_fo = &((double*)fo)[0]; |
||||
type_fo = NCL_double; |
||||
missing_fo.doubleval = missing_dfi.doubleval; |
||||
} |
||||
else { |
||||
tmp_fo = (double*)calloc(size_fo,sizeof(double)); |
||||
fo = (void*)calloc(size_fo,sizeof(float)); |
||||
type_fo = NCL_float; |
||||
missing_fo.floatval = missing_rfi.floatval; |
||||
if(tmp_fo == NULL) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rgrid2rcm: Unable to allocate memory for temporary arrays"); |
||||
return(NhlFATAL); |
||||
} |
||||
} |
||||
dsizes_fo = (ng_size_t*)calloc(ndims_fi,sizeof(ng_size_t)); |
||||
if(fo == NULL || dsizes_fo == NULL) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rgrid2rcm: Unable to allocate memory for output array"); |
||||
return(NhlFATAL); |
||||
} |
||||
for(i = 0; i < ndims_fi-2; i++) dsizes_fo[i] = dsizes_fi[i]; |
||||
dsizes_fo[ndims_fi-2] = nlat2d; |
||||
dsizes_fo[ndims_fi-1] = nlon2d; |
||||
|
||||
/*
|
||||
* Coerce input arrays to double if necessary. |
||||
*/ |
||||
tmp_lat2d = coerce_input_double(lat2d,type_lat2d,nfo,0,NULL,NULL); |
||||
tmp_lon2d = coerce_input_double(lon2d,type_lon2d,nfo,0,NULL,NULL); |
||||
tmp_lat1d = coerce_input_double(lat1d,type_lat1d,nlat1d,0,NULL,NULL); |
||||
tmp_lon1d = coerce_input_double(lon1d,type_lon1d,nlon1d,0,NULL,NULL); |
||||
tmp_fi = coerce_input_double(fi,type_fi,size_fi,has_missing_fi, |
||||
&missing_fi,&missing_dfi); |
||||
|
||||
if(tmp_lat2d == NULL || tmp_lon2d == NULL || |
||||
tmp_lat1d == NULL || tmp_lon1d == NULL || tmp_fi == NULL) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rgrid2rcm: Unable to coerce input lat/lon arrays to double precision"); |
||||
return(NhlFATAL); |
||||
} |
||||
/*
|
||||
* Force opt to zero and ncrit to 1, since they are not used yet. |
||||
*/ |
||||
tmp_opt = 0; |
||||
tmp_ncrit = 1; |
||||
|
||||
NGCALLF(drgrid2rcm,DRGRID2RCM)(&ingrid,&inlat1d,&inlon1d,tmp_lat1d,tmp_lon1d, |
||||
tmp_fi,&inlat2d,&inlon2d,tmp_lat2d, |
||||
tmp_lon2d,tmp_fo,&missing_dfi.doubleval, |
||||
&tmp_ncrit,&tmp_opt,&ier); |
||||
if(ier) { |
||||
if(ier == 1) { |
||||
NhlPError(NhlWARNING,NhlEUNKNOWN,"rgrid2rcm: not enough points in input/output array"); |
||||
} |
||||
if(2 <= ier && ier <= 5) { |
||||
NhlPError(NhlWARNING,NhlEUNKNOWN,"rgrid2rcm: lat2d, lon2d, lat1d, lon1d must be monotonically increasing"); |
||||
} |
||||
set_subset_output_missing(fo,0,type_fo,size_fo,missing_dfi.doubleval); |
||||
} |
||||
else { |
||||
if(type_fo != NCL_double) { |
||||
coerce_output_float_only(fo,tmp_fo,size_fo,0); |
||||
} |
||||
} |
||||
/*
|
||||
* Free temp arrays. |
||||
*/ |
||||
if(type_lat2d != NCL_double) NclFree(tmp_lat2d); |
||||
if(type_lon2d != NCL_double) NclFree(tmp_lon2d); |
||||
if(type_lat1d != NCL_double) NclFree(tmp_lat1d); |
||||
if(type_lon1d != NCL_double) NclFree(tmp_lon1d); |
||||
if(type_fi != NCL_double) NclFree(tmp_fi); |
||||
if(type_fo != NCL_double) NclFree(tmp_fo); |
||||
|
||||
ret = NclReturnValue(fo,ndims_fi,dsizes_fo,&missing_fo,type_fo,0); |
||||
NclFree(dsizes_fo); |
||||
return(ret); |
||||
} |
||||
|
||||
|
||||
NhlErrorTypes rcm2points_W( void ) |
||||
{ |
||||
/*
|
||||
* Input variables |
||||
*/ |
||||
void *lat2d, *lon2d, *fi, *lat1d, *lon1d; |
||||
double *tmp_lat2d, *tmp_lon2d, *tmp_lat1d, *tmp_lon1d, *tmp_fi; |
||||
int *opt, tmp_ncrit; |
||||
ng_size_t dsizes_lat2d[2]; |
||||
ng_size_t dsizes_lon2d[2]; |
||||
ng_size_t dsizes_lat1d[2]; |
||||
ng_size_t dsizes_lon1d[1]; |
||||
int ndims_fi; |
||||
ng_size_t dsizes_fi[NCL_MAX_DIMENSIONS]; |
||||
int has_missing_fi; |
||||
NclScalar missing_fi, missing_dfi, missing_rfi; |
||||
NclBasicDataTypes type_lat2d, type_lon2d, type_lat1d, type_lon1d; |
||||
NclBasicDataTypes type_fi; |
||||
/*
|
||||
* Variables for retrieving attributes from "opt". |
||||
*/ |
||||
NclAttList *attr_list; |
||||
NclAtt attr_obj; |
||||
NclStackEntry stack_entry; |
||||
logical set_search_width; |
||||
/*
|
||||
* Output variables. |
||||
*/ |
||||
void *fo; |
||||
double *tmp_fo; |
||||
int ndims_fo; |
||||
ng_size_t *dsizes_fo; |
||||
NclBasicDataTypes type_fo; |
||||
NclScalar missing_fo; |
||||
/*
|
||||
* Other variables |
||||
*/ |
||||
ng_size_t nlon2d, nlat2d, nfi, nlat1d, nfo, ngrid, size_fi, size_fo; |
||||
ng_size_t i; |
||||
int search_width, ier, ret; |
||||
int inlon2d, inlat2d, ingrid, inlat1d; |
||||
/*
|
||||
* Retrieve parameters |
||||
* |
||||
* Note that any of the pointer parameters can be set to NULL, |
||||
* which implies you don't care about its value. |
||||
*/ |
||||
lat2d = (void*)NclGetArgValue( |
||||
0, |
||||
6, |
||||
NULL, |
||||
dsizes_lat2d, |
||||
NULL, |
||||
NULL, |
||||
&type_lat2d, |
||||
DONT_CARE); |
||||
|
||||
lon2d = (void*)NclGetArgValue( |
||||
1, |
||||
6, |
||||
NULL, |
||||
dsizes_lon2d, |
||||
NULL, |
||||
NULL, |
||||
&type_lon2d, |
||||
DONT_CARE); |
||||
|
||||
fi = (void*)NclGetArgValue( |
||||
2, |
||||
6, |
||||
&ndims_fi, |
||||
dsizes_fi, |
||||
&missing_fi, |
||||
&has_missing_fi, |
||||
&type_fi, |
||||
DONT_CARE); |
||||
|
||||
lat1d = (void*)NclGetArgValue( |
||||
3, |
||||
6, |
||||
NULL, |
||||
dsizes_lat1d, |
||||
NULL, |
||||
NULL, |
||||
&type_lat1d, |
||||
DONT_CARE); |
||||
|
||||
lon1d = (void*)NclGetArgValue( |
||||
4, |
||||
6, |
||||
NULL, |
||||
dsizes_lon1d, |
||||
NULL, |
||||
NULL, |
||||
&type_lon1d, |
||||
DONT_CARE); |
||||
|
||||
opt = (int*)NclGetArgValue( |
||||
5, |
||||
6, |
||||
NULL, |
||||
NULL, |
||||
NULL, |
||||
NULL, |
||||
NULL, |
||||
DONT_CARE); |
||||
/*
|
||||
* Check the input lat/lon arrays. They must be the same size, and larger |
||||
* than one element. |
||||
*/ |
||||
if(dsizes_lat2d[0] != dsizes_lon2d[0] || |
||||
dsizes_lat2d[1] != dsizes_lon2d[1]) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rcm2points: The input lat/lon grids must be the same size"); |
||||
return(NhlFATAL); |
||||
} |
||||
|
||||
nlat2d = dsizes_lat2d[0]; |
||||
nlon2d = dsizes_lat2d[1]; /* same as dsizes_lon2d[1] */ |
||||
nlat1d = dsizes_lat1d[0]; |
||||
|
||||
if(dsizes_lon1d[0] != nlat1d) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rcm2points: The output lat/lon arrays must be the same length"); |
||||
return(NhlFATAL); |
||||
} |
||||
|
||||
if(nlon2d < 2 || nlat2d < 2 || nlat1d < 1) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rcm2points: The input lat/lon grids must have at least 2 elements, and the output lat/lon arrays 1 element"); |
||||
return(NhlFATAL); |
||||
} |
||||
|
||||
/*
|
||||
* Compute the total number of elements in our arrays. |
||||
*/ |
||||
nfi = nlon2d * nlat2d; |
||||
nfo = nlat1d; |
||||
|
||||
/*
|
||||
* Check dimensions of fi. |
||||
*/ |
||||
if(ndims_fi < 2) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rcm2points: fi must be at least two dimensions"); |
||||
return(NhlFATAL); |
||||
} |
||||
if(dsizes_fi[ndims_fi-2] != nlat2d || dsizes_fi[ndims_fi-1] != nlon2d) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rcm2points: The rightmost dimensions of fi must be nlat2d x nlon2d, where nlat2d and nlon2d are the dimensions of the lat2d/lon2d arrays"); |
||||
return(NhlFATAL); |
||||
} |
||||
/*
|
||||
* Compute the sizes of the input/output arrays. |
||||
*/ |
||||
ngrid = 1; |
||||
for( i = 0; i < ndims_fi-2; i++ ) ngrid *= dsizes_fi[i]; |
||||
size_fi = ngrid * nfi; |
||||
size_fo = ngrid * nfo; |
||||
|
||||
/*
|
||||
* Test input dimension sizes. |
||||
*/ |
||||
if((nlon2d > INT_MAX) || (nlat2d > INT_MAX) || (ngrid > INT_MAX) || (nlat1d > INT_MAX)) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rcm2points: one or more input dimension sizes is greater than INT_MAX"); |
||||
return(NhlFATAL); |
||||
} |
||||
inlon2d = (int) nlon2d; |
||||
inlat2d = (int) nlat2d; |
||||
ingrid = (int) ngrid; |
||||
inlat1d = (int) nlat1d; |
||||
|
||||
/*
|
||||
* Coerce missing values. |
||||
*/ |
||||
coerce_missing(type_fi,has_missing_fi,&missing_fi,&missing_dfi, |
||||
&missing_rfi); |
||||
/*
|
||||
* Allocate space for output array. |
||||
*/ |
||||
if(type_fi == NCL_double) { |
||||
fo = (void*)calloc(size_fo,sizeof(double)); |
||||
tmp_fo = &((double*)fo)[0]; |
||||
type_fo = NCL_double; |
||||
missing_fo.doubleval = missing_dfi.doubleval; |
||||
} |
||||
else { |
||||
fo = (void*)calloc(size_fo,sizeof(float)); |
||||
tmp_fo = (double*)calloc(size_fo,sizeof(double)); |
||||
type_fo = NCL_float; |
||||
missing_fo.floatval = missing_rfi.floatval; |
||||
if(tmp_fo == NULL) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rcm2points: Unable to allocate memory for temporary array"); |
||||
return(NhlFATAL); |
||||
} |
||||
} |
||||
ndims_fo = ndims_fi-1; |
||||
dsizes_fo = (ng_size_t*)calloc(ndims_fo,sizeof(ng_size_t)); |
||||
if(fo == NULL || dsizes_fo == NULL) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rcm2points: Unable to allocate memory for output array"); |
||||
return(NhlFATAL); |
||||
} |
||||
for(i = 0; i < ndims_fi-2; i++) dsizes_fo[i] = dsizes_fi[i]; |
||||
dsizes_fo[ndims_fi-2] = nlat1d; |
||||
|
||||
/*
|
||||
* Coerce input arrays to double if necessary. |
||||
*/ |
||||
tmp_lat2d = coerce_input_double(lat2d,type_lat2d,nfi,0,NULL,NULL); |
||||
tmp_lon2d = coerce_input_double(lon2d,type_lon2d,nfi,0,NULL,NULL); |
||||
tmp_lat1d = coerce_input_double(lat1d,type_lat1d,nlat1d,0,NULL,NULL); |
||||
tmp_lon1d = coerce_input_double(lon1d,type_lon1d,nlat1d,0,NULL,NULL); |
||||
tmp_fi = coerce_input_double(fi,type_fi,size_fi,has_missing_fi, |
||||
&missing_fi,&missing_dfi); |
||||
|
||||
if(tmp_lat2d == NULL || tmp_lon2d == NULL || |
||||
tmp_lat1d == NULL || tmp_lon1d == NULL || tmp_fi == NULL) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"rcm2points: Unable to coerce input lat/lon arrays to double precision"); |
||||
return(NhlFATAL); |
||||
} |
||||
|
||||
/*
|
||||
* Force ncrit to 1, since it is not used yet. |
||||
*/ |
||||
tmp_ncrit = 1; |
||||
|
||||
/*
|
||||
* Check if any attributes have been attached to opt. |
||||
*/ |
||||
set_search_width = False; |
||||
stack_entry = _NclGetArg(5, 6, DONT_CARE); |
||||
switch (stack_entry.kind) {;; |
||||
case NclStk_VAR: |
||||
if (stack_entry.u.data_var->var.att_id != -1) {;; |
||||
attr_obj = (NclAtt) _NclGetObj(stack_entry.u.data_var->var.att_id); |
||||
if (attr_obj == NULL) {; |
||||
break; |
||||
}; |
||||
} |
||||
else { |
||||
/*
|
||||
* att_id == -1 ==> no optional args given. |
||||
*/ |
||||
break; |
||||
} |
||||
/*
|
||||
* Get optional arguments. |
||||
*/ |
||||
if (attr_obj->att.n_atts > 0) { |
||||
/*
|
||||
* Get list of attributes. |
||||
*/ |
||||
attr_list = attr_obj->att.att_list; |
||||
/*
|
||||
* Loop through attributes and check them. The current ones recognized are: |
||||
* |
||||
* "search_width" |
||||
*/ |
||||
while (attr_list != NULL) { |
||||
if (!strcmp(attr_list->attname, "search_width")) { |
||||
if(attr_list->attvalue->multidval.data_type != NCL_int) { |
||||
NhlPError(NhlWARNING,NhlEUNKNOWN,"rcm2points: The 'search_width' attribute must be an integer, defaulting to 1."); |
||||
search_width = 1; |
||||
} |
||||
else { |
||||
search_width = *(int*) attr_list->attvalue->multidval.val; |
||||
if(search_width <= 0) { |
||||
NhlPError(NhlWARNING,NhlEUNKNOWN,"rcm2points: The 'search_width' attribute is < 0. Defaulting to 1."); |
||||
search_width = 1; |
||||
} |
||||
else { |
||||
set_search_width = True; |
||||
} |
||||
} |
||||
} |
||||
attr_list = attr_list->next; |
||||
} |
||||
} |
||||
default: |
||||
break; |
||||
} |
||||
|
||||
/*
|
||||
* If user didn't set search_width, then set it here. |
||||
*/ |
||||
if(!set_search_width) search_width = 1; |
||||
|
||||
NGCALLF(drcm2points,DRCM2POINTS)(&ingrid,&inlat2d,&inlon2d,tmp_lat2d, |
||||
tmp_lon2d,tmp_fi,&inlat1d,tmp_lat1d, |
||||
tmp_lon1d,tmp_fo,&missing_dfi.doubleval, |
||||
opt,&tmp_ncrit,&search_width,&ier); |
||||
if(ier) { |
||||
if(ier == 1) { |
||||
NhlPError(NhlWARNING,NhlEUNKNOWN,"rcm2points: not enough points in input/output array"); |
||||
} |
||||
if(2 <= ier && ier <= 5) { |
||||
NhlPError(NhlWARNING,NhlEUNKNOWN,"rcm2points: lat2d, lon2d, lat1d, lon1d must be monotonically increasing"); |
||||
} |
||||
set_subset_output_missing(fo,0,type_fo,size_fo,missing_dfi.doubleval); |
||||
} |
||||
else { |
||||
if(type_fo != NCL_double) { |
||||
coerce_output_float_only(fo,tmp_fo,size_fo,0); |
||||
} |
||||
} |
||||
/*
|
||||
* Free temp arrays. |
||||
*/ |
||||
if(type_lat2d != NCL_double) NclFree(tmp_lat2d); |
||||
if(type_lon2d != NCL_double) NclFree(tmp_lon2d); |
||||
if(type_lat1d != NCL_double) NclFree(tmp_lat1d); |
||||
if(type_lon1d != NCL_double) NclFree(tmp_lon1d); |
||||
if(type_fi != NCL_double) NclFree(tmp_fi); |
||||
if(type_fo != NCL_double) NclFree(tmp_fo); |
||||
|
||||
/*
|
||||
* Return. |
||||
*/ |
||||
ret = NclReturnValue(fo,ndims_fo,dsizes_fo,&missing_fo,type_fo,0); |
||||
NclFree(dsizes_fo); |
||||
return(ret); |
||||
} |
@ -0,0 +1,612 @@
@@ -0,0 +1,612 @@
|
||||
c====================================================================== |
||||
c |
||||
c !IROUTINE: capecalc3d -- Calculate CAPE and CIN |
||||
c |
||||
c !DESCRIPTION: |
||||
c |
||||
c If i3dflag=1, this routine calculates CAPE and CIN (in m**2/s**2, |
||||
c or J/kg) for every grid point in the entire 3D domain (treating |
||||
c each grid point as a parcel). If i3dflag=0, then it |
||||
c calculates CAPE and CIN only for the parcel with max theta-e in |
||||
c the column, (i.e. something akin to Colman's MCAPE). By "parcel", |
||||
c we mean a 500-m deep parcel, with actual temperature and moisture |
||||
c averaged over that depth. |
||||
c |
||||
c In the case of i3dflag=0, |
||||
c CAPE and CIN are 2D fields that are placed in the k=mkzh slabs of |
||||
c the cape and cin arrays. Also, if i3dflag=0, LCL and LFC heights |
||||
c are put in the k=mkzh-1 and k=mkzh-2 slabs of the cin array. |
||||
c |
||||
c ASSUMPTIONS: |
||||
c |
||||
c !REVISION HISTORY: |
||||
c 2005-May-15 - Mark T. Stoelinga - oringinal version from RIP4 |
||||
c 2005-Nov-28 - J. Schramm - modified to run outside of RIP4 with |
||||
c 2012-Jul-18 - M. Haley - modified to change/add missing value. |
||||
c NCL |
||||
c |
||||
c !INTERFACE: |
||||
c ------------------------------------------------------------------ |
||||
C NCLFORTSTART |
||||
SUBROUTINE DCAPECALC3D(PRS,TMK,QVP,GHT,TER,SFP,CAPE,CIN,CMSG, |
||||
+ MIY,MJX,MKZH,I3DFLAG,TER_FOLLOW,PSAFILE) |
||||
c |
||||
IMPLICIT NONE |
||||
INTEGER MIY,MJX,MKZH,I3DFLAG,TER_FOLLOW |
||||
DOUBLE PRECISION PRS(MIY,MJX,MKZH) |
||||
DOUBLE PRECISION TMK(MIY,MJX,MKZH) |
||||
DOUBLE PRECISION QVP(MIY,MJX,MKZH) |
||||
DOUBLE PRECISION GHT(MIY,MJX,MKZH) |
||||
DOUBLE PRECISION TER(MIY,MJX) |
||||
DOUBLE PRECISION SFP(MIY,MJX) |
||||
DOUBLE PRECISION CAPE(MIY,MJX,MKZH) |
||||
DOUBLE PRECISION CIN(MIY,MJX,MKZH) |
||||
DOUBLE PRECISION CMSG |
||||
CHARACTER*(*) PSAFILE |
||||
C NCLEND |
||||
c Local variables |
||||
INTEGER I,J,K,ILCL,IUP,KEL,KK,KLCL,KLEV,KLFC,KMAX,KPAR,KPAR1,KPAR2 |
||||
DOUBLE PRECISION DAVG,ETHMAX,Q,T,P,E,ETH,TLCL,ZLCL |
||||
DOUBLE PRECISION CP,EPS,GAMMA,GAMMAMD,RGAS,RGASMD,TLCLC1,TLCLC2, |
||||
+ TLCLC3,TLCLC4 |
||||
DOUBLE PRECISION CPMD,THTECON1,THTECON2,THTECON3 |
||||
DOUBLE PRECISION CELKEL,EZERO,ESLCON1,ESLCON2,GRAV |
||||
DOUBLE PRECISION PAVG,VIRTUAL,P1,P2,PP1,PP2,TH,TOTTHE,TOTQVP, |
||||
+ TOTPRS |
||||
DOUBLE PRECISION CPM,DELTAP,ETHPARI,GAMMAM,GHTPARI,QVPPARI, |
||||
+ PRSPARI,TMKPARI |
||||
DOUBLE PRECISION FACDEN,FAC1,FAC2,QVPLIFT,TMKLIFT,TVENV,TVLIFT, |
||||
+ GHTLIFT |
||||
DOUBLE PRECISION ESLIFT,TMKENV,QVPENV,TONPSADIABAT |
||||
DOUBLE PRECISION BENAMIN,DZ,PUP,PDN |
||||
DOUBLE PRECISION BUOY(150),ZREL(150),BENACCUM(150), |
||||
+ PRSF(MIY,MJX,MKZH) |
||||
DOUBLE PRECISION PSADITHTE(150),PSADIPRS(150),PSADITMK(150,150) |
||||
c |
||||
C The comments were taken from a Mark Stoelinga email, 23 Apr 2007, |
||||
C in response to a user getting the "Outside of lookup table bounds" |
||||
C error message. |
||||
C |
||||
C TMKPARI - Initial temperature of parcel, K |
||||
C Values of 300 okay. (Not sure how much from this you can stray.) |
||||
C |
||||
C PRSPARI - Initial pressure of parcel, hPa |
||||
C Values of 980 okay. (Not sure how much from this you can stray.) |
||||
C |
||||
C THTECON1, THTECON2, THTECON3 |
||||
C These are all constants, the first in K and the other two have |
||||
C no units. Values of 3376, 2.54, and 0.81 were stated as being |
||||
C okay. |
||||
C |
||||
C TLCL - The temperature at the parcel's lifted condensation level, K |
||||
C should be a reasonable atmospheric temperature around 250-300 K |
||||
C (398 is "way too high") |
||||
C |
||||
C QVPPARI - The initial water vapor mixing ratio of the parcel, |
||||
C kg/kg (should range from 0.000 to 0.025) |
||||
C |
||||
|
||||
c Constants |
||||
IUP = 6 |
||||
CELKEL = 273.15D0 |
||||
GRAV = 9.81D0 |
||||
C hPa |
||||
EZERO = 6.112D0 |
||||
ESLCON1 = 17.67D0 |
||||
ESLCON2 = 29.65D0 |
||||
EPS = 0.622D0 |
||||
C J/K/kg |
||||
RGAS = 287.04D0 |
||||
C J/K/kg Note: not using Bolton's value of 1005.7 |
||||
CP = 1004.D0 |
||||
GAMMA = RGAS/CP |
||||
C cp_moist=cp*(1.+cpmd*qvp) |
||||
CPMD = .887D0 |
||||
C rgas_moist=rgas*(1.+rgasmd*qvp) |
||||
RGASMD = .608D0 |
||||
C gamma_moist=gamma*(1.+gammamd*qvp) |
||||
GAMMAMD = RGASMD - CPMD |
||||
TLCLC1 = 2840.D0 |
||||
TLCLC2 = 3.5D0 |
||||
TLCLC3 = 4.805D0 |
||||
TLCLC4 = 55.D0 |
||||
C K |
||||
THTECON1 = 3376.D0 |
||||
THTECON2 = 2.54D0 |
||||
THTECON3 = .81D0 |
||||
c |
||||
c Calculated the pressure at full sigma levels (a set of pressure |
||||
c levels that bound the layers represented by the vertical grid points) |
||||
|
||||
CALL DPFCALC(PRS,SFP,PRSF,MIY,MJX,MKZH,TER_FOLLOW) |
||||
c |
||||
c Before looping, set lookup table for getting temperature on |
||||
c a pseudoadiabat. |
||||
c |
||||
CALL DLOOKUP_TABLE(PSADITHTE,PSADIPRS,PSADITMK,PSAFILE) |
||||
c |
||||
C do j=1,mjx-1 |
||||
DO J = 1,MJX |
||||
C do i=1,miy-1 |
||||
DO I = 1,MIY |
||||
CAPE(I,J,1) = 0.D0 |
||||
CIN(I,J,1) = 0.D0 |
||||
c |
||||
IF (I3DFLAG.EQ.1) THEN |
||||
KPAR1 = 2 |
||||
KPAR2 = MKZH |
||||
ELSE |
||||
c |
||||
c Find parcel with max theta-e in lowest 3 km AGL. |
||||
c |
||||
ETHMAX = -1.D0 |
||||
DO K = MKZH,1,-1 |
||||
IF (GHT(I,J,K)-TER(I,J).LT.3000.D0) THEN |
||||
Q = MAX(QVP(I,J,K),1.D-15) |
||||
T = TMK(I,J,K) |
||||
P = PRS(I,J,K) |
||||
E = Q*P/ (EPS+Q) |
||||
TLCL = TLCLC1/ (LOG(T**TLCLC2/E)-TLCLC3) + |
||||
+ TLCLC4 |
||||
ETH = T* (1000.D0/P)** |
||||
+ (GAMMA* (1.D0+GAMMAMD*Q))* |
||||
+ EXP((THTECON1/TLCL-THTECON2)*Q* |
||||
+ (1.D0+THTECON3*Q)) |
||||
IF (ETH.GT.ETHMAX) THEN |
||||
KLEV = K |
||||
ETHMAX = ETH |
||||
END IF |
||||
END IF |
||||
END DO |
||||
KPAR1 = KLEV |
||||
KPAR2 = KLEV |
||||
c |
||||
c Establish average properties of that parcel |
||||
c (over depth of approximately davg meters) |
||||
c |
||||
c davg=.1 |
||||
DAVG = 500.D0 |
||||
PAVG = DAVG*PRS(I,J,KPAR1)*GRAV/ |
||||
+ (RGAS*VIRTUAL(TMK(I,J,KPAR1),QVP(I,J,KPAR1))) |
||||
P2 = MIN(PRS(I,J,KPAR1)+.5D0*PAVG,PRSF(I,J,MKZH)) |
||||
P1 = P2 - PAVG |
||||
TOTTHE = 0.D0 |
||||
TOTQVP = 0.D0 |
||||
TOTPRS = 0.D0 |
||||
DO K = MKZH,2,-1 |
||||
IF (PRSF(I,J,K).LE.P1) GO TO 35 |
||||
IF (PRSF(I,J,K-1).GE.P2) GO TO 34 |
||||
P = PRS(I,J,K) |
||||
PUP = PRSF(I,J,K) |
||||
PDN = PRSF(I,J,K-1) |
||||
Q = MAX(QVP(I,J,K),1.D-15) |
||||
TH = TMK(I,J,K)* (1000.D0/P)** |
||||
+ (GAMMA* (1.D0+GAMMAMD*Q)) |
||||
PP1 = MAX(P1,PDN) |
||||
PP2 = MIN(P2,PUP) |
||||
IF (PP2.GT.PP1) THEN |
||||
DELTAP = PP2 - PP1 |
||||
TOTQVP = TOTQVP + Q*DELTAP |
||||
TOTTHE = TOTTHE + TH*DELTAP |
||||
TOTPRS = TOTPRS + DELTAP |
||||
END IF |
||||
34 CONTINUE |
||||
END DO |
||||
35 CONTINUE |
||||
QVPPARI = TOTQVP/TOTPRS |
||||
TMKPARI = (TOTTHE/TOTPRS)* |
||||
+ (PRS(I,J,KPAR1)/1000.D0)** (GAMMA* |
||||
+ (1.D0+GAMMAMD*QVP(I,J,KPAR1))) |
||||
END IF |
||||
c |
||||
DO KPAR = KPAR1,KPAR2 |
||||
c |
||||
c Calculate temperature and moisture properties of parcel |
||||
c (Note, qvppari and tmkpari already calculated above for 2D case.) |
||||
c |
||||
IF (I3DFLAG.EQ.1) THEN |
||||
QVPPARI = QVP(I,J,KPAR) |
||||
TMKPARI = TMK(I,J,KPAR) |
||||
END IF |
||||
PRSPARI = PRS(I,J,KPAR) |
||||
GHTPARI = GHT(I,J,KPAR) |
||||
GAMMAM = GAMMA* (1.D0+GAMMAMD*QVPPARI) |
||||
CPM = CP* (1.D0+CPMD*QVPPARI) |
||||
c |
||||
E = MAX(1.D-20,QVPPARI*PRSPARI/ (EPS+QVPPARI)) |
||||
TLCL = TLCLC1/ (LOG(TMKPARI**TLCLC2/E)-TLCLC3) + |
||||
+ TLCLC4 |
||||
ETHPARI = TMKPARI* (1000.D0/PRSPARI)** |
||||
+ (GAMMA* (1.D0+GAMMAMD*QVPPARI))* |
||||
+ EXP((THTECON1/TLCL-THTECON2)*QVPPARI* |
||||
+ (1.D0+THTECON3*QVPPARI)) |
||||
ZLCL = GHTPARI + (TMKPARI-TLCL)/ (GRAV/CPM) |
||||
c |
||||
c Calculate buoyancy and relative height of lifted parcel at |
||||
c all levels, and store in bottom up arrays. Add a level at the LCL, |
||||
c and at all points where buoyancy is zero. |
||||
c |
||||
C for arrays that go bottom to top |
||||
KK = 0 |
||||
ILCL = 0 |
||||
IF (GHTPARI.GE.ZLCL) THEN |
||||
c |
||||
c initial parcel already saturated or supersaturated. |
||||
c |
||||
ILCL = 2 |
||||
KLCL = 1 |
||||
END IF |
||||
DO K = KPAR,1,-1 |
||||
C for arrays that go bottom to top |
||||
33 KK = KK + 1 |
||||
C model level is below LCL |
||||
IF (GHT(I,J,K).LT.ZLCL) THEN |
||||
QVPLIFT = QVPPARI |
||||
TMKLIFT = TMKPARI - GRAV/CPM* |
||||
+ (GHT(I,J,K)-GHTPARI) |
||||
TVENV = VIRTUAL(TMK(I,J,K),QVP(I,J,K)) |
||||
TVLIFT = VIRTUAL(TMKLIFT,QVPLIFT) |
||||
GHTLIFT = GHT(I,J,K) |
||||
ELSE IF (GHT(I,J,K).GE.ZLCL .AND. ILCL.EQ.0) THEN |
||||
c |
||||
c This model level and previous model level straddle the LCL, |
||||
c so first create a new level in the bottom-up array, at the LCL. |
||||
c |
||||
TMKLIFT = TLCL |
||||
QVPLIFT = QVPPARI |
||||
FACDEN = GHT(I,J,K) - GHT(I,J,K+1) |
||||
FAC1 = (ZLCL-GHT(I,J,K+1))/FACDEN |
||||
FAC2 = (GHT(I,J,K)-ZLCL)/FACDEN |
||||
TMKENV = TMK(I,J,K+1)*FAC2 + TMK(I,J,K)*FAC1 |
||||
QVPENV = QVP(I,J,K+1)*FAC2 + QVP(I,J,K)*FAC1 |
||||
TVENV = VIRTUAL(TMKENV,QVPENV) |
||||
TVLIFT = VIRTUAL(TMKLIFT,QVPLIFT) |
||||
GHTLIFT = ZLCL |
||||
ILCL = 1 |
||||
ELSE |
||||
TMKLIFT = TONPSADIABAT(ETHPARI,PRS(I,J,K), |
||||
+ PSADITHTE,PSADIPRS,PSADITMK,GAMMA) |
||||
ESLIFT = EZERO*EXP(ESLCON1* (TMKLIFT-CELKEL)/ |
||||
+ (TMKLIFT-ESLCON2)) |
||||
QVPLIFT = EPS*ESLIFT/ (PRS(I,J,K)-ESLIFT) |
||||
TVENV = VIRTUAL(TMK(I,J,K),QVP(I,J,K)) |
||||
TVLIFT = VIRTUAL(TMKLIFT,QVPLIFT) |
||||
GHTLIFT = GHT(I,J,K) |
||||
END IF |
||||
C buoyancy |
||||
BUOY(KK) = GRAV* (TVLIFT-TVENV)/TVENV |
||||
ZREL(KK) = GHTLIFT - GHTPARI |
||||
IF ((KK.GT.1).AND. |
||||
+ (BUOY(KK)*BUOY(KK-1).LT.0.0D0)) THEN |
||||
c |
||||
c Parcel ascent curve crosses sounding curve, so create a new level |
||||
c in the bottom-up array at the crossing. |
||||
c |
||||
KK = KK + 1 |
||||
BUOY(KK) = BUOY(KK-1) |
||||
ZREL(KK) = ZREL(KK-1) |
||||
BUOY(KK-1) = 0.D0 |
||||
ZREL(KK-1) = ZREL(KK-2) + |
||||
+ BUOY(KK-2)/ (BUOY(KK-2)- |
||||
+ BUOY(KK))* (ZREL(KK)-ZREL(KK-2)) |
||||
END IF |
||||
IF (ILCL.EQ.1) THEN |
||||
KLCL = KK |
||||
ILCL = 2 |
||||
GO TO 33 |
||||
END IF |
||||
END DO |
||||
KMAX = KK |
||||
IF (KMAX.GT.150) THEN |
||||
print *, |
||||
+ 'capecalc3d: kmax got too big. kmax=',KMAX |
||||
STOP |
||||
END IF |
||||
c |
||||
c If no LCL was found, set klcl to kmax. It is probably not really |
||||
c at kmax, but this will make the rest of the routine behave |
||||
c properly. |
||||
c |
||||
IF (ILCL.EQ.0) KLCL=KMAX |
||||
c |
||||
c Get the accumulated buoyant energy from the parcel's starting |
||||
c point, at all levels up to the top level. |
||||
c |
||||
BENACCUM(1) = 0.0D0 |
||||
BENAMIN = 9D9 |
||||
DO K = 2,KMAX |
||||
DZ = ZREL(K) - ZREL(K-1) |
||||
BENACCUM(K) = BENACCUM(K-1) + |
||||
+ .5D0*DZ* (BUOY(K-1)+BUOY(K)) |
||||
IF (BENACCUM(K).LT.BENAMIN) THEN |
||||
BENAMIN = BENACCUM(K) |
||||
END IF |
||||
END DO |
||||
c |
||||
c Determine equilibrium level (EL), which we define as the highest |
||||
c level of non-negative buoyancy above the LCL. Note, this may be |
||||
c the top level if the parcel is still buoyant there. |
||||
c |
||||
DO K = KMAX,KLCL,-1 |
||||
IF (BUOY(K).GE.0.D0) THEN |
||||
C k of equilibrium level |
||||
KEL = K |
||||
GO TO 50 |
||||
END IF |
||||
END DO |
||||
c |
||||
c If we got through that loop, then there is no non-negative |
||||
c buoyancy above the LCL in the sounding. In these situations, |
||||
c both CAPE and CIN will be set to -0.1 J/kg. (See below about |
||||
c missing values in V6.1.0). Also, where CAPE is |
||||
c non-zero, CAPE and CIN will be set to a minimum of +0.1 J/kg, so |
||||
c that the zero contour in either the CIN or CAPE fields will |
||||
c circumscribe regions of non-zero CAPE. |
||||
c |
||||
c In V6.1.0 of NCL, we added a _FillValue attribute to the return |
||||
c value of this function. At that time we decided to change -0.1 |
||||
c to a more appropriate missing value, which is passed into this |
||||
c routine as CMSG. |
||||
c |
||||
c CAPE(I,J,KPAR) = -0.1D0 |
||||
c CIN(I,J,KPAR) = -0.1D0 |
||||
CAPE(I,J,KPAR) = CMSG |
||||
CIN(I,J,KPAR) = CMSG |
||||
KLFC = KMAX |
||||
c |
||||
GO TO 102 |
||||
c |
||||
50 CONTINUE |
||||
c |
||||
c If there is an equilibrium level, then CAPE is positive. We'll |
||||
c define the level of free convection (LFC) as the point below the |
||||
c EL, but at or above the LCL, where accumulated buoyant energy is a |
||||
c minimum. The net positive area (accumulated buoyant energy) from |
||||
c the LFC up to the EL will be defined as the CAPE, and the net |
||||
c negative area (negative of accumulated buoyant energy) from the |
||||
c parcel starting point to the LFC will be defined as the convective |
||||
c inhibition (CIN). |
||||
c |
||||
c First get the LFC according to the above definition. |
||||
c |
||||
BENAMIN = 9D9 |
||||
KLFC = KMAX |
||||
DO K = KLCL,KEL |
||||
IF (BENACCUM(K).LT.BENAMIN) THEN |
||||
BENAMIN = BENACCUM(K) |
||||
KLFC = K |
||||
END IF |
||||
END DO |
||||
c |
||||
c Now we can assign values to cape and cin |
||||
c |
||||
CAPE(I,J,KPAR) = MAX(BENACCUM(KEL)-BENAMIN,0.1D0) |
||||
CIN(I,J,KPAR) = MAX(-BENAMIN,0.1D0) |
||||
c |
||||
c CIN is uninteresting when CAPE is small (< 100 J/kg), so set |
||||
c CIN to -0.1 (see note about missing values in V6.1.0) in |
||||
c that case. |
||||
c |
||||
c In V6.1.0 of NCL, we added a _FillValue attribute to the return |
||||
c value of this function. At that time we decided to change -0.1 |
||||
c to a more appropriate missing value, which is passed into this |
||||
c routine as CMSG. |
||||
c |
||||
C IF (CAPE(I,J,KPAR).LT.100.D0) CIN(I,J,KPAR) = -0.1D0 |
||||
IF (CAPE(I,J,KPAR).LT.100.D0) CIN(I,J,KPAR) = CMSG |
||||
102 CONTINUE |
||||
c |
||||
END DO |
||||
c |
||||
IF (I3DFLAG.EQ.0) THEN |
||||
CAPE(I,J,MKZH) = CAPE(I,J,KPAR1) |
||||
CIN(I,J,MKZH) = CIN(I,J,KPAR1) |
||||
C meters AGL |
||||
CIN(I,J,MKZH-1) = ZREL(KLCL) + GHTPARI - TER(I,J) |
||||
C meters AGL |
||||
CIN(I,J,MKZH-2) = ZREL(KLFC) + GHTPARI - TER(I,J) |
||||
END IF |
||||
c |
||||
END DO |
||||
END DO |
||||
c |
||||
RETURN |
||||
END |
||||
c c |
||||
c*********************************************************************c |
||||
c c |
||||
C NCLFORTSTART |
||||
DOUBLE PRECISION FUNCTION TONPSADIABAT(THTE,PRS,PSADITHTE, |
||||
& PSADIPRS,PSADITMK,GAMMA) |
||||
IMPLICIT NONE |
||||
DOUBLE PRECISION THTE |
||||
DOUBLE PRECISION PRS |
||||
DOUBLE PRECISION PSADITHTE |
||||
DOUBLE PRECISION PSADIPRS |
||||
DOUBLE PRECISION PSADITMK |
||||
DOUBLE PRECISION GAMMA |
||||
C NCLEND |
||||
DOUBLE PRECISION FRACJT |
||||
DOUBLE PRECISION FRACJT2 |
||||
DOUBLE PRECISION FRACIP |
||||
DOUBLE PRECISION FRACIP2 |
||||
DIMENSION PSADITHTE(150),PSADIPRS(150),PSADITMK(150,150) |
||||
INTEGER IP, IPCH, JT, JTCH |
||||
c c |
||||
c This function gives the temperature (in K) on a moist adiabat |
||||
c (specified by thte in K) given pressure in hPa. It uses a |
||||
c lookup table, with data that was generated by the Bolton (1980) |
||||
c formula for theta_e. |
||||
c |
||||
c First check if pressure is less than min pressure in lookup table. |
||||
c If it is, assume parcel is so dry that the given theta-e value can |
||||
c be interpretted as theta, and get temperature from the simple dry |
||||
c theta formula. |
||||
c |
||||
IF (PRS.LE.PSADIPRS(150)) THEN |
||||
TONPSADIABAT = THTE* (PRS/1000.D0)**GAMMA |
||||
RETURN |
||||
END IF |
||||
c |
||||
c Otherwise, look for the given thte/prs point in the lookup table. |
||||
c |
||||
DO JTCH = 1,150 - 1 |
||||
IF (THTE.GE.PSADITHTE(JTCH) .AND. |
||||
+ THTE.LT.PSADITHTE(JTCH+1)) THEN |
||||
JT = JTCH |
||||
GO TO 213 |
||||
END IF |
||||
END DO |
||||
JT = -1 |
||||
213 CONTINUE |
||||
DO IPCH = 1,150 - 1 |
||||
IF (PRS.LE.PSADIPRS(IPCH) .AND. PRS.GT.PSADIPRS(IPCH+1)) THEN |
||||
IP = IPCH |
||||
GO TO 215 |
||||
END IF |
||||
END DO |
||||
IP = -1 |
||||
215 CONTINUE |
||||
IF (JT.EQ.-1 .OR. IP.EQ.-1) THEN |
||||
print *,'capecalc3d: ', |
||||
+ 'Outside of lookup table bounds. prs,thte=', |
||||
+ PRS,THTE |
||||
STOP |
||||
END IF |
||||
FRACJT = (THTE-PSADITHTE(JT))/ (PSADITHTE(JT+1)-PSADITHTE(JT)) |
||||
FRACJT2 = 1.D0 - FRACJT |
||||
FRACIP = (PSADIPRS(IP)-PRS)/ (PSADIPRS(IP)-PSADIPRS(IP+1)) |
||||
FRACIP2 = 1.D0 - FRACIP |
||||
IF (PSADITMK(IP,JT).GT.1D9 .OR. PSADITMK(IP+1,JT).GT.1D9 .OR. |
||||
+ PSADITMK(IP,JT+1).GT.1D9 .OR. PSADITMK(IP+1,JT+1).GT.1D9) THEN |
||||
print *,'capecalc3d: ', |
||||
+ 'Tried to access missing temperature in lookup table.', |
||||
+ 'Prs and Thte probably unreasonable. prs,thte=',PRS,THTE |
||||
STOP |
||||
END IF |
||||
TONPSADIABAT = FRACIP2*FRACJT2*PSADITMK(IP,JT) + |
||||
+ FRACIP*FRACJT2*PSADITMK(IP+1,JT) + |
||||
+ FRACIP2*FRACJT*PSADITMK(IP,JT+1) + |
||||
+ FRACIP*FRACJT*PSADITMK(IP+1,JT+1) |
||||
c |
||||
RETURN |
||||
END |
||||
c c |
||||
c*********************************************************************c |
||||
SUBROUTINE DLOOKUP_TABLE(PSADITHTE,PSADIPRS,PSADITMK,FNAME) |
||||
DOUBLE PRECISION PSADITHTE |
||||
DOUBLE PRECISION PSADIPRS |
||||
DOUBLE PRECISION PSADITMK |
||||
c Set up lookup table for getting temperature on a pseudoadiabat. |
||||
c (Borrow the unit number for the stationlist, just for the moment.) |
||||
c |
||||
C CHARACTER*15 FNAME |
||||
CHARACTER*(*) FNAME |
||||
DIMENSION PSADITHTE(150),PSADIPRS(150),PSADITMK(150,150) |
||||
|
||||
C FNAME = 'psadilookup.dat' |
||||
IUSTNLIST = 33 |
||||
OPEN (UNIT=IUSTNLIST,FILE=FNAME,FORM='formatted',STATUS='old') |
||||
DO I = 1,14 |
||||
READ (IUSTNLIST,FMT=*) |
||||
END DO |
||||
READ (IUSTNLIST,FMT=*) NTHTE,NPRS |
||||
IF (NTHTE.NE.150 .OR. NPRS.NE.150) THEN |
||||
WRITE (IUP,FMT=*) |
||||
+ 'Number of pressure or theta_e levels in lookup table' |
||||
WRITE (IUP,FMT=*) 'file not = 150. Check lookup table file.' |
||||
STOP |
||||
END IF |
||||
READ (IUSTNLIST,FMT=173) (PSADITHTE(JT),JT=1,NTHTE) |
||||
READ (IUSTNLIST,FMT=173) (PSADIPRS(IP),IP=1,NPRS) |
||||
READ (IUSTNLIST,FMT=173) ((PSADITMK(IP,JT),IP=1,NPRS),JT=1,NTHTE) |
||||
173 FORMAT (5D15.7) |
||||
CLOSE (IUSTNLIST) |
||||
|
||||
RETURN |
||||
END |
||||
c c |
||||
c*********************************************************************c |
||||
c c |
||||
SUBROUTINE DPFCALC(PRS,SFP,PF,MIY,MJX,MKZH,TER_FOLLOW) |
||||
DOUBLE PRECISION PRS |
||||
DOUBLE PRECISION SFP |
||||
DOUBLE PRECISION PF |
||||
c |
||||
c Historically, this routine calculated the pressure at full sigma |
||||
c levels when RIP was specifically designed for MM4/MM5 output. |
||||
c With the new generalized RIP (Feb '02), this routine is still |
||||
c intended to calculate a set of pressure levels that bound the |
||||
c layers represented by the vertical grid points, although no such |
||||
c layer boundaries are assumed to be defined. The routine simply |
||||
c uses the midpoint between the pressures of the vertical grid |
||||
c points as the bounding levels. The array only contains mkzh |
||||
c levels, so the pressure of the top of the uppermost layer is |
||||
c actually excluded. The kth value of pf is the lower bounding |
||||
c pressure for the layer represented by kth data level. At the |
||||
c lower bounding level of the lowest model layer, it uses the |
||||
c surface pressure, unless the data set is pressure-level data, in |
||||
c which case it assumes the lower bounding pressure level is as far |
||||
c below the lowest vertical level as the upper bounding pressure |
||||
c level is above. |
||||
c |
||||
DIMENSION PRS(MIY,MJX,MKZH),SFP(MIY,MJX),PF(MIY,MJX,MKZH) |
||||
INTEGER TER_FOLLOW |
||||
c |
||||
C do j=1,mjx-1 Artifact of MM5 |
||||
DO J = 1,MJX |
||||
C do i=1,miy-1 staggered grid |
||||
DO I = 1,MIY |
||||
DO K = 1,MKZH |
||||
IF (K.EQ.MKZH) THEN |
||||
C terrain-following data |
||||
IF (TER_FOLLOW.EQ.1) THEN |
||||
PF(I,J,K) = SFP(I,J) |
||||
C pressure-level data |
||||
ELSE |
||||
PF(I,J,K) = .5D0* (3.D0*PRS(I,J,K)- |
||||
+ PRS(I,J,K-1)) |
||||
END IF |
||||
ELSE |
||||
PF(I,J,K) = .5D0* (PRS(I,J,K+1)+PRS(I,J,K)) |
||||
END IF |
||||
END DO |
||||
END DO |
||||
END DO |
||||
c |
||||
RETURN |
||||
END |
||||
c====================================================================== |
||||
c |
||||
c !IROUTINE: VIRTUAL -- Calculate virtual temperature (K) |
||||
c |
||||
c !DESCRIPTION: |
||||
c |
||||
c This function returns a single value of virtual temperature in |
||||
c K, given temperature in K and mixing ratio in kg/kg. For an |
||||
c array of virtual temperatures, use subroutine VIRTUAL_TEMP. |
||||
c |
||||
c !INPUT: |
||||
c RATMIX - water vapor mixing ratio (kg/kg) |
||||
c TEMP - temperature (K) |
||||
c |
||||
c !OUTPUT: |
||||
c TV - Virtual temperature (K) |
||||
c |
||||
c !ASSUMPTIONS: |
||||
c |
||||
c !REVISION HISTORY: |
||||
c 2009-March - Mark T. Stoelinga - from RIP4.5 |
||||
c 2010-August - J. Schramm - modified to run with NCL and ARW wrf output |
||||
c |
||||
c ------------------------------------------------------------------ |
||||
C NCLFORTSTART |
||||
DOUBLE PRECISION FUNCTION VIRTUAL(TEMP,RATMIX) |
||||
IMPLICIT NONE |
||||
DOUBLE PRECISION TEMP,RATMIX |
||||
C NCLEND |
||||
DOUBLE PRECISION EPS |
||||
EPS = 0.622D0 |
||||
VIRTUAL = TEMP* (EPS+RATMIX)/ (EPS* (1.D0+RATMIX)) |
||||
RETURN |
||||
END |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,402 @@
@@ -0,0 +1,402 @@
|
||||
C |
||||
C premaptform.f and maptform.f copied from RIP/src |
||||
C By So-Young Ha on Sep 29, 2005. |
||||
C |
||||
C |
||||
C NCLFORTSTART |
||||
SUBROUTINE DMAPTFORM(DSKMC,MIYCORS,MJXCORS,NPROJ,XLATC,XLONC, |
||||
+ TRUE1,TRUE2,RIY,RJX,RLAT,RLON,IDIR) |
||||
C |
||||
C Input vars: DSKMC, MIYCORS, MJXCORS, NPROJ, XLATC, XLONC, |
||||
C NPROJ, IDIR |
||||
C Input/output vars: RIY, RIX, RLAT |
||||
C Output vars: TRUE1, TRUE2, RLON |
||||
C |
||||
C |
||||
C Possible NCL interface: |
||||
C |
||||
C wrf_maptform(dskmc, miycors, mjxcors, nproj, xlatc, xlonc, riy, rjx, |
||||
C idir, rlat, rlon, opts) |
||||
C |
||||
C where opts could contain the TRUE1 and TRUE2 information in some fashion. |
||||
C |
||||
DOUBLE PRECISION PI_MPTF |
||||
DOUBLE PRECISION RPD_MPTF |
||||
DOUBLE PRECISION REARTH_MPTF |
||||
DOUBLE PRECISION DSKMC_MPTF |
||||
DOUBLE PRECISION XLONC_MPTF |
||||
DOUBLE PRECISION CIY_MPTF |
||||
DOUBLE PRECISION CJX_MPTF |
||||
DOUBLE PRECISION CONE_MPTF |
||||
DOUBLE PRECISION CONEI_MPTF |
||||
DOUBLE PRECISION C1_MPTF |
||||
DOUBLE PRECISION C2_MPTF |
||||
DOUBLE PRECISION YC_MPTF |
||||
DOUBLE PRECISION COTRUE1 |
||||
DOUBLE PRECISION YPOINT |
||||
DOUBLE PRECISION XPOINT |
||||
DOUBLE PRECISION DLON |
||||
C |
||||
c This routine converts a coarse domain dot grid point, <riy,rjx>, |
||||
c into a lat/lon point <rlat,rlon> if idir=1, or vice versa if |
||||
c idir=-1. It works for Lambert Conformal (LC,1), |
||||
c Polar Stereographic (ST,2), or Mercator (ME,3) projections, |
||||
c with any true latitide(s). |
||||
c It is assumed that premaptform has been called prior to this so |
||||
c that the proper constants have been placed in the common block |
||||
c called mptf, which should be declared in (and only in) the |
||||
c main program and routines maptform (this routine) and premaptform. |
||||
c |
||||
|
||||
C Input, Output Args |
||||
INTEGER MIYCORS,MJXCORS,NPROJ |
||||
DOUBLE PRECISION DSKMC,XLATC,XLONC,TRUE1,TRUE2 |
||||
INTEGER IDIR |
||||
C Latitude (-90->90 deg N) |
||||
DOUBLE PRECISION RLAT |
||||
C Longitude (-180->180 E) |
||||
DOUBLE PRECISION RLON |
||||
C Cartesian X coordinate |
||||
DOUBLE PRECISION RIY |
||||
C Cartesian Y coordinate |
||||
DOUBLE PRECISION RJX |
||||
C NCLEND |
||||
|
||||
|
||||
c =========== |
||||
c premaptform |
||||
c =========== |
||||
C 3.1415... |
||||
PI_MPTF = 4.D0*ATAN(1.D0) |
||||
C radians per degree |
||||
RPD_MPTF = PI_MPTF/180.D0 |
||||
C radius of planet, in km |
||||
REARTH_MPTF = 6370.949D0 |
||||
DSKMC_MPTF = DSKMC |
||||
XLONC_MPTF = XLONC |
||||
NPROJ_MPTF = NPROJ |
||||
CIY_MPTF = .5D0* (1.D0+MIYCORS) |
||||
CJX_MPTF = .5D0* (1.D0+MJXCORS) |
||||
c |
||||
C Mercator |
||||
IF (NPROJ_MPTF.EQ.3) THEN |
||||
c |
||||
TRUE1 = 0.D0 |
||||
TRUE2 = 0.D0 |
||||
IHM_MPTF = 1 |
||||
CONE_MPTF = 1.D0 |
||||
CONEI_MPTF = 1.D0 |
||||
C1_MPTF = 1.D0 |
||||
C2_MPTF = 1.D0 |
||||
YC_MPTF = REARTH_MPTF*LOG((1.D0+SIN(RPD_MPTF*XLATC))/ |
||||
+ COS(RPD_MPTF*XLATC)) |
||||
c |
||||
C Lambert Comformal or Polar Stereographic |
||||
ELSE |
||||
c |
||||
c Make sure xlatc, true1, and true2 are all in same hemisphere, |
||||
c and calculate ihm_mptf. |
||||
c |
||||
IF (XLATC.GT.0.D0 .AND. TRUE1.GT.0.D0 .AND. |
||||
+ TRUE2.GT.0.D0) THEN |
||||
IHM_MPTF = 1 |
||||
ELSE IF (XLATC.LT.0.D0 .AND. TRUE1.LT.0.D0 .AND. |
||||
+ TRUE2.LT.0.D0) THEN |
||||
IHM_MPTF = -1 |
||||
ELSE |
||||
WRITE (*,FMT=*) 'Invalid latitude parameters for map.' |
||||
STOP |
||||
END IF |
||||
c |
||||
c Calculate cone factor |
||||
c |
||||
IF (NPROJ_MPTF.EQ.1) THEN |
||||
IF (TRUE1.NE.TRUE2) THEN |
||||
CONE_MPTF = LOG10(COS(RPD_MPTF*TRUE1)/ |
||||
+ COS(RPD_MPTF*TRUE2))/ |
||||
+ LOG10(TAN(.25D0*PI_MPTF- |
||||
+ IHM_MPTF*.5D0*RPD_MPTF*TRUE1)/ |
||||
+ TAN(.25D0*PI_MPTF-IHM_MPTF*.5D0*RPD_MPTF* |
||||
+ TRUE2)) |
||||
ELSE |
||||
CONE_MPTF = COS(RPD_MPTF* (90.D0-IHM_MPTF*TRUE1)) |
||||
END IF |
||||
ELSE IF (NPROJ_MPTF.EQ.2) THEN |
||||
CONE_MPTF = 1.D0 |
||||
END IF |
||||
c |
||||
c Calculate other constants |
||||
c |
||||
CONEI_MPTF = 1.D0/CONE_MPTF |
||||
COTRUE1 = IHM_MPTF*90.D0 - TRUE1 |
||||
IF (NPROJ_MPTF.EQ.1) THEN |
||||
C1_MPTF = REARTH_MPTF*SIN(RPD_MPTF*COTRUE1)/ |
||||
+ (CONE_MPTF* (IHM_MPTF*TAN(.5D0*RPD_MPTF* |
||||
+ COTRUE1))**CONE_MPTF) |
||||
C2_MPTF = TAN(.5D0*RPD_MPTF*COTRUE1)* |
||||
+ (CONE_MPTF/ (IHM_MPTF*REARTH_MPTF*SIN(RPD_MPTF* |
||||
+ COTRUE1)))**CONEI_MPTF |
||||
YC_MPTF = -C1_MPTF* (IHM_MPTF* |
||||
+ TAN(.25D0* (IHM_MPTF*PI_MPTF- |
||||
+ 2.D0*RPD_MPTF*XLATC)))**CONE_MPTF |
||||
ELSE IF (NPROJ_MPTF.EQ.2) THEN |
||||
C1_MPTF = 1.D0 + COS(RPD_MPTF*COTRUE1) |
||||
C2_MPTF = 1.D0 |
||||
YC_MPTF = -REARTH_MPTF*SIN(.5D0*IHM_MPTF*PI_MPTF- |
||||
+ RPD_MPTF*XLATC)*C1_MPTF/ |
||||
+ (1.D0+COS(.5D0*IHM_MPTF*PI_MPTF-RPD_MPTF*XLATC)) |
||||
END IF |
||||
c |
||||
END IF |
||||
|
||||
c ======== |
||||
c maptform |
||||
c ======== |
||||
|
||||
IF (RLAT.EQ.-90.D0) PRINT *,'maptform:',RIY,RJX,RLAT,RLON,IDIR |
||||
|
||||
C First, deal with idir=1 |
||||
IF (IDIR.EQ.1) THEN |
||||
c |
||||
YPOINT = (RIY-CIY_MPTF)*DSKMC_MPTF + YC_MPTF |
||||
XPOINT = (RJX-CJX_MPTF)*DSKMC_MPTF |
||||
c |
||||
IF (NPROJ_MPTF.EQ.3) THEN |
||||
RLAT = (2.D0*ATAN(EXP(YPOINT/REARTH_MPTF))-.5D0*PI_MPTF)/ |
||||
+ RPD_MPTF |
||||
RLON = XLONC_MPTF + (XPOINT/REARTH_MPTF)/RPD_MPTF |
||||
ELSE IF (NPROJ_MPTF.EQ.1) THEN |
||||
RLAT = (.5D0*IHM_MPTF*PI_MPTF- |
||||
+ 2.D0*ATAN(C2_MPTF* (SQRT(XPOINT**2+ |
||||
+ YPOINT**2))**CONEI_MPTF))/RPD_MPTF |
||||
RLON = XLONC_MPTF + (CONEI_MPTF* |
||||
+ ATAN2(XPOINT,-IHM_MPTF*YPOINT))/RPD_MPTF |
||||
ELSE IF (NPROJ_MPTF.EQ.2) THEN |
||||
RLAT = (.5D0*IHM_MPTF*PI_MPTF- |
||||
+ IHM_MPTF*2.D0*ATAN(SQRT(XPOINT**2+ |
||||
+ YPOINT**2)/ (REARTH_MPTF*C1_MPTF)))/RPD_MPTF |
||||
IF (XPOINT.EQ.0.D0 .AND. YPOINT.EQ.0.D0) THEN |
||||
RLON = XLONC_MPTF |
||||
ELSE |
||||
RLON = XLONC_MPTF + (ATAN2(XPOINT,-IHM_MPTF*YPOINT))/ |
||||
+ RPD_MPTF |
||||
END IF |
||||
END IF |
||||
RLON = MOD(RLON+900.D0,360.D0) - 180.D0 |
||||
c |
||||
C Otherwise, deal with idir=-1 |
||||
ELSE |
||||
c |
||||
DLON = RLON - XLONC_MPTF |
||||
IF (DLON.LT.-180.D0) DLON = DLON + 360 |
||||
IF (DLON.GT.180.D0) DLON = DLON - 360 |
||||
IF (NPROJ_MPTF.EQ.3) THEN |
||||
YPOINT = REARTH_MPTF*LOG((1.D0+SIN(RPD_MPTF*RLAT))/ |
||||
+ COS(RPD_MPTF*RLAT)) |
||||
XPOINT = DLON*RPD_MPTF*REARTH_MPTF |
||||
ELSE IF (NPROJ_MPTF.EQ.1) THEN |
||||
YPOINT = -C1_MPTF* (IHM_MPTF* |
||||
+ TAN(.25D0* (IHM_MPTF*PI_MPTF-2.D0*RPD_MPTF* |
||||
+ RLAT)))**CONE_MPTF*COS(CONE_MPTF*RPD_MPTF*DLON) |
||||
XPOINT = IHM_MPTF*C1_MPTF* (IHM_MPTF* |
||||
+ TAN(.25D0* (IHM_MPTF*PI_MPTF- |
||||
+ 2.D0*RPD_MPTF*RLAT)))**CONE_MPTF* |
||||
+ SIN(CONE_MPTF*RPD_MPTF*DLON) |
||||
ELSE IF (NPROJ_MPTF.EQ.2) THEN |
||||
YPOINT = -REARTH_MPTF*SIN(.5D0*IHM_MPTF*PI_MPTF- |
||||
+ RPD_MPTF*RLAT)*C1_MPTF/ (1.D0+ |
||||
+ COS(.5D0*IHM_MPTF*PI_MPTF-RPD_MPTF*RLAT))* |
||||
+ COS(RPD_MPTF*DLON) |
||||
XPOINT = IHM_MPTF*REARTH_MPTF* |
||||
+ SIN(.5D0*IHM_MPTF*PI_MPTF-RPD_MPTF*RLAT)*C1_MPTF/ |
||||
+ (1.D0+COS(.5D0*IHM_MPTF*PI_MPTF-RPD_MPTF*RLAT))* |
||||
+ SIN(RPD_MPTF*DLON) |
||||
END IF |
||||
RIY = (YPOINT-YC_MPTF)/DSKMC_MPTF + CIY_MPTF |
||||
RJX = XPOINT/DSKMC_MPTF + CJX_MPTF |
||||
c |
||||
END IF |
||||
|
||||
RETURN |
||||
END |
||||
|
||||
C******************************************************** |
||||
C NCLFORTSTART |
||||
SUBROUTINE DBINT3D(DATA_OUT,OBSII,OBSJJ,DATA_IN,NX,NY,NZ,NOBSICRS, |
||||
+ NOBSJCRS,ICRS,JCRS) |
||||
C |
||||
C Possible NCL interface: |
||||
C |
||||
C data_out = wrf_bint3d(data_in,obsii,obsjj,icrs,jcrs) |
||||
C |
||||
C !!! 1_based_array (cols x rows) in fortran <=> 0_based_array |
||||
C (rows x cols) in NCL !!! |
||||
C !!! Include K-index to make a 3-D array !!! |
||||
C |
||||
C INPUT VARIABLES |
||||
C --------------- |
||||
INTEGER ICRS,JCRS,NX,NY,NZ |
||||
INTEGER NOBSJCRS,NOBSICRS |
||||
DOUBLE PRECISION OBSII(NOBSICRS,NOBSJCRS) |
||||
DOUBLE PRECISION OBSJJ(NOBSICRS,NOBSJCRS) |
||||
DOUBLE PRECISION DATA_IN(NX,NY,NZ) |
||||
|
||||
C OUTPUT |
||||
C --------------- |
||||
DOUBLE PRECISION DATA_OUT(NOBSICRS,NOBSJCRS,NZ) |
||||
C NCLEND |
||||
|
||||
C LOCAL |
||||
DOUBLE PRECISION OBSI,OBSJ |
||||
DOUBLE PRECISION DATA_OBS |
||||
C |
||||
|
||||
DO K = 1,NZ |
||||
DO J = 1,NOBSJCRS |
||||
DO I = 1,NOBSICRS |
||||
C grid index in lon |
||||
OBSI = OBSII(I,J) |
||||
C grid index in lat |
||||
OBSJ = OBSJJ(I,J) |
||||
DATA_OBS = 0.0D0 |
||||
CALL DBINT(DATA_OBS,OBSI,OBSJ,DATA_IN(1,1,K),NX,NY, |
||||
+ ICRS,JCRS) |
||||
DATA_OUT(I,J,K) = DATA_OBS |
||||
END DO |
||||
END DO |
||||
END DO |
||||
|
||||
RETURN |
||||
END |
||||
|
||||
|
||||
SUBROUTINE DBINT(PP,XX,YY,LIST,III,JJJ,ICRS,JCRS) |
||||
DOUBLE PRECISION PP |
||||
DOUBLE PRECISION X |
||||
DOUBLE PRECISION Y |
||||
DOUBLE PRECISION A |
||||
DOUBLE PRECISION B |
||||
DOUBLE PRECISION C |
||||
DOUBLE PRECISION D |
||||
DOUBLE PRECISION E |
||||
DOUBLE PRECISION F |
||||
DOUBLE PRECISION G |
||||
DOUBLE PRECISION H |
||||
DOUBLE PRECISION QQ |
||||
C |
||||
C --- BI-LINEAR INTERPOLATION AMONG FOUR GRID VALUES |
||||
C |
||||
C INPUT : LIST, XX, YY |
||||
C OUTPUT: PP |
||||
C |
||||
INTEGER ICRS,JCRS,III,JJJ |
||||
DOUBLE PRECISION XX,YY |
||||
DOUBLE PRECISION LIST(III,JJJ),STL(4,4) |
||||
|
||||
C MASS GRID IN WRF (I-> west-east, J-> south-north) |
||||
C |
||||
IB = III - ICRS |
||||
JB = JJJ - JCRS |
||||
PP = 0.0D0 |
||||
N = 0 |
||||
I = INT(XX+0.00001D0) |
||||
J = INT(YY+0.00001D0) |
||||
X = XX - I |
||||
Y = YY - J |
||||
IF ((ABS(X).GT.0.00001D0) .OR. (ABS(Y).GT.0.00001D0)) THEN |
||||
C |
||||
DO 2 K = 1,4 |
||||
KK = I + K |
||||
DO 2 L = 1,4 |
||||
STL(K,L) = 0.D0 |
||||
LL = J + L |
||||
IF ((KK.GE.1) .AND. (KK.LE.IB) .AND. (LL.LE.JB) .AND. |
||||
+ (LL.GE.1)) THEN |
||||
STL(K,L) = LIST(KK,LL) |
||||
N = N + 1 |
||||
C .. a zero value inside the domain being set to 1.E-12: |
||||
IF (STL(K,L).EQ.0.D0) STL(K,L) = 1.D-12 |
||||
END IF |
||||
2 CONTINUE |
||||
C |
||||
CALL DONED(A,X,STL(1,1),STL(2,1),STL(3,1),STL(4,1)) |
||||
CALL DONED(B,X,STL(1,2),STL(2,2),STL(3,2),STL(4,2)) |
||||
CALL DONED(C,X,STL(1,3),STL(2,3),STL(3,3),STL(4,3)) |
||||
CALL DONED(D,X,STL(1,4),STL(2,4),STL(3,4),STL(4,4)) |
||||
C |
||||
C .. CHECK TANGENT LINEAR OF ONED, SAVE BASIC STATE: |
||||
C WRITE(20) XX,YY,Y,A,B,C,D |
||||
C |
||||
CALL DONED(PP,Y,A,B,C,D) |
||||
IF (N.NE.16) THEN |
||||
CALL DONED(E,Y,STL(1,1),STL(1,2),STL(1,3),STL(1,4)) |
||||
CALL DONED(F,Y,STL(2,1),STL(2,2),STL(2,3),STL(2,4)) |
||||
CALL DONED(G,Y,STL(3,1),STL(3,2),STL(3,3),STL(3,4)) |
||||
CALL DONED(H,Y,STL(4,1),STL(4,2),STL(4,3),STL(4,4)) |
||||
C .. CHECK TANGENT LINEAR OF ONED, SAVE BASIC STATE: |
||||
C WRITE(20) XX,YY,X,E,F,G,H |
||||
C |
||||
CALL DONED(QQ,X,E,F,G,H) |
||||
PP = (PP+QQ)*0.5D0 |
||||
END IF |
||||
C |
||||
ELSE |
||||
C |
||||
PP = LIST(I,J) |
||||
END IF |
||||
C |
||||
RETURN |
||||
END |
||||
|
||||
|
||||
|
||||
SUBROUTINE DONED(Y,X,A,B,C,D) |
||||
DOUBLE PRECISION Y |
||||
DOUBLE PRECISION X |
||||
DOUBLE PRECISION A |
||||
DOUBLE PRECISION B |
||||
DOUBLE PRECISION C |
||||
DOUBLE PRECISION D |
||||
DOUBLE PRECISION ONE |
||||
C |
||||
C .. Input : X, A, B, C, D |
||||
C Output: Y |
||||
C 1, 2, 3, and 4 points interpolation: |
||||
C In this subroutine, the zero value of A, B, C, D means that |
||||
C point outside the domain. |
||||
C |
||||
C .. 1-point: |
||||
C .. take the value at the second point: |
||||
IF (X.EQ.0.D0) THEN |
||||
ONE = B |
||||
C .. take the value at the third point: |
||||
ELSE IF (X.EQ.1.D0) THEN |
||||
ONE = C |
||||
C .. the point X outside the range: |
||||
ELSE IF (B*C.EQ.0.D0) THEN |
||||
ONE = 0.D0 |
||||
ELSE |
||||
IF (A*D.EQ.0.D0) THEN |
||||
C .. 3-point interpolation: |
||||
IF (A.NE.0.D0) THEN |
||||
ONE = B + X* (0.5D0* (C-A)+X* (0.5D0* (C+A)-B)) |
||||
ELSE IF (D.NE.0.D0) THEN |
||||
ONE = C + (1.0D0-X)* (0.5D0* (B-D)+ |
||||
+ (1.0D0-X)* (0.5D0* (B+D)-C)) |
||||
ELSE |
||||
C .. 2-point interpolation: |
||||
ONE = B* (1.0D0-X) + C*X |
||||
END IF |
||||
ELSE |
||||
C .. 4-point interpolation: |
||||
ONE = (1.0D0-X)* (B+X* (0.5D0* (C-A)+X* (0.5D0* (C+A)-B))) |
||||
+ + X* (C+ (1.0D0-X)* (0.5D0* (B-D)+ (1.0D0- |
||||
+ X)* (0.5D0* (B+D)-C))) |
||||
END IF |
||||
END IF |
||||
C |
||||
Y = ONE |
||||
C |
||||
RETURN |
||||
|
||||
END |
@ -0,0 +1,763 @@
@@ -0,0 +1,763 @@
|
||||
#include <stdio.h> |
||||
#include "wrapper.h" |
||||
|
||||
extern void NGCALLF(wrfcttcalc,WRFCTTCALC)(double *, double *, double *,
|
||||
double *, double *, double *,
|
||||
double *, double *, int *,
|
||||
int *, int *, int *); |
||||
|
||||
extern NclDimRec *get_wrf_dim_info(int,int,int,ng_size_t*); |
||||
|
||||
|
||||
NhlErrorTypes wrf_ctt_W( void ) |
||||
{ |
||||
|
||||
/*
|
||||
* Input variables |
||||
*/ |
||||
/*
|
||||
* Argument # 0 |
||||
*/ |
||||
void *pres; |
||||
double *tmp_pres; |
||||
int ndims_pres; |
||||
ng_size_t dsizes_pres[NCL_MAX_DIMENSIONS]; |
||||
NclBasicDataTypes type_pres; |
||||
|
||||
/*
|
||||
* Argument # 1 |
||||
*/ |
||||
void *tk; |
||||
double *tmp_tk; |
||||
int ndims_tk; |
||||
ng_size_t dsizes_tk[NCL_MAX_DIMENSIONS]; |
||||
NclBasicDataTypes type_tk; |
||||
|
||||
/*
|
||||
* Argument # 2 |
||||
*/ |
||||
void *qci; |
||||
double *tmp_qci; |
||||
int ndims_qci; |
||||
ng_size_t dsizes_qci[NCL_MAX_DIMENSIONS]; |
||||
NclBasicDataTypes type_qci; |
||||
|
||||
/*
|
||||
* Argument # 3 |
||||
*/ |
||||
void *qcw; |
||||
double *tmp_qcw; |
||||
int ndims_qcw; |
||||
ng_size_t dsizes_qcw[NCL_MAX_DIMENSIONS]; |
||||
NclBasicDataTypes type_qcw; |
||||
|
||||
/*
|
||||
* Argument # 4 |
||||
*/ |
||||
void *qvp; |
||||
double *tmp_qvp; |
||||
int ndims_qvp; |
||||
ng_size_t dsizes_qvp[NCL_MAX_DIMENSIONS]; |
||||
NclBasicDataTypes type_qvp; |
||||
|
||||
/*
|
||||
* Argument # 5 |
||||
*/ |
||||
void *ght; |
||||
double *tmp_ght; |
||||
int ndims_ght; |
||||
ng_size_t dsizes_ght[NCL_MAX_DIMENSIONS]; |
||||
NclBasicDataTypes type_ght; |
||||
|
||||
/*
|
||||
* Argument # 6 |
||||
*/ |
||||
void *ter; |
||||
double *tmp_ter; |
||||
int ndims_ter; |
||||
ng_size_t dsizes_ter[NCL_MAX_DIMENSIONS]; |
||||
NclBasicDataTypes type_ter; |
||||
|
||||
/*
|
||||
* Arguments # 7 |
||||
*/ |
||||
int *haveqci; |
||||
|
||||
/*
|
||||
* Variable for getting/setting dimension name info. |
||||
*/ |
||||
NclDimRec *dim_info = NULL; |
||||
NclDimRec *dim_info_ght = NULL; |
||||
|
||||
/*
|
||||
* Return variable and attributes |
||||
*/ |
||||
void *ctt; |
||||
NclQuark *description, *units; |
||||
char *cdescription, *cunits; |
||||
double *tmp_ctt; |
||||
int ndims_ctt; |
||||
ng_size_t *dsizes_ctt; |
||||
NclBasicDataTypes type_ctt; |
||||
NclObjClass type_obj_ctt; |
||||
|
||||
/*
|
||||
* Various |
||||
*/ |
||||
ng_size_t nlev, nlat, nlon, nlevlatlon, nlatlon; |
||||
ng_size_t index_pres, index_ter, index_ctt; |
||||
ng_size_t i, size_leftmost, size_output; |
||||
int inlev, inlat, inlon; |
||||
|
||||
/*
|
||||
* Variables for returning the output array with attributes attached. |
||||
*/ |
||||
int att_id; |
||||
ng_size_t dsizes[1]; |
||||
NclMultiDValData att_md, return_md; |
||||
NclVar tmp_var; |
||||
NclStackEntry return_data; |
||||
|
||||
/*
|
||||
* Retrieve parameters. |
||||
* |
||||
* Note any of the pointer parameters can be set to NULL, which |
||||
* implies you don't care about its value. |
||||
*/ |
||||
/*
|
||||
* Get argument # 0 |
||||
*/ |
||||
|
||||
/*
|
||||
* Get argument # 1 |
||||
*/ |
||||
pres = (void*)NclGetArgValue( |
||||
0, |
||||
8, |
||||
&ndims_pres, |
||||
dsizes_pres, |
||||
NULL, |
||||
NULL, |
||||
&type_pres, |
||||
DONT_CARE); |
||||
|
||||
if(ndims_pres < 3 || ndims_pres > 4) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: The pres array must be 3D or 4D"); |
||||
return(NhlFATAL); |
||||
} |
||||
|
||||
nlev = dsizes_pres[ndims_pres-3]; |
||||
nlat = dsizes_pres[ndims_pres-2]; |
||||
nlon = dsizes_pres[ndims_pres-1]; |
||||
|
||||
/*
|
||||
* Test dimension sizes. |
||||
*/ |
||||
if(nlev > INT_MAX || nlat > INT_MAX || nlon > INT_MAX) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: one of bottom_top, south_north, or west_east is greater than INT_MAX"); |
||||
return(NhlFATAL); |
||||
} |
||||
inlev = (int) nlev; |
||||
inlat = (int) nlat; |
||||
inlon = (int) nlon; |
||||
|
||||
/*
|
||||
* Get argument # 1 |
||||
*/ |
||||
tk = (void*)NclGetArgValue( |
||||
1, |
||||
8, |
||||
&ndims_tk, |
||||
dsizes_tk, |
||||
NULL, |
||||
NULL, |
||||
&type_tk, |
||||
DONT_CARE); |
||||
|
||||
/*
|
||||
* Check dimension sizes. |
||||
*/ |
||||
if(ndims_tk != ndims_pres) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: The tk and pres arrays must have the same dimensionality"); |
||||
return(NhlFATAL); |
||||
} |
||||
else { |
||||
for(i = 0; i < ndims_pres; i++) { |
||||
if(dsizes_tk[i] != dsizes_pres[i]) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: The tk and pres arrays must have the same dimensionality"); |
||||
return(NhlFATAL); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* Get argument # 2 |
||||
*/ |
||||
qci = (void*)NclGetArgValue( |
||||
2, |
||||
8, |
||||
&ndims_qci, |
||||
dsizes_qci, |
||||
NULL, |
||||
NULL, |
||||
&type_qci, |
||||
DONT_CARE); |
||||
|
||||
/*
|
||||
* Check dimension sizes. |
||||
*/ |
||||
if(ndims_qci != ndims_pres) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: The qci and pres arrays must have the same dimensionality"); |
||||
return(NhlFATAL); |
||||
} |
||||
else { |
||||
for(i = 0; i < ndims_pres; i++) { |
||||
if(dsizes_qci[i] != dsizes_pres[i]) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: The qci and pres arrays must have the same dimensionality"); |
||||
return(NhlFATAL); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Get argument # 3 |
||||
*/ |
||||
qcw = (void*)NclGetArgValue( |
||||
3, |
||||
8, |
||||
&ndims_qcw, |
||||
dsizes_qcw, |
||||
NULL, |
||||
NULL, |
||||
&type_qcw, |
||||
DONT_CARE); |
||||
|
||||
/*
|
||||
* Check dimension sizes. |
||||
*/ |
||||
if(ndims_qcw != ndims_pres) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: The qcw and pres arrays must have the same dimensionality"); |
||||
return(NhlFATAL); |
||||
} |
||||
else { |
||||
for(i = 0; i < ndims_pres; i++) { |
||||
if(dsizes_qcw[i] != dsizes_pres[i]) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: The qcw and pres arrays must have the same dimensionality"); |
||||
return(NhlFATAL); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Get argument # 4 |
||||
*/ |
||||
qvp = (void*)NclGetArgValue( |
||||
4, |
||||
8, |
||||
&ndims_qvp, |
||||
dsizes_qvp, |
||||
NULL, |
||||
NULL, |
||||
&type_qvp, |
||||
DONT_CARE); |
||||
|
||||
/*
|
||||
* Check dimension sizes. |
||||
*/ |
||||
if(ndims_qvp != ndims_pres) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: The qvp and pres arrays must have the same dimensionality"); |
||||
return(NhlFATAL); |
||||
} |
||||
else { |
||||
for(i = 0; i < ndims_pres; i++) { |
||||
if(dsizes_qvp[i] != dsizes_pres[i]) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: The qvp and pres arrays must have the same dimensionality"); |
||||
return(NhlFATAL); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Get argument # 5 |
||||
*/ |
||||
ght = (void*)NclGetArgValue( |
||||
5, |
||||
8, |
||||
&ndims_ght, |
||||
dsizes_ght, |
||||
NULL, |
||||
NULL, |
||||
&type_ght, |
||||
DONT_CARE); |
||||
|
||||
/*
|
||||
* Check dimension sizes. |
||||
*/ |
||||
if(ndims_ght != ndims_pres) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: The ght and pres arrays must have the same dimensionality"); |
||||
return(NhlFATAL); |
||||
} |
||||
else { |
||||
for(i = 0; i < ndims_pres; i++) { |
||||
if(dsizes_ght[i] != dsizes_pres[i]) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: The ght and pres arrays must have the same dimensionality"); |
||||
return(NhlFATAL); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Get argument # 6 |
||||
*/ |
||||
ter = (void*)NclGetArgValue( |
||||
6, |
||||
8, |
||||
&ndims_ter, |
||||
dsizes_ter, |
||||
NULL, |
||||
NULL, |
||||
&type_ter, |
||||
DONT_CARE); |
||||
|
||||
/*
|
||||
* Check dimension sizes for ter. It can either be 2D, or one fewer |
||||
* dimensions than pres. |
||||
*/ |
||||
if(ndims_ter != 2 && ndims_ter != (ndims_pres-1)) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: ter must either be a 2D array dimensioned south_north x west_east or it must have the same dimensionality as the pres array, minus the level dimension"); |
||||
return(NhlFATAL); |
||||
} |
||||
|
||||
if(ndims_ter == 2) { |
||||
if(dsizes_ter[0] != nlat || dsizes_ter[1] != nlon) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: The dimensions of ter must be south_north x west_east"); |
||||
return(NhlFATAL); |
||||
} |
||||
} |
||||
else { |
||||
for(i = 0; i < ndims_pres-3; i++) { |
||||
if(dsizes_ter[i] != dsizes_pres[i]) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: ter must either be a 2D array dimensioned south_north x west_east or it must have the same dimensionality as the pres array, minus the level dimension"); |
||||
return(NhlFATAL); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* Get argument # 7 |
||||
*/ |
||||
haveqci = (int*)NclGetArgValue( |
||||
7, |
||||
8, |
||||
NULL, |
||||
NULL, |
||||
NULL, |
||||
NULL, |
||||
NULL, |
||||
DONT_CARE); |
||||
|
||||
/*
|
||||
* Calculate size of leftmost dimensions. |
||||
*/ |
||||
size_leftmost = 1; |
||||
for(i = 0; i < ndims_pres-3; i++) size_leftmost *= dsizes_pres[i]; |
||||
|
||||
/*
|
||||
* Allocate space for coercing input arrays. If any of the input |
||||
* is already double, then we don't need to allocate space for |
||||
* temporary arrays, because we'll just change the pointer into |
||||
* the void array appropriately. |
||||
*/ |
||||
/*
|
||||
* Allocate space for tmp_pres. |
||||
*/ |
||||
nlatlon = nlat * nlon; |
||||
nlevlatlon = nlev * nlatlon; |
||||
|
||||
if(type_pres != NCL_double) { |
||||
tmp_pres = (double *)calloc(nlevlatlon,sizeof(double)); |
||||
if(tmp_pres == NULL) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: Unable to allocate memory for coercing pressure array to double"); |
||||
return(NhlFATAL); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Allocate space for tmp_tk. |
||||
*/ |
||||
if(type_tk != NCL_double) { |
||||
tmp_tk = (double *)calloc(nlevlatlon,sizeof(double)); |
||||
if(tmp_tk == NULL) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: Unable to allocate memory for coercing tk array to double"); |
||||
return(NhlFATAL); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Allocate space for tmp_qci. |
||||
*/ |
||||
if(type_qci != NCL_double) { |
||||
tmp_qci = (double *)calloc(nlevlatlon,sizeof(double)); |
||||
if(tmp_qci == NULL) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: Unable to allocate memory for coercing qci array to double"); |
||||
return(NhlFATAL); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Allocate space for tmp_qcw. |
||||
*/ |
||||
if(type_qcw != NCL_double) { |
||||
tmp_qcw = (double *)calloc(nlevlatlon,sizeof(double)); |
||||
if(tmp_qcw == NULL) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: Unable to allocate memory for coercing qcw array to double"); |
||||
return(NhlFATAL); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Allocate space for tmp_qvp. |
||||
*/ |
||||
if(type_qvp != NCL_double) { |
||||
tmp_qvp = (double *)calloc(nlevlatlon,sizeof(double)); |
||||
if(tmp_qvp == NULL) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: Unable to allocate memory for coercing qvp array to double"); |
||||
return(NhlFATAL); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Allocate space for tmp_ght. |
||||
*/ |
||||
if(type_ght != NCL_double) { |
||||
tmp_ght = (double *)calloc(nlevlatlon,sizeof(double)); |
||||
if(tmp_ght == NULL) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: Unable to allocate memory for coercing ght array to double"); |
||||
return(NhlFATAL); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Coerce ter to double, if necessary. |
||||
*/ |
||||
if(ndims_ter == 2) { |
||||
tmp_ter = coerce_input_double(ter,type_ter,nlatlon,0,NULL,NULL); |
||||
if(tmp_ter == NULL) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: Unable to allocate memory for coercing ter array to double"); |
||||
return(NhlFATAL); |
||||
} |
||||
} |
||||
else { |
||||
/*
|
||||
* Allocate space for tmp_ter. |
||||
*/ |
||||
if(type_ter != NCL_double) { |
||||
tmp_ter = (double *)calloc(nlatlon,sizeof(double)); |
||||
if(tmp_ter == NULL) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: Unable to allocate memory for coercing ter array to double"); |
||||
return(NhlFATAL); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* The output type defaults to float, unless one or more input
|
||||
* arrays are double. |
||||
*/ |
||||
if(type_pres == NCL_double || type_tk == NCL_double ||
|
||||
type_qci == NCL_double || type_qcw == NCL_double ||
|
||||
type_qvp == NCL_double || type_ght == NCL_double ||
|
||||
type_ter == NCL_double) { |
||||
type_ctt = NCL_double; |
||||
type_obj_ctt = nclTypedoubleClass; |
||||
} |
||||
else { |
||||
type_ctt = NCL_float; |
||||
type_obj_ctt = nclTypefloatClass; |
||||
} |
||||
|
||||
/*
|
||||
* Allocate space for output array. |
||||
*/ |
||||
size_output = size_leftmost * nlatlon; |
||||
if(type_ctt != NCL_double) { |
||||
ctt = (void *)calloc(size_output, sizeof(float)); |
||||
tmp_ctt = (double *)calloc(nlatlon,sizeof(double)); |
||||
if(ctt == NULL || tmp_ctt == NULL) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: Unable to allocate memory for temporary output array"); |
||||
return(NhlFATAL); |
||||
} |
||||
} |
||||
else { |
||||
ctt = (void *)calloc(size_output, sizeof(double)); |
||||
if(ctt == NULL) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: Unable to allocate memory for output array"); |
||||
return(NhlFATAL); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Allocate space for output dimension sizes and set them. |
||||
*/ |
||||
ndims_ctt = ndims_pres-1; |
||||
dsizes_ctt = (ng_size_t*)calloc(ndims_ctt,sizeof(ng_size_t));
|
||||
if( dsizes_ctt == NULL ) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: Unable to allocate memory for holding dimension sizes"); |
||||
return(NhlFATAL); |
||||
} |
||||
for(i = 0; i < ndims_ctt-2; i++) dsizes_ctt[i] = dsizes_pres[i]; |
||||
dsizes_ctt[ndims_ctt-2] = nlat; |
||||
dsizes_ctt[ndims_ctt-1] = nlon; |
||||
|
||||
/*
|
||||
* Get dimension info to see if we have named dimensions. |
||||
* Using "ght" here, because it is more likely than "pres" |
||||
* to have metadata attached to it.
|
||||
*
|
||||
* This will be used for return variable. |
||||
*/ |
||||
dim_info_ght = get_wrf_dim_info(5,8,ndims_ght,dsizes_ght); |
||||
if(dim_info_ght != NULL) { |
||||
dim_info = malloc(sizeof(NclDimRec)*ndims_ctt); |
||||
if(dim_info == NULL) { |
||||
NhlPError(NhlFATAL,NhlEUNKNOWN,"wrf_ctt: Unable to allocate memory for holding dimension information"); |
||||
return(NhlFATAL); |
||||
} |
||||
for(i = 0; i < ndims_ght-3; i++) { |
||||
dim_info[i] = dim_info_ght[i]; |
||||
} |
||||
dim_info[ndims_ctt-1] = dim_info_ght[ndims_ght-1]; |
||||
dim_info[ndims_ctt-2] = dim_info_ght[ndims_ght-2]; |
||||
} |
||||
|
||||
/*
|
||||
* Loop across leftmost dimensions and call the Fortran routine for each |
||||
* subsection of the input arrays. |
||||
*/ |
||||
index_pres = index_ter = index_ctt = 0; |
||||
|
||||
for(i = 0; i < size_leftmost; i++) { |
||||
/*
|
||||
* Coerce subsection of pres (tmp_pres) to double if necessary. |
||||
*/ |
||||
if(type_pres != NCL_double) { |
||||
coerce_subset_input_double(pres,tmp_pres,index_pres, |
||||
type_pres,nlevlatlon,0,NULL,NULL); |
||||
} |
||||
else { |
||||
tmp_pres = &((double*)pres)[index_pres]; |
||||
} |
||||
|
||||
/*
|
||||
* Coerce subsection of tk (tmp_tk) to double if necessary. |
||||
*/ |
||||
if(type_tk != NCL_double) { |
||||
coerce_subset_input_double(tk,tmp_tk,index_pres,type_tk, |
||||
nlevlatlon,0,NULL,NULL); |
||||
} |
||||
else { |
||||
tmp_tk = &((double*)tk)[index_pres]; |
||||
} |
||||
|
||||
/*
|
||||
* Coerce subsection of qci (tmp_qci) to double if necessary. |
||||
*/ |
||||
if(type_qci != NCL_double) { |
||||
coerce_subset_input_double(qci,tmp_qci,index_pres,type_qci, |
||||
nlevlatlon,0,NULL,NULL); |
||||
} |
||||
else { |
||||
tmp_qci = &((double*)qci)[index_pres]; |
||||
} |
||||
|
||||
/*
|
||||
* Coerce subsection of qcw (tmp_qcw) to double if necessary. |
||||
*/ |
||||
if(type_qcw != NCL_double) { |
||||
coerce_subset_input_double(qcw,tmp_qcw,index_pres,type_qcw, |
||||
nlevlatlon,0,NULL,NULL); |
||||
} |
||||
else { |
||||
tmp_qcw = &((double*)qcw)[index_pres]; |
||||
} |
||||
|
||||
/*
|
||||
* Coerce subsection of qvp (tmp_qvp) to double if necessary. |
||||
*/ |
||||
if(type_qvp != NCL_double) { |
||||
coerce_subset_input_double(qvp,tmp_qvp,index_pres,type_qvp, |
||||
nlevlatlon,0,NULL,NULL); |
||||
} |
||||
else { |
||||
tmp_qvp = &((double*)qvp)[index_pres]; |
||||
} |
||||
|
||||
/*
|
||||
* Coerce subsection of ght (tmp_ght) to double if necessary. |
||||
*/ |
||||
if(type_ght != NCL_double) { |
||||
coerce_subset_input_double(ght,tmp_ght,index_pres,type_ght, |
||||
nlevlatlon,0,NULL,NULL); |
||||
} |
||||
else { |
||||
tmp_ght = &((double*)ght)[index_pres]; |
||||
} |
||||
|
||||
/*
|
||||
* Coerce subsection of ter (tmp_ter) to double if necessary. |
||||
*/ |
||||
if(ndims_ter != 2) { |
||||
if(type_ter != NCL_double) { |
||||
coerce_subset_input_double(ter,tmp_ter,index_ter,type_ter, |
||||
nlatlon,0,NULL,NULL); |
||||
} |
||||
else { |
||||
tmp_ter = &((double*)ter)[index_ter]; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Point temporary output array to void output array if appropriate. |
||||
*/ |
||||
if(type_ctt == NCL_double) { |
||||
tmp_ctt = &((double*)ctt)[index_ctt]; |
||||
} |
||||
|
||||
/*
|
||||
* Call the Fortran routine. |
||||
*/ |
||||
NGCALLF(wrfcttcalc,WRFCTTCALC)(tmp_pres, tmp_tk, tmp_qci, tmp_qcw, |
||||
tmp_qvp, tmp_ght, tmp_ter, tmp_ctt, |
||||
haveqci,&inlev, &inlat, &inlon); |
||||
|
||||
/*
|
||||
* Coerce output back to float if necessary. |
||||
*/ |
||||
if(type_ctt == NCL_float) { |
||||
coerce_output_float_only(ctt,tmp_ctt,nlatlon, |
||||
index_ctt); |
||||
} |
||||
index_pres += nlevlatlon; |
||||
index_ctt += nlatlon; |
||||
if(ndims_ter != 2) {
|
||||
index_ter += nlatlon; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Free unneeded memory. |
||||
*/ |
||||
if(type_pres != NCL_double) NclFree(tmp_pres); |
||||
if(type_tk != NCL_double) NclFree(tmp_tk); |
||||
if(type_qci != NCL_double) NclFree(tmp_qci); |
||||
if(type_qcw != NCL_double) NclFree(tmp_qcw); |
||||
if(type_qvp != NCL_double) NclFree(tmp_qvp); |
||||
if(type_ght != NCL_double) NclFree(tmp_ght); |
||||
if(type_ter != NCL_double) NclFree(tmp_ter); |
||||
if(type_ctt != NCL_double) NclFree(tmp_ctt); |
||||
|
||||
/*
|
||||
* Set up some attributes ("description" and "units") to return. |
||||
*/ |
||||
cdescription = (char *)calloc(22,sizeof(char)); |
||||
cunits = (char *)calloc(2,sizeof(char)); |
||||
strcpy(cdescription,"Cloud Top Temperature"); |
||||
strcpy(cunits,"K"); |
||||
description = (NclQuark*)NclMalloc(sizeof(NclQuark)); |
||||
units = (NclQuark*)NclMalloc(sizeof(NclQuark)); |
||||
*description = NrmStringToQuark(cdescription); |
||||
*units = NrmStringToQuark(cunits); |
||||
free(cdescription); |
||||
free(cunits); |
||||
|
||||
/*
|
||||
* Set up return value. |
||||
*/ |
||||
return_md = _NclCreateVal( |
||||
NULL, |
||||
NULL, |
||||
Ncl_MultiDValData, |
||||
0, |
||||
(void*)ctt, |
||||
NULL, |
||||
ndims_ctt, |
||||
dsizes_ctt, |
||||
TEMPORARY, |
||||
NULL, |
||||
type_obj_ctt |
||||
); |
||||
/*
|
||||
* Set up attributes to return. |
||||
*/ |
||||
att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL); |
||||
|
||||
dsizes[0] = 1; |
||||
att_md = _NclCreateVal( |
||||
NULL, |
||||
NULL, |
||||
Ncl_MultiDValData, |
||||
0, |
||||
(void*)description, |
||||
NULL, |
||||
1, |
||||
dsizes, |
||||
TEMPORARY, |
||||
NULL, |
||||
(NclObjClass)nclTypestringClass |
||||
); |
||||
_NclAddAtt( |
||||
att_id, |
||||
"description", |
||||
att_md, |
||||
NULL |
||||
); |
||||
|
||||
att_md = _NclCreateVal( |
||||
NULL, |
||||
NULL, |
||||
Ncl_MultiDValData, |
||||
0, |
||||
(void*)units, |
||||
NULL, |
||||
1, |
||||
dsizes, |
||||
TEMPORARY, |
||||
NULL, |
||||
(NclObjClass)nclTypestringClass |
||||
); |
||||
_NclAddAtt( |
||||
att_id, |
||||
"units", |
||||
att_md, |
||||
NULL |
||||
); |
||||
|
||||
tmp_var = _NclVarCreate( |
||||
NULL, |
||||
NULL, |
||||
Ncl_Var, |
||||
0, |
||||
NULL, |
||||
return_md, |
||||
dim_info, |
||||
att_id, |
||||
NULL, |
||||
RETURNVAR, |
||||
NULL, |
||||
TEMPORARY |
||||
); |
||||
|
||||
if(dim_info != NULL) NclFree(dim_info); |
||||
NclFree(dim_info_ght); |
||||
|
||||
/*
|
||||
* Return output grid and attributes to NCL. |
||||
*/ |
||||
return_data.kind = NclStk_VAR; |
||||
return_data.u.data_var = tmp_var; |
||||
_NclPlaceReturn(return_data); |
||||
return(NhlNOERROR); |
||||
} |
@ -0,0 +1,117 @@
@@ -0,0 +1,117 @@
|
||||
C NCLFORTSTART |
||||
subroutine wrfcttcalc(prs,tk,qci,qcw,qvp,ght,ter,ctt, |
||||
& haveqci,nz,ns,ew) |
||||
|
||||
implicit none |
||||
integer nz,ns,ew,haveqci |
||||
double precision ght(ew,ns,nz) |
||||
double precision prs(ew,ns,nz),tk(ew,ns,nz) |
||||
double precision qci(ew,ns,nz),qcw(ew,ns,nz) |
||||
double precision qvp(ew,ns,nz) |
||||
double precision ctt(ew,ns),ter(ew,ns) |
||||
c double precision znfac(nz) |
||||
C NCLEND |
||||
c |
||||
c |
||||
integer i,j,k,mjx,miy,mkzh,ripk,wrfout |
||||
double precision vt,rgas,grav,opdepthu,opdepthd,dp |
||||
double precision ratmix,eps,arg1,arg2,agl_hgt,ussalr |
||||
double precision abscoefi,abscoef,fac,prsctt,celkel |
||||
c double precision ght(ew,ns,nz),stuff(ew,ns) |
||||
double precision pf(ns,ew,nz),p1,p2 |
||||
c |
||||
c |
||||
mjx = ew |
||||
miy = ns |
||||
mkzh = nz |
||||
eps = 0.622d0 |
||||
ussalr = .0065d0 ! deg C per m |
||||
rgas = 287.04d0 !J/K/kg |
||||
grav = 9.81d0 |
||||
abscoefi = .272d0 ! cloud ice absorption coefficient in m^2/g |
||||
abscoef =.145d0 ! cloud water absorption coefficient in m^2/g |
||||
celkel = 273.15d0 |
||||
wrfout = 1 |
||||
|
||||
|
||||
cCalculate the surface pressure |
||||
do j=1,ew |
||||
do i=1,ns |
||||
ratmix = .001d0*qvp(j,i,1) |
||||
arg1 = eps + ratmix |
||||
arg2 = eps*(1.+ratmix) |
||||
vt = tk(j,i,1) * arg1/arg2 !Virtual temperature |
||||
agl_hgt = ght(j,i,nz) - ter(j,i) |
||||
arg1 = -grav/(rgas*ussalr) |
||||
pf(i,j,nz) = prs(j,i,1)* |
||||
& (vt/(vt+ussalr*(agl_hgt)))**(arg1) |
||||
enddo |
||||
enddo |
||||
|
||||
|
||||
c |
||||
do j=1,ew |
||||
do i=1,ns |
||||
do k=1,nz-1 |
||||
ripk = nz-k+1 |
||||
pf(i,j,k)=.5d0*(prs(j,i,ripk)+prs(j,i,ripk-1)) |
||||
enddo |
||||
enddo |
||||
enddo |
||||
|
||||
do 190 j=1,ew |
||||
do 190 i=1,ns |
||||
opdepthd=0.d0 |
||||
k=0 |
||||
|
||||
c |
||||
c Integrate downward from model top, calculating path at full |
||||
c model vertical levels. |
||||
c |
||||
20 opdepthu=opdepthd |
||||
k=k+1 |
||||
ripk = nz-k+1 |
||||
|
||||
if (k.eq.1) then |
||||
dp=200.d0*(pf(i,j,1)-prs(j,i,nz)) ! should be in Pa |
||||
else |
||||
dp=100.d0*(pf(i,j,k)-pf(i,j,k-1)) ! should be in Pa |
||||
endif |
||||
if (haveqci .eq. 0) then |
||||
if (tk(i,j,k).lt.celkel) then |
||||
c Note: abscoefi is m**2/g, qcw is g/kg, |
||||
c so no convrsion needed |
||||
opdepthd=opdepthu+abscoefi*qcw(j,i,k)*dp/grav |
||||
else |
||||
opdepthd=opdepthu+abscoef*qcw(j,i,k)*dp/grav |
||||
endif |
||||
else |
||||
opdepthd=opdepthd+(abscoef*qcw(j,i,ripk)+ |
||||
& abscoefi*qci(j,i,ripk))*dp/grav |
||||
endif |
||||
|
||||
if (opdepthd.lt.1..and.k.lt.nz) then |
||||
goto 20 |
||||
elseif (opdepthd.lt.1..and.k.eq.nz) then |
||||
prsctt=prs(j,i,1) |
||||
else |
||||
fac=(1.-opdepthu)/(opdepthd-opdepthu) |
||||
prsctt=pf(i,j,k-1)+fac*(pf(i,j,k)-pf(i,j,k-1)) |
||||
prsctt=min(prs(j,i,1),max(prs(j,i,nz),prsctt)) |
||||
endif |
||||
|
||||
do 30 k=2,nz |
||||
ripk = nz-k+1 |
||||
p1 = prs(j,i,ripk+1) |
||||
p2 = prs(j,i,ripk) |
||||
if (prsctt .ge. p1 .and. prsctt .le .p2) then |
||||
fac=(prsctt-p1)/(p2-p1) |
||||
arg1 = fac*(tk(j,i,ripk)-tk(j,i,ripk+1))-celkel |
||||
ctt(j,i) = tk(j,i,ripk+1)+ arg1 |
||||
goto 40 |
||||
endif |
||||
30 continue |
||||
40 continue |
||||
190 continue |
||||
return |
||||
end |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,109 @@
@@ -0,0 +1,109 @@
|
||||
c-------------------------------------------------------- |
||||
C NCLFORTSTART |
||||
SUBROUTINE DCOMPUTEPV(PV,U,V,THETA,PRS,MSFU,MSFV,MSFT,COR,DX,DY, |
||||
+ NX,NY,NZ,NXP1,NYP1) |
||||
|
||||
IMPLICIT NONE |
||||
INTEGER NX,NY,NZ,NXP1,NYP1 |
||||
DOUBLE PRECISION U(NXP1,NY,NZ),V(NX,NYP1,NZ),PRS(NX,NY,NZ) |
||||
DOUBLE PRECISION THETA(NX,NY,NZ),PV(NX,NY,NZ) |
||||
DOUBLE PRECISION MSFU(NXP1,NY),MSFV(NX,NYP1),MSFT(NX,NY) |
||||
DOUBLE PRECISION COR(NX,NY) |
||||
DOUBLE PRECISION DX,DY |
||||
C NCLEND |
||||
INTEGER KP1,KM1,JP1,JM1,IP1,IM1,I,J,K |
||||
DOUBLE PRECISION DSY,DSX,DP,DUDY,DVDX,DUDP,DVDP,DTHDP,AVORT |
||||
DOUBLE PRECISION DTHDX,DTHDY,MM |
||||
|
||||
c print*,'nx,ny,nz,nxp1,nyp1' |
||||
c print*,nx,ny,nz,nxp1,nyp1 |
||||
DO K = 1,NZ |
||||
KP1 = MIN(K+1,NZ) |
||||
KM1 = MAX(K-1,1) |
||||
DO J = 1,NY |
||||
JP1 = MIN(J+1,NY) |
||||
JM1 = MAX(J-1,1) |
||||
DO I = 1,NX |
||||
IP1 = MIN(I+1,NX) |
||||
IM1 = MAX(I-1,1) |
||||
c print *,jp1,jm1,ip1,im1 |
||||
DSX = (IP1-IM1)*DX |
||||
DSY = (JP1-JM1)*DY |
||||
MM = MSFT(I,J)*MSFT(I,J) |
||||
c print *,j,i,u(i,jp1,k),msfu(i,jp1),u(i,jp1,k)/msfu(i,jp1) |
||||
DUDY = 0.5D0* (U(I,JP1,K)/MSFU(I,JP1)+ |
||||
+ U(I+1,JP1,K)/MSFU(I+1,JP1)- |
||||
+ U(I,JM1,K)/MSFU(I,JM1)- |
||||
+ U(I+1,JM1,K)/MSFU(I+1,JM1))/DSY*MM |
||||
DVDX = 0.5D0* (V(IP1,J,K)/MSFV(IP1,J)+ |
||||
+ V(IP1,J+1,K)/MSFV(IP1,J+1)- |
||||
+ V(IM1,J,K)/MSFV(IM1,J)- |
||||
+ V(IM1,J+1,K)/MSFV(IM1,J+1))/DSX*MM |
||||
AVORT = DVDX - DUDY + COR(I,J) |
||||
DP = PRS(I,J,KP1) - PRS(I,J,KM1) |
||||
DUDP = 0.5D0* (U(I,J,KP1)+U(I+1,J,KP1)-U(I,J,KM1)- |
||||
+ U(I+1,J,KM1))/DP |
||||
DVDP = 0.5D0* (V(I,J,KP1)+V(I,J+1,KP1)-V(I,J,KM1)- |
||||
+ V(I,J+1,KM1))/DP |
||||
DTHDP = (THETA(I,J,KP1)-THETA(I,J,KM1))/DP |
||||
DTHDX = (THETA(IP1,J,K)-THETA(IM1,J,K))/DSX*MSFT(I,J) |
||||
DTHDY = (THETA(I,JP1,K)-THETA(I,JM1,K))/DSY*MSFT(I,J) |
||||
PV(I,J,K) = -9.81D0* (DTHDP*AVORT-DVDP*DTHDX+ |
||||
+ DUDP*DTHDY)*10000.D0 |
||||
c if(i.eq.300 .and. j.eq.300) then |
||||
c print*,'avort,dudp,dvdp,dthdp,dthdx,dthdy,pv' |
||||
c print*,avort,dudp,dvdp,dthdp,dthdx,dthdy,pv(i,j,k) |
||||
c endif |
||||
PV(I,J,K) = PV(I,J,K)*1.D2 |
||||
END DO |
||||
END DO |
||||
END DO |
||||
RETURN |
||||
END |
||||
|
||||
c-------------------------------------------------------- |
||||
C NCLFORTSTART |
||||
SUBROUTINE DCOMPUTEABSVORT(AV,U,V,MSFU,MSFV,MSFT,COR,DX,DY,NX,NY, |
||||
+ NZ,NXP1,NYP1) |
||||
|
||||
IMPLICIT NONE |
||||
INTEGER NX,NY,NZ,NXP1,NYP1 |
||||
DOUBLE PRECISION U(NXP1,NY,NZ),V(NX,NYP1,NZ) |
||||
DOUBLE PRECISION AV(NX,NY,NZ) |
||||
DOUBLE PRECISION MSFU(NXP1,NY),MSFV(NX,NYP1),MSFT(NX,NY) |
||||
DOUBLE PRECISION COR(NX,NY) |
||||
DOUBLE PRECISION DX,DY |
||||
C NCLEND |
||||
INTEGER KP1,KM1,JP1,JM1,IP1,IM1,I,J,K |
||||
DOUBLE PRECISION DSY,DSX,DP,DUDY,DVDX,DUDP,DVDP,DTHDP,AVORT |
||||
DOUBLE PRECISION DTHDX,DTHDY,MM |
||||
|
||||
c print*,'nx,ny,nz,nxp1,nyp1' |
||||
c print*,nx,ny,nz,nxp1,nyp1 |
||||
DO K = 1,NZ |
||||
DO J = 1,NY |
||||
JP1 = MIN(J+1,NY) |
||||
JM1 = MAX(J-1,1) |
||||
DO I = 1,NX |
||||
IP1 = MIN(I+1,NX) |
||||
IM1 = MAX(I-1,1) |
||||
c print *,jp1,jm1,ip1,im1 |
||||
DSX = (IP1-IM1)*DX |
||||
DSY = (JP1-JM1)*DY |
||||
MM = MSFT(I,J)*MSFT(I,J) |
||||
c print *,j,i,u(i,jp1,k),msfu(i,jp1),u(i,jp1,k)/msfu(i,jp1) |
||||
DUDY = 0.5D0* (U(I,JP1,K)/MSFU(I,JP1)+ |
||||
+ U(I+1,JP1,K)/MSFU(I+1,JP1)- |
||||
+ U(I,JM1,K)/MSFU(I,JM1)- |
||||
+ U(I+1,JM1,K)/MSFU(I+1,JM1))/DSY*MM |
||||
DVDX = 0.5D0* (V(IP1,J,K)/MSFV(IP1,J)+ |
||||
+ V(IP1,J+1,K)/MSFV(IP1,J+1)- |
||||
+ V(IM1,J,K)/MSFV(IM1,J)- |
||||
+ V(IM1,J+1,K)/MSFV(IM1,J+1))/DSX*MM |
||||
AVORT = DVDX - DUDY + COR(I,J) |
||||
AV(I,J,K) = AVORT*1.D5 |
||||
END DO |
||||
END DO |
||||
END DO |
||||
RETURN |
||||
END |
@ -0,0 +1,100 @@
@@ -0,0 +1,100 @@
|
||||
|
||||
C *************************************************************** |
||||
C * Storm Relative Helicity (SRH) is a measure of the * |
||||
C * streamwise vorticity within the inflow environment of a * |
||||
C * convective storm. It is calculated by multiplying the * |
||||
C * storm-relative inflow velocity vector (Vh-C) by the * |
||||
C * streamwise vorticity (Zh) and integrating this quantity * |
||||
C * over the inflow depth (lowest 1-3 km layers above ground * |
||||
C * level). It describes the extent to which corkscrew-like * |
||||
C * motion occurs (similar to the spiraling motion of an * |
||||
C * American football). SRH corresponds to the transfer of * |
||||
C * vorticity from the environment to an air parcel in * |
||||
C * convective motion and is used to predict the potential * |
||||
C * for tornadic development (cyclonic updraft rotation) in * |
||||
C * right-moving supercells. * |
||||
C * * |
||||
C * There is no clear threshold value for SRH when forecasting * |
||||
C * supercells, since the formation of supercells appears to be * |
||||
C * related more strongly to the deeper layer vertical shear. * |
||||
C * Larger values of 0-3-km SRH (greater than 250 m**2/s**2) * |
||||
C * and 0-1-km SRH (greater than 100 m**2/s**2), suggest an * |
||||
C * increased threat of tornadoes with supercells. For SRH, * |
||||
C * larger values are generally better, but there are no clear * |
||||
C * "boundaries" between non-tornadic and significant tornadic * |
||||
C * supercells. * |
||||
C * * |
||||
C * SRH < 100 (lowest 1 km): cutoff value * |
||||
C * SRH = 150-299: supercells possible with weak tornadoes * |
||||
C * SRH = 300-499: very favorable to supercell development and * |
||||
C * strong tornadoes * |
||||
C * SRH > 450 : violent tornadoes * |
||||
C *************************************************************** |
||||
C NCLFORTSTART |
||||
subroutine dcalrelhl(u, v, ght, ter, top, sreh, miy, mjx, mkzh) |
||||
implicit none |
||||
integer miy, mjx, mkzh |
||||
double precision u(miy,mjx,mkzh), v(miy,mjx,mkzh), |
||||
& ght(miy,mjx,mkzh),top,ter(miy,mjx), |
||||
& sreh(miy,mjx) |
||||
C NCLEND |
||||
C |
||||
C This helicity code was provided by Dr. Craig Mattocks, and |
||||
C verified by Cindy Bruyere to produce results equivalent to |
||||
C those generated by RIP4. (The code came from RIP4?) |
||||
C |
||||
double precision pi, dtr, dpr |
||||
double precision dh, sdh, su, sv, ua, va, asp, adr, bsp, bdr |
||||
double precision cu, cv, x, sum |
||||
integer i, j, k, k10, k3, ktop |
||||
parameter (pi=3.14159265d0, dtr=pi/180.d0, dpr=180.d0/pi) |
||||
|
||||
do 15 j = 1, mjx-1 |
||||
do 15 i = 1, miy-1 |
||||
sdh = 0.d0 |
||||
su = 0.d0 |
||||
sv = 0.d0 |
||||
k3 = 0 |
||||
k10 = 0 |
||||
ktop = 0 |
||||
do 6 k = mkzh, 2, -1 |
||||
if (((ght(i,j,k) - ter(i,j)) .gt. 10000.d0) .and. |
||||
& (k10 .eq. 0)) then |
||||
k10 = k |
||||
go to 8 |
||||
endif |
||||
if (((ght(i,j,k) - ter(i,j)) .gt. top) .and. |
||||
& (ktop .eq. 0)) ktop = k |
||||
if (((ght(i,j,k) - ter(i,j)) .gt. 3000.d0) .and. |
||||
& (k3 .eq. 0)) k3 = k |
||||
6 continue |
||||
8 continue |
||||
if (k10 .eq. 0) k10=2 |
||||
do k = k3, k10, -1 |
||||
dh = ght(i,j,k-1) - ght(i,j,k) |
||||
sdh = sdh + dh |
||||
su = su + 0.5d0*dh*(u(i,j,k-1)+u(i,j,k)) |
||||
sv = sv + 0.5d0*dh*(v(i,j,k-1)+v(i,j,k)) |
||||
enddo |
||||
ua = su / sdh |
||||
va = sv / sdh |
||||
asp = sqrt(ua*ua + va*va) |
||||
if (ua .eq. 0.d0 .and. va .eq. 0.d0) then |
||||
adr = 0.d0 |
||||
else |
||||
adr = dpr * (pi + atan2(ua,va)) |
||||
endif |
||||
bsp = 0.75d0 * asp |
||||
bdr = adr + 30.d0 |
||||
if (bdr .gt. 360.d0) bdr = bdr-360.d0 |
||||
cu = -bsp * sin(bdr*dtr) |
||||
cv = -bsp * cos(bdr*dtr) |
||||
sum = 0.d0 |
||||
do 12 k = mkzh-1, ktop, -1 |
||||
x = ((u(i,j,k)-cu) * (v(i,j,k)-v(i,j,k+1))) - |
||||
& ((v(i,j,k)-cv) * (u(i,j,k)-u(i,j,k+1))) |
||||
sum = sum + x |
||||
12 continue |
||||
sreh(i,j) = -sum |
||||
15 continue |
||||
end |
@ -0,0 +1,264 @@
@@ -0,0 +1,264 @@
|
||||
c====================================================================== |
||||
c |
||||
c !IROUTINE: WETBULBCALC -- Calculate wet bulb temperature (C) |
||||
c |
||||
c !DESCRIPTION: |
||||
c |
||||
c Calculates wet bulb temperature in C, given pressure in |
||||
c temperature in K and mixing ratio in kg/kg. |
||||
c |
||||
c !INPUT: |
||||
c nx - index for x dimension |
||||
c ny - index for y dimension |
||||
c nz - index for z dimension |
||||
c prs - pressure (mb) |
||||
c tmk - temperature (K) |
||||
c qvp - water vapor mixing ratio (kg/kg) |
||||
c |
||||
c !OUTPUT: |
||||
c twb - Wet bulb temperature (C) |
||||
c |
||||
c !ASSUMPTIONS: |
||||
c |
||||
c !REVISION HISTORY: |
||||
c 2009-March - Mark T. Stoelinga - from RIP4.5 |
||||
c 2010-August - J. Schramm |
||||
c 2014-March - A. Jaye - modified to run with NCL and ARW wrf output |
||||
c |
||||
c !INTERFACE: |
||||
c ------------------------------------------------------------------ |
||||
C NCLFORTSTART |
||||
subroutine wetbulbcalc(prs,tmk,qvp,twb,nx,ny,nz,psafile) |
||||
implicit none |
||||
integer nx, ny, nz |
||||
double precision prs(nz,ny,nx) |
||||
double precision tmk(nz,ny,nx) |
||||
double precision qvp(nz,ny,nx) |
||||
double precision twb(nz,ny,nx) |
||||
character*(*) psafile |
||||
C NCLEND |
||||
integer i,j,k |
||||
integer jtch,jt,ipch,ip |
||||
double precision q, t, p, e, tlcl, eth |
||||
double precision fracip,fracip2,fracjt,fracjt2 |
||||
double precision PSADITHTE(150),PSADIPRS(150),PSADITMK(150,150) |
||||
double precision tonpsadiabat |
||||
double precision eps,tlclc1,tlclc2,tlclc3,tlclc4,gamma |
||||
double precision gammamd,thtecon1,thtecon2,thtecon3,celkel |
||||
double precision rgas,rgasmd,cp,cpmd |
||||
|
||||
c |
||||
c Before looping, set lookup table for getting temperature on |
||||
c a pseudoadiabat. |
||||
c |
||||
CALL DLOOKUP_TABLE(PSADITHTE,PSADIPRS,PSADITMK,psafile) |
||||
|
||||
c Define constants |
||||
|
||||
rgas=287.04 !J/K/kg |
||||
rgasmd=.608 ! rgas_moist=rgas*(1.+rgasmd*qvp) |
||||
cp=1004. ! J/K/kg Note: not using Bolton's value of 1005.7 |
||||
cpmd=.887 ! cp_moist=cp*(1.+cpmd*qvp) |
||||
eps=0.622 |
||||
tlclc1=2840. |
||||
tlclc2=3.5 |
||||
tlclc3=4.805 |
||||
tlclc4=55. |
||||
gamma=rgas/cp |
||||
gammamd=rgasmd-cpmd ! gamma_moist=gamma*(1.+gammamd*qvp) |
||||
thtecon1=3376. ! K |
||||
thtecon2=2.54 |
||||
thtecon3=.81 |
||||
celkel=273.15 |
||||
|
||||
DO k=1,nx |
||||
DO j=1,ny |
||||
DO i=1,nz |
||||
q=dmax1(qvp(i,j,k),1.d-15) |
||||
t=tmk(i,j,k) |
||||
p=prs(i,j,k)/100. |
||||
e=q*p/(eps+q) |
||||
tlcl=tlclc1/(dlog(t**tlclc2/e)-tlclc3)+tlclc4 |
||||
eth=t*(1000./p)**(gamma*(1.+gammamd*q))* |
||||
& exp((thtecon1/tlcl-thtecon2)*q*(1.+thtecon3*q)) |
||||
|
||||
|
||||
c |
||||
c Now we need to find the temperature (in K) on a moist adiabat |
||||
c (specified by eth in K) given pressure in hPa. It uses a |
||||
c lookup table, with data that was generated by the Bolton (1980) |
||||
c formula for theta_e. |
||||
c |
||||
c First check if pressure is less than min pressure in lookup table. |
||||
c If it is, assume parcel is so dry that the given theta-e value can |
||||
c be interpretted as theta, and get temperature from the simple dry |
||||
c theta formula. |
||||
c |
||||
|
||||
if (p.le.psadiprs(150)) then |
||||
tonpsadiabat=eth*(p/1000.)**gamma |
||||
else |
||||
c |
||||
c Otherwise, look for the given thte/prs point in the lookup table. |
||||
c |
||||
do jtch=1,150-1 |
||||
if (eth.ge.psadithte(jtch).and.eth.lt. |
||||
& psadithte(jtch+1)) then |
||||
jt=jtch |
||||
goto 213 |
||||
endif |
||||
enddo |
||||
jt=-1 |
||||
213 continue |
||||
do ipch=1,150-1 |
||||
if (p.le.psadiprs(ipch).and.p.gt.psadiprs(ipch+1)) then |
||||
ip=ipch |
||||
goto 215 |
||||
endif |
||||
enddo |
||||
ip=-1 |
||||
215 continue |
||||
if (jt.eq.-1.or.ip.eq.-1) then |
||||
print*, |
||||
& 'Outside of lookup table bounds. prs,thte=',p,eth |
||||
stop |
||||
endif |
||||
fracjt=(eth-psadithte(jt))/(psadithte(jt+1)-psadithte(jt)) |
||||
fracjt2=1.-fracjt |
||||
fracip=(psadiprs(ip)-p)/(psadiprs(ip)-psadiprs(ip+1)) |
||||
fracip2=1.-fracip |
||||
if (psaditmk(ip,jt).gt.1e9.or.psaditmk(ip+1,jt).gt.1e9.or. |
||||
& psaditmk(ip,jt+1).gt.1e9.or. |
||||
& psaditmk(ip+1,jt+1).gt.1e9) then |
||||
print*, |
||||
& 'Tried to access missing tmperature in lookup table.' |
||||
print*, |
||||
& 'Prs and Thte probably unreasonable. prs,thte=' |
||||
& ,p,eth |
||||
stop |
||||
endif |
||||
tonpsadiabat=fracip2*fracjt2*psaditmk(ip ,jt )+ |
||||
& fracip *fracjt2*psaditmk(ip+1,jt )+ |
||||
& fracip2*fracjt *psaditmk(ip ,jt+1)+ |
||||
& fracip *fracjt *psaditmk(ip+1,jt+1) |
||||
endif |
||||
|
||||
twb(i,j,k)=tonpsadiabat |
||||
|
||||
ENDDO |
||||
ENDDO |
||||
ENDDO |
||||
|
||||
c |
||||
return |
||||
end |
||||
c====================================================================== |
||||
c |
||||
c !IROUTINE: omgcalc -- Calculate omega (dp/dt) |
||||
c |
||||
c !DESCRIPTION: |
||||
c |
||||
c Calculate approximate omega, based on vertical velocity w (dz/dt). |
||||
c It is approximate because it cannot take into account the vertical |
||||
c motion of pressure surfaces. |
||||
c |
||||
c !INPUT: |
||||
c mx - index for x dimension |
||||
c my - index for y dimension |
||||
c mx - index for vertical dimension |
||||
c qvp - water vapor mixing ratio (kg/kg) |
||||
c tmk - temperature (K) |
||||
c www - vertical velocity (m/s) |
||||
c prs - pressure (Pa) |
||||
c |
||||
c !OUTPUT: |
||||
c omg - omega (Pa/sec) |
||||
c |
||||
c !ASSUMPTIONS: |
||||
c |
||||
c !REVISION HISTORY: |
||||
c 2009-March - Mark T. Stoelinga - from RIP4.5 |
||||
c 2010-August - J. Schramm |
||||
c 2014-March - A. Jaye - modified to run with NCL and ARW wrf output |
||||
c |
||||
c ------------------------------------------------------------------ |
||||
c NCLFORTSTART |
||||
subroutine omgcalc(qvp,tmk,www,prs,omg,mx,my,mz) |
||||
implicit none |
||||
integer mx, my, mz |
||||
double precision qvp(mz,my,mx) |
||||
double precision tmk(mz,my,mx) |
||||
double precision www(mz,my,mx) |
||||
double precision prs(mz,my,mx) |
||||
double precision omg(mz,my,mx) |
||||
c NCLEND |
||||
c Local variables |
||||
integer i, j, k |
||||
double precision grav,rgas,eps |
||||
c |
||||
c Constants |
||||
c |
||||
grav=9.81 ! m/s**2 |
||||
rgas=287.04 !J/K/kg |
||||
eps=0.622 |
||||
|
||||
do k=1,mx |
||||
do j=1,my |
||||
do i=1,mz |
||||
omg(i,j,k)=-grav*prs(i,j,k)/ |
||||
& (rgas*((tmk(i,j,k)*(eps+qvp(i,j,k)))/ |
||||
& (eps*(1.+qvp(i,j,k)))))*www(i,j,k) |
||||
enddo |
||||
enddo |
||||
enddo |
||||
c |
||||
return |
||||
end |
||||
c====================================================================== |
||||
c |
||||
c !IROUTINE: VIRTUAL_TEMP -- Calculate virtual temperature (K) |
||||
c |
||||
c !DESCRIPTION: |
||||
c |
||||
c Calculates virtual temperature in K, given temperature |
||||
c in K and mixing ratio in kg/kg. |
||||
c |
||||
c !INPUT: |
||||
c NX - index for x dimension |
||||
c NY - index for y dimension |
||||
c NZ - index for z dimension |
||||
c RATMIX - water vapor mixing ratio (kg/kg) |
||||
c TEMP - temperature (K) |
||||
c |
||||
c !OUTPUT: |
||||
c TV - Virtual temperature (K) |
||||
c |
||||
c !ASSUMPTIONS: |
||||
c |
||||
c !REVISION HISTORY: |
||||
c 2009-March - Mark T. Stoelinga - from RIP4.5 |
||||
c 2010-August - J. Schramm |
||||
c 2014-March - A. Jaye - modified to run with NCL and ARW wrf output |
||||
c |
||||
c ------------------------------------------------------------------ |
||||
C NCLFORTSTART |
||||
SUBROUTINE VIRTUAL_TEMP(TEMP,RATMIX,TV,NX,NY,NZ) |
||||
IMPLICIT NONE |
||||
INTEGER NX,NY,NZ |
||||
DOUBLE PRECISION TEMP(NZ,NY,NX) |
||||
DOUBLE PRECISION RATMIX(NZ,NY,NX) |
||||
DOUBLE PRECISION TV(NZ,NY,NX) |
||||
C NCLEND |
||||
INTEGER I,J,K |
||||
DOUBLE PRECISION EPS |
||||
EPS = 0.622D0 |
||||
DO K=1,NX |
||||
DO J=1,NY |
||||
DO I=1,NZ |
||||
TV(I,J,K) = TEMP(I,J,K)* (EPS+RATMIX(I,J,K))/ |
||||
& (EPS* (1.D0+RATMIX(I,J,K))) |
||||
ENDDO |
||||
ENDDO |
||||
ENDDO |
||||
RETURN |
||||
END |
@ -0,0 +1,771 @@
@@ -0,0 +1,771 @@
|
||||
C NCLFORTSTART |
||||
SUBROUTINE DCOMPUTEPI(PI,PRESSURE,NX,NY,NZ) |
||||
IMPLICIT NONE |
||||
INTEGER NX,NY,NZ |
||||
DOUBLE PRECISION PI(NX,NY,NZ) |
||||
DOUBLE PRECISION PRESSURE(NX,NY,NZ) |
||||
C NCLEND |
||||
|
||||
INTEGER I,J,K |
||||
DOUBLE PRECISION P1000MB,R_D,CP |
||||
PARAMETER (P1000MB=100000.D0,R_D=287.D0,CP=7.D0*R_D/2.D0) |
||||
|
||||
DO K = 1,NZ |
||||
DO J = 1,NY |
||||
DO I = 1,NX |
||||
PI(I,J,K) = (PRESSURE(I,J,K)/P1000MB)** (R_D/CP) |
||||
END DO |
||||
END DO |
||||
END DO |
||||
|
||||
END |
||||
|
||||
C NCLFORTSTART |
||||
SUBROUTINE DCOMPUTETK(TK,PRESSURE,THETA,NX) |
||||
IMPLICIT NONE |
||||
INTEGER NX |
||||
DOUBLE PRECISION PI |
||||
DOUBLE PRECISION PRESSURE(NX) |
||||
DOUBLE PRECISION THETA(NX) |
||||
DOUBLE PRECISION TK(NX) |
||||
C NCLEND |
||||
|
||||
INTEGER I |
||||
DOUBLE PRECISION P1000MB,R_D,CP |
||||
PARAMETER (P1000MB=100000.D0,R_D=287.D0,CP=7.D0*R_D/2.D0) |
||||
|
||||
DO I = 1,NX |
||||
PI = (PRESSURE(I)/P1000MB)** (R_D/CP) |
||||
TK(I) = PI*THETA(I) |
||||
END DO |
||||
|
||||
END |
||||
|
||||
C NCLFORTSTART |
||||
SUBROUTINE DINTERP3DZ(V3D,V2D,Z,LOC,NX,NY,NZ,VMSG) |
||||
IMPLICIT NONE |
||||
INTEGER NX,NY,NZ |
||||
DOUBLE PRECISION V3D(NX,NY,NZ),V2D(NX,NY) |
||||
DOUBLE PRECISION Z(NX,NY,NZ) |
||||
DOUBLE PRECISION LOC |
||||
DOUBLE PRECISION VMSG |
||||
C NCLEND |
||||
|
||||
INTEGER I,J,KP,IP,IM |
||||
LOGICAL INTERP |
||||
DOUBLE PRECISION HEIGHT,W1,W2 |
||||
|
||||
HEIGHT = LOC |
||||
|
||||
c does vertical coordinate increase or decrease with increasing k? |
||||
c set offset appropriately |
||||
|
||||
IP = 0 |
||||
IM = 1 |
||||
IF (Z(1,1,1).GT.Z(1,1,NZ)) THEN |
||||
IP = 1 |
||||
IM = 0 |
||||
END IF |
||||
|
||||
DO I = 1,NX |
||||
DO J = 1,NY |
||||
C Initialize to missing. Was initially hard-coded to -999999. |
||||
V2D(I,J) = VMSG |
||||
INTERP = .false. |
||||
KP = NZ |
||||
|
||||
DO WHILE ((.NOT.INTERP) .AND. (KP.GE.2)) |
||||
|
||||
IF (((Z(I,J,KP-IM).LE.HEIGHT).AND. (Z(I,J, |
||||
+ KP-IP).GT.HEIGHT))) THEN |
||||
W2 = (HEIGHT-Z(I,J,KP-IM))/ |
||||
+ (Z(I,J,KP-IP)-Z(I,J,KP-IM)) |
||||
W1 = 1.D0 - W2 |
||||
V2D(I,J) = W1*V3D(I,J,KP-IM) + W2*V3D(I,J,KP-IP) |
||||
INTERP = .true. |
||||
END IF |
||||
KP = KP - 1 |
||||
|
||||
END DO |
||||
|
||||
END DO |
||||
END DO |
||||
|
||||
RETURN |
||||
END |
||||
|
||||
C NCLFORTSTART |
||||
SUBROUTINE DZSTAG(ZNEW,NX,NY,NZ,Z,NXZ,NYZ,NZZ,TERRAIN) |
||||
IMPLICIT NONE |
||||
INTEGER NX,NY,NZ,NXZ,NYZ,NZZ |
||||
DOUBLE PRECISION ZNEW(NX,NY,NZ),Z(NXZ,NYZ,NZZ) |
||||
DOUBLE PRECISION TERRAIN(NXZ,NYZ) |
||||
C NCLEND |
||||
|
||||
INTEGER I,J,K,II,IM1,JJ,JM1 |
||||
|
||||
c check for u, v, or w (x,y,or z) staggering |
||||
c |
||||
c for x and y stag, avg z to x, y, point |
||||
c |
||||
IF (NX.GT.NXZ) THEN |
||||
|
||||
DO K = 1,NZ |
||||
DO J = 1,NY |
||||
DO I = 1,NX |
||||
II = MIN0(I,NXZ) |
||||
IM1 = MAX0(I-1,1) |
||||
ZNEW(I,J,K) = 0.5D0* (Z(II,J,K)+Z(IM1,J,K)) |
||||
END DO |
||||
END DO |
||||
END DO |
||||
|
||||
ELSE IF (NY.GT.NYZ) THEN |
||||
|
||||
DO K = 1,NZ |
||||
DO J = 1,NY |
||||
JJ = MIN0(J,NYZ) |
||||
JM1 = MAX0(J-1,1) |
||||
DO I = 1,NX |
||||
ZNEW(I,J,K) = 0.5D0* (Z(I,JJ,K)+Z(I,JM1,K)) |
||||
END DO |
||||
END DO |
||||
END DO |
||||
c |
||||
c w (z) staggering |
||||
c |
||||
ELSE IF (NZ.GT.NZZ) THEN |
||||
|
||||
DO J = 1,NY |
||||
DO I = 1,NX |
||||
ZNEW(I,J,1) = TERRAIN(I,J) |
||||
END DO |
||||
END DO |
||||
|
||||
DO K = 2,NZ |
||||
DO J = 1,NY |
||||
DO I = 1,NX |
||||
ZNEW(I,J,K) = ZNEW(I,J,K-1) + |
||||
+ 2.D0* (Z(I,J,K-1)-ZNEW(I,J,K-1)) |
||||
END DO |
||||
END DO |
||||
END DO |
||||
|
||||
END IF |
||||
|
||||
RETURN |
||||
END |
||||
|
||||
C NCLFORTSTART |
||||
SUBROUTINE DINTERP2DXY(V3D,V2D,XY,NX,NY,NZ,NXY) |
||||
IMPLICIT NONE |
||||
INTEGER NX,NY,NZ,NXY |
||||
DOUBLE PRECISION V3D(NX,NY,NZ),V2D(NXY,NZ) |
||||
DOUBLE PRECISION XY(2,NXY) |
||||
C NCLEND |
||||
|
||||
INTEGER I,J,K,IJ |
||||
DOUBLE PRECISION W11,W12,W21,W22,WX,WY |
||||
|
||||
DO IJ = 1,NXY |
||||
|
||||
I = MAX0(1,MIN0(NX-1,INT(XY(1,IJ)+1))) |
||||
J = MAX0(1,MIN0(NY-1,INT(XY(2,IJ)+1))) |
||||
WX = DBLE(I+1) - (XY(1,IJ)+1) |
||||
WY = DBLE(J+1) - (XY(2,IJ)+1) |
||||
W11 = WX*WY |
||||
W21 = (1.D0-WX)*WY |
||||
W12 = WX* (1.D0-WY) |
||||
W22 = (1.D0-WX)* (1.D0-WY) |
||||
DO K = 1,NZ |
||||
V2D(IJ,K) = W11*V3D(I,J,K) + W21*V3D(I+1,J,K) + |
||||
+ W12*V3D(I,J+1,K) + W22*V3D(I+1,J+1,K) |
||||
END DO |
||||
END DO |
||||
|
||||
RETURN |
||||
END |
||||
|
||||
C NCLFORTSTART |
||||
SUBROUTINE DINTERP1D(V_IN,V_OUT,Z_IN,Z_OUT,NZ_IN,NZ_OUT,VMSG) |
||||
IMPLICIT NONE |
||||
INTEGER NZ_IN,NZ_OUT |
||||
DOUBLE PRECISION V_IN(NZ_IN),Z_IN(NZ_IN) |
||||
DOUBLE PRECISION V_OUT(NZ_OUT),Z_OUT(NZ_OUT) |
||||
DOUBLE PRECISION VMSG |
||||
C NCLEND |
||||
|
||||
INTEGER KP,K,IM,IP |
||||
LOGICAL INTERP |
||||
DOUBLE PRECISION HEIGHT,W1,W2 |
||||
|
||||
c does vertical coordinate increase of decrease with increasing k? |
||||
c set offset appropriately |
||||
|
||||
IP = 0 |
||||
IM = 1 |
||||
IF (Z_IN(1).GT.Z_IN(NZ_IN)) THEN |
||||
IP = 1 |
||||
IM = 0 |
||||
END IF |
||||
|
||||
DO K = 1,NZ_OUT |
||||
V_OUT(K) = VMSG |
||||
|
||||
INTERP = .false. |
||||
KP = NZ_IN |
||||
HEIGHT = Z_OUT(K) |
||||
|
||||
DO WHILE ((.NOT.INTERP) .AND. (KP.GE.2)) |
||||
|
||||
IF (((Z_IN(KP-IM).LE.HEIGHT).AND. |
||||
+ (Z_IN(KP-IP).GT.HEIGHT))) THEN |
||||
W2 = (HEIGHT-Z_IN(KP-IM))/ (Z_IN(KP-IP)-Z_IN(KP-IM)) |
||||
W1 = 1.D0 - W2 |
||||
V_OUT(K) = W1*V_IN(KP-IM) + W2*V_IN(KP-IP) |
||||
INTERP = .true. |
||||
END IF |
||||
KP = KP - 1 |
||||
|
||||
END DO |
||||
|
||||
END DO |
||||
|
||||
RETURN |
||||
END |
||||
|
||||
c--------------------------------------------- |
||||
|
||||
c Bill, |
||||
c This routine assumes |
||||
c index order is (i,j,k) |
||||
c wrf staggering |
||||
C |
||||
c units: pressure (Pa), temperature(K), height (m), mixing ratio |
||||
c (kg kg{-1}) availability of 3d p, t, and qv; 2d terrain; 1d |
||||
c half-level zeta string |
||||
c output units of SLP are Pa, but you should divide that by 100 for the |
||||
c weather weenies. |
||||
c virtual effects are included |
||||
c |
||||
|
||||
C NCLFORTSTART |
||||
SUBROUTINE DCOMPUTESEAPRS(NX,NY,NZ,Z,T,P,Q,SEA_LEVEL_PRESSURE, |
||||
+ T_SEA_LEVEL,T_SURF,LEVEL) |
||||
IMPLICIT NONE |
||||
c Estimate sea level pressure. |
||||
INTEGER NX,NY,NZ |
||||
DOUBLE PRECISION Z(NX,NY,NZ) |
||||
DOUBLE PRECISION T(NX,NY,NZ),P(NX,NY,NZ),Q(NX,NY,NZ) |
||||
c The output is the 2d sea level pressure. |
||||
DOUBLE PRECISION SEA_LEVEL_PRESSURE(NX,NY) |
||||
INTEGER LEVEL(NX,NY) |
||||
DOUBLE PRECISION T_SURF(NX,NY),T_SEA_LEVEL(NX,NY) |
||||
C NCLEND |
||||
c Some required physical constants: |
||||
|
||||
DOUBLE PRECISION R,G,GAMMA |
||||
PARAMETER (R=287.04D0,G=9.81D0,GAMMA=0.0065D0) |
||||
|
||||
c Specific constants for assumptions made in this routine: |
||||
|
||||
DOUBLE PRECISION TC,PCONST |
||||
PARAMETER (TC=273.16D0+17.5D0,PCONST=10000) |
||||
LOGICAL RIDICULOUS_MM5_TEST |
||||
PARAMETER (RIDICULOUS_MM5_TEST=.TRUE.) |
||||
c PARAMETER (ridiculous_mm5_test = .false.) |
||||
|
||||
c Local variables: |
||||
|
||||
INTEGER I,J,K |
||||
INTEGER KLO,KHI |
||||
|
||||
|
||||
DOUBLE PRECISION PLO,PHI,TLO,THI,ZLO,ZHI |
||||
DOUBLE PRECISION P_AT_PCONST,T_AT_PCONST,Z_AT_PCONST |
||||
DOUBLE PRECISION Z_HALF_LOWEST |
||||
|
||||
LOGICAL L1,L2,L3,FOUND |
||||
|
||||
C |
||||
c Find least zeta level that is PCONST Pa above the surface. We |
||||
c later use this level to extrapolate a surface pressure and |
||||
c temperature, which is supposed to reduce the effect of the diurnal |
||||
c heating cycle in the pressure field. |
||||
|
||||
DO J = 1,NY |
||||
DO I = 1,NX |
||||
LEVEL(I,J) = -1 |
||||
|
||||
K = 1 |
||||
FOUND = .false. |
||||
DO WHILE ((.NOT.FOUND) .AND. (K.LE.NZ)) |
||||
IF (P(I,J,K).LT.P(I,J,1)-PCONST) THEN |
||||
LEVEL(I,J) = K |
||||
FOUND = .true. |
||||
END IF |
||||
K = K + 1 |
||||
END DO |
||||
|
||||
IF (LEVEL(I,J).EQ.-1) THEN |
||||
PRINT '(A,I4,A)','Troubles finding level ', |
||||
+ NINT(PCONST)/100,' above ground.' |
||||
PRINT '(A,I4,A,I4,A)','Problems first occur at (',I, |
||||
+ ',',J,')' |
||||
PRINT '(A,F6.1,A)','Surface pressure = ',P(I,J,1)/100, |
||||
+ ' hPa.' |
||||
STOP 'Error_in_finding_100_hPa_up' |
||||
END IF |
||||
|
||||
|
||||
END DO |
||||
END DO |
||||
|
||||
c Get temperature PCONST Pa above surface. Use this to extrapolate |
||||
c the temperature at the surface and down to sea level. |
||||
|
||||
DO J = 1,NY |
||||
DO I = 1,NX |
||||
|
||||
KLO = MAX(LEVEL(I,J)-1,1) |
||||
KHI = MIN(KLO+1,NZ-1) |
||||
|
||||
IF (KLO.EQ.KHI) THEN |
||||
PRINT '(A)','Trapping levels are weird.' |
||||
PRINT '(A,I3,A,I3,A)','klo = ',KLO,', khi = ',KHI, |
||||
+ ': and they should not be equal.' |
||||
STOP 'Error_trapping_levels' |
||||
END IF |
||||
|
||||
PLO = P(I,J,KLO) |
||||
PHI = P(I,J,KHI) |
||||
TLO = T(I,J,KLO)* (1.D0+0.608D0*Q(I,J,KLO)) |
||||
THI = T(I,J,KHI)* (1.D0+0.608D0*Q(I,J,KHI)) |
||||
c zlo = zetahalf(klo)/ztop*(ztop-terrain(i,j))+terrain(i,j) |
||||
c zhi = zetahalf(khi)/ztop*(ztop-terrain(i,j))+terrain(i,j) |
||||
ZLO = Z(I,J,KLO) |
||||
ZHI = Z(I,J,KHI) |
||||
|
||||
P_AT_PCONST = P(I,J,1) - PCONST |
||||
T_AT_PCONST = THI - (THI-TLO)*LOG(P_AT_PCONST/PHI)* |
||||
+ LOG(PLO/PHI) |
||||
Z_AT_PCONST = ZHI - (ZHI-ZLO)*LOG(P_AT_PCONST/PHI)* |
||||
+ LOG(PLO/PHI) |
||||
|
||||
T_SURF(I,J) = T_AT_PCONST* (P(I,J,1)/P_AT_PCONST)** |
||||
+ (GAMMA*R/G) |
||||
T_SEA_LEVEL(I,J) = T_AT_PCONST + GAMMA*Z_AT_PCONST |
||||
|
||||
END DO |
||||
END DO |
||||
|
||||
C |
||||
c If we follow a traditional computation, there is a correction to the |
||||
c sea level temperature if both the surface and sea level |
||||
c temperatures are *too* hot. |
||||
|
||||
IF (RIDICULOUS_MM5_TEST) THEN |
||||
DO J = 1,NY |
||||
DO I = 1,NX |
||||
L1 = T_SEA_LEVEL(I,J) .LT. TC |
||||
L2 = T_SURF(I,J) .LE. TC |
||||
L3 = .NOT. L1 |
||||
IF (L2 .AND. L3) THEN |
||||
T_SEA_LEVEL(I,J) = TC |
||||
ELSE |
||||
T_SEA_LEVEL(I,J) = TC - |
||||
+ 0.005D0* (T_SURF(I,J)-TC)**2 |
||||
END IF |
||||
END DO |
||||
END DO |
||||
END IF |
||||
|
||||
c The grand finale: ta da! |
||||
|
||||
DO J = 1,NY |
||||
DO I = 1,NX |
||||
c z_half_lowest=zetahalf(1)/ztop*(ztop-terrain(i,j))+terrain(i,j) |
||||
Z_HALF_LOWEST = Z(I,J,1) |
||||
|
||||
C Convert to hPa in this step, by multiplying by 0.01. The original |
||||
C Fortran routine didn't do this, but the NCL script that called it |
||||
C did, so we moved it here. |
||||
SEA_LEVEL_PRESSURE(I,J) = 0.01 * (P(I,J,1)* |
||||
+ EXP((2.D0*G*Z_HALF_LOWEST)/ |
||||
+ (R* (T_SEA_LEVEL(I,J)+T_SURF(I, |
||||
+ J))))) |
||||
END DO |
||||
END DO |
||||
|
||||
c print *,'sea pres input at weird location i=20,j=1,k=1' |
||||
c print *,'t=',t(20,1,1),t(20,2,1),t(20,3,1) |
||||
c print *,'z=',z(20,1,1),z(20,2,1),z(20,3,1) |
||||
c print *,'p=',p(20,1,1),p(20,2,1),p(20,3,1) |
||||
c print *,'slp=',sea_level_pressure(20,1), |
||||
c * sea_level_pressure(20,2),sea_level_pressure(20,3) |
||||
|
||||
END |
||||
|
||||
|
||||
c--------------------------------------------------- |
||||
|
||||
C |
||||
C Double precision version. If you make a change here, you |
||||
C must make the same change below to filter2d. |
||||
C |
||||
C NCLFORTSTART |
||||
SUBROUTINE DFILTER2D(A,B,NX,NY,IT,MISSING) |
||||
IMPLICIT NONE |
||||
c Estimate sea level pressure. |
||||
INTEGER NX,NY,IT |
||||
DOUBLE PRECISION A(NX,NY),B(NX,NY),MISSING |
||||
C NCLEND |
||||
|
||||
DOUBLE PRECISION COEF |
||||
PARAMETER (COEF=0.25D0) |
||||
INTEGER I,J,ITER |
||||
|
||||
DO ITER = 1,IT |
||||
DO J = 1,NY |
||||
DO I = 1,NX |
||||
B(I,J) = A(I,J) |
||||
END DO |
||||
END DO |
||||
DO J = 2,NY - 1 |
||||
DO I = 1,NX |
||||
IF ( B(I,J-1).EQ.MISSING .OR. B(I,J).EQ.MISSING .OR. |
||||
+ B(I,J+1).EQ.MISSING ) THEN |
||||
A(I,J) = A(I,J) |
||||
ELSE |
||||
A(I,J) = A(I,J) + COEF* (B(I,J-1)-2*B(I,J)+B(I,J+1)) |
||||
END IF |
||||
END DO |
||||
END DO |
||||
DO J = 1,NY |
||||
DO I = 2,NX - 1 |
||||
IF ( B(I-1,J).EQ.MISSING .OR. B(I,J).EQ.MISSING .OR. |
||||
+ B(I+1,J).EQ.MISSING ) THEN |
||||
A(I,J) = A(I,J) |
||||
ELSE |
||||
A(I,J) = A(I,J) + COEF* (B(I-1,J)-2*B(I,J)+B(I+1,J)) |
||||
END IF |
||||
END DO |
||||
END DO |
||||
c do j=1,ny |
||||
c do i=1,nx |
||||
c b(i,j) = a(i,j) |
||||
c enddo |
||||
c enddo |
||||
c do j=2,ny-1 |
||||
c do i=1,nx |
||||
c a(i,j) = a(i,j) - .99*coef*(b(i,j-1)-2*b(i,j)+b(i,j+1)) |
||||
c enddo |
||||
c enddo |
||||
c do j=1,ny |
||||
c do i=2,nx-1 |
||||
c a(i,j) = a(i,j) - .99*coef*(b(i-1,j)-2*b(i,j)+b(i+1,j)) |
||||
c enddo |
||||
c enddo |
||||
END DO |
||||
RETURN |
||||
END |
||||
|
||||
C |
||||
C Single precision version. If you make a change here, you |
||||
C must make the same change above to dfilter2d. |
||||
C |
||||
C NCLFORTSTART |
||||
SUBROUTINE filter2d( a, b, nx , ny , it, missing) |
||||
IMPLICIT NONE |
||||
c Estimate sea level pressure. |
||||
INTEGER nx , ny, it |
||||
REAL a(nx,ny),b(nx,ny), missing |
||||
C NCLEND |
||||
|
||||
REAL coef |
||||
parameter( coef = 0.25) |
||||
INTEGER i,j,iter |
||||
|
||||
do iter=1, it |
||||
do j=1,ny |
||||
do i=1,nx |
||||
b(i,j) = a(i,j) |
||||
enddo |
||||
enddo |
||||
do j=2,ny-1 |
||||
do i=1,nx |
||||
if ( b(i,j-1).eq.missing .or. b(i,j).eq.missing .or. |
||||
+ b(i,j+1).eq.missing ) then |
||||
a(i,j) = a(i,j) |
||||
else |
||||
a(i,j) = a(i,j) + coef*(b(i,j-1)-2*b(i,j)+b(i,j+1)) |
||||
end if |
||||
enddo |
||||
enddo |
||||
do j=1,ny |
||||
do i=2,nx-1 |
||||
if ( b(i-1,j).eq.missing .or. b(i,j).eq.missing .or. |
||||
+ b(i+1,j).eq.missing ) then |
||||
a(i,j) = a(i,j) |
||||
else |
||||
a(i,j) = a(i,j) + coef*(b(i-1,j)-2*b(i,j)+b(i+1,j)) |
||||
end if |
||||
enddo |
||||
enddo |
||||
c do j=1,ny |
||||
c do i=1,nx |
||||
c b(i,j) = a(i,j) |
||||
c enddo |
||||
c enddo |
||||
c do j=2,ny-1 |
||||
c do i=1,nx |
||||
c a(i,j) = a(i,j) - .99*coef*(b(i,j-1)-2*b(i,j)+b(i,j+1)) |
||||
c enddo |
||||
c enddo |
||||
c do j=1,ny |
||||
c do i=2,nx-1 |
||||
c a(i,j) = a(i,j) - .99*coef*(b(i-1,j)-2*b(i,j)+b(i+1,j)) |
||||
c enddo |
||||
c enddo |
||||
enddo |
||||
return |
||||
end |
||||
c--------------------------------------------------------- |
||||
|
||||
C NCLFORTSTART |
||||
SUBROUTINE DCOMPUTERH(QV,P,T,RH,NX) |
||||
|
||||
IMPLICIT NONE |
||||
INTEGER NX |
||||
DOUBLE PRECISION QV(NX),P(NX),T(NX),RH(NX) |
||||
C NCLEND |
||||
DOUBLE PRECISION SVP1,SVP2,SVP3,SVPT0 |
||||
PARAMETER (SVP1=0.6112D0,SVP2=17.67D0,SVP3=29.65D0,SVPT0=273.15D0) |
||||
INTEGER I |
||||
DOUBLE PRECISION QVS,ES,PRESSURE,TEMPERATURE |
||||
DOUBLE PRECISION EP_2,R_D,R_V |
||||
PARAMETER (R_D=287.D0,R_V=461.6D0,EP_2=R_D/R_V) |
||||
DOUBLE PRECISION EP_3 |
||||
PARAMETER (EP_3=0.622D0) |
||||
|
||||
DO I = 1,NX |
||||
PRESSURE = P(I) |
||||
TEMPERATURE = T(I) |
||||
c es = 1000.*svp1* |
||||
ES = 10.D0*SVP1*EXP(SVP2* (TEMPERATURE-SVPT0)/ |
||||
+ (TEMPERATURE-SVP3)) |
||||
c qvs = ep_2*es/(pressure-es) |
||||
QVS = EP_3*ES/ (0.01D0*PRESSURE- (1.D0-EP_3)*ES) |
||||
c rh = 100*amax1(1., qv(i)/qvs) |
||||
c rh(i) = 100.*qv(i)/qvs |
||||
RH(I) = 100.D0*DMAX1(DMIN1(QV(I)/QVS,1.0D0),0.0D0) |
||||
END DO |
||||
|
||||
RETURN |
||||
END |
||||
|
||||
c---------------------------------------------- |
||||
|
||||
C NCLFORTSTART |
||||
SUBROUTINE DGETIJLATLONG(LAT_ARRAY,LONG_ARRAY,LAT,LONGITUDE, |
||||
+ II,JJ,NX,NY,IMSG) |
||||
IMPLICIT NONE |
||||
INTEGER NX,NY,II,JJ,IMSG |
||||
DOUBLE PRECISION LAT_ARRAY(NX,NY),LONG_ARRAY(NX,NY) |
||||
DOUBLE PRECISION LAT,LONGITUDE |
||||
C NCLEND |
||||
DOUBLE PRECISION LONGD,LATD |
||||
INTEGER I,J |
||||
DOUBLE PRECISION IR,JR |
||||
DOUBLE PRECISION DIST_MIN,DIST |
||||
|
||||
C Init to missing. Was hard-coded to -999 initially. |
||||
IR = IMSG |
||||
JR = IMSG |
||||
|
||||
DIST_MIN = 1.D+20 |
||||
DO J = 1,NY |
||||
DO I = 1,NX |
||||
LATD = (LAT_ARRAY(I,J)-LAT)**2 |
||||
LONGD = (LONG_ARRAY(I,J)-LONGITUDE)**2 |
||||
C LONGD = DMIN1((LONG_ARRAY(I,J)-LONGITUDE)**2, |
||||
C + (LONG_ARRAY(I,J)+LONGITUDE)**2) |
||||
DIST = SQRT(LATD+LONGD) |
||||
IF (DIST_MIN.GT.DIST) THEN |
||||
DIST_MIN = DIST |
||||
IR = DBLE(I) |
||||
JR = DBLE(J) |
||||
END IF |
||||
END DO |
||||
END DO |
||||
C |
||||
C The original version of this routine returned IR and JR. But, then |
||||
C the NCL script that called this routine was converting IR and JR |
||||
C to integer, so why not just return II and JJ? |
||||
C |
||||
C Also, I'm subtracing 1 here, because it will be returned to NCL |
||||
C script which has 0-based indexing. |
||||
C |
||||
IF(IR.ne.IMSG.and.JR.ne.IMSG) then |
||||
II = NINT(IR)-1 |
||||
JJ = NINT(JR)-1 |
||||
ELSE |
||||
II = IMSG |
||||
JJ = IMSG |
||||
END IF |
||||
|
||||
c we will just return the nearest point at present |
||||
|
||||
RETURN |
||||
END |
||||
|
||||
C NCLFORTSTART |
||||
SUBROUTINE DCOMPUTEUVMET(U,V,UVMET,LONGCA,LONGCB,FLONG,FLAT, |
||||
+ CEN_LONG,CONE,RPD,NX,NY,NXP1,NYP1, |
||||
+ ISTAG,IS_MSG_VAL,UMSG,VMSG,UVMETMSG) |
||||
IMPLICIT NONE |
||||
|
||||
C ISTAG should be 0 if the U,V grids are not staggered. |
||||
C That is, NY = NYP1 and NX = NXP1. |
||||
|
||||
INTEGER NX,NY,NXP1,NYP1,ISTAG |
||||
LOGICAL IS_MSG_VAL |
||||
DOUBLE PRECISION U(NXP1,NY),V(NX,NYP1) |
||||
DOUBLE PRECISION UVMET(NX,NY,2) |
||||
DOUBLE PRECISION FLONG(NX,NY),FLAT(NX,NY) |
||||
DOUBLE PRECISION LONGCB(NX,NY),LONGCA(NX,NY) |
||||
DOUBLE PRECISION CEN_LONG,CONE,RPD |
||||
DOUBLE PRECISION UMSG,VMSG,UVMETMSG |
||||
C NCLEND |
||||
|
||||
INTEGER I,J |
||||
DOUBLE PRECISION UK,VK |
||||
|
||||
|
||||
c WRITE (6,FMT=*) ' in compute_uvmet ',NX,NY,NXP1,NYP1,ISTAG |
||||
|
||||
DO J = 1,NY |
||||
DO I = 1,NX |
||||
|
||||
LONGCA(I,J) = FLONG(I,J) - CEN_LONG |
||||
IF (LONGCA(I,J).GT.180.D0) THEN |
||||
LONGCA(I,J) = LONGCA(I,J) - 360.D0 |
||||
END IF |
||||
IF (LONGCA(I,J).LT.-180.D0) THEN |
||||
LONGCA(I,J) = LONGCA(I,J) + 360.D0 |
||||
END IF |
||||
IF (FLAT(I,J).LT.0.D0) THEN |
||||
LONGCB(I,J) = -LONGCA(I,J)*CONE*RPD |
||||
ELSE |
||||
LONGCB(I,J) = LONGCA(I,J)*CONE*RPD |
||||
END IF |
||||
|
||||
LONGCA(I,J) = COS(LONGCB(I,J)) |
||||
LONGCB(I,J) = SIN(LONGCB(I,J)) |
||||
|
||||
END DO |
||||
END DO |
||||
|
||||
c WRITE (6,FMT=*) ' computing velocities ' |
||||
|
||||
DO J = 1,NY |
||||
DO I = 1,NX |
||||
IF (ISTAG.EQ.1) THEN |
||||
IF (IS_MSG_VAL.AND.(U(I,J).EQ.UMSG.OR. |
||||
+ V(I,J).EQ.VMSG.OR. |
||||
+ U(I+1,J).EQ.UMSG.OR. |
||||
+ V(I,J+1).EQ.VMSG)) THEN |
||||
UVMET(I,J,1) = UVMETMSG |
||||
UVMET(I,J,2) = UVMETMSG |
||||
ELSE |
||||
UK = 0.5D0* (U(I,J)+U(I+1,J)) |
||||
VK = 0.5D0* (V(I,J)+V(I,J+1)) |
||||
UVMET(I,J,1) = VK*LONGCB(I,J) + UK*LONGCA(I,J) |
||||
UVMET(I,J,2) = VK*LONGCA(I,J) - UK*LONGCB(I,J) |
||||
END IF |
||||
ELSE |
||||
IF (IS_MSG_VAL.AND.(U(I,J).EQ.UMSG.OR. |
||||
+ V(I,J).EQ.VMSG)) THEN |
||||
UVMET(I,J,1) = UVMETMSG |
||||
UVMET(I,J,2) = UVMETMSG |
||||
ELSE |
||||
UK = U(I,J) |
||||
VK = V(I,J) |
||||
UVMET(I,J,1) = VK*LONGCB(I,J) + UK*LONGCA(I,J) |
||||
UVMET(I,J,2) = VK*LONGCA(I,J) - UK*LONGCB(I,J) |
||||
END IF |
||||
END IF |
||||
END DO |
||||
END DO |
||||
|
||||
RETURN |
||||
END |
||||
|
||||
C NCLFORTSTART |
||||
C |
||||
C This was originally a routine that took 2D input arrays. Since |
||||
C the NCL C wrapper routine can handle multiple dimensions, it's |
||||
C not necessary to have anything bigger than 1D here. |
||||
C |
||||
SUBROUTINE DCOMPUTETD(TD,PRESSURE,QV_IN,NX) |
||||
IMPLICIT NONE |
||||
INTEGER NX |
||||
DOUBLE PRECISION PRESSURE(NX) |
||||
DOUBLE PRECISION QV_IN(NX) |
||||
DOUBLE PRECISION TD(NX) |
||||
C NCLEND |
||||
DOUBLE PRECISION QV,TDC |
||||
|
||||
INTEGER I |
||||
|
||||
DO I = 1,NX |
||||
QV = DMAX1(QV_IN(I),0.D0) |
||||
c vapor pressure |
||||
TDC = QV*PRESSURE(I)/ (.622D0+QV) |
||||
|
||||
c avoid problems near zero |
||||
TDC = DMAX1(TDC,0.001D0) |
||||
TD(I) = (243.5D0*LOG(TDC)-440.8D0)/ (19.48D0-LOG(TDC)) |
||||
END DO |
||||
|
||||
RETURN |
||||
END |
||||
|
||||
C NCLFORTSTART |
||||
SUBROUTINE DCOMPUTEICLW(ICLW,PRESSURE,QC_IN,NX,NY,NZ) |
||||
IMPLICIT NONE |
||||
INTEGER NX,NY,NZ |
||||
DOUBLE PRECISION PRESSURE(NX,NY,NZ) |
||||
DOUBLE PRECISION QC_IN(NX,NY,NZ) |
||||
DOUBLE PRECISION ICLW(NX,NY) |
||||
DOUBLE PRECISION QCLW,DP,GG |
||||
C NCLEND |
||||
|
||||
INTEGER I,J,K |
||||
|
||||
GG = 1000.D0/9.8D0 |
||||
|
||||
DO J = 1,NY |
||||
DO I = 1,NX |
||||
ICLW(I,J) = 0.D0 |
||||
END DO |
||||
END DO |
||||
|
||||
DO J = 3,NY - 2 |
||||
DO I = 3,NX - 2 |
||||
DO K = 1,NZ |
||||
QCLW = DMAX1(QC_IN(I,J,K),0.D0) |
||||
IF (K.EQ.1) THEN |
||||
DP = (PRESSURE(I,J,K-1)-PRESSURE(I,J,K)) |
||||
ELSE IF (K.EQ.NZ) THEN |
||||
DP = (PRESSURE(I,J,K)-PRESSURE(I,J,K+1)) |
||||
ELSE |
||||
DP = (PRESSURE(I,J,K-1)-PRESSURE(I,J,K+1))/2.D0 |
||||
END IF |
||||
ICLW(I,J) = ICLW(I,J) + QCLW*DP*GG |
||||
END DO |
||||
END DO |
||||
END DO |
||||
|
||||
RETURN |
||||
END |
@ -0,0 +1,209 @@
@@ -0,0 +1,209 @@
|
||||
C NCLFORTSTART |
||||
SUBROUTINE CALCDBZ(DBZ,PRS,TMK,QVP,QRA,QSN,QGR,WEDIM,SNDIM,BTDIM, |
||||
+ SN0,IVARINT,ILIQSKIN) |
||||
c |
||||
c This routine computes equivalent reflectivity factor (in dBZ) at |
||||
c each model grid point. In calculating Ze, the RIP algorithm makes |
||||
c assumptions consistent with those made in an early version |
||||
c (ca. 1996) of the bulk mixed-phase microphysical scheme in the MM5 |
||||
c model (i.e., the scheme known as "Resiner-2"). For each species: |
||||
c |
||||
c 1. Particles are assumed to be spheres of constant density. The |
||||
c densities of rain drops, snow particles, and graupel particles are |
||||
c taken to be rho_r = rho_l = 1000 kg m^-3, rho_s = 100 kg m^-3, and |
||||
c rho_g = 400 kg m^-3, respectively. (l refers to the density of |
||||
c liquid water.) |
||||
c |
||||
c 2. The size distribution (in terms of the actual diameter of the |
||||
c particles, rather than the melted diameter or the equivalent solid |
||||
c ice sphere diameter) is assumed to follow an exponential |
||||
c distribution of the form N(D) = N_0 * exp( lambda*D ). |
||||
c |
||||
c 3. If ivarint=0, the intercept parameters are assumed constant |
||||
c (as in early Reisner-2), with values of 8x10^6, 2x10^7, |
||||
c and 4x10^6 m^-4, for rain, snow, and graupel, respectively. |
||||
c If ivarint=1, variable intercept parameters are used, as |
||||
c calculated in Thompson, Rasmussen, and Manning (2004, Monthly |
||||
c Weather Review, Vol. 132, No. 2, pp. 519-542.) |
||||
c |
||||
c 4. If iliqskin=1, frozen particles that are at a temperature above |
||||
c freezing are assumed to scatter as a liquid particle. |
||||
c |
||||
c More information on the derivation of simulated reflectivity in |
||||
c RIP can be found in Stoelinga (2005, unpublished write-up). |
||||
c Contact Mark Stoelinga (stoeling@atmos.washington.edu) for a copy. |
||||
c |
||||
|
||||
c Arguments |
||||
INTEGER WEDIM,SNDIM,BTDIM |
||||
INTEGER SN0,IVARINT,ILIQSKIN |
||||
DOUBLE PRECISION DBZ(WEDIM,SNDIM,BTDIM) |
||||
DOUBLE PRECISION PRS(WEDIM,SNDIM,BTDIM) |
||||
DOUBLE PRECISION TMK(WEDIM,SNDIM,BTDIM) |
||||
DOUBLE PRECISION QVP(WEDIM,SNDIM,BTDIM) |
||||
DOUBLE PRECISION QRA(WEDIM,SNDIM,BTDIM) |
||||
DOUBLE PRECISION QSN(WEDIM,SNDIM,BTDIM) |
||||
DOUBLE PRECISION QGR(WEDIM,SNDIM,BTDIM) |
||||
|
||||
C NCLEND |
||||
|
||||
c Local Variables |
||||
INTEGER I,J,K |
||||
DOUBLE PRECISION TEMP_C,VIRTUAL_T |
||||
DOUBLE PRECISION GONV,RONV,SONV |
||||
DOUBLE PRECISION FACTOR_G,FACTOR_R,FACTOR_S |
||||
DOUBLE PRECISION FACTORB_G,FACTORB_R,FACTORB_S |
||||
DOUBLE PRECISION RHOAIR,Z_E |
||||
|
||||
c Constants used to calculate variable intercepts |
||||
DOUBLE PRECISION R1,RON,RON2,SON,GON |
||||
DOUBLE PRECISION RON_MIN,RON_QR0,RON_DELQR0 |
||||
DOUBLE PRECISION RON_CONST1R,RON_CONST2R |
||||
c Constant intercepts |
||||
DOUBLE PRECISION RN0_R,RN0_S,RN0_G |
||||
c Other constants |
||||
DOUBLE PRECISION RHO_R,RHO_S,RHO_G |
||||
DOUBLE PRECISION GAMMA_SEVEN,ALPHA |
||||
DOUBLE PRECISION RHOWAT,CELKEL,PI,RD |
||||
|
||||
|
||||
c Constants used to calculate variable intercepts |
||||
R1 = 1.D-15 |
||||
RON = 8.D6 |
||||
RON2 = 1.D10 |
||||
SON = 2.D7 |
||||
GON = 5.D7 |
||||
RON_MIN = 8.D6 |
||||
RON_QR0 = 0.00010D0 |
||||
RON_DELQR0 = 0.25D0*RON_QR0 |
||||
RON_CONST1R = (RON2-RON_MIN)*0.5D0 |
||||
RON_CONST2R = (RON2+RON_MIN)*0.5D0 |
||||
|
||||
c Constant intercepts |
||||
RN0_R = 8.D6 |
||||
RN0_S = 2.D7 |
||||
RN0_G = 4.D6 |
||||
|
||||
c Other constants |
||||
GAMMA_SEVEN = 720.D0 |
||||
RHOWAT = 1000.D0 |
||||
RHO_R = RHOWAT |
||||
RHO_S = 100.D0 |
||||
RHO_G = 400.D0 |
||||
ALPHA = 0.224D0 |
||||
CELKEL = 273.15D0 |
||||
PI = 3.141592653589793D0 |
||||
RD = 287.04D0 |
||||
|
||||
c Force all Q arrays to be 0.0 or greater. |
||||
DO K = 1,BTDIM |
||||
DO J = 1,SNDIM |
||||
DO I = 1,WEDIM |
||||
IF (QVP(I,J,K).LT.0.0) THEN |
||||
QVP(I,J,K) = 0.0 |
||||
END IF |
||||
IF (QRA(I,J,K).LT.0.0) THEN |
||||
QRA(I,J,K) = 0.0 |
||||
END IF |
||||
IF (QSN(I,J,K).LT.0.0) THEN |
||||
QSN(I,J,K) = 0.0 |
||||
END IF |
||||
IF (QGR(I,J,K).LT.0.0) THEN |
||||
QGR(I,J,K) = 0.0 |
||||
END IF |
||||
END DO |
||||
END DO |
||||
END DO |
||||
|
||||
c Input pressure is Pa, but we need hPa in calculations |
||||
|
||||
IF (SN0.EQ.0) THEN |
||||
DO K = 1,BTDIM |
||||
DO J = 1,SNDIM |
||||
DO I = 1,WEDIM |
||||
IF (TMK(I,J,K).LT.CELKEL) THEN |
||||
QSN(I,J,K) = QRA(I,J,K) |
||||
QRA(I,J,K) = 0.D0 |
||||
END IF |
||||
END DO |
||||
END DO |
||||
END DO |
||||
END IF |
||||
|
||||
|
||||
FACTOR_R = GAMMA_SEVEN*1.D18* (1.D0/ (PI*RHO_R))**1.75D0 |
||||
FACTOR_S = GAMMA_SEVEN*1.D18* (1.D0/ (PI*RHO_S))**1.75D0* |
||||
+ (RHO_S/RHOWAT)**2*ALPHA |
||||
FACTOR_G = GAMMA_SEVEN*1.D18* (1.D0/ (PI*RHO_G))**1.75D0* |
||||
+ (RHO_G/RHOWAT)**2*ALPHA |
||||
|
||||
|
||||
DO K = 1,BTDIM |
||||
DO J = 1,SNDIM |
||||
DO I = 1,WEDIM |
||||
|
||||
VIRTUAL_T = TMK(I,J,K)* (0.622D0+QVP(I,J,K))/ |
||||
+ (0.622D0* (1.D0+QVP(I,J,K))) |
||||
RHOAIR = PRS(I,J,K) / (RD*VIRTUAL_T) |
||||
|
||||
c Adjust factor for brightband, where snow or graupel particle |
||||
c scatters like liquid water (alpha=1.0) because it is assumed to |
||||
c have a liquid skin. |
||||
|
||||
IF (ILIQSKIN.EQ.1 .AND. TMK(I,J,K).GT.CELKEL) THEN |
||||
FACTORB_S = FACTOR_S/ALPHA |
||||
FACTORB_G = FACTOR_G/ALPHA |
||||
ELSE |
||||
FACTORB_S = FACTOR_S |
||||
FACTORB_G = FACTOR_G |
||||
END IF |
||||
|
||||
c Calculate variable intercept parameters |
||||
|
||||
IF (IVARINT.EQ.1) THEN |
||||
|
||||
TEMP_C = DMIN1(-0.001D0,TMK(I,J,K)-CELKEL) |
||||
SONV = DMIN1(2.0D8,2.0D6*EXP(-0.12D0*TEMP_C)) |
||||
|
||||
GONV = GON |
||||
IF (QGR(I,J,K).GT.R1) THEN |
||||
GONV = 2.38D0* (PI*RHO_G/ |
||||
+ (RHOAIR*QGR(I,J,K)))**0.92D0 |
||||
GONV = MAX(1.D4,MIN(GONV,GON)) |
||||
END IF |
||||
|
||||
RONV = RON2 |
||||
IF (QRA(I,J,K).GT.R1) THEN |
||||
RONV = RON_CONST1R*TANH((RON_QR0-QRA(I,J,K))/ |
||||
+ RON_DELQR0) + RON_CONST2R |
||||
END IF |
||||
|
||||
ELSE |
||||
|
||||
RONV = RN0_R |
||||
SONV = RN0_S |
||||
GONV = RN0_G |
||||
|
||||
END IF |
||||
|
||||
c Total equivalent reflectivity factor (z_e, in mm^6 m^-3) is |
||||
c the sum of z_e for each hydrometeor species: |
||||
|
||||
Z_E = FACTOR_R* (RHOAIR*QRA(I,J,K))**1.75D0/ |
||||
+ RONV**.75D0 + FACTORB_S* |
||||
+ (RHOAIR*QSN(I,J,K))**1.75D0/SONV**.75D0 + |
||||
+ FACTORB_G* (RHOAIR*QGR(I,J,K))**1.75D0/ |
||||
+ GONV**.75D0 |
||||
|
||||
c Adjust small values of Z_e so that dBZ is no lower than -30 |
||||
Z_E = MAX(Z_E,.001D0) |
||||
|
||||
c Convert to dBZ |
||||
DBZ(I,J,K) = 10.D0*LOG10(Z_E) |
||||
|
||||
END DO |
||||
END DO |
||||
END DO |
||||
|
||||
RETURN |
||||
END |
@ -0,0 +1,511 @@
@@ -0,0 +1,511 @@
|
||||
C NCLFORTSTART |
||||
SUBROUTINE DLLTOIJ(MAP_PROJ,TRUELAT1,TRUELAT2,STDLON,LAT1,LON1, |
||||
+ POLE_LAT,POLE_LON,KNOWNI,KNOWNJ,DX,DY,LATINC, |
||||
+ LONINC,LAT,LON,LOC) |
||||
DOUBLE PRECISION DELTALON1 |
||||
DOUBLE PRECISION TL1R |
||||
|
||||
|
||||
ccc Converts input lat/lon values to the cartesian (i,j) value |
||||
ccc for the given projection. |
||||
|
||||
INTEGER MAP_PROJ |
||||
DOUBLE PRECISION TRUELAT1,TRUELAT2,STDLON |
||||
DOUBLE PRECISION LAT1,LON1,POLE_LAT,POLE_LON,KNOWNI,KNOWNJ |
||||
DOUBLE PRECISION DX,DY,LATINC,LONINC,LAT,LON,LOC(2) |
||||
C NCLEND |
||||
|
||||
DOUBLE PRECISION CLAIN,DLON,RSW,DELTALON,DELTALAT |
||||
DOUBLE PRECISION REFLON,SCALE_TOP,ALA1,ALO1,ALA,ALO,RM,POLEI,POLEJ |
||||
c Earth radius divided by dx |
||||
DOUBLE PRECISION REBYDX |
||||
DOUBLE PRECISION DELTALON1TL1R,CTL1R,ARG,CONE,HEMI |
||||
DOUBLE PRECISION I,J |
||||
DOUBLE PRECISION LAT1N,LON1N,OLAT,OLON |
||||
|
||||
DOUBLE PRECISION PI,RAD_PER_DEG,DEG_PER_RAD,RE_M |
||||
|
||||
ccc lat1 ! SW latitude (1,1) in degrees (-90->90N) |
||||
ccc lon1 ! SW longitude (1,1) in degrees (-180->180E) |
||||
ccc dx ! Grid spacing in meters at truelats |
||||
ccc dlat ! Lat increment for lat/lon grids |
||||
ccc dlon ! Lon increment for lat/lon grids |
||||
ccc stdlon ! Longitude parallel to y-axis (-180->180E) |
||||
ccc truelat1 ! First true latitude (all projections) |
||||
ccc truelat2 ! Second true lat (LC only) |
||||
ccc hemi ! 1 for NH, -1 for SH |
||||
ccc cone ! Cone factor for LC projections |
||||
ccc polei ! Computed i-location of pole point |
||||
ccc polej ! Computed j-location of pole point |
||||
ccc rsw ! Computed radius to SW corner |
||||
ccc knowni ! X-location of known lat/lon |
||||
ccc knownj ! Y-location of known lat/lon |
||||
ccc RE_M ! Radius of spherical earth, meters |
||||
ccc REbydx ! Earth radius divided by dx |
||||
|
||||
PI = 3.141592653589793D0 |
||||
RAD_PER_DEG = PI/180.D0 |
||||
DEG_PER_RAD = 180.D0/PI |
||||
c Radius of spherical earth, meters |
||||
RE_M = 6370000.D0 |
||||
REBYDX = RE_M/DX |
||||
|
||||
HEMI = 1.0D0 |
||||
IF (TRUELAT1.LT.0.0D0) THEN |
||||
HEMI = -1.0D0 |
||||
END IF |
||||
|
||||
|
||||
ccc !MERCATOR |
||||
IF (MAP_PROJ.EQ.3) THEN |
||||
|
||||
ccc ! Preliminary variables |
||||
CLAIN = COS(RAD_PER_DEG*TRUELAT1) |
||||
DLON = DX/ (RE_M*CLAIN) |
||||
|
||||
ccc ! Compute distance from equator to origin, and store in |
||||
ccc ! the rsw tag. |
||||
RSW = 0.D0 |
||||
IF (LAT1.NE.0.D0) THEN |
||||
RSW = (DLOG(TAN(0.5D0* ((LAT1+90.D0)*RAD_PER_DEG))))/DLON |
||||
END IF |
||||
|
||||
DELTALON = LON - LON1 |
||||
IF (DELTALON.LT.-180.D0) DELTALON = DELTALON + 360.D0 |
||||
IF (DELTALON.GT.180.D0) DELTALON = DELTALON - 360.D0 |
||||
I = KNOWNI + (DELTALON/ (DLON*DEG_PER_RAD)) |
||||
J = KNOWNJ + (DLOG(TAN(0.5D0* ((LAT+90.D0)*RAD_PER_DEG))))/ |
||||
+ DLON - RSW |
||||
|
||||
ccc !PS |
||||
ELSE IF (MAP_PROJ.EQ.2) THEN |
||||
|
||||
REFLON = STDLON + 90.D0 |
||||
|
||||
ccc ! Compute numerator term of map scale factor |
||||
SCALE_TOP = 1.D0 + HEMI*SIN(TRUELAT1*RAD_PER_DEG) |
||||
|
||||
ccc ! Compute radius to lower-left (SW) corner |
||||
ALA1 = LAT1*RAD_PER_DEG |
||||
RSW = REBYDX*COS(ALA1)*SCALE_TOP/ (1.D0+HEMI*SIN(ALA1)) |
||||
|
||||
ccc ! Find the pole point |
||||
ALO1 = (LON1-REFLON)*RAD_PER_DEG |
||||
POLEI = KNOWNI - RSW*COS(ALO1) |
||||
POLEJ = KNOWNJ - HEMI*RSW*SIN(ALO1) |
||||
|
||||
ccc ! Find radius to desired point |
||||
ALA = LAT*RAD_PER_DEG |
||||
RM = REBYDX*COS(ALA)*SCALE_TOP/ (1.D0+HEMI*SIN(ALA)) |
||||
ALO = (LON-REFLON)*RAD_PER_DEG |
||||
I = POLEI + RM*COS(ALO) |
||||
J = POLEJ + HEMI*RM*SIN(ALO) |
||||
|
||||
ccc !LAMBERT |
||||
ELSE IF (MAP_PROJ.EQ.1) THEN |
||||
|
||||
IF (ABS(TRUELAT2).GT.90.D0) THEN |
||||
TRUELAT2 = TRUELAT1 |
||||
END IF |
||||
|
||||
IF (ABS(TRUELAT1-TRUELAT2).GT.0.1D0) THEN |
||||
CONE = (DLOG(COS(TRUELAT1*RAD_PER_DEG))- |
||||
+ DLOG(COS(TRUELAT2*RAD_PER_DEG)))/ |
||||
+ (DLOG(TAN((90.D0-ABS(TRUELAT1))*RAD_PER_DEG* |
||||
+ 0.5D0))-DLOG(TAN((90.D0-ABS(TRUELAT2))*RAD_PER_DEG* |
||||
+ 0.5D0))) |
||||
ELSE |
||||
CONE = SIN(ABS(TRUELAT1)*RAD_PER_DEG) |
||||
END IF |
||||
|
||||
ccc ! Compute longitude differences and ensure we stay |
||||
ccc ! out of the forbidden "cut zone" |
||||
DELTALON1 = LON1 - STDLON |
||||
IF (DELTALON1.GT.+180.D0) DELTALON1 = DELTALON1 - 360.D0 |
||||
IF (DELTALON1.LT.-180.D0) DELTALON1 = DELTALON1 + 360.D0 |
||||
|
||||
ccc ! Convert truelat1 to radian and compute COS for later use |
||||
TL1R = TRUELAT1*RAD_PER_DEG |
||||
CTL1R = COS(TL1R) |
||||
|
||||
ccc ! Compute the radius to our known lower-left (SW) corner |
||||
RSW = REBYDX*CTL1R/CONE* (TAN((90.D0*HEMI- |
||||
+ LAT1)*RAD_PER_DEG/2.D0)/TAN((90.D0*HEMI- |
||||
+ TRUELAT1)*RAD_PER_DEG/2.D0))**CONE |
||||
|
||||
ccc ! Find pole point |
||||
ARG = CONE* (DELTALON1*RAD_PER_DEG) |
||||
POLEI = HEMI*KNOWNI - HEMI*RSW*SIN(ARG) |
||||
POLEJ = HEMI*KNOWNJ + RSW*COS(ARG) |
||||
|
||||
ccc ! Compute deltalon between known longitude and standard |
||||
ccc ! lon and ensure it is not in the cut zone |
||||
DELTALON = LON - STDLON |
||||
IF (DELTALON.GT.+180.D0) DELTALON = DELTALON - 360.D0 |
||||
IF (DELTALON.LT.-180.D0) DELTALON = DELTALON + 360.D0 |
||||
|
||||
ccc ! Radius to desired point |
||||
RM = REBYDX*CTL1R/CONE* (TAN((90.D0*HEMI- |
||||
+ LAT)*RAD_PER_DEG/2.D0)/TAN((90.D0*HEMI- |
||||
+ TRUELAT1)*RAD_PER_DEG/2.D0))**CONE |
||||
|
||||
ARG = CONE* (DELTALON*RAD_PER_DEG) |
||||
I = POLEI + HEMI*RM*SIN(ARG) |
||||
J = POLEJ - RM*COS(ARG) |
||||
|
||||
ccc ! Finally, if we are in the southern hemisphere, flip the |
||||
ccc ! i/j values to a coordinate system where (1,1) is the SW |
||||
ccc ! corner (what we assume) which is different than the |
||||
ccc ! original NCEP algorithms which used the NE corner as |
||||
ccc ! the origin in the southern hemisphere (left-hand vs. |
||||
ccc ! right-hand coordinate?) |
||||
I = HEMI*I |
||||
J = HEMI*J |
||||
|
||||
|
||||
ccc !lat-lon |
||||
ELSE IF (MAP_PROJ.EQ.6) THEN |
||||
|
||||
IF (POLE_LAT.NE.90.D0) THEN |
||||
CALL ROTATECOORDS(LAT,LON,OLAT,OLON,POLE_LAT,POLE_LON, |
||||
+ STDLON,-1) |
||||
LAT = OLAT |
||||
LON = OLON + STDLON |
||||
END IF |
||||
|
||||
c ! make sure center lat/lon is good |
||||
IF (POLE_LAT.NE.90.D0) THEN |
||||
CALL ROTATECOORDS(LAT1,LON1,OLAT,OLON,POLE_LAT,POLE_LON, |
||||
+ STDLON,-1) |
||||
LAT1N = OLAT |
||||
LON1N = OLON + STDLON |
||||
DELTALAT = LAT - LAT1N |
||||
DELTALON = LON - LON1N |
||||
ELSE |
||||
DELTALAT = LAT - LAT1 |
||||
DELTALON = LON - LON1 |
||||
END IF |
||||
|
||||
c ! Compute i/j |
||||
I = DELTALON/LONINC |
||||
J = DELTALAT/LATINC |
||||
|
||||
I = I + KNOWNI |
||||
J = J + KNOWNJ |
||||
|
||||
ELSE |
||||
|
||||
PRINT *,'ERROR: Do not know map projection ',MAP_PROJ |
||||
|
||||
END IF |
||||
|
||||
LOC(1) = J |
||||
LOC(2) = I |
||||
|
||||
RETURN |
||||
END |
||||
|
||||
|
||||
C NCLFORTSTART |
||||
SUBROUTINE DIJTOLL(MAP_PROJ,TRUELAT1,TRUELAT2,STDLON,LAT1,LON1, |
||||
+ POLE_LAT,POLE_LON,KNOWNI,KNOWNJ,DX,DY,LATINC, |
||||
+ LONINC,AI,AJ,LOC) |
||||
DOUBLE PRECISION GI2 |
||||
DOUBLE PRECISION ARCCOS |
||||
DOUBLE PRECISION DELTALON1 |
||||
DOUBLE PRECISION TL1R |
||||
|
||||
ccc ! Converts input lat/lon values to the cartesian (i,j) value |
||||
ccc ! for the given projection. |
||||
|
||||
INTEGER MAP_PROJ |
||||
DOUBLE PRECISION TRUELAT1,TRUELAT2,STDLON |
||||
DOUBLE PRECISION LAT1,LON1,POLE_LAT,POLE_LON,KNOWNI,KNOWNJ |
||||
DOUBLE PRECISION DX,DY,LATINC,LONINC,AI,AJ,LOC(2) |
||||
C NCLEND |
||||
|
||||
DOUBLE PRECISION CLAIN,DLON,RSW,DELTALON,DELTALAT |
||||
DOUBLE PRECISION REFLON,SCALE_TOP,ALA1,ALO1,ALA,ALO,RM,POLEI,POLEJ |
||||
c Earth radius divided by dx |
||||
DOUBLE PRECISION REBYDX |
||||
DOUBLE PRECISION DELTALON1TL1R,CTL1R,ARG,CONE,HEMI |
||||
|
||||
DOUBLE PRECISION PI,RAD_PER_DEG,DEG_PER_RAD,RE_M |
||||
|
||||
DOUBLE PRECISION INEW,JNEW,R,R2 |
||||
DOUBLE PRECISION CHI,CHI1,CHI2 |
||||
DOUBLE PRECISION XX,YY,LAT,LON |
||||
|
||||
DOUBLE PRECISION RLAT,RLON,OLAT,OLON,LAT1N,LON1N |
||||
DOUBLE PRECISION PHI_NP,LAM_NP,LAM_0,DLAM |
||||
DOUBLE PRECISION SINPHI,COSPHI,COSLAM,SINLAM |
||||
|
||||
|
||||
ccc lat1 ! SW latitude (1,1) in degrees (-90->90N) |
||||
ccc lon1 ! SW longitude (1,1) in degrees (-180->180E) |
||||
ccc dx ! Grid spacing in meters at truelats |
||||
ccc dlat ! Lat increment for lat/lon grids |
||||
ccc dlon ! Lon increment for lat/lon grids |
||||
ccc stdlon ! Longitude parallel to y-axis (-180->180E) |
||||
ccc truelat1 ! First true latitude (all projections) |
||||
ccc truelat2 ! Second true lat (LC only) |
||||
ccc hemi ! 1 for NH, -1 for SH |
||||
ccc cone ! Cone factor for LC projections |
||||
ccc polei ! Computed i-location of pole point |
||||
ccc polej ! Computed j-location of pole point |
||||
ccc rsw ! Computed radius to SW corner |
||||
ccc knowni ! X-location of known lat/lon |
||||
ccc knownj ! Y-location of known lat/lon |
||||
ccc RE_M ! Radius of spherical earth, meters |
||||
ccc REbydx ! Earth radius divided by dx |
||||
|
||||
PI = 3.141592653589793D0 |
||||
RAD_PER_DEG = PI/180.D0 |
||||
DEG_PER_RAD = 180.D0/PI |
||||
c Radius of spherical earth, meters |
||||
RE_M = 6370000.D0 |
||||
REBYDX = RE_M/DX |
||||
|
||||
HEMI = 1.0D0 |
||||
IF (TRUELAT1.LT.0.0D0) THEN |
||||
HEMI = -1.0D0 |
||||
END IF |
||||
|
||||
|
||||
ccc !MERCATOR |
||||
IF (MAP_PROJ.EQ.3) THEN |
||||
|
||||
ccc ! Preliminary variables |
||||
CLAIN = COS(RAD_PER_DEG*TRUELAT1) |
||||
DLON = DX/ (RE_M*CLAIN) |
||||
|
||||
ccc ! Compute distance from equator to origin, and store in |
||||
ccc ! the rsw tag. |
||||
RSW = 0.D0 |
||||
IF (LAT1.NE.0.D0) THEN |
||||
RSW = (DLOG(TAN(0.5D0* ((LAT1+90.D0)*RAD_PER_DEG))))/DLON |
||||
END IF |
||||
|
||||
LAT = 2.0D0*ATAN(EXP(DLON* (RSW+AJ-KNOWNJ)))*DEG_PER_RAD - |
||||
+ 90.D0 |
||||
LON = (AI-KNOWNI)*DLON*DEG_PER_RAD + LON1 |
||||
IF (LON.GT.180.D0) LON = LON - 360.D0 |
||||
IF (LON.LT.-180.D0) LON = LON + 360.D0 |
||||
|
||||
|
||||
ccc !PS |
||||
ELSE IF (MAP_PROJ.EQ.2) THEN |
||||
|
||||
ccc ! Compute the reference longitude by rotating 90 degrees to |
||||
ccc ! the east to find the longitude line parallel to the |
||||
ccc ! positive x-axis. |
||||
REFLON = STDLON + 90.D0 |
||||
|
||||
ccc ! Compute numerator term of map scale factor |
||||
SCALE_TOP = 1.D0 + HEMI*SIN(TRUELAT1*RAD_PER_DEG) |
||||
|
||||
ccc ! Compute radius to known point |
||||
ALA1 = LAT1*RAD_PER_DEG |
||||
RSW = REBYDX*COS(ALA1)*SCALE_TOP/ (1.D0+HEMI*SIN(ALA1)) |
||||
|
||||
ccc ! Find the pole point |
||||
ALO1 = (LON1-REFLON)*RAD_PER_DEG |
||||
POLEI = KNOWNI - RSW*COS(ALO1) |
||||
POLEJ = KNOWNJ - HEMI*RSW*SIN(ALO1) |
||||
|
||||
ccc ! Compute radius to point of interest |
||||
XX = AI - POLEI |
||||
YY = (AJ-POLEJ)*HEMI |
||||
R2 = XX**2 + YY**2 |
||||
|
||||
ccc ! Now the magic code |
||||
IF (R2.EQ.0.D0) THEN |
||||
LAT = HEMI*90.D0 |
||||
LON = REFLON |
||||
ELSE |
||||
GI2 = (REBYDX*SCALE_TOP)**2.D0 |
||||
LAT = DEG_PER_RAD*HEMI*ASIN((GI2-R2)/ (GI2+R2)) |
||||
ARCCOS = ACOS(XX/SQRT(R2)) |
||||
IF (YY.GT.0) THEN |
||||
LON = REFLON + DEG_PER_RAD*ARCCOS |
||||
ELSE |
||||
LON = REFLON - DEG_PER_RAD*ARCCOS |
||||
END IF |
||||
END IF |
||||
|
||||
ccc ! Convert to a -180 -> 180 East convention |
||||
IF (LON.GT.180.D0) LON = LON - 360.D0 |
||||
IF (LON.LT.-180.D0) LON = LON + 360.D0 |
||||
|
||||
ccc !LAMBERT |
||||
ELSE IF (MAP_PROJ.EQ.1) THEN |
||||
|
||||
IF (ABS(TRUELAT2).GT.90.D0) THEN |
||||
TRUELAT2 = TRUELAT1 |
||||
END IF |
||||
|
||||
IF (ABS(TRUELAT1-TRUELAT2).GT.0.1D0) THEN |
||||
CONE = (DLOG(COS(TRUELAT1*RAD_PER_DEG))- |
||||
+ DLOG(COS(TRUELAT2*RAD_PER_DEG)))/ |
||||
+ (DLOG(TAN((90.D0-ABS(TRUELAT1))*RAD_PER_DEG* |
||||
+ 0.5D0))-DLOG(TAN((90.D0-ABS(TRUELAT2))*RAD_PER_DEG* |
||||
+ 0.5D0))) |
||||
ELSE |
||||
CONE = SIN(ABS(TRUELAT1)*RAD_PER_DEG) |
||||
END IF |
||||
|
||||
ccc ! Compute longitude differences and ensure we stay out of the |
||||
ccc ! forbidden "cut zone" |
||||
DELTALON1 = LON1 - STDLON |
||||
IF (DELTALON1.GT.+180.D0) DELTALON1 = DELTALON1 - 360.D0 |
||||
IF (DELTALON1.LT.-180.D0) DELTALON1 = DELTALON1 + 360.D0 |
||||
|
||||
ccc ! Convert truelat1 to radian and compute COS for later use |
||||
TL1R = TRUELAT1*RAD_PER_DEG |
||||
CTL1R = COS(TL1R) |
||||
|
||||
ccc ! Compute the radius to our known point |
||||
RSW = REBYDX*CTL1R/CONE* (TAN((90.D0*HEMI- |
||||
+ LAT1)*RAD_PER_DEG/2.D0)/TAN((90.D0*HEMI- |
||||
+ TRUELAT1)*RAD_PER_DEG/2.D0))**CONE |
||||
|
||||
ccc ! Find pole point |
||||
ALO1 = CONE* (DELTALON1*RAD_PER_DEG) |
||||
POLEI = HEMI*KNOWNI - HEMI*RSW*SIN(ALO1) |
||||
POLEJ = HEMI*KNOWNJ + RSW*COS(ALO1) |
||||
|
||||
CHI1 = (90.D0-HEMI*TRUELAT1)*RAD_PER_DEG |
||||
CHI2 = (90.D0-HEMI*TRUELAT2)*RAD_PER_DEG |
||||
|
||||
ccc ! See if we are in the southern hemispere and flip the |
||||
ccc ! indices if we are. |
||||
INEW = HEMI*AI |
||||
JNEW = HEMI*AJ |
||||
|
||||
ccc ! Compute radius**2 to i/j location |
||||
REFLON = STDLON + 90.D0 |
||||
XX = INEW - POLEI |
||||
YY = POLEJ - JNEW |
||||
R2 = (XX*XX+YY*YY) |
||||
R = SQRT(R2)/REBYDX |
||||
|
||||
ccc ! Convert to lat/lon |
||||
IF (R2.EQ.0.D0) THEN |
||||
LAT = HEMI*90.D0 |
||||
LON = STDLON |
||||
ELSE |
||||
LON = STDLON + DEG_PER_RAD*ATAN2(HEMI*XX,YY)/CONE |
||||
LON = DMOD(LON+360.D0,360.D0) |
||||
IF (CHI1.EQ.CHI2) THEN |
||||
CHI = 2.0D0*ATAN((R/TAN(CHI1))** (1.D0/CONE)* |
||||
+ TAN(CHI1*0.5D0)) |
||||
ELSE |
||||
CHI = 2.0D0*ATAN((R*CONE/SIN(CHI1))** (1.D0/CONE)* |
||||
+ TAN(CHI1*0.5D0)) |
||||
END IF |
||||
LAT = (90.0D0-CHI*DEG_PER_RAD)*HEMI |
||||
END IF |
||||
|
||||
IF (LON.GT.+180.D0) LON = LON - 360.D0 |
||||
IF (LON.LT.-180.D0) LON = LON + 360.D0 |
||||
|
||||
|
||||
ccc !lat-lon |
||||
ELSE IF (MAP_PROJ.EQ.6) THEN |
||||
|
||||
INEW = AI - KNOWNI |
||||
JNEW = AJ - KNOWNJ |
||||
|
||||
IF (INEW.LT.0.D0) INEW = INEW + 360.D0/LONINC |
||||
IF (INEW.GE.360.D0/DX) INEW = INEW - 360.D0/LONINC |
||||
c |
||||
ccc ! Compute deltalat and deltalon |
||||
DELTALAT = JNEW*LATINC |
||||
DELTALON = INEW*LONINC |
||||
|
||||
IF (POLE_LAT.NE.90.D0) THEN |
||||
CALL ROTATECOORDS(LAT1,LON1,OLAT,OLON,POLE_LAT,POLE_LON, |
||||
+ STDLON,-1) |
||||
LAT1N = OLAT |
||||
LON1N = OLON + STDLON |
||||
LAT = DELTALAT + LAT1N |
||||
LON = DELTALON + LON1N |
||||
ELSE |
||||
LAT = DELTALAT + LAT1 |
||||
LON = DELTALON + LON1 |
||||
END IF |
||||
|
||||
|
||||
IF (POLE_LAT.NE.90.D0) THEN |
||||
LON = LON - STDLON |
||||
CALL ROTATECOORDS(LAT,LON,OLAT,OLON,POLE_LAT,POLE_LON, |
||||
+ STDLON,1) |
||||
LAT = OLAT |
||||
LON = OLON |
||||
END IF |
||||
|
||||
IF (LON.LT.-180.D0) LON = LON + 360.D0 |
||||
IF (LON.GT.180.D0) LON = LON - 360.D0 |
||||
|
||||
ELSE |
||||
|
||||
PRINT *,'ERROR: Do not know map projection ',MAP_PROJ |
||||
|
||||
END IF |
||||
|
||||
LOC(1) = LAT |
||||
LOC(2) = LON |
||||
RETURN |
||||
|
||||
END |
||||
|
||||
|
||||
C NCLFORTSTART |
||||
SUBROUTINE ROTATECOORDS(ILAT,ILON,OLAT,OLON,LAT_NP,LON_NP,LON_0, |
||||
+ DIRECTION) |
||||
DOUBLE PRECISION ILAT,ILON |
||||
DOUBLE PRECISION OLAT,OLON |
||||
DOUBLE PRECISION LAT_NP,LON_NP,LON_0 |
||||
INTEGER DIRECTION |
||||
C NCLEND |
||||
|
||||
c ! >=0, default : computational -> geographical |
||||
c ! < 0 : geographical -> computational |
||||
|
||||
DOUBLE PRECISION RLAT,RLON |
||||
DOUBLE PRECISION PHI_NP,LAM_NP,LAM_0,DLAM |
||||
DOUBLE PRECISION SINPHI,COSPHI,COSLAM,SINLAM |
||||
DOUBLE PRECISION PI,RAD_PER_DEG,DEG_PER_RAD |
||||
|
||||
PI = 3.141592653589793D0 |
||||
RAD_PER_DEG = PI/180.D0 |
||||
DEG_PER_RAD = 180.D0/PI |
||||
|
||||
c ! Convert all angles to radians |
||||
PHI_NP = LAT_NP*RAD_PER_DEG |
||||
LAM_NP = LON_NP*RAD_PER_DEG |
||||
LAM_0 = LON_0*RAD_PER_DEG |
||||
RLAT = ILAT*RAD_PER_DEG |
||||
RLON = ILON*RAD_PER_DEG |
||||
|
||||
IF (DIRECTION.LT.0) THEN |
||||
c ! The equations are exactly the same except for one |
||||
c ! small difference with respect to longitude ... |
||||
DLAM = PI - LAM_0 |
||||
ELSE |
||||
DLAM = LAM_NP |
||||
END IF |
||||
SINPHI = COS(PHI_NP)*COS(RLAT)*COS(RLON-DLAM) + |
||||
+ SIN(PHI_NP)*SIN(RLAT) |
||||
COSPHI = SQRT(1.D0-SINPHI*SINPHI) |
||||
COSLAM = SIN(PHI_NP)*COS(RLAT)*COS(RLON-DLAM) - |
||||
+ COS(PHI_NP)*SIN(RLAT) |
||||
SINLAM = COS(RLAT)*SIN(RLON-DLAM) |
||||
IF (COSPHI.NE.0.D0) THEN |
||||
COSLAM = COSLAM/COSPHI |
||||
SINLAM = SINLAM/COSPHI |
||||
END IF |
||||
OLAT = DEG_PER_RAD*ASIN(SINPHI) |
||||
OLON = DEG_PER_RAD* (ATAN2(SINLAM,COSLAM)-DLAM-LAM_0+LAM_NP) |
||||
|
||||
END |
@ -0,0 +1,291 @@
@@ -0,0 +1,291 @@
|
||||
#!/usr/bin/env python |
||||
|
||||
import traceback |
||||
import sys |
||||
import sqlite3 |
||||
from datetime import datetime as dt |
||||
|
||||
import numpy as n |
||||
import matplotlib |
||||
matplotlib.use('agg') |
||||
import matplotlib.pyplot as plt |
||||
|
||||
#from wrf.core import Constants |
||||
#from wrf.var.temp import calc_temp |
||||
#from wrf.plot.matplotlib.defaults import (get_basemap, get_default_map_opts, |
||||
# get_null_opts) |
||||
|
||||
#from wrf.plot.matplotlib.helper import (add_plot_info_text, plot_map, |
||||
# plot_contourf) |
||||
|
||||
#__all__ = ["plot_2d"] |
||||
|
||||
|
||||
|
||||
|
||||
def get_basemap(wrfnc): |
||||
#TODO: handle multiple projections |
||||
lat2d = wrfnc.variables["XLAT"][0,:,:] |
||||
lon2d = wrfnc.variables["XLONG"][0,:,:] |
||||
|
||||
ny = len(wrfnc.dimensions["south_north"]) |
||||
nx = len(wrfnc.dimensions["west_east"]) |
||||
nz = len(wrfnc.dimensions["bottom_top"]) |
||||
|
||||
dx = wrfnc.DX |
||||
dy = wrfnc.DY |
||||
center_lat = wrfnc.CEN_LAT |
||||
center_lon = wrfnc.CEN_LON |
||||
true_lat1 = wrfnc.TRUELAT1 |
||||
true_lat2 = wrfnc.TRUELAT2 |
||||
|
||||
basemap = Basemap(projection="lcc", |
||||
lat_0=center_lat, |
||||
lon_0=center_lon, |
||||
lat_1=true_lat1, |
||||
lat_2=true_lat2, |
||||
llcrnrlon=lon2d[0,0], |
||||
llcrnrlat=lat2d[0,0], |
||||
urcrnrlon=lon2d[ny-1, nx-1], |
||||
urcrnrlat=lat2d[ny-1, nx-1], |
||||
resolution='i') |
||||
|
||||
return basemap |
||||
|
||||
def get_default_map_opts(): |
||||
landcolor = (204/255.0, 204/255.0, 153/255.0) |
||||
oceancolor = (102/255.0, 204/255.0, 255/255.0) |
||||
return MapOptions( |
||||
coastargs = {"linewidth":1.0, "linestyle":'solid', "color":'k'}, |
||||
countryargs = {"linewidth":0.5, "linestyle":'solid', "color":'k'}, |
||||
stateargs = {"linewidth":0.5, "linestyle":'solid', "color":'k'}, |
||||
mapboundaryargs = {"color":'k', "linewidth":1.0, |
||||
"fill_color":oceancolor}, |
||||
continentfillargs = {"color":landcolor, "lake_color":oceancolor, |
||||
"zorder":0}) |
||||
|
||||
|
||||
def get_null_opts(): |
||||
return FilledContourOptions(fcontourargs={}, |
||||
colorbarargs={"location" : "bottom", |
||||
"size" : "5%", "pad" : "2%", |
||||
"extend" : "both"}) |
||||
|
||||
def add_plot_info_text(ax, |
||||
top_left_text="", top_right_text="", |
||||
bot_left_text="", bot_right_text=""): |
||||
|
||||
plt.ioff() |
||||
if top_left_text != "": |
||||
plt.text(0.005,.995,top_left_text, |
||||
bbox=dict(facecolor="white"), |
||||
horizontalalignment="left", |
||||
verticalalignment="top", |
||||
transform = ax.transAxes, |
||||
fontsize=10) |
||||
|
||||
if top_right_text != "": |
||||
plt.text(.995,.995,top_right_text, |
||||
bbox=dict(facecolor="white"), |
||||
horizontalalignment="right", |
||||
verticalalignment="top", |
||||
transform = ax.transAxes, |
||||
fontsize=10) |
||||
|
||||
if bot_left_text != "": |
||||
plt.text(0.005,0.005,bot_left_text, |
||||
bbox=dict(facecolor="white"), |
||||
horizontalalignment="left", |
||||
verticalalignment="bottom", |
||||
transform = ax.transAxes, |
||||
fontsize=10) |
||||
|
||||
if bot_right_text != "": |
||||
plt.text(.995,0.005,bot_right_text, |
||||
bbox=dict(facecolor="white"), |
||||
horizontalalignment="right", |
||||
verticalalignment="bottom", |
||||
transform = ax.transAxes, |
||||
fontsize=10) |
||||
|
||||
def plot_map(basemap, mapoptions): |
||||
plt.ioff() |
||||
if mapoptions.mapboundaryargs is not None: |
||||
basemap.drawmapboundary(**mapoptions.mapboundaryargs) |
||||
|
||||
if mapoptions.continentfillargs is not None: |
||||
basemap.fillcontinents(**mapoptions.continentfillargs) |
||||
|
||||
if mapoptions.coastargs is not None: |
||||
basemap.drawcoastlines(**mapoptions.coastargs) |
||||
|
||||
if mapoptions.countryargs is not None: |
||||
basemap.drawcountries(**mapoptions.countryargs) |
||||
|
||||
if mapoptions.stateargs is not None: |
||||
basemap.drawstates(**mapoptions.stateargs) |
||||
|
||||
if mapoptions.countyargs is not None: |
||||
basemap.drawcounties(**mapoptions.countyargs) |
||||
|
||||
if mapoptions.riverargs is not None: |
||||
basemap.drawrivers(**mapoptions.riverargs) |
||||
|
||||
def plot_contourf(x,y,data,basemap, contourfoptions): |
||||
plt.ioff() |
||||
cs1 = None |
||||
if contourfoptions.contourargs is not None: |
||||
cs1 = basemap.contour(x,y,data,**contourfoptions.contourargs) |
||||
|
||||
cs2 = None |
||||
if contourfoptions.fcontourargs is not None: |
||||
cs2 = basemap.contourf(x,y,data,**contourfoptions.fcontourargs) |
||||
|
||||
cb = None |
||||
if contourfoptions.colorbarargs is not None: |
||||
cb = basemap.colorbar(cs2, **contourfoptions.colorbarargs) |
||||
|
||||
if contourfoptions.labelargs is not None: |
||||
plt.clabel(cs1, **contourfoptions.labelargs) |
||||
|
||||
return cs1, cs2, cb |
||||
|
||||
def get_null_opts(): |
||||
return FilledContourOptions(fcontourargs={}, |
||||
colorbarargs={"location" : "bottom", |
||||
"size" : "5%", "pad" : "2%", |
||||
"extend" : "both"}) |
||||
|
||||
class MapOptions(object): |
||||
def __init__(self, |
||||
coastargs = None, |
||||
countyargs = None, |
||||
countryargs = None, |
||||
riverargs = None, |
||||
stateargs = None, |
||||
mapboundaryargs = None, |
||||
continentfillargs = None): |
||||
self.coastargs = coastargs |
||||
self.countyargs = countyargs |
||||
self.countryargs = countryargs |
||||
self.riverargs = riverargs |
||||
self.stateargs = stateargs |
||||
self.mapboundaryargs = mapboundaryargs |
||||
self.continentfillargs = continentfillargs |
||||
|
||||
def plot_2d(wrfnc, varname=None, outfile=None, title=None, |
||||
map_opts=None, plot_opts=None, |
||||
top_left_info="", top_right_info="", |
||||
bot_left_info="", bot_right_info="", |
||||
wks_type="png", var=None, |
||||
time_in=0): |
||||
|
||||
try: |
||||
plt.ioff() |
||||
print "generating %s.%s" % (outfile, wks_type) |
||||
if var is not None: |
||||
field = var |
||||
elif varname is not None: |
||||
field = wrfnc.variables[varname][time_in,:,:] |
||||
|
||||
lat2d = wrfnc.variables["XLAT"][time_in,:,:] |
||||
lon2d = wrfnc.variables["XLONG"][time_in,:,:] |
||||
times = wrfnc.variables["Times"][time_in,:] |
||||
model_time = "".join(times) |
||||
start_date = dt.strptime(model_time, "%Y-%m-%d_%H:%M:%S") |
||||
|
||||
ny = len(wrfnc.dimensions["south_north"]) |
||||
nx = len(wrfnc.dimensions["west_east"]) |
||||
nz = len(wrfnc.dimensions["bottom_top"]) |
||||
|
||||
fig = plt.figure(figsize=(8,8), dpi=200) |
||||
ax = fig.add_axes([0.1,0.1,0.8,0.8]) |
||||
|
||||
bm = get_basemap(wrfnc) |
||||
if map_opts is None: |
||||
map_opts = get_default_map_opts() |
||||
if plot_opts is None: |
||||
plot_opts = get_null_opts() |
||||
|
||||
x,y = bm(lon2d, lat2d) |
||||
|
||||
plot_map(bm,map_opts) |
||||
|
||||
plt.xticks(rotation=70) |
||||
tplot = plot_contourf(x,y,field,bm,plot_opts) |
||||
|
||||
|
||||
add_plot_info_text(ax, |
||||
top_left_info, top_right_info, |
||||
bot_left_info, bot_right_info) |
||||
|
||||
ax.set_title(title,fontdict={"fontsize" : 20}) |
||||
|
||||
plt.savefig("%s.%s" % (outfile, wks_type)) |
||||
|
||||
plt.clf() |
||||
plt.close(fig) |
||||
except: |
||||
# print the stack trace since it will be lost when used in a |
||||
# multiprocessing worker. |
||||
print traceback.format_exc() |
||||
raise |
||||
finally: |
||||
sys.stdout.flush() |
||||
|
||||
def main(): |
||||
parser = argparse.ArgumentParser(description="Generate meteorological " |
||||
"plots for a specific data file") |
||||
parser.add_argument("-v", "--var", required=True, |
||||
help="variable name") |
||||
parser.add_argument("-f", "--filename", required=True, |
||||
help="WRF file to plot") |
||||
parser.add_argument("-o", "--outdir", default=".", required=False, |
||||
help="output directory for images") |
||||
parser.add_argument("-l", "--levels", required=False, type=float, |
||||
nargs="+", |
||||
default=None, |
||||
help=("the start, end, and increment for contour levels" |
||||
" as a list of items with spaces between them" |
||||
"example: 1 10 2 ")) |
||||
parser.add_argument("-c", "--customlevels", required=False, type=float, |
||||
nargs="+", |
||||
default=None, |
||||
help=("a list of space delimited contour levels" |
||||
"example: 1 2 3 4 5 19 28 200 ")) |
||||
|
||||
args = parser.parse_args() |
||||
|
||||
if not os.path.exists(args.filename): |
||||
raise RuntimeError ("%s not found" % args.filename) |
||||
|
||||
if not os.path.exists(args.outdir): |
||||
os.makedirs(args.outdir) |
||||
|
||||
basename = os.path.basename(args.filename) |
||||
wrfnc = NetCDF(args.filename, mode='r') |
||||
|
||||
outfile = os.path.join(args.outdir, domain, args.var, "%s.%s" % (basename,args.var)) |
||||
if not os.path.exists(os.path.dirname(outfile)): |
||||
os.makedirs(os.path.dirname(outfile)) |
||||
|
||||
if args.levels is not None or args.customlevels is not None: |
||||
plot_opts = get_null_opts() |
||||
if args.levels is not None: |
||||
if len(args.levels) < 2 or len(args.levels) > 3: |
||||
raise RuntimeError("levels argument is invalid") |
||||
plot_opts.fcontourargs["levels"] = [x for x in n.arange(args.levels[0], |
||||
args.levels[1], |
||||
args.levels[2])] |
||||
plot_opts.fcontourargs["extend"] = "both" |
||||
elif args.customlevels is not None: |
||||
plot_opts.fcontourargs["levels"] = args.customlevels |
||||
plot_opts.fcontourargs["extend"] = "both" |
||||
else: |
||||
plot_opts = None |
||||
|
||||
plot_2d(wrfnc, args.var, outfile, "%s"%args.var, |
||||
plot_opts = plot_opts) |
||||
|
||||
if __name__ == "__main__": |
||||
main() |
@ -0,0 +1,32 @@
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env python |
||||
import os |
||||
import argparse |
||||
|
||||
import Ngl |
||||
|
||||
from wrf.system import SOMMemberPlotSystem |
||||
|
||||
if __name__ == "__main__": |
||||
|
||||
parser = argparse.ArgumentParser(description="Generate meteorological " |
||||
"plots for SOM members") |
||||
parser.add_argument("-c", "--casename", required=True, |
||||
help="the case name (e.g. 'site1-october')") |
||||
parser.add_argument("-s", "--somid", required=True, |
||||
help="the SOM ID to use (e.g. 'SOM001')") |
||||
parser.add_argument("-p", "--caseparent", required=False, |
||||
default="/projectw/reanalyses/1.2", |
||||
help=("the case parent directory " |
||||
"[default: /projectw/reanalyses/1.2]")) |
||||
args = parser.parse_args() |
||||
|
||||
parentdir = os.path.expanduser(os.path.expandvars(args.caseparent)) |
||||
casename = args.casename |
||||
somid = args.somid |
||||
|
||||
sys = SOMMemberPlotSystem(parentdir, casename, somid) |
||||
|
||||
try: |
||||
sys.run() |
||||
finally: |
||||
Ngl.end() |
@ -0,0 +1,143 @@
@@ -0,0 +1,143 @@
|
||||
|
||||
import wrf.var as w |
||||
import numpy as n |
||||
|
||||
from netCDF4 import Dataset as NetCDF |
||||
|
||||
def main(): |
||||
wrfnc = NetCDF("/Users/bladwig/wrfout_d03_2003-05-07_09:00:00") |
||||
|
||||
# Cape NO RESULTS FOR LCL OR LFC |
||||
cape, cin, lcl, lfc = w.getvar(wrfnc, "cape2d") |
||||
#cape, cin = w.getvar(wrfnc, "cape3d") |
||||
print n.amax(cape) |
||||
print n.amax(cin) |
||||
print n.amax(lcl) |
||||
print n.amax(lfc) |
||||
|
||||
|
||||
# DBZ |
||||
dbz = w.getvar(wrfnc, "dbz") |
||||
print n.amax(dbz) |
||||
|
||||
# DP |
||||
dp = w.getvar(wrfnc, "dp", units="f") |
||||
print n.amax(dp) |
||||
|
||||
dp2 = w.getvar(wrfnc, "dp2m", units="f") |
||||
print n.amax(dp2) |
||||
|
||||
# Height |
||||
ht = w.getvar(wrfnc, "height", msl=False, units="m") |
||||
print n.amax(ht) |
||||
|
||||
geopt = w.getvar(wrfnc, "geopt") |
||||
print n.amax(geopt) |
||||
|
||||
# Helicity |
||||
srh = w.getvar(wrfnc, "srh") |
||||
print n.amax(srh) |
||||
|
||||
uhel = w.getvar(wrfnc, "uhel") |
||||
print n.amax(uhel) |
||||
|
||||
# Omega (Not sure if this is correct, and units aren't C) |
||||
omega = w.getvar(wrfnc, "omega") |
||||
print n.amax(omega) |
||||
|
||||
# Precip Water (NOT SURE) |
||||
pw = w.getvar(wrfnc, "pw") |
||||
print n.amax(pw) |
||||
|
||||
# RH |
||||
rh = w.getvar(wrfnc, "rh") |
||||
print n.amax(rh) |
||||
|
||||
rh2 = w.getvar(wrfnc, "rh2m") |
||||
print n.amax(rh2) |
||||
|
||||
# SLP |
||||
slp = w.getvar(wrfnc, "slp", units="hpa") |
||||
print n.amax(slp) |
||||
|
||||
# TEMP |
||||
t = w.getvar(wrfnc, "temp", units="f") |
||||
print n.amax(t) |
||||
|
||||
# ETH VALUES SEEM HIGH.... |
||||
eth = w.getvar(wrfnc, "theta_e", units="k") |
||||
print n.amax(eth) |
||||
|
||||
tv = w.getvar(wrfnc, "tv", units="k") |
||||
print n.amax(tv) |
||||
|
||||
# Note: NCL says this is in 'C', but appears to be 'K' |
||||
tw = w.getvar(wrfnc, "tw", units="f") |
||||
print n.amax(tw) |
||||
|
||||
# WIND |
||||
umet,vmet = w.getvar(wrfnc, "uvmet", units="kts") |
||||
print n.amax(umet) |
||||
print n.amax(vmet) |
||||
|
||||
umet10,vmet10 = w.getvar(wrfnc, "uvmet10", units="kts") |
||||
print n.amax(umet10) |
||||
print n.amax(vmet10) |
||||
|
||||
|
||||
|
||||
# TERRAIN |
||||
ter = w.getvar(wrfnc, "terrain", units="dm") |
||||
print n.amax(ter) |
||||
|
||||
# VORTICITY |
||||
avo = w.getvar(wrfnc, "avo") |
||||
print n.amax(avo) |
||||
|
||||
pvo = w.getvar(wrfnc, "pvo") |
||||
print n.amax(pvo) |
||||
|
||||
# LAT/LON |
||||
lat = w.getvar(wrfnc, "lat") |
||||
print n.amax(lat) |
||||
print n.amin(lat) |
||||
|
||||
lon = w.getvar(wrfnc, "lon") |
||||
print n.amax(lon) |
||||
print n.amin(lon) |
||||
|
||||
i,j = w.get_ij(wrfnc, -97.516540, 35.467787) |
||||
print i,j |
||||
|
||||
lon, lat = w.get_ll(wrfnc, 33.5, 33.5) |
||||
print lon, lat |
||||
|
||||
#ETA -- Result somewhat different than geopt |
||||
z = w.convert_eta(wrfnc, msl=False, units="m") |
||||
print n.amax(z) |
||||
|
||||
diff = n.abs(z - ht)/ht * 100.0 |
||||
print n.amin(diff), n.amax(diff) |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
main() |
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
import setuptools |
||||
import numpy.distutils.core |
||||
|
||||
ext1 = numpy.distutils.core.Extension( |
||||
name = "wrf.var._wrfext", |
||||
sources = ["src/python/wrf/var/wrfext.f90", |
||||
"src/python/wrf/var/wrfext.pyf"] |
||||
) |
||||
|
||||
ext2 = numpy.distutils.core.Extension( |
||||
name = "wrf.var._wrfcape", |
||||
sources = ["src/python/wrf/var/wrfcape.f90", |
||||
"src/python/wrf/var/wrfcape.pyf"] |
||||
) |
||||
|
||||
numpy.distutils.core.setup( |
||||
name = "wrf.var", |
||||
version = "0.0.1", |
||||
packages = setuptools.find_packages("src/python"), |
||||
ext_modules = [ext1,ext2], |
||||
package_dir={"":"src/python"}, |
||||
scripts=[], |
||||
) |
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
try: |
||||
import pkg_resources |
||||
pkg_resources.declare_namespace(__name__) |
||||
except ImportError: |
||||
import pkgutil |
||||
__path__ = pkgutil.extend_path(__path__, __name__) |
||||
|
@ -0,0 +1,214 @@
@@ -0,0 +1,214 @@
|
||||
import warnings |
||||
|
||||
from extension import * |
||||
import extension |
||||
from cape import * |
||||
import cape |
||||
from constants import * |
||||
import constants |
||||
from ctt import * |
||||
import ctt |
||||
from dbz import * |
||||
import dbz |
||||
from destagger import * |
||||
import destagger |
||||
from dewpoint import * |
||||
import dewpoint |
||||
from etaconv import * |
||||
import etaconv |
||||
from geoht import * |
||||
import geoht |
||||
from helicity import * |
||||
import helicity |
||||
from interp import * |
||||
import interp |
||||
from latlon import * |
||||
import latlon |
||||
from omega import * |
||||
import omega |
||||
from precip import * |
||||
import precip |
||||
from pressure import * |
||||
import pressure |
||||
from psadlookup import * |
||||
import psadlookup |
||||
from pw import * |
||||
import pw |
||||
from rh import * |
||||
import rh |
||||
from slp import * |
||||
import slp |
||||
from temp import * |
||||
import temp |
||||
from terrain import * |
||||
import terrain |
||||
from uvmet import * |
||||
import uvmet |
||||
from vorticity import * |
||||
import vorticity |
||||
from wind import * |
||||
import wind |
||||
from times import * |
||||
import times |
||||
from units import * |
||||
import units |
||||
|
||||
__all__ = ["getvar"] |
||||
__all__ += extension.__all__ |
||||
__all__ += cape.__all__ |
||||
__all__ += constants.__all__ |
||||
__all__ += ctt.__all__ |
||||
__all__ += dbz.__all__ |
||||
__all__ += destagger.__all__ |
||||
__all__ += dewpoint.__all__ |
||||
__all__ += etaconv.__all__ |
||||
__all__ += geoht.__all__ |
||||
__all__ += helicity.__all__ |
||||
__all__ += interp.__all__ |
||||
__all__ += latlon.__all__ |
||||
__all__ += omega.__all__ |
||||
__all__ += precip.__all__ |
||||
__all__ += psadlookup.__all__ |
||||
__all__ += pw.__all__ |
||||
__all__ += rh.__all__ |
||||
__all__ += slp.__all__ |
||||
__all__ += temp.__all__ |
||||
__all__ += terrain.__all__ |
||||
__all__ += uvmet.__all__ |
||||
__all__ += vorticity.__all__ |
||||
__all__ += wind.__all__ |
||||
__all__ += times.__all__ |
||||
__all__ += pressure.__all__ |
||||
__all__ += units.__all__ |
||||
|
||||
# func is the function to call. kargs are required arguments that should |
||||
# not be altered by the user |
||||
_FUNC_MAP = {"cape2d" : get_2dcape, |
||||
"cape3d" : get_3dcape, |
||||
"dbz" : get_dbz, |
||||
"maxdbz" : get_max_dbz, |
||||
"dp" : get_dp, |
||||
"dp2m" : get_dp_2m, |
||||
"height" : get_height, |
||||
"geopt" : get_geopt, |
||||
"srh" : get_srh, |
||||
"uhel" : get_uh, |
||||
"omega" : get_omega, |
||||
"pw" : get_pw, |
||||
"rh" : get_rh, |
||||
"rh2m" : get_rh_2m, |
||||
"slp" : get_slp, |
||||
"theta" : get_theta, |
||||
"temp" : get_temp, |
||||
"theta_e" : get_eth, |
||||
"tv" : get_tv, |
||||
"twb" : get_tw, |
||||
"terrain" : get_terrain, |
||||
"times" : get_times, |
||||
"uvmet" : get_uvmet, |
||||
"uvmet10" : get_uvmet10, |
||||
"avo" : get_avo, |
||||
"pvo" : get_pvo, |
||||
"ua" : get_u_destag, |
||||
"va" : get_v_destag, |
||||
"wa" : get_w_destag, |
||||
"lat" : get_lat, |
||||
"lon" : get_lon, |
||||
"pressure" : get_pressure, |
||||
"wspddir" : get_destag_wspd_wdir, |
||||
"wspddir_uvmet" : get_uvmet_wspd_wdir, |
||||
"wspddir_uvmet10" : get_uvmet10_wspd_wdir, |
||||
"ctt" : get_ctt |
||||
} |
||||
|
||||
_VALID_ARGS = {"cape2d" : ["missing", "timeidx"], |
||||
"cape3d" : ["missing", "timeidx"], |
||||
"dbz" : ["do_variant", "do_liqskin", "timeidx"], |
||||
"maxdbz" : ["do_variant", "do_liqskin", "timeidx"], |
||||
"dp" : ["timeidx", "units"], |
||||
"dp2m" : ["timeidx", "units"], |
||||
"height" : ["msl", "units", "timeidx"], |
||||
"geopt" : ["timeidx"], |
||||
"srh" : ["top", "timeidx"], |
||||
"uhel" : ["bottom", "top", "timeidx"], |
||||
"omega" : ["timeidx"], |
||||
"pw" : ["timeidx"], |
||||
"rh" : ["timeidx"], |
||||
"rh2m" : ["timeidx"], |
||||
"slp" : ["units", "timeidx"], |
||||
"temp" : ["units", "timeidx"], |
||||
"theta" : ["units", "timeidx"], |
||||
"theta_e" : ["timeidx", "units"], |
||||
"tv" : ["units", "timeidx"], |
||||
"twb" : ["units", "timeidx"], |
||||
"terrain" : ["units", "timeidx"], |
||||
"times" : ["timeidx"], |
||||
"uvmet" : ["units", "timeidx"], |
||||
"uvmet10" : ["units", "timeidx"], |
||||
"avo" : ["timeidx"], |
||||
"pvo" : ["timeidx"], |
||||
"ua" : ["units", "timeidx"], |
||||
"va" : ["units", "timeidx"], |
||||
"wa" : ["units", "timeidx"], |
||||
"lat" : ["timeidx"], |
||||
"lon" : ["timeidx"], |
||||
"pressure" : ["units", "timeidx"], |
||||
"wspddir" : ["units", "timeidx"], |
||||
"wspddir_uvmet" : ["units", "timeidx"], |
||||
"wspddir_uvmet10" : ["units", "timeidx"], |
||||
"ctt" : ["timeidx"] |
||||
} |
||||
|
||||
_ALIASES = {"cape_2d" : "cape2d", |
||||
"cape_3d" : "cape3d", |
||||
"eth" : "theta_e", |
||||
"mdbz" : "maxdbz", |
||||
"geopotential" : "geopt", |
||||
"helicity" : "srh", |
||||
"latitude" : "lat", |
||||
"longitude" : "lon", |
||||
"omg" : "omega", |
||||
"pres" : "pressure", |
||||
"p" : "pressure", |
||||
"rh2" : "rh2m", |
||||
"z": "height", |
||||
"ter" : "terrain", |
||||
"updraft_helicity" : "uhel", |
||||
"td" : "dp", |
||||
"td2" : "dp2m" |
||||
} |
||||
|
||||
class ArgumentError(Exception): |
||||
def __init__(self, msg): |
||||
self.msg = msg |
||||
|
||||
def __str__(self): |
||||
return self.msg |
||||
|
||||
def _undo_alias(alias): |
||||
actual = _ALIASES.get(alias, None) |
||||
if actual is None: |
||||
return alias |
||||
else: |
||||
return actual |
||||
|
||||
def _check_kargs(var, kargs): |
||||
for arg, val in kargs.iteritems(): |
||||
if arg not in _VALID_ARGS[var]: |
||||
raise ArgumentError("'%s' is an invalid keyword " |
||||
"argument for '%s" % (arg, var)) |
||||
|
||||
|
||||
def getvar(wrfnc, var, **kargs): |
||||
actual_var = _undo_alias(var) |
||||
if actual_var not in _VALID_ARGS: |
||||
raise ArgumentError("'%s' is not a valid variable name" % (var)) |
||||
|
||||
_check_kargs(actual_var, kargs) |
||||
return _FUNC_MAP[actual_var](wrfnc,**kargs) |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,84 @@
@@ -0,0 +1,84 @@
|
||||
import numpy.ma as ma |
||||
|
||||
from wrf.var.extension import computetk,computecape |
||||
from wrf.var.destagger import destagger |
||||
from wrf.var.constants import Constants, ConversionFactors |
||||
|
||||
__all__ = ["get_2dcape", "get_3dcape"] |
||||
|
||||
def get_2dcape(wrfnc, missing=-999999.0, timeidx=0): |
||||
"""Return the 2d fields of cape, cin, lcl, and lfc""" |
||||
t = wrfnc.variables["T"][timeidx,:,:,:] |
||||
p = wrfnc.variables["P"][timeidx,:,:,:] |
||||
pb = wrfnc.variables["PB"][timeidx,:,:,:] |
||||
qv = wrfnc.variables["QVAPOR"][timeidx,:,:,:] |
||||
ph = wrfnc.variables["PH"][timeidx,:,:,:] |
||||
phb = wrfnc.variables["PHB"][timeidx,:,:,:] |
||||
ter = wrfnc.variables["HGT"][timeidx,:,:] |
||||
psfc = wrfnc.variables["PSFC"][timeidx,:,:] |
||||
|
||||
full_t = t + Constants.T_BASE |
||||
full_p = p + pb |
||||
tk = computetk(full_p, full_t) |
||||
|
||||
geopt = ph + phb |
||||
geopt_unstag = destagger(geopt, 0) |
||||
z = geopt_unstag/Constants.G |
||||
|
||||
# Convert pressure to hPa |
||||
p_hpa = ConversionFactors.PA_TO_HPA * full_p |
||||
psfc_hpa = ConversionFactors.PA_TO_HPA * psfc # This may be the bug in NCL, as they pass this in |
||||
# has Pa, but other pressure is hPa. Converting to |
||||
# hPa here. |
||||
|
||||
i3dflag = 0 |
||||
ter_follow = 1 |
||||
|
||||
cape_res,cin_res = computecape(p_hpa,tk,qv,z,ter,psfc_hpa, |
||||
missing,i3dflag,ter_follow) |
||||
|
||||
cape = cape_res[0,:,:] |
||||
cin = cin_res[0,:,:] |
||||
lcl = cin_res[1,:,:] |
||||
lfc = cin_res[2,:,:] |
||||
|
||||
return (ma.masked_values(cape,missing), |
||||
ma.masked_values(cin,missing), |
||||
ma.masked_values(lcl,missing), |
||||
ma.masked_values(lfc,missing)) |
||||
|
||||
def get_3dcape(wrfnc, missing=-999999.0, timeidx=0): |
||||
"""Return the 3d fields of cape and cin""" |
||||
t = wrfnc.variables["T"][timeidx,:,:,:] |
||||
p = wrfnc.variables["P"][timeidx,:,:,:] |
||||
pb = wrfnc.variables["PB"][timeidx,:,:,:] |
||||
qv = wrfnc.variables["QVAPOR"][timeidx,:,:,:] |
||||
ph = wrfnc.variables["PH"][timeidx,:,:,:] |
||||
phb = wrfnc.variables["PHB"][timeidx,:,:,:] |
||||
ter = wrfnc.variables["HGT"][timeidx,:,:] |
||||
psfc = wrfnc.variables["PSFC"][timeidx,:,:] |
||||
|
||||
full_t = t + Constants.T_BASE |
||||
full_p = p + pb |
||||
tk = computetk(full_p, full_t) |
||||
|
||||
geopt = ph + phb |
||||
geopt_unstag = destagger(geopt, 0) |
||||
z = geopt_unstag/Constants.G |
||||
|
||||
# Convert pressure to hPa |
||||
p_hpa = ConversionFactors.PA_TO_HPA * full_p |
||||
psfc_hpa = ConversionFactors.PA_TO_HPA * psfc # This may be the bug in NCL, as they pass this in |
||||
# has Pa, but other pressure is hPa. Converting to |
||||
# hPa here. |
||||
|
||||
i3dflag = 1 |
||||
ter_follow = 1 |
||||
|
||||
cape,cin = computecape(p_hpa,tk,qv,z,ter,psfc_hpa, |
||||
missing,i3dflag,ter_follow) |
||||
return (ma.masked_values(cape, missing), |
||||
ma.masked_values(cin, missing)) |
||||
|
||||
|
||||
|
@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
|
||||
|
||||
__all__ = ["Constants", "ConversionFactors"] |
||||
|
||||
class Constants(object): |
||||
R = 287.06 |
||||
CP = 1005.0 |
||||
G = 9.81 |
||||
TCK0 = 273.15 |
||||
T_BASE = 300.0 # In WRF the base temperature is always 300 (not var T00) |
||||
PI = 3.14159265 |
||||
|
||||
|
||||
class ConversionFactors(object): |
||||
PA_TO_HPA = .01 |
||||
PA_TO_TORR = 760.0/101325.0 |
||||
PA_TO_MMHG = PA_TO_TORR * 1.000000142466321 |
||||
PA_TO_ATM = 1.0 / 1.01325E5 |
||||
MPS_TO_KTS = 1.94384 |
||||
MPS_TO_KMPH = 3.60 |
||||
MPS_TO_MPH = 2.23694 |
||||
MPS_TO_FPS = 3.28084 |
||||
M_TO_KM = 1.0/1000.0 |
||||
M_TO_DM = 1.0/10.0 |
||||
M_TO_FT = 3.28084 |
||||
M_TO_MILES = .000621371 |
||||
|
||||
|
@ -0,0 +1,47 @@
@@ -0,0 +1,47 @@
|
||||
|
||||
import numpy as n |
||||
|
||||
from wrf.var.extension import computectt, computetk |
||||
from wrf.var.constants import Constants, ConversionFactors |
||||
from wrf.var.destagger import destagger |
||||
from wrf.var.decorators import convert_units |
||||
|
||||
__all__ = ["get_ctt"] |
||||
|
||||
@convert_units("temp", "c") |
||||
def get_ctt(wrfnc, units="c", timeidx=0): |
||||
"""Return the cloud top temperature. |
||||
|
||||
""" |
||||
t = wrfnc.variables["T"][timeidx,:,:,:] |
||||
p = wrfnc.variables["P"][timeidx,:,:,:] |
||||
pb = wrfnc.variables["PB"][timeidx,:,:,:] |
||||
ph = wrfnc.variables["PH"][timeidx,:,:,:] |
||||
phb = wrfnc.variables["PHB"][timeidx,:,:,:] |
||||
ter = wrfnc.variables["HGT"][timeidx,:,:] |
||||
qv = wrfnc.variables["QVAPOR"][timeidx,:,:,:] * 1000.0 # g/kg |
||||
|
||||
haveqci = 1 |
||||
if "QICE" in wrfnc.variables: |
||||
qice = wrfnc.variables["QICE"][timeidx,:,:,:] * 1000.0 #g/kg |
||||
else: |
||||
qice = n.zeros(qv.shape, qv.dtype) |
||||
haveqci = 0 |
||||
|
||||
if "QCLOUD" in wrfnc.variables: |
||||
qcld = wrfnc.variables["QCLOUD"][timeidx,:,:,:] * 1000.0 #g/kg |
||||
else: |
||||
raise RuntimeError("'QCLOUD' not found in NetCDF file") |
||||
|
||||
full_p = p + pb |
||||
p_hpa = full_p * ConversionFactors.PA_TO_HPA |
||||
full_t = t + Constants.T_BASE |
||||
tk = computetk(full_p, full_t) |
||||
|
||||
geopt = ph + phb |
||||
geopt_unstag = destagger(geopt, 0) |
||||
ght = geopt_unstag / Constants.G |
||||
|
||||
ctt = computectt(p_hpa,tk,qice,qcld,qv,ght,ter,haveqci) |
||||
|
||||
return ctt |
@ -0,0 +1,58 @@
@@ -0,0 +1,58 @@
|
||||
import numpy as n |
||||
|
||||
from wrf.var.extension import computedbz,computetk |
||||
from wrf.var.constants import Constants |
||||
|
||||
__all__ = ["get_dbz", "get_max_dbz"] |
||||
|
||||
def get_dbz(wrfnc, do_varint=False, do_liqskin=False, timeidx=0): |
||||
""" Return the dbz |
||||
|
||||
do_varint - do variable intercept (if False, constants are used. Otherwise, |
||||
intercepts are calculated using a technique from Thompson, Rasmussen, |
||||
and Manning (2004, Monthly Weather Review, Vol. 132, No. 2, pp. 519-542.) |
||||
|
||||
do_liqskin - do liquid skin for snow (frozen particles above freezing scatter |
||||
as liquid) |
||||
|
||||
""" |
||||
t = wrfnc.variables["T"][timeidx,:,:,:] |
||||
p = wrfnc.variables["P"][timeidx,:,:,:] |
||||
pb = wrfnc.variables["PB"][timeidx,:,:,:] |
||||
|
||||
qv = wrfnc.variables["QVAPOR"][timeidx,:,:,:] |
||||
qr = wrfnc.variables["QRAIN"][timeidx,:,:,:] |
||||
|
||||
if "QSNOW" in wrfnc.variables: |
||||
qs = wrfnc.variables["QSNOW"][timeidx,:,:,:] |
||||
else: |
||||
qs = n.zeros((qv.shape[0], qv.shape[1], qv.shape[2]), "float") |
||||
|
||||
if "QGRAUP" in wrfnc.variables: |
||||
qg = wrfnc.variables["QGRAUP"][timeidx,:,:,:] |
||||
else: |
||||
qg = n.zeros((qv.shape[0], qv.shape[1], qv.shape[2]), "float") |
||||
|
||||
# If qsnow is all 0, set sn0 to 1 |
||||
sn0 = 0 |
||||
if (n.any(qs != 0)): |
||||
sn0 = 1 |
||||
|
||||
full_t = t + Constants.T_BASE |
||||
full_p = p + pb |
||||
tk = computetk(full_p, full_t) |
||||
|
||||
ivarint = 0 |
||||
if do_varint: |
||||
ivarint = 1 |
||||
|
||||
iliqskin = 0 |
||||
if do_liqskin: |
||||
iliqskin = 1 |
||||
|
||||
return computedbz(full_p,tk,qv,qr,qs,qg,sn0,ivarint,iliqskin) |
||||
|
||||
def get_max_dbz(wrfnc, do_varint=False, do_liqskin=False, timeidx=0): |
||||
return n.amax(get_dbz(wrfnc, do_varint, do_liqskin, timeidx), |
||||
axis=0) |
||||
|
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
from functools import wraps |
||||
from inspect import getargspec |
||||
|
||||
from wrf.var.units import do_conversion, check_units |
||||
|
||||
__all__ = ["convert_units"] |
||||
|
||||
def convert_units(unit_type, alg_unit): |
||||
def convert_decorator(func): |
||||
@wraps(func) |
||||
def func_wrapper(*args, **kargs): |
||||
# If units are provided to the method call, use them. |
||||
# Otherwise, need to parse the argspec to find what the default |
||||
# value is. |
||||
if ("units" in kargs): |
||||
desired_units = kargs["units"] |
||||
else: |
||||
argspec = getargspec(func) |
||||
print argspec |
||||
arg_idx_from_right = len(argspec.args) - argspec.args.index("units") |
||||
desired_units = argspec.defaults[-arg_idx_from_right] |
||||
|
||||
#print desired_idx |
||||
#desired_units = argspec.defaults[desired_idx] |
||||
print desired_units |
||||
|
||||
check_units(desired_units, unit_type) |
||||
|
||||
# Unit conversion done here |
||||
return do_conversion(func(*args, **kargs), unit_type, |
||||
alg_unit, desired_units) |
||||
return func_wrapper |
||||
|
||||
return convert_decorator |
||||
|
||||
def combine_list_and_times(alg_out_dim): |
||||
def combine_decorator(func): |
||||
@wraps(func) |
||||
def func_wrapper(*args, **kargs): |
||||
argspec = getargspec(func) |
||||
|
||||
return func_wrapper |
||||
|
||||
return combine_decorator |
@ -0,0 +1,59 @@
@@ -0,0 +1,59 @@
|
||||
|
||||
import numpy as n |
||||
|
||||
__all__ = ["destagger", "destagger_windcomp", "destagger_winds"] |
||||
|
||||
def destagger(var, stagger_dim): |
||||
""" De-stagger the variable. |
||||
|
||||
Arguments: |
||||
- var is a numpy array for the variable |
||||
- stagger_dim is the dimension of the numpy array to de-stagger |
||||
(e.g. 0, 1, 2) |
||||
|
||||
""" |
||||
var_shape = var.shape |
||||
num_dims = len(var_shape) |
||||
stagger_dim_size = var_shape[stagger_dim] |
||||
|
||||
# Dynamically building the range slices to create the appropriate |
||||
# number of ':'s in the array accessor lists. |
||||
# For example, for a 3D array, the calculation would be |
||||
# result = .5 * (var[:,:,0:stagger_dim_size-2] + var[:,:,1:stagger_dim_size-1]) |
||||
# for stagger_dim=2. So, full slices would be used for dims 0 and 1, but |
||||
# dim 2 needs the special slice. |
||||
full_slice = slice(None, None, None) |
||||
slice1 = slice(0, stagger_dim_size - 1, 1) |
||||
slice2 = slice(1, stagger_dim_size, 1) |
||||
|
||||
# default to full slices |
||||
dim_ranges_1 = [full_slice for x in xrange(num_dims)] |
||||
dim_ranges_2 = [full_slice for x in xrange(num_dims)] |
||||
|
||||
# for the stagger dim, insert the appropriate slice range |
||||
dim_ranges_1[stagger_dim] = slice1 |
||||
dim_ranges_2[stagger_dim] = slice2 |
||||
|
||||
result = .5*(var[dim_ranges_1] + var[dim_ranges_2]) |
||||
|
||||
return result |
||||
|
||||
def destagger_windcomp(wrfnc, comp, timeidx=0): |
||||
if comp.lower() == "u": |
||||
wrfvar = "U" |
||||
stagdim = 2 |
||||
elif comp.lower() == "v": |
||||
wrfvar = "V" |
||||
stagdim = 1 |
||||
elif comp.lower() == "w": |
||||
wrfvar = "W" |
||||
stagdim = 0 |
||||
|
||||
wind_data = wrfnc.variables[wrfvar][timeidx,:,:,:] |
||||
return destagger(wind_data, stagdim) |
||||
|
||||
def destagger_winds(wrfnc, timeidx=0): |
||||
return (destagger_windcomp(wrfnc, "u", timeidx), |
||||
destagger_windcomp(wrfnc, "v", timeidx), |
||||
destagger_windcomp(wrfnc, "w", timeidx)) |
||||
|
@ -0,0 +1,31 @@
@@ -0,0 +1,31 @@
|
||||
from wrf.var.extension import computetd |
||||
from wrf.var.decorators import convert_units |
||||
|
||||
__all__ = ["get_dp", "get_dp_2m"] |
||||
|
||||
@convert_units("temp", "c") |
||||
def get_dp(wrfnc, units="c", timeidx=0): |
||||
|
||||
p = wrfnc.variables["P"][timeidx,:,:,:] |
||||
pb = wrfnc.variables["PB"][timeidx,:,:,:] |
||||
qvapor = wrfnc.variables["QVAPOR"][timeidx,:,:,:] |
||||
|
||||
# Algorithm requires hPa |
||||
full_p = .01*(p + pb) |
||||
qvapor[qvapor < 0] = 0 |
||||
|
||||
td = computetd(full_p, qvapor) |
||||
return td |
||||
|
||||
@convert_units("temp", "c") |
||||
def get_dp_2m(wrfnc, units="c", timeidx=0): |
||||
|
||||
# Algorithm requires hPa |
||||
psfc = .01*(wrfnc.variables["PSFC"][timeidx,:,:]) |
||||
q2 = wrfnc.variables["Q2"][timeidx,:,:] |
||||
q2[q2 < 0] = 0 |
||||
|
||||
td = computetd(psfc, q2) |
||||
|
||||
return td |
||||
|
@ -0,0 +1,81 @@
@@ -0,0 +1,81 @@
|
||||
import numpy as n |
||||
|
||||
from wrf.var.extension import computeeta |
||||
from wrf.var.constants import Constants |
||||
from wrf.var.decorators import convert_units |
||||
|
||||
#__all__ = ["convert_eta"] |
||||
__all__ = [] |
||||
# A useful utility, but should probably just use geopotential height when |
||||
# plotting for AGL levels |
||||
|
||||
# Eta definition (nu): |
||||
# nu = (P - Ptop) / (Psfc - Ptop) |
||||
|
||||
# def convert_eta(wrfnc, p_or_z="ht", timeidx=0): |
||||
# if (p_or_z.lower() == "height" or p_or_z.lower() == "ht" |
||||
# or p_or_z.lower() == "h"): |
||||
# return_z = True |
||||
# elif (p_or_z.lower() == "p" or p_or_z.lower() == "pres" |
||||
# or p_or_z.lower() == "pressure"): |
||||
# return_z = False |
||||
# |
||||
# R = Constants.R |
||||
# G = Constants.G |
||||
# CP = Constants.CP |
||||
# |
||||
# # Keeping the slice notation to show the dimensions |
||||
# # Note: Not sure if T00 should be used (290) or the usual hard-coded 300 for base |
||||
# # theta |
||||
# height_data = wrfnc.variables["HGT"][timeidx,:,:] |
||||
# znu_data = wrfnc.variables["ZNU"][timeidx,:] |
||||
# #t00_data = wrfnc.variables["T00"][timeidx] |
||||
# psfc_data = wrfnc.variables["PSFC"][timeidx,:,:] |
||||
# ptop_data = wrfnc.variables["P_TOP"][timeidx] |
||||
# pth_data = wrfnc.variables["T"][timeidx,:,:,:] # Pert potential temp |
||||
# |
||||
# pcalc_data = n.zeros(pth_data.shape, dtype=n.float32) |
||||
# mean_t_data = n.zeros(pth_data.shape, dtype=n.float32) |
||||
# temp_data = n.zeros(pth_data.shape, dtype=n.float32) |
||||
# z_data = n.zeros(pth_data.shape, dtype=n.float32) |
||||
# |
||||
# #theta_data = pth_data + t00_data |
||||
# theta_data = pth_data + Constants.T_BASE |
||||
# |
||||
# for k in xrange(znu_data.shape[0]): |
||||
# pcalc_data[k,:,:] = znu_data[k]*(psfc_data[:,:] - (ptop_data)) + (ptop_data) |
||||
# |
||||
# # Potential temperature: |
||||
# # theta = T * (Po/P)^(R/CP) |
||||
# # |
||||
# # Hypsometric equation: |
||||
# # h = z2-z1 = R*Tbar/G * ln(p1/p2) |
||||
# # where z1, p1 are the surface |
||||
# if return_z: |
||||
# for k in xrange(znu_data.shape[0]): |
||||
# temp_data[k,:,:] = (theta_data[k,:,:]) / ((100000.0 / (pcalc_data[k,:,:]))**(R/CP)) |
||||
# mean_t_data[k,:,:] = n.mean(temp_data[0:k+1,:,:], axis=0) |
||||
# z_data[k,:,:] = ((R*mean_t_data[k,:,:]/G) * n.log(psfc_data[:,:]/pcalc_data[k,:,:])) |
||||
# |
||||
# return z_data |
||||
# else: |
||||
# return pcalc_data * .01 |
||||
|
||||
# def convert_eta(wrfnc, units="m", msl=False, timeidx=0): |
||||
# check_units(units, "height") |
||||
# hgt = wrfnc.variables["HGT"][timeidx,:,:] |
||||
# znu = wrfnc.variables["ZNU"][timeidx,:] |
||||
# psfc = wrfnc.variables["PSFC"][timeidx,:,:] |
||||
# ptop = wrfnc.variables["P_TOP"][timeidx] |
||||
# t = wrfnc.variables["T"][timeidx,:,:,:] |
||||
# |
||||
# full_theta = t + Constants.T_BASE |
||||
# |
||||
# z = computeeta(full_theta, znu, psfc, ptop) |
||||
# |
||||
# if not msl: |
||||
# return convert_units(z, "height", "m", units) |
||||
# else: |
||||
# return convert_units(z + hgt, "height", "m", units) |
||||
|
||||
|
@ -0,0 +1,323 @@
@@ -0,0 +1,323 @@
|
||||
import numpy as n |
||||
import numpy.ma as ma |
||||
|
||||
from wrf.var.constants import Constants |
||||
from wrf.var.psadlookup import get_lookup_tables |
||||
from wrf.var._wrfext import (f_interpz3d, f_interp2dxy,f_interp1d, |
||||
f_computeslp, f_computetk, f_computetd, f_computerh, |
||||
f_computeabsvort,f_computepvo, f_computeeth, |
||||
f_computeuvmet, |
||||
f_computeomega, f_computetv, f_computewetbulb, |
||||
f_computesrh, f_computeuh, f_computepw, f_computedbz, |
||||
f_lltoij, f_ijtoll, f_converteta, f_computectt) |
||||
from wrf.var._wrfcape import f_computecape |
||||
|
||||
__all__ = ["FortranException", "computeslp", "computetk", "computetd", |
||||
"computerh", "computeavo", "computepvo", "computeeth", |
||||
"computeuvmet","computeomega", "computetv", "computesrh", |
||||
"computeuh", "computepw","computedbz","computecape", |
||||
"computeij", "computell", "computeeta", "computectt"] |
||||
|
||||
class FortranException(Exception): |
||||
def __call__(self, message): |
||||
raise self.__class__(message) |
||||
|
||||
def interpz3d(data3d,zdata,desiredloc,missingval): |
||||
res = f_interpz3d(data3d.astype("float64").T, |
||||
zdata.astype("float64").T, |
||||
desiredloc, |
||||
missingval) |
||||
return res.astype("float32").T |
||||
|
||||
def interpz2d(data3d,xy): |
||||
res = f_interp2dxy(data3d.astype("float64").T, |
||||
xy.astype("float64").T) |
||||
# Note: Fortran routine does not support missing values, so no masking |
||||
return res.astype("float32").T |
||||
|
||||
def interp1d(v_in,z_in,z_out,missingval): |
||||
res = f_interp1d(v_in.astype("float64"), |
||||
z_in.astype("float64"), |
||||
z_out.astype("float64"), |
||||
missingval) |
||||
|
||||
return res.astype("float32") |
||||
|
||||
def computeslp(z,t,p,q): |
||||
t_surf = n.zeros((z.shape[1], z.shape[2]), "float64") |
||||
t_sea_level = n.zeros((z.shape[1], z.shape[2]), "float64") |
||||
level = n.zeros((z.shape[1], z.shape[2]), "int32") |
||||
|
||||
res = f_computeslp(z.astype("float64").T, |
||||
t.astype("float64").T, |
||||
p.astype("float64").T, |
||||
q.astype("float64").T, |
||||
t_sea_level.T, |
||||
t_surf.T, |
||||
level.T, |
||||
FortranException()) |
||||
|
||||
return res.astype("float32").T |
||||
|
||||
def computetk(pres, theta): |
||||
# No need to transpose here since operations on 1D array |
||||
shape = pres.shape |
||||
res = f_computetk(pres.astype("float64").flatten("A"), |
||||
theta.astype("float64").flatten("A")) |
||||
res = n.reshape(res, shape, "A") |
||||
return res.astype("float32") |
||||
|
||||
def computetd(pressure,qv_in): |
||||
shape = pressure.shape |
||||
res = f_computetd(pressure.astype("float64").flatten("A"), qv_in.astype("float64").flatten("A")) |
||||
res = n.reshape(res, shape, "A") |
||||
return res.astype("float32") |
||||
|
||||
def computerh(qv,q,t): |
||||
shape = qv.shape |
||||
res = f_computerh(qv.astype("float64").flatten("A"), |
||||
q.astype("float64").flatten("A"), |
||||
t.astype("float64").flatten("A")) |
||||
res = n.reshape(res, shape, "A") |
||||
return res.astype("float32") |
||||
|
||||
def computeavo(u,v,msfu,msfv,msfm,cor,dx,dy): |
||||
res = f_computeabsvort(u.astype("float64").T, |
||||
v.astype("float64").T, |
||||
msfu.astype("float64").T, |
||||
msfv.astype("float64").T, |
||||
msfm.astype("float64").T, |
||||
cor.astype("float64").T, |
||||
dx, |
||||
dy) |
||||
|
||||
return res.astype("float32").T |
||||
|
||||
def computepvo(u,v,theta,prs,msfu,msfv,msfm,cor,dx,dy): |
||||
|
||||
res = f_computepvo(u.astype("float64").T, |
||||
v.astype("float64").T, |
||||
theta.astype("float64").T, |
||||
prs.astype("float64").T, |
||||
msfu.astype("float64").T, |
||||
msfv.astype("float64").T, |
||||
msfm.astype("float64").T, |
||||
cor.astype("float64").T, |
||||
dx, |
||||
dy) |
||||
|
||||
return res.astype("float32").T |
||||
|
||||
def computeeth(qv, tk, p): |
||||
|
||||
res = f_computeeth(qv.astype("float64").T, |
||||
tk.astype("float64").T, |
||||
p.astype("float64").T) |
||||
|
||||
return res.astype("float32").T |
||||
|
||||
def computeuvmet(u,v,lat,lon,cen_long,cone): |
||||
longca = n.zeros((lat.shape[0], lat.shape[1]), "float64") |
||||
longcb = n.zeros((lon.shape[0], lon.shape[1]), "float64") |
||||
rpd = Constants.PI/180. |
||||
|
||||
|
||||
# Make the 2D array a 3D array with 1 dimension |
||||
if u.ndim != 3: |
||||
u = u.reshape((1,u.shape[0], u.shape[1])) |
||||
v = v.reshape((1,v.shape[0], v.shape[1])) |
||||
|
||||
# istag will always be false since winds are destaggered already |
||||
# Missing values don't appear to be used, so setting to 0 |
||||
res = f_computeuvmet(u.astype("float64").T, |
||||
v.astype("float64").T, |
||||
longca.T, |
||||
longcb.T, |
||||
lon.astype("float64").T, |
||||
lat.astype("float64").T, |
||||
cen_long, |
||||
cone, |
||||
rpd, |
||||
0, |
||||
False, |
||||
0, |
||||
0, |
||||
0) |
||||
|
||||
|
||||
return res.astype("float32").T |
||||
|
||||
def computeomega(qv, tk, w, p): |
||||
|
||||
res = f_computeomega(qv.astype("float64").T, |
||||
tk.astype("float64").T, |
||||
w.astype("float64").T, |
||||
p.astype("float64").T) |
||||
|
||||
#return res.T |
||||
return res.astype("float32").T |
||||
|
||||
def computetv(tk,qv): |
||||
res = f_computetv(tk.astype("float64").T, |
||||
qv.astype("float64").T) |
||||
|
||||
return res.astype("float32").T |
||||
|
||||
def computewetbulb(p,tk,qv): |
||||
PSADITHTE, PSADIPRS, PSADITMK = get_lookup_tables() |
||||
|
||||
res = f_computewetbulb(p.astype("float64").T, |
||||
tk.astype("float64").T, |
||||
qv.astype("float64").T, |
||||
PSADITHTE, |
||||
PSADIPRS, |
||||
PSADITMK.T, |
||||
FortranException()) |
||||
|
||||
return res.astype("float32").T |
||||
|
||||
def computesrh(u, v, z, ter, top): |
||||
|
||||
res = f_computesrh(u.astype("float64").T, |
||||
v.astype("float64").T, |
||||
z.astype("float64").T, |
||||
ter.astype("float64").T, |
||||
top) |
||||
|
||||
return res.astype("float32").T |
||||
|
||||
def computeuh(zp, mapfct, u, v, wstag, dx, dy, bottom, top): |
||||
|
||||
tem1 = n.zeros((u.shape[0],u.shape[1],u.shape[2]), "float64") |
||||
tem2 = n.zeros((u.shape[0],u.shape[1],u.shape[2]), "float64") |
||||
|
||||
res = f_computeuh(zp.astype("float64").T, |
||||
mapfct.astype("float64").T, |
||||
dx, |
||||
dy, |
||||
bottom, |
||||
top, |
||||
u.astype("float64").T, |
||||
v.astype("float64").T, |
||||
wstag.astype("float64").T, |
||||
tem1.T, |
||||
tem2.T) |
||||
|
||||
return res.astype("float32").T |
||||
|
||||
def computepw(p,tv,qv,ht): |
||||
# Note, dim 0 is height, we only want y and x |
||||
zdiff = n.zeros((p.shape[1], p.shape[2]), "float64") |
||||
res = f_computepw(p.astype("float64").T, |
||||
tv.astype("float64").T, |
||||
qv.astype("float64").T, |
||||
ht.astype("float64").T, |
||||
zdiff.T) |
||||
|
||||
return res.astype("float32").T |
||||
|
||||
def computedbz(p,tk,qv,qr,qs,qg,sn0,ivarint,iliqskin): |
||||
|
||||
res = f_computedbz(p.astype("float64").T, |
||||
tk.astype("float64").T, |
||||
qv.astype("float64").T, |
||||
qr.astype("float64").T, |
||||
qs.astype("float64").T, |
||||
qg.astype("float64").T, |
||||
sn0, |
||||
ivarint, |
||||
iliqskin) |
||||
|
||||
return res.astype("float32").T |
||||
|
||||
def computecape(p_hpa,tk,qv,ht,ter,sfp,missing,i3dflag,ter_follow): |
||||
flip_cape = n.zeros((p_hpa.shape[0],p_hpa.shape[1],p_hpa.shape[2]), "float64") |
||||
flip_cin = n.zeros((p_hpa.shape[0],p_hpa.shape[1],p_hpa.shape[2]), "float64") |
||||
PSADITHTE, PSADIPRS, PSADITMK = get_lookup_tables() |
||||
|
||||
# The fortran routine needs pressure to be ascending in z-direction, |
||||
# along with tk,qv,and ht. |
||||
flip_p = p_hpa[::-1,:,:] |
||||
flip_tk = tk[::-1,:,:] |
||||
flip_qv = qv[::-1,:,:] |
||||
flip_ht = ht[::-1,:,:] |
||||
|
||||
f_computecape(flip_p.astype("float64").T, |
||||
flip_tk.astype("float64").T, |
||||
flip_qv.astype("float64").T, |
||||
flip_ht.astype("float64").T, |
||||
ter.astype("float64").T, |
||||
sfp.astype("float64").T, |
||||
flip_cape.T, |
||||
flip_cin.T, |
||||
PSADITHTE, |
||||
PSADIPRS, |
||||
PSADITMK.T, |
||||
missing, |
||||
i3dflag, |
||||
ter_follow, |
||||
FortranException()) |
||||
|
||||
# Don't need to transpose since we only passed a view to fortran |
||||
cape = flip_cape.astype("float32") |
||||
cin = flip_cin.astype("float32") |
||||
# Remember to flip cape and cin back to descending p coordinates |
||||
return (cape[::-1,:,:],cin[::-1,:,:]) |
||||
|
||||
|
||||
def computeij(map_proj,truelat1,truelat2,stdlon, |
||||
lat1,lon1,pole_lat,pole_lon, |
||||
knowni,knownj,dx,latinc,loninc,lat,lon): |
||||
|
||||
res = f_lltoij(map_proj,truelat1,truelat2,stdlon, |
||||
lat1,lon1,pole_lat,pole_lon, |
||||
knowni,knownj,dx,latinc,loninc,lat,lon, |
||||
FortranException()) |
||||
|
||||
return res[0],res[1] |
||||
|
||||
def computell(map_proj,truelat1,truelat2,stdlon,lat1,lon1, |
||||
pole_lat,pole_lon,knowni,knownj,dx,latinc, |
||||
loninc,i,j): |
||||
|
||||
res = f_ijtoll(map_proj,truelat1,truelat2,stdlon,lat1,lon1, |
||||
pole_lat,pole_lon,knowni,knownj,dx,latinc, |
||||
loninc,i,j,FortranException()) |
||||
|
||||
# Want lon,lat |
||||
return res[1],res[0] |
||||
|
||||
def computeeta(full_t, znu, psfc, ptop): |
||||
pcalc = n.zeros(full_t.shape, "float64") |
||||
mean_t = n.zeros(full_t.shape, "float64") |
||||
temp_t = n.zeros(full_t.shape, "float64") |
||||
|
||||
res = f_converteta(full_t.astype("float64").T, |
||||
znu.astype("float64"), |
||||
psfc.astype("float64").T, |
||||
ptop, |
||||
pcalc.T, |
||||
mean_t.T, |
||||
temp_t.T) |
||||
|
||||
return res.astype("float32").T |
||||
|
||||
def computectt(p_hpa,tk,qice,qcld,qv,ght,ter,haveqci): |
||||
res = f_computectt(p_hpa.astype("float64").T, |
||||
tk.astype("float64").T, |
||||
qice.astype("float64").T, |
||||
qcld.astype("float64").T, |
||||
qv.astype("float64").T, |
||||
ght.astype("float64").T, |
||||
ter.astype("float64").T, |
||||
haveqci) |
||||
|
||||
return res.astype("float32").T |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,40 @@
@@ -0,0 +1,40 @@
|
||||
from wrf.var.constants import Constants |
||||
from wrf.var.destagger import destagger |
||||
from wrf.var.decorators import convert_units |
||||
|
||||
__all__ = ["get_geopt", "get_height"] |
||||
|
||||
def _get_geoht(wrfnc, height=True, msl=True, timeidx=0): |
||||
"""Return the geopotential in units of m2 s-2 if height is False, |
||||
otherwise return the geopotential height in meters. If height is True, |
||||
then if msl is True the result will be in MSL, otherwise AGL (the terrain |
||||
height is subtracted). |
||||
|
||||
""" |
||||
|
||||
if "PH" in wrfnc.variables: |
||||
ph = wrfnc.variables["PH"][timeidx,:,:,:] |
||||
phb = wrfnc.variables["PHB"][timeidx,:,:,:] |
||||
hgt = wrfnc.variables["HGT"][timeidx,:,:] |
||||
geopt = ph + phb |
||||
geopt_unstag = destagger(geopt, 0) |
||||
elif "GHT" in wrfnc.variables: # met_em files |
||||
geopt_unstag = wrfnc.variables["GHT"][timeidx,:,:,:] * Constants.G |
||||
hgt = destagger(wrfnc.variables["HGT_U"][timidx,:,:], 1) |
||||
|
||||
if height: |
||||
if msl: |
||||
return geopt_unstag / Constants.G |
||||
else: |
||||
return (geopt_unstag / Constants.G) - hgt |
||||
else: |
||||
return geopt_unstag |
||||
|
||||
def get_geopt(wrfnc, timeidx=0): |
||||
return _get_geoht(wrfnc, False, timeidx=timeidx) |
||||
|
||||
@convert_units("height", "m") |
||||
def get_height(wrfnc, msl=True, units="m", timeidx=0): |
||||
z = _get_geoht(wrfnc, True, msl, timeidx) |
||||
return z |
||||
|
@ -0,0 +1,68 @@
@@ -0,0 +1,68 @@
|
||||
from wrf.var.constants import Constants |
||||
|
||||
from wrf.var.extension import computesrh, computeuh |
||||
from wrf.var.destagger import destagger |
||||
|
||||
__all__ = ["get_srh", "get_uh"] |
||||
|
||||
def get_srh(wrfnc, top=3000.0, timeidx=0): |
||||
# Top can either be 3000 or 1000 (for 0-1 srh or 0-3 srh) |
||||
|
||||
if "U" in wrfnc.variables: |
||||
u = destagger(wrfnc.variables["U"][timeidx,:,:,:], 2) |
||||
elif "UU" in wrfnc.variables: |
||||
u = destagger(wrfnc.variables["UU"][timeidx,:,:,:], 2) # support met_em files |
||||
|
||||
if "V" in wrfnc.variables: |
||||
v = destagger(wrfnc.variables["V"][timeidx,:,:,:], 1) |
||||
elif "VV" in wrfnc.variables: |
||||
v = destagger(wrfnc.variables["VV"][timeidx,:,:,:], 1) |
||||
|
||||
ter = wrfnc.variables["HGT"][timeidx,:,:] |
||||
ph = wrfnc.variables["PH"][timeidx,:,:,:] |
||||
phb = wrfnc.variables["PHB"][timeidx,:,:,:] |
||||
|
||||
geopt = ph + phb |
||||
geopt_unstag = destagger(geopt, 0) |
||||
|
||||
z = geopt_unstag / Constants.G |
||||
|
||||
# Re-ordering from high to low |
||||
u1 = u[::-1,:,:] |
||||
v1 = v[::-1,:,:] |
||||
z1 = z[::-1,:,:] |
||||
|
||||
srh = computesrh(u1, v1, z1, ter, top) |
||||
|
||||
return srh |
||||
|
||||
def get_uh(wrfnc, bottom=2000.0, top=5000.0, timeidx=0): |
||||
|
||||
if "U" in wrfnc.variables: |
||||
u = destagger(wrfnc.variables["U"][timeidx,:,:,:], 2) |
||||
elif "UU" in wrfnc.variables: |
||||
u = destagger(wrfnc.variables["UU"][timeidx,:,:,:], 2) # support met_em files |
||||
|
||||
if "V" in wrfnc.variables: |
||||
v = destagger(wrfnc.variables["V"][timeidx,:,:,:], 1) |
||||
elif "VV" in wrfnc.variables: |
||||
v = destagger(wrfnc.variables["VV"][timeidx,:,:,:], 1) |
||||
|
||||
wstag = wrfnc.variables["W"][timeidx,:,:,:] |
||||
ph = wrfnc.variables["PH"][timeidx,:,:,:] |
||||
phb = wrfnc.variables["PHB"][timeidx,:,:,:] |
||||
zp = ph + phb |
||||
|
||||
mapfct = wrfnc.variables["MAPFAC_M"][timeidx,:,:] |
||||
dx = wrfnc.getncattr("DX") |
||||
dy = wrfnc.getncattr("DY") |
||||
|
||||
|
||||
uh = computeuh(zp, mapfct, u, v, wstag, dx, dy, bottom, top) |
||||
|
||||
return uh |
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,178 @@
@@ -0,0 +1,178 @@
|
||||
from math import floor, ceil |
||||
|
||||
import numpy as n |
||||
import numpy.ma as ma |
||||
|
||||
from wrf.var.extension import interpz3d,interpz2d,interp1d |
||||
|
||||
__all__ = ["get_interplevel", "get_vertcross"] |
||||
|
||||
def get_interplevel(data3d,zdata,desiredloc,missingval=-99999): |
||||
"""Return the horizontally interpolated data at the provided level |
||||
|
||||
data3d - the 3D field to interpolate |
||||
zdata - the vertical values (height or pressure) |
||||
desiredloc - the vertical level to interpolate at (must be same units as |
||||
zdata) |
||||
missingval - the missing data value (which will be masked on return) |
||||
|
||||
""" |
||||
r1 = interpz3d(data3d, zdata, desiredloc, missingval) |
||||
masked_r1 = ma.masked_values (r1, missingval) |
||||
return masked_r1 |
||||
|
||||
def _get_xy(xdim, ydim, pivot_point=None, angle=None, |
||||
start_point=None, end_point=None): |
||||
"""Returns the x,y points for the horizontal cross section line. |
||||
|
||||
xdim - maximum x-dimension |
||||
ydim - maximum y-dimension |
||||
pivot_point - a pivot point of (x,y) (must be used with angle) |
||||
angle - the angle through the pivot point in degrees |
||||
start_point - a start_point tuple of (x,y) |
||||
end_point - an end point tuple of (x,y) |
||||
|
||||
""" |
||||
|
||||
# Have a pivot point with an angle to find cross section |
||||
if pivot is not None and angle is not None: |
||||
xp = pivot_point[0] |
||||
yp = pivot_point[1] |
||||
|
||||
if (angle > 315.0 or angle < 45.0 |
||||
or ((angle > 135.0) and (angle < 225.0))): |
||||
|
||||
#x = y*slope + intercept |
||||
slope = -(360.-angle)/45. |
||||
if( angle < 45. ): |
||||
slope = angle/45. |
||||
if( angle > 135.): |
||||
slope = (angle-180.)/45. |
||||
|
||||
intercept = xp - yp*slope |
||||
|
||||
# find intersections with domain boundaries |
||||
y0 = 0. |
||||
x0 = y0*slope + intercept |
||||
|
||||
if( x0 < 0.): # intersect outside of left boundary |
||||
x0 = 0. |
||||
y0 = (x0 - intercept)/slope |
||||
if( x0 > xdim-1): #intersect outside of right boundary |
||||
x0 = xdim-1 |
||||
y0 = (x0 - intercept)/slope |
||||
y1 = ydim-1. #need to make sure this will be a float? |
||||
x1 = y1*slope + intercept |
||||
|
||||
if( x1 < 0.): # intersect outside of left boundary |
||||
x1 = 0. |
||||
y1 = (x1 - intercept)/slope |
||||
|
||||
if( x1 > xdim-1): # intersect outside of right boundary |
||||
x1 = xdim-1 |
||||
y1 = (x1 - intercept)/slope |
||||
else: |
||||
# y = x*slope + intercept |
||||
slope = (90.-angle)/45. |
||||
if( angle > 225. ): |
||||
slope = (270.-angle)/45. |
||||
intercept = yp - xp*slope |
||||
|
||||
#find intersections with domain boundaries |
||||
x0 = 0. |
||||
y0 = x0*slope + intercept |
||||
|
||||
if( y0 < 0.): # intersect outside of bottom boundary |
||||
y0 = 0. |
||||
x0 = (y0 - intercept)/slope |
||||
|
||||
if( y0 > ydim-1): # intersect outside of top boundary |
||||
y0 = ydim-1 |
||||
x0 = (y0 - intercept)/slope |
||||
|
||||
x1 = xdim-1. # need to make sure this will be a float? |
||||
y1 = x1*slope + intercept |
||||
|
||||
if( y1 < 0.): # intersect outside of bottom boundary |
||||
y1 = 0. |
||||
x1 = (y1 - intercept)/slope |
||||
|
||||
if( y1 > ydim-1):# intersect outside of top boundary |
||||
y1 = ydim1 |
||||
x1 = (y1 - intercept)/slope |
||||
elif start_point is not None and end_point is not None: |
||||
x0 = start_point[0] |
||||
y0 = start_point[1] |
||||
x1 = end_point[0] |
||||
y1 = end_point[1] |
||||
if ( x1 > xdim-1 ): |
||||
x1 = xdim |
||||
if ( y1 > ydim-1): |
||||
y1 = ydim |
||||
else: |
||||
raise ValueError("invalid combination of None arguments") |
||||
|
||||
dx = x1 - x0 |
||||
dy = y1 - y0 |
||||
distance = (dx*dx + dy*dy)**0.5 |
||||
npts = int(distance) |
||||
dxy = distance/npts |
||||
|
||||
xz = n.zeros((npts,2), "float") |
||||
|
||||
dx = dx/npts |
||||
dy = dy/npts |
||||
|
||||
for i in xrange(npts): |
||||
xy[i,0] = x0 + i*dx |
||||
xy[i,1] = y0 + i*dy |
||||
|
||||
return xy |
||||
|
||||
|
||||
# TODO: Add flag to use lat/lon points by doing conversion |
||||
def get_vertcross(data3d, z, missingval=-99999, |
||||
pivot=None,angle=None,start_point=None,end_point=None): |
||||
|
||||
xdim = z.shape[2] |
||||
ydim = z.shape[1] |
||||
|
||||
xy = _get_xy(xdim, ydim, pivot_point, angle, start_point, end_point) |
||||
|
||||
# Interp z |
||||
var2dz = interpz2d(z, xy) |
||||
|
||||
# interp to constant z grid |
||||
if(var2dz[0,0] > var2dz[1,0]): # monotonically decreasing coordinate |
||||
z_max = floor(n.amax(z)/10)*10 # bottom value |
||||
z_min = ceil(n.amin(z)/10)*10 # top value |
||||
dz = 10 |
||||
nlevels = int( (z_max-z_min)/dz) |
||||
z_var2d = n.zeros((nlevels), dtype=z.dtype) |
||||
z_var2d[0] = z_max |
||||
dz = -dz |
||||
else: |
||||
z_max = n.amax(z) |
||||
z_min = 0. |
||||
dz = 0.01 * z_max |
||||
nlevels = int( z_max/dz ) |
||||
z_var2d = n.zeros((nlevels), dtype=z.dtype) |
||||
z_var2d[0] = z_min |
||||
|
||||
for i in xrange(1,nlevels): |
||||
z_var2d[i] = z_var2d[0] + i*dz |
||||
|
||||
#interp the variable |
||||
|
||||
var2d = n.zeros((nlevels, xy.shape[0]),dtype=var2dz.dtype) |
||||
var2dtmp = interpz2d(data3d, xy) |
||||
|
||||
for i in xrange(xy.shape[0]): |
||||
var2d[:,i] = interp1d(var2dtmp[:,i], var2dz[:,i], z_var2d, missingval) |
||||
|
||||
return ma.masked_values(var2d, missingval) |
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,104 @@
@@ -0,0 +1,104 @@
|
||||
from wrf.var.extension import computeij, computell |
||||
|
||||
__all__ = ["get_lat", "get_lon", "get_ij", "get_ll"] |
||||
|
||||
def get_lat(wrfnc, timeidx=0): |
||||
if "XLAT" in wrfnc.variables: |
||||
xlat = wrfnc.variables["XLAT"][timeidx,:,:] |
||||
elif "XLAT_M" in wrfnc.variables: |
||||
xlat = wrfnc.variables["XLAT_M"][timeidx,:,:] |
||||
|
||||
return xlat |
||||
|
||||
def get_lon(wrfnc, timeidx=0): |
||||
if "XLONG" in wrfnc.variables: |
||||
xlon = wrfnc.variables["XLONG"][timeidx,:,:] |
||||
elif "XLONG_M" in wrfnc.variables: |
||||
xlon = wrfnc.variables["XLONG_M"][timeidx,:,:] |
||||
|
||||
return xlon |
||||
|
||||
def get_ij(wrfnc, longitude, latitude, timeidx=0): |
||||
map_proj = wrfnc.getncattr("MAP_PROJ") |
||||
truelat1 = wrfnc.getncattr("TRUELAT1") |
||||
truelat2 = wrfnc.getncattr("TRUELAT2") |
||||
stdlon = wrfnc.getncattr("STAND_LON") |
||||
dx = wrfnc.getncattr("DX") |
||||
dy = wrfnc.getncattr("DY") |
||||
stdlon = wrfnc.getncattr("STAND_LON") |
||||
|
||||
if map_proj == 6: |
||||
pole_lat = wrfnc.getncattr("POLE_LAT") |
||||
pole_lon = wrfnc.getncattr("POLE_LON") |
||||
latinc = (dy*360.0)/2.0/3.141592653589793/6370000. |
||||
loninc = (dx*360.0)/2.0/3.141592653589793/6370000. |
||||
else: |
||||
pole_lat = 90.0 |
||||
pole_lon = 0.0 |
||||
latinc = 0.0 |
||||
loninc = 0.0 |
||||
|
||||
if "XLAT" in wrfnc.variables: |
||||
xlat = wrfnc.variables["XLAT"][timeidx,:,:] |
||||
elif "XLAT_M" in wrfnc.variables: |
||||
xlat = wrfnc.variables["XLAT_M"][timeidx,:,:] |
||||
|
||||
if "XLONG" in wrfnc.variables: |
||||
xlon = wrfnc.variables["XLONG"][timeidx,:,:] |
||||
elif "XLONG_M" in wrfnc.variables: |
||||
xlon = wrfnc.variables["XLONG_M"][timeidx,:,:] |
||||
|
||||
ref_lat = xlat[0,0] |
||||
ref_lon = xlon[0,0] |
||||
|
||||
known_i = 1.0 |
||||
known_j = 1.0 |
||||
|
||||
return computeij(map_proj,truelat1,truelat2,stdlon, |
||||
ref_lat,ref_lon,pole_lat,pole_lon, |
||||
known_i,known_j,dx,latinc,loninc,latitude,longitude) |
||||
|
||||
|
||||
def get_ll(wrfnc, i, j, timeidx=0): |
||||
|
||||
map_proj = wrfnc.getncattr("MAP_PROJ") |
||||
truelat1 = wrfnc.getncattr("TRUELAT1") |
||||
truelat2 = wrfnc.getncattr("TRUELAT2") |
||||
stdlon = wrfnc.getncattr("STAND_LON") |
||||
dx = wrfnc.getncattr("DX") |
||||
dy = wrfnc.getncattr("DY") |
||||
stdlon = wrfnc.getncattr("STAND_LON") |
||||
|
||||
if map_proj == 6: |
||||
pole_lat = wrfnc.getncattr("POLE_LAT") |
||||
pole_lon = wrfnc.getncattr("POLE_LON") |
||||
latinc = (dy*360.0)/2.0/3.141592653589793/6370000. |
||||
loninc = (dx*360.0)/2.0/3.141592653589793/6370000. |
||||
else: |
||||
pole_lat = 90.0 |
||||
pole_lon = 0.0 |
||||
latinc = 0.0 |
||||
loninc = 0.0 |
||||
|
||||
if "XLAT" in wrfnc.variables: |
||||
xlat = wrfnc.variables["XLAT"][timeidx,:,:] |
||||
elif "XLAT_M" in wrfnc.variables: |
||||
xlat = wrfnc.variables["XLAT_M"][timeidx,:,:] |
||||
|
||||
if "XLONG" in wrfnc.variables: |
||||
xlon = wrfnc.variables["XLONG"][timeidx,:,:] |
||||
elif "XLONG_M" in wrfnc.variables: |
||||
xlon = wrfnc.variables["XLONG_M"][timeidx,:,:] |
||||
|
||||
ref_lat = xlat[0,0] |
||||
ref_lon = xlon[0,0] |
||||
|
||||
known_i = 1.0 |
||||
known_j = 1.0 |
||||
|
||||
return computell(map_proj,truelat1,truelat2,stdlon,ref_lat,ref_lon, |
||||
pole_lat,pole_lon,known_i,known_j,dx,latinc, |
||||
loninc,i,j) |
||||
|
||||
|
||||
|
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
|
||||
from wrf.var.constants import Constants |
||||
from wrf.var.destagger import destagger |
||||
from wrf.var.extension import computeomega,computetk |
||||
|
||||
__all__ = ["get_omega"] |
||||
|
||||
def get_omega(wrfnc, timeidx=0): |
||||
t = wrfnc.variables["T"][timeidx,:,:,:] |
||||
p = wrfnc.variables["P"][timeidx,:,:,:] |
||||
w = wrfnc.variables["W"][timeidx,:,:,:] |
||||
pb = wrfnc.variables["PB"][timeidx,:,:,:] |
||||
qv = wrfnc.variables["QVAPOR"][timeidx,:,:,:] |
||||
|
||||
wa = destagger(w, 0) |
||||
full_t = t + Constants.T_BASE |
||||
full_p = p + pb |
||||
tk = computetk(full_p, full_t) |
||||
|
||||
omega = computeomega(qv,tk,wa,full_p) |
||||
|
||||
return omega |
||||
|
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
|
||||
import numpy as n |
||||
|
||||
__all__ = ["get_accum_precip", "get_precip_diff"] |
||||
|
||||
def get_accum_precip(wrfnc, timeidx=0): |
||||
rainc = wrfnc.variables["RAINC"][timeidx,:,:] |
||||
rainnc = wrfnc.variables["RAINNC"][timeidx,:,:] |
||||
|
||||
rainsum = rainc + rainnc |
||||
|
||||
return rainsum |
||||
|
||||
def get_precip_diff(wrfnc1, wrfnc2, timeidx=0): |
||||
rainc1 = wrfnc1.variables["RAINC"][timeidx,:,:] |
||||
rainnc1 = wrfnc1.variables["RAINNC"][timeidx,:,:] |
||||
|
||||
rainc2 = wrfnc2.variables["RAINC"][timeidx,:,:] |
||||
rainnc2 = wrfnc2.variables["RAINNC"][timeidx,:,:] |
||||
|
||||
rainsum1 = rainc1 + rainnc1 |
||||
rainsum2 = rainc2 + rainnc2 |
||||
|
||||
return (rainsum1 - rainsum2) |
||||
|
||||
# TODO: Handle bucket flipping |
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
|
||||
from wrf.var.constants import Constants |
||||
from wrf.var.decorators import convert_units |
||||
|
||||
__all__ = ["get_pressure"] |
||||
|
||||
@convert_units("pressure", "pa") |
||||
def get_pressure(wrfnc, units="hpa", timeidx=0): |
||||
|
||||
if "P" in wrfnc.variables: |
||||
p = wrfnc.variables["P"][timeidx,:,:,:] |
||||
pb = wrfnc.variables["PB"][timeidx,:,:,:] |
||||
pres = p + pb |
||||
elif "PRES" in wrfnc.variables: |
||||
pres = wrfnc.variables["PRES"][timeidx,:,:,:] |
||||
|
||||
return pres |
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -0,0 +1,28 @@
@@ -0,0 +1,28 @@
|
||||
|
||||
from wrf.var.extension import computepw,computetv,computetk |
||||
from wrf.var.constants import Constants |
||||
|
||||
__all__ = ["get_pw"] |
||||
|
||||
def get_pw(wrfnc, timeidx=0): |
||||
|
||||
t = wrfnc.variables["T"][timeidx,:,:,:] |
||||
p = wrfnc.variables["P"][timeidx,:,:,:] |
||||
pb = wrfnc.variables["PB"][timeidx,:,:,:] |
||||
ph = wrfnc.variables["PH"][timeidx,:,:,:] |
||||
phb = wrfnc.variables["PHB"][timeidx,:,:,:] |
||||
qv = wrfnc.variables["QVAPOR"][timeidx,:,:,:] |
||||
|
||||
# Change this to use real virtual temperature! |
||||
full_p = p + pb |
||||
ht = (ph + phb)/Constants.G |
||||
full_t = t + Constants.T_BASE |
||||
|
||||
tk = computetk(full_p, full_t) |
||||
tv = computetv(tk,qv) |
||||
|
||||
return computepw(full_p,tv,qv,ht) |
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,31 @@
@@ -0,0 +1,31 @@
|
||||
|
||||
from wrf.var.constants import Constants |
||||
from wrf.var.extension import computerh, computetk |
||||
|
||||
__all__ = ["get_rh", "get_rh_2m"] |
||||
|
||||
def get_rh(wrfnc, timeidx=0): |
||||
t = wrfnc.variables["T"][timeidx,:,:,:] |
||||
#t00 = wrfnc.variables["T00"][timeidx] |
||||
p = wrfnc.variables["P"][timeidx,:,:,:] |
||||
pb = wrfnc.variables["PB"][timeidx,:,:,:] |
||||
qvapor = wrfnc.variables["QVAPOR"][timeidx,:,:,:] |
||||
|
||||
full_t = t + Constants.T_BASE |
||||
full_p = p + pb |
||||
qvapor[qvapor < 0] = 0 |
||||
tk = computetk(full_p, full_t) |
||||
rh = computerh(qvapor, full_p, tk) |
||||
|
||||
return rh |
||||
|
||||
def get_rh_2m(wrfnc, timeidx=0): |
||||
t2 = wrfnc.variables["T2"][timeidx,:,:] |
||||
psfc = wrfnc.variables["PSFC"][timeidx,:,:] |
||||
q2 = wrfnc.variables["Q2"][timeidx,:,:] |
||||
|
||||
q2[q2 < 0] = 0 |
||||
rh = computerh(q2, psfc, t2) |
||||
|
||||
return rh |
||||
|
@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
|
||||
from wrf.var.extension import computeslp, computetk |
||||
from wrf.var.constants import Constants |
||||
from wrf.var.destagger import destagger |
||||
from wrf.var.decorators import convert_units |
||||
|
||||
__all__ = ["get_slp"] |
||||
|
||||
@convert_units("pressure", "pa") |
||||
def get_slp(wrfnc, units="hpa", timeidx=0): |
||||
|
||||
t = wrfnc.variables["T"][timeidx,:,:,:] |
||||
p = wrfnc.variables["P"][timeidx,:,:,:] |
||||
pb = wrfnc.variables["PB"][timeidx,:,:,:] |
||||
qvapor = wrfnc.variables["QVAPOR"][timeidx,:,:,:] |
||||
ph = wrfnc.variables["PH"][timeidx,:,:,:] |
||||
phb = wrfnc.variables["PHB"][timeidx,:,:,:] |
||||
|
||||
full_t = t + Constants.T_BASE |
||||
full_p = p + pb |
||||
qvapor[qvapor < 0] = 0. |
||||
full_ph = (ph + phb) / Constants.G |
||||
|
||||
destag_ph = destagger(full_ph, 0) |
||||
|
||||
tk = computetk(full_p, full_t) |
||||
slp = computeslp(destag_ph, tk, full_p, qvapor) |
||||
|
||||
return slp |
||||
|
@ -0,0 +1,82 @@
@@ -0,0 +1,82 @@
|
||||
|
||||
from wrf.var.constants import Constants |
||||
from wrf.var.extension import computetk, computeeth, computetv, computewetbulb |
||||
from wrf.var.decorators import convert_units |
||||
|
||||
__all__ = ["get_theta", "get_temp", "get_eth", "get_tv", "get_tw"] |
||||
|
||||
@convert_units("temp", "k") |
||||
def get_theta(wrfnc, units="k", timeidx=0): |
||||
t = wrfnc.variables["T"][timeidx,:,:,:] |
||||
full_t = t + Constants.T_BASE |
||||
|
||||
return full_t |
||||
|
||||
@convert_units("temp", "k") |
||||
def get_temp(wrfnc, units="k", timeidx=0): |
||||
"""Return the temperature in Kelvin or Celsius""" |
||||
|
||||
t = wrfnc.variables["T"][timeidx,:,:,:] |
||||
p = wrfnc.variables["P"][timeidx,:,:,:] |
||||
pb = wrfnc.variables["PB"][timeidx,:,:,:] |
||||
|
||||
full_t = t + Constants.T_BASE |
||||
full_p = p + pb |
||||
tk = computetk(full_p, full_t) |
||||
|
||||
return tk |
||||
|
||||
@convert_units("temp", "k") |
||||
def get_eth(wrfnc, units="k", timeidx=0): |
||||
"Return equivalent potential temperature (Theta-e) in Kelvin" |
||||
|
||||
t = wrfnc.variables["T"][timeidx,:,:,:] |
||||
p = wrfnc.variables["P"][timeidx,:,:,:] |
||||
pb = wrfnc.variables["PB"][timeidx,:,:,:] |
||||
qv = wrfnc.variables["QVAPOR"][timeidx,:,:,:] |
||||
|
||||
full_t = t + Constants.T_BASE |
||||
full_p = p + pb |
||||
tk = computetk(full_p, full_t) |
||||
|
||||
eth = computeeth ( qv, tk, full_p ) |
||||
|
||||
return eth |
||||
|
||||
@convert_units("temp", "k") |
||||
def get_tv(wrfnc, units="k", timeidx=0): |
||||
"Return the virtual temperature (tv) in Kelvin or Celsius" |
||||
|
||||
t = wrfnc.variables["T"][timeidx,:,:,:] |
||||
p = wrfnc.variables["P"][timeidx,:,:,:] |
||||
pb = wrfnc.variables["PB"][timeidx,:,:,:] |
||||
qv = wrfnc.variables["QVAPOR"][timeidx,:,:,:] |
||||
|
||||
full_t = t + Constants.T_BASE |
||||
full_p = p + pb |
||||
tk = computetk(full_p, full_t) |
||||
|
||||
tv = computetv(tk,qv) |
||||
|
||||
return tv |
||||
|
||||
|
||||
@convert_units("temp", "k") |
||||
def get_tw(wrfnc, units="k", timeidx=0): |
||||
"Return the wetbulb temperature (tw)" |
||||
|
||||
t = wrfnc.variables["T"][timeidx,:,:,:] |
||||
p = wrfnc.variables["P"][timeidx,:,:,:] |
||||
pb = wrfnc.variables["PB"][timeidx,:,:,:] |
||||
qv = wrfnc.variables["QVAPOR"][timeidx,:,:,:] |
||||
|
||||
full_t = t + Constants.T_BASE |
||||
full_p = p + pb |
||||
|
||||
tk = computetk(full_p, full_t) |
||||
tw = computewetbulb(full_p,tk,qv) |
||||
|
||||
return tw |
||||
|
||||
|
||||
|
@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
|
||||
|
||||
from wrf.var.decorators import convert_units |
||||
|
||||
__all__ = ["get_terrain"] |
||||
|
||||
@convert_units("height", "m") |
||||
def get_terrain(wrfnc, units="m", timeidx=0): |
||||
|
||||
if "HGT" in wrfnc.variables: |
||||
hgt = wrfnc.variables["HGT"][timeidx,:,:] |
||||
elif "HGT_M": |
||||
hgt = wrfnc.variables["HGT_M"][timeidx,:,:] |
||||
|
||||
return hgt |
||||
|
||||
|
@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
|
||||
|
||||
import datetime as dt |
||||
|
||||
__all__ = ["get_times"] |
||||
|
||||
def _make_time(timearr): |
||||
return dt.strptime("".join(timearr[:]), "%Y-%m-%d_%H:%M:%S") |
||||
|
||||
def get_times(wrfnc): |
||||
times = wrfnc.variables["Times"][:,:] |
||||
return [_make_time(times[i,:]) for i in xrange(times.shape[0])] |
||||
|
||||
|
@ -0,0 +1,126 @@
@@ -0,0 +1,126 @@
|
||||
|
||||
from wrf.var.constants import Constants, ConversionFactors |
||||
|
||||
__all__ = ["check_units", "do_conversion", "convert_units"] |
||||
|
||||
# Handles unit conversions that only differ by multiplication factors |
||||
def _apply_conv_fact(var, vartype, var_unit, dest_unit): |
||||
if var_unit == dest_unit: |
||||
return var |
||||
|
||||
# Note, case where var_unit and dest_unit are base unit, should be |
||||
# handled above |
||||
if var_unit == _BASE_UNITS[vartype]: |
||||
return var * _CONV_FACTORS[vartype]["to_dest"][dest_unit] |
||||
else: |
||||
if dest_unit == _BASE_UNITS[vartype]: |
||||
return var*(_CONV_FACTORS[vartype]["to_base"][var_unit]) |
||||
else: |
||||
return var*(_CONV_FACTORS[vartype]["to_base"][var_unit] * |
||||
_CONV_FACTORS[vartype]["to_dest"][dest_unit]) |
||||
|
||||
def _to_celsius(var, var_unit): |
||||
if var_unit == "k": |
||||
return var - Constants.TCK0 |
||||
elif var_unit == "f": |
||||
return (var - 32.0) * (5.0/9.0) |
||||
|
||||
def _c_to_k(var): |
||||
return var + Constants.TCK0 |
||||
|
||||
def _c_to_f(var): |
||||
return ((9.0/5.0)*var) + 32.0 |
||||
|
||||
# Temperature is a more complicated operation so requres functions |
||||
def _apply_temp_conv(var, var_unit, dest_unit): |
||||
if dest_unit == var_unit: |
||||
return var |
||||
|
||||
if var_unit != _BASE_UNITS["temp"]: |
||||
tc = _to_celsius(var, var_unit) |
||||
if dest_unit == _BASE_UNITS["temp"]: |
||||
return tc |
||||
else: |
||||
return (_TEMP_CONV_METHODS[dest_unit])(tc) |
||||
else: |
||||
return (_TEMP_CONV_METHODS[dest_unit])(var) |
||||
|
||||
_VALID_UNITS = {"wind" : ["mps", "kts", "mph", "kmph", "fps"], |
||||
"pressure" : ["pa", "hpa", "mb", "torr", "mmhg", "atm"], |
||||
"temp" : ["k", "f", "c"], |
||||
"height" : ["m", "km", "dm", "ft", "miles"] |
||||
} |
||||
|
||||
_WIND_BASE_FACTORS = {"kts" : ConversionFactors.MPS_TO_KTS, |
||||
"kmph" : ConversionFactors.MPS_TO_KMPH, |
||||
"mph" : ConversionFactors.MPS_TO_MPH, |
||||
"fps" : ConversionFactors.MPS_TO_FPS |
||||
} |
||||
|
||||
_WIND_TOBASE_FACTORS = {"kts" : 1.0/ConversionFactors.MPS_TO_KTS, |
||||
"kmph" : 1.0/ConversionFactors.MPS_TO_KMPH, |
||||
"mph" : 1.0/ConversionFactors.MPS_TO_MPH, |
||||
"fps" : 1.0/ConversionFactors.MPS_TO_FPS |
||||
} |
||||
|
||||
_PRES_BASE_FACTORS = {"hpa" : ConversionFactors.PA_TO_HPA, |
||||
"mb" : ConversionFactors.PA_TO_HPA, |
||||
"torr" : ConversionFactors.PA_TO_TORR, |
||||
"mmhg" : ConversionFactors.PA_TO_MMHG, |
||||
"atm" : ConversionFactors.PA_TO_ATM |
||||
} |
||||
|
||||
_PRES_TOBASE_FACTORS = {"hpa" : 1.0/ConversionFactors.PA_TO_HPA, |
||||
"mb" : 1.0/ConversionFactors.PA_TO_HPA, |
||||
"torr" : 1.0/ConversionFactors.PA_TO_TORR, |
||||
"mmhg" : 1.0/ConversionFactors.PA_TO_MMHG, |
||||
"atm" : 1.0/ConversionFactors.PA_TO_ATM |
||||
} |
||||
|
||||
_HEIGHT_BASE_FACTORS = {"km" : ConversionFactors.M_TO_KM, |
||||
"dm" : ConversionFactors.M_TO_DM, |
||||
"ft" : ConversionFactors.M_TO_FT, |
||||
"miles" : ConversionFactors.M_TO_MILES |
||||
} |
||||
|
||||
_HEIGHT_TOBASE_FACTORS = {"km" : 1.0/ConversionFactors.M_TO_KM, |
||||
"dm" : 1.0/ConversionFactors.M_TO_DM, |
||||
"ft" : 1.0/ConversionFactors.M_TO_FT, |
||||
"miles" : 1.0/ConversionFactors.M_TO_MILES |
||||
|
||||
} |
||||
|
||||
_BASE_UNITS = {"wind" : "mps", |
||||
"pressure" : "pa", |
||||
"temp" : "c", |
||||
"height" : "m" |
||||
} |
||||
|
||||
_CONV_FACTORS = {"wind" : {"to_dest" : _WIND_BASE_FACTORS, |
||||
"to_base" : _WIND_TOBASE_FACTORS}, |
||||
"pressure" : {"to_dest" : _PRES_BASE_FACTORS, |
||||
"to_base" : _PRES_TOBASE_FACTORS}, |
||||
"height" : {"to_dest" : _HEIGHT_BASE_FACTORS, |
||||
"to_base" : _HEIGHT_TOBASE_FACTORS} |
||||
} |
||||
|
||||
_TEMP_CONV_METHODS = {"k" : _c_to_k, |
||||
"f" : _c_to_f |
||||
} |
||||
|
||||
def check_units(unit, type): |
||||
unitl = unit.lower() |
||||
if unitl not in _VALID_UNITS[type]: |
||||
raise ValueError("invalid unit type '%s'" % unit) |
||||
|
||||
def do_conversion(var, vartype, var_unit, dest_unit): |
||||
if vartype != "temp": |
||||
return _apply_conv_fact(var, vartype, var_unit, dest_unit) |
||||
else: |
||||
return _apply_temp_conv(var, var_unit, dest_unit) |
||||
|
||||
convert_units = do_conversion |
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,105 @@
@@ -0,0 +1,105 @@
|
||||
from math import fabs, log, tan, sin, cos |
||||
|
||||
from wrf.var.extension import computeuvmet |
||||
from wrf.var.destagger import destagger |
||||
from wrf.var.constants import Constants |
||||
from wrf.var.wind import _calc_wspd_wdir |
||||
from wrf.var.decorators import convert_units |
||||
|
||||
__all__=["get_uvmet", "get_uvmet10", "get_uvmet_wspd_wdir", |
||||
"get_uvmet10_wspd_wdir"] |
||||
|
||||
@convert_units("wind", "mps") |
||||
def get_uvmet(wrfnc, ten_m=False, units ="mps", timeidx=0): |
||||
""" Return a tuple of u,v with the winds rotated in to earth space""" |
||||
|
||||
if not ten_m: |
||||
if "U" in wrfnc.variables: |
||||
u = destagger(wrfnc.variables["U"][timeidx,:,:,:], 2) |
||||
elif "UU" in wrfnc.variables: |
||||
u = destagger(wrfnc.variables["UU"][timeidx,:,:,:], 2) # support met_em files |
||||
|
||||
if "V" in wrfnc.variables: |
||||
v = destagger(wrfnc.variables["V"][timeidx,:,:,:], 1) |
||||
elif "VV" in wrfnc.variables: |
||||
v = destagger(wrfnc.variables["VV"][timeidx,:,:,:], 1) |
||||
else: |
||||
if "U10" in wrfnc.variables: |
||||
u = wrfnc.variables["U10"][timeidx,:,:] |
||||
elif "UU" in wrfnc.variables: |
||||
u = destagger(wrfnc.variables["UU"][timeidx,0,:,:], 1) # support met_em files |
||||
|
||||
if "V10" in wrfnc.variables: |
||||
v = wrfnc.variables["V10"][timeidx,:,:] |
||||
elif "VV" in wrfnc.variables: |
||||
v = destagger(wrfnc.variables["VV"][timeidx,0,:,:], 0) # support met_em files |
||||
|
||||
map_proj = wrfnc.getncattr("MAP_PROJ") |
||||
|
||||
# 1 - Lambert |
||||
# 2 - Polar Stereographic |
||||
# 3 - Mercator |
||||
# 6 - Lat/Lon |
||||
# Note: NCL has no code to handle other projections (0,4,5) as they |
||||
# don't appear to be supported any longer |
||||
|
||||
if map_proj in (0,3,6): |
||||
# No rotation needed for Mercator and Lat/Lon |
||||
return u,v |
||||
elif map_proj in (1,2): |
||||
radians_per_degree = Constants.PI/180.0 |
||||
# Rotation needed for Lambert and Polar Stereographic |
||||
cen_lat = wrfnc.getncattr("CEN_LAT") |
||||
if "STAND_LON" in wrfnc.ncattrs(): |
||||
cen_lon = wrfnc.getncattr("STAND_LON") |
||||
else: |
||||
cen_lon = wrfnc.getncattr("CEN_LON") |
||||
|
||||
true_lat1 = wrfnc.getncattr("TRUELAT1") |
||||
true_lat2 = wrfnc.getncattr("TRUELAT2") |
||||
|
||||
if "XLAT_M" in wrfnc.variables: |
||||
lat = wrfnc.variables["XLAT_M"][timeidx,:,:] |
||||
else: |
||||
lat = wrfnc.variables["XLAT"][timeidx,:,:] |
||||
|
||||
if "XLONG_M" in wrfnc.variables: |
||||
lon = wrfnc.variables["XLONG_M"][timeidx,:,:] |
||||
else: |
||||
lon = wrfnc.variables["XLONG"][timeidx,:,:] |
||||
|
||||
if map_proj == 1: |
||||
if((fabs(true_lat1 - true_lat2) > 0.1) and |
||||
(fabs(true_lat2 - 90.) > 0.1)): |
||||
cone = (log(cos(true_lat1*radians_per_degree)) |
||||
- log(cos(true_lat2*radians_per_degree))) |
||||
cone = cone / (log(tan((45.-fabs(true_lat1/2.))*radians_per_degree)) |
||||
- log(tan((45.-fabs(true_lat2/2.))*radians_per_degree))) |
||||
else: |
||||
cone = sin(fabs(true_lat1)*radians_per_degree) |
||||
else: |
||||
cone = 1 |
||||
|
||||
res = computeuvmet(u,v,lat,lon,cen_lon,cone) |
||||
|
||||
if u.ndim == 3: |
||||
return res |
||||
else: |
||||
return res[:,0,:,:] |
||||
|
||||
|
||||
def get_uvmet10(wrfnc, units="mps", timeidx=0): |
||||
return get_uvmet(wrfnc, True, units, timeidx) |
||||
|
||||
def get_uvmet_wspd_wdir(wrfnc, units="mps", timeidx=0): |
||||
u,v = get_uvmet(wrfnc, False, units, timeidx) |
||||
return _calc_wspd_wdir(u, v, units) |
||||
|
||||
def get_uvmet10_wspd_wdir(wrfnc, units="mps", timeidx=0): |
||||
u,v = get_uvmet10(wrfnc, units="mps", timeidx=0) |
||||
return _calc_wspd_wdir(u, v, units) |
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
from wrf.var.extension import computeavo, computepvo |
||||
|
||||
__all__ = ["get_avo", "get_pvo"] |
||||
|
||||
def get_avo(wrfnc, timeidx=0): |
||||
u = wrfnc.variables["U"][timeidx,:,:,:] |
||||
v = wrfnc.variables["V"][timeidx,:,:,:] |
||||
msfu = wrfnc.variables["MAPFAC_U"][timeidx,:,:] |
||||
msfv = wrfnc.variables["MAPFAC_V"][timeidx,:,:] |
||||
msfm = wrfnc.variables["MAPFAC_M"][timeidx,:,:] |
||||
cor = wrfnc.variables["F"][timeidx,:,:] |
||||
dx = wrfnc.getncattr("DX") |
||||
dy = wrfnc.getncattr("DY") |
||||
|
||||
return computeavo(u,v,msfu,msfv,msfm,cor,dx,dy) |
||||
|
||||
|
||||
def get_pvo(wrfnc, timeidx=0): |
||||
u = wrfnc.variables["U"][timeidx,:,:,:] |
||||
v = wrfnc.variables["V"][timeidx,:,:,:] |
||||
t = wrfnc.variables["T"][timeidx,:,:,:] |
||||
p = wrfnc.variables["P"][timeidx,:,:,:] |
||||
pb = wrfnc.variables["PB"][timeidx,:,:,:] |
||||
msfu = wrfnc.variables["MAPFAC_U"][timeidx,:,:] |
||||
msfv = wrfnc.variables["MAPFAC_V"][timeidx,:,:] |
||||
msfm = wrfnc.variables["MAPFAC_M"][timeidx,:,:] |
||||
cor = wrfnc.variables["F"][timeidx,:,:] |
||||
dx = wrfnc.getncattr("DX") |
||||
dy = wrfnc.getncattr("DY") |
||||
|
||||
full_t = t + 300 |
||||
full_p = p + pb |
||||
|
||||
return computepvo(u,v,full_t,full_p,msfu,msfv,msfm,cor,dx,dy) |
||||
|
@ -0,0 +1,43 @@
@@ -0,0 +1,43 @@
|
||||
|
||||
import numpy as n |
||||
|
||||
from wrf.var.constants import Constants |
||||
from wrf.var.destagger import destagger_windcomp |
||||
from wrf.var.decorators import convert_units |
||||
|
||||
__all__ = ["get_u_destag", "get_v_destag", "get_w_destag", |
||||
"get_destag_wspd_wdir"] |
||||
|
||||
def _calc_wspd(u, v): |
||||
return n.sqrt(u**2 + v**2) |
||||
|
||||
def _calc_wdir(u, v): |
||||
wdir = 270.0 - n.arctan2(v,u) * (180.0/Constants.PI) |
||||
return n.remainder(wdir, 360.0) |
||||
|
||||
@convert_units("wind", "mps") |
||||
def _calc_wspd_wdir(u, v, units="mps"): |
||||
check_units(units, "wind") |
||||
return (_calc_wspd(u,v), _calc_wdir(u,v)) |
||||
|
||||
@convert_units("wind", "mps") |
||||
def get_u_destag(wrfnc, units="mps", timeidx=0): |
||||
u = destagger_windcomp(wrfnc,"u", timeidx) |
||||
return u |
||||
|
||||
@convert_units("wind", "mps") |
||||
def get_v_destag(wrfnc, units="mps", timeidx=0): |
||||
v = destagger_windcomp(wrfnc,"v", timeidx) |
||||
return v |
||||
|
||||
@convert_units("wind", "mps") |
||||
def get_w_destag(wrfnc, units="mps", timeidx=0): |
||||
w = destagger_windcomp(wrfnc,"w", timeidx) |
||||
return w |
||||
|
||||
def get_destag_wspd_wdir(wrfnc, units="mps", timeidx=0): |
||||
u = destagger_windcomp(wrfnc,"u", timeidx) |
||||
v = destagger_windcomp(wrfnc,"v", timeidx) |
||||
|
||||
return _calc_wspd_wdir(u,v,units) |
||||
|
@ -0,0 +1,556 @@
@@ -0,0 +1,556 @@
|
||||
! The kind of code only a scientist could love. |
||||
! TODO: The cape routine needs work to remove the GOTOs |
||||
|
||||
!====================================================================== |
||||
! |
||||
! !IROUTINE: TVIRTUAL -- Calculate virtual temperature (K) |
||||
! |
||||
! !DESCRIPTION: |
||||
! |
||||
! This function returns a single value of virtual temperature in |
||||
! K, given temperature in K and mixing ratio in kg/kg. For an |
||||
! array of virtual temperatures, use subroutine VIRTUAL_TEMP. |
||||
! |
||||
! !INPUT: |
||||
! RATMIX - water vapor mixing ratio (kg/kg) |
||||
! TEMP - temperature (K) |
||||
! |
||||
! !OUTPUT: |
||||
! TV - Virtual temperature (K) |
||||
! |
||||
|
||||
REAL(KIND=8) FUNCTION tvirtual(temp,ratmix) |
||||
IMPLICIT NONE |
||||
REAL(KIND=8),INTENT(IN) :: temp,ratmix |
||||
REAL(KIND=8),PARAMETER :: EPS = .622D0 |
||||
|
||||
tvirtual = temp*(EPS+ratmix)/(EPS*(1.D0+ratmix)) |
||||
RETURN |
||||
END FUNCTION tvirtual |
||||
|
||||
REAL(KIND=8) FUNCTION tonpsadiabat(thte,prs,PSADITHTE,PSADIPRS,PSADITMK,GAMMA,& |
||||
throw_exception) |
||||
IMPLICIT NONE |
||||
EXTERNAL throw_exception |
||||
REAL(KIND=8),INTENT(IN) :: thte |
||||
REAL(KIND=8),INTENT(IN) :: prs |
||||
REAL(KIND=8),DIMENSION(150),INTENT(IN) :: PSADITHTE |
||||
REAL(KIND=8),DIMENSION(150),INTENT(IN) :: PSADIPRS |
||||
REAL(KIND=8),DIMENSION(150,150),INTENT(IN) :: PSADITMK |
||||
REAL(KIND=8),INTENT(IN) :: GAMMA |
||||
|
||||
REAL(KIND=8) :: fracjt |
||||
REAL(KIND=8) :: fracjt2 |
||||
REAL(KIND=8) :: fracip |
||||
REAL(KIND=8) :: fracip2 |
||||
|
||||
INTEGER :: ip, ipch, jt, jtch |
||||
|
||||
! This function gives the temperature (in K) on a moist adiabat |
||||
! (specified by thte in K) given pressure in hPa. It uses a |
||||
! lookup table, with data that was generated by the Bolton (1980) |
||||
! formula for theta_e. |
||||
|
||||
! First check if pressure is less than min pressure in lookup table. |
||||
! If it is, assume parcel is so dry that the given theta-e value can |
||||
! be interpretted as theta, and get temperature from the simple dry |
||||
! theta formula. |
||||
|
||||
IF (prs.LE.PSADIPRS(150)) THEN |
||||
tonpsadiabat = thte * (prs/1000.D0)**GAMMA |
||||
RETURN |
||||
END IF |
||||
|
||||
! Otherwise, look for the given thte/prs point in the lookup table. |
||||
|
||||
jt = -1 |
||||
DO jtch = 1,150 - 1 |
||||
IF (thte.GE.PSADITHTE(jtch) .AND. thte.LT.PSADITHTE(jtch+1)) THEN |
||||
jt = jtch |
||||
EXIT |
||||
!GO TO 213 |
||||
END IF |
||||
END DO |
||||
|
||||
! JT = -1 |
||||
!213 CONTINUE |
||||
ip = -1 |
||||
DO ipch = 1,150 - 1 |
||||
IF (prs.LE.PSADIPRS(ipch) .AND. prs.GT.PSADIPRS(ipch+1)) THEN |
||||
ip = ipch |
||||
EXIT |
||||
!GO TO 215 |
||||
END IF |
||||
END DO |
||||
|
||||
! IP = -1 |
||||
!215 CONTINUE |
||||
IF (jt.EQ.-1 .OR. ip.EQ.-1) THEN |
||||
! Need an exception here |
||||
CALL throw_exception('capecalc3d: ','Outside of lookup table bounds. prs,thte=',prs,thte) |
||||
!STOP |
||||
END IF |
||||
fracjt = (thte-PSADITHTE(jt)) / (PSADITHTE(jt+1)-PSADITHTE(jt)) |
||||
fracjt2 = 1.D0 - fracjt |
||||
fracip = (PSADIPRS(ip)-prs) / (PSADIPRS(ip)-PSADIPRS(ip+1)) |
||||
fracip2 = 1.D0 - fracip |
||||
IF (PSADITMK(ip,jt).GT.1D9 .OR. PSADITMK(ip+1,jt).GT.1D9 .OR. & |
||||
PSADITMK(ip,jt+1).GT.1D9 .OR. PSADITMK(ip+1,jt+1).GT.1D9) THEN |
||||
CALL throw_exception('capecalc3d: ','Tried to access missing temperature in lookup table.',& |
||||
'Prs and Thte probably unreasonable. prs,thte=',prs,thte) |
||||
!STOP |
||||
END IF |
||||
tonpsadiabat = fracip2*fracjt2*PSADITMK(ip,jt)+fracip*fracjt2*PSADITMK(ip+1,jt)+& |
||||
fracip2*fracjt*PSADITMK(ip,jt+1)+fracip*fracjt*PSADITMK(ip+1,jt+1) |
||||
|
||||
RETURN |
||||
END FUNCTION tonpsadiabat |
||||
|
||||
|
||||
! Historically, this routine calculated the pressure at full sigma |
||||
! levels when RIP was specifically designed for MM4/MM5 output. |
||||
! With the new generalized RIP (Feb '02), this routine is still |
||||
! intended to calculate a set of pressure levels that bound the |
||||
! layers represented by the vertical grid points, although no such |
||||
! layer boundaries are assumed to be defined. The routine simply |
||||
! uses the midpoint between the pressures of the vertical grid |
||||
! points as the bounding levels. The array only contains mkzh |
||||
! levels, so the pressure of the top of the uppermost layer is |
||||
! actually excluded. The kth value of pf is the lower bounding |
||||
! pressure for the layer represented by kth data level. At the |
||||
! lower bounding level of the lowest model layer, it uses the |
||||
! surface pressure, unless the data set is pressure-level data, in |
||||
! which case it assumes the lower bounding pressure level is as far |
||||
! below the lowest vertical level as the upper bounding pressure |
||||
! level is above. |
||||
SUBROUTINE dpfcalc(prs,sfp,pf,miy,mjx,mkzh,ter_follow) |
||||
|
||||
REAL(KIND=8),DIMENSION(miy,mjx,mkzh),INTENT(IN) :: prs |
||||
REAL(KIND=8),DIMENSION(miy,mjx),INTENT(IN) :: sfp |
||||
REAL(KIND=8),DIMENSION(miy,mjx,mkzh),INTENT(OUT) :: pf |
||||
INTEGER,INTENT(IN) :: ter_follow,miy,mjx,mkzh |
||||
|
||||
INTEGER :: i,j,k |
||||
|
||||
! do j=1,mjx-1 Artifact of MM5 |
||||
DO j = 1,mjx |
||||
! do i=1,miy-1 staggered grid |
||||
DO i = 1,miy |
||||
DO k = 1,mkzh |
||||
IF (k.EQ.mkzh) THEN |
||||
! terrain-following data |
||||
IF (ter_follow.EQ.1) THEN |
||||
pf(i,j,k) = sfp(i,j) |
||||
! pressure-level data |
||||
ELSE |
||||
pf(i,j,k) = .5D0 * (3.D0*prs(i,j,k)-prs(i,j,k-1)) |
||||
END IF |
||||
ELSE |
||||
pf(i,j,k) = .5D0* (prs(i,j,k+1)+prs(i,j,k)) |
||||
END IF |
||||
END DO |
||||
END DO |
||||
END DO |
||||
|
||||
RETURN |
||||
END SUBROUTINE dpfcalc |
||||
|
||||
!====================================================================== |
||||
! |
||||
! !IROUTINE: capecalc3d -- Calculate CAPE and CIN |
||||
! |
||||
! !DESCRIPTION: |
||||
! |
||||
! If i3dflag=1, this routine calculates CAPE and CIN (in m**2/s**2, |
||||
! or J/kg) for every grid point in the entire 3D domain (treating |
||||
! each grid point as a parcel). If i3dflag=0, then it |
||||
! calculates CAPE and CIN only for the parcel with max theta-e in |
||||
! the column, (i.e. something akin to Colman's MCAPE). By "parcel", |
||||
! we mean a 500-m deep parcel, with actual temperature and moisture |
||||
! averaged over that depth. |
||||
! |
||||
! In the case of i3dflag=0, |
||||
! CAPE and CIN are 2D fields that are placed in the k=mkzh slabs of |
||||
! the cape and cin arrays. Also, if i3dflag=0, LCL and LFC heights |
||||
! are put in the k=mkzh-1 and k=mkzh-2 slabs of the cin array. |
||||
! |
||||
|
||||
|
||||
! Important! The z-indexes must be arranged so that mkzh (max z-index) is the |
||||
! surface pressure. So, pressure must be ordered in ascending order before |
||||
! calling this routine. Other variables must be ordered the same (p,tk,q,z). |
||||
|
||||
! Also, be advised that missing data values are not checked during the computation. |
||||
! Also also, Pressure must be hPa |
||||
! |
||||
SUBROUTINE f_computecape(prs,tmk,qvp,ght,ter,sfp,cape,cin,& |
||||
PSADITHTE,PSADIPRS,PSADITMK,cmsg,i3dflag,ter_follow,& |
||||
throw_exception,miy,mjx,mkzh) |
||||
|
||||
IMPLICIT NONE |
||||
EXTERNAL throw_exception |
||||
INTEGER,INTENT(IN) :: miy,mjx,mkzh,i3dflag,ter_follow |
||||
REAL(KIND=8),DIMENSION(miy,mjx,mkzh),INTENT(IN) :: prs |
||||
REAL(KIND=8),DIMENSION(miy,mjx,mkzh),INTENT(IN) :: tmk |
||||
REAL(KIND=8),DIMENSION(miy,mjx,mkzh),INTENT(IN) :: qvp |
||||
REAL(KIND=8),DIMENSION(miy,mjx,mkzh),INTENT(IN) :: ght |
||||
REAL(KIND=8),DIMENSION(miy,mjx),INTENT(IN) :: ter |
||||
REAL(KIND=8),DIMENSION(miy,mjx),INTENT(IN) ::sfp |
||||
REAL(KIND=8),DIMENSION(miy,mjx,mkzh),INTENT(INOUT) :: cape |
||||
REAL(KIND=8),DIMENSION(miy,mjx,mkzh),INTENT(INOUT) :: cin |
||||
REAL(KIND=8),DIMENSION(150),INTENT(IN) :: PSADITHTE,PSADIPRS |
||||
REAL(KIND=8),DIMENSION(150,150),INTENT(IN) :: PSADITMK |
||||
REAL(KIND=8),INTENT(IN) :: cmsg |
||||
|
||||
! local variables |
||||
INTEGER :: i,j,k,ilcl,kel,kk,klcl,klev,klfc,kmax,kpar,kpar1,kpar2 |
||||
REAL(KIND=8) :: davg,ethmax,q,t,p,e,eth,tlcl,zlcl |
||||
REAL(KIND=8) :: pavg,tvirtual,p1,p2,pp1,pp2,th,totthe,totqvp,totprs |
||||
REAL(KIND=8) :: cpm,deltap,ethpari,gammam,ghtpari,qvppari,prspari,tmkpari |
||||
REAL(KIND=8) :: facden,fac1,fac2,qvplift,tmklift,tvenv,tvlift,ghtlift |
||||
REAL(KIND=8) :: eslift,tmkenv,qvpenv,tonpsadiabat |
||||
REAL(KIND=8) :: benamin,dz,pup,pdn |
||||
REAL(KIND=8),DIMENSION(150) :: buoy,zrel,benaccum |
||||
REAL(KIND=8),DIMENSION(miy,mjx,mkzh) :: prsf |
||||
|
||||
! constants |
||||
INTEGER,PARAMETER :: IUP = 6 |
||||
REAL(KIND=8),PARAMETER :: CELKEL = 273.15d0 |
||||
REAL(KIND=8),PARAMETER :: GRAV = 9.81d0 |
||||
! hpa |
||||
REAL(KIND=8),PARAMETER :: EZERO = 6.112d0 |
||||
REAL(KIND=8),PARAMETER :: ESLCON1 = 17.67d0 |
||||
REAL(KIND=8),PARAMETER :: ESLCON2 = 29.65d0 |
||||
REAL(KIND=8),PARAMETER :: EPS = 0.622d0 |
||||
! j/k/kg |
||||
REAL(KIND=8),PARAMETER :: RGAS = 287.04d0 |
||||
! j/k/kg note: not using bolton's value of 1005.7 |
||||
REAL(KIND=8),PARAMETER :: CP = 1004.d0 |
||||
REAL(KIND=8),PARAMETER :: GAMMA = RGAS/CP |
||||
! cp_moist=cp*(1.+cpmd*qvp) |
||||
REAL(KIND=8),PARAMETER :: CPMD = .887d0 |
||||
! rgas_moist=rgas*(1.+rgasmd*qvp) |
||||
REAL(KIND=8),PARAMETER :: RGASMD = .608d0 |
||||
! gamma_moist=gamma*(1.+gammamd*qvp) |
||||
REAL(KIND=8),PARAMETER :: GAMMAMD = RGASMD - CPMD |
||||
REAL(KIND=8),PARAMETER :: TLCLC1 = 2840.d0 |
||||
REAL(KIND=8),PARAMETER :: TLCLC2 = 3.5d0 |
||||
REAL(KIND=8),PARAMETER :: TLCLC3 = 4.805d0 |
||||
REAL(KIND=8),PARAMETER :: TLCLC4 = 55.d0 |
||||
! k |
||||
REAL(KIND=8),PARAMETER :: THTECON1 = 3376.d0 |
||||
REAL(KIND=8),PARAMETER :: THTECON2 = 2.54d0 |
||||
REAL(KIND=8),PARAMETER :: THTECON3 = .81d0 |
||||
|
||||
! To get rid of compiler warnings |
||||
tmkpari = 0 |
||||
qvppari = 0 |
||||
klev = 0 |
||||
klcl = 0 |
||||
|
||||
! the comments were taken from a mark stoelinga email, 23 apr 2007, |
||||
! in response to a user getting the "outside of lookup table bounds" |
||||
! error message. |
||||
|
||||
! tmkpari - initial temperature of parcel, k |
||||
! values of 300 okay. (not sure how much from this you can stray.) |
||||
|
||||
! prspari - initial pressure of parcel, hpa |
||||
! values of 980 okay. (not sure how much from this you can stray.) |
||||
|
||||
! thtecon1, thtecon2, thtecon3 |
||||
! these are all constants, the first in k and the other two have |
||||
! no units. values of 3376, 2.54, and 0.81 were stated as being |
||||
! okay. |
||||
|
||||
! tlcl - the temperature at the parcel's lifted condensation level, k |
||||
! should be a reasonable atmospheric temperature around 250-300 k |
||||
! (398 is "way too high") |
||||
|
||||
! qvppari - the initial water vapor mixing ratio of the parcel, |
||||
! kg/kg (should range from 0.000 to 0.025) |
||||
! |
||||
|
||||
! calculated the pressure at full sigma levels (a set of pressure |
||||
! levels that bound the layers represented by the vertical grid points) |
||||
|
||||
CALL dpfcalc(prs,sfp,prsf,miy,mjx,mkzh,ter_follow) |
||||
|
||||
! before looping, set lookup table for getting temperature on |
||||
! a pseudoadiabat. |
||||
|
||||
!call dlookup_table(psadithte,psadiprs,psaditmk,psafile) |
||||
|
||||
! do j=1,mjx-1 |
||||
DO j = 1,mjx |
||||
! do i=1,miy-1 |
||||
DO i = 1,miy |
||||
cape(i,j,1) = 0.d0 |
||||
cin(i,j,1) = 0.d0 |
||||
|
||||
IF (i3dflag.eq.1) THEN |
||||
kpar1 = 2 |
||||
kpar2 = mkzh |
||||
ELSE |
||||
|
||||
! find parcel with max theta-e in lowest 3 km agl. |
||||
|
||||
ethmax = -1.d0 |
||||
DO k = mkzh,1,-1 |
||||
IF (ght(i,j,k)-ter(i,j).lt.3000.d0) then |
||||
q = MAX(qvp(i,j,k),1.d-15) |
||||
t = tmk(i,j,k) |
||||
p = prs(i,j,k) |
||||
e = q*p/ (EPS+q) |
||||
tlcl = TLCLC1/ (log(t**TLCLC2/e)-TLCLC3) + TLCLC4 |
||||
eth = t* (1000.d0/p)**(GAMMA* (1.d0+GAMMAMD*q))*& |
||||
EXP((THTECON1/tlcl-THTECON2)*q*(1.d0+THTECON3*q)) |
||||
IF (eth.gt.ethmax) then |
||||
klev = k |
||||
ethmax = eth |
||||
END IF |
||||
END IF |
||||
END DO |
||||
kpar1 = klev |
||||
kpar2 = klev |
||||
|
||||
! establish average properties of that parcel |
||||
! (over depth of approximately davg meters) |
||||
|
||||
! davg=.1 |
||||
davg = 500.d0 |
||||
pavg = davg*prs(i,j,kpar1)*& |
||||
GRAV/(RGAS*tvirtual(tmk(i,j,kpar1),qvp(i,j,kpar1))) |
||||
p2 = MIN(prs(i,j,kpar1)+.5d0*pavg,prsf(i,j,mkzh)) |
||||
p1 = p2 - pavg |
||||
totthe = 0.d0 |
||||
totqvp = 0.d0 |
||||
totprs = 0.d0 |
||||
DO k = mkzh,2,-1 |
||||
IF (prsf(i,j,k).le.p1) GOTO 35 |
||||
IF (prsf(i,j,k-1).ge.p2) GOTO 34 |
||||
p = prs(i,j,k) |
||||
pup = prsf(i,j,k) |
||||
pdn = prsf(i,j,k-1) |
||||
q = MAX(qvp(i,j,k),1.d-15) |
||||
th = tmk(i,j,k)* (1000.d0/p)**(GAMMA* (1.d0+GAMMAMD*q)) |
||||
pp1 = MAX(p1,pdn) |
||||
pp2 = MIN(p2,pup) |
||||
IF (pp2.gt.pp1) then |
||||
deltap = pp2 - pp1 |
||||
totqvp = totqvp + q*deltap |
||||
totthe = totthe + th*deltap |
||||
totprs = totprs + deltap |
||||
END IF |
||||
34 CONTINUE |
||||
END DO |
||||
35 CONTINUE |
||||
qvppari = totqvp/totprs |
||||
tmkpari = (totthe/totprs)*& |
||||
(prs(i,j,kpar1)/1000.d0)**(GAMMA*(1.d0+GAMMAMD*qvp(i,j,kpar1))) |
||||
END IF |
||||
|
||||
DO kpar = kpar1,kpar2 |
||||
|
||||
! calculate temperature and moisture properties of parcel |
||||
! (note, qvppari and tmkpari already calculated above for 2d case.) |
||||
|
||||
IF (i3dflag.eq.1) then |
||||
qvppari = qvp(i,j,kpar) |
||||
tmkpari = tmk(i,j,kpar) |
||||
END IF |
||||
prspari = prs(i,j,kpar) |
||||
ghtpari = ght(i,j,kpar) |
||||
gammam = GAMMA* (1.d0+GAMMAMD*qvppari) |
||||
cpm = CP* (1.d0+CPMD*qvppari) |
||||
|
||||
e = MAX(1.d-20,qvppari*prspari/ (EPS+qvppari)) |
||||
tlcl = TLCLC1/ (LOG(tmkpari**TLCLC2/e)-TLCLC3) +TLCLC4 |
||||
ethpari = tmkpari* (1000.d0/prspari)**(GAMMA*(1.d0+GAMMAMD*qvppari))*& |
||||
EXP((THTECON1/tlcl-THTECON2)*qvppari*(1.d0+THTECON3*qvppari)) |
||||
zlcl = ghtpari + (tmkpari-tlcl)/ (GRAV/cpm) |
||||
|
||||
! calculate buoyancy and relative height of lifted parcel at |
||||
! all levels, and store in bottom up arrays. add a level at the lcl, |
||||
! and at all points where buoyancy is zero. |
||||
! |
||||
! for arrays that go bottom to top |
||||
kk = 0 |
||||
ilcl = 0 |
||||
IF (ghtpari.ge.zlcl) THEN |
||||
|
||||
! initial parcel already saturated or supersaturated. |
||||
|
||||
ilcl = 2 |
||||
klcl = 1 |
||||
END IF |
||||
DO k = kpar,1,-1 |
||||
! for arrays that go bottom to top |
||||
33 kk = kk + 1 |
||||
! model level is below lcl |
||||
IF (ght(i,j,k).lt.zlcl) THEN |
||||
qvplift = qvppari |
||||
tmklift = tmkpari - GRAV/cpm*(ght(i,j,k)-ghtpari) |
||||
tvenv = tvirtual(tmk(i,j,k),qvp(i,j,k)) |
||||
tvlift = tvirtual(tmklift,qvplift) |
||||
ghtlift = ght(i,j,k) |
||||
ELSE IF (ght(i,j,k).ge.zlcl .and. ilcl.eq.0) THEN |
||||
|
||||
! this model level and previous model level straddle the lcl, |
||||
! so first create a new level in the bottom-up array, at the lcl. |
||||
|
||||
tmklift = tlcl |
||||
qvplift = qvppari |
||||
facden = ght(i,j,k) - ght(i,j,k+1) |
||||
fac1 = (zlcl-ght(i,j,k+1))/facden |
||||
fac2 = (ght(i,j,k)-zlcl)/facden |
||||
tmkenv = tmk(i,j,k+1)*fac2 + tmk(i,j,k)*fac1 |
||||
qvpenv = qvp(i,j,k+1)*fac2 + qvp(i,j,k)*fac1 |
||||
tvenv = tvirtual(tmkenv,qvpenv) |
||||
tvlift = tvirtual(tmklift,qvplift) |
||||
ghtlift = zlcl |
||||
ilcl = 1 |
||||
ELSE |
||||
tmklift = tonpsadiabat(ethpari,prs(i,j,k),PSADITHTE,PSADIPRS,PSADITMK,GAMMA,throw_exception) |
||||
eslift = EZERO*exp(ESLCON1* (tmklift-CELKEL)/(tmklift-ESLCON2)) |
||||
qvplift = EPS*eslift/ (prs(i,j,k)-eslift) |
||||
tvenv = tvirtual(tmk(i,j,k),qvp(i,j,k)) |
||||
tvlift = tvirtual(tmklift,qvplift) |
||||
ghtlift = ght(i,j,k) |
||||
END IF |
||||
! buoyancy |
||||
buoy(kk) = GRAV* (tvlift-tvenv)/tvenv |
||||
zrel(kk) = ghtlift - ghtpari |
||||
IF ((kk.gt.1).and.(buoy(kk)*buoy(kk-1).lt.0.0d0)) THEN |
||||
|
||||
! parcel ascent curve crosses sounding curve, so create a new level |
||||
! in the bottom-up array at the crossing. |
||||
|
||||
kk = kk + 1 |
||||
buoy(kk) = buoy(kk-1) |
||||
zrel(kk) = zrel(kk-1) |
||||
buoy(kk-1) = 0.d0 |
||||
zrel(kk-1) = zrel(kk-2) +buoy(kk-2)/& |
||||
(buoy(kk-2)-buoy(kk))*(zrel(kk)-zrel(kk-2)) |
||||
END IF |
||||
IF (ilcl.eq.1) THEN |
||||
klcl = kk |
||||
ilcl = 2 |
||||
GOTO 33 |
||||
END IF |
||||
END DO |
||||
kmax = kk |
||||
IF (kmax.gt.150) THEN |
||||
! Need an exception here |
||||
CALL throw_exception('capecalc3d: kmax got too big. kmax=',kmax) |
||||
!STOP |
||||
END IF |
||||
|
||||
! if no lcl was found, set klcl to kmax. it is probably not really |
||||
! at kmax, but this will make the rest of the routine behave |
||||
! properly. |
||||
|
||||
IF (ilcl.eq.0) klcl=kmax |
||||
|
||||
! get the accumulated buoyant energy from the parcel's starting |
||||
! point, at all levels up to the top level. |
||||
|
||||
benaccum(1) = 0.0d0 |
||||
benamin = 9d9 |
||||
DO k = 2,kmax |
||||
dz = zrel(k) - zrel(k-1) |
||||
benaccum(k) = benaccum(k-1) +.5d0*dz* (buoy(k-1)+buoy(k)) |
||||
IF (benaccum(k).lt.benamin) then |
||||
benamin = benaccum(k) |
||||
END IF |
||||
END DO |
||||
|
||||
! determine equilibrium level (el), which we define as the highest |
||||
! level of non-negative buoyancy above the lcl. note, this may be |
||||
! the top level if the parcel is still buoyant there. |
||||
|
||||
DO k = kmax,klcl,-1 |
||||
IF (buoy(k).ge.0.d0) THEN |
||||
! k of equilibrium level |
||||
kel = k |
||||
GOTO 50 |
||||
END IF |
||||
END DO |
||||
|
||||
! if we got through that loop, then there is no non-negative |
||||
! buoyancy above the lcl in the sounding. in these situations, |
||||
! both cape and cin will be set to -0.1 j/kg. (see below about |
||||
! missing values in v6.1.0). also, where cape is |
||||
! non-zero, cape and cin will be set to a minimum of +0.1 j/kg, so |
||||
! that the zero contour in either the cin or cape fields will |
||||
! circumscribe regions of non-zero cape. |
||||
|
||||
! in v6.1.0 of ncl, we added a _fillvalue attribute to the return |
||||
! value of this function. at that time we decided to change -0.1 |
||||
! to a more appropriate missing value, which is passed into this |
||||
! routine as cmsg. |
||||
|
||||
! cape(i,j,kpar) = -0.1d0 |
||||
! cin(i,j,kpar) = -0.1d0 |
||||
cape(i,j,kpar) = cmsg |
||||
cin(i,j,kpar) = cmsg |
||||
klfc = kmax |
||||
|
||||
GOTO 102 |
||||
|
||||
50 CONTINUE |
||||
|
||||
! if there is an equilibrium level, then cape is positive. we'll |
||||
! define the level of free convection (lfc) as the point below the |
||||
! el, but at or above the lcl, where accumulated buoyant energy is a |
||||
! minimum. the net positive area (accumulated buoyant energy) from |
||||
! the lfc up to the el will be defined as the cape, and the net |
||||
! negative area (negative of accumulated buoyant energy) from the |
||||
! parcel starting point to the lfc will be defined as the convective |
||||
! inhibition (cin). |
||||
|
||||
! first get the lfc according to the above definition. |
||||
|
||||
benamin = 9d9 |
||||
klfc = kmax |
||||
DO k = klcl,kel |
||||
IF (benaccum(k).lt.benamin) THEN |
||||
benamin = benaccum(k) |
||||
klfc = k |
||||
END IF |
||||
END DO |
||||
|
||||
! now we can assign values to cape and cin |
||||
|
||||
cape(i,j,kpar) = MAX(benaccum(kel)-benamin,0.1d0) |
||||
cin(i,j,kpar) = MAX(-benamin,0.1d0) |
||||
|
||||
! cin is uninteresting when cape is small (< 100 j/kg), so set |
||||
! cin to -0.1 (see note about missing values in v6.1.0) in |
||||
! that case. |
||||
|
||||
! in v6.1.0 of ncl, we added a _fillvalue attribute to the return |
||||
! value of this function. at that time we decided to change -0.1 |
||||
! to a more appropriate missing value, which is passed into this |
||||
! routine as cmsg. |
||||
|
||||
! IF (cape(i,j,kpar).lt.100.d0) cin(i,j,kpar) = -0.1d0 |
||||
IF (cape(i,j,kpar).lt.100.d0) cin(i,j,kpar) = cmsg |
||||
102 CONTINUE |
||||
|
||||
END DO |
||||
|
||||
IF (i3dflag.eq.0) THEN |
||||
cape(i,j,mkzh) = cape(i,j,kpar1) |
||||
cin(i,j,mkzh) = cin(i,j,kpar1) |
||||
! meters agl |
||||
cin(i,j,mkzh-1) = zrel(klcl) + ghtpari - ter(i,j) |
||||
! meters agl |
||||
cin(i,j,mkzh-2) = zrel(klfc) + ghtpari - ter(i,j) |
||||
ENDIF |
||||
|
||||
END DO |
||||
END DO |
||||
|
||||
RETURN |
||||
END SUBROUTINE f_computecape |
@ -0,0 +1,74 @@
@@ -0,0 +1,74 @@
|
||||
! -*- f90 -*- |
||||
! Note: the context of this file is case sensitive. |
||||
|
||||
python module tonpsadiabat__user__routines |
||||
interface tonpsadiabat_user_interface |
||||
subroutine throw_exception(e__capecalc3d___err,e__outside_of_lookup_table_bounds__prs_thte__err,prs,thte) ! in :_wrfcape:wrfcape.f90:tonpsadiabat:unknown_interface |
||||
character*(*) :: e__capecalc3d___err |
||||
character*(*) :: e__outside_of_lookup_table_bounds__prs_thte__err |
||||
real(kind=8) intent(in) :: prs |
||||
real(kind=8) intent(in) :: thte |
||||
end subroutine throw_exception |
||||
end interface tonpsadiabat_user_interface |
||||
end python module tonpsadiabat__user__routines |
||||
python module f_computecape__user__routines |
||||
interface f_computecape_user_interface |
||||
subroutine throw_exception(e__capecalc3d__kmax_got_too_big__kmax__err,kmax) ! in :_wrfcape:wrfcape.f90:f_computecape:unknown_interface |
||||
character*(*) :: e__capecalc3d__kmax_got_too_big__kmax__err |
||||
integer :: kmax |
||||
end subroutine throw_exception |
||||
end interface f_computecape_user_interface |
||||
end python module f_computecape__user__routines |
||||
python module _wrfcape ! in |
||||
interface ! in :_wrfcape |
||||
function tvirtual(temp,ratmix) ! in :_wrfcape:wrfcape.f90 |
||||
real(kind=8) intent(in) :: temp |
||||
real(kind=8) intent(in) :: ratmix |
||||
real(kind=8) :: tvirtual |
||||
end function tvirtual |
||||
function tonpsadiabat(thte,prs,psadithte,psadiprs,psaditmk,gamma,throw_exception) ! in :_wrfcape:wrfcape.f90 |
||||
use tonpsadiabat__user__routines |
||||
real(kind=8) intent(in) :: thte |
||||
real(kind=8) intent(in) :: prs |
||||
real(kind=8) dimension(150),intent(in) :: psadithte |
||||
real(kind=8) dimension(150),intent(in) :: psadiprs |
||||
real(kind=8) dimension(150,150),intent(in) :: psaditmk |
||||
real(kind=8) intent(in) :: gamma |
||||
external throw_exception |
||||
real(kind=8) :: tonpsadiabat |
||||
end function tonpsadiabat |
||||
subroutine dpfcalc(prs,sfp,pf,miy,mjx,mkzh,ter_follow) ! in :_wrfcape:wrfcape.f90 |
||||
real(kind=8) dimension(miy,mjx,mkzh),intent(in) :: prs |
||||
real(kind=8) dimension(miy,mjx),intent(in),depend(miy,mjx) :: sfp |
||||
real(kind=8) dimension(miy,mjx,mkzh),intent(out),depend(miy,mjx,mkzh) :: pf |
||||
integer, optional,intent(in),check(shape(prs,0)==miy),depend(prs) :: miy=shape(prs,0) |
||||
integer, optional,intent(in),check(shape(prs,1)==mjx),depend(prs) :: mjx=shape(prs,1) |
||||
integer, optional,intent(in),check(shape(prs,2)==mkzh),depend(prs) :: mkzh=shape(prs,2) |
||||
integer intent(in) :: ter_follow |
||||
end subroutine dpfcalc |
||||
subroutine f_computecape(prs,tmk,qvp,ght,ter,sfp,cape,cin,psadithte,psadiprs,psaditmk,cmsg,i3dflag,ter_follow,throw_exception,miy,mjx,mkzh) ! in :_wrfcape:wrfcape.f90 |
||||
use f_computecape__user__routines |
||||
real(kind=8) dimension(miy,mjx,mkzh),intent(in) :: prs |
||||
real(kind=8) dimension(miy,mjx,mkzh),intent(in),depend(miy,mjx,mkzh) :: tmk |
||||
real(kind=8) dimension(miy,mjx,mkzh),intent(in),depend(miy,mjx,mkzh) :: qvp |
||||
real(kind=8) dimension(miy,mjx,mkzh),intent(in),depend(miy,mjx,mkzh) :: ght |
||||
real(kind=8) dimension(miy,mjx),intent(in),depend(miy,mjx) :: ter |
||||
real(kind=8) dimension(miy,mjx),intent(in),depend(miy,mjx) :: sfp |
||||
real(kind=8) dimension(miy,mjx,mkzh),intent(inout),depend(miy,mjx,mkzh) :: cape |
||||
real(kind=8) dimension(miy,mjx,mkzh),intent(inout),depend(miy,mjx,mkzh) :: cin |
||||
real(kind=8) dimension(150),intent(in) :: psadithte |
||||
real(kind=8) dimension(150),intent(in) :: psadiprs |
||||
real(kind=8) dimension(150,150),intent(in) :: psaditmk |
||||
real(kind=8) intent(in) :: cmsg |
||||
integer intent(in) :: i3dflag |
||||
integer intent(in) :: ter_follow |
||||
external throw_exception |
||||
integer, optional,intent(in),check(shape(prs,0)==miy),depend(prs) :: miy=shape(prs,0) |
||||
integer, optional,intent(in),check(shape(prs,1)==mjx),depend(prs) :: mjx=shape(prs,1) |
||||
integer, optional,intent(in),check(shape(prs,2)==mkzh),depend(prs) :: mkzh=shape(prs,2) |
||||
end subroutine f_computecape |
||||
end interface |
||||
end python module _wrfcape |
||||
|
||||
! This file was auto-generated with f2py (version:2). |
||||
! See http://cens.ioc.ee/projects/f2py2e/ |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,334 @@
@@ -0,0 +1,334 @@
|
||||
! -*- f90 -*- |
||||
! Note: the context of this file is case sensitive. |
||||
|
||||
python module f_computeslp__user__routines |
||||
interface f_computeslp_user_interface |
||||
subroutine throw_exception(e__error_in_finding_100_hpa_up_err) ! in :_wrfext:wrfext.f90:f_computeslp:unknown_interface |
||||
character*(*) :: e__error_in_finding_100_hpa_up_err |
||||
end subroutine throw_exception |
||||
end interface f_computeslp_user_interface |
||||
end python module f_computeslp__user__routines |
||||
python module f_computewetbulb__user__routines |
||||
interface f_computewetbulb_user_interface |
||||
subroutine throw_exception(e__outside_of_lookup_table_bounds__prs_thte__err,p,eth) ! in :_wrfext:wrfext.f90:f_computewetbulb:unknown_interface |
||||
character*(*) :: e__outside_of_lookup_table_bounds__prs_thte__err |
||||
real(kind=8) :: p |
||||
real(kind=8) :: eth |
||||
end subroutine throw_exception |
||||
end interface f_computewetbulb_user_interface |
||||
end python module f_computewetbulb__user__routines |
||||
python module f_lltoij__user__routines |
||||
interface f_lltoij_user_interface |
||||
subroutine throw_exception(e__do_not_know_map_projection__err,map_proj) ! in :_wrfext:wrfext.f90:f_lltoij:unknown_interface |
||||
character*(*) :: e__do_not_know_map_projection__err |
||||
integer intent(in) :: map_proj |
||||
end subroutine throw_exception |
||||
end interface f_lltoij_user_interface |
||||
end python module f_lltoij__user__routines |
||||
python module f_ijtoll__user__routines |
||||
interface f_ijtoll_user_interface |
||||
subroutine throw_exception(e__do_not_know_map_projection__err,map_proj) ! in :_wrfext:wrfext.f90:f_ijtoll:unknown_interface |
||||
character*(*) :: e__do_not_know_map_projection__err |
||||
integer intent(in) :: map_proj |
||||
end subroutine throw_exception |
||||
end interface f_ijtoll_user_interface |
||||
end python module f_ijtoll__user__routines |
||||
python module _wrfext ! in |
||||
interface ! in :_wrfext |
||||
subroutine f_interpz3d(data3d,zdata,desiredloc,missingval,out2d,nx,ny,nz) ! in :_wrfext:wrfext.f90 |
||||
real(kind=8) dimension(nx,ny,nz),intent(in) :: data3d |
||||
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: zdata |
||||
real(kind=8) intent(in) :: desiredloc |
||||
real(kind=8) intent(in) :: missingval |
||||
real(kind=8) dimension(nx,ny),intent(out),depend(nx,ny) :: out2d |
||||
integer, optional,intent(in),check(shape(data3d,0)==nx),depend(data3d) :: nx=shape(data3d,0) |
||||
integer, optional,intent(in),check(shape(data3d,1)==ny),depend(data3d) :: ny=shape(data3d,1) |
||||
integer, optional,intent(in),check(shape(data3d,2)==nz),depend(data3d) :: nz=shape(data3d,2) |
||||
end subroutine f_interpz3d |
||||
subroutine f_interp2dxy(v3d,xy,v2d,nx,ny,nz,nxy) ! in :_wrfext:wrfext.f90 |
||||
real(kind=8) dimension(nx,ny,nz),intent(in) :: v3d |
||||
real(kind=8) dimension(2,nxy),intent(in) :: xy |
||||
real(kind=8) dimension(nxy,nz),intent(out),depend(nxy,nz) :: v2d |
||||
integer, optional,intent(in),check(shape(v3d,0)==nx),depend(v3d) :: nx=shape(v3d,0) |
||||
integer, optional,intent(in),check(shape(v3d,1)==ny),depend(v3d) :: ny=shape(v3d,1) |
||||
integer, optional,intent(in),check(shape(v3d,2)==nz),depend(v3d) :: nz=shape(v3d,2) |
||||
integer, optional,intent(in),check(shape(xy,1)==nxy),depend(xy) :: nxy=shape(xy,1) |
||||
end subroutine f_interp2dxy |
||||
subroutine f_interp1d(v_in,z_in,z_out,vmsg,v_out,nz_in,nz_out) ! in :_wrfext:wrfext.f90 |
||||
real(kind=8) dimension(nz_in),intent(in) :: v_in |
||||
real(kind=8) dimension(nz_in),intent(in),depend(nz_in) :: z_in |
||||
real(kind=8) dimension(nz_out),intent(in) :: z_out |
||||
real(kind=8) intent(in) :: vmsg |
||||
real(kind=8) dimension(nz_out),intent(out),depend(nz_out) :: v_out |
||||
integer, optional,intent(in),check(len(v_in)>=nz_in),depend(v_in) :: nz_in=len(v_in) |
||||
integer, optional,intent(in),check(len(z_out)>=nz_out),depend(z_out) :: nz_out=len(z_out) |
||||
end subroutine f_interp1d |
||||
subroutine f_computeslp(z,t,p,q,t_sea_level,t_surf,level,throw_exception,sea_level_pressure,nx,ny,nz) ! in :_wrfext:wrfext.f90 |
||||
use f_computeslp__user__routines |
||||
real(kind=8) dimension(nx,ny,nz),intent(in) :: z |
||||
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: t |
||||
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: p |
||||
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: q |
||||
real(kind=8) dimension(nx,ny),intent(inout),depend(nx,ny) :: t_sea_level |
||||
real(kind=8) dimension(nx,ny),intent(inout),depend(nx,ny) :: t_surf |
||||
integer dimension(nx,ny),intent(inout),depend(nx,ny) :: level |
||||
external throw_exception |
||||
real(kind=8) dimension(nx,ny),intent(out),depend(nx,ny) :: sea_level_pressure |
||||
integer, optional,intent(in),check(shape(z,0)==nx),depend(z) :: nx=shape(z,0) |
||||
integer, optional,intent(in),check(shape(z,1)==ny),depend(z) :: ny=shape(z,1) |
||||
integer, optional,intent(in),check(shape(z,2)==nz),depend(z) :: nz=shape(z,2) |
||||
end subroutine f_computeslp |
||||
subroutine f_computetk(pressure,theta,tk,nx) ! in :_wrfext:wrfext.f90 |
||||
real(kind=8) dimension(nx),intent(in) :: pressure |
||||
real(kind=8) dimension(nx),intent(in),depend(nx) :: theta |
||||
real(kind=8) dimension(nx),intent(out),depend(nx) :: tk |
||||
integer, optional,intent(in),check(len(pressure)>=nx),depend(pressure) :: nx=len(pressure) |
||||
end subroutine f_computetk |
||||
subroutine f_computetd(pressure,qv_in,td,nx) ! in :_wrfext:wrfext.f90 |
||||
real(kind=8) dimension(nx),intent(in) :: pressure |
||||
real(kind=8) dimension(nx),intent(in),depend(nx) :: qv_in |
||||
real(kind=8) dimension(nx),intent(out),depend(nx) :: td |
||||
integer, optional,intent(in),check(len(pressure)>=nx),depend(pressure) :: nx=len(pressure) |
||||
end subroutine f_computetd |
||||
subroutine f_computerh(qv,p,t,rh,nx) ! in :_wrfext:wrfext.f90 |
||||
real(kind=8) dimension(nx),intent(in) :: qv |
||||
real(kind=8) dimension(nx),intent(in),depend(nx) :: p |
||||
real(kind=8) dimension(nx),intent(in),depend(nx) :: t |
||||
real(kind=8) dimension(nx),intent(out),depend(nx) :: rh |
||||
integer, optional,intent(in),check(len(qv)>=nx),depend(qv) :: nx=len(qv) |
||||
end subroutine f_computerh |
||||
subroutine f_computeabsvort(u,v,msfu,msfv,msft,cor,dx,dy,av,nx,ny,nz,nxp1,nyp1) ! in :_wrfext:wrfext.f90 |
||||
real(kind=8) dimension(nxp1,ny,nz),intent(in) :: u |
||||
real(kind=8) dimension(nx,nyp1,nz),intent(in),depend(nz) :: v |
||||
real(kind=8) dimension(nxp1,ny),intent(in),depend(nxp1,ny) :: msfu |
||||
real(kind=8) dimension(nx,nyp1),intent(in),depend(nx,nyp1) :: msfv |
||||
real(kind=8) dimension(nx,ny),intent(in),depend(nx,ny) :: msft |
||||
real(kind=8) dimension(nx,ny),intent(in),depend(nx,ny) :: cor |
||||
real(kind=8) :: dx |
||||
real(kind=8) :: dy |
||||
real(kind=8) dimension(nx,ny,nz),intent(out),depend(nx,ny,nz) :: av |
||||
integer, optional,intent(in),check(shape(v,0)==nx),depend(v) :: nx=shape(v,0) |
||||
integer, optional,intent(in),check(shape(u,1)==ny),depend(u) :: ny=shape(u,1) |
||||
integer, optional,intent(in),check(shape(u,2)==nz),depend(u) :: nz=shape(u,2) |
||||
integer, optional,intent(in),check(shape(u,0)==nxp1),depend(u) :: nxp1=shape(u,0) |
||||
integer, optional,intent(in),check(shape(v,1)==nyp1),depend(v) :: nyp1=shape(v,1) |
||||
end subroutine f_computeabsvort |
||||
subroutine f_computepvo(u,v,theta,prs,msfu,msfv,msft,cor,dx,dy,pv,nx,ny,nz,nxp1,nyp1) ! in :_wrfext:wrfext.f90 |
||||
real(kind=8) dimension(nxp1,ny,nz),intent(in) :: u |
||||
real(kind=8) dimension(nx,nyp1,nz),intent(in),depend(nz) :: v |
||||
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: theta |
||||
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: prs |
||||
real(kind=8) dimension(nxp1,ny),intent(in),depend(nxp1,ny) :: msfu |
||||
real(kind=8) dimension(nx,nyp1),intent(in),depend(nx,nyp1) :: msfv |
||||
real(kind=8) dimension(nx,ny),intent(in),depend(nx,ny) :: msft |
||||
real(kind=8) dimension(nx,ny),intent(in),depend(nx,ny) :: cor |
||||
real(kind=8) :: dx |
||||
real(kind=8) :: dy |
||||
real(kind=8) dimension(nx,ny,nz),intent(out),depend(nx,ny,nz) :: pv |
||||
integer, optional,intent(in),check(shape(v,0)==nx),depend(v) :: nx=shape(v,0) |
||||
integer, optional,intent(in),check(shape(u,1)==ny),depend(u) :: ny=shape(u,1) |
||||
integer, optional,intent(in),check(shape(u,2)==nz),depend(u) :: nz=shape(u,2) |
||||
integer, optional,intent(in),check(shape(u,0)==nxp1),depend(u) :: nxp1=shape(u,0) |
||||
integer, optional,intent(in),check(shape(v,1)==nyp1),depend(v) :: nyp1=shape(v,1) |
||||
end subroutine f_computepvo |
||||
subroutine f_computeeth(qvp,tmk,prs,eth,miy,mjx,mkzh) ! in :_wrfext:wrfext.f90 |
||||
real(kind=8) dimension(miy,mjx,mkzh),intent(in) :: qvp |
||||
real(kind=8) dimension(miy,mjx,mkzh),intent(in),depend(miy,mjx,mkzh) :: tmk |
||||
real(kind=8) dimension(miy,mjx,mkzh),intent(in),depend(miy,mjx,mkzh) :: prs |
||||
real(kind=8) dimension(miy,mjx,mkzh),intent(out),depend(miy,mjx,mkzh) :: eth |
||||
integer, optional,intent(in),check(shape(qvp,0)==miy),depend(qvp) :: miy=shape(qvp,0) |
||||
integer, optional,intent(in),check(shape(qvp,1)==mjx),depend(qvp) :: mjx=shape(qvp,1) |
||||
integer, optional,intent(in),check(shape(qvp,2)==mkzh),depend(qvp) :: mkzh=shape(qvp,2) |
||||
end subroutine f_computeeth |
||||
subroutine f_computeuvmet(u,v,longca,longcb,flong,flat,cen_long,cone,rpd,istag,is_msg_val,umsg,vmsg,uvmetmsg,uvmet,nx,ny,nxp1,nyp1,nz) ! in :_wrfext:wrfext.f90 |
||||
real(kind=8) dimension(nxp1,ny,nz),intent(in) :: u |
||||
real(kind=8) dimension(nx,nyp1,nz),intent(in),depend(nz) :: v |
||||
real(kind=8) dimension(nx,ny),intent(inout),depend(nx,ny) :: longca |
||||
real(kind=8) dimension(nx,ny),intent(inout),depend(nx,ny) :: longcb |
||||
real(kind=8) dimension(nx,ny),intent(in),depend(nx,ny) :: flong |
||||
real(kind=8) dimension(nx,ny),intent(in),depend(nx,ny) :: flat |
||||
real(kind=8) intent(in) :: cen_long |
||||
real(kind=8) intent(in) :: cone |
||||
real(kind=8) intent(in) :: rpd |
||||
integer intent(in) :: istag |
||||
logical intent(in) :: is_msg_val |
||||
real(kind=8) intent(in) :: umsg |
||||
real(kind=8) intent(in) :: vmsg |
||||
real(kind=8) intent(in) :: uvmetmsg |
||||
real(kind=8) dimension(nx,ny,nz,2),intent(out),depend(nx,ny,nz) :: uvmet |
||||
integer, optional,intent(in),check(shape(v,0)==nx),depend(v) :: nx=shape(v,0) |
||||
integer, optional,intent(in),check(shape(u,1)==ny),depend(u) :: ny=shape(u,1) |
||||
integer, optional,intent(in),check(shape(u,0)==nxp1),depend(u) :: nxp1=shape(u,0) |
||||
integer, optional,intent(in),check(shape(v,1)==nyp1),depend(v) :: nyp1=shape(v,1) |
||||
integer, optional,intent(in),check(shape(u,2)==nz),depend(u) :: nz=shape(u,2) |
||||
end subroutine f_computeuvmet |
||||
subroutine f_computeomega(qvp,tmk,www,prs,omg,mx,my,mz) ! in :_wrfext:wrfext.f90 |
||||
real(kind=8) dimension(mx,my,mz),intent(in) :: qvp |
||||
real(kind=8) dimension(mx,my,mz),intent(in),depend(mx,my,mz) :: tmk |
||||
real(kind=8) dimension(mx,my,mz),intent(in),depend(mx,my,mz) :: www |
||||
real(kind=8) dimension(mx,my,mz),intent(in),depend(mx,my,mz) :: prs |
||||
real(kind=8) dimension(mx,my,mz),intent(out),depend(mx,my,mz) :: omg |
||||
integer, optional,intent(in),check(shape(qvp,0)==mx),depend(qvp) :: mx=shape(qvp,0) |
||||
integer, optional,intent(in),check(shape(qvp,1)==my),depend(qvp) :: my=shape(qvp,1) |
||||
integer, optional,intent(in),check(shape(qvp,2)==mz),depend(qvp) :: mz=shape(qvp,2) |
||||
end subroutine f_computeomega |
||||
subroutine f_computetv(temp,qv,tv,nx,ny,nz) ! in :_wrfext:wrfext.f90 |
||||
real(kind=8) dimension(nx,ny,nz),intent(in) :: temp |
||||
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: qv |
||||
real(kind=8) dimension(nx,ny,nz),intent(out),depend(nx,ny,nz) :: tv |
||||
integer, optional,intent(in),check(shape(temp,0)==nx),depend(temp) :: nx=shape(temp,0) |
||||
integer, optional,intent(in),check(shape(temp,1)==ny),depend(temp) :: ny=shape(temp,1) |
||||
integer, optional,intent(in),check(shape(temp,2)==nz),depend(temp) :: nz=shape(temp,2) |
||||
end subroutine f_computetv |
||||
subroutine f_computewetbulb(prs,tmk,qvp,psadithte,psadiprs,psaditmk,throw_exception,twb,nx,ny,nz) ! in :_wrfext:wrfext.f90 |
||||
use f_computewetbulb__user__routines |
||||
real(kind=8) dimension(nx,ny,nz),intent(in) :: prs |
||||
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: tmk |
||||
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: qvp |
||||
real(kind=8) dimension(150),intent(in) :: psadithte |
||||
real(kind=8) dimension(150),intent(in) :: psadiprs |
||||
real(kind=8) dimension(150,150),intent(in) :: psaditmk |
||||
external throw_exception |
||||
real(kind=8) dimension(nx,ny,nz),intent(out),depend(nx,ny,nz) :: twb |
||||
integer, optional,intent(in),check(shape(prs,0)==nx),depend(prs) :: nx=shape(prs,0) |
||||
integer, optional,intent(in),check(shape(prs,1)==ny),depend(prs) :: ny=shape(prs,1) |
||||
integer, optional,intent(in),check(shape(prs,2)==nz),depend(prs) :: nz=shape(prs,2) |
||||
end subroutine f_computewetbulb |
||||
subroutine f_computesrh(u,v,ght,ter,top,sreh,miy,mjx,mkzh) ! in :_wrfext:wrfext.f90 |
||||
real(kind=8) dimension(miy,mjx,mkzh),intent(in) :: u |
||||
real(kind=8) dimension(miy,mjx,mkzh),intent(in),depend(miy,mjx,mkzh) :: v |
||||
real(kind=8) dimension(miy,mjx,mkzh),intent(in),depend(miy,mjx,mkzh) :: ght |
||||
real(kind=8) dimension(miy,mjx),intent(in),depend(miy,mjx) :: ter |
||||
real(kind=8) intent(in) :: top |
||||
real(kind=8) dimension(miy,mjx),intent(out),depend(miy,mjx) :: sreh |
||||
integer, optional,intent(in),check(shape(u,0)==miy),depend(u) :: miy=shape(u,0) |
||||
integer, optional,intent(in),check(shape(u,1)==mjx),depend(u) :: mjx=shape(u,1) |
||||
integer, optional,intent(in),check(shape(u,2)==mkzh),depend(u) :: mkzh=shape(u,2) |
||||
end subroutine f_computesrh |
||||
subroutine f_computeuh(zp,mapfct,dx,dy,uhmnhgt,uhmxhgt,us,vs,w,tem1,tem2,uh,nx,ny,nz,nzp1) ! in :_wrfext:wrfext.f90 |
||||
real(kind=8) dimension(nx,ny,nzp1),intent(in) :: zp |
||||
real(kind=8) dimension(nx,ny),intent(in),depend(nx,ny) :: mapfct |
||||
real(kind=8) intent(in) :: dx |
||||
real(kind=8) intent(in) :: dy |
||||
real(kind=8) intent(in) :: uhmnhgt |
||||
real(kind=8) intent(in) :: uhmxhgt |
||||
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny) :: us |
||||
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: vs |
||||
real(kind=8) dimension(nx,ny,nzp1),intent(in),depend(nx,ny,nzp1) :: w |
||||
real(kind=8) dimension(nx,ny,nz),intent(inout),depend(nx,ny,nz) :: tem1 |
||||
real(kind=8) dimension(nx,ny,nz),intent(inout),depend(nx,ny,nz) :: tem2 |
||||
real(kind=8) dimension(nx,ny),intent(out),depend(nx,ny) :: uh |
||||
integer, optional,intent(in),check(shape(zp,0)==nx),depend(zp) :: nx=shape(zp,0) |
||||
integer, optional,intent(in),check(shape(zp,1)==ny),depend(zp) :: ny=shape(zp,1) |
||||
integer, optional,intent(in),check(shape(us,2)==nz),depend(us) :: nz=shape(us,2) |
||||
integer, optional,intent(in),check(shape(zp,2)==nzp1),depend(zp) :: nzp1=shape(zp,2) |
||||
end subroutine f_computeuh |
||||
subroutine f_computepw(p,tv,qv,ht,zdiff,pw,nx,ny,nz,nzh) ! in :_wrfext:wrfext.f90 |
||||
real(kind=8) dimension(nx,ny,nz),intent(in) :: p |
||||
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: tv |
||||
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: qv |
||||
real(kind=8) dimension(nx,ny,nzh),intent(in),depend(nx,ny) :: ht |
||||
real(kind=8) dimension(nx,ny),intent(inout),depend(nx,ny) :: zdiff |
||||
real(kind=8) dimension(nx,ny),intent(out),depend(nx,ny) :: pw |
||||
integer, optional,intent(in),check(shape(p,0)==nx),depend(p) :: nx=shape(p,0) |
||||
integer, optional,intent(in),check(shape(p,1)==ny),depend(p) :: ny=shape(p,1) |
||||
integer, optional,intent(in),check(shape(p,2)==nz),depend(p) :: nz=shape(p,2) |
||||
integer, optional,intent(in),check(shape(ht,2)==nzh),depend(ht) :: nzh=shape(ht,2) |
||||
end subroutine f_computepw |
||||
subroutine f_computedbz(prs,tmk,qvp,qra,qsn,qgr,sn0,ivarint,iliqskin,dbz,nx,ny,nz) ! in :_wrfext:wrfext.f90 |
||||
real(kind=8) dimension(nx,ny,nz),intent(in) :: prs |
||||
real(kind=8) dimension(nx,ny,nz),intent(in),depend(nx,ny,nz) :: tmk |
||||
real(kind=8) dimension(nx,ny,nz),intent(inout),depend(nx,ny,nz) :: qvp |
||||
real(kind=8) dimension(nx,ny,nz),intent(inout),depend(nx,ny,nz) :: qra |
||||
real(kind=8) dimension(nx,ny,nz),intent(inout),depend(nx,ny,nz) :: qsn |
||||
real(kind=8) dimension(nx,ny,nz),intent(inout),depend(nx,ny,nz) :: qgr |
||||
integer intent(in) :: sn0 |
||||
integer intent(in) :: ivarint |
||||
integer intent(in) :: iliqskin |
||||
real(kind=8) dimension(nx,ny,nz),intent(out),depend(nx,ny,nz) :: dbz |
||||
integer, optional,intent(in),check(shape(prs,0)==nx),depend(prs) :: nx=shape(prs,0) |
||||
integer, optional,intent(in),check(shape(prs,1)==ny),depend(prs) :: ny=shape(prs,1) |
||||
integer, optional,intent(in),check(shape(prs,2)==nz),depend(prs) :: nz=shape(prs,2) |
||||
end subroutine f_computedbz |
||||
subroutine rotatecoords(ilat,ilon,olat,olon,lat_np,lon_np,lon_0,direction) ! in :_wrfext:wrfext.f90 |
||||
real(kind=8) intent(in) :: ilat |
||||
real(kind=8) intent(in) :: ilon |
||||
real(kind=8) intent(out) :: olat |
||||
real(kind=8) intent(out) :: olon |
||||
real(kind=8) intent(in) :: lat_np |
||||
real(kind=8) intent(in) :: lon_np |
||||
real(kind=8) intent(in) :: lon_0 |
||||
integer intent(in) :: direction |
||||
end subroutine rotatecoords |
||||
subroutine f_lltoij(map_proj,truelat1,truelat2,stdlon,lat1,lon1,pole_lat,pole_lon,knowni,knownj,dx,latinc,loninc,lat,lon,throw_exception,loc) ! in :_wrfext:wrfext.f90 |
||||
use f_lltoij__user__routines |
||||
integer intent(in) :: map_proj |
||||
real(kind=8) intent(inout) :: truelat1 |
||||
real(kind=8) intent(inout) :: truelat2 |
||||
real(kind=8) intent(in) :: stdlon |
||||
real(kind=8) intent(in) :: lat1 |
||||
real(kind=8) intent(in) :: lon1 |
||||
real(kind=8) intent(in) :: pole_lat |
||||
real(kind=8) intent(in) :: pole_lon |
||||
real(kind=8) intent(in) :: knowni |
||||
real(kind=8) intent(in) :: knownj |
||||
real(kind=8) intent(in) :: dx |
||||
real(kind=8) intent(in) :: latinc |
||||
real(kind=8) intent(in) :: loninc |
||||
real(kind=8) intent(inout) :: lat |
||||
real(kind=8) intent(inout) :: lon |
||||
external throw_exception |
||||
real(kind=8) dimension(2),intent(out) :: loc |
||||
end subroutine f_lltoij |
||||
subroutine f_ijtoll(map_proj,truelat1,truelat2,stdlon,lat1,lon1,pole_lat,pole_lon,knowni,knownj,dx,latinc,loninc,ai,aj,throw_exception,loc) ! in :_wrfext:wrfext.f90 |
||||
use f_ijtoll__user__routines |
||||
integer intent(in) :: map_proj |
||||
real(kind=8) intent(inout) :: truelat1 |
||||
real(kind=8) intent(inout) :: truelat2 |
||||
real(kind=8) intent(in) :: stdlon |
||||
real(kind=8) intent(in) :: lat1 |
||||
real(kind=8) intent(in) :: lon1 |
||||
real(kind=8) intent(in) :: pole_lat |
||||
real(kind=8) intent(in) :: pole_lon |
||||
real(kind=8) intent(in) :: knowni |
||||
real(kind=8) intent(in) :: knownj |
||||
real(kind=8) intent(in) :: dx |
||||
real(kind=8) intent(in) :: latinc |
||||
real(kind=8) intent(in) :: loninc |
||||
real(kind=8) intent(in) :: ai |
||||
real(kind=8) intent(in) :: aj |
||||
external throw_exception |
||||
real(kind=8) dimension(2),intent(out) :: loc |
||||
end subroutine f_ijtoll |
||||
subroutine f_converteta(full_t,znu,psfc,ptop,pcalc,mean_t,temp_t,z,nx,ny,nz) ! in :_wrfext:wrfext.f90 |
||||
real(kind=8) dimension(nx,ny,nz),intent(in) :: full_t |
||||
real(kind=8) dimension(nz),intent(in),depend(nz) :: znu |
||||
real(kind=8) dimension(nx,ny),intent(in),depend(nx,ny) :: psfc |
||||
real(kind=8) intent(in) :: ptop |
||||
real(kind=8) dimension(nx,ny,nz),intent(inout),depend(nx,ny,nz) :: pcalc |
||||
real(kind=8) dimension(nx,ny,nz),intent(inout),depend(nx,ny,nz) :: mean_t |
||||
real(kind=8) dimension(nx,ny,nz),intent(inout),depend(nx,ny,nz) :: temp_t |
||||
real(kind=8) dimension(nx,ny,nz),intent(out),depend(nx,ny,nz) :: z |
||||
integer, optional,intent(in),check(shape(full_t,0)==nx),depend(full_t) :: nx=shape(full_t,0) |
||||
integer, optional,intent(in),check(shape(full_t,1)==ny),depend(full_t) :: ny=shape(full_t,1) |
||||
integer, optional,intent(in),check(shape(full_t,2)==nz),depend(full_t) :: nz=shape(full_t,2) |
||||
end subroutine f_converteta |
||||
subroutine f_computectt(prs,tk,qci,qcw,qvp,ght,ter,haveqci,ctt,ew,ns,nz) ! in :_wrfext:wrfext.f90 |
||||
real(kind=8) dimension(ew,ns,nz),intent(in) :: prs |
||||
real(kind=8) dimension(ew,ns,nz),intent(in),depend(ew,ns,nz) :: tk |
||||
real(kind=8) dimension(ew,ns,nz),intent(in),depend(ew,ns,nz) :: qci |
||||
real(kind=8) dimension(ew,ns,nz),intent(in),depend(ew,ns,nz) :: qcw |
||||
real(kind=8) dimension(ew,ns,nz),intent(in),depend(ew,ns,nz) :: qvp |
||||
real(kind=8) dimension(ew,ns,nz),intent(in),depend(ew,ns,nz) :: ght |
||||
real(kind=8) dimension(ew,ns),intent(in),depend(ew,ns) :: ter |
||||
integer intent(in) :: haveqci |
||||
real(kind=8) dimension(ew,ns),intent(out),depend(ew,ns) :: ctt |
||||
integer, optional,intent(in),check(shape(prs,0)==ew),depend(prs) :: ew=shape(prs,0) |
||||
integer, optional,intent(in),check(shape(prs,1)==ns),depend(prs) :: ns=shape(prs,1) |
||||
integer, optional,intent(in),check(shape(prs,2)==nz),depend(prs) :: nz=shape(prs,2) |
||||
end subroutine f_computectt |
||||
end interface |
||||
end python module _wrfext |
||||
|
||||
! This file was auto-generated with f2py (version:2). |
||||
! See http://cens.ioc.ee/projects/f2py2e/ |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
l = NewList("fifo") |
||||
name = "foo" |
||||
ListAppend(l, (/name/)) |
||||
print(l) |
||||
print(l[0]) |
||||
name = "bar" |
@ -0,0 +1,136 @@
@@ -0,0 +1,136 @@
|
||||
load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" |
||||
load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" |
||||
load "$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl" |
||||
|
||||
;system("printenv") |
||||
|
||||
if (.not. isvar("in_file")) then |
||||
in_file = "/Users/ladwig/Documents/wrf_files/wrfout_d02_2010-06-13_21:00:00.nc" |
||||
end if |
||||
|
||||
if (.not. isvar("out_file")) then |
||||
out_file = "/tmp/wrftest.nc" |
||||
end if |
||||
input_file = addfile(in_file,"r") |
||||
|
||||
system("/bin/rm -f " + out_file) ; remove if exists |
||||
fout = addfile(out_file, "c") |
||||
|
||||
time = 0 |
||||
|
||||
wrf_vars = [/"avo", "eth", "cape_2d", "cape_3d", "ctt", "dbz", "mdbz", \ |
||||
"geopt", "helicity", "lat", "lon", "omg", "p", "pressure", \ |
||||
"pvo", "pw", "rh2", "rh", "slp", "ter", "td2", "td", "tc", \ |
||||
"theta", "tk", "tv", "twb", "updraft_helicity", "ua", "va", \ |
||||
"wa", "uvmet10", "uvmet", "z"/] |
||||
|
||||
unique_dimname_list = NewList("fifo") |
||||
unique_dimsize_list = NewList("fifo") |
||||
full_vardimname_list = NewList("fifo") ; Workaround for issue where NCL |
||||
; is dropping the dim names from |
||||
; the array stored in a list |
||||
vardata_list = NewList("fifo") |
||||
|
||||
; NCL lists need unique variable names to be inserted, so using these |
||||
; variables to create unique named attributes |
||||
vardata = True |
||||
vardimnamedata = True |
||||
|
||||
; Note: The list type seems to only work correctly when inserting |
||||
; variables with unique names. This is the reason for all of the |
||||
; name attribute stuff below. |
||||
do i = 0, ListCount(wrf_vars) - 1 |
||||
|
||||
print("working on: " + wrf_vars[i]) |
||||
v := wrf_user_getvar(input_file, wrf_vars[i], time) |
||||
|
||||
;if (wrf_vars[i] .eq. "avo") then |
||||
; print(v) |
||||
;end if |
||||
|
||||
; pw is written in pure NCL and does not contain dimension names |
||||
; so manually creating the dimension names here |
||||
if (wrf_vars[i] .eq. "pw") then |
||||
dim_names := (/"south_north", "west_east"/) |
||||
dim_sizes := dimsizes(v) |
||||
else |
||||
dim_names := getvardims(v) |
||||
dim_sizes := dimsizes(v) |
||||
end if |
||||
|
||||
vardata@$wrf_vars[i]$ := v |
||||
vardimnamedata@$wrf_vars[i]$ := dim_names |
||||
ListAppend(vardata_list,vardata@$wrf_vars[i]$) |
||||
ListAppend(full_vardimname_list, vardimnamedata@$wrf_vars[i]$) |
||||
;print(vardata_list) |
||||
|
||||
dimname=True |
||||
dimsize=True |
||||
|
||||
; Determine the unique dimensions names, which will be used when |
||||
; creating the output NetCDF file |
||||
do j=0, dimsizes(dim_sizes)-1 |
||||
;print(dim_names) |
||||
;print(dim_names(j)) |
||||
|
||||
name_id = sprintf("dimname_%i",i*j) |
||||
size_id = sprintf("dimsize_%i",i*j) |
||||
|
||||
dimname@$name_id$ = dim_names(j) |
||||
dimsize@$size_id$ = dim_sizes(j) |
||||
|
||||
has_name = False |
||||
do k=0, ListCount(unique_dimname_list)-1 |
||||
if ((/unique_dimname_list[k]/) .eq. (/dimname@$name_id$/)) then |
||||
has_name = True |
||||
end if |
||||
end do |
||||
|
||||
if (.not. has_name) then |
||||
;print("inserting: " + dimname@$name_id$) |
||||
ListAppend(unique_dimname_list, dimname@$name_id$) |
||||
ListAppend(unique_dimsize_list, dimsize@$size_id$) |
||||
end if |
||||
|
||||
end do |
||||
end do |
||||
|
||||
setfileoption(fout,"DefineMode",True) |
||||
|
||||
; Set global attributes |
||||
f_att = True ; assign file attributes |
||||
f_att@title = "NCL generated netCDF file" |
||||
f_att@Conventions = "None" |
||||
fileattdef(fout, f_att) ; copy file attributes |
||||
|
||||
; Set up the NetCDF dimensions |
||||
d_names = new(ListCount(unique_dimname_list), string) |
||||
d_sizes = new(ListCount(unique_dimname_list), integer) |
||||
d_unlim = new(ListCount(unique_dimname_list), logical) |
||||
|
||||
; Note: Need to do this copy since NCL can't coerce the list data to |
||||
; array data |
||||
do i=0, ListCount(unique_dimname_list) - 1 |
||||
d_names(i) = unique_dimname_list[i] |
||||
d_sizes(i) = unique_dimsize_list[i] |
||||
d_unlim(i) = False |
||||
end do |
||||
|
||||
filedimdef(fout, d_names, d_sizes, d_unlim) |
||||
|
||||
; Save the variables to the NetCDF file |
||||
do i=0, ListCount(vardata_list)-1 |
||||
d := vardata_list[i] |
||||
filevardef(fout, wrf_vars[i], typeof(d), full_vardimname_list[i]) |
||||
filevarattdef(fout,wrf_vars[i], d) |
||||
fout->$wrf_vars[i]$ = (/d/) |
||||
end do |
||||
|
||||
delete(fout) |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,152 @@
@@ -0,0 +1,152 @@
|
||||
import unittest as ut |
||||
import numpy.testing as nt |
||||
import numpy as n |
||||
import os, sys |
||||
import subprocess |
||||
|
||||
import Ngl, Nio |
||||
from wrf.var import getvar |
||||
|
||||
# This should work with Nio |
||||
from netCDF4 import Dataset as NetCDF |
||||
from boto.ec2.instancestatus import Status |
||||
|
||||
NCL_EXE = "/Users/ladwig/nclbuild/6.3.0/bin/ncl" |
||||
TEST_FILE = "/Users/ladwig/Documents/wrf_files/wrfout_d01_2010-06-13_21:00:00" |
||||
OUT_NC_FILE = "/tmp/wrftest.nc" |
||||
|
||||
def setUpModule(): |
||||
ncarg_root = os.environ.get("NCARG_ROOT", None) |
||||
if ncarg_root is None: |
||||
raise RuntimeError("$NCARG_ROOT environment variable not set") |
||||
|
||||
|
||||
this_path = os.path.realpath(__file__) |
||||
ncl_script = os.path.join(os.path.dirname(this_path), |
||||
"ncl_get_var.ncl") |
||||
ncfile = TEST_FILE + ".nc" # NCL requires extension |
||||
|
||||
# This needs to be set when PyNIO is installed, since PyNIOs data does |
||||
# not contain the dat file for the CAPE calcluations |
||||
os.environ["NCARG_NCARG"] = os.path.join(os.environ["NCARG_ROOT"], |
||||
"lib", "ncarg") |
||||
cmd = "%s %s 'in_file=\"%s\"' 'out_file=\"%s\"'" % (NCL_EXE, |
||||
ncl_script, |
||||
ncfile, |
||||
OUT_NC_FILE) |
||||
|
||||
#print cmd |
||||
|
||||
if not os.path.exists(OUT_NC_FILE): |
||||
status = subprocess.call(cmd, shell=True) |
||||
if (status != 0): |
||||
raise RuntimeError("NCL script failed. Could not set up test.") |
||||
|
||||
# Using helpful information at: |
||||
# http://eli.thegreenplace.net/2014/04/02/dynamically-generating-python-test-cases |
||||
def make_test(varname, wrf_in, referent): |
||||
def test(self): |
||||
in_wrfnc = NetCDF(wrf_in) |
||||
refnc = NetCDF(referent) |
||||
|
||||
ref_vals = refnc.variables[varname][...] |
||||
|
||||
if (varname == "tc"): |
||||
my_vals = getvar(in_wrfnc, "temp", units="c") |
||||
tol = 0 |
||||
atol = .1 |
||||
nt.assert_allclose(my_vals, ref_vals, tol, atol) |
||||
elif (varname == "tk"): |
||||
my_vals = getvar(in_wrfnc, "temp", units="k") |
||||
tol = 0 |
||||
atol = .1 |
||||
nt.assert_allclose(my_vals, ref_vals, tol, atol) |
||||
elif (varname == "td"): |
||||
my_vals = getvar(in_wrfnc, "td", units="c") |
||||
tol = 0 |
||||
atol = .1 |
||||
nt.assert_allclose(my_vals, ref_vals, tol, atol) |
||||
elif (varname == "pressure"): |
||||
my_vals = getvar(in_wrfnc, varname, units="hpa") |
||||
tol = 1/100. |
||||
atol = 0 |
||||
nt.assert_allclose(my_vals, ref_vals, tol, atol) |
||||
elif (varname == "p"): |
||||
my_vals = getvar(in_wrfnc, varname, units="pa") |
||||
tol = 1/100. |
||||
atol = 0 |
||||
nt.assert_allclose(my_vals, ref_vals, tol, atol) |
||||
elif (varname == "slp"): |
||||
my_vals = getvar(in_wrfnc, varname, units="hpa") |
||||
tol = 2/100. |
||||
atol = 0 |
||||
nt.assert_allclose(my_vals, ref_vals, tol, atol) |
||||
|
||||
elif (varname == "uvmet"): |
||||
my_vals = getvar(in_wrfnc, varname) |
||||
tol = 1/100. |
||||
atol = .5 |
||||
nt.assert_allclose(my_vals, ref_vals, tol, atol) |
||||
elif (varname == "uvmet10"): |
||||
my_vals = getvar(in_wrfnc, varname) |
||||
tol = 1/100. |
||||
atol = .5 |
||||
nt.assert_allclose(my_vals, ref_vals, tol, atol) |
||||
|
||||
elif (varname == "omg"): |
||||
my_vals = getvar(in_wrfnc, varname) |
||||
tol = 2/100. |
||||
atol = 0 |
||||
nt.assert_allclose(my_vals, ref_vals, tol, atol) |
||||
elif (varname == "ctt"): |
||||
my_vals = getvar(in_wrfnc, varname) |
||||
tol = 1/100. |
||||
atol = 0 |
||||
nt.assert_allclose(my_vals, ref_vals, tol, atol) |
||||
elif (varname == "cape_2d"): |
||||
mcape, mcin, lcl, lfc = getvar(in_wrfnc, varname) |
||||
tol = 1/100. |
||||
atol = 0 |
||||
nt.assert_allclose(mcape, ref_vals[0,:,:], tol, atol) |
||||
nt.assert_allclose(mcin, ref_vals[1,:,:], tol, atol) |
||||
nt.assert_allclose(lcl, ref_vals[2,:,:], tol, atol) |
||||
nt.assert_allclose(lfc, ref_vals[3,:,:], tol, atol) |
||||
elif (varname == "cape_3d"): |
||||
cape, cin = getvar(in_wrfnc, varname) |
||||
tol = 1/100. |
||||
atol = 0 |
||||
nt.assert_allclose(cape, ref_vals[0,:,:], tol, atol) |
||||
nt.assert_allclose(cin, ref_vals[1,:,:], tol, atol) |
||||
|
||||
|
||||
else: |
||||
my_vals = getvar(in_wrfnc, varname) |
||||
tol = 1/100. |
||||
atol = 0 |
||||
nt.assert_allclose(my_vals, ref_vals, tol, atol) |
||||
|
||||
|
||||
return test |
||||
|
||||
class WRFVarsTest(ut.TestCase): |
||||
longMessage = True |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
ignore_vars = [] # Not testable yet |
||||
wrf_vars = ["avo", "eth", "cape_2d", "cape_3d", "ctt", "dbz", "mdbz", |
||||
"geopt", "helicity", "lat", "lon", "omg", "p", "pressure", |
||||
"pvo", "pw", "rh2", "rh", "slp", "ter", "td2", "td", "tc", |
||||
"theta", "tk", "tv", "twb", "updraft_helicity", "ua", "va", |
||||
"wa", "uvmet10", "uvmet", "z", "ctt", "cape_2d", "cape_3d"] |
||||
|
||||
for var in wrf_vars: |
||||
if var in ignore_vars: |
||||
continue |
||||
|
||||
test_func = make_test(var, TEST_FILE, OUT_NC_FILE) |
||||
setattr(WRFVarsTest, 'test_{0}'.format(var), test_func) |
||||
|
||||
|
||||
ut.main() |
||||
|
Loading…
Reference in new issue