LCOV - code coverage report
Current view: top level - dynamics/fv - d2a3dikj.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 100 140 71.4 %
Date: 2025-03-14 01:33:33 Functions: 1 1 100.0 %

          Line data    Source code
       1             : module d2a3dikj_mod
       2             : 
       3             : implicit none
       4             : save
       5             : private
       6             : public :: d2a3dikj
       7             : 
       8             : contains
       9             : 
      10             : !-----------------------------------------------------------------------
      11             : !BOP
      12             : ! !ROUTINE: d2a3ikj -- Generalized 2nd order D-to-A grid transform (3D)
      13             : !                      Output array is i,k,j
      14             : !
      15             : ! !INTERFACE:
      16             : 
      17       16128 :       subroutine d2a3dikj(grid, am_geom_crrct, u, v, ua, va)
      18             : 
      19             : ! !USES:
      20             : 
      21             :       use shr_kind_mod, only: r8 => shr_kind_r8
      22             :       use dynamics_vars, only : t_fvdycore_grid
      23             : 
      24             : #if defined( SPMD )
      25             :       use parutilitiesmodule, only : parcollective, sumop
      26             :       use mod_comm, only: mp_send3d, mp_recv3d
      27             : #endif
      28             : 
      29             :       use shr_reprosum_mod, only : shr_reprosum_calc, &
      30             :            shr_reprosum_tolExceeded, &
      31             :            shr_reprosum_reldiffmax, &
      32             :            shr_reprosum_recompute
      33             :       use cam_logfile,   only : iulog
      34             :       use perf_mod
      35             : 
      36             :       implicit none
      37             : ! !INPUT PARAMETERS:
      38             :       type (t_fvdycore_grid), intent(in) :: grid
      39             :       logical,  intent(in) :: am_geom_crrct
      40             :       real(r8), intent(in) :: u(grid%ifirstxy:grid%ilastxy,                  &
      41             :                                 grid%jfirstxy:grid%jlastxy,grid%km) ! U-Wind
      42             :       real(r8), intent(in) :: v(grid%ifirstxy:grid%ilastxy,                  &
      43             :                                 grid%jfirstxy:grid%jlastxy,grid%km) ! V-Wind
      44             : 
      45             : ! !INPUT/OUTPUT PARAMETERS:
      46             :       real(r8), intent(inout) :: ua(grid%ifirstxy:grid%ilastxy,grid%km,      &
      47             :                                     grid%jfirstxy:grid%jlastxy)     ! U-Wind
      48             :       real(r8), intent(inout) :: va(grid%ifirstxy:grid%ilastxy,grid%km,      &
      49             :                                     grid%jfirstxy:grid%jlastxy)     ! V-Wind
      50             : 
      51             : ! !DESCRIPTION:
      52             : !
      53             : !     This routine performs a second order 
      54             : !     interpolation of three-dimensional wind
      55             : !     fields on a D grid to an A grid.  !
      56             : !
      57             : ! !REVISION HISTORY:
      58             : !     WS  00.12.22 : Creation from d2a3d
      59             : !     AAM 01.06.13 : Generalized to 2D decomposition
      60             : !     WS  02.04.25 : New mod_comm interfaces
      61             : !     WS  03.08.13 : Use unorth for ghosting U (aligned with d2a3dijk)
      62             : !     WS  05.07.06 : Simplified interface with grid
      63             : !     WS  06.09.08 : isolated magic numbers as F90 parameters
      64             : !     PW  08.07.03 : introduced reprosum logic
      65             : !     SS  12.10.29 : reprosum is now in csm_share
      66             : !
      67             : !EOP
      68             : !-----------------------------------------------------------------------
      69             : !BOC
      70             :       real(r8), parameter ::  D0_0                    =  0.0_r8
      71             :       real(r8), parameter ::  D0_5                    =  0.5_r8
      72             : 
      73             :       integer  :: imh, i, j, k, m, itot, jtot, ltot, ik
      74       32256 :       real(r8) :: veast(grid%jfirstxy:grid%jlastxy,grid%km)
      75       32256 :       real(r8) :: unorth(grid%ifirstxy:grid%ilastxy,grid%km)
      76             : 
      77       32256 :       real(r8) :: uva(grid%ifirstxy:grid%ilastxy,grid%km,2)
      78       32256 :       real(r8) :: uvn(grid%km,2), uvs(grid%km,2)
      79       32256 :       real(r8) :: rel_diff(2,grid%km,2)
      80       16128 :       real(r8),allocatable :: uva_tmp(:)
      81             : 
      82             :       integer  :: ifirstxy, ilastxy, jfirstxy, jlastxy, im, jm, km
      83             :       integer  :: myidxy_y, myidxy_x, nprxy_x, iam
      84             : 
      85             :       logical  :: write_warning
      86             : 
      87       16128 :       real(r8), pointer :: coslon(:),sinlon(:)  ! Sine and cosine in longitude
      88             : 
      89             : #if defined( SPMD )
      90             :       integer dest, src, incount, outcount
      91             : #endif
      92             : 
      93             :       ! for AM correction
      94       16128 :       real(r8), pointer :: cosp(:), cose(:)
      95             : 
      96       16128 :       myidxy_y = grid%myidxy_y
      97       16128 :       myidxy_x = grid%myidxy_x
      98       16128 :       nprxy_x  = grid%nprxy_x
      99       16128 :       iam      = grid%iam
     100             : 
     101       16128 :       im       = grid%im
     102       16128 :       jm       = grid%jm
     103       16128 :       km       = grid%km
     104             : 
     105       16128 :       ifirstxy = grid%ifirstxy
     106       16128 :       ilastxy  = grid%ilastxy
     107       16128 :       jfirstxy = grid%jfirstxy
     108       16128 :       jlastxy  = grid%jlastxy
     109             : 
     110       16128 :       itot = ilastxy-ifirstxy+1
     111       16128 :       jtot = jlastxy-jfirstxy+1
     112       16128 :       imh = im/2
     113             : 
     114       16128 :       coslon   => grid%coslon
     115       16128 :       sinlon   => grid%sinlon
     116       16128 :       cosp     => grid%cosp
     117       16128 :       cose     => grid%cose
     118             : 
     119             : #if defined( SPMD )
     120             : ! Set ua on A-grid
     121             :       call mp_send3d( grid%commxy, iam-nprxy_x, iam+nprxy_x, im, jm, km,      &
     122             :                       ifirstxy, ilastxy, jfirstxy, jlastxy, 1, km,           &
     123       16128 :                       ifirstxy, ilastxy, jfirstxy, jfirstxy, 1, km, u )
     124             :       call mp_recv3d( grid%commxy, iam+nprxy_x, im, jm, km,                   &
     125             :                       ifirstxy, ilastxy, jlastxy+1, jlastxy+1, 1, km,        &
     126       16128 :                       ifirstxy, ilastxy, jlastxy+1, jlastxy+1, 1, km, unorth )
     127             : 
     128       16128 :       if ( jlastxy .lt. jm ) then
     129             : 
     130       15876 :          if (am_geom_crrct) then
     131             : !$omp  parallel do private(i, k)
     132           0 :             do k = 1, km
     133           0 :                do i = ifirstxy, ilastxy
     134           0 :                   ua(i,k,jlastxy) = 0.5_r8*(u(i,jlastxy,k)*cose(jlastxy) + &
     135           0 :                                     unorth(i,k)*cose(jlastxy+1))/cosp(jlastxy) 
     136             :                end do
     137             :             end do
     138             :          else
     139             : !$omp  parallel do private(i, k)
     140     1127196 :             do k = 1, km
     141    27798876 :                do i = ifirstxy, ilastxy
     142    27783000 :                   ua(i,k,jlastxy) = 0.5_r8*(u(i,jlastxy,k) + unorth(i,k)) 
     143             :                end do
     144             :             end do
     145             :          end if
     146             :       end if
     147             : #endif
     148             : 
     149       16128 :       if (am_geom_crrct) then
     150             : !$omp  parallel do private(i,j,k)
     151           0 :          do k = 1, km
     152           0 :             do j = jfirstxy, jlastxy-1
     153           0 :                do i = ifirstxy, ilastxy
     154           0 :                   if (cosp(j) .ne. 0.0_r8) then 
     155           0 :                      ua(i,k,j) = 0.5_r8*(u(i,j,k)*cose(j) + u(i,j+1,k)*cose(j+1))/cosp(j) ! preserve curl-free flow
     156             :                   else 
     157           0 :                      ua(i,k,j) = (u(i,j,k)*cose(j)+u(i,j+1,k)*cose(j+1))/(cose(j)+cose(j+1)) 
     158             :                   end if
     159             :                end do
     160             :             end do
     161             :          end do
     162             :       else
     163             : !$omp  parallel do private(i,j,k)
     164     1145088 :          do k = 1, km
     165     3403008 :             do j = jfirstxy, jlastxy-1
     166    57576960 :                do i = ifirstxy, ilastxy
     167    56448000 :                   ua(i,k,j) = 0.5_r8*(u(i,j,k) + u(i,j+1,k))  ! preserve solid-body flow 
     168             :                end do
     169             :             end do
     170             :          end do
     171             :       end if
     172             : 
     173             : ! Set va on A-grid
     174             : 
     175             : !$omp  parallel do private(j,k)
     176             : 
     177     1145088 :       do k = 1,km
     178     4531968 :          do j=jfirstxy,jlastxy
     179     4515840 :             veast(j,k) = v(ifirstxy,j,k)
     180             :          enddo
     181             :       enddo
     182             : 
     183             : #if defined( SPMD )
     184       16128 :       if (itot .ne. im) then
     185       16128 :          dest = myidxy_y*nprxy_x + MOD(iam+nprxy_x-1,nprxy_x)
     186       16128 :          src  = myidxy_y*nprxy_x + MOD(iam+1,nprxy_x)
     187             :          call mp_send3d( grid%commxy, dest, src, im, jm, km,               &
     188             :                          ifirstxy, ilastxy, jfirstxy, jlastxy, 1, km,     &
     189       16128 :                          ifirstxy, ifirstxy, jfirstxy, jlastxy, 1, km, v )
     190             :          call mp_recv3d( grid%commxy, src, im, jm, km,                     &
     191             :                          ilastxy+1, ilastxy+1, jfirstxy, jlastxy, 1, km,  &
     192       16128 :                          ilastxy+1, ilastxy+1, jfirstxy, jlastxy, 1, km, veast )
     193             :       endif
     194             : #endif
     195             : 
     196             : !$omp  parallel do private(i,j,k)
     197             : 
     198     1145088 :       do k=1,km
     199     4531968 :          do j=jfirstxy, jlastxy
     200    81285120 :             do i=ifirstxy,ilastxy-1
     201    81285120 :                va(i,k,j) = D0_5*(v(i,j,k) + v(i+1,j,k))
     202             :             enddo
     203     4515840 :             va(ilastxy,k,j) = D0_5*(v(ilastxy,j,k) + veast(j,k))
     204             :          enddo
     205             :       enddo
     206             : 
     207       16128 :       if (jfirstxy .eq. 1) then
     208             : ! Was (something like) ...
     209             : !            do i=1,imh
     210             : !               us(k) = us(k) + (uvaglob(i+imh,k,1)-uvaglob(i,k,1))*sinlon(i)  &
     211             : !                     + (uvaglob(i,k,2)-uvaglob(i+imh,k,2))*coslon(i)
     212             : !               vs(k) = vs(k) + (uvaglob(i+imh,k,1)-uvaglob(i,k,1))*coslon(i)  & 
     213             : !                     + (uvaglob(i+imh,k,2)-uvaglob(i,k,2))*sinlon(i)
     214             : !            enddo
     215             : 
     216             : !$omp  parallel do private(i,k)
     217       17892 :          do k = 1,km
     218      229320 :             do i=ifirstxy,min(imh,ilastxy)
     219      211680 :                uva(i,k,1) = -ua(i,k,2)*sinlon(i) + va(i,k,2)*coslon(i)
     220      229320 :                uva(i,k,2) = -ua(i,k,2)*coslon(i) - va(i,k,2)*sinlon(i)
     221             :             enddo
     222      229572 :             do i=max(imh+1,ifirstxy),ilastxy
     223      211680 :                uva(i,k,1) =  ua(i,k,2)*sinlon(i-imh) - va(i,k,2)*coslon(i-imh)
     224      229320 :                uva(i,k,2) =  ua(i,k,2)*coslon(i-imh) + va(i,k,2)*sinlon(i-imh)
     225             :             enddo
     226             :          enddo
     227             : 
     228         252 :          call t_startf("d2a3dikj_reprosum")
     229             :          call shr_reprosum_calc(uva, uvs, itot, itot, 2*km, gbl_count=im, &
     230         252 :                         commid=grid%commxy_x, rel_diff=rel_diff)
     231         252 :          call t_stopf("d2a3dikj_reprosum")
     232             : 
     233             :          ! check that "fast" reproducible sum is accurate enough. If not, calculate
     234             :          ! using old method
     235         252 :          write_warning = .false.
     236         252 :          if (myidxy_x == 0) write_warning = .true.
     237         252 :          if ( shr_reprosum_tolExceeded('d2a3dikj/South Pole', 2*km, write_warning, &
     238             :               iulog, rel_diff) ) then
     239           0 :             if ( shr_reprosum_recompute ) then
     240           0 :                call t_startf("d2a3dikj_sumfix")
     241           0 :                allocate( uva_tmp(im) )
     242           0 :                do m = 1,2
     243           0 :                   do k = 1,km
     244           0 :                      if (rel_diff(1,k,m) > shr_reprosum_reldiffmax) then
     245           0 :                         uva_tmp(:) = D0_0
     246           0 :                         do i = ifirstxy,ilastxy
     247           0 :                            uva_tmp(i) = uva(i,k,m)
     248             :                         enddo
     249             : #if defined(SPMD)
     250           0 :                         call parcollective(grid%commxy_x,sumop,im,uva_tmp)
     251             : #endif
     252           0 :                         uvs(k,m) = D0_0
     253           0 :                         do i = 1,im
     254           0 :                            uvs(k,m) = uvs(k,m) + uva_tmp(i)
     255             :                         enddo
     256             :                      endif
     257             :                   enddo
     258             :                enddo
     259           0 :                deallocate( uva_tmp )
     260           0 :                call t_stopf("d2a3dikj_sumfix")
     261             :             endif
     262             :          endif
     263             : 
     264             : !$omp  parallel do private(i,k)
     265       17892 :          do k = 1,km
     266       17640 :             uvs(k,1) = uvs(k,1)/im
     267       17640 :             uvs(k,2) = uvs(k,2)/im
     268      229320 :             do i=ifirstxy,min(imh,ilastxy)
     269      211680 :                ua(i,k,1) = -uvs(k,1)*sinlon(i) - uvs(k,2)*coslon(i)
     270      229320 :                va(i,k,1) =  uvs(k,1)*coslon(i) - uvs(k,2)*sinlon(i)
     271             :             enddo
     272      229572 :             do i=max(imh+1,ifirstxy),ilastxy
     273      211680 :                ua(i,k,1) =  uvs(k,1)*sinlon(i-imh) + uvs(k,2)*coslon(i-imh)
     274      229320 :                va(i,k,1) = -uvs(k,1)*coslon(i-imh) + uvs(k,2)*sinlon(i-imh)
     275             :             enddo
     276             :          enddo
     277             : 
     278             :       endif
     279             : 
     280       16128 :       if (jlastxy .eq. jm) then
     281             : ! Was (something like) ...
     282             : !            do i=1,imh
     283             : !               un(k) = un(k) + (uaglob(i+imh,k,jm-1)-uaglob(i,k,jm-1))*sinlon(i) &
     284             : !                     + (vaglob(i+imh,k,jm-1)-vaglob(i,k,jm-1))*coslon(i)
     285             : !               vn(k) = vn(k) + (uaglob(i,k,jm-1)-uaglob(i+imh,k,jm-1))*coslon(i) &
     286             : !                     + (vaglob(i+imh,k,jm-1)-vaglob(i,k,jm-1))*sinlon(i)
     287             : !            enddo
     288             : 
     289             : !$omp  parallel do private(i,k)
     290       17892 :          do k = 1,km
     291      229320 :             do i=ifirstxy,min(imh,ilastxy)
     292      211680 :                uva(i,k,1) = -ua(i,k,jm-1)*sinlon(i) - va(i,k,jm-1)*coslon(i)
     293      229320 :                uva(i,k,2) =  ua(i,k,jm-1)*coslon(i) - va(i,k,jm-1)*sinlon(i)
     294             :             enddo
     295      229572 :             do i=max(imh+1,ifirstxy),ilastxy
     296      211680 :                uva(i,k,1) =  ua(i,k,jm-1)*sinlon(i-imh) + va(i,k,jm-1)*coslon(i-imh)
     297      229320 :                uva(i,k,2) = -ua(i,k,jm-1)*coslon(i-imh) + va(i,k,jm-1)*sinlon(i-imh)
     298             :             enddo
     299             :          enddo
     300             : 
     301         252 :          call t_startf("d2a3dikj_reprosum")
     302             :          call shr_reprosum_calc(uva, uvn, itot, itot, 2*km, gbl_count=im, &
     303         252 :                         commid=grid%commxy_x, rel_diff=rel_diff)
     304         252 :          call t_stopf("d2a3dikj_reprosum")
     305             : 
     306             :          ! check that "fast" reproducible sum is accurate enough. If not, calculate
     307             :          ! using old method
     308         252 :          write_warning = .false.
     309         252 :          if (myidxy_x == 0) write_warning = .true.
     310         252 :          if ( shr_reprosum_tolExceeded('d2a3dikj/Nouth Pole', 2*km, write_warning, &
     311             :               iulog, rel_diff) ) then
     312           0 :             if ( shr_reprosum_recompute ) then
     313           0 :                call t_startf("d2a3dikj_sumfix")
     314           0 :                allocate( uva_tmp(im) )
     315           0 :                do m = 1,2
     316           0 :                   do k = 1,km
     317           0 :                      if (rel_diff(1,k,m) > shr_reprosum_reldiffmax) then
     318           0 :                         uva_tmp(:) = D0_0
     319           0 :                         do i = ifirstxy,ilastxy
     320           0 :                            uva_tmp(i) = uva(i,k,m)
     321             :                         enddo
     322             : #if defined(SPMD)
     323           0 :                         call parcollective(grid%commxy_x,sumop,im,uva_tmp)
     324             : #endif
     325           0 :                         uvn(k,m) = D0_0
     326           0 :                         do i = 1,im
     327           0 :                            uvn(k,m) = uvn(k,m) + uva_tmp(i)
     328             :                         enddo
     329             :                      endif
     330             :                   enddo
     331             :                enddo
     332           0 :                deallocate( uva_tmp )
     333           0 :                call t_stopf("d2a3dikj_sumfix")
     334             :             endif
     335             :          endif
     336             : 
     337             : !$omp  parallel do private(i,k)
     338       17892 :          do k = 1,km
     339       17640 :             uvn(k,1) = uvn(k,1)/im
     340       17640 :             uvn(k,2) = uvn(k,2)/im
     341      229320 :             do i=ifirstxy,min(imh,ilastxy)
     342      211680 :                ua(i,k,jm) = -uvn(k,1)*sinlon(i) + uvn(k,2)*coslon(i)
     343      229320 :                va(i,k,jm) = -uvn(k,1)*coslon(i) - uvn(k,2)*sinlon(i)
     344             :             enddo
     345      229572 :             do i=max(imh+1,ifirstxy),ilastxy
     346      211680 :                ua(i,k,jm) =  uvn(k,1)*sinlon(i-imh) - uvn(k,2)*coslon(i-imh)
     347      229320 :                va(i,k,jm) =  uvn(k,1)*coslon(i-imh) + uvn(k,2)*sinlon(i-imh)
     348             :             enddo
     349             :          enddo
     350             : 
     351             :       endif
     352             : 
     353       16128 :       return
     354             : !EOC
     355       32256 :    end subroutine d2a3dikj
     356             : !-----------------------------------------------------------------------
     357             : end module d2a3dikj_mod

Generated by: LCOV version 1.14