module module_stats_for_move 2
implicit none
private
public :: stats_for_move, vorttrak_init
contains
SUBROUTINE VORTTRAK_INIT(grid,config_flags, & 1,5
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
ITS,ITE,JTS,JTE,KTS,KTE)
USE MODULE_CONFIGURE
, ONLY : grid_config_rec_type
USE MODULE_DOMAIN
, ONLY : domain
IMPLICIT NONE
integer, intent(in) :: IDS,IDE,JDS,JDE,KDS,KDE
integer, intent(in) :: IMS,IME,JMS,JME,KMS,KME
integer, intent(in) :: ITS,ITE,JTS,JTE,KTS,KTE
type(domain), intent(inout) :: grid
type(grid_config_rec_type), intent(in) :: config_flags
integer :: vortex_tracker
character*255 :: message
! For vortex_tracker==4 option:
integer :: cx,cy ! center x,y
real :: xfar,yfar,far ! distance from center: x,y components and dist^2
integer :: xshift ! for handling grid staggering
integer :: i,j
#ifdef HWRF
vortex_tracker=grid%vortex_tracker
if(vortex_tracker<1 .or. vortex_tracker>4) then
write(message,*)' domain ',grid%id,' has an invalid value ',vortex_tracker,' for vortex_tracker. It must be 1, 2, 3 or 4.'
call wrf_error_fatal
(message)
endif
is_vt4: if(vortex_tracker==4) then
call wrf_message
('in VORTTRAK_INIT for vortex tracker 4')
if(.not.(grid%vt4_pmax<0.0)) then
if(grid%vt4_pmax<100000.0 .or. grid%vt4_pmax>107000) then
write(message,'("vt4_pmax bad: vt4_pmax must be either <0 or within [1e5,1.07e5], but it is ",F15.5,". We recommend -1.")') grid%vt4_pmax
call wrf_error_fatal
(message)
endif
endif
cx=ide/2
cy=jde/2
! Calculate distance of various points from the domain center:
jdo: do j = jts, min(jte,jde)
if(mod(j,2)==1) then
xshift=1.
else
xshift=-1.
endif
do i = its, min(ite,ide)
xfar=(i-cx)*grid%dx_nmm(i,j)*2
yfar=(j-cy)*grid%dy_nmm
if(mod(cy-j,2) /= 0) then
xfar=xfar + grid%dx_nmm(i,j)*xshift
endif
far = xfar*xfar + yfar*yfar
GRID%distsq(i,j)=far
enddo
enddo jdo
endif is_vt4
#endif
END SUBROUTINE VORTTRAK_INIT
!----------------------------------------------------------------------
!
SUBROUTINE STATS_FOR_MOVE(grid,config_flags, & 1,9
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE, &
ITS,ITE,JTS,JTE,KTS,KTE )
! STATS_FOR_MOVE
!
! PURPOSE: If it is time to consider the possibility of nest
! motion, then this routine calculates certain nest motion
! dynamical fields (PDYN, MSLP, SQWS), locates the vortex in those
! fields and then decides if the domain needs to be moved to
! recenter on the vortex.
!
! Several vortex tracking methods are implemented, and are
! chosen using the vortex_tracker namelist parameter:
!
! vortex_tracker=1 -- old pre-2012 HWRF method: center on minimum MSLP
! vortex_tracker=2 -- not a vortex tracker. Instead, it tracks
! its child domain. This is used in the 9km domain of the 27:9:3
! vortex_tracker=3 -- old HWRF-X algorithm. This is a mass-based
! centroid algorithm. It works well for strong storms. With
! weaker storms, it can be fooled by other nearby high- or
! low-pressure systems, or noise in the MSLP field due to
! explicitly resolved gravity waves near sharp terrain changes.
! vortex_tracker=4 -- new centroid algorithm. This is similar to
! option 3, but uses the dynamic pressure PDYN and includes PDYN
! noise removal. Plus, it only searches within X km of the nest
! center to avoid other nearby systems.
!
! HISTORY:
! 2004? - initial implementation by gopal
! 2004-2010 - gopal, xuejin, young added vortex tracker changes
! late 2010 - sam added vortex_tracker variable to switch between trackers
! late 2010 - sam added a new child tracker (vortex_tracker=2)
! Nov 08 2011 - sam split implementation into several functions and
! added the vortex_tracker=4 option
USE MODULE_CONFIGURE
, ONLY : grid_config_rec_type
USE MODULE_DOMAIN
, ONLY : domain,get_ijk_from_grid
#ifdef DM_PARALLEL
# ifdef HWRF
USE MODULE_COMM_DM
, ONLY : HALO_NMM_VT4_NOISE_sub, HALO_NMM_VT4_MSLP_sub
USE MODULE_DM
, ONLY: ntasks_x, ntasks_y, mytask, ntasks, local_communicator
# endif
#endif
IMPLICIT NONE
type(domain), intent(inout) :: grid
type(grid_config_rec_type), intent(in) :: config_flags
integer :: i,movefreq
integer, intent(in) :: IDS,IDE,JDS,JDE,KDS,KDE
integer, intent(in) :: IMS,IME,JMS,JME,KMS,KME
integer, intent(in) :: IPS,IPE,JPS,JPE,KPS,KPE
integer, intent(in) :: ITS,ITE,JTS,JTE,KTS,KTE
integer :: vortex_tracker
! KEEP NEST MOTION IN SINK WITH PHYSICS TIME STEPS
#if ( NMM_NEST == 1 )
#ifdef HWRF
MOVEFREQ=grid%movemin*grid%nphs
vortex_tracker=grid%vortex_tracker
#else
MOVEFREQ=grid%nphs
vortex_tracker=-1
#endif
IF(MOD(grid%NTSD+1,MOVEFREQ)/=0)THEN
#ifdef HWRF
IF(grid%MOVED) grid%NTIME0=grid%NTSD !FOR UPDATING NTIM0
#endif
grid%MVNEST=.FALSE.
RETURN
ENDIF
CALL STATS_MAKE_MSLP
(grid%PDYN,grid%MSLP,grid%SQWS, &
grid%PINT,grid%T,grid%Q,grid%U,grid%V, &
grid%FIS,grid%PD,grid%SM, &
grid%PDTOP,grid%PT, &
grid%DETA1,grid%DETA2, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
ITS,ITE,JTS,JTE,KTS,KTE)
! HAND OFF CONTROL TO STATS_FOR_MOVE_123 FOR TRACKERS 1, 2 and 3
oldmove: if(vortex_tracker /= 4) then
! PDYN causes noise in the presence of strong vorticity variations,
! so it is not used by HWRF for nest tracking.
CALL STATS_FOR_MOVE_123
(grid%XLOC_2,grid%YLOC_2 &
#ifdef HWRF
,grid%MSLP &
#else
,grid%PDYN &
#endif
,grid%sm &
#ifdef HWRF
,GRID%RESTART,grid%NTIME0 &
,GRID%MOVED,grid%MVNEST,grid%ntsd,GRID%NPHS,GRID%MOVEMIN &
#else
,GRID%MOVED,grid%MVNEST,grid%ntsd,GRID%NPHS &
#endif
,GRID%VORTEX_TRACKER &
,IDS,IDE-1,JDS,JDE-1,KDS,KDE &
,IMS,IME,JMS,JME,KMS,KME &
,ITS,ITE,JTS,JTE,KTS,KTE)
RETURN
else
#ifdef HWRF
! HANDLE VORTEX TRACKER 4 HERE
! (we only get here in HWRF mode)
if(config_flags%vt4_noise_iter<0) then
grid%mslp_noisy=0
else
# ifdef DM_PARALLEL
# include "HALO_NMM_VT4_MSLP.inc"
# endif
call vt4_noise_detect
(grid%mslp,grid%mslp_noisy, &
config_flags%vt4_noise_pmax, &
config_flags%vt4_noise_pmin, &
config_flags%vt4_noise_dpdr, &
grid%dx_nmm,grid%dy_nmm, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
ITS,ITE,JTS,JTE,KTS,KTE)
do i=1,config_flags%vt4_noise_iter
# ifdef DM_PARALLEL
# include "HALO_NMM_VT4_NOISE.inc"
# endif
call vt4_noise_iter
(grid%mslp_noisy, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
ITS,ITE,JTS,JTE,KTS,KTE)
enddo
endif
call vt4_move
(grid%mslp,grid%weightout,grid%distsq, &
grid%mslp_noisy, grid%dx_nmm, &
grid%dy_nmm,grid%xloc_2,grid%yloc_2, &
grid%xloc_1,grid%yloc_1,grid%mvnest, &
config_flags%vt4_radius, &
config_flags%vt4_weightexp, &
config_flags%vt4_pmax, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE, &
ITS,ITE,JTS,JTE,KTS,KTE)
#endif
endif oldmove
#endif
END SUBROUTINE STATS_FOR_MOVE
SUBROUTINE vt4_noise_iter(NOISY, & 1
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
ITS,ITE,JTS,JTE,KTS,KTE)
! VT4_NOISE_DETECT
!
! PURPOSE: Takes in a "NOISY" array, finds all points where
! NOISY(I,J)/=01, and marks all surrounding points with a 1.
! With repeated calls, this will produce diamond-shaped
! areas of 1s around areas that originally had a 1.
!
! The first and last row and column are not modified.
!
! HISTORY:
! Nov 08 2011 - written by Sam Trahan
IMPLICIT NONE
integer,dimension(ims:ime,jms:jme), intent(inout) :: noisy
integer, intent(in) :: IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
ITS,ITE,JTS,JTE,KTS,KTE
integer :: i,j,iadd
#ifdef HWRF
do j = max(jds+1,jts), min(jte,jde-2)
iadd=mod(j,2)-1
do i = max(ids+1,its), min(ite,ide-2)
if( noisy(i+1+iadd,j+1)/=0 &
.or. noisy(i+1+iadd,j-1)/=0 &
.or. noisy(i+iadd,j+1)/=0 &
.or. noisy(i+iadd,j-1)/=0) then
noisy(i,j)=1
endif
enddo
enddo
#endif
END SUBROUTINE vt4_noise_iter
SUBROUTINE vt4_noise_detect(MSLP,NOISY,PMAX,PMIN,DPDR, & 1,4
DX_NMM, DY_NMM, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
ITS,ITE,JTS,JTE,KTS,KTE)
! VT4_NOISE_DETECT
!
! PURPOSE: Finds "noisy" MSLP values and marks a "1" in the
! "NOISY" array wherever such noisy values occur. An MSLP
! value is "noisy" if it meets one of these criteria:
!
! MSLP > PMAX
! MSLP < PMIN
! |d(MSLP)/d(northwest-southeast)| > DPDR
! |d(MSLP)/d(southwest-northeast)| > DPDR
!
! HISTORY:
! Nov 08 2011 - written by Sam Trahan
IMPLICIT NONE
real,dimension(ims:ime,jms:jme), intent(in) :: mslp,dx_nmm
real, intent(in) :: dy_nmm,pmax,pmin,dpdr
integer,dimension(ims:ime,jms:jme), intent(out) :: noisy
integer, intent(in) :: IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
ITS,ITE,JTS,JTE,KTS,KTE
real :: dp2,dy2,dx2,pdiff,dp2max
integer :: i,j
integer :: iadd
#ifdef EXPENSIVE_HWRF_DEBUG_STUFF
character*255 :: message
integer :: nprint
nprint=10
#endif
#ifdef HWRF
dy2=dy_nmm*dy_nmm*4
dp2max=dpdr*dpdr
do j=jts,min(jte,jde-1)
iadd=mod(j,2)-1
do i=its,min(ite,ide-1)
noisetype: if(mslp(i,j)>pmax) then
#ifdef EXPENSIVE_HWRF_DEBUG_STUFF
if(nprint>0) then
3088 format('MSLP(',I0,',',I0,') = ',F0.3,' > pmax = ',F0.3)
write(message,3088) i,j,mslp(i,j),pmax
call wrf_message
(message)
nprint=nprint-1
endif
#endif
noisy(i,j)=1
elseif(mslp(i,j)<pmin) then
#ifdef EXPENSIVE_HWRF_DEBUG_STUFF
if(nprint>0) then
3089 format('MSLP(',I0,',',I0,') = ',F0.3,' < pmin = ',F0.3)
write(message,3089) i,j,mslp(i,j),pmin
call wrf_message
(message)
nprint=nprint-1
endif
#endif
noisy(i,j)=1
else
dx2=dx_nmm(i,j)*dx_nmm(i,j)*4
notbdy: if(i>ids .and. i<ide-1 .and. j>jds .and. j<jde-1) then
! northeast-southwest direction:
pdiff=mslp(i+1+iadd,j+1)-mslp(i+iadd,j-1)
dp2=pdiff*pdiff/(dx2+dy2)
if(dp2>dp2max) then
noisy(i,j)=1
#ifdef EXPENSIVE_HWRF_DEBUG_STUFF
if(nprint>0) then
3091 format('dpdr(',I0,',',I0,') in NE-SW dir = ',F0.5,' > dpdrmax = ',F0.5)
write(message,3091) i,j,sqrt(dp2),sqrt(dp2max)
call wrf_message
(message)
nprint=nprint-1
endif
#endif
cycle
endif
! southeast-northwest direction:
pdiff=mslp(i+1+iadd,j-1)-mslp(i+iadd,j+1)
dp2=pdiff*pdiff/(dx2+dy2)
if(dp2>dp2max) then
noisy(i,j)=1
#ifdef EXPENSIVE_HWRF_DEBUG_STUFF
if(nprint>0) then
3092 format('dpdr(',I0,',',I0,') in SE-NW dir = ',F0.5,' > dpdrmax = ',F0.5)
write(message,3092) i,j,sqrt(dp2),sqrt(dp2max)
call wrf_message
(message)
nprint=nprint-1
endif
#endif
cycle
endif
endif notbdy
! We get here if the point and its surroudings are not
! "noisy"
noisy(i,j)=0
endif noisetype
enddo
enddo
#endif
END SUBROUTINE vt4_noise_detect
#ifdef HWRF
SUBROUTINE vt4_move(MSLP,WEIGHTOUT,DISTSQ,NOISY,DX_NMM,DY_NMM, & 1,16
xloc,yloc,cx,cy,mvnest, &
searchrad,searchpow,searchpmax, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE, &
ITS,ITE,JTS,JTE,KTS,KTE)
! VT4_MOVE
!
! PURPOSE: Searches the MSLP field to find the center of the
! cyclone vortex. This is done by first discarding points that
! don't match certain conditions, and then doing a weighted
! average of the point locations to find a centroid.
!
! Several conditions are used to eliminate points. The "NOISY"
! field is used to mask out areas where the MSLP may be
! questionable. This frequently happens due to terrain-induced
! gravity waves. Points more than SEARCHRAD away from the nest
! center are ignored. Lastly, points with MSLP>PMAX are ignored,
! where PMAX is either the maximum pressure in the non-noisy MSLP
! if SEARCHPMAX<0, or SEARCHPMAX if SEARCHPMAX>=0.
!
! The center is found using a weighted average of point I and J
! locations for all points that survive the above conditions.
!
! HISTORY:
! Nov 08 2011 - written by Sam Trahan
#ifdef DM_PARALLEL && !defined(STUBMPI)
USE module_dm
, only: wrf_dm_maxval_real, wrf_dm_sum_real, &
local_communicator_y, local_communicator_x
IMPLICIT NONE
INCLUDE 'mpif.h'
#else
IMPLICIT NONE
#endif
character*512 :: message
integer, intent(out) :: xloc,yloc
integer, intent(in) :: cx,cy
real,dimension(ims:ime,jms:jme), intent(in) :: mslp,distsq,dx_nmm
real, intent(in) :: dy_nmm,searchrad,searchpow,searchpmax
real,dimension(ims:ime,jms:jme), intent(out) :: weightout
integer,dimension(ims:ime,jms:jme), intent(inout) :: noisy
integer, intent(in) :: IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE, &
ITS,ITE,JTS,JTE,KTS,KTE
logical, intent(out) :: mvnest
real :: pmax,sr2,weight,xsum,ysum,xwsum,ywsum
real :: centroid_x, centroid_y, xdiff, ydiff
real :: xweight,yweight,maxweight
integer :: i,j,idum,jdum,ierr,ctx,cty
integer :: xcount(jps:jpe),ycount(ips:ipe)
integer :: myxcount(jps:jpe),myycount(ips:ipe)
! NOTE: cx and cy MUST match the domain center used in
! direction_of_move2 in mediation_nest_move.F
if(searchrad<dy_nmm*4) then
call wrf_error_fatal
('increase searchrad: searchrad<dy_nmm*4')
endif
sr2=searchrad*searchrad
! Final noisiness pass: mark all values outside of sr2 as noisy=2
! so we don't use far away points in the vortex search. Also,
! mark points near the boundaries as 3 (within 9 points of J
! boundary or within 6 of I boundary), even if they are within
! the search radius.
!
! In situations where noisy is already 1, we retain the value of
! 1, except at the boundaries where it is set to 3. This allows
! us to see where, outside the search area, there is noise.
! Having "3" at the boundary avoids regions where there is
! noise from prior moves, and also allows us to see where the
! boundary was after the nest moves.
do j=jts,min(jte,jde-1)
if(j<jds+10 .or. j>jde-11) then
noisy(its:ite,j)=3
else
do i=its,min(ite,ide-1)
if(i<ids+7 .or. i>ide-8) then
noisy(i,j)=3
elseif(distsq(i,j)>sr2 .and. noisy(i,j)/=1) then
noisy(i,j)=2
endif
enddo
endif
enddo
! Get the number of points in the X and Y directions along each
! row and column.
myxcount=0
myycount=0
do j=jps,min(jpe,jde-1)
do i=ips,min(ipe,ide-1)
if(noisy(i,j)==0) then
myxcount(j)=myxcount(j)+1
endif
enddo
enddo
do j=jps,min(jpe,jde-1)
do i=ips,min(ipe,ide-1)
if(noisy(i,j)==0) then
myycount(i)=myycount(i)+1
endif
enddo
enddo
#ifdef DM_PARALLEL
call MPI_Allreduce(myxcount,xcount,jpe-jps+1,MPI_INTEGER,MPI_SUM,local_communicator_x,ierr)
call MPI_Allreduce(myycount,ycount,ipe-ips+1,MPI_INTEGER,MPI_SUM,local_communicator_y,ierr)
#else
xcount=myxcount
ycount=myycount
#endif
#ifdef EXPENSIVE_HWRF_DEBUG_STUFF
do j=jps,min(jpe,jde-1)
write(message,'("xcount(",I0,") = ",I0)') j,xcount(j)
call wrf_debug
(5,message)
enddo
do i=ips,min(ipe,ide-1)
write(message,'("ycount(",I0,") = ",I0)') i,ycount(i)
call wrf_debug
(5,message)
enddo
#endif
! Find maximum pressure if requested
findpmax: if(searchpmax<0.0) then
pmax=-9e9
do j = max(jds+2,jts), min(jte,jde-3)
do i = max(ids+1,its), min(ite,ide-2)
if(noisy(i,j)==0 .and. mslp(i,j)>pmax) then
pmax=mslp(i,j)
endif
enddo
enddo
idum=-99 ; jdum=-99 ! to keep debug modes happy
call wrf_dm_maxval_real(pmax,idum,jdum)
pmax=min(105000.0,pmax)
else
pmax=searchpmax
endif findpmax
! Find vortex location.
xsum=0.0 ; ysum=0.0 ; xwsum=0.0 ; ywsum=0.0
maxweight=-99.
if_pow_1: if(abs(searchpow-1.0)<1e-5) then
! Special copy of loop for exponent of 1, for efficiency
call wrf_debug
(10,'got into pow=1 loop')
do j = max(jds+2,jts), min(jte,jde-3)
do i = max(ids+1,its), min(ite,ide-2)
if(noisy(i,j)==0) then
weight = pmax - mslp(i,j)
if(weight>0) then
if(weight>maxweight) maxweight=weight
weight=weight/pmax
weightout(i,j)=weight
xweight=weight/ycount(i)
yweight=weight/xcount(j)
xsum=xsum + i*xweight
ysum=ysum + j*yweight
xwsum=xwsum + xweight
ywsum=ywsum + yweight
else
weightout(i,j)=0
end if
else
weightout(i,j)=0
endif
enddo
enddo
else
if_sqrt: if(abs(searchpow-0.5)<1e-5) then
call wrf_debug
(10,'got into pow=0.5 loop')
do j = max(jds+2,jts), min(jte,jde-3)
do i = max(ids+1,its), min(ite,ide-2)
if(noisy(i,j)==0) then
weight = pmax - mslp(i,j)
if(weight>0) then
if(weight>maxweight) maxweight=weight
weight=sqrt(weight/pmax)
weightout(i,j)=weight
xweight=weight/ycount(i)
yweight=weight/xcount(j)
xsum=xsum + i*xweight
ysum=ysum + j*yweight
xwsum=xwsum + xweight
ywsum=ywsum + yweight
else
weightout(i,j)=0
end if
else
weightout(i,j)=0
endif
enddo
enddo
else
! General loop for exponents other than 1:
do j = max(jds+2,jts), min(jte,jde-3)
do i = max(ids+1,its), min(ite,ide-2)
if(noisy(i,j)==0) then
weight = pmax - mslp(i,j)
if(weight>0) then
if(weight>maxweight) maxweight=weight
weight=(weight/pmax)**searchpow
weightout(i,j)=weight
xweight=weight/ycount(i)
yweight=weight/xcount(j)
xsum=xsum + i*xweight
ysum=ysum + j*yweight
xwsum=xwsum + xweight
ywsum=ywsum + yweight
else
weightout(i,j)=0
end if
else
weightout(i,j)=0
endif
enddo
enddo
endif if_sqrt
endif if_pow_1
if(maxweight<=0) then
call wrf_debug
(1,'No valid points found in this tile.')
else
write(message,'("Max weight was ",F0.3)') maxweight
call wrf_debug
(1,message)
endif
xwsum = wrf_dm_sum_real
(xwsum)
no_vortex: if(xwsum <= 0) then
! All pressures are >= pmax so disable move by
! specifying the vortex center at the domain center.
centroid_x=cx
centroid_y=cy
write(message,*) 'Lost the storm. Search rad,pmax,pow = ', &
searchrad,pmax,searchpow
call wrf_message
(message)
mvnest=.false.
return
else
ywsum = wrf_dm_sum_real
(ywsum)
xsum = wrf_dm_sum_real
(xsum)
ysum = wrf_dm_sum_real
(ysum)
centroid_x = xsum/xwsum
centroid_y = ysum/ywsum
383 format("XSUM=",F0.3," YSUM=",F0.3," XWSUM=",F0.3," YWSUM=",F0.3, &
" Center=(",I0,",",I0,")", &
" Centroid=(",F0.3,",",F0.3,")")
write(message,383) xsum,ysum,xwsum,ywsum,cx,cy,centroid_x,centroid_y
call wrf_message
(message)
endif no_vortex
! Place a plus at the centroid in the "noisy" array
ctx=nint(centroid_x)
cty=nint(centroid_y)
do j=cty-1,cty+1
do i=ctx-4,ctx+4
if(i>=its .and. i<=ite .and. j>=jts .and. j<=jte) then
noisy(i,j)=noisy(i,j)-6
endif
enddo
enddo
do j=cty-4,cty+4
do i=ctx-1,ctx+1
if(i>=its .and. i<=ite .and. j>=jts .and. j<=jte) then
noisy(i,j)=noisy(i,j)-6
endif
enddo
enddo
xdiff=abs(centroid_x-real(cx))/3.0
ydiff=abs(centroid_y-real(cy))/6.0
if(xdiff>=1. .or. ydiff>=1.) then
! We have moved >1 parent gridpoints in X or >2 parent
! gridpoints in Y, so trigger a nest move:
mvnest=.true.
xloc=nint(centroid_x)
yloc=nint(centroid_y)
call wrf_debug
(1,'Centroid is far enough from nest center to trigger a move.')
else
mvnest=.false.
xloc=cx
yloc=cy
call wrf_debug
(1,'Nest has not moved far enough yet.')
endif
END SUBROUTINE vt4_move
#endif
SUBROUTINE STATS_MAKE_MSLP(PDYN,MSLP,SQWS & 1,1
,PINT,T,Q,U,V &
,FIS,PD,SM,PDTOP,PTOP &
,DETA1,DETA2 &
,IDS,IDE,JDS,JDE,KDS,KDE &
,IMS,IME,JMS,JME,KMS,KME &
,ITS,ITE,JTS,JTE,KTS,KTE)
! STATS_MAKE_MSLP
!
! PURPOSE: Calculates the PDYN, MSLP and SQWS fields needed
! by the vortex trackers. This code was taken from the old
! STATS_FOR_MOVE routine.
!
! HISTORY:
! 2004? : written by gopal
! 2004-2011 : various modifications by gopal, xuejin, young, sam
! Nov 08 2011: moved code into a seperate STATS_MAKE_MSLP routine
USE MODULE_MODEL_CONSTANTS
IMPLICIT NONE
INTEGER,INTENT(IN) :: IDS,IDE,JDS,JDE,KDS,KDE &
,IMS,IME,JMS,JME,KMS,KME &
,ITS,ITE,JTS,JTE,KTS,KTE
REAL, DIMENSION(KMS:KME), INTENT(IN) :: DETA1,DETA2
REAL, INTENT(IN) :: PDTOP,PTOP
REAL, DIMENSION(IMS:IME,JMS:JME), INTENT(IN) :: FIS,PD,SM
REAL, DIMENSION(IMS:IME,JMS:JME,KMS:KME), INTENT(IN) :: PINT,T,Q,U,V
REAL, DIMENSION(IMS:IME,JMS:JME), INTENT(OUT) :: PDYN,MSLP,SQWS
INTEGER :: ITF,JTF, i,j,k
REAL :: DZ,RTOPP,APELP,A,TSFC
REAL, PARAMETER :: LAPSR=6.5E-3, GI=1./G,D608=0.608
REAL, PARAMETER :: COEF3=287.05*GI*LAPSR, COEF2=-1./COEF3
REAL, PARAMETER :: TRG=2.0*R_D*GI,LAPSI=1.0/LAPSR
REAL, DIMENSION(IMS:IME,JMS:JME,KMS:KME) :: Z
ITF=MIN(ITE,IDE-1)
JTF=MIN(JTE,JDE-1)
! DETERMINE THE HEIGHTS ON THE PARENT DOMAIN
DO J = JTS, MIN(JTE,JDE)
DO I = ITS, MIN(ITE,IDE)
Z(I,J,1)=FIS(I,J)*GI
ENDDO
ENDDO
!
DO K = KTS,KTE
DO J = JTS, MIN(JTE,JDE)
DO I = ITS, MIN(ITE,IDE)
APELP = (PINT(I,J,K+1)+PINT(I,J,K))
RTOPP = TRG*T(I,J,K)*(1.0+Q(I,J,K)*P608)/APELP
DZ = RTOPP*(DETA1(K)*PDTOP+DETA2(K)*PD(I,J))
Z(I,J,K+1) = Z(I,J,K) + DZ
ENDDO
ENDDO
ENDDO
! DETERMINE THE MEAN SEA LEVEL PRESSURE, THE VERTICALLY AVERAGED WIND
! SPEED AT ABOUT LEVELS 9 10 AND 11 AND THE DYNAMIC PRESSURES DEFINED
! FROM BASIC BERNOULLI's THEOREM
DO J = JTS, MIN(JTE,JDE)
DO I = ITS, MIN(ITE,IDE)
TSFC = T(I,J,1)*(1.+D608*Q(I,J,1)) + LAPSR*(Z(I,J,1)+Z(I,J,2))*0.5
A = LAPSR*Z(I,J,1)/TSFC
MSLP(I,J) = PINT(I,J,1)*(1-A)**COEF2
SQWS(I,J) = (U(I,J,9)*U(I,J,9) + V(I,J,9)*V(I,J,9) &
+ U(I,J,10)*U(I,J,10) + V(I,J,10)*V(I,J,10) &
+ U(I,J,11)*U(I,J,11) + V(I,J,11)*V(I,J,11))/3.0
PDYN(I,J) = MSLP(I,J) + 1.1*SQWS(I,J)/2.0
ENDDO
ENDDO
END SUBROUTINE STATS_MAKE_MSLP
!----------------------------------------------------------------------
!
SUBROUTINE STATS_FOR_MOVE_123 (XLOC,YLOC,PRES,SM & 1,20
#ifdef HWRF
,RESTART,NTIME0 & ! zhang's doing
,MOVED,MVNEST,NTSD,NPHS,CFREQ & ! CFREQ*DT*NPHS=540s
#else
,MOVED,MVNEST,NTSD,NPHS &
#endif
,vortex_tracker &
,IDS,IDE,JDS,JDE,KDS,KDE &
,IMS,IME,JMS,JME,KMS,KME &
,ITS,ITE,JTS,JTE,KTS,KTE )
!**********************************************************************
!$$$ SUBPROGRAM DOCUMENTATION BLOCK
! . . .
! SUBPROGRAM: STATS_FOR_MOVE_123
! PRGRMMR: gopal
!
! ABSTRACT:
! THIS ROUTINE COMPUTES SOME STATS REQUIRED FOR AUTOMATIC GRID MOTION
! THERE ARE THREE DIFFERENT MODES:
! vortex_tracker=1 -- follow vortex using pre-2012 HWRF algorithm
! vortex_tracker=2 -- follow child
! vortex_tracker=3 -- follow vortex using HWRF-X algorithm
! NOTE: This routine does not handle vortex_tracker==4. The
! stats_for_move routine handles that vortex tracker.
! PROGRAM HISTORY LOG:
! (inbetween) : gopal, xuejin, young added vortex tracker changes
! late 2010 : sam added vortex_tracker variable to switch between trackers
! late 2010 : sam added a new child tracker (vortex_tracker=2)
! 11-08-2011 : renamed to stats_for_move_123, and moved all PRES
! calculation stuff to another routine.
!
! USAGE: CALL STATS_FOR_MOVE FROM SUBROUTINE SOLVE_RUNSTREAM FOR NESTED DOMAIN ONLY
!
! ATTRIBUTES:
! LANGUAGE: FORTRAN 90
! MACHINE : IBM SP
!$$$
!**********************************************************************
USE MODULE_MODEL_CONSTANTS
USE MODULE_DM
USE MODULE_WRF_ERROR
IMPLICIT NONE
!
LOGICAL,INTENT(INOUT) :: MVNEST ! NMM SWITCH FOR GRID MOTION
LOGICAL,INTENT(IN) :: MOVED
INTEGER,INTENT(IN) :: vortex_tracker
INTEGER,INTENT(IN) :: IDS,IDE,JDS,JDE,KDS,KDE &
,IMS,IME,JMS,JME,KMS,KME &
,ITS,ITE,JTS,JTE,KTS,KTE &
#ifdef HWRF
,NTSD,NPHS,CFREQ
#else
,NTSD,NPHS
#endif
!
INTEGER, INTENT(OUT) :: XLOC,YLOC
INTEGER :: NXLOC,NYLOC
REAL :: NSUM1,NSUM2,NSUM3
REAL, DIMENSION(IMS:IME,JMS:JME), INTENT(IN) :: SM,PRES
!
! LOCAL
character*256 :: message
#ifdef HWRF
!zhang's doing
INTEGER,INTENT(INOUT) :: NTIME0
LOGICAL,INTENT(IN) :: RESTART
REAL :: far,weight,sr2,pmax,xfar,yfar,xshift,yshift
integer :: cx,cy
#else
INTEGER,SAVE :: NTIME0
#endif
INTEGER :: IM,JM,IP,JP
INTEGER :: I,K,J,XR,YR,DTMOVE,IDUM,JDUM,ITF,JTF
REAL :: STMP0,STMP1
REAL :: SMSUM,SMOUT,XDIFF,YDIFF,PCUT,PGR
REAL :: MINGBL_PRES,MAXGBL_PRES,MAXGBL_SQWS
REAL :: MINGBL_MIJ
REAL, DIMENSION(IMS:IME,JMS:JME) :: MIJ
! Bug in the original code that is intentionally preserved:
! IDE is already IDE-1, but the code subtracts 1 again and
! uses ITF
ITF=min(ITE,IDE-1)
JTF=min(JTE,JDE-1)
! FILTER OUT PRES AND STORE THAT IN MIJ. THE MAXIMUM VALUE OF
! MIJ GIVES THE STORM CENTER ALSO DO THAT WITHIN A SUB DOMAIN
MAXGBL_PRES=MAXVAL(PRES(ITS:ITF,JTS:JTF))
CALL WRF_DM_MAXVAL
(MAXGBL_PRES,IDUM,JDUM)
MINGBL_PRES=MINVAL(PRES(ITS:ITF,JTS:JTF))
CALL WRF_DM_MINVAL
(MINGBL_PRES,IDUM,JDUM)
PCUT = 0.5*(MAXGBL_PRES + MINGBL_PRES)
!
IM=IDE/2 - IDE/6
IP=IDE/2 + IDE/6
JM=JDE/2 - JDE/4
JP=JDE/2 + JDE/4
!
DO J = JTS, MIN(JTE,JDE)
DO I = ITS, MIN(ITE,IDE)
IF(I .GE. IM .AND. I .LE. IP .AND. J .GE. JM .AND. J .LE. JP &
.AND. PCUT .GT. PRES(I,J))THEN
MIJ(I,J) = PRES(I,J)
ELSE
MIJ(I,J) = 105000.0
ENDIF
ENDDO
ENDDO
! BEGIN OLD TRACKER CODE ----------------------------------------------------
old_tracker_1: if(vortex_tracker == 1) then
!
! DETERMINE THE LOCATION OF CENTER OF THE CIRCULATION DEFINED BY MIJ AND FIND THE CORRESPONDING PRES
!
STMP0=MAXGBL_PRES*100. ! define arbitrary maximum
MINGBL_MIJ=MINVAL(MIJ(ITS:ITF,JTS:JTF))
DO J = JTS, MIN(JTE,JDE)
DO I = ITS, MIN(ITE,IDE)
IF(MIJ(I,J) .EQ. MINGBL_MIJ)THEN
XLOC=I
YLOC=J
STMP0=PRES(I,J)
ENDIF
ENDDO
ENDDO
CALL WRF_DM_MINVAL
(MINGBL_MIJ,XLOC,YLOC)
CALL WRF_DM_MINVAL
(STMP0,IDUM,JDUM)
endif old_tracker_1
! END OLD TRACKER CODE ------------------------------------------------------
! BEGIN HWRF-X TRACKER CODE -------------------------------------------------
hwrfx_tracker: if(vortex_tracker == 3) then
! USE CENTROID TO FIND THE CENTER Xuejin's doing
NSUM1=0.0
NSUM2=0.0
NSUM3=0.0
DO J = JTS, MIN(JTE,JDE)
DO I = ITS, MIN(ITE,IDE)
IF(I .GE. IM .AND. I .LE. IP .AND. J .GE. JM .AND. J .LE. JP )THEN
! IF(I .EQ. IM .AND. J .EQ. JM)THEN
NSUM1 = NSUM1 + I*(105000.1 - MIJ(I,J))
NSUM2 = NSUM2 + J*(105000.1 - MIJ(I,J))
NSUM3 = NSUM3 + (105000.1 - MIJ(I,J))
! WRITE(0,*)'TEST',NSUM1,I,J,0.01*(105000.0 - MIJ(I,J)),MIJ(I,J)
ENDIF
ENDDO
ENDDO
NSUM1 = WRF_DM_SUM_REAL
(NSUM1)
NSUM2 = WRF_DM_SUM_REAL
(NSUM2)
NSUM3 = WRF_DM_SUM_REAL
(NSUM3)
NXLOC = NINT(NSUM1/NSUM3)
NYLOC = NINT(NSUM2/NSUM3)
XLOC = NXLOC
YLOC = NYLOC
WRITE(message,*)'NEW CALC',NSUM1,NSUM2,NSUM3
call wrf_debug
(1,message)
WRITE(message,*)'XLOC,YLOC',NXLOC,XLOC,NYLOC,YLOC
call wrf_debug
(1,message)
endif hwrfx_tracker
! END HWRF-X TRACKER CODE ---------------------------------------------------
! BEGIN OLD TRACKER CODE ----------------------------------------------------
! DETERMINE THE MAXIMUM MIJ AT ABOUT 18 GRID POINTS AWAY FROM THE STORM CENTER
old_tracker_2: if ( vortex_tracker == 1 ) then
STMP1=0.0
DO J = JTS, MIN(JTE,JDE)
DO I = ITS, MIN(ITE,IDE)
IF(I .EQ. XLOC+18)THEN
XR=I
YR=J
STMP1=MIJ(I,J)
ENDIF
ENDDO
ENDDO
CALL WRF_DM_MAXVAL
(STMP1,XR,YR)
!
! DETERMINE IF THE ENTIRE NESTED DOMAIN IS OVER LAND (SM=0)
!
SMSUM = 0.0
DO J = JTS, MIN(JTE,JDE)
DO I = ITS, MIN(ITE,IDE)
SMSUM = SMSUM + SM(I,J)
ENDDO
ENDDO
SMOUT=WRF_DM_SUM_REAL
(SMSUM)/(IDE*JDE)
! STOP GRID MOTION. AVOID MOVING TOO RAPID GRID MOTION, SAY SOMETHING LIKE EVERY
! OTHER TIME STEP OR SO
PGR=STMP1-STMP0
endif old_tracker_2
! END OLD TRACKER CODE ------------------------------------------------
XDIFF=ABS(XLOC - IDE/2)
YDIFF=ABS(YLOC - JDE/2)
#ifdef HWRF
!zhang's doing
IF((.NOT.RESTART .AND. NTSD==0) .OR. MOVED)NTIME0=NTSD
#else
IF(NTSD==0 .OR. MOVED)NTIME0=NTSD
#endif
DTMOVE=NTSD-NTIME0 ! TIME INTERVAL SINCE THE PREVIOUS MOVE
!
! DECIDE IF NEST MOTION SHOULD HAPPEN
!
if(vortex_tracker == 3) then
! Using HWRF-X tracker. Move if centroid moved.
IF(XDIFF .GE. 1 .OR. YDIFF .GE. 2) THEN
MVNEST=.TRUE.
NTIME0=NTSD
ELSE
! Centroid has not moved one parent gridpoint yet.
MVNEST=.FALSE.
ENDIF
elseif(vortex_tracker==2) then
! Tracking child domain. Nest motion check happens in
! direction_of_move2, but we MUST set mvnest=true here:
MVNEST=.TRUE.
elseif(vortex_tracker==1) then
! Using old HWRF tracker. Decide if it wants to move.
IF(DTMOVE .LE. 45 .OR. PGR .LE. 200.)THEN
WRITE(message,*)'SUSPEND MOTION: SMALL DTMOVE OR WEAK PGF:','DTMOVE=',DTMOVE,'PGR=',PGR
call wrf_debug
(1,message)
MVNEST=.FALSE. ! SET STATIC GRID
ELSE IF(STMP0 .GE. STMP1)THEN
WRITE(message,*)'SUSPEND MOTION: THERE IS NO VORTEX IN THE DOMAIN:','STMP0=',STMP0,'STMP1=',STMP1
call wrf_debug
(1,message)
MVNEST=.FALSE.
ELSE IF(XDIFF .GT. 24 .OR. YDIFF .GT. 24)THEN
WRITE(message,*)'SUSPEND MOTION: LOST VORTEX ','DTMOVE=',DTMOVE,'XDIFF=',XDIFF,'YDIFF=',YDIFF
call wrf_debug
(1,message)
MVNEST=.FALSE.
ELSE IF(SMOUT .LE. 0.2 .AND. XDIFF .GT. 12 .AND. YDIFF .GT. 12)THEN
WRITE(message,*)'SUSPEND MOTION: VORTEX LOST OVER LAND ','DTMOVE=',DTMOVE,'XDIFF=',XDIFF,'YDIFF=',YDIFF
call wrf_debug
(1,message)
MVNEST=.FALSE.
ELSE IF(SMOUT .LE. 0.2 .AND. PGR .LE. 400.)THEN
WRITE(message,*)'SUSPEND MOTION: VORTEX WEAK OVER LAND ','SMOUT=',SMOUT,'PGR=',PGR
call wrf_debug
(1,message)
MVNEST=.FALSE.
ELSE IF(SMOUT .LE. 0.2 .AND. DTMOVE .GE. 1500)THEN
WRITE(message,*)'SUSPEND MOTION: STOP MOTION OVER LAND','SMOUT=',SMOUT,'DTMOVE=',DTMOVE
call wrf_debug
(1,message)
MVNEST=.FALSE.
ELSE
MVNEST=.TRUE.
ENDIF
else
! Not using any valid trackers, so set MVNEST to false.
MVNEST=.false.
endif
RETURN
END SUBROUTINE STATS_FOR_MOVE_123
END module module_stats_for_move