fold_plan_build Subroutine

public pure subroutine fold_plan_build(plan, ni, px, ng, rx, status)

Build tile rx’s send/receive lists for every peer and both column families. Pure: every north-row rank computes every tile’s receive lists itself (decomp_init arithmetic), so no handshake.

Arguments

Type IntentOptional Attributes Name
type(fold_plan_t), intent(out) :: plan
integer, intent(in) :: ni

Global physical width of the fold row.

integer, intent(in) :: px

Tiles along the fold row.

integer, intent(in) :: ng

Ghost width.

integer, intent(in) :: rx

This tile’s x-coordinate (0-based).

integer, intent(out) :: status

FOLD_PLAN_OK, or FOLD_PLAN_ERR_ARGS.


Calls

proc~~fold_plan_build~~CallsGraph proc~fold_plan_build fold_plan_build proc~fold_receiver_entries fold_receiver_entries proc~fold_plan_build->proc~fold_receiver_entries proc~fold_tile_extent fold_tile_extent proc~fold_plan_build->proc~fold_tile_extent proc~fold_receiver_entries->proc~fold_tile_extent proc~fold_tile_owner fold_tile_owner proc~fold_receiver_entries->proc~fold_tile_owner

Called by

proc~~fold_plan_build~~CalledByGraph proc~fold_plan_build fold_plan_build proc~ocean_fold_exchange_init ocean_fold_exchange_init proc~ocean_fold_exchange_init->proc~fold_plan_build proc~engine_setup engine_setup proc~engine_setup->proc~ocean_fold_exchange_init proc~complete_ocean_create complete_ocean_create proc~complete_ocean_create->proc~engine_setup proc~driver_run_ocean driver_run_ocean proc~driver_run_ocean->proc~engine_setup proc~driver_validate driver_validate proc~driver_validate->proc~engine_setup proc~driver_run driver_run proc~driver_run->proc~driver_run_ocean proc~rdb_ocean_create_finalize rdb_ocean_create_finalize proc~rdb_ocean_create_finalize->proc~complete_ocean_create proc~rdb_ocean_create_from_string rdb_ocean_create_from_string proc~rdb_ocean_create_from_string->proc~complete_ocean_create

Variables

Type Visibility Attributes Name Initial
integer, private :: a
integer, private, allocatable :: cls(:)
integer, private :: fam
integer, private :: i
integer, private :: k
integer, private :: kr
integer, private :: ks
integer, private :: ncap
integer, private :: ncol
integer, private, allocatable :: own(:)
integer, private :: p
integer, private, allocatable :: pidx(:)
integer, private :: r
integer, private, allocatable :: rn(:,:)
integer, private, allocatable :: sn(:,:)
integer, private, allocatable :: src(:)
integer, private :: w
integer, private :: wmax

Source Code

   pure subroutine fold_plan_build(plan, ni, px, ng, rx, status)
      !! Build tile `rx`'s send/receive lists for every peer and both
      !! column families.  Pure: every north-row rank computes every tile's
      !! receive lists itself (`decomp_init` arithmetic), so no handshake.
      type(fold_plan_t), intent(out) :: plan
      integer, intent(in) :: ni
         !! Global physical width of the fold row.
      integer, intent(in) :: px
         !! Tiles along the fold row.
      integer, intent(in) :: ng
         !! Ghost width.
      integer, intent(in) :: rx
         !! This tile's x-coordinate (0-based).
      integer, intent(out) :: status
         !! `FOLD_PLAN_OK`, or `FOLD_PLAN_ERR_ARGS`.

      integer, allocatable :: own(:), src(:), cls(:)
      integer, allocatable :: sn(:, :), rn(:, :), pidx(:)
      integer :: ncap, ncol, fam, r, i, p, k, ks, kr
      integer :: wmax, a, w

      status = FOLD_PLAN_OK
      if (px < 1 .or. ng < 1 .or. ni < px .or. rx < 0 .or. rx >= px) then
         status = FOLD_PLAN_ERR_ARGS
         return
      end if

      plan%ni = ni
      plan%px = px
      plan%ng = ng
      plan%rx = rx

      call fold_tile_extent(ni, px, 0, a, wmax)   ! tile 0 is the widest
      ncap = wmax + 2*ng + 1
      allocate (own(ncap), src(ncap), cls(ncap))
      ! Per-tile counts, indexed by tile x-coordinate 0..px-1.
      allocate (sn(0:px - 1, FOLD_NFAM), rn(0:px - 1, FOLD_NFAM))
      sn = 0
      rn = 0

      ! Pass 1: counts.  Receive: my own window, by owner.  Send: every
      ! receiver's window, the entries whose owner is me.
      do fam = 1, FOLD_NFAM
         do r = 0, px - 1
            call fold_receiver_entries(ni, px, ng, fam, r, ncol, own, src, cls)
            do i = 1, ncol
               if (r == rx) rn(own(i), fam) = rn(own(i), fam) + 1
               if (own(i) == rx) sn(r, fam) = sn(r, fam) + 1
            end do
         end do
      end do

      ! Peers: ascending tile order, union of send and receive partners.
      allocate (pidx(0:px - 1))
      pidx = 0
      plan%npeer = 0
      do r = 0, px - 1
         if (sum(sn(r, :)) + sum(rn(r, :)) > 0) then
            plan%npeer = plan%npeer + 1
            pidx(r) = plan%npeer
         end if
      end do
      allocate (plan%peer_rx(plan%npeer))
      allocate (plan%send_n(plan%npeer, FOLD_NFAM), plan%send_start(plan%npeer, FOLD_NFAM))
      allocate (plan%recv_n(plan%npeer, FOLD_NFAM), plan%recv_start(plan%npeer, FOLD_NFAM))
      do r = 0, px - 1
         if (pidx(r) > 0) then
            plan%peer_rx(pidx(r)) = r
            plan%send_n(pidx(r), :) = sn(r, :)
            plan%recv_n(pidx(r), :) = rn(r, :)
         end if
      end do
      plan%self_peer = pidx(rx)

      ! Offsets: family-major, then peer, into one flat array per side.
      ks = 0
      kr = 0
      do fam = 1, FOLD_NFAM
         do p = 1, plan%npeer
            plan%send_start(p, fam) = ks
            plan%recv_start(p, fam) = kr
            ks = ks + plan%send_n(p, fam)
            kr = kr + plan%recv_n(p, fam)
         end do
         plan%nsend(fam) = sum(plan%send_n(:, fam))
         plan%nrecv(fam) = sum(plan%recv_n(:, fam))
      end do
      plan%nmax = 0
      if (plan%npeer > 0) plan%nmax = max(maxval(plan%send_n), maxval(plan%recv_n))
      allocate (plan%send_col(max(ks, 1)), plan%send_peer(max(ks, 1)), plan%send_e(max(ks, 1)))
      allocate (plan%recv_col(max(kr, 1)), plan%recv_peer(max(kr, 1)), &
                plan%recv_e(max(kr, 1)), plan%recv_cls(max(kr, 1)))

      ! Pass 2: fill, in the canonical order (receiver's destination
      ! columns ascending).  `sn`/`rn` are reused as running cursors.
      sn = 0
      rn = 0
      do fam = 1, FOLD_NFAM
         do r = 0, px - 1
            call fold_receiver_entries(ni, px, ng, fam, r, ncol, own, src, cls)
            do i = 1, ncol
               if (r == rx) then
                  p = pidx(own(i))
                  rn(own(i), fam) = rn(own(i), fam) + 1
                  k = plan%recv_start(p, fam) + rn(own(i), fam)
                  plan%recv_col(k) = i
                  plan%recv_peer(k) = p
                  plan%recv_e(k) = rn(own(i), fam)
                  plan%recv_cls(k) = cls(i)
               end if
               if (own(i) == rx) then
                  p = pidx(r)
                  sn(r, fam) = sn(r, fam) + 1
                  k = plan%send_start(p, fam) + sn(r, fam)
                  plan%send_col(k) = src(i)
                  plan%send_peer(k) = p
                  plan%send_e(k) = sn(r, fam)
               end if
            end do
         end do
      end do
   end subroutine fold_plan_build