Commit 0772b5a6 authored by Jannis Teunissen's avatar Jannis Teunissen

Add support for variables fully defined by a function

This is for example useful to set a variable for a level set function. It avoids
recomputing values at cell centers.
parent a33332b8
......@@ -31,8 +31,7 @@ program dielectric_surface
call af_add_cc_variable(tree, "field_norm", ix=i_field_norm)
call af_add_fc_variable(tree, "field", ix=i_field)
call af_set_cc_methods(tree, i_lsf, af_bc_neumann_zero)
call af_set_cc_methods(tree, i_lsf, funcval=set_lsf)
call af_set_cc_methods(tree, i_rhs, af_bc_neumann_zero)
! If an argument is given, switch to cylindrical coordinates in 2D
......@@ -55,8 +54,6 @@ program dielectric_surface
if (ref_info%n_add == 0) exit
end do
call af_loop_box(tree, set_init_cond)
mg%i_phi = i_phi
mg%i_rhs = i_rhs
mg%i_tmp = i_tmp
......@@ -92,9 +89,10 @@ contains
end if
end subroutine ref_routine
! This routine sets the initial conditions for each box
subroutine set_init_cond(box)
! This routine sets the level set function
subroutine set_lsf(box, iv)
type(box_t), intent(inout) :: box
integer, intent(in) :: iv
integer :: IJK, nc
real(dp) :: rr(NDIM), r0(NDIM), r1(NDIM)
real(dp) :: radius
......@@ -108,10 +106,10 @@ contains
do KJI_DO(0,nc+1)
rr = af_r_cc(box, [IJK])
box%cc(IJK, i_lsf) = dist_vec_line(rr, r0, r1, NDIM) - radius
box%cc(IJK, iv) = dist_vec_line(rr, r0, r1, NDIM) - radius
end do; CLOSE_DO
end subroutine set_init_cond
end subroutine set_lsf
!> Compute distance vector between point and its projection onto a line
!> between r0 and r1
......
......@@ -175,6 +175,8 @@ contains
! Initialize list of cell-centered variables with methods
if (.not. allocated(tree%cc_auto_vars)) &
allocate(tree%cc_auto_vars(0))
if (.not. allocated(tree%cc_func_vars)) &
allocate(tree%cc_func_vars(0))
call af_set_coarse_grid(tree, grid_size, periodic)
......@@ -190,6 +192,7 @@ contains
logical, intent(in), optional :: periodic_dims(NDIM)
logical :: periodic(NDIM)
integer :: nx(NDIM), ix(NDIM), IJK, id, n_boxes, nb
integer :: n, iv
integer, allocatable :: id_array(DTIMES(:))
if (tree%highest_id > 0) &
......@@ -227,29 +230,29 @@ contains
! Loop over the boxes and set their neighbors
#if NDIM == 1
do i = 1, nx(1)
id = id_array(IJK)
tree%boxes(id)%lvl = 1
tree%boxes(id)%ix = [IJK]
tree%boxes(id)%dr = tree%dr_base
tree%boxes(id)%r_min = tree%r_base + &
(tree%boxes(id)%ix - 1) * tree%dr_base * tree%n_cell
tree%boxes(id)%n_cell = tree%n_cell
tree%boxes(id)%coord_t = tree%coord_t
tree%boxes(id)%parent = af_no_box
tree%boxes(id)%children(:) = af_no_box
! Connectivity
do nb = 1, af_num_neighbors
ix = [IJK] + af_neighb_dix(:, nb)
tree%boxes(id)%neighbors(nb) = id_array(ix(1))
end do
tree%boxes(id)%neighbor_mat = id_array(i-1:i+1)
call af_init_box(tree%boxes(id), tree%boxes(id)%n_cell, &
tree%n_var_cell, tree%n_var_face)
do i = 1, nx(1)
id = id_array(IJK)
tree%boxes(id)%lvl = 1
tree%boxes(id)%ix = [IJK]
tree%boxes(id)%dr = tree%dr_base
tree%boxes(id)%r_min = tree%r_base + &
(tree%boxes(id)%ix - 1) * tree%dr_base * tree%n_cell
tree%boxes(id)%n_cell = tree%n_cell
tree%boxes(id)%coord_t = tree%coord_t
tree%boxes(id)%parent = af_no_box
tree%boxes(id)%children(:) = af_no_box
! Connectivity
do nb = 1, af_num_neighbors
ix = [IJK] + af_neighb_dix(:, nb)
tree%boxes(id)%neighbors(nb) = id_array(ix(1))
end do
tree%boxes(id)%neighbor_mat = id_array(i-1:i+1)
call af_init_box(tree%boxes(id), tree%boxes(id)%n_cell, &
tree%n_var_cell, tree%n_var_face)
end do
#elif NDIM == 2
do j = 1, nx(2)
do i = 1, nx(1)
......@@ -308,22 +311,32 @@ contains
tree%highest_lvl = 1
! Set values for variables with a 'funcval'
do i = 1, size(tree%lvls(1)%ids)
id = tree%lvls(1)%ids(i)
do n = 1, size(tree%cc_func_vars)
iv = tree%cc_func_vars(n)
call tree%cc_methods(iv)%funcval(tree%boxes(id), iv)
end do
end do
end subroutine af_set_coarse_grid
!> Set the methods for a cell-centered variable
subroutine af_set_cc_methods(tree, iv, bc, rb, prolong, restrict, &
bc_custom)
bc_custom, funcval)
use m_af_ghostcell, only: af_gc_interp
use m_af_prolong, only: af_prolong_linear
use m_af_restrict, only: af_restrict_box
type(af_t), intent(inout) :: tree !< Tree to operate on
integer, intent(in) :: iv !< Index of variable
procedure(af_subr_bc), optional :: bc !< Boundary condition method
procedure(af_subr_rb), optional :: rb !< Refinement boundary method
procedure(af_subr_prolong), optional :: prolong !< Prolongation method
procedure(af_subr_restrict), optional :: restrict !< Restriction method
type(af_t), intent(inout) :: tree !< Tree to operate on
integer, intent(in) :: iv !< Index of variable
procedure(af_subr_bc), optional :: bc !< Boundary condition method
procedure(af_subr_rb), optional :: rb !< Refinement boundary method
procedure(af_subr_prolong), optional :: prolong !< Prolongation method
procedure(af_subr_restrict), optional :: restrict !< Restriction method
procedure(af_subr_bc_custom), optional :: bc_custom !< Custom b.c. method
integer :: i
procedure(af_subr_funcval), optional :: funcval !< Variable defined by function
integer :: i
if (tree%has_cc_method(iv)) then
print *, "Cannot call af_set_cc_methods twice for ", &
......@@ -337,8 +350,12 @@ contains
tree%cc_methods(i)%bc => bc
else if (present(bc_custom)) then
tree%cc_methods(i)%bc_custom => bc_custom
else
error stop "af_set_cc_methods: either bc or bc_custom required"
else if (.not. present(funcval)) then
error stop "af_set_cc_methods: bc, bc_custom or funcval required"
end if
if (present(funcval)) then
tree%cc_methods(i)%funcval => funcval
end if
if (present(rb)) then
......@@ -364,10 +381,17 @@ contains
if (.not. allocated(tree%cc_auto_vars)) &
allocate(tree%cc_auto_vars(0))
if (.not. allocated(tree%cc_func_vars)) &
allocate(tree%cc_func_vars(0))
! Append only original variable to cc_auto_vars, so that the copies are not
! automatically prolongated etc.
tree%cc_auto_vars = [tree%cc_auto_vars, iv]
! Append only original variable, so that the copies are not automatically
! prolongated etc.
if (present(funcval)) then
tree%cc_func_vars = [tree%cc_func_vars, iv]
else
tree%cc_auto_vars = [tree%cc_auto_vars, iv]
end if
end subroutine af_set_cc_methods
......@@ -381,6 +405,7 @@ contains
deallocate(tree%boxes)
deallocate(tree%removed_ids)
deallocate(tree%cc_auto_vars)
deallocate(tree%cc_func_vars)
do lvl = af_min_lvl, af_max_lvl
deallocate(tree%lvls(lvl)%ids)
......@@ -762,18 +787,17 @@ contains
subroutine auto_restrict(tree, id)
type(af_t), intent(inout) :: tree
integer, intent(in) :: id
integer :: iv, i_ch, ch_id
integer :: i, iv, i_ch, ch_id
if (.not. any(tree%has_cc_method(:))) return
do iv = 1, tree%n_var_cell
if (tree%has_cc_method(iv)) then
do i_ch = 1, af_num_children
ch_id = tree%boxes(id)%children(i_ch)
call tree%cc_methods(iv)%restrict(tree%boxes(ch_id), &
tree%boxes(id), [iv])
end do
end if
do i_ch = 1, af_num_children
ch_id = tree%boxes(id)%children(i_ch)
do i = 1, size(tree%cc_auto_vars)
iv = tree%cc_auto_vars(i)
call tree%cc_methods(iv)%restrict(tree%boxes(ch_id), &
tree%boxes(id), [iv])
end do
end do
end subroutine auto_restrict
......@@ -801,6 +825,10 @@ contains
call tree%cc_methods(iv)%prolong(tree%boxes(p_id), &
tree%boxes(id), iv)
end do
do n = 1, size(tree%cc_func_vars)
iv = tree%cc_func_vars(n)
call tree%cc_methods(iv)%funcval(tree%boxes(id), iv)
end do
end do
!$omp end do
......
......@@ -183,6 +183,8 @@ contains
! Skip methods (these have to be set again)
if (.not. allocated(tree%cc_auto_vars)) &
allocate(tree%cc_auto_vars(0))
if (.not. allocated(tree%cc_func_vars)) &
allocate(tree%cc_func_vars(0))
read(my_unit) tree%cc_names
read(my_unit) tree%fc_names
......
......@@ -247,6 +247,8 @@ module m_af_types
procedure(af_subr_rb), pointer, nopass :: rb => null()
!> Custom boundary condition routine
procedure(af_subr_bc_custom), pointer, nopass :: bc_custom => null()
!> Function defining the values of this variables
procedure(af_subr_funcval), pointer, nopass :: funcval => null()
end type af_cc_methods
!> The basic building block of afivo: a box with cell-centered and face
......@@ -314,6 +316,9 @@ module m_af_types
!> Indices of cell-centered variables with methods
integer, allocatable :: cc_auto_vars(:)
!> Indices of cell-centered variables defined by a function
integer, allocatable :: cc_func_vars(:)
!> List storing the tree levels
type(lvl_t) :: lvls(af_min_lvl:af_max_lvl)
......@@ -420,6 +425,15 @@ module m_af_types
cc(DTIMES(1-n_gc:box%n_cell+n_gc))
end subroutine af_subr_bc_custom
!> To set cell-centered variables based on a user-defined function. This
!> can be useful to avoid recomputing values. The values should also be set
!> in ghost cells.
subroutine af_subr_funcval(box, iv)
import
type(box_t), intent(inout) :: box !< Box to fill values in
integer, intent(in) :: iv !< Index of variable
end subroutine af_subr_funcval
!> Subroutine for prolongation
subroutine af_subr_prolong(box_p, box_c, iv, iv_to, add)
import
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment