LCOV - code coverage report
Current view: top level - dynamics/se - gravity_waves_sources.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 107 119 89.9 %
Date: 2025-03-13 19:18:33 Functions: 5 5 100.0 %

          Line data    Source code
       1             : module gravity_waves_sources
       2             :   use derivative_mod, only: derivative_t
       3             :   use dimensions_mod, only: np,nlev
       4             :   use edgetype_mod,   only: EdgeBuffer_t
       5             :   use element_mod,    only: element_t
       6             :   use hybrid_mod,     only: hybrid_t
       7             :   use shr_kind_mod,   only: r8 => shr_kind_r8
       8             : 
       9             :   implicit none
      10             :   private
      11             :   save
      12             : 
      13             :   !! gravity_waves_sources created by S Santos, 10 Aug 2011
      14             :   !!
      15             :   !! gws_src_fnct starts parallel environment and computes frontogenesis
      16             :   !!   for use by WACCM (via dp_coupling)
      17             : 
      18             :   public  :: gws_src_fnct
      19             :   public  :: gws_src_vort
      20             :   public  :: gws_init
      21             :   private :: compute_frontogenesis
      22             :   private :: compute_vorticity_4gw
      23             : 
      24             :   type (EdgeBuffer_t) :: edge3,edge1
      25             :   type (derivative_t)   :: deriv
      26             :   real(r8) :: psurf_ref
      27             : 
      28             : !----------------------------------------------------------------------
      29             : CONTAINS
      30             : !----------------------------------------------------------------------
      31             : 
      32       26880 :   subroutine gws_init(elem)
      33             :     use parallel_mod, only   : par
      34             :     use edge_mod, only       : initEdgeBuffer
      35             :     use hycoef, only         : hypi
      36             :     use pmgrid, only         : plev
      37             :     use thread_mod, only     : horz_num_threads
      38             :     implicit none
      39             : 
      40             :     ! Elem will be needed for future updates to edge code
      41             :     type(element_t), pointer :: elem(:)
      42             : 
      43             :     ! Set up variables similar to dyn_comp and prim_driver_mod initializations
      44        2304 :     call initEdgeBuffer(par, edge3, elem, 3*nlev,nthreads=1)
      45        2304 :     call initEdgeBuffer(par, edge1, elem, nlev,nthreads=1)
      46             : 
      47        2304 :     psurf_ref = hypi(plev+1)
      48             : 
      49        2304 :   end subroutine gws_init
      50             : 
      51       24576 :   subroutine gws_src_fnct(elem, tl, tlq, frontgf, frontga, nphys)
      52        2304 :     use derivative_mod, only  : derivinit
      53             :     use dimensions_mod, only  : nelemd
      54             :     use dof_mod, only         : UniquePoints
      55             :     use hybrid_mod, only      : config_thread_region, get_loop_ranges
      56             :     use parallel_mod, only    : par
      57             :     use ppgrid, only          : pver
      58             :     use thread_mod, only      : horz_num_threads
      59             :     use dimensions_mod, only  : fv_nphys
      60             :     use cam_abortutils, only  : handle_allocate_error
      61             : 
      62             :     implicit none
      63             :     type (element_t), intent(inout), dimension(:) :: elem
      64             :     integer, intent(in)          :: tl, nphys, tlq
      65             :     real (kind=r8), intent(out) :: frontgf(nphys*nphys,pver,nelemd)
      66             :     real (kind=r8), intent(out) :: frontga(nphys*nphys,pver,nelemd)
      67             : 
      68             : 
      69             :     ! Local variables
      70             :     type (hybrid_t) :: hybrid
      71             :     integer :: nets, nete, ithr, ncols, ie, ierr
      72       24576 :     real(kind=r8), allocatable  ::  frontgf_thr(:,:,:,:)
      73       24576 :     real(kind=r8), allocatable  ::  frontga_thr(:,:,:,:)
      74             : 
      75             : 
      76             :     ! This does not need to be a thread private data-structure
      77       24576 :     call derivinit(deriv)
      78             :     !!$OMP PARALLEL NUM_THREADS(horz_num_threads),  DEFAULT(SHARED), PRIVATE(nets,nete,hybrid,ie,ncols,frontgf_thr,frontga_thr)
      79       24576 :     hybrid = config_thread_region(par,'serial')
      80       24576 :     call get_loop_ranges(hybrid,ibeg=nets,iend=nete)
      81             : 
      82      147456 :     allocate(frontgf_thr(nphys,nphys,nlev,nets:nete), stat=ierr)
      83       24576 :     call handle_allocate_error(ierr, 'gws_src_fnct', 'frontgf_thr')
      84             : 
      85      122880 :     allocate(frontga_thr(nphys,nphys,nlev,nets:nete), stat=ierr)
      86       24576 :     call handle_allocate_error(ierr, 'gws_src_fnct', 'frontga_thr')
      87             : 
      88             : 
      89       24576 :     call compute_frontogenesis(frontgf_thr,frontga_thr,tl,tlq,elem,deriv,hybrid,nets,nete,nphys)
      90             : 
      91       24576 :     if (fv_nphys>0) then
      92      197376 :       do ie=nets,nete
      93      518400 :         frontgf(:,:,ie) = RESHAPE(frontgf_thr(:,:,:,ie),(/nphys*nphys,nlev/))
      94      542976 :         frontga(:,:,ie) = RESHAPE(frontga_thr(:,:,:,ie),(/nphys*nphys,nlev/))
      95             :       end do
      96             :     else
      97           0 :       do ie=nets,nete
      98           0 :         ncols = elem(ie)%idxP%NumUniquePts
      99           0 :         call UniquePoints(elem(ie)%idxP, nlev, frontgf_thr(:,:,:,ie), frontgf(1:ncols,:,ie))
     100           0 :         call UniquePoints(elem(ie)%idxP, nlev, frontga_thr(:,:,:,ie), frontga(1:ncols,:,ie))
     101             :       end do
     102             :     end if
     103       24576 :     deallocate(frontga_thr)
     104       24576 :     deallocate(frontgf_thr)
     105             : 
     106             :     !!$OMP END PARALLEL
     107             : 
     108       49152 :   end subroutine gws_src_fnct
     109             : 
     110             :   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     111       24576 :   subroutine gws_src_vort(elem, tl, tlq, vort4gw, nphys)
     112       24576 :     use derivative_mod, only  : derivinit
     113             :     use dimensions_mod, only  : nelemd
     114             :     use dof_mod, only         : UniquePoints
     115             :     use hybrid_mod, only      : config_thread_region, get_loop_ranges
     116             :     use parallel_mod, only    : par
     117             :     use ppgrid, only          : pver
     118             :     use thread_mod, only      : horz_num_threads
     119             :     use dimensions_mod, only  : fv_nphys
     120             :     use cam_abortutils, only  : handle_allocate_error
     121             : 
     122             :     implicit none
     123             :     type (element_t), intent(in), dimension(:) :: elem
     124             :     integer, intent(in)          :: tl, nphys, tlq
     125             : 
     126             :     !
     127             :     real (kind=r8), intent(out) :: vort4gw(nphys*nphys,pver,nelemd)
     128             : 
     129             :     ! Local variables
     130             :     type (hybrid_t) :: hybrid
     131             :     integer :: nets, nete, ithr, ncols, ie, ierr
     132             : 
     133             :     !
     134       24576 :     real(kind=r8), allocatable  ::  vort4gw_thr(:,:,:,:)
     135             : 
     136             :     ! This does not need to be a thread private data-structure
     137       24576 :     call derivinit(deriv)
     138             :     !!$OMP PARALLEL NUM_THREADS(horz_num_threads),  DEFAULT(SHARED), PRIVATE(nets,nete,hybrid,ie,ncols,vort4gw_thr)
     139       24576 :     hybrid = config_thread_region(par,'serial')
     140       24576 :     call get_loop_ranges(hybrid,ibeg=nets,iend=nete)
     141             : 
     142      147456 :     allocate(vort4gw_thr(nphys,nphys,nlev,nets:nete), stat=ierr)
     143       24576 :     call handle_allocate_error(ierr, 'gws_src_vort', 'vort4gw_thr')
     144             : 
     145       24576 :     call compute_vorticity_4gw(vort4gw_thr,tl,tlq,elem,deriv,hybrid,nets,nete,nphys)
     146             : 
     147       24576 :     if (fv_nphys>0) then
     148      197376 :       do ie=nets,nete
     149      542976 :         vort4gw(:,:,ie) = RESHAPE(vort4gw_thr(:,:,:,ie),(/nphys*nphys,nlev/))
     150             :       end do
     151             :     else
     152           0 :       do ie=nets,nete
     153           0 :         ncols = elem(ie)%idxP%NumUniquePts
     154           0 :         call UniquePoints(elem(ie)%idxP, nlev, vort4gw_thr(:,:,:,ie), vort4gw(1:ncols,:,ie))
     155             :       end do
     156             :     end if
     157       24576 :     deallocate(vort4gw_thr)
     158             : 
     159             :     !!$OMP END PARALLEL
     160             : 
     161       49152 :   end subroutine gws_src_vort
     162             : 
     163       24576 :   subroutine compute_vorticity_4gw(vort4gw,tl,tlq,elem,ederiv,hybrid,nets,nete,nphys)
     164             :   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     165             :   ! compute vorticity for use in gw params
     166             :   !   F = ( curl ) [U,V]
     167             :   !
     168             :   ! Original by Peter Lauritzen, Julio Bacmeister*, Dec 2024
     169             :   ! Patterned on 'compute_frontogenesis'
     170             :   !
     171             :   ! * corresponding/blame-able
     172             :   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     173       24576 :     use derivative_mod, only: vorticity_sphere
     174             :     use edge_mod,       only: edgevpack, edgevunpack
     175             :     use bndry_mod,      only: bndry_exchange
     176             :     use dimensions_mod, only: fv_nphys
     177             :     use fvm_mapping,    only: dyn2phys
     178             : 
     179             :     type(hybrid_t),     intent(in)            :: hybrid
     180             :     type(element_t),    intent(in)            :: elem(:)
     181             :     type(derivative_t), intent(in)            :: ederiv
     182             :     integer,            intent(in)            :: nets,nete,nphys
     183             :     integer,            intent(in)            :: tl,tlq
     184             :     real(r8),           intent(out)           :: vort4gw(nphys,nphys,nlev,nets:nete)
     185             : 
     186             :     ! local
     187       49152 :     real(r8) :: area_inv(fv_nphys,fv_nphys), tmp(np,np)
     188       49152 :     real(r8) :: vort_gll(np,np,nlev,nets:nete)
     189             :     integer  :: k,kptr,i,j,ie,component,h,nq,m_cnst,n0
     190             : 
     191             :     !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     192             :     ! First calculate vorticity on GLL grid
     193             :     !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     194             :     ! set timelevel=1 fro velocities
     195       24576 :     n0=tl
     196      197376 :     do ie=nets,nete
     197    16243200 :        do k=1,nlev
     198    16243200 :           call vorticity_sphere(elem(ie)%state%v(:,:,:,k,n0),ederiv,elem(ie),vort_gll(:,:,k,ie))
     199             :        end do
     200    16243200 :        do k=1,nlev
     201   337651200 :           vort_gll(:,:,k,ie) = vort_gll(:,:,k,ie)*elem(ie)%spheremp(:,:)
     202             :        end do
     203             :        ! pack
     204      197376 :        call edgeVpack(edge1, vort_gll(:,:,:,ie),nlev,0,ie)
     205             :     enddo
     206       24576 :     call bndry_exchange(hybrid,edge1,location='compute_vorticity_4gw')
     207      197376 :     do ie=nets,nete
     208      172800 :        call edgeVunpack(edge1, vort_gll(:,:,:,ie),nlev,0,ie)
     209             :        ! apply inverse mass matrix,
     210    16243200 :        do k=1,nlev
     211   337651200 :           vort_gll(:,:,k,ie) = vort_gll(:,:,k,ie)*elem(ie)%rspheremp(:,:)
     212             :        end do
     213             : 
     214             :        !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     215             :        ! Now regrid from GLL to PhysGrid if necessary
     216             :        ! otherwise just return vorticity on GLL grid
     217             :        !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     218      197376 :        if (fv_nphys>0) then
     219     3628800 :           tmp = 1.0_r8
     220      172800 :           area_inv = dyn2phys(tmp,elem(ie)%metdet)
     221     2246400 :           area_inv = 1.0_r8/area_inv
     222    16243200 :           do k=1,nlev
     223    16243200 :              vort4gw(:,:,k,ie) = dyn2phys( vort_gll(:,:,k,ie) , elem(ie)%metdet , area_inv )
     224             :           end do
     225             :        else
     226           0 :           do k=1,nlev
     227           0 :              vort4gw(:,:,k,ie) = vort_gll(:,:,k,ie)
     228             :           end do
     229             :        end if
     230             :     enddo
     231             : 
     232             : 
     233       24576 :   end subroutine compute_vorticity_4gw
     234             : 
     235             : 
     236       24576 :   subroutine compute_frontogenesis(frontgf,frontga,tl,tlq,elem,ederiv,hybrid,nets,nete,nphys)
     237             :   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     238             :   ! compute frontogenesis function F
     239             :   !   F =  -gradth dot C
     240             :   ! with:
     241             :   !   theta  = potential temperature
     242             :   !   gradth = grad(theta)
     243             :   !   C = ( gradth dot grad ) U
     244             :   !
     245             :   ! Original by Mark Taylor, July 2011
     246             :   ! Change by Santos, 10 Aug 2011:
     247             :   ! Integrated into gravity_waves_sources module, several arguments made global
     248             :   !  to prevent repeated allocation/initialization
     249             :   !
     250             :   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     251       24576 :     use physconst,      only: cappa
     252             :     use air_composition,only: dry_air_species_num, thermodynamic_active_species_num
     253             :     use air_composition,only: thermodynamic_active_species_idx_dycore
     254             :     use derivative_mod, only: gradient_sphere, ugradv_sphere
     255             :     use edge_mod,       only: edgevpack, edgevunpack
     256             :     use bndry_mod,      only: bndry_exchange
     257             :     use dyn_grid,       only: hvcoord
     258             :     use dimensions_mod, only: fv_nphys,ntrac
     259             :     use fvm_mapping,    only: dyn2phys_vector,dyn2phys
     260             : 
     261             :     type(hybrid_t),     intent(in)            :: hybrid
     262             :     type(element_t),    intent(inout), target :: elem(:)
     263             :     type(derivative_t), intent(in)            :: ederiv
     264             :     integer,            intent(in)            :: nets,nete,nphys
     265             :     integer,            intent(in)            :: tl,tlq
     266             :     real(r8),           intent(out)           :: frontgf(nphys,nphys,nlev,nets:nete)
     267             :     real(r8),           intent(out)           :: frontga(nphys,nphys,nlev,nets:nete)
     268             : 
     269             :     ! local
     270       49152 :     real(r8) :: area_inv(fv_nphys,fv_nphys), tmp(np,np)
     271       49152 :     real(r8) :: uv_tmp(fv_nphys*fv_nphys,2,nlev)
     272       49152 :     real(r8) :: frontgf_gll(np,np,nlev,nets:nete)
     273             :     real(r8) :: frontga_gll(np,np,nlev,nets:nete)
     274             :     integer  :: k,kptr,i,j,ie,component,h,nq,m_cnst
     275       49152 :     real(r8) :: gradth(np,np,2,nlev,nets:nete) ! grad(theta)
     276             :     real(r8) :: p(np,np)                       ! pressure at mid points
     277             :     real(r8) :: pint(np,np)                    ! pressure at interface points
     278             :     real(r8) :: theta(np,np)                   ! potential temperature at mid points
     279             :     real(r8) :: C(np,np,2), sum_water(np,np)
     280             : 
     281      197376 :     do ie=nets,nete
     282             :       ! pressure at model top
     283     3628800 :       pint(:,:) = hvcoord%hyai(1)*hvcoord%ps0
     284    16243200 :       do k=1,nlev
     285             :         ! moist pressure at mid points
     286   337478400 :         sum_water(:,:) = 1.0_r8
     287   112492800 :         do nq=dry_air_species_num+1,thermodynamic_active_species_num
     288    96422400 :           m_cnst = thermodynamic_active_species_idx_dycore(nq)
     289             :           !
     290             :           ! make sure Q is updated
     291             :           !
     292  2040940800 :           sum_water(:,:) = sum_water(:,:) + elem(ie)%state%Qdp(:,:,k,m_cnst,tlq)/elem(ie)%state%dp3d(:,:,k,tl)
     293             :         end do
     294   337478400 :         p(:,:) = pint(:,:) + 0.5_r8*sum_water(:,:)*elem(ie)%state%dp3d(:,:,k,tl)
     295             :         ! moist pressure at interface for next iteration
     296   337478400 :         pint(:,:) = pint(:,:)+elem(ie)%state%dp3d(:,:,k,tl)
     297             :         !
     298   337478400 :         theta(:,:) = elem(ie)%state%T(:,:,k,tl)*(psurf_ref / p(:,:))**cappa
     299             :         ! gradth(:,:,:,k,ie) = gradient_sphere(theta,ederiv,elem(ie)%Dinv)
     300    16070400 :         call gradient_sphere(theta,ederiv,elem(ie)%Dinv,gradth(:,:,:,k,ie))
     301             :         ! compute C = (grad(theta) dot grad ) u
     302    16070400 :         C(:,:,:) = ugradv_sphere(gradth(:,:,:,k,ie), elem(ie)%state%v(:,:,:,k,tl),ederiv,elem(ie))
     303             :         ! gradth dot C
     304   337478400 :         frontgf_gll(:,:,k,ie) = -( C(:,:,1)*gradth(:,:,1,k,ie) +  C(:,:,2)*gradth(:,:,2,k,ie)  )
     305             :         ! apply mass matrix
     306   337478400 :         gradth(:,:,1,k,ie)=gradth(:,:,1,k,ie)*elem(ie)%spheremp(:,:)
     307   337478400 :         gradth(:,:,2,k,ie)=gradth(:,:,2,k,ie)*elem(ie)%spheremp(:,:)
     308   337651200 :         frontgf_gll(:,:,k,ie)=frontgf_gll(:,:,k,ie)*elem(ie)%spheremp(:,:)
     309             :       enddo
     310             :       ! pack
     311      172800 :       call edgeVpack(edge3, frontgf_gll(:,:,:,ie),nlev,0,ie)
     312      197376 :       call edgeVpack(edge3, gradth(:,:,:,:,ie),2*nlev,nlev,ie)
     313             :     enddo
     314       24576 :     call bndry_exchange(hybrid,edge3,location='compute_frontogenesis')
     315      197376 :     do ie=nets,nete
     316      172800 :       call edgeVunpack(edge3, frontgf_gll(:,:,:,ie),nlev,0,ie)
     317      172800 :       call edgeVunpack(edge3, gradth(:,:,:,:,ie),2*nlev,nlev,ie)
     318             :       ! apply inverse mass matrix,
     319    16243200 :       do k=1,nlev
     320   337478400 :         gradth(:,:,1,k,ie)=gradth(:,:,1,k,ie)*elem(ie)%rspheremp(:,:)
     321   337478400 :         gradth(:,:,2,k,ie)=gradth(:,:,2,k,ie)*elem(ie)%rspheremp(:,:)
     322   337651200 :         frontgf_gll(:,:,k,ie)=frontgf_gll(:,:,k,ie)*elem(ie)%rspheremp(:,:)
     323             :       end do
     324      197376 :       if (fv_nphys>0) then
     325      172800 :         uv_tmp(:,:,:) = dyn2phys_vector(gradth(:,:,:,:,ie),elem(ie))
     326    16243200 :         do k=1,nlev
     327    16070400 :           h=0
     328    64454400 :           do j=1,fv_nphys
     329   208915200 :             do i=1,fv_nphys
     330   144633600 :               h=h+1
     331   192844800 :               frontga(i,j,k,ie) = atan2 ( uv_tmp(h,2,k) , uv_tmp(h,1,k) + 1.e-10_r8 )
     332             :             end do
     333             :           end do
     334             :         end do
     335             :         !
     336             :         ! compute inverse physgrid area for mapping of scaler
     337             :         !
     338     3628800 :         tmp = 1.0_r8
     339      172800 :         area_inv = dyn2phys(tmp,elem(ie)%metdet)
     340     2246400 :         area_inv = 1.0_r8/area_inv
     341    16243200 :         do k=1,nlev
     342    16243200 :           frontgf(:,:,k,ie) = dyn2phys(frontgf_gll(:,:,k,ie),elem(ie)%metdet,area_inv)
     343             :         end do
     344             :       else
     345           0 :         do k=1,nlev
     346           0 :           frontgf(:,:,k,ie)=frontgf_gll(:,:,k,ie)
     347             :           ! Frontogenesis angle
     348           0 :           frontga(:,:,k,ie) = atan2 ( gradth(:,:,2,k,ie) , gradth(:,:,1,k,ie) + 1.e-10_r8 )
     349             :         end do
     350             :       end if
     351             :     enddo
     352       24576 :   end subroutine compute_frontogenesis
     353             : 
     354             : 
     355             : end module gravity_waves_sources

Generated by: LCOV version 1.14