!----------------------------------------------------------------------- ! ! BOP ! ! !MODULE: module diag_module 1 ! ! !DESCRIPTION ! Utilities which perform special calculations for diagnostics ! Currently only compute\_vdot\_grad to calculate total derivative ! ! !PUBLIC MEMBER FUNCTIONS public :: compute_vdot_gradp ! !REVISION HISTORY: ! 05.09.10 Rasch Creation of compute_vdot_gradp ! 05.10.18 Sawyer Revisions for 2D decomp, placed in module ! 07.01.29 Chen Removed pft2d calculation for OMGA (is in cd_core) ! ! EOP !----------------------------------------------------------------------- private CONTAINS subroutine compute_vdot_gradp(grid, dt, frac, cx, cy, pexy, omgaxy ) 1,13 use shr_kind_mod, only : r8 => shr_kind_r8 use dynamics_vars, only : T_FVDYCORE_GRID #if defined( SPMD ) use mod_comm, only: mp_send3d, mp_recv3d, & mp_sendirr, mp_recvirr #endif implicit none ! !INPUT PARAMETERS: type (T_FVDYCORE_GRID), intent(in) :: grid real(r8), intent(in):: dt real(r8), intent(in):: frac real(r8), intent(in):: cx(grid%im,grid%jfirst:grid%jlast,grid%kfirst:grid%klast) real(r8), intent(in):: cy(grid%im,grid%jfirst:grid%jlast+1,grid%kfirst:grid%klast) real(r8), target, intent(in):: & pexy(grid%ifirstxy:grid%ilastxy,grid%km+1,grid%jfirstxy:grid%jlastxy) ! P (pascal) at layer edges real(r8), target, intent(inout):: & omgaxy(grid%ifirstxy:grid%ilastxy,grid%km,grid%jfirstxy:grid%jlastxy) ! vert. press. velocity (pa/sec) ! Local integer :: im ! dimension in east-west integer :: jm ! dimension in North-South integer :: km ! number of Lagrangian layers integer :: jfirst ! starting latitude index for MPI integer :: jlast ! ending latitude index for MPI integer :: kfirst ! starting level index for MPI integer :: klast ! ending level index for MPI integer :: js2g0 ! j==1 not included integer :: jn2g0 ! j==jm not included real(r8) :: pm(grid%im, grid%jfirst-1:grid%jlast+1) real(r8) :: grad(grid%im, grid%jfirst:grid%jlast+1) real(r8) :: fac, sum1 real(r8), pointer :: pe(:,:,:) ! YZ version of edge pressures real(r8), pointer :: omga(:,:,:) ! YZ version of vert. vel. real(r8), parameter :: half = 0.5_r8 real(r8), parameter :: zero = 0.0_r8 integer :: i,j,k #if defined( SPMD ) integer :: iam, dest, src, npr_y, npes_yz real(r8) :: penorth(grid%im, grid%kfirst:grid%klast+1) real(r8) :: pesouth(grid%im, grid%kfirst:grid%klast+1) #endif im = grid%im jm = grid%jm km = grid%km jfirst = grid%jfirst jlast = grid%jlast kfirst = grid%kfirst klast = grid%klast js2g0 = grid%js2g0 jn2g0 = grid%jn2g0 fac = half / (dt * frac) #if defined( SPMD ) if ( grid%twod_decomp == 1 ) then allocate(pe(im,kfirst:klast+1,jfirst:jlast)) allocate(omga(im,kfirst:klast,jfirst:jlast)) call mp_sendirr( grid%commxy, grid%ikj_xy_to_yz%SendDesc, & grid%ikj_xy_to_yz%RecvDesc, omgaxy, omga, & modc=grid%modc_dynrun ) call mp_recvirr( grid%commxy, grid%ikj_xy_to_yz%SendDesc, & grid%ikj_xy_to_yz%RecvDesc, omgaxy, omga, & modc=grid%modc_dynrun ) call mp_sendirr( grid%commxy, grid%pexy_to_pe%SendDesc, & grid%pexy_to_pe%RecvDesc, pexy, pe, & modc=grid%modc_dynrun ) call mp_recvirr( grid%commxy, grid%pexy_to_pe%SendDesc, & grid%pexy_to_pe%RecvDesc, pexy, pe, & modc=grid%modc_dynrun ) else pe => pexy omga => omgaxy endif iam = grid%iam npes_yz = grid%npes_yz if (iam .lt. npes_yz) then npr_y = grid%npr_y dest = iam+1 src = iam-1 if ( mod(iam+1,npr_y) == 0 ) dest = -1 if ( mod(iam,npr_y) == 0 ) src = -1 ! ! Have to give more thought to the source and destination for 2D ! call mp_send3d(grid%commyz, dest, src, im, km+1, jm, & 1, im, kfirst, klast+1, jfirst, jlast, & 1, im, kfirst, klast+1, jlast, jlast, pe) call mp_recv3d(grid%commyz, src, im, km+1, jm, & 1, im, kfirst, klast+1, jfirst-1, jfirst-1, & 1, im, kfirst, klast+1, jfirst-1, jfirst-1, pesouth) call mp_send3d(grid%commyz, src, dest, im, km+1, jm, & 1, im, kfirst, klast+1, jfirst, jlast, & 1, im, kfirst, klast+1, jfirst, jfirst, pe) call mp_recv3d(grid%commyz, dest, im, km+1, jm, & 1, im, kfirst, klast+1, jlast+1, jlast+1, & 1, im, kfirst, klast+1, jlast+1, jlast+1, penorth) end if ! (iam .lt. npes_yz) #else pe => pexy omga => omgaxy #endif !$omp parallel do private(i,j,k,pm,grad, sum1) do k=kfirst,klast ! Compute layer mean p do j=jfirst,jlast do i=1,im pm(i,j) = half * ( pe(i,k,j) + pe(i,k+1,j) ) enddo enddo #if defined( SPMD ) if ( jfirst/=1 ) then do i=1,im pm(i,jfirst-1) = half * ( pesouth(i,k) + pesouth(i,k+1)) enddo endif if ( jlast/=jm ) then do i=1,im pm(i,jlast+1) = half * ( penorth(i,k) + penorth(i,k+1)) enddo endif #endif do j=js2g0,jn2g0 i=1 grad(i,j) = fac * cx(i,j,k) * (pm(i,j)-pm(im,j)) do i=2,im grad(i,j) = fac * cx(i,j,k) * (pm(i,j)-pm(i-1,j)) enddo enddo do j=js2g0,jn2g0 do i=1,im-1 omga(i,k,j) = omga(i,k,j) + grad(i,j) + grad(i+1,j) enddo i=im omga(i,k,j) = omga(i,k,j) + grad(i,j) + grad(1,j) enddo do j=js2g0,min(jm,jlast+1) do i=1,im grad(i,j) = fac * cy(i,j,k) * (pm(i,j)-pm(i,j-1)) enddo enddo do j=js2g0,jn2g0 do i=1,im omga(i,k,j) = omga(i,k,j) + grad(i,j) + grad(i,j+1) enddo enddo ! Note: Since V*grad(P) at poles are harder to compute accurately we use the average of sourding points ! to be used as input to physics. if ( jfirst==1 ) then sum1 = zero do i=1,im sum1 = sum1 + omga(i,k,2) enddo sum1 = sum1 / real(im,r8) do i=1,im omga(i,k,1) = sum1 enddo endif if ( jlast==jm ) then sum1 = zero do i=1,im sum1 = sum1 + omga(i,k,jm-1) enddo sum1 = sum1 / real(im,r8) do i=1,im omga(i,k,jm) = sum1 enddo endif enddo #if defined( SPMD) if ( grid%twod_decomp == 1 ) then ! ! Transpose back to XY (if 1D, the changes to omgaxy were made in place) ! call mp_sendirr( grid%commxy, grid%ikj_yz_to_xy%SendDesc, & grid%ikj_yz_to_xy%RecvDesc, omga, omgaxy, & modc=grid%modc_dynrun ) call mp_recvirr( grid%commxy, grid%ikj_yz_to_xy%SendDesc, & grid%ikj_yz_to_xy%RecvDesc, omga, omgaxy, & modc=grid%modc_dynrun ) deallocate( pe ) deallocate( omga ) endif #endif end subroutine compute_vdot_gradp end module diag_module