module module_tracker 4
implicit none
private
#if ( HWRF == 1 )
public :: ncep_tracker_center, ncep_tracker_init, update_tracker_post_move
real, parameter :: invE=0.36787944117 ! 1/e
! Copied from tracker:
real,parameter :: searchrad_6=250.0 ! km - ignore data more than this far from domain center
real,parameter :: searchrad_7=200.0 ! km - ignore data more than this far from domain center
integer, parameter :: maxtp=11 ! number of tracker parameters
real, parameter :: uverrmax = 225.0 ! For use in get_uv_guess
real, parameter :: ecircum = 40030.2 ! Earth's circumference
! (km) using erad=6371.e3
real, parameter :: rads_vmag=120.0 ! max search radius for wind minimum
real, parameter :: err_reg_init=300.0 ! max err at initial time (km)
real, parameter :: err_reg_max=225.0 ! max err at other times (km)
real, parameter :: errpmax=485.0 ! max stddev of track parameters
real, parameter :: errpgro=1.25 ! stddev multiplier
real, parameter :: max_wind_search_radius=searchrad_7 ! max radius for vmax search
real, parameter :: min_mlsp_search_radius=searchrad_7 ! max radius for pmin search
! Also used:
real, parameter :: km2nmi = 0.539957, kn2mps=0.514444, mps2kn=1./kn2mps, pi180=0.01745329251
contains
!----------------------------------------------------------------------------------
! These two simple routines return an N, S, E or W for the
! hemisphere of a latitude or longitude. They are copied from
! module_HIFREQ to avoid a relatively pointless compiler dependency.
character(1) function get_lat_ns(lat)
! This could be written simply as merge('N','S',lat>=0) if WRF allowed F95
implicit none ; real lat
if(lat>=0) then
get_lat_ns='N'
else
get_lat_ns='S'
endif
end function get_lat_ns
character(1) function get_lon_ew(lon)
! This could be written simply as merge('E','W',lon>=0) if WRF allowed F95
implicit none ; real lon
if(lon>=0) then
get_lon_ew='E'
else
get_lon_ew='W'
endif
end function get_lon_ew
subroutine ncep_tracker_init(grid) 1,2
! Initialize tracker variables in the grid structure.
use module_domain
, only: domain
implicit none
type(domain), intent(inout) :: grid
call wrf_message
('ncep_tracker_init')
grid%track_stderr_m1=-99.9
grid%track_stderr_m2=-99.9
grid%track_stderr_m3=-99.9
grid%track_n_old=0
grid%track_old_lon=0
grid%track_old_lat=0
grid%track_old_ntsd=0
grid%tracker_angle=0
grid%tracker_fixlon=-999.0
grid%tracker_fixlat=-999.0
grid%tracker_ifix=-99
grid%tracker_jfix=-99
grid%tracker_havefix=.false.
grid%tracker_gave_up=.false.
grid%tracker_pmin=-99999.
grid%tracker_vmax=-99.
grid%tracker_rmw=-99.
grid%track_have_guess=.false.
grid%track_guess_lat=-999.0
grid%track_guess_lon=-999.0
end subroutine ncep_tracker_init
subroutine ncep_tracker_center(grid) 1,3
! Top-level entry to the inline ncep tracker. Finds the center of
! the storm in the specified grid and updates the grid variables.
! Will do nothing and return immediately if
! grid%tracker_gave_up=.true.
USE MODULE_DOMAIN
, ONLY : domain,get_ijk_from_grid
implicit none
type(domain), intent(inout) :: grid
character*255 :: message
integer :: IDS,IDE,JDS,JDE,KDS,KDE
integer :: IMS,IME,JMS,JME,KMS,KME
integer :: IPS,IPE,JPS,JPE,KPS,KPE
CALL get_ijk_from_grid
( grid , &
ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
ips, ipe, jps, jpe, kps, kpe )
call ntc_impl
(grid, &
ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
ips, ipe, jps, jpe, kps, kpe )
end subroutine ncep_tracker_center
subroutine ntc_impl(grid, & 1,29
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE)
! This is the main entry point to the tracker. It is most similar
! to the function "tracker" in the GFDL/NCEP vortex tracker.
USE MODULE_DOMAIN
, ONLY : domain,get_ijk_from_grid
#ifdef DM_PARALLEL
use module_dm
, only: wrf_dm_sum_real
#endif
implicit none
logical, external :: wrf_dm_on_monitor
type(domain), intent(inout) :: grid
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
real :: dxdymean, sum
integer :: i,j, iweights,ip
integer :: iguess, jguess ! first guess location
real :: latguess, longuess ! same, but in lat & lon
integer :: iuvguess, juvguess ! "second guess" location using everything except wind maxima
real :: srsq
integer :: ifinal,jfinal
real :: latfinal,lonfinal
integer :: ierr
integer :: icen(maxtp), jcen(maxtp) ! center locations for each parameter
real :: loncen(maxtp), latcen(maxtp) ! lat, lon locations in degrees
logical :: calcparm(maxtp) ! do we have a valid center location for this parameter?
real :: max_wind,min_pres ! for ATCF output
real :: rcen(maxtp) ! center value (max wind, min mslp, etc.)
character*255 :: message
logical :: north_hemi ! true = northern hemisphere
logical :: have_guess ! first guess is available
real :: guessdist,guessdeg ! first guess distance to nearest point on grid
real :: latnear, lonnear ! nearest point in grid to first guess
! icen,jcen: Same meaning as clon, clat in tracker, but uses i and
! j indexes of the center instead of lat/lon. Tracker comment:
! Holds the coordinates for the center positions for
! all storms at all times for all parameters.
! (max_#_storms, max_fcst_times, max_#_parms).
! For the third position (max_#_parms), here they are:
! 1: Relative vorticity at 850 mb
! 2: Relative vorticity at 700 mb
! 3: Vector wind magnitude at 850 mb
! 4: NOT CURRENTLY USED
! 5: Vector wind magnitude at 700 mb
! 6: NOT CURRENTLY USED
! 7: Geopotential height at 850 mb
! 8: Geopotential height at 700 mb
! 9: Mean Sea Level Pressure
! 10: Vector wind magnitude at 10 m
! 11: Relative vorticity at 10 m
call wrf_message
('ncep_tracker_center')
! Initialize center information to invalid values for all centers:
icen=-99
jcen=-99
latcen=9e9
loncen=9e9
rcen=9e9
calcparm=.false.
if(grid%vortex_tracker==6) then
srsq=searchrad_6*searchrad_6*1e6
else
srsq=searchrad_7*searchrad_7*1e6
endif
! Get the first guess from the prior nest motion timestep:
have_guess=grid%track_have_guess
if(have_guess) then
! We have a first guess center. We have to translate it to gridpoint space.
longuess=grid%track_guess_lon
latguess=grid%track_guess_lat
call get_nearest_lonlat
(grid,iguess,jguess,ierr,longuess,latguess, &
ids,ide, jds,jde, kds,kde, &
ims,ime, jms,jme, kms,kme, &
ips,ipe, jps,jpe, kps,kpe, lonnear, latnear)
if(ierr==0) then
call calcdist
(longuess,latguess, lonnear,latnear, guessdist,guessdeg)
if(guessdist*1e3>3*grid%dy) then
108 format('WARNING: guess lon=',F0.3,',lat=',F0.3, &
' too far (',F0.3,'km) from nearest point lon=',F0.3,',lat=',F0.3, &
'. Will use domain center as first guess.')
write(message,108) grid%track_guess_lon,grid%track_guess_lat, &
guessdist,lonnear,latnear
call wrf_message
(message)
have_guess=.false. ! indicate that the first guess is unusable
else
latguess=latnear
longuess=lonnear
endif
else
have_guess=.false. ! indicate that the first guess is unusable.
109 format('WARNING: guess lon=',F0.3,',lat=',F0.3, &
' does not exist in this domain. Will use domain center as first guess.')
write(message,109) grid%track_guess_lon,grid%track_guess_lat
call wrf_message
(message)
endif
endif
! If we could not get the first guess from the prior nest motion
! timestep, then use the default first guess: the domain center.
if(grid%vortex_tracker==6 .or. .not.have_guess) then
! vt=6: hard coded first-guess center is domain center:
! vt=7: first guess comes from prior timestep
! Initial first guess is domain center.
! Backup first guess is domain center if first guess is unusable.
iguess=ide/2
jguess=jde/2
if(grid%vortex_tracker==7) then
call wrf_message
('Using domain center as first guess since no valid first guess is available.')
endif
call get_lonlat
(grid,iguess,jguess,longuess,latguess,ierr, &
ids,ide, jds,jde, kds,kde, &
ims,ime, jms,jme, kms,kme, &
ips,ipe, jps,jpe, kps,kpe)
if(ierr/=0) then
call wrf_error_fatal
("ERROR: center of domain is not inside the domain")
endif
have_guess=.true.
endif
if(.not.have_guess) then
call wrf_error_fatal
("INTERNAL ERROR: No first guess is available (should never happen).")
endif
north_hemi = latguess>0.0
! Get the mean V-to-H point-to-point distance:
sum=0
do j=jps,min(jde-1,jpe)
do i=ips,min(ide-1,ipe)
sum=sum+grid%dx_nmm(i,j)
enddo
enddo
#ifdef DM_PARALLEL
sum=wrf_dm_sum_real
(sum)
#endif
dxdymean=0.5*(grid%dy_nmm + sum/( (ide-ids) * (jde-jds) ))/1000.0
33 format ('dxdymean=',F0.3,' dx=',F0.3,' dy=',F0.3,' sum=',F0.3,' count=',I0)
!write(0,33) dxdymean,grid%dx_nmm((ips+ipe)/2,(jps+jpe)/2),grid%dy_nmm, &
! sum,(ide-ids) * (jde-jds)
! Find the centers of all fields except the wind minima:
call find_center
(grid,grid%p850rv,grid%sp850rv,srsq, &
icen(1),jcen(1),rcen(1),calcparm(1),loncen(1),latcen(1),dxdymean,'zeta', &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE, north_hemi=north_hemi)
call find_center
(grid,grid%p700rv,grid%sp700rv,srsq, &
icen(2),jcen(2),rcen(2),calcparm(2),loncen(2),latcen(2),dxdymean,'zeta', &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE, north_hemi=north_hemi)
call find_center
(grid,grid%p850z,grid%sp850z,srsq, &
icen(7),jcen(7),rcen(7),calcparm(7),loncen(7),latcen(7),dxdymean,'hgt', &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE)
call find_center
(grid,grid%p700z,grid%sp700z,srsq, &
icen(8),jcen(8),rcen(8),calcparm(8),loncen(8),latcen(8),dxdymean,'hgt', &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE)
call find_center
(grid,grid%membrane_mslp,grid%smslp,srsq, &
icen(9),jcen(9),rcen(9),calcparm(9),loncen(9),latcen(9),dxdymean,'slp', &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE)
call find_center
(grid,grid%m10rv,grid%sm10rv,srsq, &
icen(11),jcen(11),rcen(11),calcparm(11),loncen(11),latcen(11),dxdymean,'zeta', &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE, north_hemi=north_hemi)
! Get a guess center location for the wind minimum searches:
call get_uv_guess
(grid,icen,jcen,loncen,latcen,calcparm, &
iguess,jguess,longuess,latguess,iuvguess,juvguess, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE)
! Find wind minima. Requires a first guess center:
windmin: if(grid%vortex_tracker==6) then
call find_center
(grid,grid%p850wind,grid%sp850wind,srsq, &
icen(3),jcen(3),rcen(3),calcparm(3),loncen(3),latcen(3),dxdymean,'wind', &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE, &
iuvguess=iuvguess, juvguess=juvguess)
call find_center
(grid,grid%p700wind,grid%sp700wind,srsq, &
icen(5),jcen(5),rcen(5),calcparm(5),loncen(5),latcen(5),dxdymean,'wind', &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE, &
iuvguess=iuvguess, juvguess=juvguess)
call find_center
(grid,grid%m10wind,grid%sm10wind,srsq, &
icen(10),jcen(10),rcen(10),calcparm(10),loncen(10),latcen(10),dxdymean,'wind', &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE, &
iuvguess=iuvguess, juvguess=juvguess)
else
call get_uv_center
(grid,grid%p850wind, &
icen(3),jcen(3),rcen(3),calcparm(3),loncen(3),latcen(3),dxdymean,'wind', &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE, &
iuvguess=iuvguess, juvguess=juvguess)
call get_uv_center
(grid,grid%p700wind, &
icen(5),jcen(5),rcen(5),calcparm(5),loncen(5),latcen(5),dxdymean,'wind', &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE, &
iuvguess=iuvguess, juvguess=juvguess)
call get_uv_center
(grid,grid%m10wind, &
icen(10),jcen(10),rcen(10),calcparm(10),loncen(10),latcen(10),dxdymean,'wind', &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE, &
iuvguess=iuvguess, juvguess=juvguess)
endif windmin
! Get a final guess center location:
call fixcenter
(grid,icen,jcen,calcparm,loncen,latcen, &
iguess,jguess,longuess,latguess, &
ifinal,jfinal,lonfinal,latfinal, &
north_hemi, &
ids,ide, jds,jde, kds,kde, &
ims,ime, jms,jme, kms,kme, &
ips,ipe, jps,jpe, kps,kpe)
grid%tracker_fixes=0
do ip=1,maxtp
if(calcparm(ip)) then
300 format('Parameter ',I0,': i=',I0,' j=',I0,' lon=',F0.2,' lat=',F0.2)
!write(0,300) ip,icen(ip),jcen(ip),loncen(ip),latcen(ip)
if(icen(ip)>=ips .and. icen(ip)<=ipe &
.and. jcen(ip)>=jps .and. jcen(ip)<=jpe) then
grid%tracker_fixes(icen(ip),jcen(ip))=ip
endif
else
301 format('Parameter ',I0,' invalid')
!write(0,301) ip
endif
enddo
if(iguess>=ips .and. iguess<=ipe .and. jguess>=jps .and. jguess<=jpe) then
grid%tracker_fixes(iguess,jguess)=-1
201 format('First guess: i=',I0,' j=',I0,' lon=',F0.2,' lat=',F0.2)
!write(0,201) iguess,jguess,longuess,latguess
endif
if(iuvguess>=ips .and. iuvguess<=ipe .and. juvguess>=jps .and. juvguess<=jpe) then
grid%tracker_fixes(iuvguess,juvguess)=-2
202 format('UV guess: i=',I0,' j=',I0)
!write(0,202) iguess,jguess
endif
1000 format('Back with final lat/lon at i=',I0,' j=',I0,' lon=',F0.3,' lat=',F0.3)
!write(0,1000) ifinal,jfinal,lonfinal,latfinal
if(ifinal>=ips .and. ifinal<=ipe .and. jfinal>=jps .and. jfinal<=jpe) then
grid%tracker_fixes(ifinal,jfinal)=-3
203 format('Final fix: i=',I0,' j=',I0,' lon=',F0.2,' lat=',F0.2)
!write(0,201) ifinal,jfinal,lonfinal,latfinal
endif
call get_tracker_distsq
(grid, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE)
call get_wind_pres_intensity
(grid, &
grid%tracker_pmin,grid%tracker_vmax,grid%tracker_rmw, &
max_wind_search_radius, min_mlsp_search_radius, &
lonfinal,latfinal, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE)
#ifdef DM_PARALLEL
if(wrf_dm_on_monitor()) then
#endif
call output_partial_atcfunix
(grid, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE)
#ifdef DM_PARALLEL
endif
#endif
! if(grid%vortex_tracker==7) then
! call get_first_ges(grid,iguess,jguess,longuess,latguess, &
! IDS,IDE,JDS,JDE,KDS,KDE, &
! IMS,IME,JMS,JME,KMS,KME, &
! IPS,IPE,JPS,JPE,KPS,KPE)
! call store_old_fixes(grid, &
! IDS,IDE,JDS,JDE,KDS,KDE, &
! IMS,IME,JMS,JME,KMS,KME, &
! IPS,IPE,JPS,JPE,KPS,KPE)
! ! Store the first guess:
! grid%track_have_guess=.true.
! grid%track_guess_lat=latguess
! grid%track_guess_lon=longuess
! 3011 format('First guess: lon=',F0.3,' lat=',F0.3)
! write(message,3011) grid%track_guess_lon,grid%track_guess_lat
! call wrf_debug(1,message)
! endif
end subroutine ntc_impl
subroutine get_first_ges(grid, &,23
iguess,jguess,longuess,latguess, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE)
! This replicates the functionality of the tracker get_first_ges
! routine, whose purpose is to analyze the storm and guess where
! it will be at the next nest motion timestep. It does that using
! two different methods, similar to the GFDL/NCEP Tracker's
! methods:
!
! 1. Use the present, and past few, fix locations and extrapolate
! to the next location.
!
! 2. Calculate the mean motion and extrapolate to get the
! location at the next nest motion timestep.
!
! The average of the two results is used.
#ifdef DM_PARALLEL
use module_dm
, only: wrf_dm_maxval_real
#endif
USE MODULE_DOMAIN
, ONLY : domain,get_ijk_from_grid
use module_wrf_error
, only: wrf_at_debug_level
implicit none
type(domain), intent(inout) :: grid
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(out) :: iguess,jguess
real, intent(out) :: longuess,latguess
character*255 message
integer :: iold, inew, jold, jnew
integer :: ifix,jfix,jrot,irot,ierr, pinky,brain, n, tsum, ntsd_plus_1, i, told
real :: motion_grideast, motion_gridnorth, fixdx
real :: dxeast,dynorth, xeast, ynorth
real :: dxrot, dyrot, tracker_dt, xsum, ysum, ytsum, xtsum, xxsum, yysum, ttsum
real :: mx, my, bx, by ! x=mx*t+bx ; y=my*t+by
real :: xrot,yrot
logical :: have_motion_guess, have_line_guess
have_motion_guess=.false.
have_line_guess=.false.
if(grid%tracker_havefix) then
ifix=grid%tracker_ifix
jfix=grid%tracker_jfix
call mean_motion
(grid, motion_grideast, motion_gridnorth, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE)
#ifdef DM_PARALLEL
fixdx=0
if(ifix>=ips .and. ifix<=ipe .and. jfix>=jps .and. jfix<=jpe) then
fixdx=grid%dx_nmm(ifix,jfix)
endif
pinky=2 ; brain=308
call wrf_dm_maxval_real
(fixdx,pinky,brain)
#else
fixdx=grid%dx_nmm(ifix,jfix)
#endif
! Rotated east and north motion in gridpoints per second, on the combined H+V grid:
tracker_dt=grid%dt*grid%nphs*grid%ntrack
dxeast = motion_grideast * tracker_dt / fixdx
dynorth = motion_gridnorth * tracker_dt / grid%dy_nmm
! Combine the H & V coordinate systems and rotate 45 degrees.
! This puts the H points on a rectangular grid. Add storm motion
! to the rotated coordinates and round to nearest H point
xeast=ifix*2
ynorth=jfix
if(mod(jfix,2)==0) xeast=xeast+1
jrot=nint((xeast+ynorth)/2 + (dxeast+dynorth)/2)
irot=nint((ynorth-xeast)/2 + ((jde-1)/2) + (dynorth-dxeast)/2)
! Translate back to usual E grid H points
iguess=irot-jrot+((jde-1)/2)
jguess=irot+jrot-((jde-1)/2)
if(mod(jguess,2)==0) then
iguess=(iguess-1)/2
else
iguess=iguess/2
endif
! This last step should not be necessary but done just in case:
have_motion_guess = .not.(iguess<ide/4 .or. iguess>ide*3/4 .or. jguess<jde/4 .or. jguess>jde*3/4)
!print *,'got have_motion_guess=',have_motion_guess
endif
if(.not.have_motion_guess) then
! Could not find the storm, so give the domain center as the
! next first guess location.
iguess=ide/2
jguess=jde/2
!print *,'cannot find storm, so using domain center for motion guess'
endif
if(grid%track_n_old>0) then
!print *,'line guess: have old'
n=1
call to_rot45_grid
(grid%tracker_ifix,grid%tracker_jfix,jde,xrot,yrot)
xsum=xrot
ysum=yrot
tsum=grid%ntsd
xtsum=xsum*tsum
xxsum=xsum*xsum
yysum=ysum*ysum
ytsum=ysum*tsum
ttsum=tsum*tsum
do i=1,grid%track_n_old
call get_nearest_lonlat
(grid,iold,jold,ierr, &
grid%track_old_lon(i),grid%track_old_lat(i), &
ids,ide, jds,jde, kds,kde, &
ims,ime, jms,jme, kms,kme, &
ips,ipe, jps,jpe, kps,kpe)
if(ierr==0) then
!print *,'insert: i=',iold,' j=',jold,' lon=',grid%track_old_lon(i),' lat=',grid%track_old_lat(i),' t=',grid%track_old_ntsd(i)
call to_rot45_grid
(iold,jold,jde,xrot,yrot)
n=n+1
xsum=xsum+xrot
ysum=ysum+yrot
told=grid%track_old_ntsd(i)
tsum=tsum+told
xtsum=xtsum+xrot*told
xxsum=xxsum+xrot*xrot
ytsum=ytsum+yrot*told
yysum=xxsum+yrot*yrot
ttsum=ttsum+told*told
endif
enddo
!print *,'line guess: n=',n
if(n>1) then
ntsd_plus_1 = grid%ntsd + grid%ntrack*grid%nphs
mx=(xtsum-(xsum*tsum)/real(n))/(ttsum-(tsum*tsum)/real(n))
my=(ytsum-(ysum*tsum)/real(n))/(ttsum-(tsum*tsum)/real(n))
bx=(xsum-mx*tsum)/real(n)
by=(ysum-my*tsum)/real(n)
!print *,'mx=',mx,' my=',my,' bx=',bx,' by=',by,' t+1=',ntsd_plus_1
xrot=nint(mx*ntsd_plus_1+bx)
yrot=nint(my*ntsd_plus_1+by)
call from_rot45_grid
(inew,jnew,jde,xrot,yrot)
!print *,'inew=',inew,' jnew=',jnew,' xrot=',xrot,' yrot=',yrot
have_line_guess=.not.(inew<ide/4 .or. inew>ide*3/4 &
.or. jnew<jde/4 .or. jnew>jde*3/4)
else
have_line_guess=.false.
endif
endif
print_locs: if(wrf_at_debug_level(2)) then
call get_lonlat
(grid,iguess,jguess,longuess,latguess,ierr, &
ids,ide, jds,jde, kds,kde, &
ims,ime, jms,jme, kms,kme, &
ips,ipe, jps,jpe, kps,kpe)
if(ierr==0) then
if(have_motion_guess) then
3088 format('Motion Guess: lon=',F0.3,' lat=',F0.3)
write(message,3088) longuess,latguess
call wrf_debug
(2,message)
else
3089 format('Motion Guess failed; use domain center: lon=',F0.3,' lat=',F0.3)
write(message,3089) longuess,latguess
call wrf_debug
(2,message)
endif
else
3090 format('Motion guess ierr=',I0)
write(message,3090) ierr
call wrf_debug
(2,message)
endif
if(have_line_guess) then
call get_lonlat
(grid,inew,jnew,longuess,latguess,ierr, &
ids,ide, jds,jde, kds,kde, &
ims,ime, jms,jme, kms,kme, &
ips,ipe, jps,jpe, kps,kpe)
if(ierr==0) then
3091 format('Line guess: lon=',F0.3,' lat=',F0.3)
write(message,3091) longuess,latguess
call wrf_debug
(2,message)
else
3092 format('Line guess ierr=',I0)
write(message,3092) ierr
call wrf_debug
(2,message)
endif
endif
endif print_locs
if(have_line_guess) then
if(have_motion_guess) then
call wrf_debug
(1,'get_first_ges: have MOTION and LINE guesses')
iguess=(iguess+inew)/2
jguess=(jguess+jnew)/2
else
call wrf_debug
(1,'get_first_ges: have LINE guess only')
iguess=inew
jguess=jnew
endif
elseif(have_motion_guess) then
call wrf_debug
(1,'get_first_ges: have MOTION guess only')
else
call wrf_debug
(1,'get_first_ges: have no guesses; will use domain center')
endif
! Now get lats & lons:
call get_lonlat
(grid,iguess,jguess,longuess,latguess,ierr, &
ids,ide, jds,jde, kds,kde, &
ims,ime, jms,jme, kms,kme, &
ips,ipe, jps,jpe, kps,kpe)
if(ierr/=0) then
! Should never get here due to max/min check before.
call wrf_error_fatal
("ERROR: domain is not inside the domain in get_first_ges (!?)")
endif
38 format('First guess: i=',I0,' j=',I0,' lat=',F8.3,' lon=',F8.3)
write(message,38) iguess,jguess,latguess,longuess
call wrf_message
(message)
end subroutine get_first_ges
subroutine store_old_fixes(grid, &,1
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE)
! This stores old fix locations for later use in the get_first_ges
! routine's line of best fit.
USE MODULE_DOMAIN
, ONLY : domain,get_ijk_from_grid
implicit none
type(domain), intent(inout) :: grid
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 i
if(grid%tracker_havefix) then
!print *,'in store old, have fix'
if(grid%track_n_old>0) then
!print *,'in store old, shifting old'
do i=1,grid%num_old_fixes-1
grid%track_old_lon(i+1)=grid%track_old_lon(i)
grid%track_old_lat(i+1)=grid%track_old_lat(i)
grid%track_old_ntsd(i+1)=grid%track_old_ntsd(i)
enddo
endif
grid%track_old_lon(1)=grid%tracker_fixlon
grid%track_old_lat(1)=grid%tracker_fixlat
grid%track_old_ntsd(1)=grid%ntsd
grid%track_n_old=min(grid%num_old_fixes,grid%track_n_old+1)
!print *,'in store old, now have ',grid%track_n_old
endif
end subroutine store_old_fixes
subroutine to_rot45_grid(i,j,jde,x,y) 2
implicit none
integer, intent(in) :: i,j,jde
real, intent(inout) :: x,y
real :: a,b
a=i*2
b=j
if(mod(j,2)==0) a=a+1
x=(a+b)/2
y=(b-a)/2+((jde-1)/2)
end subroutine to_rot45_grid
subroutine from_rot45_grid(i,j,jde,x,y) 1
implicit none
integer, intent(inout) :: i,j
integer, intent(in) :: jde
real, intent(in) :: x,y
i=x-y+((jde-1)/2)
j=x+y-((jde-1)/2)
if(mod(j,2)==0) then
i=(i-1)/2
else
i=i/2
endif
end subroutine from_rot45_grid
subroutine get_nearest_lonlat(grid,iloc,jloc,ierr,lon,lat, & 3,3
ids,ide, jds,jde, kds,kde, &
ims,ime, jms,jme, kms,kme, &
ips,ipe, jps,jpe, kps,kpe, &
lonnear, latnear)
! Finds the nearest point in the domain to the specified lon,lat
! location.
#ifdef DM_PARALLEL
use module_dm
, only: wrf_dm_minloc_real
#endif
USE MODULE_DOMAIN
, ONLY : domain,get_ijk_from_grid
implicit none
type(domain), intent(inout) :: grid
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(out) :: iloc,jloc,ierr
real, intent(in) :: lon,lat
real :: dx,dy,d,dmin, zdummy, latmin,lonmin
integer :: i,j,imin,jmin
real, intent(out), optional :: latnear, lonnear
zdummy=42
dmin=9e9
imin=-99
jmin=-99
latmin=9e9
lonmin=9e9
ierr=0
do j=jps,min(jde-1,jpe)
do i=ips,min(ide-1,ipe)
dy=abs(lat-grid%hlat(i,j))
dx=abs(mod(3600.+180.+(lon-grid%hlon(i,j)),360.)-180.)
d=dx*dx+dy*dy
if(d<dmin) then
dmin=d
imin=i
jmin=j
latmin=grid%hlat(i,j)
lonmin=grid%hlon(i,j)
endif
enddo
enddo
#ifdef DM_PARALLEL
call wrf_dm_minloc_real
(dmin,latmin,lonmin,zdummy,imin,jmin)
#endif
if(imin<0 .or. jmin<0) then
ierr=-99
else
iloc=imin ; jloc=jmin
endif
if(present(latnear)) latnear=latmin
if(present(lonnear)) lonnear=lonmin
end subroutine get_nearest_lonlat
subroutine output_partial_atcfunix(grid, & 1,1
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
ITS,ITE,JTS,JTE,KTS,KTE)
! This outputs to a format that can be easily converted to ATCF,
! using units used by ATCF.
USE MODULE_DOMAIN
, ONLY : domain,get_ijk_from_grid
implicit none
type(domain), intent(inout) :: grid
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
character*255 message
313 format(F11.2,", ", &
"W10 = ",F7.3," kn, PMIN = ",F8.3," mbar, ", &
"LAT = ",F6.3,A1,", LON = ",F7.3,A1,", ", &
"RMW = ",F7.3," nmi")
write(grid%outatcf_lun,313) grid%dt*grid%ntsd, &
grid%tracker_vmax*mps2kn,grid%tracker_pmin/100., &
abs(grid%tracker_fixlat),get_lat_ns(grid%tracker_fixlat), &
abs(grid%tracker_fixlon),get_lon_ew(grid%tracker_fixlon), &
grid%tracker_rmw*km2nmi
! write(message,313) grid%dt*grid%ntsd, &
! grid%tracker_vmax*mps2kn,grid%tracker_pmin/100., &
! abs(grid%tracker_fixlat),get_lat_ns(grid%tracker_fixlat), &
! abs(grid%tracker_fixlon),get_lon_ew(grid%tracker_fixlon), &
! grid%tracker_rmw*km2nmi
! call wrf_message(message)
end subroutine output_partial_atcfunix
subroutine get_wind_pres_intensity(grid, & 1,9
min_mslp,max_wind,rmw, &
max_wind_search_radius, min_mlsp_search_radius, clon,clat, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
ITS,ITE,JTS,JTE,KTS,KTE)
! This determines the maximum wind, RMW and minimum mslp in the domain.
USE MODULE_DOMAIN
, ONLY : domain,get_ijk_from_grid
#ifdef DM_PARALLEL
use module_dm
, only: wrf_dm_maxval_real,wrf_dm_minval_real
#endif
implicit none
type(domain), intent(inout) :: grid
real, intent(out) :: min_mslp,max_wind,rmw
real, intent(in) :: max_wind_search_radius, min_mlsp_search_radius,clon,clat
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
real :: localextreme,globalextreme, sdistsq,windsq
real :: globallat,globallon,degrees
integer :: locali,localj,globali,globalj,ierr,i,j
! Get the MSLP minimum location and determine if what we found is
! still a storm:
localextreme=9e9
locali=-1
localj=-1
sdistsq=min_mlsp_search_radius*min_mlsp_search_radius*1e6
do j=jts,min(jte,jde-1)
do i=its,min(ite,ide-1)
if(grid%membrane_mslp(i,j)<localextreme .and. &
grid%tracker_distsq(i,j)<sdistsq) then
localextreme=grid%membrane_mslp(i,j)
locali=i
localj=j
endif
enddo
enddo
globalextreme=localextreme
globali=locali
globalj=localj
#ifdef DM_PARALLEL
call wrf_dm_minval_real
(globalextreme,globali,globalj)
#endif
min_mslp=globalextreme
if(globali<0 .or. globalj<0) then
call wrf_message
("WARNING: No membrane mslp values found that were less than 9*10^9.")
min_mslp=-999
endif
! Get the wind maximum location. Note that we're using the square
! of the wind until after the loop to avoid the sqrt() call.
localextreme=-9e9
locali=-1
localj=-1
sdistsq=max_wind_search_radius*max_wind_search_radius*1e6
do j=jts,min(jte,jde-1)
do i=its,min(ite,ide-1)
if(grid%tracker_distsq(i,j)<sdistsq) then
windsq=grid%u10(i,j)*grid%u10(i,j) + &
grid%v10(i,j)*grid%v10(i,j)
if(windsq>localextreme) then
localextreme=windsq
locali=i
localj=j
endif
endif
enddo
enddo
if(localextreme>0) localextreme=sqrt(localextreme)
globalextreme=localextreme
globali=locali
globalj=localj
#ifdef DM_PARALLEL
call wrf_dm_maxval_real
(globalextreme,globali,globalj)
#endif
call get_lonlat
(grid,globali,globalj,globallon,globallat,ierr, &
ids,ide, jds,jde, kds,kde, &
ims,ime, jms,jme, kms,kme, &
its,ite, jts,jte, kts,kte)
if(ierr/=0) then
call wrf_message
("WARNING: Unable to find location of wind maximum.")
rmw=-99
else
call calcdist
(clon,clat,globallon,globallat,rmw,degrees)
end if
! Get the guess location for the next time:
max_wind=globalextreme
if(globali<0 .or. globalj<0) then
call wrf_message
("WARNING: No wind values found that were greater than -9*10^9.")
min_mslp=-999
endif
end subroutine get_wind_pres_intensity
subroutine mean_motion(grid,motion_grideast,motion_gridnorth, & 1,6
ids,ide, jds,jde, kds,kde, &
ims,ime, jms,jme, kms,kme, &
its,ite, jts,jte, kts,kte)
! This calculates the mean motion of the storm by calculating the
! average wind vector at 850, 700 and 500 mbars.
#ifdef DM_PARALLEL
use module_dm
, only: wrf_dm_sum_real8, wrf_dm_sum_integer
#endif
use module_wrf_error
USE MODULE_DOMAIN
, ONLY : domain, domain_clock_get
implicit none
integer, intent(in) :: &
ids,ide, jds,jde, kds,kde, &
ims,ime, jms,jme, kms,kme, &
its,ite, jts,jte, kts,kte
type(domain), intent(in) :: grid
real, intent(out) :: motion_grideast,motion_gridnorth
integer :: count,i,j,ierr
real :: distsq, dist
real*8 :: e,n
e=0 ; n=0 ; count=0 ! east sum, north sum, count
dist = min(grid%tracker_edge_dist, max(50e3, 3e3*grid%tracker_rmw))
distsq = dist * dist
! print *,'motion search radius (m) = ',dist
! print *,' considered edge dist = ',grid%tracker_edge_dist
! print *,' considered 3e3*rmw = ',3e3*grid%tracker_rmw
! print *,' considered 50e3.'
do j=jts,min(jte,jde-1)
do i=its,min(ite,ide-1)
if(grid%tracker_distsq(i,j)<distsq) then
count = count + 3
e = e + (grid%p500u(i,j) + grid%p700u(i,j) + grid%p850u(i,j))
n = n + (grid%p500v(i,j) + grid%p700v(i,j) + grid%p850v(i,j))
endif
enddo
enddo
#ifdef DM_PARALLEL
e=wrf_dm_sum_real8
(e)
n=wrf_dm_sum_real8
(n)
count=wrf_dm_sum_integer
(count)
#endif
motion_grideast=e/count
motion_gridnorth=n/count
! print *,'e=',e,' n=',n,' count=',count
! print *,'motion: east=',motion_grideast,' north=',motion_gridnorth
end subroutine mean_motion
subroutine fixcenter(grid,icen,jcen,calcparm,loncen,latcen, & 1,18
iguess,jguess,longuess,latguess, &
ifinal,jfinal,lonfinal,latfinal, &
north_hemi, &
ids,ide, jds,jde, kds,kde, &
ims,ime, jms,jme, kms,kme, &
ips,ipe, jps,jpe, kps,kpe)
! This is the same as "fixcenter" in gettrk_main. Original comment:
!
! ABSTRACT: This subroutine loops through the different parameters
! for the input storm number (ist) and calculates the
! center position of the storm by taking an average of
! the center positions obtained for those parameters.
! First we check to see which parameters are within a
! max error range (errmax), and we discard those that are
! not within that range. Of the remaining parms, we get
! a mean position, and then we re-calculate the position
! by giving more weight to those estimates that are closer
! to this mean first-guess position estimate.
! Arguments: Input:
! grid - the grid being processed
! icen,jcen - arrays of center gridpoint locations
! calcperm - array of center validity flags (true = center is valid)
! loncen,latcen - center geographic locations
! iguess,jguess - first guess gridpoint location
! longuess,latguess - first guess geographic location
! Arguments: Output:
! ifinal,jfinal - final center gridpoint location
! lonfinal,latfinal - final center geographic location
! Arguments: Optional input:
! north_hemi - true = northern hemisphere, false=south
use module_wrf_error
USE MODULE_DOMAIN
, ONLY : domain, domain_clock_get
implicit none
integer, intent(in) :: &
ids,ide, jds,jde, kds,kde, &
ims,ime, jms,jme, kms,kme, &
ips,ipe, jps,jpe, kps,kpe
type(domain), intent(inout) :: grid
integer, intent(in) :: icen(maxtp), jcen(maxtp)
real, intent(in) :: loncen(maxtp), latcen(maxtp)
logical, intent(inout) :: calcparm(maxtp)
integer, intent(in) :: iguess,jguess
real, intent(in) :: latguess,longuess
integer, intent(inout) :: ifinal,jfinal
real, intent(inout) :: lonfinal,latfinal
logical, intent(in), optional :: north_hemi
character*255 :: message
real :: errdist(maxtp),avgerr,errmax,errinit,xavg_stderr
real :: dist,degrees, total
real :: minutes,hours,trkerr_avg, dist_from_mean(maxtp),wsum
integer :: ip,itot4next,iclose,count,ifound,ierr
integer(kind=8) :: isum,jsum
real :: irsum,jrsum,errtmp,devia,wtpos
real :: xmn_dist_from_mean, stderr_close
logical use4next(maxtp)
! Determine forecast hour:
call domain_clock_get
(grid,minutesSinceSimulationStart=minutes)
hours=minutes/60.
! Decide maximum values for distance and std. dev.:
if(hours<0.5) then
errmax=err_reg_init
errinit=err_reg_init
else
errmax=err_reg_max
errinit=err_reg_max
endif
if(hours>4.) then
xavg_stderr = ( grid%track_stderr_m1 + &
grid%track_stderr_m2 + grid%track_stderr_m3 ) / 3.0
elseif(hours>3.) then
xavg_stderr = ( grid%track_stderr_m1 + grid%track_stderr_m2 ) / 2.0
elseif(hours>2.) then
xavg_stderr = grid%track_stderr_m1
endif
if(hours>2.) then
errtmp = 3.0*xavg_stderr*errpgro
errmax = max(errtmp,errinit)
errtmp = errpmax
errmax = min(errmax,errtmp)
endif
! Initialize loop variables:
errdist=0.0
use4next=.false.
trkerr_avg=0
itot4next=0
iclose=0
isum=0
jsum=0
ifound=0
!write(0,*) 'errpmax=',errpmax
!write(0,*) 'errmax=',errmax
500 format('Parm ip=',I0,' dist=',F0.3)
501 format(' too far, but discard')
do ip=1,maxtp
if(ip==4 .or. ip==6) then
calcparm(ip)=.false.
cycle
elseif(calcparm(ip)) then
ifound=ifound+1
call calcdist
(longuess,latguess,loncen(ip),latcen(ip),dist,degrees)
errdist(ip)=dist
!write(0,500) ip,dist
if(dist<=errpmax) then
if(ip==3 .or. ip==5 .or. ip==10) then
use4next(ip)=.false.
!write(0,'(A)') ' within range but discard: errpmax'
else
!write(0,'(A)') ' within range and keep: errpmax'
use4next(ip)=.true.
trkerr_avg=trkerr_avg+dist
itot4next=itot4next+1
endif
endif
if(dist<=errmax) then
502 format(' apply i=',I0,' j=',I0)
!write(0,502) icen(ip),jcen(ip)
iclose=iclose+1
isum=isum+icen(ip)
jsum=jsum+jcen(ip)
503 format(' added things isum=',I0,' jsum=',I0,' iclose=',I0)
!write(0,503) isum,jsum,iclose
else
!write(0,*) ' discard; too far: errmax'
calcparm(ip)=.false.
endif
endif
enddo
if(ifound<=0) then
call wrf_message
('The tracker could not find the centers for any parameters. Thus,')
call wrf_message
('a center position could not be obtained for this storm.')
goto 999
endif
if(iclose<=0) then
200 format('No storms are within errmax=',F0.1,'km of the parameters')
!write(message,200) errmax
call wrf_message
(message)
goto 999
endif
ifinal=real(isum)/real(iclose)
jfinal=real(jsum)/real(iclose)
504 format(' calculated ifinal, jfinal: ifinal=',I0,' jfinal=',I0,' isum=',I0,' jsum=',I0,' iclose=',I0)
!write(0,504) ifinal,jfinal,isum,jsum,iclose
call get_lonlat
(grid,ifinal,jfinal,lonfinal,latfinal,ierr, &
ids,ide, jds,jde, kds,kde, &
ims,ime, jms,jme, kms,kme, &
ips,ipe, jps,jpe, kps,kpe)
if(ierr/=0) then
call wrf_message
('Gave up on finding the storm location due to error in get_lonlat (1).')
goto 999
endif
count=0
dist_from_mean=0.0
total=0.0
do ip=1,maxtp
if(calcparm(ip)) then
call calcdist
(lonfinal,latfinal,loncen(ip),latcen(ip),dist,degrees)
dist_from_mean(ip)=dist
total=total+dist
count=count+1
endif
enddo
xmn_dist_from_mean=total/real(count)
do ip=1,maxtp
if(calcparm(ip)) then
total=total+(xmn_dist_from_mean-dist_from_mean(ip))**2
endif
enddo
if(count<2) then
stderr_close=0.0
else
stderr_close=max(1.0,sqrt(1./(count-1) * total))
endif
if(calcparm(1) .or. calcparm(2) .or. calcparm(7) .or. &
calcparm(8) .or. calcparm(9) .or. calcparm(11)) then
continue
else
! Message copied straight from tracker:
call wrf_message
('In fixcenter, STOPPING PROCESSING for this storm. The reason is that')
call wrf_message
('none of the fix locations for parms z850, z700, zeta 850, zeta 700')
call wrf_message
('MSLP or sfc zeta were within a reasonable distance of the guess location.')
goto 999
endif
! Recalculate the final center location using weights
if(stderr_close<5.0) then
! Old code forced a minimum of 5.0 stddev
stderr_close=5.0
endif
irsum=0
jrsum=0
wsum=0
do ip=1,maxtp
if(calcparm(ip)) then
devia=max(1.0,dist_from_mean(ip)/stderr_close)
wtpos=exp(-devia/3.)
irsum=icen(ip)*wtpos+irsum
jrsum=jcen(ip)*wtpos+jrsum
wsum=wtpos+wsum
1100 format(' Adding parm: devia=',F0.3,' wtpos=',F0.3,' irsum=',F0.3,' jrsum=',F0.3,' wsum=',F0.3)
!write(0,1100) devia,wtpos,irsum,jrsum,wsum
endif
enddo
ifinal=nint(real(irsum)/real(wsum))
jfinal=nint(real(jrsum)/real(wsum))
call get_lonlat
(grid,ifinal,jfinal,lonfinal,latfinal,ierr, &
ids,ide, jds,jde, kds,kde, &
ims,ime, jms,jme, kms,kme, &
ips,ipe, jps,jpe, kps,kpe)
if(ierr/=0) then
call wrf_message
('Gave up on finding the storm location due to error in get_lonlat (2).')
goto 999
endif
! Store the lat/lon location:
grid%tracker_fixlon=lonfinal
grid%tracker_fixlat=latfinal
grid%tracker_ifix=ifinal
grid%tracker_jfix=jfinal
grid%tracker_havefix=.true.
1000 format('Stored lat/lon at i=',I0,' j=',I0,' lon=',F0.3,' lat=',F0.3)
!write(0,1000) ifinal,jfinal,lonfinal,latfinal
if(nint(hours) > grid%track_last_hour ) then
! It is time to recalculate the std. dev. of the track:
count=0
dist_from_mean=0.0
total=0.0
do ip=1,maxtp
if(calcparm(ip)) then
call calcdist
(lonfinal,latfinal,loncen(ip),loncen(ip),dist,degrees)
dist_from_mean(ip)=dist
total=total+dist
count=count+1
endif
enddo
xmn_dist_from_mean=total/real(count)
do ip=1,maxtp
if(calcparm(ip)) then
total=total+(xmn_dist_from_mean-dist_from_mean(ip))**2
endif
enddo
if(count<2) then
stderr_close=0.0
else
stderr_close=max(1.0,sqrt(1./(count-1) * total))
endif
grid%track_stderr_m3=grid%track_stderr_m2
grid%track_stderr_m2=grid%track_stderr_m1
grid%track_stderr_m1=stderr_close
grid%track_last_hour=nint(hours)
endif
!write(0,*) 'got to return'
return
! We jump here if we're giving up on finding the center
999 continue
! Use domain center as storm location
grid%tracker_ifix=ide/2
grid%tracker_jfix=jde/2
grid%tracker_havefix=.false.
grid%tracker_gave_up=.true.
call get_lonlat
(grid,ifinal,jfinal,lonfinal,latfinal,ierr, &
ids,ide, jds,jde, kds,kde, &
ims,ime, jms,jme, kms,kme, &
ips,ipe, jps,jpe, kps,kpe)
if(ierr/=0) then
call wrf_error_fatal
('Center of domain is not in domain (!?)')
goto 999
endif
grid%tracker_fixlon=-999.0
grid%tracker_fixlat=-999.0
end subroutine fixcenter
subroutine get_uv_guess(grid,icen,jcen,loncen,latcen,calcparm, & 1,3
iguess,jguess,longuess,latguess,iout,jout, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
ITS,ITE,JTS,JTE,KTS,KTE)
! This is a rewrite of the gettrk_main.f get_uv_guess. Original comment:
! ABSTRACT: The purpose of this subroutine is to get a modified
! first guess lat/lon position before searching for the
! minimum in the wind field. The reason for doing this is
! to better refine the guess and avoid picking up a wind
! wind minimum far away from the center. So, use the
! first guess position (and give it strong weighting), and
! then also use the fix positions for the current time
! (give the vorticity centers stronger weighting as well),
! and then take the average of these positions.
! Arguments: Input:
! grid - grid being searched
! icen,jcen - tracker parameter center gridpoints
! loncen,latcen - tracker parameter centers' geographic locations
! calcparm - is each center valid?
! iguess, jguess - first guess gridpoint location
! longuess,latguess - first guess geographic location
! Arguments: Output:
! iout,jout - uv guess center location
USE MODULE_DOMAIN
, ONLY : domain,get_ijk_from_grid
#ifdef DM_PARALLEL
use module_dm
, only: wrf_dm_sum_real
#endif
implicit none
type(domain), intent(inout) :: grid
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
integer, intent(in) :: icen(maxtp), jcen(maxtp)
real, intent(in) :: loncen(maxtp), latcen(maxtp)
logical, intent(in) :: calcparm(maxtp)
integer, intent(in) :: iguess,jguess
real, intent(in) :: latguess,longuess
integer, intent(inout) :: iout,jout
real :: degrees,dist
integer :: ip,ict
integer(kind=8) :: isum,jsum
ict=2
isum=2*iguess
jsum=2*jguess
! Get a guess storm center location for searching for the wind centers:
do ip=1,maxtp
if ((ip > 2 .and. ip < 7) .or. ip == 10) then
cycle ! because 3-6 are for 850 & 700 u & v and 10 is
! for surface wind magnitude.
elseif(calcparm(ip)) then
call calcdist
(longuess,latguess,loncen(ip),latcen(ip),dist,degrees)
if(dist<uverrmax) then
if(ip==1 .or. ip==2 .or. ip==11) then
isum=isum+2*icen(ip)
jsum=jsum+2*jcen(ip)
ict=ict+2
else
isum=isum+icen(ip)
jsum=jsum+jcen(ip)
ict=ict+1
endif
endif
endif
enddo
iout=nint(real(isum)/real(ict))
jout=nint(real(jsum)/real(ict))
end subroutine get_uv_guess
subroutine get_uv_center(grid,orig, & 3,6
iout,jout,rout,calcparm,lonout,latout, &
dxdymean,cparm, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE, &
iuvguess,juvguess)
use module_wrf_error
#ifdef DM_PARALLEL
use module_dm
, only: wrf_dm_minval_real, wrf_dm_maxval_real, wrf_dm_sum_real
#endif
USE MODULE_DOMAIN
, ONLY : domain,get_ijk_from_grid
use module_relax
implicit none
integer, intent(in) :: iuvguess,juvguess
type(domain), intent(inout) :: grid
character*(*), intent(in) :: cparm
real, intent(in) :: dxdymean
real, intent(inout) :: rout
integer, intent(inout) :: iout,jout
logical, intent(inout) :: calcparm
real, intent(inout) :: latout,lonout
real, intent(in) :: orig(ims:ime,jms:jme)
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 :: icen,jcen, i,j, istart,istop, jstart,jstop, ierr
real :: rcen, srsq
! Restrict the search area. By default, we search everywhere except the boundary:
istart=max(ids+1,ips)
istop=min(ide-2,ipe)
jstart=max(jds+2,jps)
jstop=min(jde-3,jpe)
! If the guess location is given, then further restrict the search area:
istart=max(istart,iuvguess-nint(rads_vmag/(2.*dxdymean)))
istop=min(istop,iuvguess+nint(rads_vmag/(2.*dxdymean)))
jstart=max(jstart,juvguess-nint(rads_vmag/(2.*dxdymean)))
jstop=min(jstop,juvguess+nint(rads_vmag/(2.*dxdymean)))
srsq=rads_vmag*rads_vmag*1e6
icen=-99
jcen=-99
rcen=9e9
do j=jstart,jstop
do i=istart,istop
if(orig(i,j)<rcen .and. grid%distsq(i,j)<srsq) then
rcen=orig(i,j)
icen=i
jcen=j
endif
enddo
enddo
#ifdef DM_PARALLEL
call wrf_dm_minval_real
(rcen,icen,jcen)
!write(0,*) 'global',icen,jcen,rcen
#endif
! Return result:
resultif: if(icen==-99 .or. jcen==-99) then
! No center found.
calcparm=.false.
!write(0,*) 'no center found'
else
iout=icen
jout=jcen
rout=rcen
calcparm=.true.
call get_lonlat
(grid,iout,jout,lonout,latout,ierr, &
ids,ide, jds,jde, kds,kde, &
ims,ime, jms,jme, kms,kme, &
ips,ipe, jps,jpe, kps,kpe)
if(ierr/=0) then
!write(0,*) 'bad lonlat'
calcparm=.false.
return
endif
!write(0,*) 'center found; lon=',lonout,' lat=',latout
endif resultif
end subroutine get_uv_center
subroutine find_center(grid,orig,smooth,srsq, & 9,10
iout,jout,rout,calcparm,lonout,latout, &
dxdymean,cparm, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE, &
iuvguess,juvguess,north_hemi)
! This routine replaces the gettrk_main functions find_maxmin and
! get_uv_center.
! Finds the minimum or maximum value of the smoothed version
! (smooth) of the given field (orig). If a center cannot be
! found, sets calcparm=.false., otherwise places the longitude in
! lonout and latitude in latout, gridpoint location in (iout,jout)
! Mandatory arguments:
! grid - grid to search
! orig - field to search
! smooth - smoothed version of the field (smoothed via relax4e)
! iout,jout - center location
! rout - center value (min MSLP, min wind, max or min zeta, etc.)
! calcparm - true if a center was found, false otherwise
! lonout,latout - geographic location of the center
! dxdymean - mean H-to-V gridpoint distance of the entire domain
! cparm - which type of field: zeta, hgt, wind, slp
! srsq - square of the maximum radius from domain center to search
! ids, ..., kpe - grid, memory and patch dimensions
! Optional arguments:
! iuvguess,juvguess - first guess center location to restrict search
! to a subset of the grid.
! north_hemi - we're in the northern hemisphere: true or false?
use module_wrf_error
#ifdef DM_PARALLEL
use module_dm
, only: wrf_dm_minval_real, wrf_dm_maxval_real, wrf_dm_sum_real
#endif
USE MODULE_DOMAIN
, ONLY : domain,get_ijk_from_grid
use module_relax
implicit none
integer, intent(in), optional :: iuvguess,juvguess
type(domain), intent(inout) :: grid
character*(*), intent(in) :: cparm
real, intent(in) :: dxdymean, srsq
real, intent(inout) :: rout
integer, intent(inout) :: iout,jout
logical, intent(inout) :: calcparm
real, intent(inout) :: latout,lonout
real, intent(in) :: orig(ims:ime,jms:jme)
real, intent(out) :: smooth(ims:ime,jms:jme)
character*255 :: message
logical, optional :: north_hemi
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 :: icen,jcen,i,j,ismooth,ierr
real :: rcen, here, sum, mean, cendist, heredist
integer :: istart,istop, jstart,jstop,itemp
logical :: findmin
! Emulate the tracker's barnes analysis with a 1/e iterative smoother:
grid%relaxmask=.false.
do j=max(jds+2,jps),min(jde-3,jpe)
do i=max(ids+2,ips),min(ide-3,ipe)
grid%relaxmask(i,j)=.true.
enddo
enddo
do j=jps,min(jde-1,jpe)
do i=ips,min(ide-1,ipe)
grid%relaxwork(i,j)=orig(i,j)
enddo
enddo
! Decide how many smoother iterations to do based on the parameter
! and grid spacing:
if(trim(cparm)=='wind') then
itemp=nint(1.2*111./(dxdymean*sqrt(2.)))
ismooth=min(30,max(2,itemp))
!write(0,*) 'wind itemp=',itemp,' ismooth=',ismooth,' dxdymean=',dxdymean
elseif(grid%vortex_tracker==6) then
itemp=nint(0.3*111./(dxdymean*sqrt(2.)))
ismooth=min(15,max(1,itemp))
!write(0,*) 'non-wind itemp=',itemp,' ismooth=',ismooth,' dxdymean=',dxdymean
else
itemp=nint(150./(dxdymean*sqrt(2.)))
ismooth=min(50,max(2,itemp))
endif
! Restrict the search area. By default, we search everywhere except the boundary:
istart=max(ids+1,ips)
istop=min(ide-2,ipe)
jstart=max(jds+2,jps)
jstop=min(jde-3,jpe)
! If the guess location is given, then further restrict the search area:
if(present(iuvguess)) then
istart=max(istart,iuvguess-nint(rads_vmag/(2.*dxdymean)))
istop=min(istop,iuvguess+nint(rads_vmag/(2.*dxdymean)))
endif
if(present(juvguess)) then
jstart=max(jstart,juvguess-nint(rads_vmag/(2.*dxdymean)))
jstop=min(jstop,juvguess+nint(rads_vmag/(2.*dxdymean)))
endif
! Call the smoother:
!write(0,*) 'SMOOTH: ',ismooth
call relax4e
(grid,real(0.59539032480831),ismooth,0, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE)
! Copy the smoothed data back in:
do j=jps,min(jde-1,jpe)
do i=ips,min(ide-1,ipe)
smooth(i,j)=grid%relaxwork(i,j)
enddo
enddo
! Figure out whether we're finding a min or max:
ifmin: if(trim(cparm)=='zeta') then
if(.not.present(north_hemi)) then
call wrf_error_fatal
('When calling module_tracker find_center for zeta, you must specify the hemisphere parameter.')
endif
findmin=.not.north_hemi
elseif(trim(cparm)=='hgt') then
findmin=.true.
elseif(trim(cparm)=='slp') then
findmin=.true.
elseif(trim(cparm)=='wind') then
findmin=.true.
else
100 format('Invalid parameter cparm="',A,'" in module_tracker find_center')
!write(message,100) trim(cparm)
call wrf_error_fatal
(message)
endif ifmin
3011 format('ips=',I0,' ipe=',I0,' istart=',I0,' istop=',I0)
3012 format('jps=',I0,' jpe=',I0,' jstart=',I0,' jstop=',I0)
!write(0,3011) ips,ipe,istart,istop
!write(0,3012) jps,jpe,jstart,jstop
! Find the extremum:
icen=-99
jcen=-99
findminmax: if(findmin) then ! Find a minimum
rcen=9e9
do j=jstart,jstop
do i=istart,istop
if(grid%relaxwork(i,j)<rcen .and. grid%distsq(i,j)<srsq) then
rcen=grid%relaxwork(i,j)
icen=i
jcen=j
endif
enddo
enddo
3013 format(A,' minval i=',I0,' j=',I0,' r=',F0.3)
!write(0,3013) 'local',icen,jcen,rcen
#ifdef DM_PARALLEL
call wrf_dm_minval_real
(rcen,icen,jcen)
!write(0,3013) 'global',icen,jcen,rcen
#endif
else ! Find a maximum
3014 format(A,' maxval i=',I0,' j=',I0,' r=',F0.3)
rcen=-9e9
do j=jstart,jstop
do i=istart,istop
if(grid%relaxwork(i,j)>rcen .and. grid%distsq(i,j)<srsq) then
rcen=grid%relaxwork(i,j)
icen=i
jcen=j
endif
enddo
enddo
!write(0,3014) 'local',icen,jcen,rcen
#ifdef DM_PARALLEL
call wrf_dm_maxval_real
(rcen,icen,jcen)
!write(0,3014) 'global',icen,jcen,rcen
#endif
endif findminmax
! Return result:
resultif: if(icen==-99 .or. jcen==-99) then
! No center found.
calcparm=.false.
!write(0,*) 'no center found'
else
iout=icen
jout=jcen
rout=rcen
calcparm=.true.
call get_lonlat
(grid,iout,jout,lonout,latout,ierr, &
ids,ide, jds,jde, kds,kde, &
ims,ime, jms,jme, kms,kme, &
ips,ipe, jps,jpe, kps,kpe)
if(ierr/=0) then
!write(0,*) 'bad lonlat'
calcparm=.false.
return
endif
!write(0,*) 'center found; lon=',lonout,' lat=',latout
endif resultif
end subroutine find_center
subroutine get_tracker_distsq(grid, & 2,8
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
ITS,ITE,JTS,JTE,KTS,KTE)
! This computes approximate distances in km from the tracker
! center of the various points in the domain. It uses the same
! computation as used for distsq: the calculation is done in
! gridpoint space, approximating the domain as flat.
! Point-to-point distances come from grid%dx_nmm and grid%dy_nmm.
! This routine also determines the distance from the tracker
! center location to the nearest point in the domain edge.
#ifdef DM_PARALLEL
use module_dm
, only: wrf_dm_minval_real
#endif
USE MODULE_DOMAIN
, ONLY : domain,get_ijk_from_grid
implicit none
type(domain), intent(inout) :: grid
character*255 message
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
integer i,j,cx,cy,ierr
integer wilbur,harvey ! filler variables for a function call
real xfar,yfar,far,xshift,max_edge_distsq,clatr,clonr
real ylat1,ylat2,xlon1,xlon2,mindistsq
cx=grid%tracker_ifix
cy=grid%tracker_jfix
call get_lonlat
(grid,cx,cy,clonr,clatr,ierr, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
ITS,ITE,JTS,JTE,KTS,KTE)
if(ierr/=0) then
call wrf_error_fatal
('Tracker fix location is not inside domain.')
end if
do j=jts,min(jte,jde-1)
if(mod(j,2)==1) then
xshift=1.
else
xshift=-1.
endif
do i=its,min(ite,ide-1)
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%tracker_distsq(i,j)=far
enddo
enddo
! Determine angle. Note that this is mathematical angle, not
! compass angle, and is in geographic lat/lon, not rotated
! lat/lon. (Geographic East=0, geographic North=pi/2.)
xlon1=clonr ; ylat1=clatr
call clean_lon_lat
(xlon1,ylat1)
xlon1=xlon1*pi180
ylat1=ylat1*pi180
do j=jts,min(jte,jde-1)
do i=its,min(ite,ide-1)
xlon2=grid%glon(i,j)
ylat2=grid%glat(i,j)
call clean_lon_lat
(xlon2,ylat2)
xlon2=xlon2*pi180
ylat2=ylat2*pi180
grid%tracker_angle(i,j)=atan2(xlon2-xlon1,ylat2-ylat1)
enddo
enddo
! Determine the distance between the center location and the
! domain edge.
mindistsq=9e19
if(jts==jds) then
mindistsq=min(mindistsq,minval(grid%tracker_distsq(its:min(ite,ide-1),jds)))
endif
if(jte==jde) then
mindistsq=min(mindistsq,minval(grid%tracker_distsq(its:min(ite,ide-1),jde-1)))
endif
if(its==ids) then
mindistsq=min(mindistsq,minval(grid%tracker_distsq(ids,jts:min(jte,jde-1))))
endif
if(ite==ide) then
mindistsq=min(mindistsq,minval(grid%tracker_distsq(ide-1,jts:min(jte,jde-1))))
endif
#ifdef DM_PARALLEL
wilbur=1
harvey=2
call wrf_dm_minval_real
(mindistsq,wilbur,harvey)
#endif
grid%tracker_edge_dist=sqrt(mindistsq)
17 format('Min distance from lon=',F9.3,', lat=',F9.3,' to center is ',F19.3)
!print *,'Min distance from edge to center is ',grid%tracker_edge_dist
write(message,17) clonr, clatr, grid%tracker_edge_dist
call wrf_message
(message)
end subroutine get_tracker_distsq
subroutine clean_lon_lat(xlon1,ylat1) 2
real, intent(inout) :: xlon1,ylat1
! This modifies a (lat,lon) pair so that the longitude fits
! between [-180,180] and the latitude between [-90,90], taking
! into account spherical geometry.
! NOTE: inputs and outputs are in degrees
xlon1=(mod(xlon1+3600.+180.,360.)-180.)
ylat1=(mod(ylat1+3600.+180.,360.)-180.)
if(ylat1>90.) then
ylat1=180.-ylat1
xlon1=mod(xlon1+360.,360.)-180.
elseif(ylat1<-90.) then
ylat1=-180. - ylat1
xlon1=mod(xlon1+360.,360.)-180.
endif
end subroutine clean_lon_lat
subroutine calcdist(rlonb,rlatb,rlonc,rlatc,xdist,degrees) 6
! Copied from gettrk_main.f
!
! ABSTRACT: This subroutine computes the distance between two
! lat/lon points by using spherical coordinates to
! calculate the great circle distance between the points.
! Figure out the angle (a) between pt.B and pt.C,
! N. Pole then figure out how much of a % of a great
! x circle distance that angle represents.
! / \
! b/ \ cos(a) = (cos b)(cos c) + (sin b)(sin c)(cos A)
! / \ .
! pt./<--A-->\c NOTE: The latitude arguments passed to the
! B / \ subr are the actual lat vals, but in
! \ the calculation we use 90-lat.
! a \ .
! \pt. NOTE: You may get strange results if you:
! C (1) use positive values for SH lats AND
! you try computing distances across the
! equator, or (2) use lon values of 0 to
! -180 for WH lons AND you try computing
! distances across the 180E meridian.
!
! NOTE: In the diagram above, (a) is the angle between pt. B and
! pt. C (with pt. x as the vertex), and (A) is the difference in
! longitude (in degrees, absolute value) between pt. B and pt. C.
!
! !!! NOTE !!! -- THE PARAMETER ecircum IS DEFINED (AS OF THE
! ORIGINAL WRITING OF THIS SYSTEM) IN KM, NOT M, SO BE AWARE THAT
! THE DISTANCE RETURNED FROM THIS SUBROUTINE IS ALSO IN KM.
!
implicit none
real, intent(inout) :: degrees
real, intent(out) :: xdist
real, intent(in) :: rlonb,rlatb,rlonc,rlatc
real, parameter :: dtr = 0.0174532925199433
real :: distlatb,distlatc,pole,difflon,cosanga,circ_fract
!
if (rlatb < 0.0 .or. rlatc < 0.0) then
pole = -90.
else
pole = 90.
endif
!
distlatb = (pole - rlatb) * dtr
distlatc = (pole - rlatc) * dtr
difflon = abs( (rlonb - rlonc)*dtr )
!
cosanga = ( cos(distlatb) * cos(distlatc) + &
sin(distlatb) * sin(distlatc) * cos(difflon))
! This next check of cosanga is needed since I have had ACOS crash
! when calculating the distance between 2 identical points (should
! = 0), but the input for ACOS was just slightly over 1
! (e.g., 1.00000000007), due to (I'm guessing) rounding errors.
if (cosanga > 1.0) then
cosanga = 1.0
endif
degrees = acos(cosanga) / dtr
circ_fract = degrees / 360.
xdist = circ_fract * ecircum
!
! NOTE: whether this subroutine returns the value of the distance
! in km or m depends on the scale of the parameter ecircum.
! At the original writing of this subroutine (7/97), ecircum
! was given in km.
!
return
end subroutine calcdist
! subroutine get_lonlat(grid,iguess,jguess,longuess,latguess, &
! ids,ide, jds,jde, kds,kde, &
! ims,ime, jms,jme, kms,kme, &
! ips,ipe, jps,jpe, kps,kpe)
! ! Returns the latitude (latguess) and longitude (longuess) of the
! ! specified location (iguess,jguess) in the specified grid.
! USE MODULE_DOMAIN, ONLY : domain,get_ijk_from_grid
! USE MODULE_DM, ONLY: wrf_dm_at_ij_real
! implicit none
! integer, intent(in) :: &
! ids,ide, jds,jde, kds,kde, &
! ims,ime, jms,jme, kms,kme, &
! ips,ipe, jps,jpe, kps,kpe
! type(domain), intent(inout) :: grid
! integer, intent(in) :: iguess,jguess
! real, intent(inout) :: longuess,latguess
! call wrf_dm_at_ij_real(grid,iguess,jguess,ims,ime, jms,jme, &
! longuess,grid%hlon, &
! val2=latguess,field2=grid%hlat)
! end subroutine get_lonlat
subroutine get_lonlat(grid,iguess,jguess,longuess,latguess,ierr, & 11,3
ids,ide, jds,jde, kds,kde, &
ims,ime, jms,jme, kms,kme, &
ips,ipe, jps,jpe, kps,kpe)
! Returns the latitude (latguess) and longitude (longuess) of the
! specified location (iguess,jguess) in the specified grid.
USE MODULE_DOMAIN
, ONLY : domain,get_ijk_from_grid
USE MODULE_DM
, ONLY: wrf_dm_maxloc_real
implicit none
integer, intent(in) :: &
ids,ide, jds,jde, kds,kde, &
ims,ime, jms,jme, kms,kme, &
ips,ipe, jps,jpe, kps,kpe
integer, intent(out) :: ierr
type(domain), intent(inout) :: grid
integer, intent(in) :: iguess,jguess
real, intent(inout) :: longuess,latguess
real :: weight,zjunk
integer :: itemp,jtemp
ierr=0
zjunk=1
if(iguess>=ips .and. iguess<=ipe .and. jguess>=jps .and. jguess<=jpe) then
weight=1
longuess=grid%hlon(iguess,jguess)
latguess=grid%hlat(iguess,jguess)
itemp=iguess
jtemp=jguess
else
weight=0
longuess=-999.9
latguess=-999.9
itemp=-99
jtemp=-99
endif
#ifdef DM_PARALLEL
call wrf_dm_maxloc_real
(weight,latguess,longuess,zjunk,itemp,jtemp)
#endif
if(itemp==-99 .and. jtemp==-99) then
ierr=95
endif
end subroutine get_lonlat
subroutine update_tracker_post_move(grid) 1,4
! This updates the tracker i/j fix location and square of the
! distance to the tracker center after a nest move.
USE MODULE_DOMAIN
, ONLY : domain,get_ijk_from_grid
type(domain), intent(inout) :: grid
integer :: ierr, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE
! Get the grid bounds:
CALL get_ijk_from_grid
( grid , &
ids, ide, jds, jde, kds, kde, &
ims, ime, jms, jme, kms, kme, &
ips, ipe, jps, jpe, kps, kpe )
! Get the i/j center location from the fix location:
ierr=0
call get_nearest_lonlat
(grid,grid%tracker_ifix,grid%tracker_jfix, &
ierr,grid%tracker_fixlon,grid%tracker_fixlat, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE)
! Get the square of the approximate distance to the tracker center
! at all points:
if(ierr==0) &
call get_tracker_distsq
(grid, &
IDS,IDE,JDS,JDE,KDS,KDE, &
IMS,IME,JMS,JME,KMS,KME, &
IPS,IPE,JPS,JPE,KPS,KPE)
end subroutine update_tracker_post_move
#endif
end module module_tracker
#if (HWRF == 1)
subroutine nmm_med_tracker_post_move(grid) 1,3
! This updates the tracker i/j fix location and square of the
! distance to the tracker center after a nest move.
use module_tracker
, only: update_tracker_post_move
use module_domain
, only : domain
type(domain), intent(inout) :: grid
call update_tracker_post_move
(grid)
end subroutine nmm_med_tracker_post_move
#endif