LCOV - code coverage report
Current view: top level - dynamics/se/dycore - reduction_mod.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 71 124 57.3 %
Date: 2025-01-13 21:54:50 Functions: 9 17 52.9 %

          Line data    Source code
       1             : module reduction_mod
       2             :   use shr_kind_mod,   only: r8=>shr_kind_r8
       3             :   use spmd_utils,     only: mpi_sum, mpi_min, mpi_max, mpi_real8, mpi_integer
       4             :   use spmd_utils,     only: mpi_success
       5             :   use cam_abortutils, only: endrun
       6             : 
       7             :   implicit none
       8             :   private
       9             : 
      10             :   type, public :: ReductionBuffer_int_1d_t
      11             :      integer, dimension(:), pointer :: buf
      12             :      integer :: len=0
      13             :      integer :: ctr
      14             :   end type ReductionBuffer_int_1d_t
      15             : 
      16             :   type, public :: ReductionBuffer_r_1d_t
      17             :      real (kind=r8), dimension(:), pointer :: buf
      18             :      integer :: len=0
      19             :      integer :: ctr
      20             :   end type ReductionBuffer_r_1d_t
      21             : 
      22             :   type, public :: ReductionBuffer_ordered_1d_t
      23             :      real (kind=r8), dimension(:,:),pointer :: buf
      24             :      integer :: len=0
      25             :      integer :: ctr
      26             :   end type ReductionBuffer_ordered_1d_t
      27             : 
      28             :   public :: ParallelMin
      29             :   public :: ParallelMax
      30             : 
      31             :   type (ReductionBuffer_int_1d_t), public :: red_max_int
      32             :   type (ReductionBuffer_int_1d_t), public :: red_sum_int
      33             :   type (ReductionBuffer_r_1d_t),   public :: red_flops
      34             :   type (ReductionBuffer_r_1d_t),   public :: red_max
      35             :   type (ReductionBuffer_r_1d_t),   public :: red_min
      36             :   type (ReductionBuffer_r_1d_t),   public :: red_sum
      37             : #ifndef Darwin
      38             :   SAVE red_max_int, red_sum_int, red_flops, red_max, red_min, red_sum
      39             : #endif
      40             : 
      41             :   interface ParallelMin
      42             :      module procedure ParallelMin1d
      43             :      module procedure ParallelMin0d
      44             :   end interface
      45             :   interface ParallelMax
      46             :      module procedure ParallelMax1d_int
      47             :      module procedure ParallelMax2d_int
      48             :      module procedure ParallelMax1d
      49             :      module procedure ParallelMax0d
      50             :      module procedure ParallelMax0d_int
      51             :   end interface
      52             : 
      53             :   interface pmax_mt
      54             :      module procedure pmax_mt_int_1d
      55             :      module procedure pmax_mt_r_1d
      56             :   end interface
      57             : 
      58             :   interface pmin_mt
      59             :      module procedure pmin_mt_r_1d
      60             :   end interface
      61             : 
      62             :   interface InitReductionBuffer
      63             :      module procedure InitReductionBuffer_int_1d
      64             :      module procedure InitReductionBuffer_r_1d
      65             :      module procedure InitReductionBuffer_ordered_1d
      66             :   end interface
      67             : 
      68             :   public :: InitReductionBuffer
      69             :   public :: pmax_mt, pmin_mt
      70             :   public :: ElementSum_1d
      71             : 
      72             : contains
      73             : 
      74       66048 :   function ParallelMin1d(data,hybrid) result(pmin)
      75             :     use hybrid_mod, only : hybrid_t
      76             : 
      77             :     real(kind=r8),   intent(in) :: data(:)
      78             :     type (hybrid_t), intent(in) :: hybrid
      79             :     real(kind=r8)               :: pmin
      80             : 
      81             :     real(kind=r8)               :: tmp(1)
      82             : 
      83             : 
      84      596496 :     tmp(1) = MINVAL(data)
      85       66048 :     call pmin_mt(red_min,tmp,1,hybrid)
      86       66048 :     pmin = red_min%buf(1)
      87             : 
      88       66048 :   end function ParallelMin1d
      89             : 
      90        6144 :   function ParallelMin0d(data,hybrid) result(pmin)
      91             :     use hybrid_mod, only : hybrid_t
      92             :     implicit none
      93             :     real(kind=r8), intent(in)    :: data
      94             :     type (hybrid_t),      intent(in)    :: hybrid
      95             :     real(kind=r8)                :: pmin
      96             :     real(kind=r8)                :: tmp(1)
      97        6144 :     tmp(1) = data
      98        6144 :     call pmin_mt(red_min,tmp,1,hybrid)
      99        6144 :     pmin = red_min%buf(1)
     100             : 
     101        6144 :   end function ParallelMin0d
     102             :   !==================================================
     103           0 :   function ParallelMax2d_int(data, n, m, hybrid) result(pmax)
     104             :     use hybrid_mod, only : hybrid_t
     105             :     implicit none
     106             :     integer, intent(in)                 :: n,m
     107             :     integer, intent(in), dimension(n,m) :: data
     108             :     type (hybrid_t), intent(in)         :: hybrid
     109             :     integer, dimension(n,m)             :: pmax
     110           0 :     integer, dimension(n*m)             :: tmp
     111             :     integer :: i,j
     112           0 :     do i=1,n 
     113           0 :       do j=1,m
     114           0 :         tmp(i+(j-1)*n) = data(i,j)
     115             :       enddo 
     116             :     enddo 
     117           0 :     call pmax_mt(red_max_int,tmp,n*m,hybrid)
     118           0 :     do i=1,n 
     119           0 :       do j=1,m
     120           0 :         pmax(i,j) = red_max_int%buf(i+(j-1)*n) 
     121             :       enddo 
     122             :     enddo 
     123           0 :   end function ParallelMax2d_int
     124             : 
     125           0 :   function ParallelMax1d_int(data, len, hybrid) result(pmax)
     126             :     use hybrid_mod, only : hybrid_t
     127             :     implicit none
     128             :     integer, intent(in)                 :: len
     129             :     integer, intent(in), dimension(len) :: data
     130             :     type (hybrid_t), intent(in)         :: hybrid
     131           0 :     integer, dimension(len)             :: pmax, tmp
     132             : 
     133           0 :     tmp = data(:)
     134           0 :     call pmax_mt(red_max_int,tmp,len,hybrid)
     135           0 :     pmax(:) = red_max_int%buf(1:len)
     136             : 
     137           0 :   end function ParallelMax1d_int
     138       66048 :   function ParallelMax1d(data,hybrid) result(pmax)
     139             :     use hybrid_mod, only : hybrid_t
     140             :     implicit none
     141             :     real(kind=r8), intent(in)    :: data(:)
     142             :     type (hybrid_t),      intent(in)    :: hybrid
     143             :     real(kind=r8)                :: pmax
     144             : 
     145             :     real(kind=r8)                :: tmp(1)
     146             : 
     147             : 
     148      596496 :     tmp(1) = MAXVAL(data)
     149       66048 :     call pmax_mt(red_max,tmp,1,hybrid)
     150       66048 :     pmax = red_max%buf(1)
     151             : 
     152       66048 :   end function ParallelMax1d
     153        6144 :   function ParallelMax0d(data,hybrid) result(pmax)
     154             :     use hybrid_mod, only : hybrid_t
     155             :     implicit none
     156             :     real(kind=r8), intent(in)    :: data
     157             :     type (hybrid_t),      intent(in)    :: hybrid
     158             :     real(kind=r8)                :: pmax
     159             :     real(kind=r8)                :: tmp(1)
     160             : 
     161        6144 :     tmp(1)=data
     162             : 
     163        6144 :     call pmax_mt(red_max,tmp,1,hybrid)
     164        6144 :     pmax = red_max%buf(1)
     165             : 
     166        6144 :   end function ParallelMax0d
     167           0 :   function ParallelMax0d_int(data,hybrid) result(pmax)
     168             :     use hybrid_mod, only : hybrid_t
     169             :     implicit none
     170             :     integer             , intent(in)    :: data
     171             :     type (hybrid_t),      intent(in)    :: hybrid
     172             :     integer                             :: pmax
     173             :     integer                             :: tmp(1)
     174             : 
     175           0 :     tmp(1)=data
     176             : 
     177           0 :     call pmax_mt(red_max_int,tmp,1,hybrid)
     178           0 :     pmax = red_max_int%buf(1)
     179             : 
     180           0 :   end function ParallelMax0d_int
     181             :   !==================================================
     182        3072 :   subroutine InitReductionBuffer_int_1d(red,len)
     183             :     use thread_mod, only: omp_get_num_threads
     184             :     integer, intent(in)           :: len
     185             :     type (ReductionBuffer_int_1d_t),intent(out) :: red
     186             : 
     187        3072 :     if (omp_get_num_threads()>1) then
     188           0 :        call endrun("Error: attempt to allocate reduction buffer in threaded region")
     189             :     endif
     190             : 
     191             :     ! if buffer is already allocated and large enough, do nothing
     192        3072 :     if (len > red%len) then
     193             :        !buffer is too small, or has not yet been allocated
     194        3072 :        if (red%len>0) deallocate(red%buf)
     195        3072 :        red%len  = len
     196        9216 :        allocate(red%buf(len))
     197        6144 :        red%buf  = 0
     198        3072 :        red%ctr  = 0
     199             :     endif
     200             : 
     201        3072 :   end subroutine InitReductionBuffer_int_1d
     202             :   !****************************************************************
     203        6144 :   subroutine InitReductionBuffer_r_1d(red,len)
     204             :     use thread_mod, only: omp_get_num_threads
     205             :     integer, intent(in)           :: len
     206             :     type (ReductionBuffer_r_1d_t),intent(out) :: red
     207             : 
     208        6144 :     if (omp_get_num_threads()>1) then
     209           0 :        call endrun("Error: attempt to allocate reduction buffer in threaded region")
     210             :     endif
     211             : 
     212        6144 :     if (len > red%len) then
     213        6144 :        if (red%len>0) deallocate(red%buf)
     214        6144 :        red%len  = len
     215       18432 :        allocate(red%buf(len))
     216       18432 :        red%buf  = 0.0_R8
     217        6144 :        red%ctr  = 0
     218             :     endif
     219        6144 :   end subroutine InitReductionBuffer_r_1d
     220             :   !****************************************************************
     221        1536 :   subroutine InitReductionBuffer_ordered_1d(red,len,nthread)
     222             :     use thread_mod, only: omp_get_num_threads
     223             :     integer, intent(in)           :: len
     224             :     integer, intent(in)           :: nthread
     225             :     type (ReductionBuffer_ordered_1d_t),intent(out) :: red
     226             : 
     227        1536 :     if (omp_get_num_threads()>1) then
     228           0 :        call endrun("Error: attempt to allocate reduction buffer in threaded region")
     229             :     endif
     230             : 
     231        1536 :     if (len > red%len) then
     232        1536 :        if (red%len>0) deallocate(red%buf)
     233        1536 :        red%len  = len
     234        6144 :        allocate(red%buf(len,nthread+1))
     235      244224 :        red%buf  = 0.0_R8
     236        1536 :        red%ctr  = 0
     237             :     endif
     238        1536 :   end subroutine InitReductionBuffer_ordered_1d
     239             : 
     240             :   ! =======================================
     241             :   ! pmax_mt:
     242             :   !
     243             :   ! thread safe, parallel reduce maximum
     244             :   ! of a one dimensional reduction vector
     245             :   ! =======================================
     246             : 
     247           0 :   subroutine pmax_mt_int_1d(red,redp,len,hybrid)
     248             :     use hybrid_mod, only : hybrid_t
     249             : 
     250             :     type (ReductionBuffer_int_1d_t)   :: red       ! shared memory reduction buffer struct
     251             :     integer,               intent(in) :: len       ! buffer length
     252             :     integer, intent(inout)            :: redp(len) ! thread private vector of partial sum
     253             :     type (hybrid_t),       intent(in) :: hybrid    ! parallel handle
     254             : 
     255             :     ! Local variables
     256             : #ifdef _MPI
     257             :     integer ierr
     258             : #endif
     259             : 
     260             :     integer  :: k
     261           0 :     if (len>red%len) then
     262           0 :       call endrun('ERROR: threadsafe reduction buffer too small')
     263             :     end if
     264             : 
     265             :     !$OMP BARRIER
     266             :     !$OMP CRITICAL (CRITMAX)
     267           0 :     if (red%ctr == 0) red%buf(1:len)= -9999
     268           0 :     if (red%ctr < hybrid%NThreads) then
     269           0 :        do k=1,len
     270           0 :           red%buf(k)=MAX(red%buf(k),redp(k))
     271             :        enddo
     272           0 :        red%ctr=red%ctr+1
     273             :     end if
     274           0 :     if (red%ctr == hybrid%NThreads) red%ctr=0
     275             :     !$OMP END CRITICAL (CRITMAX)
     276             : #ifdef _MPI
     277             :     !$OMP BARRIER
     278           0 :     if (hybrid%ithr==0) then
     279             : 
     280           0 :        call MPI_Allreduce(red%buf(1),redp,len,Mpi_integer, &
     281           0 :             MPI_MAX,hybrid%par%comm,ierr)
     282             : 
     283           0 :        red%buf(1:len)=redp(1:len)
     284             :     end if
     285             : #endif
     286             :     !$OMP BARRIER
     287             : 
     288           0 :   end subroutine pmax_mt_int_1d
     289             :   
     290       72192 :   subroutine pmax_mt_r_1d(red,redp,len,hybrid)
     291             :     use hybrid_mod, only : hybrid_t
     292             : 
     293             :     type (ReductionBuffer_r_1d_t)     :: red     ! shared memory reduction buffer struct
     294             :     real (kind=r8), intent(inout) :: redp(:) ! thread private vector of partial sum
     295             :     integer,               intent(in) :: len     ! buffer length
     296             :     type (hybrid_t),       intent(in) :: hybrid  ! parallel handle
     297             : 
     298             :     ! Local variables
     299             : #ifdef _MPI
     300             :     integer ierr
     301             : #endif
     302             : 
     303             :     integer  :: k
     304       72192 :     if (len>red%len) then
     305           0 :       call endrun('ERROR: threadsafe reduction buffer too small')
     306             :     end if
     307             : 
     308             :     !$OMP BARRIER
     309             :     !$OMP CRITICAL (CRITMAX)
     310      144384 :     if (red%ctr == 0) red%buf(1:len)= -9.11e30_r8
     311       72192 :     if (red%ctr < hybrid%NThreads) then
     312      144384 :        do k=1,len
     313      144384 :           red%buf(k)=MAX(red%buf(k),redp(k))
     314             :        enddo
     315       72192 :        red%ctr=red%ctr+1
     316             :     end if
     317       72192 :     if (red%ctr == hybrid%NThreads) red%ctr=0
     318             :     !$OMP END CRITICAL (CRITMAX)
     319             : #ifdef _MPI
     320             :     !$OMP BARRIER
     321       72192 :     if (hybrid%ithr==0) then
     322             : 
     323           0 :        call MPI_Allreduce(red%buf(1),redp,len,Mpi_real8, &
     324       72192 :             MPI_MAX,hybrid%par%comm,ierr)
     325             : 
     326      144384 :        red%buf(1:len)=redp(1:len)
     327             :     end if
     328             : #endif
     329             :     !$OMP BARRIER
     330             : 
     331       72192 :   end subroutine pmax_mt_r_1d
     332             : 
     333             :   ! =======================================
     334             :   ! pmin_mt:
     335             :   !
     336             :   ! thread safe, parallel reduce maximum
     337             :   ! of a one dimensional reduction vector
     338             :   ! =======================================
     339             : 
     340       72192 :   subroutine pmin_mt_r_1d(red,redp,len,hybrid)
     341             :     use hybrid_mod, only : hybrid_t
     342             : 
     343             :     type (ReductionBuffer_r_1d_t)     :: red     ! shared memory reduction buffer struct
     344             :     real (kind=r8), intent(inout) :: redp(:) ! thread private vector of partial sum
     345             :     integer,               intent(in) :: len     ! buffer length
     346             :     type (hybrid_t),       intent(in) :: hybrid  ! parallel handle
     347             : 
     348             :     ! Local variables
     349             : 
     350             : #ifdef _MPI
     351             :     integer :: ierr
     352             : #endif
     353             :     integer :: k
     354             : 
     355       72192 :     if (len>red%len) then
     356           0 :       call endrun('ERROR: threadsafe reduction buffer too small')
     357             :     end if
     358             : 
     359             :     !$OMP BARRIER
     360             :     !$OMP CRITICAL (CRITMAX)
     361      144384 :     if (red%ctr == 0) red%buf(1:len)= 9.11e30_r8
     362       72192 :     if (red%ctr < hybrid%NThreads) then
     363      144384 :        do k=1,len
     364      144384 :           red%buf(k)=MIN(red%buf(k),redp(k))
     365             :        enddo
     366       72192 :        red%ctr=red%ctr+1
     367             :     end if
     368       72192 :     if (red%ctr == hybrid%NThreads) red%ctr=0
     369             :     !$OMP END CRITICAL (CRITMAX)
     370             : #ifdef _MPI
     371             :     !$OMP BARRIER
     372       72192 :     if (hybrid%ithr==0) then
     373             : 
     374           0 :        call MPI_Allreduce(red%buf(1),redp,len,Mpi_real8, &
     375       72192 :             MPI_MIN,hybrid%par%comm,ierr)
     376             : 
     377      144384 :        red%buf(1:len)=redp(1:len)
     378             :     end if
     379             : #endif
     380             :     !$OMP BARRIER
     381             : 
     382       72192 :   end subroutine pmin_mt_r_1d
     383             : 
     384           0 :   subroutine ElementSum_1d(res,variable,type,hybrid)
     385             :     use hybrid_mod,     only: hybrid_t
     386             :     use dimensions_mod, only: nelem
     387             :     use parallel_mod,   only: ORDERED
     388             : 
     389             :     ! ==========================
     390             :     !     Arguments
     391             :     ! ==========================
     392             :     real(kind=r8),   intent(out) :: res
     393             :     real(kind=r8),   intent(in)  :: variable(:)
     394             :     integer,         intent(in)  :: type
     395             :     type (hybrid_t), intent(in)  :: hybrid 
     396             : 
     397             :     ! ==========================
     398             :     !       Local Variables
     399             :     ! ==========================
     400             : 
     401             :     !
     402             :     ! Note this is a real kludge here since it may be used for
     403             :     !  arrays of size other then nelem
     404             :     !
     405             : 
     406             : #ifdef _MPI
     407             :     integer           :: errorcode,errorlen
     408             :     character(len=80) :: errorstring
     409             : 
     410             :     real(kind=r8)     :: local_sum
     411             :     integer           :: ierr
     412             : #else
     413             :     integer           :: i
     414             : #endif
     415             : 
     416             : #ifdef _MPI
     417           0 :     if(hybrid%ithr == 0) then 
     418           0 :           local_sum=SUM(variable)
     419           0 :           call MPI_Barrier(hybrid%par%comm,ierr)
     420             : 
     421             :           call MPI_Allreduce(local_sum,res,1,Mpi_real8, &
     422           0 :                MPI_SUM,hybrid%par%comm,ierr)
     423           0 :           if(ierr .ne. MPI_SUCCESS) then 
     424           0 :              errorcode=ierr
     425           0 :              call MPI_Error_String(errorcode,errorstring,errorlen,ierr)
     426           0 :              print *,'ElementSum_1d: Error after call to MPI_Allreduce: ',errorstring
     427             :           endif
     428             :     endif
     429             : #else
     430             :     if(hybrid%ithr == 0) then 
     431             :        if(type == ORDERED) then
     432             :           ! ===========================
     433             :           !  Perform the ordererd sum
     434             :           ! ===========================
     435             :           res = 0.0_r8
     436             :           do i=1,nelem
     437             :              res = res + variable(i)
     438             :           enddo
     439             :        else
     440             :           res=SUM(variable)
     441             :        endif
     442             :     endif
     443             : #endif
     444             : 
     445           0 :   end subroutine ElementSum_1d
     446             : 
     447           0 : end module reduction_mod

Generated by: LCOV version 1.14