!*********************************************************************** !* GNU Lesser General Public License !* !* This file is part of the GFDL Flexible Modeling System (FMS). !* !* FMS is free software: you can redistribute it and/or modify it under !* the terms of the GNU Lesser General Public License as published by !* the Free Software Foundation, either version 3 of the License, or (at !* your option) any later version. !* !* FMS is distributed in the hope that it will be useful, but WITHOUT !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License !* for more details. !* !* You should have received a copy of the GNU Lesser General Public !* License along with FMS. If not, see . !*********************************************************************** !> \file !! \brief Contains the \ref block_control_mod module module block_control_mod #include use mpp_mod, only: mpp_error, NOTE, WARNING, FATAL use mpp_domains_mod, only: mpp_compute_extent implicit none public block_control_type type ix_type integer, dimension(:,:), _ALLOCATABLE :: ix _NULL end type ix_type type pk_type integer, dimension(:), _ALLOCATABLE :: ii _NULL integer, dimension(:), _ALLOCATABLE :: jj _NULL end type pk_type type block_control_type integer :: nx_block, ny_block !< blocking factor using mpp-style decomposition integer :: nblks !< number of blocks cover MPI domain integer :: isc, iec, jsc, jec !< MPI domain global extents integer :: npz !< vertical extent integer, dimension(:), _ALLOCATABLE :: ibs _NULL, & !< block extents for mpp-style ibe _NULL, & !! decompositions jbs _NULL, & jbe _NULL type(ix_type), dimension(:), _ALLOCATABLE :: ix _NULL !< dereference packed index from global index !--- packed blocking fields integer, dimension(:), _ALLOCATABLE :: blksz _NULL !< number of points in each individual block !! blocks are not required to be uniforom in size integer, dimension(:,:), _ALLOCATABLE :: blkno _NULL !< dereference block number using global indices integer, dimension(:,:), _ALLOCATABLE :: ixp _NULL !< dereference packed index from global indices !! must be used in conjuction with blkno type(pk_type), dimension(:), _ALLOCATABLE :: index _NULL !< dereference global indices from !! block/ixp combo end type block_control_type public :: define_blocks, define_blocks_packed contains !############################################################################### !> \fn define_blocks !! !! \brief Sets up "blocks" used for OpenMP threading of column-based !! calculations using rad_n[x/y]xblock from coupler_nml !! !! Parameters: !! !! \code{.f90} !! character(len=*), intent(in) :: component !! type(block_control_type), intent(inout) :: Block !! integer, intent(in) :: isc, iec, jsc, jec, kpts !! integer, intent(in) :: nx_block, ny_block !! logical, intent(inout) :: message !! \endcode !! !! \param [in] !! \param [inout] !! \param [in] !! \param [in] !! \param [in] !! \param [in] !! \param [in] !! \param [in] !! \param [in] !! \param [inout] !! subroutine define_blocks (component, Block, isc, iec, jsc, jec, kpts, & nx_block, ny_block, message) character(len=*), intent(in) :: component type(block_control_type), intent(inout) :: Block integer, intent(in) :: isc, iec, jsc, jec, kpts integer, intent(in) :: nx_block, ny_block logical, intent(inout) :: message !------------------------------------------------------------------------------- ! Local variables: ! blocks ! i1 ! i2 ! j1 ! j2 ! text ! i ! j ! nblks ! ix ! ii ! jj !------------------------------------------------------------------------------- integer :: blocks integer, dimension(nx_block) :: i1, i2 integer, dimension(ny_block) :: j1, j2 character(len=256) :: text integer :: i, j, nblks, ix, ii, jj if (message) then if ((mod(iec-isc+1,nx_block) .ne. 0) .or. (mod(jec-jsc+1,ny_block) .ne. 0)) then write( text,'(a,a,2i4,a,2i4,a)' ) trim(component),'define_blocks: domain (',& (iec-isc+1), (jec-jsc+1),') is not an even divisor with definition (',& nx_block, ny_block,') - blocks will not be uniform' call mpp_error (WARNING, trim(text)) endif message = .false. endif !--- set up blocks if (iec-isc+1 .lt. nx_block) & call mpp_error(FATAL, 'block_control: number of '//trim(component)//' nxblocks .gt. & &number of elements in MPI-domain size') if (jec-jsc+1 .lt. ny_block) & call mpp_error(FATAL, 'block_control: number of '//trim(component)//' nyblocks .gt. & &number of elements in MPI-domain size') call mpp_compute_extent(isc,iec,nx_block,i1,i2) call mpp_compute_extent(jsc,jec,ny_block,j1,j2) nblks = nx_block*ny_block Block%isc = isc Block%iec = iec Block%jsc = jsc Block%jec = jec Block%npz = kpts Block%nx_block = nx_block Block%ny_block = ny_block Block%nblks = nblks if (.not._ALLOCATED(Block%ibs)) & allocate (Block%ibs(nblks), & Block%ibe(nblks), & Block%jbs(nblks), & Block%jbe(nblks), & Block%ix(nblks) ) blocks=0 do j = 1, ny_block do i = 1, nx_block blocks = blocks + 1 Block%ibs(blocks) = i1(i) Block%jbs(blocks) = j1(j) Block%ibe(blocks) = i2(i) Block%jbe(blocks) = j2(j) allocate(Block%ix(blocks)%ix(i1(i):i2(i),j1(j):j2(j)) ) ix = 0 do jj = j1(j), j2(j) do ii = i1(i), i2(i) ix = ix+1 Block%ix(blocks)%ix(ii,jj) = ix enddo enddo enddo enddo end subroutine define_blocks !############################################################################### !> \fn define_blocks_packed !! !! \brief Creates and populates a data type which is used for defining the !! sub-blocks of the MPI-domain to enhance OpenMP and memory performance. !! Uses a packed concept !! !! Parameters: !! !! \code{.f90} !! character(len=*), intent(in) :: component !! type(block_control_type), intent(inout) :: Block !! integer, intent(in) :: isc, iec, jsc, jec, kpts !! integer, intent(inout) :: blksz !! logical, intent(inout) :: message !! \endcode !! !! \param [in] !! \param [inout] !! \param [in] !! \param [in] !! \param [in] !! \param [in] !! \param [in] !! \param [inout] !! \param [inout] !! subroutine define_blocks_packed (component, Block, isc, iec, jsc, jec, & kpts, blksz, message) character(len=*), intent(in) :: component type(block_control_type), intent(inout) :: Block integer, intent(in) :: isc, iec, jsc, jec, kpts integer, intent(inout) :: blksz logical, intent(inout) :: message !------------------------------------------------------------------------------- ! Local variables: ! nblks ! lblksz ! tot_pts ! nb ! ix ! ii ! jj ! text !------------------------------------------------------------------------------- integer :: nblks, lblksz, tot_pts, nb, ix, ii, jj character(len=256) :: text tot_pts = (iec - isc + 1) * (jec - jsc + 1) if (blksz < 0) then nblks = 1 blksz = tot_pts else if (mod(tot_pts,blksz) .eq. 0) then nblks = tot_pts/blksz else nblks = ceiling(real(tot_pts)/real(blksz)) endif endif if (message) then if (mod(tot_pts,blksz) .ne. 0) then write( text,'(a,a,2i4,a,i4,a,i4)' ) trim(component),'define_blocks_packed: domain (',& (iec-isc+1), (jec-jsc+1),') is not an even divisor with definition (',& blksz,') - blocks will not be uniform with a remainder of ',mod(tot_pts,blksz) call mpp_error (WARNING, trim(text)) endif message = .false. endif Block%isc = isc Block%iec = iec Block%jsc = jsc Block%jec = jec Block%npz = kpts Block%nblks = nblks if (.not. _ALLOCATED(Block%blksz)) & allocate (Block%blksz(nblks), & Block%index(nblks), & Block%blkno(isc:iec,jsc:jec), & Block%ixp(isc:iec,jsc:jec)) !--- set up blocks do nb = 1, nblks lblksz = blksz if (nb .EQ. nblks) lblksz = tot_pts - (nb-1) * blksz Block%blksz(nb) = lblksz allocate (Block%index(nb)%ii(lblksz), & Block%index(nb)%jj(lblksz)) enddo !--- set up packed indices nb = 1 ix = 0 do jj = jsc, jec do ii = isc, iec ix = ix + 1 if (ix .GT. blksz) then ix = 1 nb = nb + 1 endif Block%ixp(ii,jj) = ix Block%blkno(ii,jj) = nb Block%index(nb)%ii(ix) = ii Block%index(nb)%jj(ix) = jj enddo enddo end subroutine define_blocks_packed end module block_control_mod