forked from 3rdparty/wrf-python
28 changed files with 0 additions and 33110 deletions
@ -1,293 +0,0 @@
@@ -1,293 +0,0 @@
|
||||
;************************************************************************* |
||||
; 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 |
@ -1,158 +0,0 @@
@@ -1,158 +0,0 @@
|
||||
! 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 |
@ -1,60 +0,0 @@
@@ -1,60 +0,0 @@
|
||||
C NCLFORTSTART |
||||
subroutine cloud_frac(pres,rh,lowc,midc,highc,nz,ns,ew) |
||||
|
||||
implicit none |
||||
integer nz,ns,ew |
||||
real pres(ew,ns,nz),rh(ew,ns,nz) |
||||
real lowc(ew,ns),midc(ew,ns),highc(ew,ns) |
||||
C NCLEND |
||||
|
||||
integer i,j,k |
||||
integer kchi,kcmi,kclo |
||||
|
||||
|
||||
DO j = 1,ns |
||||
DO i = 1,ew |
||||
DO k = 1,nz-1 |
||||
|
||||
c if((pres(i,j,k) .ge. 45000. ) .and. |
||||
c & (pres(i,j,k) .lt. 80000.)) then |
||||
c kchi = k |
||||
|
||||
c else if((pres(i,j,k) .ge. 80000.) .and. |
||||
c & (pres(i,j,k) .lt. 97000.)) then |
||||
c kcmi = k |
||||
|
||||
c else if (pres(i,j,k) .ge. 97000.) then |
||||
c kclo = k |
||||
c end if |
||||
IF ( pres(i,j,k) .gt. 97000. ) kclo=k |
||||
IF ( pres(i,j,k) .gt. 80000. ) kcmi=k |
||||
IF ( pres(i,j,k) .gt. 45000. ) kchi=k |
||||
|
||||
end do |
||||
|
||||
DO k = 1,nz-1 |
||||
IF ( k .ge. kclo .AND. k .lt. kcmi ) then |
||||
lowc(i,j) = AMAX1(rh(i,j,k),lowc(i,j)) |
||||
else IF ( k .ge. kcmi .AND. k .lt. kchi ) then !! mid cloud |
||||
midc(i,j) = AMAX1(rh(i,j,k),midc(i,j)) |
||||
else if ( k .ge. kchi ) then !! high cloud |
||||
highc(i,j) = AMAX1(rh(i,j,k),highc(i,j)) |
||||
end if |
||||
END DO |
||||
|
||||
|
||||
lowc(i,j) = 4.0 * lowc(i,j)/100.-3.0 |
||||
midc(i,j) = 4.0 * midc(i,j)/100.-3.0 |
||||
highc(i,j) = 2.5 * highc(i,j)/100.-1.5 |
||||
|
||||
lowc(i,j) = amin1(lowc(i,j),1.0) |
||||
lowc(i,j) = amax1(lowc(i,j),0.0) |
||||
midc(i,j) = amin1(midc(i,j),1.0) |
||||
midc(i,j) = amax1(midc(i,j),0.0) |
||||
highc(i,j) = amin1(highc(i,j),1.0) |
||||
highc(i,j) = amax1(highc(i,j),0.0) |
||||
|
||||
END DO |
||||
END DO |
||||
return |
||||
end |
@ -1,72 +0,0 @@
@@ -1,72 +0,0 @@
|
||||
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 |
@ -1,82 +0,0 @@
@@ -1,82 +0,0 @@
|
||||
import numpy as n |
||||
|
||||
from wrf.var.extension import computeeta |
||||
from wrf.var.constants import Constants |
||||
from wrf.var.decorators import convert_units |
||||
from wrf.var.util import extract_vars |
||||
|
||||
#__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) |
||||
|
||||
|
@ -1,183 +0,0 @@
@@ -1,183 +0,0 @@
|
||||
''' |
||||
Created on Jan 16, 2014 |
||||
|
||||
@author: sean |
||||
''' |
||||
from __future__ import absolute_import, division, print_function |
||||
|
||||
from functools import partial |
||||
import json |
||||
import logging |
||||
import os |
||||
import sys |
||||
|
||||
import jinja2 |
||||
|
||||
from .conda_interface import PY3 |
||||
from .environ import get_dict as get_environ |
||||
from .metadata import select_lines, ns_cfg |
||||
from .source import WORK_DIR |
||||
|
||||
log = logging.getLogger(__file__) |
||||
|
||||
|
||||
class UndefinedNeverFail(jinja2.Undefined): |
||||
""" |
||||
A class for Undefined jinja variables. |
||||
This is even less strict than the default jinja2.Undefined class, |
||||
because it permits things like {{ MY_UNDEFINED_VAR[:2] }} and |
||||
{{ MY_UNDEFINED_VAR|int }}. This can mask lots of errors in jinja templates, so it |
||||
should only be used for a first-pass parse, when you plan on running a 'strict' |
||||
second pass later. |
||||
""" |
||||
all_undefined_names = [] |
||||
|
||||
def __init__(self, hint=None, obj=jinja2.runtime.missing, name=None, |
||||
exc=jinja2.exceptions.UndefinedError): |
||||
UndefinedNeverFail.all_undefined_names.append(name) |
||||
jinja2.Undefined.__init__(self, hint, obj, name, exc) |
||||
|
||||
__add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \ |
||||
__truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \ |
||||
__mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \ |
||||
__getitem__ = __lt__ = __le__ = __gt__ = __ge__ = \ |
||||
__complex__ = __pow__ = __rpow__ = \ |
||||
lambda self, *args, **kwargs: UndefinedNeverFail(hint=self._undefined_hint, |
||||
obj=self._undefined_obj, |
||||
name=self._undefined_name, |
||||
exc=self._undefined_exception) |
||||
|
||||
__str__ = __repr__ = \ |
||||
lambda *args, **kwargs: u'' |
||||
|
||||
__int__ = lambda _: 0 |
||||
__float__ = lambda _: 0.0 |
||||
|
||||
def __getattr__(self, k): |
||||
try: |
||||
return object.__getattr__(self, k) |
||||
except AttributeError: |
||||
return UndefinedNeverFail(hint=self._undefined_hint, |
||||
obj=self._undefined_obj, |
||||
name=self._undefined_name + '.' + k, |
||||
exc=self._undefined_exception) |
||||
|
||||
|
||||
class FilteredLoader(jinja2.BaseLoader): |
||||
""" |
||||
A pass-through for the given loader, except that the loaded source is |
||||
filtered according to any metadata selectors in the source text. |
||||
""" |
||||
|
||||
def __init__(self, unfiltered_loader): |
||||
self._unfiltered_loader = unfiltered_loader |
||||
self.list_templates = unfiltered_loader.list_templates |
||||
|
||||
def get_source(self, environment, template): |
||||
contents, filename, uptodate = self._unfiltered_loader.get_source(environment, |
||||
template) |
||||
return select_lines(contents, ns_cfg()), filename, uptodate |
||||
|
||||
|
||||
def load_setup_py_data(setup_file='setup.py', from_recipe_dir=False, recipe_dir=None, |
||||
unload_modules=None, fail_on_error=False): |
||||
|
||||
_setuptools_data = {} |
||||
|
||||
def setup(**kw): |
||||
_setuptools_data.update(kw) |
||||
|
||||
import setuptools |
||||
import distutils.core |
||||
|
||||
try: |
||||
import numpy.distutils.core |
||||
except ImportError: |
||||
do_numpy = False |
||||
else: |
||||
do_numpy = True |
||||
|
||||
cd_to_work = False |
||||
|
||||
if from_recipe_dir and recipe_dir: |
||||
setup_file = os.path.abspath(os.path.join(recipe_dir, setup_file)) |
||||
elif os.path.exists(WORK_DIR): |
||||
cd_to_work = True |
||||
cwd = os.getcwd() |
||||
os.chdir(WORK_DIR) |
||||
if not os.path.isabs(setup_file): |
||||
setup_file = os.path.join(WORK_DIR, setup_file) |
||||
# this is very important - or else if versioneer or otherwise is in the start folder, |
||||
# things will pick up the wrong versioneer/whatever! |
||||
sys.path.insert(0, WORK_DIR) |
||||
else: |
||||
log.debug("Did not find setup.py file in manually specified location, and source " |
||||
"not downloaded yet.") |
||||
return {} |
||||
|
||||
# Patch setuptools, distutils |
||||
setuptools_setup = setuptools.setup |
||||
distutils_setup = distutils.core.setup |
||||
setuptools.setup = distutils.core.setup = setup |
||||
|
||||
if do_numpy: |
||||
numpy_setup = numpy.distutils.core.setup |
||||
numpy.distutils.core.setup = setup |
||||
|
||||
ns = { |
||||
'__name__': '__main__', |
||||
'__doc__': None, |
||||
'__file__': setup_file, |
||||
} |
||||
try: |
||||
code = compile(open(setup_file).read(), setup_file, 'exec', dont_inherit=1) |
||||
exec(code, ns, ns) |
||||
distutils.core.setup = distutils_setup |
||||
setuptools.setup = setuptools_setup |
||||
if do_numpy: |
||||
numpy.distutils.core.setup = numpy_setup |
||||
# this happens if setup.py is used in load_setup_py_data, but source is not yet downloaded |
||||
except: |
||||
raise |
||||
finally: |
||||
if cd_to_work: |
||||
os.chdir(cwd) |
||||
del sys.path[0] |
||||
|
||||
return _setuptools_data |
||||
|
||||
|
||||
def load_setuptools(setup_file='setup.py', from_recipe_dir=False, recipe_dir=None, |
||||
unload_modules=None, fail_on_error=False): |
||||
log.warn("Deprecation notice: the load_setuptools function has been renamed to " |
||||
"load_setup_py_data. load_setuptools will be removed in a future release.") |
||||
return load_setup_py_data(setup_file=setup_file, from_recipe_dir=from_recipe_dir, |
||||
recipe_dir=recipe_dir, unload_modules=unload_modules, |
||||
fail_on_error=fail_on_error) |
||||
|
||||
|
||||
def load_npm(): |
||||
# json module expects bytes in Python 2 and str in Python 3. |
||||
mode_dict = {'mode': 'r', 'encoding': 'utf-8'} if PY3 else {'mode': 'rb'} |
||||
with open('package.json', **mode_dict) as pkg: |
||||
return json.load(pkg) |
||||
|
||||
|
||||
def context_processor(initial_metadata, recipe_dir): |
||||
""" |
||||
Return a dictionary to use as context for jinja templates. |
||||
|
||||
initial_metadata: Augment the context with values from this MetaData object. |
||||
Used to bootstrap metadata contents via multiple parsing passes. |
||||
""" |
||||
ctx = get_environ(m=initial_metadata) |
||||
environ = dict(os.environ) |
||||
environ.update(get_environ(m=initial_metadata)) |
||||
|
||||
ctx.update( |
||||
load_setup_py_data=partial(load_setup_py_data, recipe_dir=recipe_dir), |
||||
# maintain old alias for backwards compatibility: |
||||
load_setuptools=partial(load_setuptools, recipe_dir=recipe_dir), |
||||
load_npm=load_npm, |
||||
environ=environ) |
||||
return ctx |
@ -1,170 +0,0 @@
@@ -1,170 +0,0 @@
|
||||
!WRF:MODEL_LAYER:CONSTANTS |
||||
! |
||||
|
||||
MODULE module_model_constants |
||||
|
||||
! 2. Following are constants for use in defining real number bounds. |
||||
|
||||
! A really small number. |
||||
|
||||
REAL , PARAMETER :: epsilon = 1.E-15 |
||||
|
||||
! 4. Following is information related to the physical constants. |
||||
|
||||
! These are the physical constants used within the model. |
||||
|
||||
! JM NOTE -- can we name this grav instead? |
||||
REAL , PARAMETER :: g = 9.81 ! acceleration due to gravity (m {s}^-2) |
||||
|
||||
#if ( NMM_CORE == 1 ) |
||||
REAL , PARAMETER :: r_d = 287.04 |
||||
REAL , PARAMETER :: cp = 1004.6 |
||||
#else |
||||
REAL , PARAMETER :: r_d = 287. |
||||
REAL , PARAMETER :: cp = 7.*r_d/2. |
||||
#endif |
||||
|
||||
REAL , PARAMETER :: r_v = 461.6 |
||||
REAL , PARAMETER :: cv = cp-r_d |
||||
REAL , PARAMETER :: cpv = 4.*r_v |
||||
REAL , PARAMETER :: cvv = cpv-r_v |
||||
REAL , PARAMETER :: cvpm = -cv/cp |
||||
REAL , PARAMETER :: cliq = 4190. |
||||
REAL , PARAMETER :: cice = 2106. |
||||
REAL , PARAMETER :: psat = 610.78 |
||||
REAL , PARAMETER :: rcv = r_d/cv |
||||
REAL , PARAMETER :: rcp = r_d/cp |
||||
REAL , PARAMETER :: rovg = r_d/g |
||||
REAL , PARAMETER :: c2 = cp * rcv |
||||
real , parameter :: mwdry = 28.966 ! molecular weight of dry air (g/mole) |
||||
|
||||
REAL , PARAMETER :: p1000mb = 100000. |
||||
REAL , PARAMETER :: t0 = 300. |
||||
REAL , PARAMETER :: p0 = p1000mb |
||||
REAL , PARAMETER :: cpovcv = cp/(cp-r_d) |
||||
REAL , PARAMETER :: cvovcp = 1./cpovcv |
||||
REAL , PARAMETER :: rvovrd = r_v/r_d |
||||
|
||||
REAL , PARAMETER :: reradius = 1./6370.0e03 |
||||
|
||||
REAL , PARAMETER :: asselin = .025 |
||||
! REAL , PARAMETER :: asselin = .0 |
||||
REAL , PARAMETER :: cb = 25. |
||||
|
||||
REAL , PARAMETER :: XLV0 = 3.15E6 |
||||
REAL , PARAMETER :: XLV1 = 2370. |
||||
REAL , PARAMETER :: XLS0 = 2.905E6 |
||||
REAL , PARAMETER :: XLS1 = 259.532 |
||||
|
||||
REAL , PARAMETER :: XLS = 2.85E6 |
||||
REAL , PARAMETER :: XLV = 2.5E6 |
||||
REAL , PARAMETER :: XLF = 3.50E5 |
||||
|
||||
REAL , PARAMETER :: rhowater = 1000. |
||||
REAL , PARAMETER :: rhosnow = 100. |
||||
REAL , PARAMETER :: rhoair0 = 1.28 |
||||
! |
||||
! Now namelist-specified parameter: ccn_conc - RAS |
||||
! REAL , PARAMETER :: n_ccn0 = 1.0E8 |
||||
! |
||||
REAL , PARAMETER :: piconst = 3.1415926535897932384626433 |
||||
REAL , PARAMETER :: DEGRAD = piconst/180. |
||||
REAL , PARAMETER :: DPD = 360./365. |
||||
|
||||
REAL , PARAMETER :: SVP1=0.6112 |
||||
REAL , PARAMETER :: SVP2=17.67 |
||||
REAL , PARAMETER :: SVP3=29.65 |
||||
REAL , PARAMETER :: SVPT0=273.15 |
||||
REAL , PARAMETER :: EP_1=R_v/R_d-1. |
||||
REAL , PARAMETER :: EP_2=R_d/R_v |
||||
REAL , PARAMETER :: KARMAN=0.4 |
||||
REAL , PARAMETER :: EOMEG=7.2921E-5 |
||||
REAL , PARAMETER :: STBOLT=5.67051E-8 |
||||
|
||||
REAL , PARAMETER :: prandtl = 1./3.0 |
||||
! constants for w-damping option |
||||
REAL , PARAMETER :: w_alpha = 0.3 ! strength m/s/s |
||||
REAL , PARAMETER :: w_beta = 1.0 ! activation cfl number |
||||
|
||||
REAL , PARAMETER :: pq0=379.90516 |
||||
REAL , PARAMETER :: epsq2=0.2 |
||||
REAL , PARAMETER :: a2=17.2693882 |
||||
REAL , PARAMETER :: a3=273.16 |
||||
REAL , PARAMETER :: a4=35.86 |
||||
REAL , PARAMETER :: epsq=1.e-12 |
||||
REAL , PARAMETER :: p608=rvovrd-1. |
||||
!#if ( NMM_CORE == 1 ) |
||||
REAL , PARAMETER :: climit=1.e-20 |
||||
REAL , PARAMETER :: cm1=2937.4 |
||||
REAL , PARAMETER :: cm2=4.9283 |
||||
REAL , PARAMETER :: cm3=23.5518 |
||||
! REAL , PARAMETER :: defc=8.0 |
||||
! REAL , PARAMETER :: defm=32.0 |
||||
REAL , PARAMETER :: defc=0.0 |
||||
REAL , PARAMETER :: defm=99999.0 |
||||
REAL , PARAMETER :: epsfc=1./1.05 |
||||
REAL , PARAMETER :: epswet=0.0 |
||||
REAL , PARAMETER :: fcdif=1./3. |
||||
#if ( HWRF == 1 ) |
||||
REAL , PARAMETER :: fcm=0.0 |
||||
#else |
||||
REAL , PARAMETER :: fcm=0.00003 |
||||
#endif |
||||
REAL , PARAMETER :: gma=-r_d*(1.-rcp)*0.5 |
||||
REAL , PARAMETER :: p400=40000.0 |
||||
REAL , PARAMETER :: phitp=15000.0 |
||||
REAL , PARAMETER :: pi2=2.*3.1415926, pi1=3.1415926 |
||||
REAL , PARAMETER :: plbtm=105000.0 |
||||
REAL , PARAMETER :: plomd=64200.0 |
||||
REAL , PARAMETER :: pmdhi=35000.0 |
||||
REAL , PARAMETER :: q2ini=0.50 |
||||
REAL , PARAMETER :: rfcp=0.25/cp |
||||
REAL , PARAMETER :: rhcrit_land=0.75 |
||||
REAL , PARAMETER :: rhcrit_sea=0.80 |
||||
REAL , PARAMETER :: rlag=14.8125 |
||||
REAL , PARAMETER :: rlx=0.90 |
||||
REAL , PARAMETER :: scq2=50.0 |
||||
REAL , PARAMETER :: slopht=0.001 |
||||
REAL , PARAMETER :: tlc=2.*0.703972477 |
||||
REAL , PARAMETER :: wa=0.15 |
||||
REAL , PARAMETER :: wght=0.35 |
||||
REAL , PARAMETER :: wpc=0.075 |
||||
REAL , PARAMETER :: z0land=0.10 |
||||
#if ( HWRF == 1 ) |
||||
REAL , PARAMETER :: z0max=0.01 |
||||
#else |
||||
REAL , PARAMETER :: z0max=0.008 |
||||
#endif |
||||
REAL , PARAMETER :: z0sea=0.001 |
||||
!#endif |
||||
|
||||
|
||||
! Earth |
||||
|
||||
! The value for P2SI *must* be set to 1.0 for Earth |
||||
! Although, now we may not need this declaration here (see above) |
||||
!REAL , PARAMETER :: P2SI = 1.0 |
||||
|
||||
! Orbital constants: |
||||
|
||||
INTEGER , PARAMETER :: PLANET_YEAR = 365 |
||||
REAL , PARAMETER :: OBLIQUITY = 23.5 |
||||
REAL , PARAMETER :: ECCENTRICITY = 0.014 |
||||
REAL , PARAMETER :: SEMIMAJORAXIS = 1.0 ! In AU |
||||
! Don't know the following values, so we'll fake them for now |
||||
REAL , PARAMETER :: zero_date = 0.0 ! Time of perihelion passage |
||||
! Fraction into the year (from perhelion) of the |
||||
! occurrence of the Northern Spring Equinox |
||||
REAL , PARAMETER :: EQUINOX_FRACTION= 0.0 |
||||
|
||||
! 2012103 |
||||
#if (EM_CORE == 1) |
||||
! for calls to set_tiles |
||||
INTEGER, PARAMETER :: ZONE_SOLVE_EM = 1 |
||||
INTEGER, PARAMETER :: ZONE_SFS = 2 |
||||
#endif |
||||
|
||||
CONTAINS |
||||
SUBROUTINE init_module_model_constants |
||||
END SUBROUTINE init_module_model_constants |
||||
END MODULE module_model_constants |
@ -1,77 +0,0 @@
@@ -1,77 +0,0 @@
|
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| Variable Name | Description | Units | Additional Keyword Arguments | |
||||
+====================+===============================================================+=====================+===============================================================================================+ |
||||
| avo | Absolute Vorticity | 10-5 s-1 | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| eth/theta_e | Equivalent Potential Temperature | K | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| cape_2d | 2D cape (mcape/mcin/lcl/lfc) | J/kg / J/kg / m / m | missing: Fill value for output only (float) | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| cape_3d | 3D cape and cin | J/kg | missing: Fill value for output only (float) | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| ctt | Cloud Top Temperature | C | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| cloudfrac | Cloud Fraction | % | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| dbz | Reflectivity | dBz | do_variant: Set to True to enable variant calculation. Default is False. | |
||||
| | | | do_liqskin : Set to True to enable liquid skin calculation. Default is False. | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| mdbz | Maximum Reflectivity | dBz | do_variant: Set to True to enable variant calculation. Default is False. | |
||||
| | | | do_liqskin: Set to True to enable liquid skin calculation. Default is False. | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| geopt/geopotential | Full Model Geopotential | m2 s-2 | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| helicity | Storm Relative Helicity | m2 s-2 | top: The top level for the calculation in meters (float). Default is 3000.0. | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| lat | Latitude | decimal degrees | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| lon | Longitude | decimal degrees | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| omg/omega | Omega | Pa/s | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| p/pres | Full Model Pressure | Pa | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| pressure | Full Model Pressure | hPa | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| pvo | Potential Vorticity | PVU | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| pw | Precipitable Water | kg m-2 | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| rh2 | 2m Relative Humidity | % | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| slp | Sea Level Pressure | hPa | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| ter | Model Terrain Height | m | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| td2 | 2m Dew Point Temperature | C | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| td | Dew Point Temperature | C | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| tc | Temperature | C | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| th/theta | Potential Temperature | K | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| tk | Temperature | K | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| times | Times in the File or Sequence | | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| tv | Virtual Temperature | K | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| twb | Wet Bulb Temperature | K | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| updraft_helicity | Updraft Helicity | m2 s-2 | bottom: The bottom level for the calculation in meters (float). Default is 2000.0. | |
||||
| | | | top: The top level for the calculation in meters (float). Default is 5000.0. | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| ua | U-component of Wind on Mass Points | m/s | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| va | V-component of Wind on Mass Points | m/s | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| wa | W-component of Wind on Mass Points | m/s | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| uvmet10 | 10 m U and V Components of Wind Rotated to Earth Coordinates | m/s | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| uvmet | U and V Components of Wind Rotated to Earth Coordinates | m/s | | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
| z/height | Full Model Height | m | msl: Set to False to return AGL values. Otherwise, MSL. Default is True. | |
||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
||||
|
@ -1,215 +0,0 @@
@@ -1,215 +0,0 @@
|
||||
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 |
@ -1,376 +0,0 @@
@@ -1,376 +0,0 @@
|
||||
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 |
@ -1,832 +0,0 @@
@@ -1,832 +0,0 @@
|
||||
#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); |
||||
} |
@ -1,612 +0,0 @@
@@ -1,612 +0,0 @@
|
||||
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 |
@ -1,402 +0,0 @@
@@ -1,402 +0,0 @@
|
||||
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 |
@ -1,763 +0,0 @@
@@ -1,763 +0,0 @@
|
||||
#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); |
||||
} |
@ -1,117 +0,0 @@
@@ -1,117 +0,0 @@
|
||||
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
@ -1,380 +0,0 @@
@@ -1,380 +0,0 @@
|
||||
undef("set_mp_wrf_map_resources") |
||||
function set_mp_wrf_map_resources(in_file[1]:file,opt_args[1]:logical) |
||||
|
||||
begin |
||||
; |
||||
opts = opt_args ; Make a copy of the resource list |
||||
|
||||
; Set some resources depending on what kind of map projection is |
||||
; chosen. |
||||
; |
||||
; MAP_PROJ = 0 : "CylindricalEquidistant" |
||||
; MAP_PROJ = 1 : "LambertConformal" |
||||
; MAP_PROJ = 2 : "Stereographic" |
||||
; MAP_PROJ = 3 : "Mercator" |
||||
; MAP_PROJ = 6 : "Lat/Lon" |
||||
|
||||
if(isatt(in_file,"MAP_PROJ")) |
||||
|
||||
; CylindricalEquidistant |
||||
if(in_file@MAP_PROJ .eq. 0) |
||||
projection = "CylindricalEquidistant" |
||||
opts@mpProjection = projection |
||||
opts@mpGridSpacingF = 45 |
||||
opts@mpCenterLatF = get_res_value_keep(opts, "mpCenterLatF", 0.0) |
||||
if(isatt(in_file,"STAND_LON")) |
||||
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF",in_file@STAND_LON) |
||||
else |
||||
if(isatt(in_file,"CEN_LON")) |
||||
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF",in_file@CEN_LON) |
||||
else |
||||
print("ERROR: Found neither STAND_LON or CEN_LON in file") |
||||
end if |
||||
end if |
||||
end if |
||||
|
||||
; LambertConformal projection |
||||
if(in_file@MAP_PROJ .eq. 1) |
||||
projection = "LambertConformal" |
||||
opts@mpProjection = projection |
||||
opts@mpLambertParallel1F = get_res_value_keep(opts, "mpLambertParallel1F",in_file@TRUELAT1) |
||||
opts@mpLambertParallel2F = get_res_value_keep(opts, "mpLambertParallel2F",in_file@TRUELAT2) |
||||
if(isatt(in_file,"STAND_LON")) |
||||
opts@mpLambertMeridianF = get_res_value_keep(opts, "mpLambertMeridianF",in_file@STAND_LON) |
||||
else |
||||
if(isatt(in_file,"CEN_LON")) |
||||
opts@mpLambertMeridianF = get_res_value_keep(opts, "mpLambertMeridianF",in_file@CEN_LON) |
||||
else |
||||
print("ERROR: Found neither STAND_LON or CEN_LON in file") |
||||
end if |
||||
end if |
||||
end if |
||||
|
||||
; Stereographic projection |
||||
if(in_file@MAP_PROJ .eq. 2) |
||||
projection = "Stereographic" |
||||
opts@mpProjection = projection |
||||
opts@mpCenterLatF = get_res_value_keep(opts, "mpCenterLatF", in_file@CEN_LAT) |
||||
if(isatt(in_file,"STAND_LON")) |
||||
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF",in_file@STAND_LON) |
||||
else |
||||
if(isatt(in_file,"CEN_LON")) |
||||
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF",in_file@CEN_LON) |
||||
else |
||||
print("ERROR: Found neither STAND_LON or CEN_LON in file") |
||||
end if |
||||
end if |
||||
end if |
||||
|
||||
; Mercator projection |
||||
if(in_file@MAP_PROJ .eq. 3) |
||||
projection = "Mercator" |
||||
opts@mpProjection = projection |
||||
opts@mpCenterLatF = get_res_value_keep(opts, "mpCenterLatF", 0.0) |
||||
if(isatt(in_file,"STAND_LON")) |
||||
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF",in_file@STAND_LON) |
||||
else |
||||
if(isatt(in_file,"CEN_LON")) |
||||
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF",in_file@CEN_LON) |
||||
else |
||||
print("ERROR: Found neither STAND_LON or CEN_LON in file") |
||||
end if |
||||
end if |
||||
end if |
||||
|
||||
; global WRF CylindricalEquidistant |
||||
if(in_file@MAP_PROJ .eq. 6) |
||||
projection = "CylindricalEquidistant" |
||||
opts@mpProjection = projection |
||||
opts@mpGridSpacingF = 45 |
||||
|
||||
if (isatt(in_file,"POLE_LON") .and. isatt(in_file,"POLE_LAT") .and. isatt(in_file,"STAND_LON")) then |
||||
|
||||
if (in_file@POLE_LON .eq. 0 .and. in_file@POLE_LAT .eq. 90) then |
||||
; not rotated |
||||
|
||||
opts@mpCenterLatF = get_res_value_keep(opts, "mpCenterLatF", 0.0) |
||||
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF",180 - in_file@STAND_LON) |
||||
|
||||
else |
||||
; rotated |
||||
|
||||
southern = False ; default to northern hemisphere |
||||
if (in_file@POLE_LON .eq. 0.0) then |
||||
southern = True |
||||
else if (in_file@POLE_LON .ne. 180) then |
||||
if (isatt(in_file,"CEN_LAT") .and. in_file@CEN_LAT .lt. 0.0) then |
||||
southern = True ; probably but not necessarily true -- no way to tell for sure |
||||
end if |
||||
end if |
||||
end if |
||||
|
||||
if (.not. southern) then |
||||
opts@mpCenterLatF = get_res_value_keep(opts, "mpCenterLatF", 90.0 - in_file@POLE_LAT) |
||||
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF", -in_file@STAND_LON) |
||||
else |
||||
opts@mpCenterLatF = get_res_value_keep(opts, "mpCenterLatF", in_file@POLE_LAT - 90) |
||||
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF", 180 - in_file@STAND_LON) |
||||
end if |
||||
|
||||
end if |
||||
|
||||
else if (isatt(in_file,"ref_lon") .and. isatt(in_file,"ref_lat")) then |
||||
;; this is definitely true for NMM grids but unlikely for ARW grids especially if ref_x and ref_y are set |
||||
opts@mpCenterLatF = get_res_value_keep(opts, "mpCenterLatF", in_file@REF_LAT) |
||||
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF", in_file@REF_LON) |
||||
|
||||
else if (isatt(in_file,"cen_lat") .and. isatt(in_file,"cen_lon")) then |
||||
;; these usually specifiy the center of the coarse domain --- not necessarily the center of the projection |
||||
opts@mpCenterLatF = get_res_value_keep(opts, "mpCenterLatF",in_file@CEN_LAT) |
||||
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF",in_file@CEN_LON) |
||||
|
||||
else |
||||
;; default values for global grid |
||||
opts@mpCenterLatF = get_res_value_keep(opts, "mpCenterLatF", 0.0) |
||||
opts@mpCenterLonF = get_res_value_keep(opts, "mpCenterLonF", 180.0) |
||||
|
||||
end if |
||||
end if |
||||
end if |
||||
end if |
||||
|
||||
end if |
||||
|
||||
return(opts) ; Return. |
||||
|
||||
end |
||||
|
||||
|
||||
undef("wrf_map_resources") |
||||
function wrf_map_resources(in_file[1]:file,map_args[1]:logical) |
||||
local lat, lon, x1, x2, y1, y2, dims, ii, jj, southern |
||||
begin |
||||
; |
||||
; This function sets resources for a WRF map plot, basing the projection on |
||||
; the MAP_PROJ attribute in the given file. It's intended to be callable |
||||
; by users who need to set mpXXXX resources for other plotting scripts. |
||||
; |
||||
|
||||
; Set some resources depending on what kind of map projection is |
||||
; chosen. |
||||
; |
||||
; MAP_PROJ = 0 : "CylindricalEquidistant" |
||||
; MAP_PROJ = 1 : "LambertConformal" |
||||
; MAP_PROJ = 2 : "Stereographic" |
||||
; MAP_PROJ = 3 : "Mercator" |
||||
; MAP_PROJ = 6 : "Lat/Lon" |
||||
|
||||
if(isatt(in_file,"MAP_PROJ")) |
||||
|
||||
; CylindricalEquidistant |
||||
if(in_file@MAP_PROJ .eq. 0) |
||||
map_args@mpProjection = "CylindricalEquidistant" |
||||
map_args@mpGridSpacingF = 45 |
||||
map_args@mpCenterLatF = get_res_value_keep(map_args, "mpCenterLatF", 0.0) |
||||
if(isatt(in_file,"STAND_LON")) |
||||
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF",in_file@STAND_LON) |
||||
else |
||||
if(isatt(in_file,"CEN_LON")) |
||||
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF",in_file@CEN_LON) |
||||
else |
||||
print("ERROR: Found neither STAND_LON or CEN_LON in file") |
||||
end if |
||||
end if |
||||
end if |
||||
|
||||
; LambertConformal projection |
||||
if(in_file@MAP_PROJ .eq. 1) |
||||
map_args@mpProjection = "LambertConformal" |
||||
map_args@mpLambertParallel1F = get_res_value_keep(map_args, "mpLambertParallel1F",in_file@TRUELAT1) |
||||
map_args@mpLambertParallel2F = get_res_value_keep(map_args, "mpLambertParallel2F",in_file@TRUELAT2) |
||||
if(isatt(in_file,"STAND_LON")) |
||||
map_args@mpLambertMeridianF = get_res_value_keep(map_args, "mpLambertMeridianF",in_file@STAND_LON) |
||||
else |
||||
if(isatt(in_file,"CEN_LON")) |
||||
map_args@mpLambertMeridianF = get_res_value_keep(map_args, "mpLambertMeridianF",in_file@CEN_LON) |
||||
else |
||||
print("ERROR: Found neither STAND_LON or CEN_LON in file") |
||||
end if |
||||
end if |
||||
end if |
||||
|
||||
; Stereographic projection |
||||
if(in_file@MAP_PROJ .eq. 2) |
||||
map_args@mpProjection = "Stereographic" |
||||
map_args@mpCenterLatF = get_res_value_keep(map_args, "mpCenterLatF", in_file@CEN_LAT) |
||||
if(isatt(in_file,"STAND_LON")) |
||||
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF",in_file@STAND_LON) |
||||
else |
||||
if(isatt(in_file,"CEN_LON")) |
||||
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF",in_file@CEN_LON) |
||||
else |
||||
print("ERROR: Found neither STAND_LON or CEN_LON in file") |
||||
end if |
||||
end if |
||||
end if |
||||
|
||||
; Mercator projection |
||||
if(in_file@MAP_PROJ .eq. 3) |
||||
map_args@mpProjection = "Mercator" |
||||
map_args@mpCenterLatF = get_res_value_keep(map_args, "mpCenterLatF", 0.0) |
||||
if(isatt(in_file,"STAND_LON")) |
||||
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF",in_file@STAND_LON) |
||||
else |
||||
if(isatt(in_file,"CEN_LON")) |
||||
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF",in_file@CEN_LON) |
||||
else |
||||
print("ERROR: Found neither STAND_LON or CEN_LON in file") |
||||
end if |
||||
end if |
||||
end if |
||||
|
||||
; global WRF CylindricalEquidistant |
||||
if(in_file@MAP_PROJ .eq. 6) |
||||
print ("YES, THIS WORKED") |
||||
projection = "CylindricalEquidistant" |
||||
map_args@mpProjection = projection |
||||
map_args@mpGridSpacingF = 45 |
||||
|
||||
;; according to the docs if POLE_LON is 0 then the projection center is in the southern hemisphere |
||||
;; if POLE_LON is 180 the projection center is in the northern hemisphere |
||||
;; otherwise you can't tell for sure -- CEN_LAT does not have to be the projection center but hopefully |
||||
;; it is in the same hemisphere. The same is true for REF_LAT except that if REF_Y is specified REF_LAT might |
||||
;; be in a corner or somewhere else and therefore it is even less reliable |
||||
;; |
||||
|
||||
if (isatt(in_file,"POLE_LON") .and. isatt(in_file,"POLE_LAT") .and. isatt(in_file,"STAND_LON")) then |
||||
|
||||
if (in_file@POLE_LON .eq. 0 .and. in_file@POLE_LAT .eq. 90) then |
||||
; not rotated |
||||
|
||||
map_args@mpCenterLatF = get_res_value_keep(map_args, "mpCenterLatF", 0.0) |
||||
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF",180 - in_file@STAND_LON) |
||||
|
||||
else |
||||
; rotated |
||||
|
||||
southern = False ; default to northern hemisphere |
||||
if (in_file@POLE_LON .eq. 0.0) then |
||||
southern = True |
||||
else if (in_file@POLE_LON .ne. 180) then |
||||
if (isatt(in_file,"CEN_LAT") .and. in_file@CEN_LAT .lt. 0.0) then |
||||
southern = True ; probably but not necessarily true -- no way to tell for sure |
||||
end if |
||||
end if |
||||
end if |
||||
|
||||
if (.not. southern) then |
||||
map_args@mpCenterLatF = get_res_value_keep(map_args, "mpCenterLatF", 90.0 - in_file@POLE_LAT) |
||||
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF", -in_file@STAND_LON) |
||||
else |
||||
map_args@mpCenterLatF = get_res_value_keep(map_args, "mpCenterLatF", in_file@POLE_LAT - 90) |
||||
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF", 180 - in_file@STAND_LON) |
||||
end if |
||||
|
||||
end if |
||||
|
||||
else if (isatt(in_file,"ref_lon") .and. isatt(in_file,"ref_lat")) then |
||||
;; this is definitely true for NMM grids but unlikely for ARW grids especially if ref_x and ref_y are set |
||||
map_args@mpCenterLatF = get_res_value_keep(map_args, "mpCenterLatF", in_file@REF_LAT) |
||||
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF", in_file@REF_LON) |
||||
|
||||
else if (isatt(in_file,"cen_lat") .and. isatt(in_file,"cen_lon")) then |
||||
;; these usually specifiy the center of the coarse domain --- not necessarily the center of the projection |
||||
map_args@mpCenterLatF = get_res_value_keep(map_args, "mpCenterLatF",in_file@CEN_LAT) |
||||
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF",in_file@CEN_LON) |
||||
|
||||
else |
||||
;; default values for global grid |
||||
map_args@mpCenterLatF = get_res_value_keep(map_args, "mpCenterLatF", 0.0) |
||||
map_args@mpCenterLonF = get_res_value_keep(map_args, "mpCenterLonF", 180.0) |
||||
|
||||
end if |
||||
end if |
||||
end if |
||||
|
||||
end if |
||||
|
||||
else |
||||
|
||||
return(map_args) |
||||
|
||||
end if |
||||
|
||||
map_args@mpNestTime = get_res_value_keep(map_args, "mpNestTime",0) |
||||
|
||||
if(isfilevar(in_file,"XLAT")) |
||||
lat = in_file->XLAT(map_args@mpNestTime,:,:) |
||||
lon = in_file->XLONG(map_args@mpNestTime,:,:) |
||||
else |
||||
lat = in_file->XLAT_M(map_args@mpNestTime,:,:) |
||||
lon = in_file->XLONG_M(map_args@mpNestTime,:,:) |
||||
end if |
||||
dims = dimsizes(lat) |
||||
|
||||
do ii = 0, dims(0)-1 |
||||
do jj = 0, dims(1)-1 |
||||
if ( lon(ii,jj) .lt. 0.0) then |
||||
lon(ii,jj) = lon(ii,jj) + 360. |
||||
end if |
||||
end do |
||||
end do |
||||
|
||||
map_args@start_lat = lat(0,0) |
||||
map_args@start_lon = lon(0,0) |
||||
map_args@end_lat = lat(dims(0)-1,dims(1)-1) |
||||
map_args@end_lon = lon(dims(0)-1,dims(1)-1) |
||||
|
||||
; end_lon must be greater than start_lon, or errors are thrown |
||||
if (map_args@end_lon .le. map_args@start_lon) then |
||||
map_args@end_lon = map_args@end_lon + 360.0 |
||||
end if |
||||
|
||||
|
||||
; Set some resources common to all map projections. |
||||
map_args = set_mp_resources(map_args) |
||||
|
||||
if ( isatt(map_args,"ZoomIn") .and. map_args@ZoomIn ) then |
||||
y1 = 0 |
||||
x1 = 0 |
||||
y2 = dims(0)-1 |
||||
x2 = dims(1)-1 |
||||
if ( isatt(map_args,"Ystart") ) then |
||||
y1 = map_args@Ystart |
||||
delete(map_args@Ystart) |
||||
end if |
||||
if ( isatt(map_args,"Xstart") ) then |
||||
x1 = map_args@Xstart |
||||
delete(map_args@Xstart) |
||||
end if |
||||
if ( isatt(map_args,"Yend") ) then |
||||
if ( map_args@Yend .le. y2 ) then |
||||
y2 = map_args@Yend |
||||
end if |
||||
delete(map_args@Yend) |
||||
end if |
||||
if ( isatt(map_args,"Xend") ) then |
||||
if ( map_args@Xend .le. x2 ) then |
||||
x2 = map_args@Xend |
||||
end if |
||||
delete(map_args@Xend) |
||||
end if |
||||
|
||||
map_args@mpLeftCornerLatF = lat(y1,x1) |
||||
map_args@mpLeftCornerLonF = lon(y1,x1) |
||||
map_args@mpRightCornerLatF = lat(y2,x2) |
||||
map_args@mpRightCornerLonF = lon(y2,x2) |
||||
|
||||
if ( map_args@mpRightCornerLonF .lt. 0.0 ) then |
||||
map_args@mpRightCornerLonF = map_args@mpRightCornerLonF + 360.0 |
||||
end if |
||||
|
||||
if ( map_args@mpRightCornerLonF .le. map_args@mpRightCornerLonF ) then |
||||
map_args@mpRightCornerLonF = map_args@mpRightCornerLonF + 360.0 |
||||
end if |
||||
|
||||
delete(map_args@ZoomIn) |
||||
end if |
||||
|
||||
return(map_args) |
||||
end |
@ -1,109 +0,0 @@
@@ -1,109 +0,0 @@
|
||||
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 |
@ -1,100 +0,0 @@
@@ -1,100 +0,0 @@
|
||||
|
||||
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 |
@ -1,264 +0,0 @@
@@ -1,264 +0,0 @@
|
||||
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 |
@ -1,771 +0,0 @@
@@ -1,771 +0,0 @@
|
||||
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 |
@ -1,209 +0,0 @@
@@ -1,209 +0,0 @@
|
||||
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 |
@ -1,511 +0,0 @@
@@ -1,511 +0,0 @@
|
||||
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 |
@ -1,404 +0,0 @@
@@ -1,404 +0,0 @@
|
||||
CThe subroutines in this file were taken directly from RIP code written |
||||
C by Dr. Mark Stoelinga. They were modified by Sherrie |
||||
C Fredrick(NCAR/MMM) to work with NCL February 2015. |
||||
C NCLFORTSTART |
||||
subroutine wrf_monotonic(out,in,lvprs,cor,idir,delta, |
||||
& ew,ns,nz,icorsw) |
||||
implicit none |
||||
integer idir,ew,ns,nz,icorsw |
||||
double precision delta |
||||
double precision in(ew,ns,nz),out(ew,ns,nz) |
||||
double precision lvprs(ew,ns,nz),cor(ew,ns) |
||||
C NCLEND |
||||
|
||||
integer i,j,k,ripk,k300 |
||||
|
||||
do j=1,ns |
||||
do i=1,ew |
||||
if (icorsw.eq.1.and.cor(i,j).lt.0.) then |
||||
do k=1,nz |
||||
in(i,j,k)=-in(i,j,k) |
||||
enddo |
||||
endif |
||||
|
||||
|
||||
c |
||||
c First find k index that is at or below (height-wise) the 300 hPa |
||||
c level. |
||||
c |
||||
do k = 1,nz |
||||
ripk = nz-k+1 |
||||
if (lvprs(i,j,k) .le. 300.d0) then |
||||
k300=k |
||||
goto 40 |
||||
endif |
||||
enddo |
||||
c |
||||
40 continue |
||||
|
||||
do k = k300, 1,-1 |
||||
if (idir.eq.1) then |
||||
out(i,j,k)=min(in(i,j,k),in(i,j,k+1)+delta) |
||||
elseif (idir.eq.-1) then |
||||
out(i,j,k)=max(in(i,j,k),in(i,j,k+1)-delta) |
||||
endif |
||||
enddo |
||||
|
||||
|
||||
do k = k300+1, nz |
||||
if (idir.eq.1) then |
||||
out(i,j,k)=max(in(i,j,k),in(i,j,k-1)-delta) |
||||
elseif (idir.eq.-1) then |
||||
out(i,j,k)=min(in(i,j,k),in(i,j,k-1)+delta) |
||||
endif |
||||
enddo |
||||
|
||||
end do |
||||
end do |
||||
|
||||
return |
||||
end |
||||
|
||||
c-------------------------------------------------------------------- |
||||
|
||||
C NCLFORTSTART |
||||
FUNCTION wrf_intrp_value (wvalp0,wvalp1,vlev,vcp0,vcp1,icase) |
||||
implicit none |
||||
|
||||
integer icase |
||||
double precision wvalp0,wvalp1,vlev,vcp0,vcp1 |
||||
C NCLEND |
||||
double precision valp0,valp1,rvalue,rgas,ussalr,sclht |
||||
|
||||
double precision wrf_intrp_value,chkdiff |
||||
|
||||
rgas = 287.04d0 !J/K/kg |
||||
ussalr = 0.0065d0 ! deg C per m |
||||
sclht = rgas*256.d0/9.81d0 |
||||
|
||||
valp0 = wvalp0 |
||||
valp1 = wvalp1 |
||||
if ( icase .eq. 2) then !GHT |
||||
valp0=exp(-wvalp0/sclht) |
||||
valp1=exp(-wvalp1/sclht) |
||||
end if |
||||
|
||||
chkdiff = vcp1 - vcp0 |
||||
if(chkdiff .eq. 0) then |
||||
print *,"bad difference in vcp's" |
||||
stop |
||||
end if |
||||
|
||||
rvalue = (vlev-vcp0)*(valp1-valp0)/(vcp1-vcp0)+valp0 |
||||
if (icase .eq. 2) then !GHT |
||||
wrf_intrp_value = -sclht*log(rvalue) |
||||
else |
||||
wrf_intrp_value = rvalue |
||||
endif |
||||
|
||||
return |
||||
end |
||||
c------------------------------------------------------------ |
||||
C NOTES: |
||||
c vcarray is the array holding the values for the vertical |
||||
c coordinate. |
||||
c It will always come in with the dimensions of |
||||
c the staggered U and V grid. |
||||
C NCLFORTSTART |
||||
|
||||
subroutine wrf_vintrp(datain,dataout,pres,tk,qvp,ght,terrain, |
||||
& sfp,smsfp,vcarray,interp_levels,numlevels, |
||||
& icase,ew,ns,nz,extrap,vcor,logp,rmsg) |
||||
|
||||
|
||||
implicit none |
||||
integer ew,ns,nz,icase,extrap |
||||
integer vcor,numlevels,logp |
||||
double precision datain(ew,ns,nz),pres(ew,ns,nz),tk(ew,ns,nz) |
||||
double precision ght(ew,ns,nz) |
||||
double precision terrain(ew,ns),sfp(ew,ns),smsfp(ew,ns) |
||||
double precision dataout(ew,ns,numlevels),qvp(ew,ns,nz) |
||||
double precision vcarray(ew,ns,nz) |
||||
double precision interp_levels(numlevels),rmsg |
||||
C NCLEND |
||||
integer njx,niy,nreqlvs,ripk |
||||
integer i,j,k,itriv,kupper |
||||
integer ifound,miy,mjx,isign |
||||
double precision rlevel,vlev,diff |
||||
double precision tempout(ew,ns),tmpvlev |
||||
double precision vcp1,vcp0,valp0,valp1 |
||||
double precision rgas,rgasmd,sclht,ussalr,cvc,eps |
||||
double precision qvlhsl,ttlhsl,vclhsl,vctophsl |
||||
double precision wrf_intrp_value |
||||
double precision plhsl,zlhsl,ezlhsl,tlhsl,psurf,pratio,tlev |
||||
double precision ezsurf,psurfsm,zsurf,qvapor,vt |
||||
double precision rconst,expon,exponi |
||||
double precision ezlev,plev,zlev,ptarget,dpmin,dp |
||||
double precision pbot,zbot,tbotextrap,e |
||||
double precision tlclc1,tlclc2,tlclc3,tlclc4 |
||||
double precision thtecon1,thtecon2,thtecon3 |
||||
double precision tlcl,gamma,cp,cpmd,gammamd,gammam |
||||
character cvcord*1 |
||||
|
||||
rgas = 287.04d0 !J/K/kg |
||||
rgasmd = .608d0 |
||||
ussalr = .0065d0 ! deg C per m |
||||
sclht = rgas*256.d0/9.81d0 |
||||
eps = 0.622d0 |
||||
rconst = -9.81d0/(rgas * ussalr) |
||||
expon = rgas*ussalr/9.81d0 |
||||
exponi = 1./expon |
||||
tlclc1 = 2840.d0 |
||||
tlclc2 = 3.5d0 |
||||
tlclc3 = 4.805d0 |
||||
tlclc4 = 55.d0 |
||||
thtecon1 = 3376.d0 ! K |
||||
thtecon2 = 2.54d0 |
||||
thtecon3 = 0.81d0 |
||||
cp = 1004.d0 |
||||
cpmd = 0.887d0 |
||||
gamma = rgas/cp |
||||
gammamd = rgasmd-cpmd |
||||
|
||||
if(vcor .eq. 1) then |
||||
cvcord = 'p' |
||||
else if((vcor .eq. 2) .or. (vcor .eq. 3)) then |
||||
cvcord = 'z' |
||||
else if((vcor .eq. 4) .or. (vcor .eq. 5)) then |
||||
cvcord = 't' |
||||
end if |
||||
|
||||
|
||||
miy = ns |
||||
mjx = ew |
||||
njx = ew |
||||
niy = ns |
||||
|
||||
|
||||
do j = 1,mjx |
||||
do i = 1,miy |
||||
tempout(j,i) = rmsg |
||||
end do |
||||
end do |
||||
|
||||
|
||||
|
||||
do nreqlvs = 1,numlevels |
||||
if(cvcord .eq. 'z') then |
||||
!Convert rlevel to meters from km |
||||
|
||||
rlevel = interp_levels(nreqlvs) * 1000.d0 |
||||
vlev = exp(-rlevel/sclht) |
||||
else if(cvcord .eq. 'p') then |
||||
vlev = interp_levels(nreqlvs) |
||||
else if(cvcord .eq. 't') then |
||||
vlev = interp_levels(nreqlvs) |
||||
end if |
||||
|
||||
|
||||
do j=1,mjx |
||||
do i=1,miy |
||||
cGet the interpolated value that is within the model domain |
||||
ifound = 0 |
||||
do k = 1,nz-1 |
||||
ripk = nz-k+1 |
||||
vcp1 = vcarray(j,i,ripk-1) |
||||
vcp0 = vcarray(j,i,ripk) |
||||
valp0 = datain(j,i,ripk) |
||||
valp1 = datain(j,i,ripk-1) |
||||
if ((vlev.ge.vcp0.and.vlev.le.vcp1) .or. |
||||
& (vlev.le.vcp0.and.vlev.ge.vcp1)) then |
||||
c print *,i,j,valp0,valp1 |
||||
if((valp0 .eq. rmsg).or.(valp1 .eq. rmsg)) then |
||||
tempout(j,i) = rmsg |
||||
ifound=1 |
||||
else |
||||
if(logp .eq. 1) then |
||||
vcp1 = log(vcp1) |
||||
vcp0 = log(vcp0) |
||||
if(vlev .eq. 0.0d0) then |
||||
print *,"Pressure value = 0" |
||||
print *,"Unable to take log of 0" |
||||
stop |
||||
end if |
||||
tmpvlev = log(vlev) |
||||
else |
||||
tmpvlev = vlev |
||||
end if |
||||
tempout(j,i) = wrf_intrp_value(valp0,valp1, |
||||
& tmpvlev,vcp0,vcp1,icase) |
||||
c print *,"one ",i,j,tempout(j,i) |
||||
ifound=1 |
||||
end if |
||||
goto 115 |
||||
end if |
||||
end do !end for the k loop |
||||
115 continue |
||||
|
||||
|
||||
if (ifound.eq.1) then !Grid point is in the model domain |
||||
goto 333 |
||||
end if |
||||
|
||||
cIf the user has requested no extrapolatin then just assign |
||||
call values above or below the model level to rmsg. |
||||
if(extrap .eq. 0) then |
||||
tempout(j,i) = rmsg |
||||
goto 333 |
||||
end if |
||||
|
||||
|
||||
c The grid point is either above or below the model domain |
||||
c |
||||
c First we will check to see if the grid point is above the |
||||
c model domain. |
||||
vclhsl = vcarray(j,i,1) !lowest model level |
||||
vctophsl = vcarray(j,i,nz)!highest model level |
||||
diff = vctophsl-vclhsl |
||||
isign = nint(diff/abs(diff)) |
||||
C |
||||
if(isign*vlev.ge.isign*vctophsl) then |
||||
C Assign the highest model level to the out array |
||||
tempout(j,i)=datain(j,i,nz) |
||||
C print *,"at warn",j,i,tempout(j,i) |
||||
goto 333 |
||||
endif |
||||
|
||||
|
||||
c |
||||
c Only remaining possibility is that the specified level is below |
||||
c lowest model level. If lowest model level value is missing, |
||||
c set interpolated value to missing. |
||||
c |
||||
if (datain(i,j,1) .eq. rmsg) then |
||||
tempout(j,i) = rmsg |
||||
goto 333 |
||||
endif |
||||
|
||||
c |
||||
c If the field comming in is not a pressure,temperature or height |
||||
C field we can set the output array to the value at the lowest |
||||
c model level. |
||||
c |
||||
tempout(j,i) = datain(j,i,1) |
||||
c |
||||
c For the special cases of pressure on height levels or height on |
||||
c pressure levels, or temperature-related variables on pressure or |
||||
c height levels, perform a special extrapolation based on |
||||
c US Standard Atmosphere. Here we calcualate the surface pressure |
||||
c with the altimeter equation. This is how RIP calculates the |
||||
c surface pressure. |
||||
c |
||||
if (icase.gt.0) then |
||||
plhsl = pres(j,i,1) * 0.01d0 !pressure at lowest model level |
||||
zlhsl = ght(j,i,1) !grid point height a lowest model level |
||||
ezlhsl = exp(-zlhsl/sclht) |
||||
tlhsl = tk(j,i,1) !temperature in K at lowest model level |
||||
zsurf = terrain(j,i) |
||||
qvapor = max((qvp(j,i,1)*.001d0),1.e-15) |
||||
c virtual temperature |
||||
c vt = tlhsl * (eps + qvapor)/(eps*(1.0 + qvapor)) |
||||
c psurf = plhsl * (vt/(vt+ussalr * (zlhsl-zsurf)))**rconst |
||||
psurf = sfp(j,i) |
||||
psurfsm = smsfp(j,i) |
||||
ezsurf = exp(-zsurf/sclht) |
||||
|
||||
cThe if for checking above ground |
||||
if ((cvcord.eq.'z'.and.vlev.lt.ezsurf).or. |
||||
& (cvcord.eq.'p'.and.vlev.lt.psurf)) then |
||||
c |
||||
c We are below the lowest data level but above the ground. |
||||
c Use linear interpolation (linear in prs and exp-height). |
||||
c |
||||
if (cvcord.eq.'p') then |
||||
plev=vlev |
||||
ezlev=((plev-plhsl)*ezsurf+(psurf-plev)*ezlhsl)/ |
||||
& (psurf-plhsl) |
||||
zlev=-sclht*log(ezlev) |
||||
if (icase .eq. 2) then |
||||
tempout(j,i)=zlev |
||||
goto 333 |
||||
endif |
||||
|
||||
elseif (cvcord.eq.'z') then |
||||
ezlev=vlev |
||||
zlev=-sclht*log(ezlev) |
||||
plev=((ezlev-ezlhsl)*psurf+(ezsurf-ezlev)*plhsl)/ |
||||
& (ezsurf-ezlhsl) |
||||
if (icase .eq. 1) then |
||||
tempout(j,i)=plev |
||||
goto 333 |
||||
endif |
||||
endif |
||||
|
||||
else !else for checking above ground |
||||
ptarget=psurfsm-150.d0 |
||||
dpmin=1.e4 |
||||
do k=1,nz |
||||
ripk = nz-k+1 |
||||
dp=abs((pres(j,i,ripk) * 0.01d0)-ptarget) |
||||
if (dp.gt.dpmin) goto 334 |
||||
dpmin=min(dpmin,dp) |
||||
enddo |
||||
334 kupper=k-1 |
||||
|
||||
ripk = nz - kupper + 1 |
||||
pbot = max(plhsl,psurf) |
||||
zbot = min(zlhsl,zsurf) |
||||
pratio = pbot/(pres(j,i,ripk) * 0.01d0) |
||||
tbotextrap = tk(j,i,ripk)*(pratio)**expon |
||||
c virtual temperature |
||||
vt = tbotextrap * (eps + qvapor)/(eps*(1.0d0+qvapor)) |
||||
if (cvcord.eq.'p') then |
||||
plev=vlev |
||||
zlev=zbot+vt/ussalr*(1.-(vlev/pbot)**expon) |
||||
if(icase .eq. 2) then |
||||
tempout(j,i)=zlev |
||||
goto 333 |
||||
endif |
||||
elseif (cvcord.eq.'z') then |
||||
zlev=-sclht*log(vlev) |
||||
plev=pbot*(1.+ussalr/vt*(zbot-zlev))**exponi |
||||
if (icase .eq. 1) then |
||||
tempout(j,i)=plev |
||||
goto 333 |
||||
endif |
||||
endif |
||||
end if !end if for checking above ground |
||||
end if !for icase gt 0 |
||||
|
||||
|
||||
if(icase .gt. 2) then !extrapolation for temperature |
||||
tlev=tlhsl+(zlhsl-zlev)*ussalr |
||||
qvapor = max(qvp(j,i,1),1.e-15) |
||||
gammam = gamma*(1.+gammamd*qvapor) |
||||
if(icase .eq. 3) then |
||||
tempout(j,i) = tlev - 273.16d0 |
||||
else if(icase .eq. 4) then |
||||
tempout(j,i) = tlev |
||||
C Potential temperature - theta |
||||
else if (icase. eq. 5) then |
||||
tempout(j,i)=tlev*(1000.d0/plev)**gammam |
||||
C extraolation for equivalent potential temperature |
||||
else if (icase .eq. 6) then |
||||
e = qvapor*plev/(eps+qvapor) |
||||
tlcl = tlclc1/(log(tlev**tlclc2/e)-tlclc3)+tlclc4 |
||||
tempout(j,i)=tlev*(1000.d0/plev)**(gammam)* |
||||
& exp((thtecon1/tlcl-thtecon2)*qvapor* |
||||
& (1.+thtecon3*qvapor)) |
||||
end if |
||||
end if |
||||
|
||||
333 continue |
||||
|
||||
end do |
||||
end do |
||||
! print *,"----done----",interp_levels(nreqlvs) |
||||
do i = 1,njx |
||||
do j = 1,niy |
||||
dataout(i,j,nreqlvs) = tempout(i,j) |
||||
end do |
||||
end do |
||||
end do !end for the nreqlvs |
||||
return |
||||
end !wrf_vinterp |
Loading…
Reference in new issue