LCOV - code coverage report
Current view: | top level - dynamics/se/dycore - element_mod.F90 (source / functions) |  |  | Hit | Total | Coverage
Test: | coverage.info |  | Lines: | 27 | 65 | 41.5 %
Date: | 2025-01-13 21:54:50 |  | Functions: | 2 | 15 | 13.3 %

              Line data    Source code
           1             : module element_mod
           2             :
           3             :   use shr_kind_mod,           only: r8=>shr_kind_r8, i8=>shr_kind_i8
           4             :   use coordinate_systems_mod, only: spherical_polar_t, cartesian2D_t, cartesian3D_t, distance
           5             :   use dimensions_mod,         only: np, nc, npsq, nlev, nlevp, qsize_d, max_neigh_edges,ntrac_d
           6             :   use edgetype_mod,           only: edgedescriptor_t
           7             :   use gridgraph_mod,          only: gridvertex_t
           8             :
           9             :   implicit none
          10             :   private
          11             :   integer, public, parameter :: timelevels = 3
          12             :
          13             :
          14             : ! =========== PRIMITIVE-EQUATION DATA-STRUCTURES =====================
          15             :
          16             :   type, public :: elem_state_t
          17             :
          18             :     ! prognostic variables for preqx solver
          19             :
          20             :     ! prognostics must match those in prim_restart_mod.F90
          21             :     ! vertically-lagrangian code advects dp3d instead of ps
          22             :     ! tracers Q, Qdp always use 2 level time scheme
          23             :
          24             :     real (kind=r8) :: v     (np,np,2,nlev,timelevels)            ! velocity
          25             :     real (kind=r8) :: T     (np,np,nlev,timelevels)              ! temperature
          26             :     real (kind=r8) :: dp3d  (np,np,nlev,timelevels)              ! dry delta p on levels
          27             :     real (kind=r8) :: psdry (np,np)                              ! dry surface pressure
          28             :     real (kind=r8) :: phis  (np,np)                              ! surface geopotential (prescribed)
          29             :     real (kind=r8), allocatable :: Qdp(:,:,:,:,:)                ! Tracer mass
          30             :   end type elem_state_t
          31             :
          32             :   !___________________________________________________________________
          33             :   type, public :: derived_state_t
          34             :      !
          35             :      ! storage for subcycling tracers/dynamics
          36             :      !
          37             :     real (kind=r8) :: vn0  (np,np,2,nlev)                      ! velocity for SE tracer advection
          38             :     real (kind=r8) :: dpdiss_biharmonic(np,np,nlev)            ! mean dp dissipation tendency, if nu_p>0
          39             :     real (kind=r8) :: dpdiss_ave(np,np,nlev)                   ! mean dp used to compute psdiss_tens
          40             :
          41             :     ! diagnostics for explicit timestep
          42             :     real (kind=r8) :: phi(np,np,nlev)                          ! geopotential
          43             :     real (kind=r8) :: omega(np,np,nlev)                        ! vertical velocity
          44             :
          45             :     ! tracer advection fields used for consistency and limiters
          46             :     real (kind=r8) :: dp(np,np,nlev)                           ! for dp_tracers at physics timestep
          47             :     real (kind=r8), allocatable :: divdp(:,:,:)                ! divergence of dp
          48             :     real (kind=r8), allocatable :: divdp_proj(:,:,:)           ! DSSed divdp
          49             :     real (kind=r8) :: mass(MAX(qsize_d,ntrac_d)+9)             ! total tracer mass for diagnostics
          50             :
          51             :     ! forcing terms for CAM
          52             :     real (kind=r8), allocatable :: FQ(:,:,:,:)                 ! tracer forcing
          53             :     real (kind=r8) :: FM(np,np,2,nlev)                         ! momentum forcing
          54             :     real (kind=r8), allocatable :: FDP(:,:,:)                  ! save full updated dp right after physics
          55             :     real (kind=r8) :: FT(np,np,nlev)                           ! temperature forcing
          56             :     real (kind=r8) :: etadot_prescribed(np,np,nlevp)           ! prescribed vertical tendency
          57             :     real (kind=r8) :: u_met(np,np,nlev)                        ! zonal component of prescribed meteorology winds
          58             :     real (kind=r8) :: dudt_met(np,np,nlev)                     ! rate of change of zonal component of prescribed meteorology winds
          59             :     real (kind=r8) :: v_met(np,np,nlev)                        ! meridional component of prescribed meteorology winds
          60             :     real (kind=r8) :: dvdt_met(np,np,nlev)                     ! rate of change of meridional component of prescribed meteorology winds
          61             :     real (kind=r8) :: T_met(np,np,nlev)                        ! prescribed meteorology temperature
          62             :     real (kind=r8) :: dTdt_met(np,np,nlev)                     ! rate of change of prescribed meteorology temperature
          63             :     real (kind=r8) :: ps_met(np,np)                            ! surface pressure of prescribed meteorology
          64             :     real (kind=r8) :: dpsdt_met(np,np)                         ! rate of change of surface pressure of prescribed meteorology
          65             :     real (kind=r8) :: nudge_factor(np,np,nlev)                 ! nudging factor (prescribed)
          66             :     real (kind=r8) :: Utnd(npsq,nlev)                          ! accumulated U tendency due to nudging towards prescribed met
          67             :     real (kind=r8) :: Vtnd(npsq,nlev)                          ! accumulated V tendency due to nudging towards prescribed met
          68             :     real (kind=r8) :: Ttnd(npsq,nlev)                          ! accumulated T tendency due to nudging towards prescribed met
          69             :
          70             :     real (kind=r8) :: pecnd(np,np,nlev)                        ! pressure perturbation from condensate
          71             :
          72             :     ! reference profiles
          73             :     real (kind=r8) :: T_ref(np,np,nlev)                        ! reference temperature
          74             :     real (kind=r8) :: dp_ref(np,np,nlev)                       ! reference pressure level thickness
          75             :   end type derived_state_t
          76             :
          77             :   !___________________________________________________________________
          78             :   type, public :: elem_accum_t
          79             :
          80             :
          81             :     ! the "4" timelevels represents data computed at:
          82             :     !  1  t-.5
          83             :     !  2  t+.5   after dynamics
          84             :     !  3  t+.5   after forcing
          85             :     !  4  t+.5   after Robert
          86             :     ! after calling TimeLevelUpdate, all times above decrease by 1.0
          87             :
          88             :
          89             :   end type elem_accum_t
          90             :
          91             :
          92             : ! ============= DATA-STRUCTURES COMMON TO ALL SOLVERS ================
          93             :
          94             :   type, public :: index_t
          95             :      integer :: ia(npsq),ja(npsq)
          96             :      integer :: is,ie
          97             :      integer :: NumUniquePts
          98             :      integer :: UniquePtOffset
          99             :   end type index_t
         100             :
         101             :   !___________________________________________________________________
         102             :   type, public :: element_t
         103             :      integer :: LocalId
         104             :      integer :: GlobalId
         105             :
         106             :      ! Coordinate values of element points
         107             :      type (spherical_polar_t) :: spherep(np,np)                       ! Spherical coords of GLL points
         108             :
         109             :      ! Equ-angular gnomonic projection coordinates
         110             :      type (cartesian2D_t)     :: cartp(np,np)                         ! gnomonic coords of GLL points
         111             :      type (cartesian2D_t)     :: corners(4)                           ! gnomonic coords of element corners
         112             :      real (kind=r8)    :: u2qmap(4,2)                          ! bilinear map from ref element to quad in cubedsphere coordinates
         113             :                                                                       ! SHOULD BE REMOVED
         114             :      ! 3D cartesian coordinates
         115             :      type (cartesian3D_t)     :: corners3D(4)
         116             :
         117             :      ! Element diagnostics
         118             :      real (kind=r8)    :: area                                 ! Area of element
         119             :      real (kind=r8)    :: normDinv                             ! some type of norm of Dinv used for CFL
         120             :      real (kind=r8)    :: dx_short                             ! short length scale in km
         121             :      real (kind=r8)    :: dx_long                              ! long length scale in km
         122             :
         123             :      real (kind=r8)    :: variable_hyperviscosity(np,np)       ! hyperviscosity based on above
         124             :      real (kind=r8)    :: hv_courant                           ! hyperviscosity courant number
         125             :      real (kind=r8)    :: tensorVisc(np,np,2,2)                !og, matrix V for tensor viscosity
         126             :
         127             :      ! Edge connectivity information
         128             : !     integer :: node_numbers(4)
         129             : !     integer :: node_multiplicity(4)                 ! number of elements sharing corner node
         130             :
         131             :      type (GridVertex_t)      :: vertex                               ! element grid vertex information
         132             :      type (EdgeDescriptor_t)  :: desc
         133             :
         134             :      type (elem_state_t)      :: state
         135             :
         136             :      type (derived_state_t)   :: derived
         137             :      ! Metric terms
         138             :      real (kind=r8)    :: met(np,np,2,2)                       ! metric tensor on velocity and pressure grid
         139             :      real (kind=r8)    :: metinv(np,np,2,2)                    ! metric tensor on velocity and pressure grid
         140             :      real (kind=r8)    :: metdet(np,np)                        ! g = SQRT(det(g_ij)) on velocity and pressure grid
         141             :      real (kind=r8)    :: rmetdet(np,np)                       ! 1/metdet on velocity pressure grid
         142             :      real (kind=r8)    :: D(np,np,2,2)                         ! Map covariant field on cube to vector field on the sphere
         143             :      real (kind=r8)    :: Dinv(np,np,2,2)                      ! Map vector field on the sphere to covariant v on cube
         144             :
         145             :
         146             :      ! Mass flux across the sides of each sub-element.
         147             :      ! The storage is redundent since the mass across shared sides
         148             :      ! must be equal in magnitude and opposite in sign.
         149             :      ! The layout is like:
         150             :      !   --------------------------------------------------------------
         151             :      ! ^|    (1,4,3)     |                |              |    (4,4,3) |
         152             :      ! ||                |                |              |            |
         153             :      ! ||(1,4,4)         |                |              |(4,4,4)     |
         154             :      ! ||         (1,4,2)|                |              |     (4,4,2)|
         155             :      ! ||                |                |              |            |
         156             :      ! ||   (1,4,1)      |                |              |  (4,4,1)   |
         157             :      ! |---------------------------------------------------------------
         158             :      ! S|                |                |              |            |
         159             :      ! e|                |                |              |            |
         160             :      ! c|                |                |              |            |
         161             :      ! o|                |                |              |            |
         162             :      ! n|                |                |              |            |
         163             :      ! d|                |                |              |            |
         164             :      !  ---------------------------------------------------------------
         165             :      ! C|                |                |              |            |
         166             :      ! o|                |                |              |            |
         167             :      ! o|                |                |              |            |
         168             :      ! r|                |                |              |            |
         169             :      ! d|                |                |              |            |
         170             :      ! i|                |                |              |            |
         171             :      ! n---------------------------------------------------------------
         172             :      ! a|    (1,1,3)     |                |              |    (4,1,3) |
         173             :      ! t|                |                |              |(4,1,4)     |
         174             :      ! e|(1,1,4)         |                |              |            |
         175             :      !  |         (1,1,2)|                |              |     (4,1,2)|
         176             :      !  |                |                |              |            |
         177             :      !  |    (1,1,1)     |                |              |  (4,1,1)   |
         178             :      !  ---------------------------------------------------------------
         179             :      !          First Coordinate ------->
         180             :      real (kind=r8) :: sub_elem_mass_flux(nc,nc,4,nlev)
         181             :
         182             :      ! Convert vector fields from spherical to rectangular components
         183             :      ! The transpose of this operation is its pseudoinverse.
         184             :      real (kind=r8)    :: vec_sphere2cart(np,np,3,2)
         185             :
         186             :      ! Mass matrix terms for an element on a cube face
         187             :      real (kind=r8)    :: mp(np,np)                            ! mass matrix on v and p grid
         188             :      real (kind=r8)    :: rmp(np,np)                           ! inverse mass matrix on v and p grid
         189             :
         190             :      ! Mass matrix terms for an element on the sphere
         191             :      ! This mass matrix is used when solving the equations in weak form
         192             :      ! with the natural (surface area of the sphere) inner product
         193             :      real (kind=r8)    :: spheremp(np,np)                      ! mass matrix on v and p grid
         194             :      real (kind=r8)    :: rspheremp(np,np)                     ! inverse mass matrix on v and p grid
         195             :
         196             :      integer(i8) :: gdofP(np,np)                     ! global degree of freedom (P-grid)
         197             :
         198             :      real (kind=r8)    :: fcor(np,np)                          ! Coreolis term
         199             :
         200             :      type (index_t) :: idxP
         201             :      type (index_t),pointer :: idxV
         202             :      integer :: FaceNum
         203             :
         204             :      ! force element_t to be a multiple of 8 bytes.
         205             :      ! on BGP, code will crash (signal 7, or signal 15) if 8 byte alignment is off
         206             :      ! check core file for:
         207             :      ! core.63:Generated by interrupt..(Alignment Exception DEAR=0xa1ef671c ESR=0x01800000 CCR0=0x4800a002)
         208             :      integer :: dummy
         209             :   end type element_t
         210             :
         211             :   !___________________________________________________________________
         212             :   public :: element_coordinates
         213             :   public :: element_var_coordinates
         214             :   public :: element_var_coordinates3D
         215             :   public :: GetColumnIdP,GetColumnIdV
         216             :   public :: allocate_element_desc
         217             :   public :: PrintElem
         218             :
         219             : contains
         220             :
         221           0 :   subroutine PrintElem(arr)
         222             :
         223             :     real(kind=r8) :: arr(:,:)
         224             :     integer :: i,j
         225             :
         226           0 :       do j=np,1,-1
         227           0 :          write(6,*) (arr(i,j), i=1,np)
         228             :       enddo
         229             :
         230           0 :   end subroutine PrintElem
         231             : ! ===================== ELEMENT_MOD METHODS ==========================
         232             :
         233           0 :   function GetColumnIdP(elem,i,j) result(col_id)
         234             :
         235             :     ! Get unique identifier for a Physics column on the P-grid
         236             :
         237             :     type(element_t), intent(in) :: elem
         238             :     integer, intent(in) :: i,j
         239             :     integer :: col_id
         240           0 :     col_id = elem%gdofP(i,j)
         241           0 :   end function GetColumnIdP
         242             :
         243             :   !___________________________________________________________________
         244           0 :   function GetColumnIdV(elem,i,j) result(col_id)
         245             :
         246             :     !  Get unique identifier for a Physics column on the V-grid
         247             :
         248             :     type(element_t), intent(in) :: elem
         249             :     integer, intent(in) :: i,j
         250             :     integer :: col_id
         251           0 :     col_id = elem%gdofP(i,j)
         252           0 :   end function GetColumnIdV
         253             :
         254             :   !___________________________________________________________________
         255           0 :   function element_coordinates(start,end,points) result(cart)
         256             :
         257             :     ! Initialize 2D rectilinear element colocation points
         258             :
         259             :     type (cartesian2D_t), intent(in) :: start
         260             :     type (cartesian2D_t), intent(in) :: end
         261             :     real(r8),             intent(in) :: points(:)
         262             :     type (cartesian2D_t)             :: cart(SIZE(points),SIZE(points))
         263             :
         264             :     type (cartesian2D_t) :: length, centroid
         265             :     real(r8)             :: y
         266             :     integer              :: i,j
         267             :
         268           0 :     length%x   = 0.50D0*(end%x-start%x)
         269           0 :     length%y   = 0.50D0*(end%y-start%y)
         270           0 :     centroid%x = 0.50D0*(end%x+start%x)
         271           0 :     centroid%y = 0.50D0*(end%y+start%y)
         272           0 :     do j=1,SIZE(points)
         273           0 :        y = centroid%y + length%y*points(j)
         274           0 :        do i=1,SIZE(points)
         275           0 :           cart(i,j)%x = centroid%x + length%x*points(i)
         276           0 :           cart(i,j)%y = y
         277             :        end do
         278             :     end do
         279           0 :   end function element_coordinates
         280             :
         281             :   !___________________________________________________________________
         282       21600 :   function element_var_coordinates(c,points) result(cart)
         283             :
         284             :     type (cartesian2D_t), intent(in) :: c(4)
         285             :     real(r8),             intent(in) :: points(:)
         286             :     type (cartesian2D_t)             :: cart(SIZE(points),SIZE(points))
         287             :
         288       43200 :     real(r8) :: p(size(points))
         289       43200 :     real(r8) :: q(size(points))
         290             :     integer  :: i,j
         291             :
         292      129600 :     p(:) = (1.0D0-points(:))/2.0D0
         293      108000 :     q(:) = (1.0D0+points(:))/2.0D0
         294             :
         295      108000 :     do j=1,SIZE(points)
         296      453600 :        do i=1,SIZE(points)
         297      691200 :           cart(i,j)%x = p(i)*p(j)*c(1)%x &
         298             :                       + q(i)*p(j)*c(2)%x &
         299             :                       + q(i)*q(j)*c(3)%x &
         300      691200 :                       + p(i)*q(j)*c(4)%x
         301             :           cart(i,j)%y = p(i)*p(j)*c(1)%y &
         302             :                       + q(i)*p(j)*c(2)%y &
         303             :                       + q(i)*q(j)*c(3)%y &
         304      432000 :                       + p(i)*q(j)*c(4)%y
         305             :        end do
         306             :     end do
         307       21600 :   end function element_var_coordinates
         308             :
         309             :   !___________________________________________________________________
         310           0 :   function element_var_coordinates3d(c,points) result(cart)
         311             :
         312             :     type(cartesian3D_t), intent(in) :: c(4)
         313             :     real(r8), intent(in) :: points(:)
         314             :
         315             :     type(cartesian3D_t)  :: cart(SIZE(points),SIZE(points))
         316             :
         317           0 :     real(r8) :: p(size(points))
         318           0 :     real(r8) :: q(size(points)), r
         319             :     integer  :: i,j
         320             :
         321           0 :     p(:) = (1.0D0-points(:))/2.0D0
         322           0 :     q(:) = (1.0D0+points(:))/2.0D0
         323             :
         324           0 :     do j=1,SIZE(points)
         325           0 :        do i=1,SIZE(points)
         326           0 :           cart(i,j)%x = p(i)*p(j)*c(1)%x &
         327             :                       + q(i)*p(j)*c(2)%x &
         328             :                       + q(i)*q(j)*c(3)%x &
         329           0 :                       + p(i)*q(j)*c(4)%x
         330             :           cart(i,j)%y = p(i)*p(j)*c(1)%y &
         331             :                       + q(i)*p(j)*c(2)%y &
         332             :                       + q(i)*q(j)*c(3)%y &
         333           0 :                       + p(i)*q(j)*c(4)%y
         334             :           cart(i,j)%z = p(i)*p(j)*c(1)%z &
         335             :                       + q(i)*p(j)*c(2)%z &
         336             :                       + q(i)*q(j)*c(3)%z &
         337           0 :                       + p(i)*q(j)*c(4)%z
         338             :
         339             :           ! project back to sphere:
         340           0 :           r = distance(cart(i,j))
         341           0 :           cart(i,j)%x = cart(i,j)%x/r
         342           0 :           cart(i,j)%y = cart(i,j)%y/r
         343           0 :           cart(i,j)%z = cart(i,j)%z/r
         344             :        end do
         345             :     end do
         346           0 :   end function element_var_coordinates3d
         347             :
         348             :   !___________________________________________________________________
         349        1536 :   subroutine allocate_element_desc(elem)
         350             :
         351             :     type (element_t), intent(inout)   :: elem(:)
         352             :     integer                           :: num, j,i
         353             :
         354        1536 :     num = SIZE(elem)
         355             :
         356       12336 :     do j=1,num
         357       32400 :        allocate(elem(j)%desc%putmapP(max_neigh_edges))
         358       21600 :        allocate(elem(j)%desc%getmapP(max_neigh_edges))
         359       21600 :        allocate(elem(j)%desc%putmapP_ghost(max_neigh_edges))
         360       21600 :        allocate(elem(j)%desc%getmapP_ghost(max_neigh_edges))
         361       21600 :        allocate(elem(j)%desc%putmapS(max_neigh_edges))
         362       21600 :        allocate(elem(j)%desc%getmapS(max_neigh_edges))
         363       21600 :        allocate(elem(j)%desc%reverse(max_neigh_edges))
         364       21600 :        allocate(elem(j)%desc%globalID(max_neigh_edges))
         365       21600 :        allocate(elem(j)%desc%loc2buf(max_neigh_edges))
         366       98736 :        do i=1,max_neigh_edges
         367       86400 :           elem(j)%desc%loc2buf(i)=i
         368       97200 :           elem(j)%desc%globalID(i)=-1
         369             :        enddo
         370             :
         371             :     end do
         372        1536 :   end subroutine allocate_element_desc
         373             :
         374             :
         375           0 : end module element_mod

Generated by: LCOV version 1.14