!----------------------------------------------------------------------- !BOP ! !ROUTINE: epvd --- Calculate absolute potential vorticity ! ! !INTERFACE: subroutine epvd( grid, u, v, pt, delp, grav, ae, omega, epv ),12 ! !USES: use shr_kind_mod, only : r8 => shr_kind_r8 use mapz_module, only : ppme use dynamics_vars, only : T_FVDYCORE_GRID #if defined( SPMD ) use parutilitiesmodule, only: sumop, parcollective use mod_comm, only : gid, mp_send3d, mp_recv3d #endif implicit none ! !INPUT PARAMETERS: type (T_FVDYCORE_GRID), intent(in) :: grid ! grid (for XY decomp) real (r8) :: u(grid%ifirstxy:grid%ilastxy,grid%jfirstxy:grid%jlastxy,grid%km) real (r8) :: v(grid%ifirstxy:grid%ilastxy,grid%jfirstxy:grid%jlastxy,grid%km) real (r8) :: pt(grid%ifirstxy:grid%ilastxy,grid%jfirstxy:grid%jlastxy,grid%km) real (r8) :: delp(grid%ifirstxy:grid%ilastxy,grid%jfirstxy:grid%jlastxy,grid%km) real(r8), intent(in) :: GRAV ! Constants, passed as arguments to real(r8), intent(in) :: AE ! ensure portability between real(r8), intent(in) :: OMEGA ! CAM and GEOS5 ! !OUTPUT PARAMETERS: real(r8) epv(grid%ifirstxy:grid%ilastxy,grid%jfirstxy:grid%jlastxy,grid%km) ! !DESCRIPTION: ! Compute absolute vorticity on the D grid ! epv = -g * (vort+f0)*dpt/dp ! ! !REVISION HISTORY: ! WS 99.11.02 Documentation; indentation; jfirstxy:jlastxy ! WS 00.07.08 Use precision module; Kevin's ghost indices ! WS 05.02.16 Rewritten for FVdycore_GridCompMod, XY decomposition ! WS 05.05.25 Add constants to avoid dependencies on GEOS_Mod ! ! !BUGS: ! Not yet tested... ! !EOP !--------------------------------------------------------------------- !BOC real(r8), parameter :: D0_0 = 0.0_r8 real(r8), parameter :: D1_0 = 1.0_r8 real(r8), parameter :: D2_0 = 2.0_r8 real(r8) :: te(grid%ifirstxy:grid%ilastxy,grid%jfirstxy:grid%jlastxy,grid%km+1) real(r8) :: te2(grid%ifirstxy:grid%ilastxy,grid%km+1) real(r8) :: t2(grid%ifirstxy:grid%ilastxy,grid%km) real(r8) :: delp2(grid%ifirstxy:grid%ilastxy,grid%km) real(r8) :: fx(grid%ifirstxy:grid%ilastxy,grid%jfirstxy:grid%jlastxy+1) real(r8) :: fy(grid%ifirstxy:grid%ilastxy,grid%jfirstxy:grid%jlastxy) ! Geometric arrays real(r8) :: rdx(grid%jfirstxy:grid%jlastxy) ! 1 / ae*cos(\theta)* dtheta real(r8) :: cy(grid%jfirstxy:grid%jlastxy) ! 1 / ae*cos(\theta)* dlam integer :: i, j, k, js2g0, jn2g0 integer :: iam, myidxy_y, nprxy_x, nprxy_y, dest, src ! SPMD related integer :: im, jm, km ! problem dimensions integer :: ifirstxy, ilastxy, jfirstxy, jlastxy ! This PE's intervals real(r8) :: c1, c2, rdy real(r8), allocatable :: veast(:,:) ! East halo real(r8), allocatable :: unorth(:,:) ! North halo real(r8), allocatable :: fx_sp(:,:), fx_np(:,:) real(r8), allocatable :: f0(:) ! Coriolis force real(r8), allocatable :: vort(:,:) ! Relative vorticity im = grid%im jm = grid%jm km = grid%km ifirstxy = grid%ifirstxy ilastxy = grid%ilastxy jfirstxy = grid%jfirstxy jlastxy = grid%jlastxy iam = grid%iam myidxy_y = grid%myidxy_y nprxy_x = grid%nprxy_x nprxy_y = grid%nprxy_y js2g0 = max(2,jfirstxy) jn2g0 = min(jm-1,jlastxy) allocate(veast(jfirstxy:jlastxy,km)) ! East halo allocate(unorth(ifirstxy:ilastxy,km)) ! North halo allocate(fx_sp(im,km), fx_np(im,km) ) allocate(f0(jfirstxy:jlastxy)) ! Coriolis force allocate(vort(ifirstxy:ilastxy,jfirstxy:jlastxy)) ! Relative vorticity ! Geometric factors do j=jfirstxy,jlastxy f0(j) = D2_0*omega*grid%sinp(j) enddo rdy = D1_0/(ae*grid%dp) do j=js2g0,jn2g0 rdx(j) = D1_0/(grid%dl*ae*grid%cosp(j)) cy(j) = rdy / grid%cosp(j) enddo unorth = D0_0 ! Periodic boundary (for the case of no decomposition in X) do k=1,km do j=jfirstxy,jlastxy veast(j,k) = v(ifirstxy,j,k) enddo enddo #if defined( SPMD ) if (nprxy_y > 1) then ! Nontrivial y decomposition call mp_send3d( grid%commxy, iam-nprxy_x, iam+nprxy_x, im, jm, km, & ifirstxy, ilastxy, jfirstxy, jlastxy, 1, km, & ifirstxy, ilastxy, jfirstxy, jfirstxy, 1, km, u ) endif if (nprxy_x > 1) then ! Nontrivial x decomposition dest = myidxy_y*nprxy_x + MOD(iam+nprxy_x-1,nprxy_x) src = myidxy_y*nprxy_x + MOD(iam+1,nprxy_x) call mp_send3d( grid%commxy, dest, src, im, jm, km, & ifirstxy, ilastxy, jfirstxy, jlastxy, 1,km, & ifirstxy, ifirstxy, jfirstxy, jlastxy, 1, km, v ) endif #endif ! Compute PT at layer edges. !$omp parallel do & !$omp default(shared) & !$omp private(i,j,k,t2,delp2,te2) do 1000 j=jfirstxy,jlastxy do k=1,km do i=ifirstxy,ilastxy t2(i,k) = pt(i,j,k) delp2(i,k) = delp(i,j,k) enddo enddo call ppme(t2,te2,delp2,ilastxy-ifirstxy+1,km) do k=1,km+1 do i=ifirstxy,ilastxy te(i,j,k) = te2(i,k) enddo enddo 1000 continue ! ! Prepare sum of U-winds for vorticities at pole ! fx_sp = D0_0 fx_np = D0_0 !$omp parallel do & !$omp default(shared) & !$omp private(i,k) do k=1,km if ( jfirstxy == 1 ) then ! SP do i=ifirstxy,ilastxy fx_sp(i,k) = u(i,2,k)*grid%cose(2) enddo endif if ( jlastxy == jm ) then ! NP do i=ifirstxy,ilastxy fx_np(i,k) = u(i,jm,k)*grid%cose(jm) enddo endif enddo #if defined( SPMD ) if ( nprxy_y > 1 ) then ! Non-trivial Y decomposition call mp_recv3d( grid%commxy, iam+nprxy_x, im, jm, km, & ifirstxy, ilastxy, jlastxy+1, jlastxy+1, 1, km, & ifirstxy, ilastxy, jlastxy+1, jlastxy+1, 1, km, unorth ) endif if ( nprxy_x > 1 ) then ! Non-trivial X decomposition call mp_recv3d( grid%commxy, src, im, jm, km, & ilastxy+1, ilastxy+1, jfirstxy, jlastxy, 1, km, & ilastxy+1, ilastxy+1, jfirstxy, jlastxy, 1, km, veast ) endif #endif #if defined( SPMD ) ! ! Collect on all PETs the weighted U-winds at both poles ! if (nprxy_x > 1) then call parcollective(grid%commxy_x, sumop, im, km, fx_sp) call parcollective(grid%commxy_x, sumop, im, km, fx_np) endif #endif !$omp parallel do & !$omp default(shared) & !$omp private(i,j,k,fx,fy,vort,c1,c2) do 2000 k=1,km ! Compute relative vorticity do j=js2g0,jlastxy do i=ifirstxy,ilastxy fx(i,j) = u(i,j,k)*grid%cose(j) enddo enddo if ( jlastxy < jm ) then do i=ifirstxy,ilastxy fx(i,jlastxy+1) = unorth(i,k)*grid%cose(jlastxy+1) enddo endif do j=js2g0,jn2g0 do i=ifirstxy,ilastxy-1 fy(i,j) = v(i+1,j,k) - v(i,j,k) enddo enddo do j=js2g0,jn2g0 fy(ilastxy,j) = veast(j,k) - v(ilastxy,j,k) enddo do j=js2g0,jn2g0 do i=ifirstxy,ilastxy vort(i,j) = (fx(i,j)-fx(i,j+1))*cy(j) + fy(i,j)*rdx(j) enddo enddo ! Vort at poles computed by circulation theorem if ( jfirstxy == 1 ) then c1 = -SUM(fx_sp(1:im,k))*rdy*grid%rcap do i=ifirstxy,ilastxy vort(i, 1) = c1 enddo endif if ( jlastxy == jm ) then c2 = SUM(fx_np(1:im,k))*rdy*grid%rcap do i=ifirstxy,ilastxy vort(i,jm) = c2 enddo endif do j=jfirstxy,jlastxy do i=ifirstxy,ilastxy ! Entropy is the thermodynamic variable in the following formulation. epv(i,j,k) = grav*(vort(i,j)+f0(j))*(te(i,j,k)-te(i,j,k+1)) & / (pt(i,j,k)*delp(i,j,k)) enddo enddo !!! write(iulog,*) "k", k, ifirstxy, jfirstxy, "minmax epv", minval(epv(:,:,k)), & !!! maxval(epv(:,:,k)), minloc(epv(:,:,k)), maxloc(epv(:,:,k)) 2000 continue deallocate(veast) deallocate(unorth) deallocate(fx_sp,fx_np) deallocate(f0) deallocate(vort) return end