30 integer,
parameter,
public ::
dp = kind(0.0d0)
33 integer,
parameter,
public ::
i8 = selected_int_kind(18)
112 [0,0,0, 1,0,0, 0,1,0, 1,1,0, &
113 0,0,1, 1,0,1, 0,1,1, 1,1,1], [3,8])
116 [2,1,4,3,6,5,8,7, 3,4,1,2,7,8,5,6, 5,6,7,8,1,2,3,4], [8,3])
119 [1,3,5,7, 2,4,6,8, 1,2,5,6, 3,4,7,8, 1,2,3,4, 5,6,7,8], [4,6])
122 .true., .true., .true., .false., .true., .true., &
123 .true., .false., .true., .false., .false., .true., &
124 .true., .true., .false., .false., .true., .false., &
125 .true., .false., .false., .false., .false., .false.], [3, 8])
137 [-1,0,0, 1,0,0, 0,-1,0, 0,1,0, 0,0,-1, 0,0,1], [3,6])
140 [.true., .false., .true., .false., .true., .false.]
150 integer,
allocatable :: leaves(:)
151 integer,
allocatable :: parents(:)
152 integer,
allocatable :: ref_bnds(:)
153 integer,
allocatable :: ids(:)
154 integer,
allocatable :: my_leaves(:)
155 integer,
allocatable :: my_parents(:)
156 integer,
allocatable :: my_ref_bnds(:)
157 integer,
allocatable :: my_ids(:)
167 integer :: children(2**3)
168 integer :: neighbors(2*3)
172 real(
dp),
allocatable :: cc(:, :, :, :)
180 integer,
allocatable :: ix(:)
181 real(
dp),
allocatable :: send(:)
182 real(
dp),
allocatable :: recv(:)
186 integer,
allocatable :: n_send(:, :)
187 integer,
allocatable :: n_recv(:, :)
192 real(
dp) :: bc_value = 0.0_dp
194 procedure(
mg_subr_bc),
pointer,
nopass :: boundary_cond => null()
196 procedure(mg_subr_rb),
pointer,
nopass :: refinement_bnd => null()
200 character(len=20) :: name
201 real(
dp) :: t = 0.0_dp
207 logical :: tree_created = .false.
209 logical :: is_allocated = .false.
211 integer :: n_extra_vars = 0
215 integer :: n_cpu = -1
217 integer :: my_rank = -1
219 integer :: box_size = -1
221 integer :: highest_lvl = -1
223 integer :: lowest_lvl = -1
226 integer :: first_normal_lvl = -1
228 integer :: n_boxes = 0
253 logical :: phi_bc_data_stored = .false.
256 logical :: periodic(3) = .false.
271 integer :: n_smoother_substeps = 1
273 integer :: n_cycle_down = 2
275 integer :: n_cycle_up = 2
277 integer :: max_coarse_cycles = 1000
278 integer :: coarsest_grid(3) = 2
280 real(
dp) :: residual_coarse_abs = 1e-8_dp
282 real(
dp) :: residual_coarse_rel = 1e-8_dp
285 procedure(mg_box_op),
pointer,
nopass :: box_op => null()
288 procedure(mg_box_gsrb),
pointer,
nopass :: box_smoother => null()
291 procedure(mg_box_prolong),
pointer,
nopass :: box_prolong => null()
294 integer :: n_timers = 0
303 type(mg_box_t),
intent(in) :: box
304 integer,
intent(in) :: nc
305 integer,
intent(in) :: iv
306 integer,
intent(in) :: nb
307 integer,
intent(out) :: bc_type
309 real(dp),
intent(out) :: bc(nc, nc)
313 subroutine mg_subr_rb(box, nc, iv, nb, cgc)
315 type(mg_box_t),
intent(inout) :: box
316 integer,
intent(in) :: nc
317 integer,
intent(in) :: iv
318 integer,
intent(in) :: nb
320 real(dp),
intent(in) :: cgc(nc, nc)
321 end subroutine mg_subr_rb
324 subroutine mg_box_op(mg, id, nc, i_out)
326 type(mg_t),
intent(inout) :: mg
327 integer,
intent(in) :: id
328 integer,
intent(in) :: nc
329 integer,
intent(in) :: i_out
330 end subroutine mg_box_op
333 subroutine mg_box_gsrb(mg, id, nc, redblack_cntr)
335 type(mg_t),
intent(inout) :: mg
336 integer,
intent(in) :: id
337 integer,
intent(in) :: nc
338 integer,
intent(in) :: redblack_cntr
339 end subroutine mg_box_gsrb
342 subroutine mg_box_prolong(mg, p_id, dix, nc, iv, fine)
344 type(mg_t),
intent(inout) :: mg
345 integer,
intent(in) :: p_id
346 integer,
intent(in) :: dix(3)
347 integer,
intent(in) :: nc
348 integer,
intent(in) :: iv
349 real(dp),
intent(out) :: fine(nc, nc, nc)
350 end subroutine mg_box_prolong
357 public :: mg_box_gsrb
358 public :: mg_box_prolong
462 integer :: timer_total_vcycle = -1
463 integer :: timer_total_fmg = -1
464 integer :: timer_smoother = -1
465 integer :: timer_smoother_gc = -1
466 integer :: timer_coarse = -1
467 integer :: timer_correct = -1
468 integer :: timer_update_coarse = -1
485 Integer,
Parameter :: kdp = selected_real_kind(15)
490 module procedure i_mrgrnk
520 integer,
intent(in) :: ix(3)
523 2 * iand(ix(2), 1) - iand(ix(1), 1)
530 type(
mg_t),
intent(in) :: mg
531 integer,
intent(in) :: id
532 integer :: ix_offset(3)
534 if (mg%boxes(id)%lvl <= mg%first_normal_lvl)
then
537 ix_offset = iand(mg%boxes(id)%ix-1, 1) * &
538 ishft(mg%box_size, -1)
543 type(
mg_t),
intent(in) :: mg
546 do lvl = mg%first_normal_lvl, mg%highest_lvl-1
548 if (
size(mg%lvls(lvl)%leaves) /= 0 .and. &
549 size(mg%lvls(lvl)%parents) /= 0)
exit
556 type(
mg_t),
intent(in) :: mg
558 integer(i8) :: n_unknowns
561 do lvl = mg%first_normal_lvl, mg%highest_lvl
562 n_unknowns = n_unknowns +
size(mg%lvls(lvl)%leaves)
564 n_unknowns = n_unknowns * int(mg%box_size**3,
i8)
570 integer,
intent(in) :: nb
571 integer,
intent(in) :: nc
572 real(
dp),
intent(out) :: x(nc, nc, 3)
573 integer :: i, j, ixs(3-1)
580 ixs = [(i, i = 1, 3-1)]
581 ixs(nb_dim:) = ixs(nb_dim:) + 1
585 rmin(nb_dim) = rmin(nb_dim) + box%dr(nb_dim) * nc
591 x(i, j, ixs) = x(i, j, ixs) + ([i, j] - 0.5d0) * box%dr(ixs)
597 type(
mg_t),
intent(inout) :: mg
598 character(len=*),
intent(in) :: name
600 mg%n_timers = mg%n_timers + 1
608 timer%t0 = mpi_wtime()
614 timer%t = timer%t + mpi_wtime() - timer%t0
619 type(
mg_t),
intent(in) :: mg
621 real(
dp) :: tmin(mg%n_timers)
622 real(
dp) :: tmax(mg%n_timers)
624 call mpi_reduce(mg%timers(1:mg%n_timers)%t, tmin, mg%n_timers, &
625 mpi_double, mpi_min, 0, mg%comm, ierr)
626 call mpi_reduce(mg%timers(1:mg%n_timers)%t, tmax, mg%n_timers, &
627 mpi_double, mpi_max, 0, mg%comm, ierr)
629 if (mg%my_rank == 0)
then
630 write(*,
"(A20,2A16)")
"name ",
"min(s)",
"max(s)"
631 do n = 1, mg%n_timers
632 write(*,
"(A20,2F16.6)") mg%timers(n)%name, &
642 type(
mg_t),
intent(inout) :: mg
645 if (.not. mg%is_allocated) &
646 error stop
"deallocate_storage: tree is not allocated"
651 deallocate(mg%comm_restrict%n_send)
652 deallocate(mg%comm_restrict%n_recv)
654 deallocate(mg%comm_prolong%n_send)
655 deallocate(mg%comm_prolong%n_recv)
657 deallocate(mg%comm_ghostcell%n_send)
658 deallocate(mg%comm_ghostcell%n_recv)
660 do lvl = mg%lowest_lvl, mg%highest_lvl
661 deallocate(mg%lvls(lvl)%ids)
662 deallocate(mg%lvls(lvl)%leaves)
663 deallocate(mg%lvls(lvl)%parents)
664 deallocate(mg%lvls(lvl)%ref_bnds)
665 deallocate(mg%lvls(lvl)%my_ids)
666 deallocate(mg%lvls(lvl)%my_leaves)
667 deallocate(mg%lvls(lvl)%my_parents)
668 deallocate(mg%lvls(lvl)%my_ref_bnds)
671 mg%is_allocated = .false.
673 mg%phi_bc_data_stored = .false.
680 type(
mg_t),
intent(inout) :: mg
681 integer :: i, id, lvl, nc
682 integer :: n_send(0:mg%n_cpu-1, 3)
683 integer :: n_recv(0:mg%n_cpu-1, 3)
685 integer :: n_in, n_out, n_id
687 if (.not. mg%tree_created) &
688 error stop
"allocate_storage: tree is not yet created"
690 if (mg%is_allocated) &
691 error stop
"allocate_storage: tree is already allocated"
693 do lvl = mg%lowest_lvl, mg%highest_lvl
694 nc = mg%box_size_lvl(lvl)
695 do i = 1,
size(mg%lvls(lvl)%my_ids)
696 id = mg%lvls(lvl)%my_ids(i)
697 allocate(mg%boxes(id)%cc(0:nc+1, 0:nc+1, 0:nc+1, &
701 mg%boxes(id)%cc(:, :, :, :) = 0.0_dp
705 allocate(mg%buf(0:mg%n_cpu-1))
708 n_recv(:, 1), dsize(1))
710 n_recv(:, 2), dsize(2))
712 n_recv(:, 3), dsize(3))
715 n_out = maxval(n_send(i, :) * dsize(:))
716 n_in = maxval(n_recv(i, :) * dsize(:))
717 n_id = maxval(n_send(i, :))
718 allocate(mg%buf(i)%send(n_out))
719 allocate(mg%buf(i)%recv(n_in))
720 allocate(mg%buf(i)%ix(n_id))
723 mg%is_allocated = .true.
733 type(
mg_t),
intent(inout) :: mg
734 real(
dp),
intent(in) :: dt
735 real(
dp),
intent(in) :: diffusion_coeff
736 integer,
intent(in) :: order
737 real(
dp),
intent(in) :: max_res
738 integer,
parameter :: max_its = 10
748 call set_rhs(mg, -1/(dt * diffusion_coeff), 0.0_dp)
753 call set_rhs(mg, -2/(dt * diffusion_coeff), -1.0_dp)
755 error stop
"diffusion_solve: order should be 1 or 2"
763 if (res <= max_res)
exit
767 if (n == max_its + 1)
then
768 if (mg%my_rank == 0) &
769 print *,
"Did you specify boundary conditions correctly?"
770 error stop
"diffusion_solve: no convergence"
780 type(
mg_t),
intent(inout) :: mg
781 real(
dp),
intent(in) :: dt
782 integer,
intent(in) :: order
783 real(
dp),
intent(in) :: max_res
784 integer,
parameter :: max_its = 10
794 call set_rhs(mg, -1/dt, 0.0_dp)
799 call set_rhs(mg, -2/dt, -1.0_dp)
801 error stop
"diffusion_solve: order should be 1 or 2"
809 if (res <= max_res)
exit
813 if (n == max_its + 1)
then
814 if (mg%my_rank == 0)
then
815 print *,
"Did you specify boundary conditions correctly?"
816 print *,
"Or is the variation in diffusion too large?"
818 error stop
"diffusion_solve: no convergence"
829 type(
mg_t),
intent(inout) :: mg
830 real(
dp),
intent(in) :: dt
831 integer,
intent(in) :: order
832 real(
dp),
intent(in) :: max_res
833 integer,
parameter :: max_its = 10
843 call set_rhs(mg, -1/dt, 0.0_dp)
848 call set_rhs(mg, -2/dt, -1.0_dp)
850 error stop
"diffusion_solve: order should be 1 or 2"
858 if (res <= max_res)
exit
862 if (n == max_its + 1)
then
863 if (mg%my_rank == 0)
then
864 print *,
"Did you specify boundary conditions correctly?"
865 print *,
"Or is the variation in diffusion too large?"
867 error stop
"diffusion_solve: no convergence"
871 subroutine set_rhs(mg, f1, f2)
872 type(
mg_t),
intent(inout) :: mg
873 real(
dp),
intent(in) :: f1, f2
874 integer :: lvl, i, id, nc
876 do lvl = 1, mg%highest_lvl
877 nc = mg%box_size_lvl(lvl)
878 do i = 1,
size(mg%lvls(lvl)%my_leaves)
879 id = mg%lvls(lvl)%my_leaves(i)
880 mg%boxes(id)%cc(1:nc, 1:nc, 1:nc,
mg_irhs) = &
881 f1 * mg%boxes(id)%cc(1:nc, 1:nc, 1:nc,
mg_iphi) + &
882 f2 * mg%boxes(id)%cc(1:nc, 1:nc, 1:nc,
mg_irhs)
885 end subroutine set_rhs
890 type(
mg_t),
intent(inout) :: mg
892 if (all(mg%periodic))
then
895 mg%subtract_mean = .true.
898 select case (mg%geometry_type)
902 select case (mg%smoother_type)
906 mg%box_smoother => box_gs_lpl
908 error stop
"laplacian_set_methods: unsupported smoother type"
911 error stop
"laplacian_set_methods: unsupported geometry"
917 subroutine box_gs_lpl(mg, id, nc, redblack_cntr)
918 type(
mg_t),
intent(inout) :: mg
919 integer,
intent(in) :: id
920 integer,
intent(in) :: nc
921 integer,
intent(in) :: redblack_cntr
922 integer :: i, j, k, i0, di
923 real(
dp) :: idr2(3), fac
925 real(
dp),
parameter :: sixth = 1/6.0_dp
927 idr2 = 1/mg%dr(:, mg%boxes(id)%lvl)**2
928 fac = 0.5_dp / sum(idr2)
940 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
944 i0 = 2 - iand(ieor(redblack_cntr, k+j), 1)
946 cc(i, j, k, n) = fac * ( &
947 idr2(1) * (cc(i+1, j, k, n) + cc(i-1, j, k, n)) + &
948 idr2(2) * (cc(i, j+1, k, n) + cc(i, j-1, k, n)) + &
949 idr2(3) * (cc(i, j, k+1, n) + cc(i, j, k-1, n)) - &
955 end subroutine box_gs_lpl
996 subroutine box_lpl(mg, id, nc, i_out)
997 type(
mg_t),
intent(inout) :: mg
998 integer,
intent(in) :: id
999 integer,
intent(in) :: nc
1000 integer,
intent(in) :: i_out
1004 idr2 = 1 / mg%dr(:, mg%boxes(id)%lvl)**2
1006 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
1010 cc(i, j, k, i_out) = &
1011 idr2(1) * (cc(i-1, j, k, n) + cc(i+1, j, k, n) &
1012 - 2 * cc(i, j, k, n)) &
1013 + idr2(2) * (cc(i, j-1, k, n) + cc(i, j+1, k, n) &
1014 - 2 * cc(i, j, k, n)) &
1015 + idr2(3) * (cc(i, j, k-1, n) + cc(i, j, k+1, n) &
1016 - 2 * cc(i, j, k, n))
1021 end subroutine box_lpl
1027 type(
mg_t),
intent(inout) :: mg
1029 if (mg%n_extra_vars == 0 .and. mg%is_allocated)
then
1030 error stop
"vhelmholtz_set_methods: mg%n_extra_vars == 0"
1032 mg%n_extra_vars = max(1, mg%n_extra_vars)
1035 mg%subtract_mean = .false.
1040 mg%bc(:,
mg_iveps)%bc_value = 0.0_dp
1042 select case (mg%geometry_type)
1044 mg%box_op => box_vhelmh
1046 select case (mg%smoother_type)
1048 mg%box_smoother => box_gs_vhelmh
1050 error stop
"vhelmholtz_set_methods: unsupported smoother type"
1053 error stop
"vhelmholtz_set_methods: unsupported geometry"
1059 real(
dp),
intent(in) :: lambda
1062 error stop
"vhelmholtz_set_lambda: lambda < 0 not allowed"
1068 subroutine box_gs_vhelmh(mg, id, nc, redblack_cntr)
1069 type(
mg_t),
intent(inout) :: mg
1070 integer,
intent(in) :: id
1071 integer,
intent(in) :: nc
1072 integer,
intent(in) :: redblack_cntr
1073 integer :: i, j, k, i0, di
1075 real(
dp) :: idr2(2*3), u(2*3)
1076 real(
dp) :: a0, a(2*3), c(2*3)
1079 idr2(1:2*3:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1080 idr2(2:2*3:2) = idr2(1:2*3:2)
1092 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1097 i0 = 2 - iand(ieor(redblack_cntr, k+j), 1)
1099 a0 = cc(i, j, k, i_eps)
1100 u(1:2) = cc(i-1:i+1:2, j, k, n)
1101 a(1:2) = cc(i-1:i+1:2, j, k, i_eps)
1102 u(3:4) = cc(i, j-1:j+1:2, k, n)
1103 a(3:4) = cc(i, j-1:j+1:2, k, i_eps)
1104 u(5:6) = cc(i, j, k-1:k+1:2, n)
1105 a(5:6) = cc(i, j, k-1:k+1:2, i_eps)
1106 c(:) = 2 * a0 * a(:) / (a0 + a(:)) * idr2
1108 cc(i, j, k, n) = (sum(c(:) * u(:)) - &
1115 end subroutine box_gs_vhelmh
1118 subroutine box_vhelmh(mg, id, nc, i_out)
1119 type(
mg_t),
intent(inout) :: mg
1120 integer,
intent(in) :: id
1121 integer,
intent(in) :: nc
1122 integer,
intent(in) :: i_out
1124 real(
dp) :: idr2(2*3), a0, u0, u(2*3), a(2*3)
1127 idr2(1:2*3:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1128 idr2(2:2*3:2) = idr2(1:2*3:2)
1130 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1136 a0 = cc(i, j, k, i_eps)
1137 u(1:2) = cc(i-1:i+1:2, j, k, n)
1138 u(3:4) = cc(i, j-1:j+1:2, k, n)
1139 u(5:6) = cc(i, j, k-1:k+1:2, n)
1140 a(1:2) = cc(i-1:i+1:2, j, k, i_eps)
1141 a(3:4) = cc(i, j-1:j+1:2, k, i_eps)
1142 a(5:6) = cc(i, j, k-1:k+1:2, i_eps)
1144 cc(i, j, k, i_out) = sum(2 * idr2 * &
1145 a0*a(:)/(a0 + a(:)) * (u(:) - u0)) - &
1151 end subroutine box_vhelmh
1157 type(
mg_t),
intent(inout) :: mg
1158 integer,
intent(in) :: domain_size(3)
1159 integer,
intent(in) :: box_size
1160 real(
dp),
intent(in) :: dx(3)
1161 real(
dp),
intent(in) :: r_min(3)
1162 logical,
intent(in) :: periodic(3)
1163 integer,
intent(in) :: n_finer
1164 integer :: i, j, k, lvl, n, id, nx(3)
1165 integer :: boxes_per_dim(3,
mg_lvl_lo:1)
1166 integer :: periodic_offset(3)
1168 if (modulo(box_size, 2) /= 0) &
1169 error stop
"box_size should be even"
1170 if (any(modulo(domain_size, box_size) /= 0)) &
1171 error stop
"box_size does not divide domain_size"
1173 if (all(periodic))
then
1174 mg%subtract_mean = .true.
1178 mg%box_size = box_size
1179 mg%box_size_lvl(1) = box_size
1180 mg%domain_size_lvl(:, 1) = domain_size
1181 mg%first_normal_lvl = 1
1184 mg%periodic = periodic
1185 boxes_per_dim(:, :) = 0
1186 boxes_per_dim(:, 1) = domain_size / box_size
1191 if (any(modulo(nx, 2) == 1 .or. nx == mg%coarsest_grid .or. &
1192 (mg%box_size_lvl(lvl) == mg%coarsest_grid .and. &
1195 if (all(modulo(nx/mg%box_size_lvl(lvl), 2) == 0))
then
1196 mg%box_size_lvl(lvl-1) = mg%box_size_lvl(lvl)
1197 boxes_per_dim(:, lvl-1) = boxes_per_dim(:, lvl)/2
1198 mg%first_normal_lvl = lvl-1
1200 mg%box_size_lvl(lvl-1) = mg%box_size_lvl(lvl)/2
1201 boxes_per_dim(:, lvl-1) = boxes_per_dim(:, lvl)
1204 mg%dr(:, lvl-1) = mg%dr(:, lvl) * 2
1206 mg%domain_size_lvl(:, lvl-1) = nx
1213 mg%dr(:, lvl) = mg%dr(:, lvl-1) * 0.5_dp
1214 mg%box_size_lvl(lvl) = box_size
1215 mg%domain_size_lvl(:, lvl) = 2 * mg%domain_size_lvl(:, lvl-1)
1218 n = sum(product(boxes_per_dim, dim=1)) + n_finer
1219 allocate(mg%boxes(n))
1222 nx = boxes_per_dim(:, mg%lowest_lvl)
1223 periodic_offset = [nx(1)-1, (nx(2)-1)*nx(1), &
1224 (nx(3)-1) * nx(2) * nx(1)]
1226 do k=1,nx(3);
do j=1,nx(2);
do i=1,nx(1)
1227 mg%n_boxes = mg%n_boxes + 1
1230 mg%boxes(n)%rank = 0
1232 mg%boxes(n)%lvl = mg%lowest_lvl
1233 mg%boxes(n)%ix(:) = [i, j, k]
1234 mg%boxes(n)%r_min(:) = r_min + (mg%boxes(n)%ix(:) - 1) * &
1235 mg%box_size_lvl(mg%lowest_lvl) * mg%dr(:, mg%lowest_lvl)
1236 mg%boxes(n)%dr(:) = mg%dr(:, mg%lowest_lvl)
1241 mg%boxes(n)%neighbors(:) = [n-1, n+1, n-nx(1), n+nx(1), &
1242 n-nx(1)*nx(2), n+nx(1)*nx(2)]
1245 where ([i, j, k] == 1 .and. .not. periodic)
1249 where ([i, j, k] == 1 .and. periodic)
1254 where ([i, j, k] == nx .and. .not. periodic)
1258 where ([i, j, k] == nx .and. periodic)
1262 end do;
end do;
end do
1264 mg%lvls(mg%lowest_lvl)%ids = [(n, n=1, mg%n_boxes)]
1267 do lvl = mg%lowest_lvl, 0
1268 if (mg%box_size_lvl(lvl+1) == mg%box_size_lvl(lvl))
then
1269 do i = 1,
size(mg%lvls(lvl)%ids)
1270 id = mg%lvls(lvl)%ids(i)
1278 do i = 1,
size(mg%lvls(lvl)%ids)
1279 id = mg%lvls(lvl)%ids(i)
1280 call add_single_child(mg, id,
size(mg%lvls(lvl)%ids))
1291 do lvl = mg%lowest_lvl, 1
1292 if (
allocated(mg%lvls(lvl)%ref_bnds)) &
1293 deallocate(mg%lvls(lvl)%ref_bnds)
1294 allocate(mg%lvls(lvl)%ref_bnds(0))
1297 mg%tree_created = .true.
1301 type(
mg_t),
intent(inout) :: mg
1302 integer,
intent(in) :: lvl
1305 do i = 1,
size(mg%lvls(lvl)%ids)
1306 id = mg%lvls(lvl)%ids(i)
1307 call set_neighbs(mg%boxes, id)
1312 type(
mg_t),
intent(inout) :: mg
1313 integer,
intent(in) :: lvl
1316 if (
allocated(mg%lvls(lvl+1)%ids)) &
1317 deallocate(mg%lvls(lvl+1)%ids)
1320 if (mg%box_size_lvl(lvl+1) == mg%box_size_lvl(lvl))
then
1322 allocate(mg%lvls(lvl+1)%ids(n))
1325 do i = 1,
size(mg%lvls(lvl)%parents)
1326 id = mg%lvls(lvl)%parents(i)
1327 mg%lvls(lvl+1)%ids(n*(i-1)+1:n*i) = mg%boxes(id)%children
1330 n =
size(mg%lvls(lvl)%parents)
1331 allocate(mg%lvls(lvl+1)%ids(n))
1334 do i = 1,
size(mg%lvls(lvl)%parents)
1335 id = mg%lvls(lvl)%parents(i)
1336 mg%lvls(lvl+1)%ids(i) = mg%boxes(id)%children(1)
1343 subroutine set_neighbs(boxes, id)
1344 type(
mg_box_t),
intent(inout) :: boxes(:)
1345 integer,
intent(in) :: id
1346 integer :: nb, nb_id
1349 if (boxes(id)%neighbors(nb) ==
mg_no_box)
then
1350 nb_id = find_neighb(boxes, id, nb)
1352 boxes(id)%neighbors(nb) = nb_id
1357 end subroutine set_neighbs
1360 function find_neighb(boxes, id, nb)
result(nb_id)
1361 type(
mg_box_t),
intent(in) :: boxes(:)
1362 integer,
intent(in) :: id
1363 integer,
intent(in) :: nb
1364 integer :: nb_id, p_id, c_ix, d, old_pid
1366 p_id = boxes(id)%parent
1374 p_id = boxes(p_id)%neighbors(nb)
1379 end function find_neighb
1383 type(
mg_box_t),
intent(in) :: boxes(:)
1384 type(
mg_lvl_t),
intent(inout) :: level
1385 integer :: i, id, i_leaf, i_parent
1386 integer :: n_parents, n_leaves
1389 n_leaves =
size(level%ids) - n_parents
1391 if (.not.
allocated(level%parents))
then
1392 allocate(level%parents(n_parents))
1393 else if (n_parents /=
size(level%parents))
then
1394 deallocate(level%parents)
1395 allocate(level%parents(n_parents))
1398 if (.not.
allocated(level%leaves))
then
1399 allocate(level%leaves(n_leaves))
1400 else if (n_leaves /=
size(level%leaves))
then
1401 deallocate(level%leaves)
1402 allocate(level%leaves(n_leaves))
1407 do i = 1,
size(level%ids)
1410 i_parent = i_parent + 1
1411 level%parents(i_parent) = id
1414 level%leaves(i_leaf) = id
1421 type(
mg_box_t),
intent(in) :: boxes(:)
1422 type(
mg_lvl_t),
intent(inout) :: level
1423 integer,
allocatable :: tmp(:)
1424 integer :: i, id, nb, nb_id, ix
1426 if (
allocated(level%ref_bnds))
deallocate(level%ref_bnds)
1428 if (
size(level%parents) == 0)
then
1430 allocate(level%ref_bnds(0))
1432 allocate(tmp(
size(level%leaves)))
1434 do i = 1,
size(level%leaves)
1435 id = level%leaves(i)
1438 nb_id = boxes(id)%neighbors(nb)
1449 allocate(level%ref_bnds(ix))
1450 level%ref_bnds(:) = tmp(1:ix)
1455 type(
mg_t),
intent(inout) :: mg
1456 integer,
intent(in) :: id
1457 integer :: lvl, i, nb, child_nb(2**(3-1))
1459 integer :: c_id, c_ix_base(3)
1462 error stop
"mg_add_children: not enough space"
1467 mg%boxes(id)%children = c_ids
1468 c_ix_base = 2 * mg%boxes(id)%ix - 1
1469 lvl = mg%boxes(id)%lvl+1
1473 mg%boxes(c_id)%rank = mg%boxes(id)%rank
1475 mg%boxes(c_id)%lvl = lvl
1476 mg%boxes(c_id)%parent = id
1479 mg%boxes(c_id)%r_min = mg%boxes(id)%r_min + &
1481 mg%boxes(c_id)%dr(:) = mg%dr(:, lvl)
1486 if (mg%boxes(id)%neighbors(nb) <
mg_no_box)
then
1488 mg%boxes(child_nb)%neighbors(nb) = mg%boxes(id)%neighbors(nb)
1493 subroutine add_single_child(mg, id, n_boxes_lvl)
1494 type(
mg_t),
intent(inout) :: mg
1495 integer,
intent(in) :: id
1496 integer,
intent(in) :: n_boxes_lvl
1497 integer :: lvl, c_id
1499 c_id = mg%n_boxes + 1
1500 mg%n_boxes = mg%n_boxes + 1
1501 mg%boxes(id)%children(1) = c_id
1502 lvl = mg%boxes(id)%lvl+1
1504 mg%boxes(c_id)%rank = mg%boxes(id)%rank
1505 mg%boxes(c_id)%ix = mg%boxes(id)%ix
1506 mg%boxes(c_id)%lvl = lvl
1507 mg%boxes(c_id)%parent = id
1510 mg%boxes(c_id)%neighbors = mg%boxes(id)%neighbors
1512 mg%boxes(c_id)%neighbors = mg%boxes(id)%neighbors + n_boxes_lvl
1514 mg%boxes(c_id)%r_min = mg%boxes(id)%r_min
1515 mg%boxes(c_id)%dr(:) = mg%dr(:, lvl)
1517 end subroutine add_single_child
1527 type(
mg_t),
intent(inout) :: mg
1528 integer :: i, id, lvl, single_cpu_lvl
1529 integer :: work_left, my_work, i_cpu
1533 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1535 do lvl = mg%lowest_lvl, single_cpu_lvl
1536 do i = 1,
size(mg%lvls(lvl)%ids)
1537 id = mg%lvls(lvl)%ids(i)
1538 mg%boxes(id)%rank = 0
1544 do lvl = single_cpu_lvl+1, mg%highest_lvl
1545 work_left =
size(mg%lvls(lvl)%ids)
1549 do i = 1,
size(mg%lvls(lvl)%ids)
1550 if ((mg%n_cpu - i_cpu - 1) * my_work >= work_left)
then
1555 my_work = my_work + 1
1556 work_left = work_left - 1
1558 id = mg%lvls(lvl)%ids(i)
1559 mg%boxes(id)%rank = i_cpu
1563 do lvl = mg%lowest_lvl, mg%highest_lvl
1564 call update_lvl_info(mg, mg%lvls(lvl))
1576 type(
mg_t),
intent(inout) :: mg
1577 integer :: i, id, lvl, single_cpu_lvl
1578 integer :: work_left, my_work(0:mg%n_cpu), i_cpu
1581 integer :: coarse_rank
1585 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1589 do lvl = mg%highest_lvl, single_cpu_lvl+1, -1
1593 do i = 1,
size(mg%lvls(lvl)%parents)
1594 id = mg%lvls(lvl)%parents(i)
1596 c_ids = mg%boxes(id)%children
1597 c_ranks = mg%boxes(c_ids)%rank
1598 i_cpu = most_popular(c_ranks, my_work, mg%n_cpu)
1599 mg%boxes(id)%rank = i_cpu
1600 my_work(i_cpu) = my_work(i_cpu) + 1
1603 work_left =
size(mg%lvls(lvl)%leaves)
1606 do i = 1,
size(mg%lvls(lvl)%leaves)
1608 if ((mg%n_cpu - i_cpu - 1) * my_work(i_cpu) >= &
1609 work_left + sum(my_work(i_cpu+1:)))
then
1613 my_work(i_cpu) = my_work(i_cpu) + 1
1614 work_left = work_left - 1
1616 id = mg%lvls(lvl)%leaves(i)
1617 mg%boxes(id)%rank = i_cpu
1622 if (single_cpu_lvl < mg%highest_lvl)
then
1623 coarse_rank = most_popular(mg%boxes(&
1624 mg%lvls(single_cpu_lvl+1)%ids)%rank, my_work, mg%n_cpu)
1629 do lvl = mg%lowest_lvl, single_cpu_lvl
1630 do i = 1,
size(mg%lvls(lvl)%ids)
1631 id = mg%lvls(lvl)%ids(i)
1632 mg%boxes(id)%rank = coarse_rank
1636 do lvl = mg%lowest_lvl, mg%highest_lvl
1637 call update_lvl_info(mg, mg%lvls(lvl))
1645 type(
mg_t),
intent(inout) :: mg
1646 integer :: i, id, lvl
1649 integer :: single_cpu_lvl, coarse_rank
1650 integer :: my_work(0:mg%n_cpu), i_cpu
1654 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1656 do lvl = mg%highest_lvl-1, single_cpu_lvl+1, -1
1660 do i = 1,
size(mg%lvls(lvl)%leaves)
1661 id = mg%lvls(lvl)%leaves(i)
1662 i_cpu = mg%boxes(id)%rank
1663 my_work(i_cpu) = my_work(i_cpu) + 1
1666 do i = 1,
size(mg%lvls(lvl)%parents)
1667 id = mg%lvls(lvl)%parents(i)
1669 c_ids = mg%boxes(id)%children
1670 c_ranks = mg%boxes(c_ids)%rank
1671 i_cpu = most_popular(c_ranks, my_work, mg%n_cpu)
1672 mg%boxes(id)%rank = i_cpu
1673 my_work(i_cpu) = my_work(i_cpu) + 1
1679 if (single_cpu_lvl < mg%highest_lvl)
then
1680 coarse_rank = most_popular(mg%boxes(&
1681 mg%lvls(single_cpu_lvl+1)%ids)%rank, my_work, mg%n_cpu)
1686 do lvl = mg%lowest_lvl, single_cpu_lvl
1687 do i = 1,
size(mg%lvls(lvl)%ids)
1688 id = mg%lvls(lvl)%ids(i)
1689 mg%boxes(id)%rank = coarse_rank
1693 do lvl = mg%lowest_lvl, mg%highest_lvl
1694 call update_lvl_info(mg, mg%lvls(lvl))
1701 pure integer function most_popular(list, work, n_cpu)
1702 integer,
intent(in) :: list(:)
1703 integer,
intent(in) :: n_cpu
1704 integer,
intent(in) :: work(0:n_cpu-1)
1705 integer :: i, best_count, current_count
1706 integer :: my_work, best_work
1712 do i = 1,
size(list)
1713 current_count = count(list == list(i))
1714 my_work = work(list(i))
1717 if (current_count > best_count .or. &
1718 current_count == best_count .and. my_work < best_work)
then
1719 best_count = current_count
1721 most_popular = list(i)
1725 end function most_popular
1727 subroutine update_lvl_info(mg, lvl)
1728 type(
mg_t),
intent(inout) :: mg
1729 type(
mg_lvl_t),
intent(inout) :: lvl
1731 lvl%my_ids = pack(lvl%ids, &
1732 mg%boxes(lvl%ids)%rank == mg%my_rank)
1733 lvl%my_leaves = pack(lvl%leaves, &
1734 mg%boxes(lvl%leaves)%rank == mg%my_rank)
1735 lvl%my_parents = pack(lvl%parents, &
1736 mg%boxes(lvl%parents)%rank == mg%my_rank)
1737 lvl%my_ref_bnds = pack(lvl%ref_bnds, &
1738 mg%boxes(lvl%ref_bnds)%rank == mg%my_rank)
1739 end subroutine update_lvl_info
1744 type(
mg_t),
intent(inout) :: mg
1746 if (mg%n_extra_vars == 0 .and. mg%is_allocated)
then
1747 error stop
"vlaplacian_set_methods: mg%n_extra_vars == 0"
1749 mg%n_extra_vars = max(1, mg%n_extra_vars)
1752 mg%subtract_mean = .false.
1757 mg%bc(:,
mg_iveps)%bc_value = 0.0_dp
1759 select case (mg%geometry_type)
1761 mg%box_op => box_vlpl
1766 select case (mg%smoother_type)
1768 mg%box_smoother => box_gs_vlpl
1770 error stop
"vlaplacian_set_methods: unsupported smoother type"
1774 error stop
"vlaplacian_set_methods: unsupported geometry"
1780 subroutine box_gs_vlpl(mg, id, nc, redblack_cntr)
1781 type(
mg_t),
intent(inout) :: mg
1782 integer,
intent(in) :: id
1783 integer,
intent(in) :: nc
1784 integer,
intent(in) :: redblack_cntr
1785 integer :: i, j, k, i0, di
1787 real(
dp) :: idr2(2*3), u(2*3)
1788 real(
dp) :: a0, a(2*3), c(2*3)
1791 idr2(1:2*3:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1792 idr2(2:2*3:2) = idr2(1:2*3:2)
1804 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1809 i0 = 2 - iand(ieor(redblack_cntr, k+j), 1)
1811 a0 = cc(i, j, k, i_eps)
1812 u(1:2) = cc(i-1:i+1:2, j, k, n)
1813 a(1:2) = cc(i-1:i+1:2, j, k, i_eps)
1814 u(3:4) = cc(i, j-1:j+1:2, k, n)
1815 a(3:4) = cc(i, j-1:j+1:2, k, i_eps)
1816 u(5:6) = cc(i, j, k-1:k+1:2, n)
1817 a(5:6) = cc(i, j, k-1:k+1:2, i_eps)
1818 c(:) = 2 * a0 * a(:) / (a0 + a(:)) * idr2
1820 cc(i, j, k, n) = (sum(c(:) * u(:)) - &
1821 cc(i, j, k,
mg_irhs)) / sum(c(:))
1826 end subroutine box_gs_vlpl
1829 subroutine box_vlpl(mg, id, nc, i_out)
1830 type(
mg_t),
intent(inout) :: mg
1831 integer,
intent(in) :: id
1832 integer,
intent(in) :: nc
1833 integer,
intent(in) :: i_out
1835 real(
dp) :: idr2(2*3), a0, u0, u(2*3), a(2*3)
1838 idr2(1:2*3:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1839 idr2(2:2*3:2) = idr2(1:2*3:2)
1841 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1847 a0 = cc(i, j, k, i_eps)
1848 u(1:2) = cc(i-1:i+1:2, j, k, n)
1849 u(3:4) = cc(i, j-1:j+1:2, k, n)
1850 u(5:6) = cc(i, j, k-1:k+1:2, n)
1851 a(1:2) = cc(i-1:i+1:2, j, k, i_eps)
1852 a(3:4) = cc(i, j-1:j+1:2, k, i_eps)
1853 a(5:6) = cc(i, j, k-1:k+1:2, i_eps)
1855 cc(i, j, k, i_out) = sum(2 * idr2 * &
1856 a0*a(:)/(a0 + a(:)) * (u(:) - u0))
1861 end subroutine box_vlpl
1969 type(
mg_t),
intent(inout) :: mg
1971 integer,
intent(in),
optional :: comm
1973 logical :: initialized
1975 call mpi_initialized(initialized, ierr)
1976 if (.not. initialized)
then
1980 if (
present(comm))
then
1983 mg%comm = mpi_comm_world
1986 call mpi_comm_rank(mg%comm, mg%my_rank, ierr)
1987 call mpi_comm_size(mg%comm, mg%n_cpu, ierr)
1992 type(
mg_t),
intent(inout) :: mg
1993 integer,
intent(in) :: dsize
1994 integer :: i, n_send, n_recv
1995 integer :: send_req(mg%n_cpu)
1996 integer :: recv_req(mg%n_cpu)
2002 do i = 0, mg%n_cpu - 1
2003 if (mg%buf(i)%i_send > 0)
then
2006 call mpi_isend(mg%buf(i)%send, mg%buf(i)%i_send, mpi_double, &
2007 i, 0, mg%comm, send_req(n_send), ierr)
2009 if (mg%buf(i)%i_recv > 0)
then
2011 call mpi_irecv(mg%buf(i)%recv, mg%buf(i)%i_recv, mpi_double, &
2012 i, 0, mg%comm, recv_req(n_recv), ierr)
2016 call mpi_waitall(n_recv, recv_req(1:n_recv), mpi_statuses_ignore, ierr)
2017 call mpi_waitall(n_send, send_req(1:n_send), mpi_statuses_ignore, ierr)
2024 type(
mg_buf_t),
intent(inout) :: gc
2025 integer,
intent(in) :: dsize
2026 integer :: ix_sort(gc%i_ix)
2027 real(dp) :: buf_cpy(gc%i_send)
2030 call mrgrnk(gc%ix(1:gc%i_ix), ix_sort)
2032 buf_cpy = gc%send(1:gc%i_send)
2036 j = (ix_sort(n)-1) * dsize
2037 gc%send(i+1:i+dsize) = buf_cpy(j+1:j+dsize)
2039 gc%ix(1:gc%i_ix) = gc%ix(ix_sort)
2047 type(
mg_t),
intent(inout) :: mg
2048 integer,
intent(out) :: n_send(0:mg%n_cpu-1)
2049 integer,
intent(out) :: n_recv(0:mg%n_cpu-1)
2050 integer,
intent(out) :: dsize
2051 integer :: i, id, lvl, nc
2053 allocate(mg%comm_ghostcell%n_send(0:mg%n_cpu-1, &
2054 mg%first_normal_lvl:mg%highest_lvl))
2055 allocate(mg%comm_ghostcell%n_recv(0:mg%n_cpu-1, &
2056 mg%first_normal_lvl:mg%highest_lvl))
2058 dsize = mg%box_size**(3-1)
2060 do lvl = mg%first_normal_lvl, mg%highest_lvl
2061 nc = mg%box_size_lvl(lvl)
2062 mg%buf(:)%i_send = 0
2063 mg%buf(:)%i_recv = 0
2066 do i = 1,
size(mg%lvls(lvl)%my_ids)
2067 id = mg%lvls(lvl)%my_ids(i)
2068 call buffer_ghost_cells(mg, id, nc, 1, dry_run=.true.)
2072 do i = 1,
size(mg%lvls(lvl-1)%my_ref_bnds)
2073 id = mg%lvls(lvl-1)%my_ref_bnds(i)
2074 call buffer_refinement_boundaries(mg, id, nc, 1, dry_run=.true.)
2079 mg%buf(:)%i_recv = 0
2080 do i = 1,
size(mg%lvls(lvl)%my_ids)
2081 id = mg%lvls(lvl)%my_ids(i)
2082 call set_ghost_cells(mg, id, nc, 1, dry_run=.true.)
2085 mg%comm_ghostcell%n_send(:, lvl) = mg%buf(:)%i_send/dsize
2086 mg%comm_ghostcell%n_recv(:, lvl) = mg%buf(:)%i_recv/dsize
2089 n_send = maxval(mg%comm_ghostcell%n_send, dim=2)
2090 n_recv = maxval(mg%comm_ghostcell%n_recv, dim=2)
2096 type(
mg_t),
intent(inout) :: mg
2101 do lvl = mg%lowest_lvl, mg%highest_lvl
2102 nc = mg%box_size_lvl(lvl)
2103 call mg_phi_bc_store_lvl(mg, lvl, nc)
2106 mg%phi_bc_data_stored = .true.
2109 subroutine mg_phi_bc_store_lvl(mg, lvl, nc)
2110 type(
mg_t),
intent(inout) :: mg
2111 integer,
intent(in) :: lvl
2112 integer,
intent(in) :: nc
2113 real(
dp) :: bc(nc, nc)
2114 integer :: i, id, nb, nb_id, bc_type
2116 do i = 1,
size(mg%lvls(lvl)%my_ids)
2117 id = mg%lvls(lvl)%my_ids(i)
2119 nb_id = mg%boxes(id)%neighbors(nb)
2122 if (
associated(mg%bc(nb,
mg_iphi)%boundary_cond))
then
2123 call mg%bc(nb,
mg_iphi)%boundary_cond(mg%boxes(id), nc, &
2126 bc_type = mg%bc(nb,
mg_iphi)%bc_type
2127 bc = mg%bc(nb,
mg_iphi)%bc_value
2133 mg%boxes(id)%neighbors(nb) = bc_type
2136 call box_set_gc(mg%boxes(id), nb, nc,
mg_irhs, bc)
2140 end subroutine mg_phi_bc_store_lvl
2145 integer,
intent(in) :: iv
2148 do lvl = mg%lowest_lvl, mg%highest_lvl
2157 integer,
intent(in) :: lvl
2158 integer,
intent(in) :: iv
2159 integer :: i, id, dsize, nc
2161 if (lvl < mg%lowest_lvl) &
2162 error stop
"fill_ghost_cells_lvl: lvl < lowest_lvl"
2163 if (lvl > mg%highest_lvl) &
2164 error stop
"fill_ghost_cells_lvl: lvl > highest_lvl"
2166 nc = mg%box_size_lvl(lvl)
2168 if (lvl >= mg%first_normal_lvl)
then
2170 mg%buf(:)%i_send = 0
2171 mg%buf(:)%i_recv = 0
2174 do i = 1,
size(mg%lvls(lvl)%my_ids)
2175 id = mg%lvls(lvl)%my_ids(i)
2176 call buffer_ghost_cells(mg, id, nc, iv, .false.)
2180 do i = 1,
size(mg%lvls(lvl-1)%my_ref_bnds)
2181 id = mg%lvls(lvl-1)%my_ref_bnds(i)
2182 call buffer_refinement_boundaries(mg, id, nc, iv, .false.)
2187 mg%buf(:)%i_recv = mg%comm_ghostcell%n_recv(:, lvl) * dsize
2191 mg%buf(:)%i_recv = 0
2194 do i = 1,
size(mg%lvls(lvl)%my_ids)
2195 id = mg%lvls(lvl)%my_ids(i)
2196 call set_ghost_cells(mg, id, nc, iv, .false.)
2200 subroutine buffer_ghost_cells(mg, id, nc, iv, dry_run)
2201 type(
mg_t),
intent(inout) :: mg
2202 integer,
intent(in) :: id
2203 integer,
intent(in) :: nc
2204 integer,
intent(in) :: iv
2205 logical,
intent(in) :: dry_run
2206 integer :: nb, nb_id, nb_rank
2209 nb_id = mg%boxes(id)%neighbors(nb)
2213 nb_rank = mg%boxes(nb_id)%rank
2215 if (nb_rank /= mg%my_rank)
then
2216 call buffer_for_nb(mg, mg%boxes(id), nc, iv, nb_id, nb_rank, &
2221 end subroutine buffer_ghost_cells
2223 subroutine buffer_refinement_boundaries(mg, id, nc, iv, dry_run)
2224 type(
mg_t),
intent(inout) :: mg
2225 integer,
intent(in) :: id
2226 integer,
intent(in) :: nc
2227 integer,
intent(in) :: iv
2228 logical,
intent(in) :: dry_run
2229 integer :: nb, nb_id, c_ids(2**(3-1))
2230 integer :: n, c_id, c_rank
2233 nb_id = mg%boxes(id)%neighbors(nb)
2236 c_ids = mg%boxes(nb_id)%children(&
2241 c_rank = mg%boxes(c_id)%rank
2243 if (c_rank /= mg%my_rank)
then
2245 call buffer_for_fine_nb(mg, mg%boxes(id), nc, iv, c_id, &
2246 c_rank, nb, dry_run)
2252 end subroutine buffer_refinement_boundaries
2255 subroutine set_ghost_cells(mg, id, nc, iv, dry_run)
2256 type(
mg_t),
intent(inout) :: mg
2257 integer,
intent(in) :: id
2258 integer,
intent(in) :: nc
2259 integer,
intent(in) :: iv
2260 logical,
intent(in) :: dry_run
2261 real(
dp) :: bc(nc, nc)
2262 integer :: nb, nb_id, nb_rank, bc_type
2265 nb_id = mg%boxes(id)%neighbors(nb)
2269 nb_rank = mg%boxes(nb_id)%rank
2271 if (nb_rank /= mg%my_rank)
then
2272 call fill_buffered_nb(mg, mg%boxes(id), nb_rank, &
2273 nb, nc, iv, dry_run)
2274 else if (.not. dry_run)
then
2275 call copy_from_nb(mg%boxes(id), mg%boxes(nb_id), &
2280 call fill_refinement_bnd(mg, id, nb, nc, iv, dry_run)
2281 else if (.not. dry_run)
then
2283 if (mg%phi_bc_data_stored .and. iv ==
mg_iphi)
then
2286 call box_get_gc(mg%boxes(id), nb, nc,
mg_irhs, bc)
2289 if (
associated(mg%bc(nb, iv)%boundary_cond))
then
2290 call mg%bc(nb, iv)%boundary_cond(mg%boxes(id), nc, iv, &
2293 bc_type = mg%bc(nb, iv)%bc_type
2294 bc = mg%bc(nb, iv)%bc_value
2298 call box_set_gc(mg%boxes(id), nb, nc, iv, bc)
2299 call bc_to_gc(mg, id, nc, iv, nb, bc_type)
2302 end subroutine set_ghost_cells
2304 subroutine fill_refinement_bnd(mg, id, nb, nc, iv, dry_run)
2305 type(
mg_t),
intent(inout) :: mg
2306 integer,
intent(in) :: id
2307 integer,
intent(in) :: nc
2308 integer,
intent(in) :: iv
2309 integer,
intent(in) :: nb
2310 logical,
intent(in) :: dry_run
2311 real(
dp) :: gc(nc, nc)
2312 integer :: p_id, p_nb_id, ix_offset(3)
2313 integer :: i, dsize, p_nb_rank
2316 p_id = mg%boxes(id)%parent
2317 p_nb_id = mg%boxes(p_id)%neighbors(nb)
2318 p_nb_rank = mg%boxes(p_nb_id)%rank
2320 if (p_nb_rank /= mg%my_rank)
then
2321 i = mg%buf(p_nb_rank)%i_recv
2322 if (.not. dry_run)
then
2323 gc = reshape(mg%buf(p_nb_rank)%recv(i+1:i+dsize), shape(gc))
2325 mg%buf(p_nb_rank)%i_recv = mg%buf(p_nb_rank)%i_recv + dsize
2326 else if (.not. dry_run)
then
2328 call box_gc_for_fine_neighbor(mg%boxes(p_nb_id),
mg_neighb_rev(nb), &
2329 ix_offset, nc, iv, gc)
2332 if (.not. dry_run)
then
2333 if (
associated(mg%bc(nb, iv)%refinement_bnd))
then
2334 call mg%bc(nb, iv)%refinement_bnd(mg%boxes(id), nc, iv, nb, gc)
2336 call sides_rb(mg%boxes(id), nc, iv, nb, gc)
2339 end subroutine fill_refinement_bnd
2341 subroutine copy_from_nb(box, box_nb, nb, nc, iv)
2342 type(
mg_box_t),
intent(inout) :: box
2343 type(
mg_box_t),
intent(in) :: box_nb
2344 integer,
intent(in) :: nb
2345 integer,
intent(in) :: nc
2346 integer,
intent(in) :: iv
2347 real(
dp) :: gc(nc, nc)
2349 call box_gc_for_neighbor(box_nb,
mg_neighb_rev(nb), nc, iv, gc)
2350 call box_set_gc(box, nb, nc, iv, gc)
2351 end subroutine copy_from_nb
2353 subroutine buffer_for_nb(mg, box, nc, iv, nb_id, nb_rank, nb, dry_run)
2354 type(
mg_t),
intent(inout) :: mg
2355 type(
mg_box_t),
intent(inout) :: box
2356 integer,
intent(in) :: nc
2357 integer,
intent(in) :: iv
2358 integer,
intent(in) :: nb_id
2359 integer,
intent(in) :: nb_rank
2360 integer,
intent(in) :: nb
2361 logical,
intent(in) :: dry_run
2363 real(
dp) :: gc(nc, nc)
2365 i = mg%buf(nb_rank)%i_send
2368 if (.not. dry_run)
then
2369 call box_gc_for_neighbor(box, nb, nc, iv, gc)
2370 mg%buf(nb_rank)%send(i+1:i+dsize) = pack(gc, .true.)
2375 i = mg%buf(nb_rank)%i_ix
2376 if (.not. dry_run)
then
2380 mg%buf(nb_rank)%i_send = mg%buf(nb_rank)%i_send + dsize
2381 mg%buf(nb_rank)%i_ix = mg%buf(nb_rank)%i_ix + 1
2382 end subroutine buffer_for_nb
2384 subroutine buffer_for_fine_nb(mg, box, nc, iv, fine_id, fine_rank, nb, dry_run)
2385 type(
mg_t),
intent(inout) :: mg
2386 type(
mg_box_t),
intent(inout) :: box
2387 integer,
intent(in) :: nc
2388 integer,
intent(in) :: iv
2389 integer,
intent(in) :: fine_id
2390 integer,
intent(in) :: fine_rank
2391 integer,
intent(in) :: nb
2392 logical,
intent(in) :: dry_run
2393 integer :: i, dsize, ix_offset(3)
2394 real(
dp) :: gc(nc, nc)
2396 i = mg%buf(fine_rank)%i_send
2399 if (.not. dry_run)
then
2401 call box_gc_for_fine_neighbor(box, nb, ix_offset, nc, iv, gc)
2402 mg%buf(fine_rank)%send(i+1:i+dsize) = pack(gc, .true.)
2407 i = mg%buf(fine_rank)%i_ix
2408 if (.not. dry_run)
then
2413 mg%buf(fine_rank)%i_send = mg%buf(fine_rank)%i_send + dsize
2414 mg%buf(fine_rank)%i_ix = mg%buf(fine_rank)%i_ix + 1
2415 end subroutine buffer_for_fine_nb
2417 subroutine fill_buffered_nb(mg, box, nb_rank, nb, nc, iv, dry_run)
2418 type(
mg_t),
intent(inout) :: mg
2419 type(
mg_box_t),
intent(inout) :: box
2420 integer,
intent(in) :: nb_rank
2421 integer,
intent(in) :: nb
2422 integer,
intent(in) :: nc
2423 integer,
intent(in) :: iv
2424 logical,
intent(in) :: dry_run
2426 real(
dp) :: gc(nc, nc)
2428 i = mg%buf(nb_rank)%i_recv
2431 if (.not. dry_run)
then
2432 gc = reshape(mg%buf(nb_rank)%recv(i+1:i+dsize), shape(gc))
2433 call box_set_gc(box, nb, nc, iv, gc)
2435 mg%buf(nb_rank)%i_recv = mg%buf(nb_rank)%i_recv + dsize
2437 end subroutine fill_buffered_nb
2439 subroutine box_gc_for_neighbor(box, nb, nc, iv, gc)
2441 integer,
intent(in) :: nb, nc, iv
2442 real(
dp),
intent(out) :: gc(nc, nc)
2446 gc = box%cc(1, 1:nc, 1:nc, iv)
2448 gc = box%cc(nc, 1:nc, 1:nc, iv)
2450 gc = box%cc(1:nc, 1, 1:nc, iv)
2452 gc = box%cc(1:nc, nc, 1:nc, iv)
2454 gc = box%cc(1:nc, 1:nc, 1, iv)
2456 gc = box%cc(1:nc, 1:nc, nc, iv)
2458 end subroutine box_gc_for_neighbor
2461 subroutine box_gc_for_fine_neighbor(box, nb, di, nc, iv, gc)
2463 integer,
intent(in) :: nb
2464 integer,
intent(in) :: di(3)
2465 integer,
intent(in) :: nc, iv
2466 real(
dp),
intent(out) :: gc(nc, nc)
2467 real(
dp) :: tmp(0:nc/2+1, 0:nc/2+1), grad(3-1)
2468 integer :: i, j, hnc
2475 tmp = box%cc(1, di(2):di(2)+hnc+1, di(3):di(3)+hnc+1, iv)
2477 tmp = box%cc(nc, di(2):di(2)+hnc+1, di(3):di(3)+hnc+1, iv)
2479 tmp = box%cc(di(1):di(1)+hnc+1, 1, di(3):di(3)+hnc+1, iv)
2481 tmp = box%cc(di(1):di(1)+hnc+1, nc, di(3):di(3)+hnc+1, iv)
2483 tmp = box%cc(di(1):di(1)+hnc+1, di(2):di(2)+hnc+1, 1, iv)
2485 tmp = box%cc(di(1):di(1)+hnc+1, di(2):di(2)+hnc+1, nc, iv)
2494 grad(1) = 0.125_dp * (tmp(i+1, j) - tmp(i-1, j))
2495 grad(2) = 0.125_dp * (tmp(i, j+1) - tmp(i, j-1))
2496 gc(2*i-1, 2*j-1) = tmp(i, j) - grad(1) - grad(2)
2497 gc(2*i, 2*j-1) = tmp(i, j) + grad(1) - grad(2)
2498 gc(2*i-1, 2*j) = tmp(i, j) - grad(1) + grad(2)
2499 gc(2*i, 2*j) = tmp(i, j) + grad(1) + grad(2)
2502 end subroutine box_gc_for_fine_neighbor
2504 subroutine box_get_gc(box, nb, nc, iv, gc)
2506 integer,
intent(in) :: nb, nc, iv
2507 real(
dp),
intent(out) :: gc(nc, nc)
2511 gc = box%cc(0, 1:nc, 1:nc, iv)
2513 gc = box%cc(nc+1, 1:nc, 1:nc, iv)
2515 gc = box%cc(1:nc, 0, 1:nc, iv)
2517 gc = box%cc(1:nc, nc+1, 1:nc, iv)
2519 gc = box%cc(1:nc, 1:nc, 0, iv)
2521 gc = box%cc(1:nc, 1:nc, nc+1, iv)
2523 end subroutine box_get_gc
2525 subroutine box_set_gc(box, nb, nc, iv, gc)
2526 type(
mg_box_t),
intent(inout) :: box
2527 integer,
intent(in) :: nb, nc, iv
2528 real(
dp),
intent(in) :: gc(nc, nc)
2532 box%cc(0, 1:nc, 1:nc, iv) = gc
2534 box%cc(nc+1, 1:nc, 1:nc, iv) = gc
2536 box%cc(1:nc, 0, 1:nc, iv) = gc
2538 box%cc(1:nc, nc+1, 1:nc, iv) = gc
2540 box%cc(1:nc, 1:nc, 0, iv) = gc
2542 box%cc(1:nc, 1:nc, nc+1, iv) = gc
2544 end subroutine box_set_gc
2546 subroutine bc_to_gc(mg, id, nc, iv, nb, bc_type)
2547 type(
mg_t),
intent(inout) :: mg
2548 integer,
intent(in) :: id
2549 integer,
intent(in) :: nc
2550 integer,
intent(in) :: iv
2551 integer,
intent(in) :: nb
2552 integer,
intent(in) :: bc_type
2553 real(
dp) :: c0, c1, c2, dr
2563 select case (bc_type)
2578 error stop
"bc_to_gc: unknown boundary condition"
2583 mg%boxes(id)%cc(0, 1:nc, 1:nc, iv) = &
2584 c0 * mg%boxes(id)%cc(0, 1:nc, 1:nc, iv) + &
2585 c1 * mg%boxes(id)%cc(1, 1:nc, 1:nc, iv) + &
2586 c2 * mg%boxes(id)%cc(2, 1:nc, 1:nc, iv)
2588 mg%boxes(id)%cc(nc+1, 1:nc, 1:nc, iv) = &
2589 c0 * mg%boxes(id)%cc(nc+1, 1:nc, 1:nc, iv) + &
2590 c1 * mg%boxes(id)%cc(nc, 1:nc, 1:nc, iv) + &
2591 c2 * mg%boxes(id)%cc(nc-1, 1:nc, 1:nc, iv)
2593 mg%boxes(id)%cc(1:nc, 0, 1:nc, iv) = &
2594 c0 * mg%boxes(id)%cc(1:nc, 0, 1:nc, iv) + &
2595 c1 * mg%boxes(id)%cc(1:nc, 1, 1:nc, iv) + &
2596 c2 * mg%boxes(id)%cc(1:nc, 2, 1:nc, iv)
2598 mg%boxes(id)%cc(1:nc, nc+1, 1:nc, iv) = &
2599 c0 * mg%boxes(id)%cc(1:nc, nc+1, 1:nc, iv) + &
2600 c1 * mg%boxes(id)%cc(1:nc, nc, 1:nc, iv) + &
2601 c2 * mg%boxes(id)%cc(1:nc, nc-1, 1:nc, iv)
2603 mg%boxes(id)%cc(1:nc, 1:nc, 0, iv) = &
2604 c0 * mg%boxes(id)%cc(1:nc, 1:nc, 0, iv) + &
2605 c1 * mg%boxes(id)%cc(1:nc, 1:nc, 1, iv) + &
2606 c2 * mg%boxes(id)%cc(1:nc, 1:nc, 2, iv)
2608 mg%boxes(id)%cc(1:nc, 1:nc, nc+1, iv) = &
2609 c0 * mg%boxes(id)%cc(1:nc, 1:nc, nc+1, iv) + &
2610 c1 * mg%boxes(id)%cc(1:nc, 1:nc, nc, iv) + &
2611 c2 * mg%boxes(id)%cc(1:nc, 1:nc, nc-1, iv)
2613 end subroutine bc_to_gc
2616 subroutine sides_rb(box, nc, iv, nb, gc)
2617 type(
mg_box_t),
intent(inout) :: box
2618 integer,
intent(in) :: nc
2619 integer,
intent(in) :: iv
2620 integer,
intent(in) :: nb
2622 real(
dp),
intent(in) :: gc(nc, nc)
2623 integer :: di, dj, dk
2624 integer :: i, j, k, ix, dix
2639 dk = -1 + 2 * iand(k, 1)
2641 dj = -1 + 2 * iand(j, 1)
2642 box%cc(i-di, j, k, iv) = 0.5_dp * gc(j, k) &
2643 + 0.75_dp * box%cc(i, j, k, iv) &
2644 - 0.25_dp * box%cc(i+di, j, k, iv)
2651 dk = -1 + 2 * iand(k, 1)
2653 di = -1 + 2 * iand(i, 1)
2654 box%cc(i, j-dj, k, iv) = 0.5_dp * gc(i, k) &
2655 + 0.75_dp * box%cc(i, j, k, iv) &
2656 - 0.25_dp * box%cc(i, j+dj, k, iv)
2663 dj = -1 + 2 * iand(j, 1)
2665 di = -1 + 2 * iand(i, 1)
2666 box%cc(i, j, k-dk, iv) = 0.5_dp * gc(i, j) &
2667 + 0.75_dp * box%cc(i, j, k, iv) &
2668 - 0.25_dp * box%cc(i, j, k+dk, iv)
2673 end subroutine sides_rb
2679 type(
mg_t),
intent(inout) :: mg
2680 integer,
intent(out) :: n_send(0:mg%n_cpu-1)
2681 integer,
intent(out) :: n_recv(0:mg%n_cpu-1)
2682 integer,
intent(out) :: dsize
2683 integer :: lvl, min_lvl
2685 if (.not.
allocated(mg%comm_restrict%n_send))
then
2686 error stop
"Call restrict_buffer_size before prolong_buffer_size"
2689 min_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
2690 allocate(mg%comm_prolong%n_send(0:mg%n_cpu-1, &
2691 min_lvl:mg%highest_lvl))
2692 allocate(mg%comm_prolong%n_recv(0:mg%n_cpu-1, &
2693 min_lvl:mg%highest_lvl))
2695 mg%comm_prolong%n_recv(:, mg%highest_lvl) = 0
2696 mg%comm_prolong%n_send(:, mg%highest_lvl) = 0
2698 do lvl = min_lvl, mg%highest_lvl-1
2699 mg%comm_prolong%n_recv(:, lvl) = &
2700 mg%comm_restrict%n_send(:, lvl+1)
2701 mg%comm_prolong%n_send(:, lvl) = &
2702 mg%comm_restrict%n_recv(:, lvl+1)
2707 dsize = (mg%box_size)**3
2708 n_send = maxval(mg%comm_prolong%n_send, dim=2)
2709 n_recv = maxval(mg%comm_prolong%n_recv, dim=2)
2715 type(
mg_t),
intent(inout) :: mg
2716 integer,
intent(in) :: lvl
2717 integer,
intent(in) :: iv
2718 integer,
intent(in) :: iv_to
2719 procedure(mg_box_prolong) :: method
2720 logical,
intent(in) :: add
2721 integer :: i, id, dsize, nc
2723 if (lvl == mg%highest_lvl) error stop
"cannot prolong highest level"
2724 if (lvl < mg%lowest_lvl) error stop
"cannot prolong below lowest level"
2727 if (lvl >= mg%first_normal_lvl-1)
then
2728 dsize = mg%box_size**3
2729 mg%buf(:)%i_send = 0
2732 do i = 1,
size(mg%lvls(lvl)%my_ids)
2733 id = mg%lvls(lvl)%my_ids(i)
2734 call prolong_set_buffer(mg, id, mg%box_size, iv, method)
2737 mg%buf(:)%i_recv = mg%comm_prolong%n_recv(:, lvl) * dsize
2739 mg%buf(:)%i_recv = 0
2742 nc = mg%box_size_lvl(lvl+1)
2743 do i = 1,
size(mg%lvls(lvl+1)%my_ids)
2744 id = mg%lvls(lvl+1)%my_ids(i)
2745 call prolong_onto(mg, id, nc, iv, iv_to, add, method)
2752 subroutine prolong_set_buffer(mg, id, nc, iv, method)
2753 type(
mg_t),
intent(inout) :: mg
2754 integer,
intent(in) :: id
2755 integer,
intent(in) :: nc
2756 integer,
intent(in) :: iv
2757 procedure(mg_box_prolong) :: method
2758 integer :: i, dix(3)
2759 integer :: i_c, c_id, c_rank, dsize
2760 real(
dp) :: tmp(nc, nc, nc)
2765 c_id = mg%boxes(id)%children(i_c)
2767 c_rank = mg%boxes(c_id)%rank
2768 if (c_rank /= mg%my_rank)
then
2770 call method(mg, id, dix, nc, iv, tmp)
2772 i = mg%buf(c_rank)%i_send
2773 mg%buf(c_rank)%send(i+1:i+dsize) = pack(tmp, .true.)
2774 mg%buf(c_rank)%i_send = mg%buf(c_rank)%i_send + dsize
2776 i = mg%buf(c_rank)%i_ix
2777 mg%buf(c_rank)%ix(i+1) = c_id
2778 mg%buf(c_rank)%i_ix = mg%buf(c_rank)%i_ix + 1
2782 end subroutine prolong_set_buffer
2785 subroutine prolong_onto(mg, id, nc, iv, iv_to, add, method)
2786 type(
mg_t),
intent(inout) :: mg
2787 integer,
intent(in) :: id
2788 integer,
intent(in) :: nc
2789 integer,
intent(in) :: iv
2790 integer,
intent(in) :: iv_to
2791 logical,
intent(in) :: add
2792 procedure(mg_box_prolong) :: method
2793 integer :: hnc, p_id, p_rank, i, dix(3), dsize
2794 real(
dp) :: tmp(nc, nc, nc)
2797 p_id = mg%boxes(id)%parent
2798 p_rank = mg%boxes(p_id)%rank
2800 if (p_rank == mg%my_rank)
then
2802 call method(mg, p_id, dix, nc, iv, tmp)
2805 i = mg%buf(p_rank)%i_recv
2806 tmp = reshape(mg%buf(p_rank)%recv(i+1:i+dsize), [nc, nc, nc])
2807 mg%buf(p_rank)%i_recv = mg%buf(p_rank)%i_recv + dsize
2811 mg%boxes(id)%cc(1:nc, 1:nc, 1:nc, iv_to) = &
2812 mg%boxes(id)%cc(1:nc, 1:nc, 1:nc, iv_to) + tmp
2814 mg%boxes(id)%cc(1:nc, 1:nc, 1:nc, iv_to) = tmp
2817 end subroutine prolong_onto
2821 type(
mg_t),
intent(inout) :: mg
2822 integer,
intent(in) :: p_id
2823 integer,
intent(in) :: dix(3)
2824 integer,
intent(in) :: nc
2825 integer,
intent(in) :: iv
2826 real(
dp),
intent(out) :: fine(nc, nc, nc)
2828 integer :: i, j, k, hnc
2829 integer :: ic, jc, kc
2830 real(
dp) :: f0, flx, fhx, fly, fhy, flz, fhz
2834 associate(crs => mg%boxes(p_id)%cc)
2842 f0 = 0.25_dp * crs(ic, jc, kc, iv)
2843 flx = 0.25_dp * crs(ic-1, jc, kc, iv)
2844 fhx = 0.25_dp * crs(ic+1, jc, kc, iv)
2845 fly = 0.25_dp * crs(ic, jc-1, kc, iv)
2846 fhy = 0.25_dp * crs(ic, jc+1, kc, iv)
2847 flz = 0.25_dp * crs(ic, jc, kc-1, iv)
2848 fhz = 0.25_dp * crs(ic, jc, kc+1, iv)
2850 fine(2*i-1, 2*j-1, 2*k-1) = f0 + flx + fly + flz
2851 fine(2*i, 2*j-1, 2*k-1) = f0 + fhx + fly + flz
2852 fine(2*i-1, 2*j, 2*k-1) = f0 + flx + fhy + flz
2853 fine(2*i, 2*j, 2*k-1) = f0 + fhx + fhy + flz
2854 fine(2*i-1, 2*j-1, 2*k) = f0 + flx + fly + fhz
2855 fine(2*i, 2*j-1, 2*k) = f0 + fhx + fly + fhz
2856 fine(2*i-1, 2*j, 2*k) = f0 + flx + fhy + fhz
2857 fine(2*i, 2*j, 2*k) = f0 + fhx + fhy + fhz
2867 type(
mg_t),
intent(inout) :: mg
2869 mg%subtract_mean = .false.
2871 select case (mg%geometry_type)
2873 mg%box_op => box_helmh
2875 select case (mg%smoother_type)
2877 mg%box_smoother => box_gs_helmh
2879 error stop
"helmholtz_set_methods: unsupported smoother type"
2882 error stop
"helmholtz_set_methods: unsupported geometry"
2888 real(
dp),
intent(in) :: lambda
2891 error stop
"helmholtz_set_lambda: lambda < 0 not allowed"
2897 subroutine box_gs_helmh(mg, id, nc, redblack_cntr)
2898 type(
mg_t),
intent(inout) :: mg
2899 integer,
intent(in) :: id
2900 integer,
intent(in) :: nc
2901 integer,
intent(in) :: redblack_cntr
2902 integer :: i, j, k, i0, di
2903 real(
dp) :: idr2(3), fac
2905 real(
dp),
parameter :: sixth = 1/6.0_dp
2907 idr2 = 1/mg%dr(:, mg%boxes(id)%lvl)**2
2920 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
2924 i0 = 2 - iand(ieor(redblack_cntr, k+j), 1)
2926 cc(i, j, k, n) = fac * ( &
2927 idr2(1) * (cc(i+1, j, k, n) + cc(i-1, j, k, n)) + &
2928 idr2(2) * (cc(i, j+1, k, n) + cc(i, j-1, k, n)) + &
2929 idr2(3) * (cc(i, j, k+1, n) + cc(i, j, k-1, n)) - &
2935 end subroutine box_gs_helmh
2938 subroutine box_helmh(mg, id, nc, i_out)
2939 type(
mg_t),
intent(inout) :: mg
2940 integer,
intent(in) :: id
2941 integer,
intent(in) :: nc
2942 integer,
intent(in) :: i_out
2946 idr2 = 1 / mg%dr(:, mg%boxes(id)%lvl)**2
2948 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
2952 cc(i, j, k, i_out) = &
2953 idr2(1) * (cc(i-1, j, k, n) + cc(i+1, j, k, n) &
2954 - 2 * cc(i, j, k, n)) &
2955 + idr2(2) * (cc(i, j-1, k, n) + cc(i, j+1, k, n) &
2956 - 2 * cc(i, j, k, n)) &
2957 + idr2(3) * (cc(i, j, k-1, n) + cc(i, j, k+1, n) &
2958 - 2 * cc(i, j, k, n)) - &
2964 end subroutine box_helmh
2970 type(
mg_t),
intent(inout) :: mg
2975 select case (mg%operator_type)
2987 error stop
"mg_set_methods: unknown operator"
2993 mg%n_smoother_substeps = 2
2995 mg%n_smoother_substeps = 1
2999 subroutine check_methods(mg)
3000 type(
mg_t),
intent(inout) :: mg
3002 if (.not.
associated(mg%box_op) .or. &
3003 .not.
associated(mg%box_smoother))
then
3007 end subroutine check_methods
3009 subroutine mg_add_timers(mg)
3010 type(
mg_t),
intent(inout) :: mg
3011 timer_total_vcycle =
mg_add_timer(mg,
"mg total V-cycle")
3012 timer_total_fmg =
mg_add_timer(mg,
"mg total FMG cycle")
3014 timer_smoother_gc =
mg_add_timer(mg,
"mg smoother g.c.")
3017 timer_update_coarse =
mg_add_timer(mg,
"mg update coarse")
3018 end subroutine mg_add_timers
3022 type(
mg_t),
intent(inout) :: mg
3023 logical,
intent(in) :: have_guess
3024 real(
dp),
intent(out),
optional :: max_res
3025 integer :: lvl, i, id
3027 call check_methods(mg)
3028 if (timer_smoother == -1)
call mg_add_timers(mg)
3032 if (.not. have_guess)
then
3033 do lvl = mg%highest_lvl, mg%lowest_lvl, -1
3034 do i = 1,
size(mg%lvls(lvl)%my_ids)
3035 id = mg%lvls(lvl)%my_ids(i)
3036 mg%boxes(id)%cc(:, :, :,
mg_iphi) = 0.0_dp
3044 do lvl = mg%highest_lvl, mg%lowest_lvl+1, -1
3047 call update_coarse(mg, lvl)
3051 if (mg%subtract_mean)
then
3056 do lvl = mg%lowest_lvl, mg%highest_lvl
3058 do i = 1,
size(mg%lvls(lvl)%my_ids)
3059 id = mg%lvls(lvl)%my_ids(i)
3060 mg%boxes(id)%cc(:, :, :,
mg_iold) = &
3061 mg%boxes(id)%cc(:, :, :,
mg_iphi)
3064 if (lvl > mg%lowest_lvl)
then
3068 call correct_children(mg, lvl-1)
3076 if (lvl == mg%highest_lvl)
then
3089 type(
mg_t),
intent(inout) :: mg
3090 integer,
intent(in),
optional :: highest_lvl
3091 real(
dp),
intent(out),
optional :: max_res
3093 logical,
intent(in),
optional :: standalone
3094 integer :: lvl, min_lvl, i, max_lvl, ierr
3095 real(
dp) :: init_res, res
3096 logical :: is_standalone
3098 is_standalone = .true.
3099 if (
present(standalone)) is_standalone = standalone
3101 call check_methods(mg)
3102 if (timer_smoother == -1)
call mg_add_timers(mg)
3104 if (is_standalone) &
3107 if (mg%subtract_mean .and. .not.
present(highest_lvl))
then
3113 min_lvl = mg%lowest_lvl
3114 max_lvl = mg%highest_lvl
3115 if (
present(highest_lvl)) max_lvl = highest_lvl
3118 if (is_standalone)
then
3122 do lvl = max_lvl, min_lvl+1, -1
3124 call smooth_boxes(mg, lvl, mg%n_cycle_down)
3129 call update_coarse(mg, lvl)
3134 if (.not. all(mg%boxes(mg%lvls(min_lvl)%ids)%rank == &
3135 mg%boxes(mg%lvls(min_lvl)%ids(1))%rank))
then
3136 error stop
"Multiple CPUs for coarse grid (not implemented yet)"
3139 init_res = max_residual_lvl(mg, min_lvl)
3140 do i = 1, mg%max_coarse_cycles
3141 call smooth_boxes(mg, min_lvl, mg%n_cycle_up+mg%n_cycle_down)
3142 res = max_residual_lvl(mg, min_lvl)
3143 if (res < mg%residual_coarse_rel * init_res .or. &
3144 res < mg%residual_coarse_abs)
exit
3149 do lvl = min_lvl+1, max_lvl
3153 call correct_children(mg, lvl-1)
3160 call smooth_boxes(mg, lvl, mg%n_cycle_up)
3163 if (
present(max_res))
then
3165 do lvl = min_lvl, max_lvl
3166 res = max_residual_lvl(mg, lvl)
3167 init_res = max(res, init_res)
3169 call mpi_allreduce(init_res, max_res, 1, &
3170 mpi_double, mpi_max, mg%comm, ierr)
3174 if (mg%subtract_mean)
then
3178 if (is_standalone) &
3184 type(
mg_t),
intent(inout) :: mg
3185 integer,
intent(in) :: iv
3186 logical,
intent(in) :: include_ghostcells
3187 integer :: i, id, lvl, nc, ierr
3188 real(dp) :: sum_iv, mean_iv, volume
3192 call mpi_allreduce(sum_iv, mean_iv, 1, &
3193 mpi_double, mpi_sum, mg%comm, ierr)
3196 volume = nc**3 * product(mg%dr(:, 1)) *
size(mg%lvls(1)%ids)
3197 mean_iv = mean_iv / volume
3199 do lvl = mg%lowest_lvl, mg%highest_lvl
3200 nc = mg%box_size_lvl(lvl)
3202 do i = 1,
size(mg%lvls(lvl)%my_ids)
3203 id = mg%lvls(lvl)%my_ids(i)
3204 if (include_ghostcells)
then
3205 mg%boxes(id)%cc(:, :, :, iv) = &
3206 mg%boxes(id)%cc(:, :, :, iv) - mean_iv
3208 mg%boxes(id)%cc(1:nc, 1:nc, 1:nc, iv) = &
3209 mg%boxes(id)%cc(1:nc, 1:nc, 1:nc, iv) - mean_iv
3216 type(
mg_t),
intent(in) :: mg
3217 integer,
intent(in) :: iv
3218 integer :: lvl, i, id, nc
3222 do lvl = 1, mg%highest_lvl
3223 nc = mg%box_size_lvl(lvl)
3224 w = product(mg%dr(:, lvl))
3225 do i = 1,
size(mg%lvls(lvl)%my_leaves)
3226 id = mg%lvls(lvl)%my_leaves(i)
3228 sum(mg%boxes(id)%cc(1:nc, 1:nc, 1:nc, iv))
3233 real(
dp) function max_residual_lvl(mg, lvl)
3234 type(
mg_t),
intent(inout) :: mg
3235 integer,
intent(in) :: lvl
3236 integer :: i, id, nc
3239 nc = mg%box_size_lvl(lvl)
3240 max_residual_lvl = 0.0_dp
3242 do i = 1,
size(mg%lvls(lvl)%my_ids)
3243 id = mg%lvls(lvl)%my_ids(i)
3244 call residual_box(mg, id, nc)
3245 res = maxval(abs(mg%boxes(id)%cc(1:nc, 1:nc, 1:nc,
mg_ires)))
3246 max_residual_lvl = max(max_residual_lvl, res)
3248 end function max_residual_lvl
3284 subroutine update_coarse(mg, lvl)
3285 type(
mg_t),
intent(inout) :: mg
3286 integer,
intent(in) :: lvl
3287 integer :: i, id, nc, nc_c
3289 nc = mg%box_size_lvl(lvl)
3290 nc_c = mg%box_size_lvl(lvl-1)
3293 do i = 1,
size(mg%lvls(lvl)%my_ids)
3294 id = mg%lvls(lvl)%my_ids(i)
3295 call residual_box(mg, id, nc)
3306 do i = 1,
size(mg%lvls(lvl-1)%my_parents)
3307 id = mg%lvls(lvl-1)%my_parents(i)
3310 call mg%box_op(mg, id, nc_c,
mg_irhs)
3313 mg%boxes(id)%cc(1:nc_c, 1:nc_c, 1:nc_c,
mg_irhs) = &
3314 mg%boxes(id)%cc(1:nc_c, 1:nc_c, 1:nc_c,
mg_irhs) + &
3315 mg%boxes(id)%cc(1:nc_c, 1:nc_c, 1:nc_c,
mg_ires)
3318 mg%boxes(id)%cc(:, :, :,
mg_iold) = &
3319 mg%boxes(id)%cc(:, :, :,
mg_iphi)
3321 end subroutine update_coarse
3324 subroutine correct_children(mg, lvl)
3325 type(
mg_t),
intent(inout) :: mg
3326 integer,
intent(in) :: lvl
3329 do i = 1,
size(mg%lvls(lvl)%my_parents)
3330 id = mg%lvls(lvl)%my_parents(i)
3333 mg%boxes(id)%cc(:, :, :,
mg_ires) = &
3334 mg%boxes(id)%cc(:, :, :,
mg_iphi) - &
3335 mg%boxes(id)%cc(:, :, :,
mg_iold)
3339 end subroutine correct_children
3341 subroutine smooth_boxes(mg, lvl, n_cycle)
3342 type(
mg_t),
intent(inout) :: mg
3343 integer,
intent(in) :: lvl
3344 integer,
intent(in) :: n_cycle
3345 integer :: n, i, id, nc
3347 nc = mg%box_size_lvl(lvl)
3349 do n = 1, n_cycle * mg%n_smoother_substeps
3351 do i = 1,
size(mg%lvls(lvl)%my_ids)
3352 id = mg%lvls(lvl)%my_ids(i)
3353 call mg%box_smoother(mg, id, nc, n)
3361 end subroutine smooth_boxes
3363 subroutine residual_box(mg, id, nc)
3364 type(
mg_t),
intent(inout) :: mg
3365 integer,
intent(in) :: id
3366 integer,
intent(in) :: nc
3368 call mg%box_op(mg, id, nc,
mg_ires)
3370 mg%boxes(id)%cc(1:nc, 1:nc, 1:nc,
mg_ires) = &
3371 mg%boxes(id)%cc(1:nc, 1:nc, 1:nc,
mg_irhs) &
3372 - mg%boxes(id)%cc(1:nc, 1:nc, 1:nc,
mg_ires)
3373 end subroutine residual_box
3377 type(
mg_t),
intent(inout) :: mg
3378 integer,
intent(in) :: i_out
3379 procedure(mg_box_op),
optional :: op
3380 integer :: lvl, i, id, nc
3382 do lvl = mg%lowest_lvl, mg%highest_lvl
3383 nc = mg%box_size_lvl(lvl)
3384 do i = 1,
size(mg%lvls(lvl)%my_ids)
3385 id = mg%lvls(lvl)%my_ids(i)
3386 if (
present(op))
then
3387 call op(mg, id, nc, i_out)
3389 call mg%box_op(mg, id, nc, i_out)
3399 type(
mg_t),
intent(inout) :: mg
3400 integer,
intent(out) :: n_send(0:mg%n_cpu-1)
3401 integer,
intent(out) :: n_recv(0:mg%n_cpu-1)
3402 integer,
intent(out) :: dsize
3403 integer :: n_out(0:mg%n_cpu-1, mg%first_normal_lvl:mg%highest_lvl)
3404 integer :: n_in(0:mg%n_cpu-1, mg%first_normal_lvl:mg%highest_lvl)
3405 integer :: lvl, i, id, p_id, p_rank
3406 integer :: i_c, c_id, c_rank, min_lvl
3410 min_lvl = max(mg%lowest_lvl+1, mg%first_normal_lvl)
3412 do lvl = min_lvl, mg%highest_lvl
3414 do i = 1,
size(mg%lvls(lvl-1)%my_parents)
3415 id = mg%lvls(lvl-1)%my_parents(i)
3417 c_id = mg%boxes(id)%children(i_c)
3420 c_rank = mg%boxes(c_id)%rank
3421 if (c_rank /= mg%my_rank)
then
3422 n_in(c_rank, lvl) = n_in(c_rank, lvl) + 1
3429 do i = 1,
size(mg%lvls(lvl)%my_ids)
3430 id = mg%lvls(lvl)%my_ids(i)
3432 p_id = mg%boxes(id)%parent
3433 p_rank = mg%boxes(p_id)%rank
3434 if (p_rank /= mg%my_rank)
then
3435 n_out(p_rank, lvl) = n_out(p_rank, lvl) + 1
3441 allocate(mg%comm_restrict%n_send(0:mg%n_cpu-1, &
3442 mg%first_normal_lvl:mg%highest_lvl))
3443 allocate(mg%comm_restrict%n_recv(0:mg%n_cpu-1, &
3444 mg%first_normal_lvl:mg%highest_lvl))
3445 mg%comm_restrict%n_send = n_out
3446 mg%comm_restrict%n_recv = n_in
3448 dsize = (mg%box_size/2)**3
3449 n_send = maxval(n_out, dim=2)
3450 n_recv = maxval(n_in, dim=2)
3455 type(
mg_t),
intent(inout) :: mg
3456 integer,
intent(in) :: iv
3459 do lvl = mg%highest_lvl, mg%lowest_lvl+1, -1
3467 type(
mg_t),
intent(inout) :: mg
3468 integer,
intent(in) :: iv
3469 integer,
intent(in) :: lvl
3470 integer :: i, id, dsize, nc
3472 if (lvl <= mg%lowest_lvl) error stop
"cannot restrict lvl <= lowest_lvl"
3474 nc = mg%box_size_lvl(lvl)
3476 if (lvl >= mg%first_normal_lvl)
then
3479 mg%buf(:)%i_send = 0
3482 do i = 1,
size(mg%lvls(lvl)%my_ids)
3483 id = mg%lvls(lvl)%my_ids(i)
3484 call restrict_set_buffer(mg, id, iv)
3487 mg%buf(:)%i_recv = mg%comm_restrict%n_recv(:, lvl) * dsize
3489 mg%buf(:)%i_recv = 0
3492 do i = 1,
size(mg%lvls(lvl-1)%my_parents)
3493 id = mg%lvls(lvl-1)%my_parents(i)
3494 call restrict_onto(mg, id, nc, iv)
3498 subroutine restrict_set_buffer(mg, id, iv)
3499 type(
mg_t),
intent(inout) :: mg
3500 integer,
intent(in) :: id
3501 integer,
intent(in) :: iv
3502 integer :: i, j, k, n, hnc, p_id, p_rank
3503 real(
dp) :: tmp(mg%box_size/2, mg%box_size/2, mg%box_size/2)
3506 p_id = mg%boxes(id)%parent
3507 p_rank = mg%boxes(p_id)%rank
3509 if (p_rank /= mg%my_rank)
then
3513 tmp(i, j, k) = 0.125_dp * sum(mg%boxes(id)%cc(2*i-1:2*i, &
3514 2*j-1:2*j, 2*k-1:2*k, iv))
3521 i = mg%buf(p_rank)%i_send
3522 mg%buf(p_rank)%send(i+1:i+n) = pack(tmp, .true.)
3523 mg%buf(p_rank)%i_send = mg%buf(p_rank)%i_send + n
3526 i = mg%buf(p_rank)%i_ix
3529 mg%buf(p_rank)%i_ix = mg%buf(p_rank)%i_ix + 1
3531 end subroutine restrict_set_buffer
3533 subroutine restrict_onto(mg, id, nc, iv)
3534 type(
mg_t),
intent(inout) :: mg
3535 integer,
intent(in) :: id
3536 integer,
intent(in) :: nc
3537 integer,
intent(in) :: iv
3538 integer :: i, j, k, hnc, dsize, i_c, c_id
3539 integer :: c_rank, dix(3)
3545 c_id = mg%boxes(id)%children(i_c)
3547 c_rank = mg%boxes(c_id)%rank
3550 if (c_rank == mg%my_rank)
then
3551 do j=1, hnc;
do i=1, hnc;
do k=1, hnc
3552 mg%boxes(id)%cc(dix(1)+i, dix(2)+j, dix(3)+k, iv) = &
3553 0.125_dp * sum(mg%boxes(c_id)%cc(2*i-1:2*i, &
3554 2*j-1:2*j, 2*k-1:2*k, iv))
3555 end do;
end do;
end do
3557 i = mg%buf(c_rank)%i_recv
3558 mg%boxes(id)%cc(dix(1)+1:dix(1)+hnc, &
3559 dix(2)+1:dix(2)+hnc, dix(3)+1:dix(3)+hnc, iv) = &
3560 reshape(mg%buf(c_rank)%recv(i+1:i+dsize), [hnc, hnc, hnc])
3561 mg%buf(c_rank)%i_recv = mg%buf(c_rank)%i_recv + dsize
3565 end subroutine restrict_onto
3569 Subroutine i_mrgrnk (XDONT, IRNGT)
3576 Integer,
Dimension (:),
Intent (In) :: xdont
3577 Integer,
Dimension (:),
Intent (Out) :: irngt
3579 Integer :: xvala, xvalb
3581 Integer,
Dimension (SIZE(IRNGT)) :: jwrkt
3582 Integer :: lmtna, lmtnc, irng1, irng2
3583 Integer :: nval, iind, iwrkd, iwrk, iwrkf, jinda, iinda, iindb
3585 nval = min(
SIZE(xdont),
SIZE(irngt))
3598 Do iind = 2, nval, 2
3599 If (xdont(iind-1) <= xdont(iind))
Then
3600 irngt(iind-1) = iind - 1
3603 irngt(iind-1) = iind
3604 irngt(iind) = iind - 1
3607 If (modulo(nval, 2) /= 0)
Then
3624 Do iwrkd = 0, nval - 1, 4
3625 If ((iwrkd+4) > nval)
Then
3626 If ((iwrkd+2) >= nval)
Exit
3630 If (xdont(irngt(iwrkd+2)) <= xdont(irngt(iwrkd+3)))
Exit
3634 If (xdont(irngt(iwrkd+1)) <= xdont(irngt(iwrkd+3)))
Then
3635 irng2 = irngt(iwrkd+2)
3636 irngt(iwrkd+2) = irngt(iwrkd+3)
3637 irngt(iwrkd+3) = irng2
3642 irng1 = irngt(iwrkd+1)
3643 irngt(iwrkd+1) = irngt(iwrkd+3)
3644 irngt(iwrkd+3) = irngt(iwrkd+2)
3645 irngt(iwrkd+2) = irng1
3652 If (xdont(irngt(iwrkd+2)) <= xdont(irngt(iwrkd+3))) cycle
3656 If (xdont(irngt(iwrkd+1)) <= xdont(irngt(iwrkd+3)))
Then
3657 irng2 = irngt(iwrkd+2)
3658 irngt(iwrkd+2) = irngt(iwrkd+3)
3659 If (xdont(irng2) <= xdont(irngt(iwrkd+4)))
Then
3661 irngt(iwrkd+3) = irng2
3664 irngt(iwrkd+3) = irngt(iwrkd+4)
3665 irngt(iwrkd+4) = irng2
3671 irng1 = irngt(iwrkd+1)
3672 irng2 = irngt(iwrkd+2)
3673 irngt(iwrkd+1) = irngt(iwrkd+3)
3674 If (xdont(irng1) <= xdont(irngt(iwrkd+4)))
Then
3675 irngt(iwrkd+2) = irng1
3676 If (xdont(irng2) <= xdont(irngt(iwrkd+4)))
Then
3678 irngt(iwrkd+3) = irng2
3681 irngt(iwrkd+3) = irngt(iwrkd+4)
3682 irngt(iwrkd+4) = irng2
3686 irngt(iwrkd+2) = irngt(iwrkd+4)
3687 irngt(iwrkd+3) = irng1
3688 irngt(iwrkd+4) = irng2
3703 If (lmtna >= nval)
Exit
3712 jinda = iwrkf + lmtna
3713 iwrkf = iwrkf + lmtnc
3714 If (iwrkf >= nval)
Then
3715 If (jinda >= nval)
Exit
3731 jwrkt(1:lmtna) = irngt(iwrkd:jinda)
3733 xvala = xdont(jwrkt(iinda))
3734 xvalb = xdont(irngt(iindb))
3741 If (xvala > xvalb)
Then
3742 irngt(iwrk) = irngt(iindb)
3744 If (iindb > iwrkf)
Then
3746 irngt(iwrk+1:iwrkf) = jwrkt(iinda:lmtna)
3749 xvalb = xdont(irngt(iindb))
3751 irngt(iwrk) = jwrkt(iinda)
3753 If (iinda > lmtna) exit
3754 xvala = xdont(jwrkt(iinda))
3767 End Subroutine i_mrgrnk
3772 type(
mg_t),
intent(inout) :: mg
3774 if (mg%n_extra_vars == 0 .and. mg%is_allocated)
then
3775 error stop
"ahelmholtz_set_methods: mg%n_extra_vars == 0"
3777 mg%n_extra_vars = max(3, mg%n_extra_vars)
3791 select case (mg%geometry_type)
3793 mg%box_op => box_ahelmh
3795 select case (mg%smoother_type)
3797 mg%box_smoother => box_gs_ahelmh
3799 error stop
"ahelmholtz_set_methods: unsupported smoother type"
3802 error stop
"ahelmholtz_set_methods: unsupported geometry"
3808 real(
dp),
intent(in) :: lambda
3811 error stop
"ahelmholtz_set_lambda: lambda < 0 not allowed"
3817 subroutine box_gs_ahelmh(mg, id, nc, redblack_cntr)
3818 type(
mg_t),
intent(inout) :: mg
3819 integer,
intent(in) :: id
3820 integer,
intent(in) :: nc
3821 integer,
intent(in) :: redblack_cntr
3822 integer :: i, j, k, i0, di
3824 real(
dp) :: idr2(2*3), u(2*3)
3825 real(
dp) :: a0(2*3), a(2*3), c(2*3)
3828 idr2(1:2*3:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
3829 idr2(2:2*3:2) = idr2(1:2*3:2)
3841 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
3849 i0 = 2 - iand(ieor(redblack_cntr, k+j), 1)
3851 a0(1:2) = cc(i, j, k, i_eps1)
3852 a0(3:4) = cc(i, j, k, i_eps2)
3853 a0(4:5) = cc(i, j, k, i_eps3)
3854 u(1:2) = cc(i-1:i+1:2, j, k, n)
3855 a(1:2) = cc(i-1:i+1:2, j, k, i_eps1)
3856 u(3:4) = cc(i, j-1:j+1:2, k, n)
3857 a(3:4) = cc(i, j-1:j+1:2, k, i_eps2)
3858 u(5:6) = cc(i, j, k-1:k+1:2, n)
3859 a(5:6) = cc(i, j, k-1:k+1:2, i_eps3)
3860 c(:) = 2 * a0(:) * a(:) / (a0(:) + a(:)) * idr2
3862 cc(i, j, k, n) = (sum(c(:) * u(:)) - &
3869 end subroutine box_gs_ahelmh
3872 subroutine box_ahelmh(mg, id, nc, i_out)
3873 type(
mg_t),
intent(inout) :: mg
3874 integer,
intent(in) :: id
3875 integer,
intent(in) :: nc
3876 integer,
intent(in) :: i_out
3878 real(
dp) :: idr2(2*3), a0(2*3), u0, u(2*3), a(2*3)
3881 idr2(1:2*3:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
3882 idr2(2:2*3:2) = idr2(1:2*3:2)
3884 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
3892 a0(1:2) = cc(i, j, k, i_eps1)
3893 a0(3:4) = cc(i, j, k, i_eps2)
3894 a0(5:6) = cc(i, j, k, i_eps3)
3895 u(1:2) = cc(i-1:i+1:2, j, k, n)
3896 u(3:4) = cc(i, j-1:j+1:2, k, n)
3897 u(5:6) = cc(i, j, k-1:k+1:2, n)
3898 a(1:2) = cc(i-1:i+1:2, j, k, i_eps1)
3899 a(3:4) = cc(i, j-1:j+1:2, k, i_eps2)
3900 a(5:6) = cc(i, j, k-1:k+1:2, i_eps3)
3902 cc(i, j, k, i_out) = sum(2 * idr2 * &
3903 a0(:)*a(:)/(a0(:) + a(:)) * (u(:) - u0)) - &
3909 end subroutine box_ahelmh
To fill ghost cells near physical boundaries.
subroutine, public helmholtz_set_lambda(lambda)
subroutine, public mg_set_methods(mg)
subroutine, public mg_restrict_buffer_size(mg, n_send, n_recv, dsize)
Specify minimum buffer size (per process) for communication.
integer, parameter, public mg_irhs
Index of right-hand side.
integer, parameter, public mg_vhelmholtz
Indicates a variable-coefficient Helmholtz equation.
integer, dimension(4, 6), parameter, public mg_child_adj_nb
integer, parameter, public mg_ahelmholtz
Indicates a anisotropic-coefficient Helmholtz equation.
integer, dimension(3, 6), parameter, public mg_neighb_dix
integer function, public mg_ix_to_ichild(ix)
Compute the child index for a box with spatial index ix. With child index we mean the index in the ch...
subroutine, public mg_fas_fmg(mg, have_guess, max_res)
Perform FAS-FMG cycle (full approximation scheme, full multigrid).
integer, parameter, public mg_smoother_gsrb
subroutine subtract_mean(mg, iv, include_ghostcells)
subroutine, public mg_load_balance(mg)
Load balance all boxes in the multigrid tree. Compared to mg_load_balance_simple, this method does a ...
integer, parameter, public mg_num_children
subroutine, public mg_timers_show(mg)
integer, parameter, public mg_max_timers
Maximum number of timers to use.
subroutine, public mg_fas_vcycle(mg, highest_lvl, max_res, standalone)
Perform FAS V-cycle (full approximation scheme).
subroutine, public vhelmholtz_set_methods(mg)
integer, parameter, public mg_bc_dirichlet
Value to indicate a Dirichlet boundary condition.
integer, parameter, public mg_iveps
Index of the variable coefficient (at cell centers)
subroutine, public mg_load_balance_parents(mg)
Load balance the parents (non-leafs). Assign them to the rank that has most children.
integer, dimension(3, 8), parameter, public mg_child_dix
subroutine, public mg_phi_bc_store(mg)
Store boundary conditions for the solution variable, this can speed up calculations if the same bound...
integer(i8) function, public mg_number_of_unknowns(mg)
Determine total number of unknowns (on leaves)
integer, parameter, public mg_vlaplacian
Indicates a variable-coefficient Laplacian.
integer, parameter, public mg_cylindrical
Cylindrical coordinate system.
subroutine, public mg_prolong_sparse(mg, p_id, dix, nc, iv, fine)
Prolong from a parent to a child with index offset dix.
subroutine, public mg_build_rectangle(mg, domain_size, box_size, dx, r_min, periodic, n_finer)
subroutine, public vhelmholtz_set_lambda(lambda)
integer, parameter, public mg_ires
Index of residual.
integer, parameter, public mg_smoother_gs
subroutine, public laplacian_set_methods(mg)
subroutine, public mg_load_balance_simple(mg)
Load balance all boxes in the multigrid tree, by simply distributing the load per grid level....
subroutine, public mg_ghost_cell_buffer_size(mg, n_send, n_recv, dsize)
Specify minimum buffer size (per process) for communication.
subroutine, public mg_set_neighbors_lvl(mg, lvl)
integer, parameter, public mg_smoother_jacobi
integer, parameter, public mg_neighb_lowy
integer, parameter, public mg_bc_continuous
Value to indicate a continuous boundary condition.
subroutine, public mg_set_leaves_parents(boxes, level)
Create a list of leaves and a list of parents for a level.
subroutine, public helmholtz_set_methods(mg)
subroutine, public mg_add_children(mg, id)
integer, parameter, public mg_lvl_lo
Minimum allowed grid level.
integer, parameter, public mg_num_neighbors
integer, parameter, public mg_neighb_highy
real(dp), public, protected ahelmholtz_lambda
Module which contains multigrid procedures for a Helmholtz operator of the form: div(D grad(phi)) - l...
integer, parameter, public mg_iold
Index of previous solution (used for correction)
integer, parameter, public mg_bc_neumann
Value to indicate a Neumann boundary condition.
integer, dimension(6), parameter, public mg_neighb_high_pm
integer, parameter, public mg_ndim
Problem dimension.
integer, parameter, public mg_iphi
Index of solution.
integer, parameter, public mg_helmholtz
Indicates a constant-coefficient Helmholtz equation.
real(dp) function get_sum(mg, iv)
subroutine, public mg_allocate_storage(mg)
Allocate communication buffers and local boxes for a tree that has already been created.
subroutine, public mg_timer_end(timer)
integer, parameter, public mg_num_vars
Number of predefined multigrid variables.
subroutine, public ahelmholtz_set_methods(mg)
real(dp), public, protected vhelmholtz_lambda
Module for implicitly solving diffusion equations.
subroutine, public mg_restrict(mg, iv)
Restrict all levels.
integer, parameter, public mg_neighb_lowx
subroutine, public mg_set_next_level_ids(mg, lvl)
integer, parameter, public mg_physical_boundary
Special value that indicates there is a physical boundary.
integer, dimension(6), parameter, public mg_neighb_rev
integer, parameter, public mg_spherical
Spherical coordinate system.
integer, parameter, public mg_laplacian
Indicates a standard Laplacian.
subroutine, public mg_get_face_coords(box, nb, nc, x)
Get coordinates at the face of a box.
subroutine, public mg_timer_start(timer)
subroutine, public mg_prolong_buffer_size(mg, n_send, n_recv, dsize)
Specify minimum buffer size (per process) for communication.
subroutine, public diffusion_solve(mg, dt, diffusion_coeff, order, max_res)
Solve a diffusion equation implicitly, assuming a constant diffusion coefficient. The solution at tim...
integer, parameter, public mg_neighb_highx
integer, parameter, public mg_cartesian
Cartesian coordinate system.
integer, parameter, public mg_iveps2
integer, parameter, public i8
Type for 64-bit integers.
integer, parameter, public mg_iveps1
Indexes of anisotropic variable coefficients.
subroutine, public mg_fill_ghost_cells_lvl(mg, lvl, iv)
Fill ghost cells at a grid level.
integer, parameter, public mg_neighb_lowz
subroutine, public diffusion_solve_vcoeff(mg, dt, order, max_res)
Solve a diffusion equation implicitly, assuming a variable diffusion coefficient which has been store...
subroutine, public mg_comm_init(mg, comm)
Prolong from a parent to a child with index offset dix. This method could sometimes work better than ...
integer, parameter, public mg_lvl_hi
Maximum allowed grid level.
subroutine, public vlaplacian_set_methods(mg)
logical, dimension(6), parameter, public mg_neighb_low
integer, parameter, public mg_iveps3
elemental logical function, public mg_has_children(box)
Return .true. if a box has children.
subroutine, public mg_deallocate_storage(mg)
Deallocate all allocatable arrays.
real(dp), public, protected helmholtz_lambda
Module for load balancing a tree (that already has been constructed). The load balancing determines w...
subroutine sort_sendbuf(gc, dsize)
Sort send buffers according to the idbuf array.
subroutine, public mg_set_refinement_boundaries(boxes, level)
Create a list of refinement boundaries (from the coarse side)
pure integer function, dimension(3), public mg_get_child_offset(mg, id)
Get the offset of a box with respect to its parent (e.g. in 2d, there can be a child at offset 0,...
integer, parameter, public mg_no_box
Special value that indicates there is no box.
subroutine, public mg_restrict_lvl(mg, iv, lvl)
Restrict from lvl to lvl-1.
subroutine, public diffusion_solve_acoeff(mg, dt, order, max_res)
Solve a diffusion equation implicitly, assuming anisotropic diffusion coefficient which has been stor...
pure integer function, public mg_highest_uniform_lvl(mg)
integer, dimension(6), parameter, public mg_neighb_dim
subroutine, public mg_prolong(mg, lvl, iv, iv_to, method, add)
Prolong variable iv from lvl to variable iv_to at lvl+1.
subroutine, public ahelmholtz_set_lambda(lambda)
subroutine, public mg_fill_ghost_cells(mg, iv)
Fill ghost cells at all grid levels.
integer function, public mg_add_timer(mg, name)
subroutine, public mg_apply_op(mg, i_out, op)
Apply operator to the tree and store in variable i_out.
integer, dimension(8, 3), parameter, public mg_child_rev
logical, dimension(3, 8), parameter, public mg_child_low
integer, parameter, public mg_max_num_vars
Maximum number of variables.
integer, parameter, public dp
Type of reals.
subroutine, public sort_and_transfer_buffers(mg, dsize)
integer, parameter, public mg_neighb_highz
Buffer type (one is used for each pair of communicating processes)
Lists of blocks per refinement level.