Gather/Scatter interfaces
Goal
Create generic interfaces for gather/scatter operations.
Motivation
Gathers and scatters between global fields and fields on the local physics or dynamics decomposition are done for
- history output
- restart I/O
- reading initial files
- reading boundary datasets
- diagnostic output to log file
Lack of a generic interface leads to code like the following in the write_restart_history method of the history module:All of this code is to gather two fields: hbuf and nacs. Similarly large sections of code are used to gather hbuf when the history file is written, and to scatter hbuf and nacs when the restart file is read. The dycore dependence of the gather/scatter methods means that code must be added to all three sections to support a new dycore.select case (tape(t)%hlist(f)%field%decomp_type) case (phys_decomp) call gather_chunk_to_field_hbuf (1, numlev, 1, plon, tape(t)%hlist(f)%hbuf, hbuf) call gather_chunk_to_field_int (1, 1, 1, plon, tape(t)%hlist(f)%nacs, fullnacs) case (dyn_decomp) if ( dycore_is('LR') )then # if ( defined STAGGERED ) h3. NEW LR CODING lenarr = plon[numlev]plat if (tape(t)%hlist(f)%hbuf_prec == 8) then select case (numlev) case (1) call fv_gather('2d', tape(t)%hlist(f)%hbuf%buf8, lenarr, 2, hbuf%buf8) case (plev) call fv_gather('3dxzy', tape(t)%hlist(f)%hbuf%buf8, lenarr, 3, hbuf%buf8) case (plevp) call fv_gather('3dxzyp', tape(t)%hlist(f)%hbuf%buf8, lenarr, 3, hbuf%buf8) case default write(6,*)'WRITE_RESTART_HISTORY: invalid number of levels=', numlev call endrun () end select else select case (numlev) case (1) call fv_gather4('2d', tape(t)%hlist(f)%hbuf%buf4, lenarr, 2, hbuf%buf4) case (plev) call fv_gather4('3dxzy', tape(t)%hlist(f)%hbuf%buf4, lenarr, 3, hbuf%buf4) case (plevp) call fv_gather4('3dxzyp', tape(t)%hlist(f)%hbuf%buf4, lenarr, 3, hbuf%buf4) case default write(6,*)'WRITE_RESTART_HISTORY: invalid number of levels=', numlev call endrun () end select endif call fv_gatheri('2d', tape(t)%hlist(f)%nacs, lenarr, 2, fullnacs) # endif else numowned = coldimin*numlev call compute_gsfactors (numowned, numsend, numrecv, displs) call mpigatherv_hbuf (tape(t)%hlist(f)%hbuf, numsend, mpireal, hbuf, numrecv, & displs, mpireal, 0, mpicom) numowned = coldimin call compute_gsfactors (numowned, numsend, numrecv, displs) call mpigatherv (tape(t)%hlist(f)%nacs, numsend, mpiint, fullnacs, numrecv, & displs, mpiint, 0, mpicom) endif end select
Current interfaces for gathering physics chunks
Gathering physics chunks to global fields is done by the gather_chunk_to_hbuf methods in the phys_grid module:This interface contains references to pcols, plat, begchunk, and endchunk which are present as module data in phys_grid. There are also real(r4) and integer versions which could easily be encapsulated in a generic interface.subroutine gather_chunk_to_field(fdim,mdim,ldim, & nlond,localchunks,globalfield) integer, intent(in) :: fdim ! declared length of first dimension integer, intent(in) :: mdim ! declared length of middle dimension integer, intent(in) :: ldim ! declared length of last dimension integer, intent(in) :: nlond ! declared number of longitudes real(r8), intent(in):: localchunks(fdim,pcols,mdim, & begchunk:endchunk,ldim) ! local chunks real(r8), intent(out) :: globalfield(fdim,nlond,mdim,plat,ldim) ! global field
Current interfaces for gathering FV dycore blocks
The fv_gather methods are contained in the io_dist module. They are implemented using the pargather method of the parutilities module.subroutine fv_gather(decomp_type, arr, lenarr, ndim, bufres) character(len=*) :: decomp_type # if defined( SPMD ) real(r8) arr(*) ! Array to be gathered # else real(r8) arr(lenarr) ! Array (SMP-only) # endif integer lenarr ! Global length of array integer ndim ! dimensionality (2 or 3) of array real(r8), intent(out) :: bufres(*)
Current interfaces for gathering spectral dycore blocks
The spectral dycores only implement a 1D decomposition by latitude slices. There is no single gather routine, but instead the gather is done by first calling the compute_gsfactors routine which sets up the indexing required by the mpigather methods. There is a wrapper routine mpigatherv_hbuf which encapsulates whether mpigatherv is called with the real(r8) or real(r4) version of hbuf. The compute_gsfactors method is contained in the spmd_dyn module and the mpigatherv_hbuf method is contained in the history modulesubroutine compute_gsfactors (numperlat, numtot, numperproc, displs) integer, intent(in) :: numperlat ! number of elements per latitude integer, intent(out) :: numtot ! total number of elements (to send or recv) integer, intent(out) :: numperproc(0:npes-1) ! per-PE number of items to receive integer, intent(out) :: displs(0:npes-1) ! per-PE displacements subroutine mpigatherv_hbuf (hbuf_send, numsend, mpireal1, hbuf_recv, & numrecv, displs, mpireal2, root, comm) type (hbuffer_3d), intent(in ) :: hbuf_send ! send buffer type (hbuffer_3d), intent(inout) :: hbuf_recv ! receive buffer integer :: numsend ! number of items to be sent integer :: mpireal1 ! MPI real data type for hbuf_send integer :: mpireal2 ! MPI real data type for hbuf_recv integer :: numrecv(*) ! number of items to be received integer :: displs(*) ! displacement array integer, intent(in) :: root integer, intent(in) :: comm