forked from 3rdparty/wrf-python
28 changed files with 0 additions and 33110 deletions
@ -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 @@ |
|||||||
! 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 @@ |
|||||||
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 @@ |
|||||||
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 @@ |
|||||||
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 @@ |
|||||||
''' |
|
||||||
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 @@ |
|||||||
!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 @@ |
|||||||
+--------------------+---------------------------------------------------------------+---------------------+-----------------------------------------------------------------------------------------------+ |
|
||||||
| 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 @@ |
|||||||
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 @@ |
|||||||
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 @@ |
|||||||
#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 @@ |
|||||||
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 @@ |
|||||||
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 @@ |
|||||||
#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 @@ |
|||||||
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 @@ |
|||||||
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 @@ |
|||||||
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 @@ |
|||||||
|
|
||||||
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 @@ |
|||||||
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 @@ |
|||||||
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 @@ |
|||||||
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 @@ |
|||||||
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 @@ |
|||||||
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