mod_selectgrids.f90 Source File


This file depends on

sourcefile~~mod_selectgrids.f90~~EfferentGraph sourcefile~mod_selectgrids.f90 mod_selectgrids.f90 sourcefile~mod_comm_lib.f90 mod_comm_lib.f90 sourcefile~mod_selectgrids.f90->sourcefile~mod_comm_lib.f90 sourcefile~mod_forest.f90 mod_forest.f90 sourcefile~mod_selectgrids.f90->sourcefile~mod_forest.f90 sourcefile~mod_global_parameters.f90 mod_global_parameters.f90 sourcefile~mod_selectgrids.f90->sourcefile~mod_global_parameters.f90 sourcefile~mod_usr_methods.f90 mod_usr_methods.f90 sourcefile~mod_selectgrids.f90->sourcefile~mod_usr_methods.f90 sourcefile~mod_comm_lib.f90->sourcefile~mod_global_parameters.f90 sourcefile~mod_basic_types.f90 mod_basic_types.f90 sourcefile~mod_global_parameters.f90->sourcefile~mod_basic_types.f90 sourcefile~mod_connectivity.f90 mod_connectivity.f90 sourcefile~mod_global_parameters.f90->sourcefile~mod_connectivity.f90 sourcefile~mod_constants.f90 mod_constants.f90 sourcefile~mod_global_parameters.f90->sourcefile~mod_constants.f90 sourcefile~mod_physicaldata.f90 mod_physicaldata.f90 sourcefile~mod_global_parameters.f90->sourcefile~mod_physicaldata.f90 sourcefile~mod_variables.f90 mod_variables.f90 sourcefile~mod_global_parameters.f90->sourcefile~mod_variables.f90 sourcefile~mod_usr_methods.f90->sourcefile~mod_global_parameters.f90 sourcefile~mod_variables.f90->sourcefile~mod_basic_types.f90

Files dependent on this one

sourcefile~~mod_selectgrids.f90~~AfferentGraph sourcefile~mod_selectgrids.f90 mod_selectgrids.f90 sourcefile~agile.f90 agile.f90 sourcefile~agile.f90->sourcefile~mod_selectgrids.f90 sourcefile~mod_amr_grid.f90 mod_amr_grid.f90 sourcefile~agile.f90->sourcefile~mod_amr_grid.f90 sourcefile~mod_coarsen_refine.f90 mod_coarsen_refine.f90 sourcefile~mod_coarsen_refine.f90->sourcefile~mod_selectgrids.f90 sourcefile~mod_amr_grid.f90->sourcefile~mod_coarsen_refine.f90

Source Code

module mod_selectgrids

  implicit none
  private

  !> Distance, in blocks, from the active zone, for every block of every rank.
  !> The lookups at the bottom of this file index it by (igrid, ipe) straight
  !> out of the neighbour tables, so it stays a full [max_blocks, 0:npe-1]
  !> table.  Only the *exchange* is sized by the number of leaves; see
  !> gather_isafety.  Kept between calls rather than allocated per regrid.
  integer, allocatable :: isafety(:,:)

  !> Exchange buffers for gather_isafety, one entry per leaf.
  integer, allocatable :: sndsafety(:), rcvsafety(:)

  public :: selectgrids

contains

  !> Make every rank's isafety flags known to every rank.
  !>
  !> The flags live in a [max_blocks, 0:npe-1] table, but only the leaves carry
  !> a meaningful value and only the owner of a leaf writes one, so gathering
  !> the whole table would move npe*max_blocks integers - sized by the
  !> allocated bound rather than by the blocks that exist.  Instead each rank
  !> contributes just its own leaves, in Morton order, and the gather moves
  !> nleafs integers in total.
  !>
  !> sfc(1:2, Morton_no) is the globally replicated (igrid, ipe) of each leaf,
  !> and Morton_start/Morton_stop cut it into the per-rank runs, so the counts
  !> and displacements are known to everyone without a handshake and the
  !> scatter back into (igrid, ipe) needs no inverse map.
  subroutine gather_isafety
    use mod_forest
    use mod_global_parameters
    use mod_comm_lib, only: mpistop

    integer :: Morton_no, ipe, nown
    integer :: cnt(0:npe-1), disp(0:npe-1)

    do ipe = 0, npe-1
      cnt(ipe)  = Morton_stop(ipe) - Morton_start(ipe) + 1
      disp(ipe) = Morton_start(ipe) - 1
    end do
    nown = cnt(mype)

    if (.not. allocated(sndsafety)) then
      allocate(sndsafety(max(nleafs,1)), rcvsafety(max(nleafs,1)))
    else if (size(rcvsafety) < nleafs) then
      deallocate(sndsafety, rcvsafety)
      allocate(sndsafety(max(nleafs,1)), rcvsafety(max(nleafs,1)))
    end if

    do Morton_no = Morton_start(mype), Morton_stop(mype)
      ! the run this rank owns must be the run sfc says it owns, or the
      ! displacements below would scatter another rank's flags
      if (sfc(2,Morton_no) /= mype) call mpistop(&
         "gather_isafety: Morton range disagrees with the space-filling curve")
      sndsafety(Morton_no-Morton_start(mype)+1) = isafety(sfc(1,Morton_no),mype)
    end do

    call MPI_ALLGATHERV(sndsafety, nown, MPI_INTEGER, rcvsafety, cnt, disp,&
       MPI_INTEGER, icomm, ierrmpi)

    isafety = -1
    do Morton_no = 1, nleafs
      isafety(sfc(1,Morton_no),sfc(2,Morton_no)) = rcvsafety(Morton_no)
    end do

  end subroutine gather_isafety

  !=============================================================================
  subroutine selectgrids
  
  use mod_forest
  use mod_global_parameters
  use mod_usr_methods, only: usr_flag_grid
  integer :: iigrid, igrid, jgrid, kgrid, isave, my_isafety
  
  ! Set the number of safety-blocks (additional blocks after 
  ! flag_grid_usr): 
  integer, parameter :: nsafety = 1
  integer             :: ixOmin1,ixOmin2,ixOmin3,ixOmax1,ixOmax2,ixOmax3, ipe
  integer             :: Morton_no
  type(tree_node_ptr) :: tree
  integer             :: userflag
  logical             :: have_flag_hook
  !-----------------------------------------------------------------------------
  if (.not. allocated(isafety)) allocate(isafety(max_blocks,0:npe-1))

  ! Whether the user asked for grids to be deactivated at all.  Tested up front
  ! rather than by inspecting the last grid's flag below, because everything
  ! past the early return is collective: a rank that owns no grids never enters
  ! the loop, so the last-flag test made the return condition differ between
  ! ranks and could leave the others inside MPI_ALLGATHERV.
  have_flag_hook = associated(usr_flag_grid)
  
  ! reset all grids to active:
  neighbor_active = .true.
  
        jgrid=0
        kgrid=0
        isafety = -1
        userflag = -1
  
  !     Check the user flag:
        do iigrid=1,igridstail; igrid=igrids(iigrid);
           userflag = igrid_active(igrid)
           if (userflag <= 0) then
              jgrid=jgrid+1
              igrids_active(jgrid)=igrid
           else
              kgrid=kgrid+1
              igrids_passive(kgrid)=igrid
           end if
           isafety(igrid,mype) = userflag
        end do
  
        igridstail_active  = jgrid
        igridstail_passive = kgrid
  
  !     Check if user wants to deactivate grids at all and return if not:
        if (.not. have_flag_hook) then
           
           return
        end if
  
  !     Got the passive grids. 
  !     Now, we re-activate a safety belt of radius nsafety blocks.
  
  !     First communicate the current isafety buffer:
        call gather_isafety
  
  !     Now check the distance of neighbors to the active zone:
        do isave = 1, nsafety
           do iigrid=1,igridstail_passive; igrid=igrids_passive(iigrid);
              if ( isafety(igrid,mype) /= isave) cycle
  !     Get the minimum neighbor isafety:
              if(min_isafety_neighbor(igrid) >= isafety(igrid,mype)) then
  !     Increment the buffer:
                 isafety(igrid,mype)=isafety(igrid,mype)+1
              end if
           end do
           
  !     Communicate the incremented buffers:
           call gather_isafety
        end do
  
  !     Update the active and passive arrays:
        jgrid=0
        kgrid=0
        do iigrid=1,igridstail; igrid=igrids(iigrid);
           if (isafety(igrid,mype) <= nsafety) then
              jgrid=jgrid+1
              igrids_active(jgrid)=igrid
           else 
              kgrid=kgrid+1
              igrids_passive(kgrid)=igrid
           end if
  !     Create the neighbor flags:
           call set_neighbor_state(igrid)
        end do
        igridstail_active  = jgrid
        igridstail_passive = kgrid
  
  !     Update the tree:
  !     Walk the leaves through the space-filling curve rather than scanning
  !     the whole [max_blocks, 0:npe-1] table: sfc lists exactly the blocks
  !     that exist, so this is O(nleafs) and needs no associated() test.
        nleafs_active = 0
        do Morton_no=1,nleafs
           igrid = sfc(1,Morton_no)
           ipe   = sfc(2,Morton_no)
           if (isafety(igrid,ipe) == -1) cycle
           tree%node => igrid_to_node(igrid,ipe)%node
           if (isafety(igrid,ipe) > nsafety) then
              tree%node%active=.false.
           else
              tree%node%active=.true.
              nleafs_active = nleafs_active + 1
           end if
        end do

   
        
        contains
  !=============================================================================
  subroutine set_neighbor_state(igrid)
  
  integer, intent(in)  :: igrid
  integer :: my_neighbor_type, i1,i2,i3, isafety_neighbor
  !-----------------------------------------------------------------------------
  
  
     do i3=-1,1
     do i2=-1,1
     do i1=-1,1
        if (i1==0.and.i2==0.and.i3==0) then 
           if (isafety(igrid,mype) > nsafety) neighbor_active(i1,i2,i3,&
              igrid) = .false.
        end if
        my_neighbor_type=neighbor_type(i1,i2,i3,igrid)
  
        select case (my_neighbor_type)
        case (neighbor_boundary) ! boundary
           isafety_neighbor = nsafety+1
        case (neighbor_coarse) ! fine-coarse
           isafety_neighbor = isafety_fc(i1,i2,i3,igrid)
        case (neighbor_sibling) ! same level
           isafety_neighbor = isafety_srl(i1,i2,i3,igrid)
        case (neighbor_fine) ! coarse-fine
           isafety_neighbor = isafety_cf_max(i1,i2,i3,igrid)
        end select
  
        if (isafety_neighbor > nsafety) neighbor_active(i1,i2,i3,&
           igrid) = .false.
  
     end do
     end do
     end do
  
  end subroutine set_neighbor_state
  !=============================================================================
  integer function min_isafety_neighbor(igrid)
  
  integer, intent(in) :: igrid
  integer :: my_neighbor_type, i1,i2,i3
  !-----------------------------------------------------------------------------
  
  min_isafety_neighbor = biginteger
  
     do i3=-1,1
     do i2=-1,1
     do i1=-1,1
        if (i1==0.and.i2==0.and.i3==0) cycle
        my_neighbor_type=neighbor_type(i1,i2,i3,igrid)
  
        select case (my_neighbor_type)
        case (neighbor_coarse) ! fine-coarse
           min_isafety_neighbor = min(isafety_fc(i1,i2,i3,igrid),&
              min_isafety_neighbor)
        case (neighbor_sibling) ! same level
           min_isafety_neighbor = min(isafety_srl(i1,i2,i3,igrid),&
              min_isafety_neighbor)
        case (neighbor_fine) ! coarse-fine
           min_isafety_neighbor = min(isafety_cf_min(i1,i2,i3,igrid),&
              min_isafety_neighbor)
        end select
  
     end do
     end do
     end do
  
  end function min_isafety_neighbor
  !=============================================================================
  integer function isafety_fc(i1,i2,i3,igrid)
  
  integer, intent(in) :: i1,i2,i3, igrid
  integer            :: ineighbor, ipe_neighbor
  !-----------------------------------------------------------------------------
  ineighbor=neighbor(1,i1,i2,i3,igrid)
  ipe_neighbor=neighbor(2,i1,i2,i3,igrid)
  
        isafety_fc = isafety(ineighbor,ipe_neighbor)
  
  end function isafety_fc
  !=============================================================================
  integer function isafety_srl(i1,i2,i3,igrid)
  
  integer, intent(in) :: i1,i2,i3, igrid
  integer            :: ineighbor, ipe_neighbor
  !-----------------------------------------------------------------------------
  ineighbor=neighbor(1,i1,i2,i3,igrid)
  ipe_neighbor=neighbor(2,i1,i2,i3,igrid)
  
        isafety_srl = isafety(ineighbor,ipe_neighbor)
  
  end function isafety_srl
  !=============================================================================
  integer function isafety_cf_min(i1,i2,i3,igrid)
  
  integer, intent(in) :: i1,i2,i3, igrid
  integer            :: ic1,ic2,ic3, inc1,inc2,inc3
  integer            :: ineighbor, ipe_neighbor
  !-----------------------------------------------------------------------------
  
  isafety_cf_min = biginteger
  
        do ic3=1+int((1-i3)/2),2-int((1+i3)/2)
        inc3=2*i3+ic3
        
        do ic2=1+int((1-i2)/2),2-int((1+i2)/2)
        inc2=2*i2+ic2
        
        do ic1=1+int((1-i1)/2),2-int((1+i1)/2)
        inc1=2*i1+ic1
        
          ineighbor    = neighbor_child(1,inc1,inc2,inc3,igrid)
          ipe_neighbor = neighbor_child(2,inc1,inc2,inc3,igrid)
  
          isafety_cf_min = min(isafety_cf_min,isafety(ineighbor,ipe_neighbor))
  
        end do
        end do
        end do
  
  end function isafety_cf_min
  !=============================================================================
  integer function isafety_cf_max(i1,i2,i3,igrid)
  
  integer, intent(in) :: i1,i2,i3, igrid
  integer            :: ic1,ic2,ic3, inc1,inc2,inc3
  integer            :: ineighbor, ipe_neighbor
  !-----------------------------------------------------------------------------
  
  isafety_cf_max = - biginteger
  
        do ic3=1+int((1-i3)/2),2-int((1+i3)/2)
        inc3=2*i3+ic3
        
        do ic2=1+int((1-i2)/2),2-int((1+i2)/2)
        inc2=2*i2+ic2
        
        do ic1=1+int((1-i1)/2),2-int((1+i1)/2)
        inc1=2*i1+ic1
        
          ineighbor    = neighbor_child(1,inc1,inc2,inc3,igrid)
          ipe_neighbor = neighbor_child(2,inc1,inc2,inc3,igrid)
  
          isafety_cf_max = max(isafety_cf_max,isafety(ineighbor,ipe_neighbor))
  
        end do
        end do
        end do
  
  end function isafety_cf_max
  !=============================================================================
  end subroutine selectgrids
  !=============================================================================
  
  integer function igrid_active(igrid)
    use mod_usr_methods, only: usr_flag_grid
    use mod_global_parameters
  
    integer, intent(in) :: igrid
    integer             :: ixOmin1,ixOmin2,ixOmin3,ixOmax1,ixOmax2,ixOmax3,&
        flag
    !-----------------------------------------------------------------------------
    ixOmin1=ixGlo1+nghostcells;ixOmin2=ixGlo2+nghostcells
    ixOmin3=ixGlo3+nghostcells;ixOmax1=ixGhi1-nghostcells
    ixOmax2=ixGhi2-nghostcells;ixOmax3=ixGhi3-nghostcells;
  
    igrid_active = -1
  
    if (associated(usr_flag_grid)) then
       call usr_flag_grid(global_time,ixGlo1,ixGlo2,ixGlo3,ixGhi1,ixGhi2,&
          ixGhi3,ixOmin1,ixOmin2,ixOmin3,ixOmax1,ixOmax2,ixOmax3,ps(igrid)%w,&
          ps(igrid)%x,igrid_active)
    end if
  
  end function igrid_active
  !=============================================================================

end module mod_selectgrids