mod_multigrid_coupling.f90 Source File


This file depends on

sourcefile~~mod_multigrid_coupling.f90~~EfferentGraph sourcefile~mod_multigrid_coupling.f90 mod_multigrid_coupling.f90 sourcefile~m_octree_mg_3d.f90 m_octree_mg_3d.f90 sourcefile~mod_multigrid_coupling.f90->sourcefile~m_octree_mg_3d.f90 sourcefile~mod_forest.f90 mod_forest.f90 sourcefile~mod_multigrid_coupling.f90->sourcefile~mod_forest.f90 sourcefile~mod_geometry.f90 mod_geometry.f90 sourcefile~mod_multigrid_coupling.f90->sourcefile~mod_geometry.f90 sourcefile~mod_global_parameters.f90 mod_global_parameters.f90 sourcefile~mod_multigrid_coupling.f90->sourcefile~mod_global_parameters.f90 sourcefile~mod_mpi_wrapper.f90 mod_mpi_wrapper.f90 sourcefile~m_octree_mg_3d.f90->sourcefile~mod_mpi_wrapper.f90 sourcefile~mod_geometry.f90->sourcefile~mod_global_parameters.f90 sourcefile~mod_comm_lib.f90 mod_comm_lib.f90 sourcefile~mod_geometry.f90->sourcefile~mod_comm_lib.f90 sourcefile~mod_limiter.f90 mod_limiter.f90 sourcefile~mod_geometry.f90->sourcefile~mod_limiter.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_comm_lib.f90->sourcefile~mod_global_parameters.f90 sourcefile~mod_limiter.f90->sourcefile~mod_global_parameters.f90 sourcefile~mod_limiter.f90->sourcefile~mod_comm_lib.f90 sourcefile~mod_variables.f90->sourcefile~mod_basic_types.f90

Files dependent on this one

sourcefile~~mod_multigrid_coupling.f90~~AfferentGraph sourcefile~mod_multigrid_coupling.f90 mod_multigrid_coupling.f90 sourcefile~agile.f90 agile.f90 sourcefile~agile.f90->sourcefile~mod_multigrid_coupling.f90 sourcefile~mod_initialize_amr.f90 mod_initialize_amr.f90 sourcefile~agile.f90->sourcefile~mod_initialize_amr.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_multigrid_coupling.f90 sourcefile~mod_coarsen_refine.f90->sourcefile~mod_initialize_amr.f90 sourcefile~mod_refine.f90 mod_refine.f90 sourcefile~mod_coarsen_refine.f90->sourcefile~mod_refine.f90 sourcefile~mod_initialize_amr.f90->sourcefile~mod_multigrid_coupling.f90 sourcefile~mod_amr_grid.f90->sourcefile~mod_coarsen_refine.f90 sourcefile~mod_refine.f90->sourcefile~mod_initialize_amr.f90

Source Code

!> Module to couple the octree-mg library to AMRVAC. This file uses the VACPP
!> preprocessor, but its use is kept to a minimum.
module mod_multigrid_coupling
  
  
  
  use m_octree_mg_3d
 


  implicit none
  public

  !> Data structure containing the multigrid tree.
  type(mg_t) :: mg

  !> If defined, this routine is called after a new multigrid tree is
  !> constructed.
  procedure(after_new_tree), pointer :: mg_after_new_tree => null()

  interface
     subroutine after_new_tree()
     end subroutine after_new_tree
  end interface

contains

  !> Setup multigrid for usage
  subroutine mg_setup_multigrid()
    use mod_global_parameters
    use mod_geometry

    if (ndim /= mg_ndim) error stop "Multigrid module was compiled for different ndim"

    select case (coordinate)
    case (Cartesian)
       continue
    case (cylindrical)
       if (ndim == 3) error stop "Multigrid does not support cylindrical 3D"
       mg%geometry_type = mg_cylindrical
    case default
       error stop "Multigrid does not support your geometry"
    end select

    if (any([ block_nx1,block_nx2,block_nx3 ] /= block_nx1)) error stop "Multigrid requires all block_nx to be equal"

    call mg_comm_init(mg)
    call mg_set_methods(mg)
    call mg_tree_from_amrvac(mg)
  end subroutine mg_setup_multigrid

  !> Set multigrid boundary conditions for the solution according to variable iw
  subroutine mg_copy_boundary_conditions(mg, iw)
    use mod_global_parameters
    type(mg_t), intent(inout) :: mg
    integer, intent(in)       :: iw
    character(len=std_len)    :: bnd_name(mg_num_neighbors)
    integer                   :: n

    do n = 1, mg_num_neighbors
       select case (typeboundary(iw, n))
       case (bc_symm)
          mg%bc(n, mg_iphi)%bc_type = mg_bc_neumann
          mg%bc(n, mg_iphi)%bc_value = 0.0_dp
       case (bc_asymm)
          mg%bc(n, mg_iphi)%bc_type = mg_bc_dirichlet
          mg%bc(n, mg_iphi)%bc_value = 0.0_dp
       case (bc_cont)
          mg%bc(n, mg_iphi)%bc_type = mg_bc_continuous
          mg%bc(n, mg_iphi)%bc_value = 0.0_dp ! Not needed
       case (bc_periodic)
          ! Nothing to do here
       case default
          write(*,*) "mg_copy_boundary_conditions: unknown boundary type"
       end select
    end do
  end subroutine mg_copy_boundary_conditions

  !> If the grid has changed, rebuild the full multigrid tree
  subroutine mg_update_refinement(n_coarsen, n_refine)
    use mod_global_parameters
    integer, intent(in) :: n_coarsen
    integer, intent(in) :: n_refine

    ! Don't build multigrid tree while doing initial refinement
    if (.not. time_advance) return

    if (.not. mg%is_allocated) then
       call mg_tree_from_amrvac(mg)
    else if (n_coarsen + n_refine > 0) then
       call mg_deallocate_storage(mg)
       call mg_tree_from_amrvac(mg)
    end if
  end subroutine mg_update_refinement

  !> Copy a variable to the multigrid tree, including a layer of ghost cells
  subroutine mg_copy_to_tree(iw_from, iw_to, restrict, restrict_gc, factor,&
      state_from)
    use mod_global_parameters
    use mod_forest
    integer, intent(in)            :: iw_from
    !< Variable to use as right-hand side
    integer, intent(in)            :: iw_to
    !< Copy to this variable
    logical, intent(in), optional  :: restrict
    !< Restrict variable on multigrid tree
    logical, intent(in), optional  :: restrict_gc
    !< Fill ghost cells after restrict
    real(dp), intent(in), optional :: factor
    !< out = factor * in
    !> If present, use this as the input state
    type(state), intent(in), optional, target :: state_from(max_blocks)
    integer                        :: iigrid, igrid, id
    integer                        :: nc, lvl, ilo1,ilo2,ilo3, ihi1,ihi2,ihi3
    type(tree_node), pointer       :: pnode
    real(dp)                       :: fac
    logical                        :: do_restrict, do_gc

    if (.not. mg%is_allocated) error stop "mg_copy_to_tree: tree not allocated yet"

    fac = 1.0_dp; if (present(factor)) fac = factor
    do_restrict = .false.; if (present(restrict)) do_restrict = restrict
    do_gc = .false.; if (present(restrict_gc)) do_gc = restrict_gc

    ilo1=ixMlo1-1;ilo2=ixMlo2-1;ilo3=ixMlo3-1;
    ihi1=ixMhi1+1;ihi2=ixMhi2+1;ihi3=ixMhi3+1;

    do iigrid = 1, igridstail
       igrid =  igrids(iigrid);
       pnode => igrid_to_node(igrid, mype)%node
       id    =  pnode%id
       lvl   =  mg%boxes(id)%lvl
       nc    =  mg%box_size_lvl(lvl)

       ! Include one layer of ghost cells on grid leaves
       if (present(state_from)) then
          mg%boxes(id)%cc(0:nc+1,0:nc+1,0:nc+1,&
              iw_to) = fac * state_from(igrid)%w(ilo1:ihi1,ilo2:ihi2,ilo3:ihi3,&
              iw_from)
       else
          mg%boxes(id)%cc(0:nc+1,0:nc+1,0:nc+1,&
              iw_to) = fac * ps(igrid)%w(ilo1:ihi1,ilo2:ihi2,ilo3:ihi3,&
              iw_from)
       end if
    end do

    if (do_restrict) then
       call mg_restrict(mg, iw_to)
       if (do_gc) call mg_fill_ghost_cells(mg, iw_to)
    end if

  end subroutine mg_copy_to_tree

  !> Copy a variable from the multigrid tree
  subroutine mg_copy_from_tree(iw_from, iw_to, state_to)
    use mod_global_parameters
    use mod_forest
    integer, intent(in)      :: iw_from
    !< Variable to use as right-hand side
    integer, intent(in)      :: iw_to
    !< Copy to this variable
    !> If present, use this as the output state
    type(state), intent(inout), optional, target :: state_to(max_blocks)
    integer                  :: iigrid, igrid, id
    integer                  :: nc, lvl
    type(tree_node), pointer :: pnode

    if (.not. mg%is_allocated) error stop "mg_copy_from_tree: tree not allocated yet"

    do iigrid = 1, igridstail
       igrid =  igrids(iigrid);
       pnode => igrid_to_node(igrid, mype)%node
       id    =  pnode%id
       lvl   =  mg%boxes(id)%lvl
       nc    =  mg%box_size_lvl(lvl)

       if (present(state_to)) then
          state_to(igrid)%w(ixMlo1:ixMhi1,ixMlo2:ixMhi2,ixMlo3:ixMhi3,&
              iw_to) = mg%boxes(id)%cc(1:nc,1:nc,1:nc, iw_from)
       else
          ps(igrid)%w(ixMlo1:ixMhi1,ixMlo2:ixMhi2,ixMlo3:ixMhi3,&
              iw_to) = mg%boxes(id)%cc(1:nc,1:nc,1:nc, iw_from)
       end if
    end do
  end subroutine mg_copy_from_tree

  !> Copy from multigrid tree with one layer of ghost cells. Corner ghost cells
  !> are not used/set.
  subroutine mg_copy_from_tree_gc(iw_from, iw_to, state_to)
    use mod_global_parameters
    use mod_forest
    integer, intent(in)      :: iw_from
    !< Variable to use as right-hand side
    integer, intent(in)      :: iw_to
    !< Copy to this variable
    !> If present, use this as the output state
    type(state), intent(inout), optional, target :: state_to(max_blocks)
    integer                  :: iigrid, igrid, id
    integer                  :: nc, lvl, ilo1,ilo2,ilo3, ihi1,ihi2,ihi3
    type(tree_node), pointer :: pnode

    if (.not. mg%is_allocated) error stop "mg_copy_from_tree_gc: tree not allocated yet"

    ilo1=ixMlo1-1;ilo2=ixMlo2-1;ilo3=ixMlo3-1;
    ihi1=ixMhi1+1;ihi2=ixMhi2+1;ihi3=ixMhi3+1;

    do iigrid = 1, igridstail
       igrid =  igrids(iigrid);
       pnode => igrid_to_node(igrid, mype)%node
       id    =  pnode%id
       lvl   =  mg%boxes(id)%lvl
       nc    =  mg%box_size_lvl(lvl)

       if (present(state_to)) then
          state_to(igrid)%w(ilo1:ihi1,ilo2:ihi2,ilo3:ihi3,&
              iw_to) = mg%boxes(id)%cc(0:nc+1,0:nc+1,0:nc+1, iw_from)
       else
          ps(igrid)%w(ilo1:ihi1,ilo2:ihi2,ilo3:ihi3,&
              iw_to) = mg%boxes(id)%cc(0:nc+1,0:nc+1,0:nc+1, iw_from)
       end if
    end do
  end subroutine mg_copy_from_tree_gc

  !> Generate a multigrid tree that includes the amrvac tree, but also contains
  !> coarser grid levels. A number of checks has already been performed in
  !> mg_setup_multigrid, so we don't repeat these checks here.
  subroutine mg_tree_from_amrvac(mg)
    use mod_forest
    use mod_global_parameters
    type(mg_t), intent(inout)        :: mg
    integer                          :: i, n, id, ix(ndim)
    integer                          :: n_boxes_total, i_c, c_id, c_ix(ndim)
    integer                          :: min_lvl, lvl
    integer                          :: nb, nb_ix, nb_dim
    integer                          :: n_finer
    type(tree_node), pointer         :: pnode, pnode_ch
    type(tree_node_ptr), allocatable :: id_to_node(:)
    real(dp)                         :: dr_coarse

    ! Estimate number of finer blocks
    n_finer = nparents+nleafs

    call mg_build_rectangle(mg, [ domain_nx1,domain_nx2,domain_nx3 ],&
        block_nx1, dx(:,1), [ xprobmin1,xprobmin2,xprobmin3 ], periodB,&
        n_finer)

    mg%highest_lvl = levmax
    n_boxes_total = mg%n_boxes + n_finer

    ! To link the two trees
    allocate(id_to_node(n_boxes_total))

    ! Link base level
    do i = 1, size(mg%lvls(1)%ids)
       id = mg%lvls(1)%ids(i)
       ix = mg%boxes(id)%ix

       pnode               => tree_root(ix(1),ix(2),ix(3))%node
       pnode%id            =  id
       id_to_node(id)%node => pnode
       mg%boxes(id)%rank   =  pnode%ipe
    end do

    ! Add refinement
    do lvl = 1, mg%highest_lvl
       do i = 1, size(mg%lvls(lvl)%ids)
          id = mg%lvls(lvl)%ids(i)
          pnode => id_to_node(id)%node

          if (.not. pnode%leaf) then
             call mg_add_children(mg, id)

             do i_c = 1, mg_num_children
                c_id = mg%boxes(id)%children(i_c)
                c_ix = mg_child_dix(:, i_c) + 1
                pnode_ch => pnode%child(c_ix(1),c_ix(2),c_ix(3))%node
                id_to_node(c_id)%node => pnode_ch
                pnode_ch%id = c_id
                mg%boxes(c_id)%rank = pnode_ch%ipe
             end do
          end if
       end do

       call mg_set_leaves_parents(mg%boxes, mg%lvls(lvl))

       if (lvl < mg%highest_lvl) then
          call mg_set_next_level_ids(mg, lvl)
          call mg_set_neighbors_lvl(mg, lvl+1)
       end if
    end do

    ! Store boxes with refinement boundaries (from the coarse side)
    do lvl = 1, mg%highest_lvl
       call mg_set_refinement_boundaries(mg%boxes, mg%lvls(lvl))
    end do

    ! Assign boxes to MPI processes
    call mg_load_balance_parents(mg)

    ! Allocate storage for boxes owned by this process
    call mg_allocate_storage(mg)

    if (associated(mg_after_new_tree)) then
       call mg_after_new_tree()
    end if

  end subroutine mg_tree_from_amrvac

end module mod_multigrid_coupling