30 integer,
parameter,
public ::
dp = kind(0.0d0)
33 integer,
parameter,
public ::
i8 = selected_int_kind(18)
111 integer,
parameter,
public ::
mg_child_dix(2, 4) = reshape([0,0,1,0,0,1,1,1], [2,4])
113 integer,
parameter,
public ::
mg_child_rev(4, 2) = reshape([2,1,4,3,3,4,1,2], [4,2])
115 integer,
parameter,
public ::
mg_child_adj_nb(2, 4) = reshape([1,3,2,4,1,2,3,4], [2,4])
117 logical,
parameter,
public ::
mg_child_low(2, 4) = reshape([.true., .true., &
118 .false., .true., .true., .false., .false., .false.], [2, 4])
128 integer,
parameter,
public ::
mg_neighb_dix(2, 4) = reshape([-1,0,1,0,0,-1,0,1], [2,4])
130 logical,
parameter,
public ::
mg_neighb_low(4) = [.true., .false., .true., .false.]
141 integer,
allocatable :: leaves(:)
142 integer,
allocatable :: parents(:)
143 integer,
allocatable :: ref_bnds(:)
144 integer,
allocatable :: ids(:)
145 integer,
allocatable :: my_leaves(:)
146 integer,
allocatable :: my_parents(:)
147 integer,
allocatable :: my_ref_bnds(:)
148 integer,
allocatable :: my_ids(:)
158 integer :: children(2**2)
159 integer :: neighbors(2*2)
163 real(
dp),
allocatable :: cc(:, :, :)
171 integer,
allocatable :: ix(:)
172 real(
dp),
allocatable :: send(:)
173 real(
dp),
allocatable :: recv(:)
177 integer,
allocatable :: n_send(:, :)
178 integer,
allocatable :: n_recv(:, :)
183 real(
dp) :: bc_value = 0.0_dp
185 procedure(
mg_subr_bc),
pointer,
nopass :: boundary_cond => null()
187 procedure(mg_subr_rb),
pointer,
nopass :: refinement_bnd => null()
191 character(len=20) :: name
192 real(
dp) :: t = 0.0_dp
198 logical :: tree_created = .false.
200 logical :: is_allocated = .false.
202 integer :: n_extra_vars = 0
206 integer :: n_cpu = -1
208 integer :: my_rank = -1
210 integer :: box_size = -1
212 integer :: highest_lvl = -1
214 integer :: lowest_lvl = -1
217 integer :: first_normal_lvl = -1
219 integer :: n_boxes = 0
244 logical :: phi_bc_data_stored = .false.
247 logical :: periodic(2) = .false.
262 integer :: n_smoother_substeps = 1
264 integer :: n_cycle_down = 2
266 integer :: n_cycle_up = 2
268 integer :: max_coarse_cycles = 1000
269 integer :: coarsest_grid(2) = 2
271 real(
dp) :: residual_coarse_abs = 1e-8_dp
273 real(
dp) :: residual_coarse_rel = 1e-8_dp
276 procedure(mg_box_op),
pointer,
nopass :: box_op => null()
279 procedure(mg_box_gsrb),
pointer,
nopass :: box_smoother => null()
282 procedure(mg_box_prolong),
pointer,
nopass :: box_prolong => null()
285 integer :: n_timers = 0
294 type(mg_box_t),
intent(in) :: box
295 integer,
intent(in) :: nc
296 integer,
intent(in) :: iv
297 integer,
intent(in) :: nb
298 integer,
intent(out) :: bc_type
300 real(dp),
intent(out) :: bc(nc)
304 subroutine mg_subr_rb(box, nc, iv, nb, cgc)
306 type(mg_box_t),
intent(inout) :: box
307 integer,
intent(in) :: nc
308 integer,
intent(in) :: iv
309 integer,
intent(in) :: nb
311 real(dp),
intent(in) :: cgc(nc)
312 end subroutine mg_subr_rb
315 subroutine mg_box_op(mg, id, nc, i_out)
317 type(mg_t),
intent(inout) :: mg
318 integer,
intent(in) :: id
319 integer,
intent(in) :: nc
320 integer,
intent(in) :: i_out
321 end subroutine mg_box_op
324 subroutine mg_box_gsrb(mg, id, nc, redblack_cntr)
326 type(mg_t),
intent(inout) :: mg
327 integer,
intent(in) :: id
328 integer,
intent(in) :: nc
329 integer,
intent(in) :: redblack_cntr
330 end subroutine mg_box_gsrb
333 subroutine mg_box_prolong(mg, p_id, dix, nc, iv, fine)
335 type(mg_t),
intent(inout) :: mg
336 integer,
intent(in) :: p_id
337 integer,
intent(in) :: dix(2)
338 integer,
intent(in) :: nc
339 integer,
intent(in) :: iv
340 real(dp),
intent(out) :: fine(nc, nc)
341 end subroutine mg_box_prolong
348 public :: mg_box_gsrb
349 public :: mg_box_prolong
453 integer :: timer_total_vcycle = -1
454 integer :: timer_total_fmg = -1
455 integer :: timer_smoother = -1
456 integer :: timer_smoother_gc = -1
457 integer :: timer_coarse = -1
458 integer :: timer_correct = -1
459 integer :: timer_update_coarse = -1
476 Integer,
Parameter :: kdp = selected_real_kind(15)
481 module procedure i_mrgrnk
511 integer,
intent(in) :: ix(2)
520 type(
mg_t),
intent(in) :: mg
521 integer,
intent(in) :: id
522 integer :: ix_offset(2)
524 if (mg%boxes(id)%lvl <= mg%first_normal_lvl)
then
527 ix_offset = iand(mg%boxes(id)%ix-1, 1) * &
528 ishft(mg%box_size, -1)
533 type(
mg_t),
intent(in) :: mg
536 do lvl = mg%first_normal_lvl, mg%highest_lvl-1
538 if (
size(mg%lvls(lvl)%leaves) /= 0 .and. &
539 size(mg%lvls(lvl)%parents) /= 0)
exit
546 type(
mg_t),
intent(in) :: mg
548 integer(i8) :: n_unknowns
551 do lvl = mg%first_normal_lvl, mg%highest_lvl
552 n_unknowns = n_unknowns +
size(mg%lvls(lvl)%leaves)
554 n_unknowns = n_unknowns * int(mg%box_size**3,
i8)
560 integer,
intent(in) :: nb
561 integer,
intent(in) :: nc
562 real(
dp),
intent(out) :: x(nc, 2)
563 integer :: i, ixs(2-1)
570 ixs = [(i, i = 1, 2-1)]
571 ixs(nb_dim:) = ixs(nb_dim:) + 1
575 rmin(nb_dim) = rmin(nb_dim) + box%dr(nb_dim) * nc
580 x(i, ixs(1)) = x(i, ixs(1)) + (i-0.5d0) * box%dr(ixs(1))
585 type(
mg_t),
intent(inout) :: mg
586 character(len=*),
intent(in) :: name
588 mg%n_timers = mg%n_timers + 1
596 timer%t0 = mpi_wtime()
602 timer%t = timer%t + mpi_wtime() - timer%t0
607 type(
mg_t),
intent(in) :: mg
609 real(
dp) :: tmin(mg%n_timers)
610 real(
dp) :: tmax(mg%n_timers)
612 call mpi_reduce(mg%timers(1:mg%n_timers)%t, tmin, mg%n_timers, &
613 mpi_double, mpi_min, 0, mg%comm, ierr)
614 call mpi_reduce(mg%timers(1:mg%n_timers)%t, tmax, mg%n_timers, &
615 mpi_double, mpi_max, 0, mg%comm, ierr)
617 if (mg%my_rank == 0)
then
618 write(*,
"(A20,2A16)")
"name ",
"min(s)",
"max(s)"
619 do n = 1, mg%n_timers
620 write(*,
"(A20,2F16.6)") mg%timers(n)%name, &
630 type(
mg_t),
intent(inout) :: mg
633 if (.not. mg%is_allocated) &
634 error stop
"deallocate_storage: tree is not allocated"
639 deallocate(mg%comm_restrict%n_send)
640 deallocate(mg%comm_restrict%n_recv)
642 deallocate(mg%comm_prolong%n_send)
643 deallocate(mg%comm_prolong%n_recv)
645 deallocate(mg%comm_ghostcell%n_send)
646 deallocate(mg%comm_ghostcell%n_recv)
648 do lvl = mg%lowest_lvl, mg%highest_lvl
649 deallocate(mg%lvls(lvl)%ids)
650 deallocate(mg%lvls(lvl)%leaves)
651 deallocate(mg%lvls(lvl)%parents)
652 deallocate(mg%lvls(lvl)%ref_bnds)
653 deallocate(mg%lvls(lvl)%my_ids)
654 deallocate(mg%lvls(lvl)%my_leaves)
655 deallocate(mg%lvls(lvl)%my_parents)
656 deallocate(mg%lvls(lvl)%my_ref_bnds)
659 mg%is_allocated = .false.
661 mg%phi_bc_data_stored = .false.
668 type(
mg_t),
intent(inout) :: mg
669 integer :: i, id, lvl, nc
670 integer :: n_send(0:mg%n_cpu-1, 3)
671 integer :: n_recv(0:mg%n_cpu-1, 3)
673 integer :: n_in, n_out, n_id
675 if (.not. mg%tree_created) &
676 error stop
"allocate_storage: tree is not yet created"
678 if (mg%is_allocated) &
679 error stop
"allocate_storage: tree is already allocated"
681 do lvl = mg%lowest_lvl, mg%highest_lvl
682 nc = mg%box_size_lvl(lvl)
683 do i = 1,
size(mg%lvls(lvl)%my_ids)
684 id = mg%lvls(lvl)%my_ids(i)
685 allocate(mg%boxes(id)%cc(0:nc+1, 0:nc+1, &
689 mg%boxes(id)%cc(:, :, :) = 0.0_dp
693 allocate(mg%buf(0:mg%n_cpu-1))
696 n_recv(:, 1), dsize(1))
698 n_recv(:, 2), dsize(2))
700 n_recv(:, 3), dsize(3))
703 n_out = maxval(n_send(i, :) * dsize(:))
704 n_in = maxval(n_recv(i, :) * dsize(:))
705 n_id = maxval(n_send(i, :))
706 allocate(mg%buf(i)%send(n_out))
707 allocate(mg%buf(i)%recv(n_in))
708 allocate(mg%buf(i)%ix(n_id))
711 mg%is_allocated = .true.
721 type(
mg_t),
intent(inout) :: mg
722 real(
dp),
intent(in) :: dt
723 real(
dp),
intent(in) :: diffusion_coeff
724 integer,
intent(in) :: order
725 real(
dp),
intent(in) :: max_res
726 integer,
parameter :: max_its = 10
736 call set_rhs(mg, -1/(dt * diffusion_coeff), 0.0_dp)
741 call set_rhs(mg, -2/(dt * diffusion_coeff), -1.0_dp)
743 error stop
"diffusion_solve: order should be 1 or 2"
751 if (res <= max_res)
exit
755 if (n == max_its + 1)
then
756 if (mg%my_rank == 0) &
757 print *,
"Did you specify boundary conditions correctly?"
758 error stop
"diffusion_solve: no convergence"
768 type(
mg_t),
intent(inout) :: mg
769 real(
dp),
intent(in) :: dt
770 integer,
intent(in) :: order
771 real(
dp),
intent(in) :: max_res
772 integer,
parameter :: max_its = 10
782 call set_rhs(mg, -1/dt, 0.0_dp)
787 call set_rhs(mg, -2/dt, -1.0_dp)
789 error stop
"diffusion_solve: order should be 1 or 2"
797 if (res <= max_res)
exit
801 if (n == max_its + 1)
then
802 if (mg%my_rank == 0)
then
803 print *,
"Did you specify boundary conditions correctly?"
804 print *,
"Or is the variation in diffusion too large?"
806 error stop
"diffusion_solve: no convergence"
817 type(
mg_t),
intent(inout) :: mg
818 real(
dp),
intent(in) :: dt
819 integer,
intent(in) :: order
820 real(
dp),
intent(in) :: max_res
821 integer,
parameter :: max_its = 100
831 call set_rhs(mg, -1/dt, 0.0_dp)
836 call set_rhs(mg, -2/dt, -1.0_dp)
838 error stop
"diffusion_solve: order should be 1 or 2"
847 if (res <= max_res)
exit
851 if (n == max_its + 1)
then
852 if (mg%my_rank == 0)
then
853 print *,
"Did you specify boundary conditions correctly?"
854 print *,
"Or is the variation in diffusion too large?"
856 error stop
"diffusion_solve: no convergence"
860 subroutine set_rhs(mg, f1, f2)
861 type(
mg_t),
intent(inout) :: mg
862 real(
dp),
intent(in) :: f1, f2
863 integer :: lvl, i, id, nc
865 do lvl = 1, mg%highest_lvl
866 nc = mg%box_size_lvl(lvl)
867 do i = 1,
size(mg%lvls(lvl)%my_leaves)
868 id = mg%lvls(lvl)%my_leaves(i)
869 mg%boxes(id)%cc(1:nc, 1:nc,
mg_irhs) = &
870 f1 * mg%boxes(id)%cc(1:nc, 1:nc,
mg_iphi) + &
871 f2 * mg%boxes(id)%cc(1:nc, 1:nc,
mg_irhs)
874 end subroutine set_rhs
879 type(
mg_t),
intent(inout) :: mg
881 if (all(mg%periodic))
then
884 mg%subtract_mean = .true.
887 select case (mg%geometry_type)
891 select case (mg%smoother_type)
895 mg%box_smoother => box_gs_lpl
897 error stop
"laplacian_set_methods: unsupported smoother type"
900 mg%box_op => box_clpl
902 select case (mg%smoother_type)
904 mg%box_smoother => box_gs_clpl
906 error stop
"laplacian_set_methods: unsupported smoother type"
909 error stop
"laplacian_set_methods: unsupported geometry"
915 subroutine box_gs_lpl(mg, id, nc, redblack_cntr)
916 type(
mg_t),
intent(inout) :: mg
917 integer,
intent(in) :: id
918 integer,
intent(in) :: nc
919 integer,
intent(in) :: redblack_cntr
920 integer :: i, j, i0, di
921 real(
dp) :: idr2(2), fac
924 idr2 = 1/mg%dr(:, mg%boxes(id)%lvl)**2
925 fac = 0.5_dp / sum(idr2)
937 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
940 i0 = 2 - iand(ieor(redblack_cntr, j), 1)
943 cc(i, j, n) = fac * ( &
944 idr2(1) * (cc(i+1, j, n) + cc(i-1, j, n)) + &
945 idr2(2) * (cc(i, j+1, n) + cc(i, j-1, n)) - &
950 end subroutine box_gs_lpl
991 subroutine box_lpl(mg, id, nc, i_out)
992 type(
mg_t),
intent(inout) :: mg
993 integer,
intent(in) :: id
994 integer,
intent(in) :: nc
995 integer,
intent(in) :: i_out
999 idr2 = 1 / mg%dr(:, mg%boxes(id)%lvl)**2
1001 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
1005 idr2(1) * (cc(i-1, j, n) + cc(i+1, j, n) - 2 * cc(i, j, n)) + &
1006 idr2(2) * (cc(i, j-1, n) + cc(i, j+1, n) - 2 * cc(i, j, n))
1010 end subroutine box_lpl
1014 subroutine box_clpl(mg, id, nc, i_out)
1015 type(
mg_t),
intent(inout) :: mg
1016 integer,
intent(in) :: id
1017 integer,
intent(in) :: nc
1018 integer,
intent(in) :: i_out
1020 real(
dp) :: dr(2), idr2(2)
1021 real(
dp) :: r_face(nc+1), r_inv(nc)
1023 dr = mg%dr(:, mg%boxes(id)%lvl)
1025 r_face = mg%boxes(id)%r_min(1) + dr(1) * [(i, i=0,nc)]
1026 r_inv = 1/(mg%boxes(id)%r_min(1) + dr(1) * [(i-0.5_dp, i=1,nc)])
1028 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
1031 cc(i, j, i_out) = idr2(1) * (&
1032 r_face(i) * r_inv(i) * cc(i-1, j, n) + &
1033 r_face(i+1) * r_inv(i) * cc(i+1, j, n) &
1034 - 2 * cc(i, j, n)) &
1035 + idr2(2) * (cc(i, j-1, n) + cc(i, j+1, n) - 2 * cc(i, j, n))
1039 end subroutine box_clpl
1044 subroutine box_gs_clpl(mg, id, nc, redblack_cntr)
1045 type(
mg_t),
intent(inout) :: mg
1046 integer,
intent(in) :: id
1047 integer,
intent(in) :: nc
1048 integer,
intent(in) :: redblack_cntr
1049 integer :: i, j, i0, di
1051 real(
dp) :: idr2(2), dr(2), dr2(2), fac
1052 real(
dp) :: r_face(nc+1), r_inv(nc)
1054 dr = mg%dr(:, mg%boxes(id)%lvl)
1057 fac = 0.5_dp / sum(idr2)
1058 r_face = mg%boxes(id)%r_min(1) + dr(1) * [(i, i=0,nc)]
1059 r_inv = 1/(mg%boxes(id)%r_min(1) + dr(1) * [(i-0.5_dp, i=1,nc)])
1071 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
1074 i0 = 2 - iand(ieor(redblack_cntr, j), 1)
1077 cc(i, j, n) = fac * (idr2(1) * &
1078 (r_face(i+1) * r_inv(i) * cc(i+1, j, n) + &
1079 r_face(i) * r_inv(i) * cc(i-1, j, n)) + &
1080 idr2(2) * (cc(i, j+1, n) + cc(i, j-1, n)) &
1085 end subroutine box_gs_clpl
1090 type(
mg_t),
intent(inout) :: mg
1092 if (mg%n_extra_vars == 0 .and. mg%is_allocated)
then
1093 error stop
"vhelmholtz_set_methods: mg%n_extra_vars == 0"
1095 mg%n_extra_vars = max(1, mg%n_extra_vars)
1098 mg%subtract_mean = .false.
1103 mg%bc(:,
mg_iveps)%bc_value = 0.0_dp
1105 select case (mg%geometry_type)
1107 mg%box_op => box_vhelmh
1109 select case (mg%smoother_type)
1111 mg%box_smoother => box_gs_vhelmh
1113 error stop
"vhelmholtz_set_methods: unsupported smoother type"
1116 error stop
"vhelmholtz_set_methods: unsupported geometry"
1122 real(
dp),
intent(in) :: lambda
1125 error stop
"vhelmholtz_set_lambda: lambda < 0 not allowed"
1131 subroutine box_gs_vhelmh(mg, id, nc, redblack_cntr)
1132 type(
mg_t),
intent(inout) :: mg
1133 integer,
intent(in) :: id
1134 integer,
intent(in) :: nc
1135 integer,
intent(in) :: redblack_cntr
1136 integer :: i, j, i0, di
1138 real(
dp) :: idr2(2*2), u(2*2)
1139 real(
dp) :: a0, a(2*2), c(2*2)
1142 idr2(1:2*2:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1143 idr2(2:2*2:2) = idr2(1:2*2:2)
1155 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1159 i0 = 2 - iand(ieor(redblack_cntr, j), 1)
1162 a0 = cc(i, j, i_eps)
1163 u(1:2) = cc(i-1:i+1:2, j, n)
1164 a(1:2) = cc(i-1:i+1:2, j, i_eps)
1165 u(3:4) = cc(i, j-1:j+1:2, n)
1166 a(3:4) = cc(i, j-1:j+1:2, i_eps)
1167 c(:) = 2 * a0 * a(:) / (a0 + a(:)) * idr2
1170 (sum(c(:) * u(:)) - cc(i, j,
mg_irhs)) / &
1175 end subroutine box_gs_vhelmh
1178 subroutine box_vhelmh(mg, id, nc, i_out)
1179 type(
mg_t),
intent(inout) :: mg
1180 integer,
intent(in) :: id
1181 integer,
intent(in) :: nc
1182 integer,
intent(in) :: i_out
1184 real(
dp) :: idr2(2*2), a0, u0, u(2*2), a(2*2)
1187 idr2(1:2*2:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1188 idr2(2:2*2:2) = idr2(1:2*2:2)
1190 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1194 a0 = cc(i, j, i_eps)
1195 a(1:2) = cc(i-1:i+1:2, j, i_eps)
1196 a(3:4) = cc(i, j-1:j+1:2, i_eps)
1198 u(1:2) = cc(i-1:i+1:2, j, n)
1199 u(3:4) = cc(i, j-1:j+1:2, n)
1201 cc(i, j, i_out) = sum(2 * idr2 * &
1202 a0*a(:)/(a0 + a(:)) * (u(:) - u0)) - &
1207 end subroutine box_vhelmh
1213 type(
mg_t),
intent(inout) :: mg
1214 integer,
intent(in) :: domain_size(2)
1215 integer,
intent(in) :: box_size
1216 real(
dp),
intent(in) :: dx(2)
1217 real(
dp),
intent(in) :: r_min(2)
1218 logical,
intent(in) :: periodic(2)
1219 integer,
intent(in) :: n_finer
1220 integer :: i, j, lvl, n, id, nx(2), ib, nb(2)
1221 integer :: boxes_per_dim(2,
mg_lvl_lo:1)
1222 integer :: periodic_offset(2)
1224 if (modulo(box_size, 2) /= 0) &
1225 error stop
"box_size should be even"
1226 if (any(modulo(domain_size, box_size) /= 0)) &
1227 error stop
"box_size does not divide domain_size"
1229 if (all(periodic))
then
1230 mg%subtract_mean = .true.
1234 mg%box_size = box_size
1235 mg%box_size_lvl(1) = box_size
1236 mg%domain_size_lvl(:, 1) = domain_size
1237 mg%first_normal_lvl = 1
1240 mg%periodic = periodic
1241 boxes_per_dim(:, :) = 0
1242 boxes_per_dim(:, 1) = domain_size / box_size
1247 if (any(modulo(nx, 2) == 1 .or. nx == mg%coarsest_grid .or. &
1248 (mg%box_size_lvl(lvl) == mg%coarsest_grid .and. &
1251 if (all(modulo(nx/mg%box_size_lvl(lvl), 2) == 0))
then
1252 mg%box_size_lvl(lvl-1) = mg%box_size_lvl(lvl)
1253 boxes_per_dim(:, lvl-1) = boxes_per_dim(:, lvl)/2
1254 mg%first_normal_lvl = lvl-1
1256 mg%box_size_lvl(lvl-1) = mg%box_size_lvl(lvl)/2
1257 boxes_per_dim(:, lvl-1) = boxes_per_dim(:, lvl)
1260 mg%dr(:, lvl-1) = mg%dr(:, lvl) * 2
1262 mg%domain_size_lvl(:, lvl-1) = nx
1269 mg%dr(:, lvl) = mg%dr(:, lvl-1) * 0.5_dp
1270 mg%box_size_lvl(lvl) = box_size
1271 mg%domain_size_lvl(:, lvl) = 2 * mg%domain_size_lvl(:, lvl-1)
1274 n = sum(product(boxes_per_dim, dim=1)) + n_finer
1275 allocate(mg%boxes(n))
1278 nx = boxes_per_dim(:, mg%lowest_lvl)
1279 periodic_offset = [nx(1)-1, (nx(2)-1)*nx(1)]
1281 do j=1,nx(2);
do i=1,nx(1)
1282 mg%n_boxes = mg%n_boxes + 1
1285 mg%boxes(n)%rank = 0
1287 mg%boxes(n)%lvl = mg%lowest_lvl
1288 mg%boxes(n)%ix(:) = [i, j]
1289 mg%boxes(n)%r_min(:) = r_min + (mg%boxes(n)%ix(:) - 1) * &
1290 mg%box_size_lvl(mg%lowest_lvl) * mg%dr(:, mg%lowest_lvl)
1291 mg%boxes(n)%dr(:) = mg%dr(:, mg%lowest_lvl)
1296 mg%boxes(n)%neighbors(:) = [n-1, n+1, n-nx(1), n+nx(1)]
1301 if(nb(ib)==1 .and. .not.periodic(ib))
then
1304 if(nb(ib)==1 .and. periodic(ib))
then
1305 mg%boxes(n)%neighbors(ib*2-1) = n + periodic_offset(ib)
1307 if(nb(ib)==nx(ib) .and. .not.periodic(ib))
then
1310 if(nb(ib)==nx(ib) .and. periodic(ib))
then
1311 mg%boxes(n)%neighbors(ib*2) = n - periodic_offset(ib)
1333 mg%lvls(mg%lowest_lvl)%ids = [(n, n=1, mg%n_boxes)]
1336 do lvl = mg%lowest_lvl, 0
1337 if (mg%box_size_lvl(lvl+1) == mg%box_size_lvl(lvl))
then
1338 do i = 1,
size(mg%lvls(lvl)%ids)
1339 id = mg%lvls(lvl)%ids(i)
1347 do i = 1,
size(mg%lvls(lvl)%ids)
1348 id = mg%lvls(lvl)%ids(i)
1349 call add_single_child(mg, id,
size(mg%lvls(lvl)%ids))
1360 do lvl = mg%lowest_lvl, 1
1361 if (
allocated(mg%lvls(lvl)%ref_bnds)) &
1362 deallocate(mg%lvls(lvl)%ref_bnds)
1363 allocate(mg%lvls(lvl)%ref_bnds(0))
1366 mg%tree_created = .true.
1370 type(
mg_t),
intent(inout) :: mg
1371 integer,
intent(in) :: lvl
1374 do i = 1,
size(mg%lvls(lvl)%ids)
1375 id = mg%lvls(lvl)%ids(i)
1376 call set_neighbs(mg%boxes, id)
1381 type(
mg_t),
intent(inout) :: mg
1382 integer,
intent(in) :: lvl
1385 if (
allocated(mg%lvls(lvl+1)%ids)) &
1386 deallocate(mg%lvls(lvl+1)%ids)
1389 if (mg%box_size_lvl(lvl+1) == mg%box_size_lvl(lvl))
then
1391 allocate(mg%lvls(lvl+1)%ids(n))
1394 do i = 1,
size(mg%lvls(lvl)%parents)
1395 id = mg%lvls(lvl)%parents(i)
1396 mg%lvls(lvl+1)%ids(n*(i-1)+1:n*i) = mg%boxes(id)%children
1399 n =
size(mg%lvls(lvl)%parents)
1400 allocate(mg%lvls(lvl+1)%ids(n))
1403 do i = 1,
size(mg%lvls(lvl)%parents)
1404 id = mg%lvls(lvl)%parents(i)
1405 mg%lvls(lvl+1)%ids(i) = mg%boxes(id)%children(1)
1412 subroutine set_neighbs(boxes, id)
1413 type(
mg_box_t),
intent(inout) :: boxes(:)
1414 integer,
intent(in) :: id
1415 integer :: nb, nb_id
1418 if (boxes(id)%neighbors(nb) ==
mg_no_box)
then
1419 nb_id = find_neighb(boxes, id, nb)
1421 boxes(id)%neighbors(nb) = nb_id
1426 end subroutine set_neighbs
1429 function find_neighb(boxes, id, nb)
result(nb_id)
1430 type(
mg_box_t),
intent(in) :: boxes(:)
1431 integer,
intent(in) :: id
1432 integer,
intent(in) :: nb
1433 integer :: nb_id, p_id, c_ix, d, old_pid
1435 p_id = boxes(id)%parent
1443 p_id = boxes(p_id)%neighbors(nb)
1448 end function find_neighb
1452 type(
mg_box_t),
intent(in) :: boxes(:)
1453 type(
mg_lvl_t),
intent(inout) :: level
1454 integer :: i, id, i_leaf, i_parent
1455 integer :: n_parents, n_leaves
1458 n_leaves =
size(level%ids) - n_parents
1460 if (.not.
allocated(level%parents))
then
1461 allocate(level%parents(n_parents))
1462 else if (n_parents /=
size(level%parents))
then
1463 deallocate(level%parents)
1464 allocate(level%parents(n_parents))
1467 if (.not.
allocated(level%leaves))
then
1468 allocate(level%leaves(n_leaves))
1469 else if (n_leaves /=
size(level%leaves))
then
1470 deallocate(level%leaves)
1471 allocate(level%leaves(n_leaves))
1476 do i = 1,
size(level%ids)
1479 i_parent = i_parent + 1
1480 level%parents(i_parent) = id
1483 level%leaves(i_leaf) = id
1490 type(
mg_box_t),
intent(in) :: boxes(:)
1491 type(
mg_lvl_t),
intent(inout) :: level
1492 integer,
allocatable :: tmp(:)
1493 integer :: i, id, nb, nb_id, ix
1495 if (
allocated(level%ref_bnds))
deallocate(level%ref_bnds)
1497 if (
size(level%parents) == 0)
then
1499 allocate(level%ref_bnds(0))
1501 allocate(tmp(
size(level%leaves)))
1503 do i = 1,
size(level%leaves)
1504 id = level%leaves(i)
1507 nb_id = boxes(id)%neighbors(nb)
1518 allocate(level%ref_bnds(ix))
1519 level%ref_bnds(:) = tmp(1:ix)
1524 type(
mg_t),
intent(inout) :: mg
1525 integer,
intent(in) :: id
1526 integer :: lvl, i, nb, child_nb(2**(2-1))
1528 integer :: c_id, c_ix_base(2)
1531 error stop
"mg_add_children: not enough space"
1536 mg%boxes(id)%children = c_ids
1537 c_ix_base = 2 * mg%boxes(id)%ix - 1
1538 lvl = mg%boxes(id)%lvl+1
1542 mg%boxes(c_id)%rank = mg%boxes(id)%rank
1544 mg%boxes(c_id)%lvl = lvl
1545 mg%boxes(c_id)%parent = id
1548 mg%boxes(c_id)%r_min = mg%boxes(id)%r_min + &
1550 mg%boxes(c_id)%dr(:) = mg%dr(:, lvl)
1555 if (mg%boxes(id)%neighbors(nb) <
mg_no_box)
then
1557 mg%boxes(child_nb)%neighbors(nb) = mg%boxes(id)%neighbors(nb)
1562 subroutine add_single_child(mg, id, n_boxes_lvl)
1563 type(
mg_t),
intent(inout) :: mg
1564 integer,
intent(in) :: id
1565 integer,
intent(in) :: n_boxes_lvl
1566 integer :: lvl, c_id
1568 c_id = mg%n_boxes + 1
1569 mg%n_boxes = mg%n_boxes + 1
1570 mg%boxes(id)%children(1) = c_id
1571 lvl = mg%boxes(id)%lvl+1
1573 mg%boxes(c_id)%rank = mg%boxes(id)%rank
1574 mg%boxes(c_id)%ix = mg%boxes(id)%ix
1575 mg%boxes(c_id)%lvl = lvl
1576 mg%boxes(c_id)%parent = id
1579 mg%boxes(c_id)%neighbors = mg%boxes(id)%neighbors
1581 mg%boxes(c_id)%neighbors = mg%boxes(id)%neighbors + n_boxes_lvl
1583 mg%boxes(c_id)%r_min = mg%boxes(id)%r_min
1584 mg%boxes(c_id)%dr(:) = mg%dr(:, lvl)
1586 end subroutine add_single_child
1596 type(
mg_t),
intent(inout) :: mg
1597 integer :: i, id, lvl, single_cpu_lvl
1598 integer :: work_left, my_work, i_cpu
1602 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1604 do lvl = mg%lowest_lvl, single_cpu_lvl
1605 do i = 1,
size(mg%lvls(lvl)%ids)
1606 id = mg%lvls(lvl)%ids(i)
1607 mg%boxes(id)%rank = 0
1613 do lvl = single_cpu_lvl+1, mg%highest_lvl
1614 work_left =
size(mg%lvls(lvl)%ids)
1618 do i = 1,
size(mg%lvls(lvl)%ids)
1619 if ((mg%n_cpu - i_cpu - 1) * my_work >= work_left)
then
1624 my_work = my_work + 1
1625 work_left = work_left - 1
1627 id = mg%lvls(lvl)%ids(i)
1628 mg%boxes(id)%rank = i_cpu
1632 do lvl = mg%lowest_lvl, mg%highest_lvl
1633 call update_lvl_info(mg, mg%lvls(lvl))
1645 type(
mg_t),
intent(inout) :: mg
1646 integer :: i, id, lvl, single_cpu_lvl
1647 integer :: work_left, my_work(0:mg%n_cpu), i_cpu
1650 integer :: coarse_rank
1654 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1658 do lvl = mg%highest_lvl, single_cpu_lvl+1, -1
1662 do i = 1,
size(mg%lvls(lvl)%parents)
1663 id = mg%lvls(lvl)%parents(i)
1665 c_ids = mg%boxes(id)%children
1666 c_ranks = mg%boxes(c_ids)%rank
1667 i_cpu = most_popular(c_ranks, my_work, mg%n_cpu)
1668 mg%boxes(id)%rank = i_cpu
1669 my_work(i_cpu) = my_work(i_cpu) + 1
1672 work_left =
size(mg%lvls(lvl)%leaves)
1675 do i = 1,
size(mg%lvls(lvl)%leaves)
1677 if ((mg%n_cpu - i_cpu - 1) * my_work(i_cpu) >= &
1678 work_left + sum(my_work(i_cpu+1:)))
then
1682 my_work(i_cpu) = my_work(i_cpu) + 1
1683 work_left = work_left - 1
1685 id = mg%lvls(lvl)%leaves(i)
1686 mg%boxes(id)%rank = i_cpu
1691 if (single_cpu_lvl < mg%highest_lvl)
then
1692 coarse_rank = most_popular(mg%boxes(&
1693 mg%lvls(single_cpu_lvl+1)%ids)%rank, my_work, mg%n_cpu)
1698 do lvl = mg%lowest_lvl, single_cpu_lvl
1699 do i = 1,
size(mg%lvls(lvl)%ids)
1700 id = mg%lvls(lvl)%ids(i)
1701 mg%boxes(id)%rank = coarse_rank
1705 do lvl = mg%lowest_lvl, mg%highest_lvl
1706 call update_lvl_info(mg, mg%lvls(lvl))
1714 type(
mg_t),
intent(inout) :: mg
1715 integer :: i, id, lvl
1718 integer :: single_cpu_lvl, coarse_rank
1719 integer :: my_work(0:mg%n_cpu), i_cpu
1723 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1725 do lvl = mg%highest_lvl-1, single_cpu_lvl+1, -1
1729 do i = 1,
size(mg%lvls(lvl)%leaves)
1730 id = mg%lvls(lvl)%leaves(i)
1731 i_cpu = mg%boxes(id)%rank
1732 my_work(i_cpu) = my_work(i_cpu) + 1
1735 do i = 1,
size(mg%lvls(lvl)%parents)
1736 id = mg%lvls(lvl)%parents(i)
1738 c_ids = mg%boxes(id)%children
1739 c_ranks = mg%boxes(c_ids)%rank
1740 i_cpu = most_popular(c_ranks, my_work, mg%n_cpu)
1741 mg%boxes(id)%rank = i_cpu
1742 my_work(i_cpu) = my_work(i_cpu) + 1
1748 if (single_cpu_lvl < mg%highest_lvl)
then
1749 coarse_rank = most_popular(mg%boxes(&
1750 mg%lvls(single_cpu_lvl+1)%ids)%rank, my_work, mg%n_cpu)
1755 do lvl = mg%lowest_lvl, single_cpu_lvl
1756 do i = 1,
size(mg%lvls(lvl)%ids)
1757 id = mg%lvls(lvl)%ids(i)
1758 mg%boxes(id)%rank = coarse_rank
1762 do lvl = mg%lowest_lvl, mg%highest_lvl
1763 call update_lvl_info(mg, mg%lvls(lvl))
1770 pure integer function most_popular(list, work, n_cpu)
1771 integer,
intent(in) :: list(:)
1772 integer,
intent(in) :: n_cpu
1773 integer,
intent(in) :: work(0:n_cpu-1)
1774 integer :: i, best_count, current_count
1775 integer :: my_work, best_work
1781 do i = 1,
size(list)
1782 current_count = count(list == list(i))
1783 my_work = work(list(i))
1786 if (current_count > best_count .or. &
1787 current_count == best_count .and. my_work < best_work)
then
1788 best_count = current_count
1790 most_popular = list(i)
1794 end function most_popular
1796 subroutine update_lvl_info(mg, lvl)
1797 type(
mg_t),
intent(inout) :: mg
1798 type(
mg_lvl_t),
intent(inout) :: lvl
1800 lvl%my_ids = pack(lvl%ids, &
1801 mg%boxes(lvl%ids)%rank == mg%my_rank)
1802 lvl%my_leaves = pack(lvl%leaves, &
1803 mg%boxes(lvl%leaves)%rank == mg%my_rank)
1804 lvl%my_parents = pack(lvl%parents, &
1805 mg%boxes(lvl%parents)%rank == mg%my_rank)
1806 lvl%my_ref_bnds = pack(lvl%ref_bnds, &
1807 mg%boxes(lvl%ref_bnds)%rank == mg%my_rank)
1808 end subroutine update_lvl_info
1813 type(
mg_t),
intent(inout) :: mg
1815 if (mg%n_extra_vars == 0 .and. mg%is_allocated)
then
1816 error stop
"vlaplacian_set_methods: mg%n_extra_vars == 0"
1818 mg%n_extra_vars = max(1, mg%n_extra_vars)
1821 mg%subtract_mean = .false.
1826 mg%bc(:,
mg_iveps)%bc_value = 0.0_dp
1828 select case (mg%geometry_type)
1830 mg%box_op => box_vlpl
1835 select case (mg%smoother_type)
1837 mg%box_smoother => box_gs_vlpl
1839 error stop
"vlaplacian_set_methods: unsupported smoother type"
1843 error stop
"vlaplacian_set_methods: unsupported geometry"
1849 subroutine box_gs_vlpl(mg, id, nc, redblack_cntr)
1850 type(
mg_t),
intent(inout) :: mg
1851 integer,
intent(in) :: id
1852 integer,
intent(in) :: nc
1853 integer,
intent(in) :: redblack_cntr
1854 integer :: i, j, i0, di
1856 real(
dp) :: idr2(2*2), u(2*2)
1857 real(
dp) :: a0, a(2*2), c(2*2)
1860 idr2(1:2*2:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1861 idr2(2:2*2:2) = idr2(1:2*2:2)
1873 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1877 i0 = 2 - iand(ieor(redblack_cntr, j), 1)
1880 a0 = cc(i, j, i_eps)
1881 u(1:2) = cc(i-1:i+1:2, j, n)
1882 a(1:2) = cc(i-1:i+1:2, j, i_eps)
1883 u(3:4) = cc(i, j-1:j+1:2, n)
1884 a(3:4) = cc(i, j-1:j+1:2, i_eps)
1885 c(:) = 2 * a0 * a(:) / (a0 + a(:)) * idr2
1888 (sum(c(:) * u(:)) - cc(i, j,
mg_irhs)) / sum(c(:))
1892 end subroutine box_gs_vlpl
1895 subroutine box_vlpl(mg, id, nc, i_out)
1896 type(
mg_t),
intent(inout) :: mg
1897 integer,
intent(in) :: id
1898 integer,
intent(in) :: nc
1899 integer,
intent(in) :: i_out
1901 real(
dp) :: idr2(2*2), a0, u0, u(2*2), a(2*2)
1904 idr2(1:2*2:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1905 idr2(2:2*2:2) = idr2(1:2*2:2)
1907 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1911 a0 = cc(i, j, i_eps)
1912 a(1:2) = cc(i-1:i+1:2, j, i_eps)
1913 a(3:4) = cc(i, j-1:j+1:2, i_eps)
1915 u(1:2) = cc(i-1:i+1:2, j, n)
1916 u(3:4) = cc(i, j-1:j+1:2, n)
1918 cc(i, j, i_out) = sum(2 * idr2 * &
1919 a0*a(:)/(a0 + a(:)) * (u(:) - u0))
1923 end subroutine box_vlpl
2031 type(
mg_t),
intent(inout) :: mg
2033 integer,
intent(in),
optional :: comm
2035 logical :: initialized
2037 call mpi_initialized(initialized, ierr)
2038 if (.not. initialized)
then
2042 if (
present(comm))
then
2045 mg%comm = mpi_comm_world
2048 call mpi_comm_rank(mg%comm, mg%my_rank, ierr)
2049 call mpi_comm_size(mg%comm, mg%n_cpu, ierr)
2054 type(
mg_t),
intent(inout) :: mg
2055 integer,
intent(in) :: dsize
2056 integer :: i, n_send, n_recv
2057 integer :: send_req(mg%n_cpu)
2058 integer :: recv_req(mg%n_cpu)
2064 do i = 0, mg%n_cpu - 1
2065 if (mg%buf(i)%i_send > 0)
then
2068 call mpi_isend(mg%buf(i)%send, mg%buf(i)%i_send, mpi_double, &
2069 i, 0, mg%comm, send_req(n_send), ierr)
2071 if (mg%buf(i)%i_recv > 0)
then
2073 call mpi_irecv(mg%buf(i)%recv, mg%buf(i)%i_recv, mpi_double, &
2074 i, 0, mg%comm, recv_req(n_recv), ierr)
2078 call mpi_waitall(n_recv, recv_req(1:n_recv), mpi_statuses_ignore, ierr)
2079 call mpi_waitall(n_send, send_req(1:n_send), mpi_statuses_ignore, ierr)
2086 type(
mg_buf_t),
intent(inout) :: gc
2087 integer,
intent(in) :: dsize
2088 integer :: ix_sort(gc%i_ix)
2089 real(dp) :: buf_cpy(gc%i_send)
2092 call mrgrnk(gc%ix(1:gc%i_ix), ix_sort)
2094 buf_cpy = gc%send(1:gc%i_send)
2098 j = (ix_sort(n)-1) * dsize
2099 gc%send(i+1:i+dsize) = buf_cpy(j+1:j+dsize)
2101 gc%ix(1:gc%i_ix) = gc%ix(ix_sort)
2109 type(
mg_t),
intent(inout) :: mg
2110 integer,
intent(out) :: n_send(0:mg%n_cpu-1)
2111 integer,
intent(out) :: n_recv(0:mg%n_cpu-1)
2112 integer,
intent(out) :: dsize
2113 integer :: i, id, lvl, nc
2115 allocate(mg%comm_ghostcell%n_send(0:mg%n_cpu-1, &
2116 mg%first_normal_lvl:mg%highest_lvl))
2117 allocate(mg%comm_ghostcell%n_recv(0:mg%n_cpu-1, &
2118 mg%first_normal_lvl:mg%highest_lvl))
2120 dsize = mg%box_size**(2-1)
2122 do lvl = mg%first_normal_lvl, mg%highest_lvl
2123 nc = mg%box_size_lvl(lvl)
2124 mg%buf(:)%i_send = 0
2125 mg%buf(:)%i_recv = 0
2128 do i = 1,
size(mg%lvls(lvl)%my_ids)
2129 id = mg%lvls(lvl)%my_ids(i)
2130 call buffer_ghost_cells(mg, id, nc, 1, dry_run=.true.)
2134 do i = 1,
size(mg%lvls(lvl-1)%my_ref_bnds)
2135 id = mg%lvls(lvl-1)%my_ref_bnds(i)
2136 call buffer_refinement_boundaries(mg, id, nc, 1, dry_run=.true.)
2141 mg%buf(:)%i_recv = 0
2142 do i = 1,
size(mg%lvls(lvl)%my_ids)
2143 id = mg%lvls(lvl)%my_ids(i)
2144 call set_ghost_cells(mg, id, nc, 1, dry_run=.true.)
2147 mg%comm_ghostcell%n_send(:, lvl) = mg%buf(:)%i_send/dsize
2148 mg%comm_ghostcell%n_recv(:, lvl) = mg%buf(:)%i_recv/dsize
2151 n_send = maxval(mg%comm_ghostcell%n_send, dim=2)
2152 n_recv = maxval(mg%comm_ghostcell%n_recv, dim=2)
2158 type(
mg_t),
intent(inout) :: mg
2163 do lvl = mg%lowest_lvl, mg%highest_lvl
2164 nc = mg%box_size_lvl(lvl)
2165 call mg_phi_bc_store_lvl(mg, lvl, nc)
2168 mg%phi_bc_data_stored = .true.
2171 subroutine mg_phi_bc_store_lvl(mg, lvl, nc)
2172 type(
mg_t),
intent(inout) :: mg
2173 integer,
intent(in) :: lvl
2174 integer,
intent(in) :: nc
2176 integer :: i, id, nb, nb_id, bc_type
2178 do i = 1,
size(mg%lvls(lvl)%my_ids)
2179 id = mg%lvls(lvl)%my_ids(i)
2181 nb_id = mg%boxes(id)%neighbors(nb)
2184 if (
associated(mg%bc(nb,
mg_iphi)%boundary_cond))
then
2185 call mg%bc(nb,
mg_iphi)%boundary_cond(mg%boxes(id), nc, &
2188 bc_type = mg%bc(nb,
mg_iphi)%bc_type
2189 bc = mg%bc(nb,
mg_iphi)%bc_value
2195 mg%boxes(id)%neighbors(nb) = bc_type
2198 call box_set_gc(mg%boxes(id), nb, nc,
mg_irhs, bc)
2202 end subroutine mg_phi_bc_store_lvl
2207 integer,
intent(in) :: iv
2210 do lvl = mg%lowest_lvl, mg%highest_lvl
2219 integer,
intent(in) :: lvl
2220 integer,
intent(in) :: iv
2221 integer :: i, id, dsize, nc
2223 if (lvl < mg%lowest_lvl) &
2224 error stop
"fill_ghost_cells_lvl: lvl < lowest_lvl"
2225 if (lvl > mg%highest_lvl) &
2226 error stop
"fill_ghost_cells_lvl: lvl > highest_lvl"
2228 nc = mg%box_size_lvl(lvl)
2230 if (lvl >= mg%first_normal_lvl)
then
2232 mg%buf(:)%i_send = 0
2233 mg%buf(:)%i_recv = 0
2236 do i = 1,
size(mg%lvls(lvl)%my_ids)
2237 id = mg%lvls(lvl)%my_ids(i)
2238 call buffer_ghost_cells(mg, id, nc, iv, .false.)
2242 do i = 1,
size(mg%lvls(lvl-1)%my_ref_bnds)
2243 id = mg%lvls(lvl-1)%my_ref_bnds(i)
2244 call buffer_refinement_boundaries(mg, id, nc, iv, .false.)
2249 mg%buf(:)%i_recv = mg%comm_ghostcell%n_recv(:, lvl) * dsize
2253 mg%buf(:)%i_recv = 0
2256 do i = 1,
size(mg%lvls(lvl)%my_ids)
2257 id = mg%lvls(lvl)%my_ids(i)
2258 call set_ghost_cells(mg, id, nc, iv, .false.)
2262 subroutine buffer_ghost_cells(mg, id, nc, iv, dry_run)
2263 type(
mg_t),
intent(inout) :: mg
2264 integer,
intent(in) :: id
2265 integer,
intent(in) :: nc
2266 integer,
intent(in) :: iv
2267 logical,
intent(in) :: dry_run
2268 integer :: nb, nb_id, nb_rank
2271 nb_id = mg%boxes(id)%neighbors(nb)
2275 nb_rank = mg%boxes(nb_id)%rank
2277 if (nb_rank /= mg%my_rank)
then
2278 call buffer_for_nb(mg, mg%boxes(id), nc, iv, nb_id, nb_rank, &
2283 end subroutine buffer_ghost_cells
2285 subroutine buffer_refinement_boundaries(mg, id, nc, iv, dry_run)
2286 type(
mg_t),
intent(inout) :: mg
2287 integer,
intent(in) :: id
2288 integer,
intent(in) :: nc
2289 integer,
intent(in) :: iv
2290 logical,
intent(in) :: dry_run
2291 integer :: nb, nb_id, c_ids(2**(2-1))
2292 integer :: n, c_id, c_rank
2295 nb_id = mg%boxes(id)%neighbors(nb)
2298 c_ids = mg%boxes(nb_id)%children(&
2303 c_rank = mg%boxes(c_id)%rank
2305 if (c_rank /= mg%my_rank)
then
2307 call buffer_for_fine_nb(mg, mg%boxes(id), nc, iv, c_id, &
2308 c_rank, nb, dry_run)
2314 end subroutine buffer_refinement_boundaries
2317 subroutine set_ghost_cells(mg, id, nc, iv, dry_run)
2318 type(
mg_t),
intent(inout) :: mg
2319 integer,
intent(in) :: id
2320 integer,
intent(in) :: nc
2321 integer,
intent(in) :: iv
2322 logical,
intent(in) :: dry_run
2324 integer :: nb, nb_id, nb_rank, bc_type
2327 nb_id = mg%boxes(id)%neighbors(nb)
2331 nb_rank = mg%boxes(nb_id)%rank
2333 if (nb_rank /= mg%my_rank)
then
2334 call fill_buffered_nb(mg, mg%boxes(id), nb_rank, &
2335 nb, nc, iv, dry_run)
2336 else if (.not. dry_run)
then
2337 call copy_from_nb(mg%boxes(id), mg%boxes(nb_id), &
2342 call fill_refinement_bnd(mg, id, nb, nc, iv, dry_run)
2343 else if (.not. dry_run)
then
2345 if (mg%phi_bc_data_stored .and. iv ==
mg_iphi)
then
2348 call box_get_gc(mg%boxes(id), nb, nc,
mg_irhs, bc)
2351 if (
associated(mg%bc(nb, iv)%boundary_cond))
then
2352 call mg%bc(nb, iv)%boundary_cond(mg%boxes(id), nc, iv, &
2355 bc_type = mg%bc(nb, iv)%bc_type
2356 bc = mg%bc(nb, iv)%bc_value
2360 call box_set_gc(mg%boxes(id), nb, nc, iv, bc)
2361 call bc_to_gc(mg, id, nc, iv, nb, bc_type)
2364 end subroutine set_ghost_cells
2366 subroutine fill_refinement_bnd(mg, id, nb, nc, iv, dry_run)
2367 type(
mg_t),
intent(inout) :: mg
2368 integer,
intent(in) :: id
2369 integer,
intent(in) :: nc
2370 integer,
intent(in) :: iv
2371 integer,
intent(in) :: nb
2372 logical,
intent(in) :: dry_run
2374 integer :: p_id, p_nb_id, ix_offset(2)
2375 integer :: i, dsize, p_nb_rank
2378 p_id = mg%boxes(id)%parent
2379 p_nb_id = mg%boxes(p_id)%neighbors(nb)
2380 p_nb_rank = mg%boxes(p_nb_id)%rank
2382 if (p_nb_rank /= mg%my_rank)
then
2383 i = mg%buf(p_nb_rank)%i_recv
2384 if (.not. dry_run)
then
2385 gc = reshape(mg%buf(p_nb_rank)%recv(i+1:i+dsize), shape(gc))
2387 mg%buf(p_nb_rank)%i_recv = mg%buf(p_nb_rank)%i_recv + dsize
2388 else if (.not. dry_run)
then
2390 call box_gc_for_fine_neighbor(mg%boxes(p_nb_id),
mg_neighb_rev(nb), &
2391 ix_offset, nc, iv, gc)
2394 if (.not. dry_run)
then
2395 if (
associated(mg%bc(nb, iv)%refinement_bnd))
then
2396 call mg%bc(nb, iv)%refinement_bnd(mg%boxes(id), nc, iv, nb, gc)
2398 call sides_rb(mg%boxes(id), nc, iv, nb, gc)
2401 end subroutine fill_refinement_bnd
2403 subroutine copy_from_nb(box, box_nb, nb, nc, iv)
2404 type(
mg_box_t),
intent(inout) :: box
2405 type(
mg_box_t),
intent(in) :: box_nb
2406 integer,
intent(in) :: nb
2407 integer,
intent(in) :: nc
2408 integer,
intent(in) :: iv
2411 call box_gc_for_neighbor(box_nb,
mg_neighb_rev(nb), nc, iv, gc)
2412 call box_set_gc(box, nb, nc, iv, gc)
2413 end subroutine copy_from_nb
2415 subroutine buffer_for_nb(mg, box, nc, iv, nb_id, nb_rank, nb, dry_run)
2416 type(
mg_t),
intent(inout) :: mg
2417 type(
mg_box_t),
intent(inout) :: box
2418 integer,
intent(in) :: nc
2419 integer,
intent(in) :: iv
2420 integer,
intent(in) :: nb_id
2421 integer,
intent(in) :: nb_rank
2422 integer,
intent(in) :: nb
2423 logical,
intent(in) :: dry_run
2427 i = mg%buf(nb_rank)%i_send
2430 if (.not. dry_run)
then
2431 call box_gc_for_neighbor(box, nb, nc, iv, gc)
2432 mg%buf(nb_rank)%send(i+1:i+dsize) = pack(gc, .true.)
2437 i = mg%buf(nb_rank)%i_ix
2438 if (.not. dry_run)
then
2442 mg%buf(nb_rank)%i_send = mg%buf(nb_rank)%i_send + dsize
2443 mg%buf(nb_rank)%i_ix = mg%buf(nb_rank)%i_ix + 1
2444 end subroutine buffer_for_nb
2446 subroutine buffer_for_fine_nb(mg, box, nc, iv, fine_id, fine_rank, nb, dry_run)
2447 type(
mg_t),
intent(inout) :: mg
2448 type(
mg_box_t),
intent(inout) :: box
2449 integer,
intent(in) :: nc
2450 integer,
intent(in) :: iv
2451 integer,
intent(in) :: fine_id
2452 integer,
intent(in) :: fine_rank
2453 integer,
intent(in) :: nb
2454 logical,
intent(in) :: dry_run
2455 integer :: i, dsize, ix_offset(2)
2458 i = mg%buf(fine_rank)%i_send
2461 if (.not. dry_run)
then
2463 call box_gc_for_fine_neighbor(box, nb, ix_offset, nc, iv, gc)
2464 mg%buf(fine_rank)%send(i+1:i+dsize) = pack(gc, .true.)
2469 i = mg%buf(fine_rank)%i_ix
2470 if (.not. dry_run)
then
2475 mg%buf(fine_rank)%i_send = mg%buf(fine_rank)%i_send + dsize
2476 mg%buf(fine_rank)%i_ix = mg%buf(fine_rank)%i_ix + 1
2477 end subroutine buffer_for_fine_nb
2479 subroutine fill_buffered_nb(mg, box, nb_rank, nb, nc, iv, dry_run)
2480 type(
mg_t),
intent(inout) :: mg
2481 type(
mg_box_t),
intent(inout) :: box
2482 integer,
intent(in) :: nb_rank
2483 integer,
intent(in) :: nb
2484 integer,
intent(in) :: nc
2485 integer,
intent(in) :: iv
2486 logical,
intent(in) :: dry_run
2490 i = mg%buf(nb_rank)%i_recv
2493 if (.not. dry_run)
then
2494 gc = reshape(mg%buf(nb_rank)%recv(i+1:i+dsize), shape(gc))
2495 call box_set_gc(box, nb, nc, iv, gc)
2497 mg%buf(nb_rank)%i_recv = mg%buf(nb_rank)%i_recv + dsize
2499 end subroutine fill_buffered_nb
2501 subroutine box_gc_for_neighbor(box, nb, nc, iv, gc)
2503 integer,
intent(in) :: nb, nc, iv
2504 real(
dp),
intent(out) :: gc(nc)
2508 gc = box%cc(1, 1:nc, iv)
2510 gc = box%cc(nc, 1:nc, iv)
2512 gc = box%cc(1:nc, 1, iv)
2514 gc = box%cc(1:nc, nc, iv)
2516 end subroutine box_gc_for_neighbor
2519 subroutine box_gc_for_fine_neighbor(box, nb, di, nc, iv, gc)
2521 integer,
intent(in) :: nb
2522 integer,
intent(in) :: di(2)
2523 integer,
intent(in) :: nc, iv
2524 real(
dp),
intent(out) :: gc(nc)
2525 real(
dp) :: tmp(0:nc/2+1), grad(2-1)
2533 tmp = box%cc(1, di(2):di(2)+hnc+1, iv)
2535 tmp = box%cc(nc, di(2):di(2)+hnc+1, iv)
2537 tmp = box%cc(di(1):di(1)+hnc+1, 1, iv)
2539 tmp = box%cc(di(1):di(1)+hnc+1, nc, iv)
2547 grad(1) = 0.125_dp * (tmp(i+1) - tmp(i-1))
2548 gc(2*i-1) = tmp(i) - grad(1)
2549 gc(2*i) = tmp(i) + grad(1)
2551 end subroutine box_gc_for_fine_neighbor
2553 subroutine box_get_gc(box, nb, nc, iv, gc)
2555 integer,
intent(in) :: nb, nc, iv
2556 real(
dp),
intent(out) :: gc(nc)
2560 gc = box%cc(0, 1:nc, iv)
2562 gc = box%cc(nc+1, 1:nc, iv)
2564 gc = box%cc(1:nc, 0, iv)
2566 gc = box%cc(1:nc, nc+1, iv)
2568 end subroutine box_get_gc
2570 subroutine box_set_gc(box, nb, nc, iv, gc)
2571 type(
mg_box_t),
intent(inout) :: box
2572 integer,
intent(in) :: nb, nc, iv
2573 real(
dp),
intent(in) :: gc(nc)
2577 box%cc(0, 1:nc, iv) = gc
2579 box%cc(nc+1, 1:nc, iv) = gc
2581 box%cc(1:nc, 0, iv) = gc
2583 box%cc(1:nc, nc+1, iv) = gc
2585 end subroutine box_set_gc
2587 subroutine bc_to_gc(mg, id, nc, iv, nb, bc_type)
2588 type(
mg_t),
intent(inout) :: mg
2589 integer,
intent(in) :: id
2590 integer,
intent(in) :: nc
2591 integer,
intent(in) :: iv
2592 integer,
intent(in) :: nb
2593 integer,
intent(in) :: bc_type
2594 real(
dp) :: c0, c1, c2, dr
2604 select case (bc_type)
2619 error stop
"bc_to_gc: unknown boundary condition"
2624 mg%boxes(id)%cc(0, 1:nc, iv) = &
2625 c0 * mg%boxes(id)%cc(0, 1:nc, iv) + &
2626 c1 * mg%boxes(id)%cc(1, 1:nc, iv) + &
2627 c2 * mg%boxes(id)%cc(2, 1:nc, iv)
2629 mg%boxes(id)%cc(nc+1, 1:nc, iv) = &
2630 c0 * mg%boxes(id)%cc(nc+1, 1:nc, iv) + &
2631 c1 * mg%boxes(id)%cc(nc, 1:nc, iv) + &
2632 c2 * mg%boxes(id)%cc(nc-1, 1:nc, iv)
2634 mg%boxes(id)%cc(1:nc, 0, iv) = &
2635 c0 * mg%boxes(id)%cc(1:nc, 0, iv) + &
2636 c1 * mg%boxes(id)%cc(1:nc, 1, iv) + &
2637 c2 * mg%boxes(id)%cc(1:nc, 2, iv)
2639 mg%boxes(id)%cc(1:nc, nc+1, iv) = &
2640 c0 * mg%boxes(id)%cc(1:nc, nc+1, iv) + &
2641 c1 * mg%boxes(id)%cc(1:nc, nc, iv) + &
2642 c2 * mg%boxes(id)%cc(1:nc, nc-1, iv)
2644 end subroutine bc_to_gc
2647 subroutine sides_rb(box, nc, iv, nb, gc)
2648 type(
mg_box_t),
intent(inout) :: box
2649 integer,
intent(in) :: nc
2650 integer,
intent(in) :: iv
2651 integer,
intent(in) :: nb
2653 real(
dp),
intent(in) :: gc(nc)
2655 integer :: i, j, ix, dix
2671 dj = -1 + 2 * iand(j, 1)
2672 box%cc(i-di, j, iv) = 0.5_dp * gc(j) &
2673 + 0.75_dp * box%cc(i, j, iv) &
2674 - 0.25_dp * box%cc(i+di, j, iv)
2680 di = -1 + 2 * iand(i, 1)
2681 box%cc(i, j-dj, iv) = 0.5_dp * gc(i) &
2682 + 0.75_dp * box%cc(i, j, iv) &
2683 - 0.25_dp * box%cc(i, j+dj, iv)
2687 end subroutine sides_rb
2693 type(
mg_t),
intent(inout) :: mg
2694 integer,
intent(out) :: n_send(0:mg%n_cpu-1)
2695 integer,
intent(out) :: n_recv(0:mg%n_cpu-1)
2696 integer,
intent(out) :: dsize
2697 integer :: lvl, min_lvl
2699 if (.not.
allocated(mg%comm_restrict%n_send))
then
2700 error stop
"Call restrict_buffer_size before prolong_buffer_size"
2703 min_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
2704 allocate(mg%comm_prolong%n_send(0:mg%n_cpu-1, &
2705 min_lvl:mg%highest_lvl))
2706 allocate(mg%comm_prolong%n_recv(0:mg%n_cpu-1, &
2707 min_lvl:mg%highest_lvl))
2709 mg%comm_prolong%n_recv(:, mg%highest_lvl) = 0
2710 mg%comm_prolong%n_send(:, mg%highest_lvl) = 0
2712 do lvl = min_lvl, mg%highest_lvl-1
2713 mg%comm_prolong%n_recv(:, lvl) = &
2714 mg%comm_restrict%n_send(:, lvl+1)
2715 mg%comm_prolong%n_send(:, lvl) = &
2716 mg%comm_restrict%n_recv(:, lvl+1)
2721 dsize = (mg%box_size)**2
2722 n_send = maxval(mg%comm_prolong%n_send, dim=2)
2723 n_recv = maxval(mg%comm_prolong%n_recv, dim=2)
2729 type(
mg_t),
intent(inout) :: mg
2730 integer,
intent(in) :: lvl
2731 integer,
intent(in) :: iv
2732 integer,
intent(in) :: iv_to
2733 procedure(mg_box_prolong) :: method
2734 logical,
intent(in) :: add
2735 integer :: i, id, dsize, nc
2737 if (lvl == mg%highest_lvl) error stop
"cannot prolong highest level"
2738 if (lvl < mg%lowest_lvl) error stop
"cannot prolong below lowest level"
2741 if (lvl >= mg%first_normal_lvl-1)
then
2742 dsize = mg%box_size**2
2743 mg%buf(:)%i_send = 0
2746 do i = 1,
size(mg%lvls(lvl)%my_ids)
2747 id = mg%lvls(lvl)%my_ids(i)
2748 call prolong_set_buffer(mg, id, mg%box_size, iv, method)
2751 mg%buf(:)%i_recv = mg%comm_prolong%n_recv(:, lvl) * dsize
2753 mg%buf(:)%i_recv = 0
2756 nc = mg%box_size_lvl(lvl+1)
2757 do i = 1,
size(mg%lvls(lvl+1)%my_ids)
2758 id = mg%lvls(lvl+1)%my_ids(i)
2759 call prolong_onto(mg, id, nc, iv, iv_to, add, method)
2766 subroutine prolong_set_buffer(mg, id, nc, iv, method)
2767 type(
mg_t),
intent(inout) :: mg
2768 integer,
intent(in) :: id
2769 integer,
intent(in) :: nc
2770 integer,
intent(in) :: iv
2771 procedure(mg_box_prolong) :: method
2772 integer :: i, dix(2)
2773 integer :: i_c, c_id, c_rank, dsize
2774 real(
dp) :: tmp(nc, nc)
2779 c_id = mg%boxes(id)%children(i_c)
2781 c_rank = mg%boxes(c_id)%rank
2782 if (c_rank /= mg%my_rank)
then
2784 call method(mg, id, dix, nc, iv, tmp)
2786 i = mg%buf(c_rank)%i_send
2787 mg%buf(c_rank)%send(i+1:i+dsize) = pack(tmp, .true.)
2788 mg%buf(c_rank)%i_send = mg%buf(c_rank)%i_send + dsize
2790 i = mg%buf(c_rank)%i_ix
2791 mg%buf(c_rank)%ix(i+1) = c_id
2792 mg%buf(c_rank)%i_ix = mg%buf(c_rank)%i_ix + 1
2796 end subroutine prolong_set_buffer
2799 subroutine prolong_onto(mg, id, nc, iv, iv_to, add, method)
2800 type(
mg_t),
intent(inout) :: mg
2801 integer,
intent(in) :: id
2802 integer,
intent(in) :: nc
2803 integer,
intent(in) :: iv
2804 integer,
intent(in) :: iv_to
2805 logical,
intent(in) :: add
2806 procedure(mg_box_prolong) :: method
2807 integer :: hnc, p_id, p_rank, i, dix(2), dsize
2808 real(
dp) :: tmp(nc, nc)
2811 p_id = mg%boxes(id)%parent
2812 p_rank = mg%boxes(p_id)%rank
2814 if (p_rank == mg%my_rank)
then
2816 call method(mg, p_id, dix, nc, iv, tmp)
2819 i = mg%buf(p_rank)%i_recv
2820 tmp = reshape(mg%buf(p_rank)%recv(i+1:i+dsize), [nc, nc])
2821 mg%buf(p_rank)%i_recv = mg%buf(p_rank)%i_recv + dsize
2825 mg%boxes(id)%cc(1:nc, 1:nc, iv_to) = &
2826 mg%boxes(id)%cc(1:nc, 1:nc, iv_to) + tmp
2828 mg%boxes(id)%cc(1:nc, 1:nc, iv_to) = tmp
2831 end subroutine prolong_onto
2835 type(
mg_t),
intent(inout) :: mg
2836 integer,
intent(in) :: p_id
2837 integer,
intent(in) :: dix(2)
2838 integer,
intent(in) :: nc
2839 integer,
intent(in) :: iv
2840 real(
dp),
intent(out) :: fine(nc, nc)
2842 integer :: i, j, hnc
2844 real(
dp) :: f0, flx, fhx, fly, fhy
2848 associate(crs => mg%boxes(p_id)%cc)
2854 f0 = 0.5_dp * crs(ic, jc, iv)
2855 flx = 0.25_dp * crs(ic-1, jc, iv)
2856 fhx = 0.25_dp * crs(ic+1, jc, iv)
2857 fly = 0.25_dp * crs(ic, jc-1, iv)
2858 fhy = 0.25_dp * crs(ic, jc+1, iv)
2860 fine(2*i-1, 2*j-1) = f0 + flx + fly
2861 fine(2*i , 2*j-1) = f0 + fhx + fly
2862 fine(2*i-1, 2*j) = f0 + flx + fhy
2863 fine(2*i , 2*j) = f0 + fhx + fhy
2872 type(
mg_t),
intent(inout) :: mg
2874 mg%subtract_mean = .false.
2876 select case (mg%geometry_type)
2878 mg%box_op => box_helmh
2880 select case (mg%smoother_type)
2882 mg%box_smoother => box_gs_helmh
2884 error stop
"helmholtz_set_methods: unsupported smoother type"
2887 error stop
"helmholtz_set_methods: unsupported geometry"
2893 real(
dp),
intent(in) :: lambda
2896 error stop
"helmholtz_set_lambda: lambda < 0 not allowed"
2902 subroutine box_gs_helmh(mg, id, nc, redblack_cntr)
2903 type(
mg_t),
intent(inout) :: mg
2904 integer,
intent(in) :: id
2905 integer,
intent(in) :: nc
2906 integer,
intent(in) :: redblack_cntr
2907 integer :: i, j, i0, di
2908 real(
dp) :: idr2(2), fac
2911 idr2 = 1/mg%dr(:, mg%boxes(id)%lvl)**2
2924 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
2927 i0 = 2 - iand(ieor(redblack_cntr, j), 1)
2930 cc(i, j, n) = fac * ( &
2931 idr2(1) * (cc(i+1, j, n) + cc(i-1, j, n)) + &
2932 idr2(2) * (cc(i, j+1, n) + cc(i, j-1, n)) - &
2937 end subroutine box_gs_helmh
2940 subroutine box_helmh(mg, id, nc, i_out)
2941 type(
mg_t),
intent(inout) :: mg
2942 integer,
intent(in) :: id
2943 integer,
intent(in) :: nc
2944 integer,
intent(in) :: i_out
2948 idr2 = 1 / mg%dr(:, mg%boxes(id)%lvl)**2
2950 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
2954 idr2(1) * (cc(i-1, j, n) + cc(i+1, j, n) - 2 * cc(i, j, n)) + &
2955 idr2(2) * (cc(i, j-1, n) + cc(i, j+1, n) - 2 * cc(i, j, n)) - &
2960 end subroutine box_helmh
2966 type(
mg_t),
intent(inout) :: mg
2971 select case (mg%operator_type)
2983 error stop
"mg_set_methods: unknown operator"
2989 mg%n_smoother_substeps = 2
2991 mg%n_smoother_substeps = 1
2995 subroutine check_methods(mg)
2996 type(
mg_t),
intent(inout) :: mg
2998 if (.not.
associated(mg%box_op) .or. &
2999 .not.
associated(mg%box_smoother))
then
3003 end subroutine check_methods
3005 subroutine mg_add_timers(mg)
3006 type(
mg_t),
intent(inout) :: mg
3007 timer_total_vcycle =
mg_add_timer(mg,
"mg total V-cycle")
3008 timer_total_fmg =
mg_add_timer(mg,
"mg total FMG cycle")
3010 timer_smoother_gc =
mg_add_timer(mg,
"mg smoother g.c.")
3013 timer_update_coarse =
mg_add_timer(mg,
"mg update coarse")
3014 end subroutine mg_add_timers
3018 type(
mg_t),
intent(inout) :: mg
3019 logical,
intent(in) :: have_guess
3020 real(
dp),
intent(out),
optional :: max_res
3021 integer :: lvl, i, id
3023 call check_methods(mg)
3024 if (timer_smoother == -1)
call mg_add_timers(mg)
3028 if (.not. have_guess)
then
3029 do lvl = mg%highest_lvl, mg%lowest_lvl, -1
3030 do i = 1,
size(mg%lvls(lvl)%my_ids)
3031 id = mg%lvls(lvl)%my_ids(i)
3032 mg%boxes(id)%cc(:, :,
mg_iphi) = 0.0_dp
3040 do lvl = mg%highest_lvl, mg%lowest_lvl+1, -1
3043 call update_coarse(mg, lvl)
3047 if (mg%subtract_mean)
then
3052 do lvl = mg%lowest_lvl, mg%highest_lvl
3054 do i = 1,
size(mg%lvls(lvl)%my_ids)
3055 id = mg%lvls(lvl)%my_ids(i)
3056 mg%boxes(id)%cc(:, :,
mg_iold) = &
3057 mg%boxes(id)%cc(:, :,
mg_iphi)
3060 if (lvl > mg%lowest_lvl)
then
3064 call correct_children(mg, lvl-1)
3072 if (lvl == mg%highest_lvl)
then
3085 type(
mg_t),
intent(inout) :: mg
3086 integer,
intent(in),
optional :: highest_lvl
3087 real(
dp),
intent(out),
optional :: max_res
3089 logical,
intent(in),
optional :: standalone
3090 integer :: lvl, min_lvl, i, max_lvl, ierr
3091 real(
dp) :: init_res, res
3092 logical :: is_standalone
3094 is_standalone = .true.
3095 if (
present(standalone)) is_standalone = standalone
3097 call check_methods(mg)
3098 if (timer_smoother == -1)
call mg_add_timers(mg)
3100 if (is_standalone) &
3103 if (mg%subtract_mean .and. .not.
present(highest_lvl))
then
3109 min_lvl = mg%lowest_lvl
3110 max_lvl = mg%highest_lvl
3111 if (
present(highest_lvl)) max_lvl = highest_lvl
3114 if (is_standalone)
then
3118 do lvl = max_lvl, min_lvl+1, -1
3120 call smooth_boxes(mg, lvl, mg%n_cycle_down)
3125 call update_coarse(mg, lvl)
3130 if (.not. all(mg%boxes(mg%lvls(min_lvl)%ids)%rank == &
3131 mg%boxes(mg%lvls(min_lvl)%ids(1))%rank))
then
3132 error stop
"Multiple CPUs for coarse grid (not implemented yet)"
3135 init_res = max_residual_lvl(mg, min_lvl)
3136 do i = 1, mg%max_coarse_cycles
3137 call smooth_boxes(mg, min_lvl, mg%n_cycle_up+mg%n_cycle_down)
3138 res = max_residual_lvl(mg, min_lvl)
3139 if (res < mg%residual_coarse_rel * init_res .or. &
3140 res < mg%residual_coarse_abs)
exit
3145 do lvl = min_lvl+1, max_lvl
3149 call correct_children(mg, lvl-1)
3156 call smooth_boxes(mg, lvl, mg%n_cycle_up)
3159 if (
present(max_res))
then
3161 do lvl = min_lvl, max_lvl
3162 res = max_residual_lvl(mg, lvl)
3163 init_res = max(res, init_res)
3165 call mpi_allreduce(init_res, max_res, 1, &
3166 mpi_double, mpi_max, mg%comm, ierr)
3170 if (mg%subtract_mean)
then
3174 if (is_standalone) &
3180 type(
mg_t),
intent(inout) :: mg
3181 integer,
intent(in) :: iv
3182 logical,
intent(in) :: include_ghostcells
3183 integer :: i, id, lvl, nc, ierr
3184 real(dp) :: sum_iv, mean_iv, volume
3188 call mpi_allreduce(sum_iv, mean_iv, 1, &
3189 mpi_double, mpi_sum, mg%comm, ierr)
3192 volume = nc**2 * product(mg%dr(:, 1)) *
size(mg%lvls(1)%ids)
3193 mean_iv = mean_iv / volume
3195 do lvl = mg%lowest_lvl, mg%highest_lvl
3196 nc = mg%box_size_lvl(lvl)
3198 do i = 1,
size(mg%lvls(lvl)%my_ids)
3199 id = mg%lvls(lvl)%my_ids(i)
3200 if (include_ghostcells)
then
3201 mg%boxes(id)%cc(:, :, iv) = &
3202 mg%boxes(id)%cc(:, :, iv) - mean_iv
3204 mg%boxes(id)%cc(1:nc, 1:nc, iv) = &
3205 mg%boxes(id)%cc(1:nc, 1:nc, iv) - mean_iv
3212 type(
mg_t),
intent(in) :: mg
3213 integer,
intent(in) :: iv
3214 integer :: lvl, i, id, nc
3218 do lvl = 1, mg%highest_lvl
3219 nc = mg%box_size_lvl(lvl)
3220 w = product(mg%dr(:, lvl))
3221 do i = 1,
size(mg%lvls(lvl)%my_leaves)
3222 id = mg%lvls(lvl)%my_leaves(i)
3224 sum(mg%boxes(id)%cc(1:nc, 1:nc, iv))
3229 real(
dp) function max_residual_lvl(mg, lvl)
3230 type(
mg_t),
intent(inout) :: mg
3231 integer,
intent(in) :: lvl
3232 integer :: i, id, nc
3235 nc = mg%box_size_lvl(lvl)
3236 max_residual_lvl = 0.0_dp
3238 do i = 1,
size(mg%lvls(lvl)%my_ids)
3239 id = mg%lvls(lvl)%my_ids(i)
3240 call residual_box(mg, id, nc)
3241 res = maxval(abs(mg%boxes(id)%cc(1:nc, 1:nc,
mg_ires)))
3242 max_residual_lvl = max(max_residual_lvl, res)
3244 end function max_residual_lvl
3280 subroutine update_coarse(mg, lvl)
3281 type(
mg_t),
intent(inout) :: mg
3282 integer,
intent(in) :: lvl
3283 integer :: i, id, nc, nc_c
3285 nc = mg%box_size_lvl(lvl)
3286 nc_c = mg%box_size_lvl(lvl-1)
3289 do i = 1,
size(mg%lvls(lvl)%my_ids)
3290 id = mg%lvls(lvl)%my_ids(i)
3291 call residual_box(mg, id, nc)
3302 do i = 1,
size(mg%lvls(lvl-1)%my_parents)
3303 id = mg%lvls(lvl-1)%my_parents(i)
3306 call mg%box_op(mg, id, nc_c,
mg_irhs)
3309 mg%boxes(id)%cc(1:nc_c, 1:nc_c,
mg_irhs) = &
3310 mg%boxes(id)%cc(1:nc_c, 1:nc_c,
mg_irhs) + &
3311 mg%boxes(id)%cc(1:nc_c, 1:nc_c,
mg_ires)
3314 mg%boxes(id)%cc(:, :,
mg_iold) = &
3315 mg%boxes(id)%cc(:, :,
mg_iphi)
3317 end subroutine update_coarse
3320 subroutine correct_children(mg, lvl)
3321 type(
mg_t),
intent(inout) :: mg
3322 integer,
intent(in) :: lvl
3325 do i = 1,
size(mg%lvls(lvl)%my_parents)
3326 id = mg%lvls(lvl)%my_parents(i)
3329 mg%boxes(id)%cc(:, :,
mg_ires) = &
3330 mg%boxes(id)%cc(:, :,
mg_iphi) - &
3331 mg%boxes(id)%cc(:, :,
mg_iold)
3335 end subroutine correct_children
3337 subroutine smooth_boxes(mg, lvl, n_cycle)
3338 type(
mg_t),
intent(inout) :: mg
3339 integer,
intent(in) :: lvl
3340 integer,
intent(in) :: n_cycle
3341 integer :: n, i, id, nc
3343 nc = mg%box_size_lvl(lvl)
3345 do n = 1, n_cycle * mg%n_smoother_substeps
3347 do i = 1,
size(mg%lvls(lvl)%my_ids)
3348 id = mg%lvls(lvl)%my_ids(i)
3349 call mg%box_smoother(mg, id, nc, n)
3357 end subroutine smooth_boxes
3359 subroutine residual_box(mg, id, nc)
3360 type(
mg_t),
intent(inout) :: mg
3361 integer,
intent(in) :: id
3362 integer,
intent(in) :: nc
3364 call mg%box_op(mg, id, nc,
mg_ires)
3366 mg%boxes(id)%cc(1:nc, 1:nc,
mg_ires) = &
3367 mg%boxes(id)%cc(1:nc, 1:nc,
mg_irhs) &
3368 - mg%boxes(id)%cc(1:nc, 1:nc,
mg_ires)
3369 end subroutine residual_box
3373 type(
mg_t),
intent(inout) :: mg
3374 integer,
intent(in) :: i_out
3375 procedure(mg_box_op),
optional :: op
3376 integer :: lvl, i, id, nc
3378 do lvl = mg%lowest_lvl, mg%highest_lvl
3379 nc = mg%box_size_lvl(lvl)
3380 do i = 1,
size(mg%lvls(lvl)%my_ids)
3381 id = mg%lvls(lvl)%my_ids(i)
3382 if (
present(op))
then
3383 call op(mg, id, nc, i_out)
3385 call mg%box_op(mg, id, nc, i_out)
3395 type(
mg_t),
intent(inout) :: mg
3396 integer,
intent(out) :: n_send(0:mg%n_cpu-1)
3397 integer,
intent(out) :: n_recv(0:mg%n_cpu-1)
3398 integer,
intent(out) :: dsize
3399 integer :: n_out(0:mg%n_cpu-1, mg%first_normal_lvl:mg%highest_lvl)
3400 integer :: n_in(0:mg%n_cpu-1, mg%first_normal_lvl:mg%highest_lvl)
3401 integer :: lvl, i, id, p_id, p_rank
3402 integer :: i_c, c_id, c_rank, min_lvl
3406 min_lvl = max(mg%lowest_lvl+1, mg%first_normal_lvl)
3408 do lvl = min_lvl, mg%highest_lvl
3410 do i = 1,
size(mg%lvls(lvl-1)%my_parents)
3411 id = mg%lvls(lvl-1)%my_parents(i)
3413 c_id = mg%boxes(id)%children(i_c)
3416 c_rank = mg%boxes(c_id)%rank
3417 if (c_rank /= mg%my_rank)
then
3418 n_in(c_rank, lvl) = n_in(c_rank, lvl) + 1
3425 do i = 1,
size(mg%lvls(lvl)%my_ids)
3426 id = mg%lvls(lvl)%my_ids(i)
3428 p_id = mg%boxes(id)%parent
3429 p_rank = mg%boxes(p_id)%rank
3430 if (p_rank /= mg%my_rank)
then
3431 n_out(p_rank, lvl) = n_out(p_rank, lvl) + 1
3437 allocate(mg%comm_restrict%n_send(0:mg%n_cpu-1, &
3438 mg%first_normal_lvl:mg%highest_lvl))
3439 allocate(mg%comm_restrict%n_recv(0:mg%n_cpu-1, &
3440 mg%first_normal_lvl:mg%highest_lvl))
3441 mg%comm_restrict%n_send = n_out
3442 mg%comm_restrict%n_recv = n_in
3444 dsize = (mg%box_size/2)**2
3445 n_send = maxval(n_out, dim=2)
3446 n_recv = maxval(n_in, dim=2)
3451 type(
mg_t),
intent(inout) :: mg
3452 integer,
intent(in) :: iv
3455 do lvl = mg%highest_lvl, mg%lowest_lvl+1, -1
3463 type(
mg_t),
intent(inout) :: mg
3464 integer,
intent(in) :: iv
3465 integer,
intent(in) :: lvl
3466 integer :: i, id, dsize, nc
3468 if (lvl <= mg%lowest_lvl) error stop
"cannot restrict lvl <= lowest_lvl"
3470 nc = mg%box_size_lvl(lvl)
3472 if (lvl >= mg%first_normal_lvl)
then
3475 mg%buf(:)%i_send = 0
3478 do i = 1,
size(mg%lvls(lvl)%my_ids)
3479 id = mg%lvls(lvl)%my_ids(i)
3480 call restrict_set_buffer(mg, id, iv)
3483 mg%buf(:)%i_recv = mg%comm_restrict%n_recv(:, lvl) * dsize
3485 mg%buf(:)%i_recv = 0
3488 do i = 1,
size(mg%lvls(lvl-1)%my_parents)
3489 id = mg%lvls(lvl-1)%my_parents(i)
3490 call restrict_onto(mg, id, nc, iv)
3494 subroutine restrict_set_buffer(mg, id, iv)
3495 type(
mg_t),
intent(inout) :: mg
3496 integer,
intent(in) :: id
3497 integer,
intent(in) :: iv
3498 integer :: i, j, n, hnc, p_id, p_rank
3499 real(
dp) :: tmp(mg%box_size/2, mg%box_size/2)
3502 p_id = mg%boxes(id)%parent
3503 p_rank = mg%boxes(p_id)%rank
3505 if (p_rank /= mg%my_rank)
then
3508 tmp(i, j) = 0.25_dp * &
3509 sum(mg%boxes(id)%cc(2*i-1:2*i, 2*j-1:2*j, iv))
3515 i = mg%buf(p_rank)%i_send
3516 mg%buf(p_rank)%send(i+1:i+n) = pack(tmp, .true.)
3517 mg%buf(p_rank)%i_send = mg%buf(p_rank)%i_send + n
3520 i = mg%buf(p_rank)%i_ix
3523 mg%buf(p_rank)%i_ix = mg%buf(p_rank)%i_ix + 1
3525 end subroutine restrict_set_buffer
3527 subroutine restrict_onto(mg, id, nc, iv)
3528 type(
mg_t),
intent(inout) :: mg
3529 integer,
intent(in) :: id
3530 integer,
intent(in) :: nc
3531 integer,
intent(in) :: iv
3532 integer :: i, j, hnc, dsize, i_c, c_id
3533 integer :: c_rank, dix(2)
3539 c_id = mg%boxes(id)%children(i_c)
3541 c_rank = mg%boxes(c_id)%rank
3544 if (c_rank == mg%my_rank)
then
3545 do j=1, hnc;
do i=1, hnc
3546 mg%boxes(id)%cc(dix(1)+i, dix(2)+j, iv) = 0.25_dp * &
3547 sum(mg%boxes(c_id)%cc(2*i-1:2*i, 2*j-1:2*j, iv))
3550 i = mg%buf(c_rank)%i_recv
3551 mg%boxes(id)%cc(dix(1)+1:dix(1)+hnc, &
3552 dix(2)+1:dix(2)+hnc, iv) = &
3553 reshape(mg%buf(c_rank)%recv(i+1:i+dsize), [hnc, hnc])
3554 mg%buf(c_rank)%i_recv = mg%buf(c_rank)%i_recv + dsize
3558 end subroutine restrict_onto
3562 Subroutine i_mrgrnk (XDONT, IRNGT)
3569 Integer,
Dimension (:),
Intent (In) :: xdont
3570 Integer,
Dimension (:),
Intent (Out) :: irngt
3572 Integer :: xvala, xvalb
3574 Integer,
Dimension (SIZE(IRNGT)) :: jwrkt
3575 Integer :: lmtna, lmtnc, irng1, irng2
3576 Integer :: nval, iind, iwrkd, iwrk, iwrkf, jinda, iinda, iindb
3578 nval = min(
SIZE(xdont),
SIZE(irngt))
3591 Do iind = 2, nval, 2
3592 If (xdont(iind-1) <= xdont(iind))
Then
3593 irngt(iind-1) = iind - 1
3596 irngt(iind-1) = iind
3597 irngt(iind) = iind - 1
3600 If (modulo(nval, 2) /= 0)
Then
3617 Do iwrkd = 0, nval - 1, 4
3618 If ((iwrkd+4) > nval)
Then
3619 If ((iwrkd+2) >= nval)
Exit
3623 If (xdont(irngt(iwrkd+2)) <= xdont(irngt(iwrkd+3)))
Exit
3627 If (xdont(irngt(iwrkd+1)) <= xdont(irngt(iwrkd+3)))
Then
3628 irng2 = irngt(iwrkd+2)
3629 irngt(iwrkd+2) = irngt(iwrkd+3)
3630 irngt(iwrkd+3) = irng2
3635 irng1 = irngt(iwrkd+1)
3636 irngt(iwrkd+1) = irngt(iwrkd+3)
3637 irngt(iwrkd+3) = irngt(iwrkd+2)
3638 irngt(iwrkd+2) = irng1
3645 If (xdont(irngt(iwrkd+2)) <= xdont(irngt(iwrkd+3))) cycle
3649 If (xdont(irngt(iwrkd+1)) <= xdont(irngt(iwrkd+3)))
Then
3650 irng2 = irngt(iwrkd+2)
3651 irngt(iwrkd+2) = irngt(iwrkd+3)
3652 If (xdont(irng2) <= xdont(irngt(iwrkd+4)))
Then
3654 irngt(iwrkd+3) = irng2
3657 irngt(iwrkd+3) = irngt(iwrkd+4)
3658 irngt(iwrkd+4) = irng2
3664 irng1 = irngt(iwrkd+1)
3665 irng2 = irngt(iwrkd+2)
3666 irngt(iwrkd+1) = irngt(iwrkd+3)
3667 If (xdont(irng1) <= xdont(irngt(iwrkd+4)))
Then
3668 irngt(iwrkd+2) = irng1
3669 If (xdont(irng2) <= xdont(irngt(iwrkd+4)))
Then
3671 irngt(iwrkd+3) = irng2
3674 irngt(iwrkd+3) = irngt(iwrkd+4)
3675 irngt(iwrkd+4) = irng2
3679 irngt(iwrkd+2) = irngt(iwrkd+4)
3680 irngt(iwrkd+3) = irng1
3681 irngt(iwrkd+4) = irng2
3696 If (lmtna >= nval)
Exit
3705 jinda = iwrkf + lmtna
3706 iwrkf = iwrkf + lmtnc
3707 If (iwrkf >= nval)
Then
3708 If (jinda >= nval)
Exit
3724 jwrkt(1:lmtna) = irngt(iwrkd:jinda)
3726 xvala = xdont(jwrkt(iinda))
3727 xvalb = xdont(irngt(iindb))
3734 If (xvala > xvalb)
Then
3735 irngt(iwrk) = irngt(iindb)
3737 If (iindb > iwrkf)
Then
3739 irngt(iwrk+1:iwrkf) = jwrkt(iinda:lmtna)
3742 xvalb = xdont(irngt(iindb))
3744 irngt(iwrk) = jwrkt(iinda)
3746 If (iinda > lmtna) exit
3747 xvala = xdont(jwrkt(iinda))
3760 End Subroutine i_mrgrnk
3765 type(
mg_t),
intent(inout) :: mg
3767 if (mg%n_extra_vars == 0 .and. mg%is_allocated)
then
3768 error stop
"ahelmholtz_set_methods: mg%n_extra_vars == 0"
3770 mg%n_extra_vars = max(2, mg%n_extra_vars)
3782 select case (mg%geometry_type)
3784 mg%box_op => box_ahelmh
3786 select case (mg%smoother_type)
3788 mg%box_smoother => box_gs_ahelmh
3790 error stop
"ahelmholtz_set_methods: unsupported smoother type"
3793 error stop
"ahelmholtz_set_methods: unsupported geometry"
3799 real(
dp),
intent(in) :: lambda
3802 error stop
"ahelmholtz_set_lambda: lambda < 0 not allowed"
3808 subroutine box_gs_ahelmh(mg, id, nc, redblack_cntr)
3809 type(
mg_t),
intent(inout) :: mg
3810 integer,
intent(in) :: id
3811 integer,
intent(in) :: nc
3812 integer,
intent(in) :: redblack_cntr
3813 integer :: i, j, i0, di
3815 real(
dp) :: idr2(2*2), u(2*2)
3816 real(
dp) :: a0(2*2), a(2*2), c(2*2)
3819 idr2(1:2*2:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
3820 idr2(2:2*2:2) = idr2(1:2*2:2)
3832 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
3838 i0 = 2 - iand(ieor(redblack_cntr, j), 1)
3841 a0(1:2) = cc(i, j, i_eps1)
3842 a0(3:4) = cc(i, j, i_eps2)
3843 u(1:2) = cc(i-1:i+1:2, j, n)
3844 a(1:2) = cc(i-1:i+1:2, j, i_eps1)
3845 u(3:4) = cc(i, j-1:j+1:2, n)
3846 a(3:4) = cc(i, j-1:j+1:2, i_eps2)
3847 c(:) = 2 * a0(:) * a(:) / (a0(:) + a(:)) * idr2
3850 (sum(c(:) * u(:)) - cc(i, j,
mg_irhs)) / &
3855 end subroutine box_gs_ahelmh
3858 subroutine box_ahelmh(mg, id, nc, i_out)
3859 type(
mg_t),
intent(inout) :: mg
3860 integer,
intent(in) :: id
3861 integer,
intent(in) :: nc
3862 integer,
intent(in) :: i_out
3864 real(
dp) :: idr2(2*2), a0(2*2), u0, u(2*2), a(2*2)
3867 idr2(1:2*2:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
3868 idr2(2:2*2:2) = idr2(1:2*2:2)
3870 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
3875 a0(1:2) = cc(i, j, i_eps1)
3876 a0(3:4) = cc(i, j, i_eps2)
3877 a(1:2) = cc(i-1:i+1:2, j, i_eps1)
3878 a(3:4) = cc(i, j-1:j+1:2, i_eps2)
3880 u(1:2) = cc(i-1:i+1:2, j, n)
3881 u(3:4) = cc(i, j-1:j+1:2, n)
3883 cc(i, j, i_out) = sum(2 * idr2 * &
3884 a0(:)*a(:)/(a0(:) + a(:)) * (u(:) - u0)) - &
3889 end subroutine box_ahelmh
To fill ghost cells near physical boundaries.
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 ...
subroutine, public mg_fas_vcycle(mg, highest_lvl, max_res, standalone)
Perform FAS V-cycle (full approximation scheme).
subroutine, public vhelmholtz_set_methods(mg)
subroutine, public mg_ghost_cell_buffer_size(mg, n_send, n_recv, dsize)
Specify minimum buffer size (per process) for communication.
integer, parameter, public mg_num_children
subroutine, public mg_timer_end(timer)
subroutine, public mg_restrict(mg, iv)
Restrict all levels.
integer, parameter, public mg_vhelmholtz
Indicates a variable-coefficient Helmholtz equation.
integer, parameter, public mg_iveps1
Indexes of anisotropic variable coefficients.
integer, parameter, public mg_ahelmholtz
Indicates a anisotropic-coefficient Helmholtz equation.
integer, parameter, public mg_vlaplacian
Indicates a variable-coefficient Laplacian.
integer, dimension(2, 4), parameter, public mg_neighb_dix
integer, parameter, public mg_helmholtz
Indicates a constant-coefficient Helmholtz equation.
integer, parameter, public mg_physical_boundary
Special value that indicates there is a physical boundary.
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_get_face_coords(box, nb, nc, x)
Get coordinates at the face of a box.
subroutine, public sort_and_transfer_buffers(mg, dsize)
integer, parameter, public dp
Type of reals.
pure integer function, public mg_highest_uniform_lvl(mg)
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...
integer, parameter, public mg_ndim
Problem dimension.
subroutine, public mg_prolong_buffer_size(mg, n_send, n_recv, dsize)
Specify minimum buffer size (per process) for communication.
subroutine, public diffusion_solve_acoeff(mg, dt, order, max_res)
Solve a diffusion equation implicitly, assuming anisotropic diffusion coefficient which has been stor...
subroutine, public mg_fas_fmg(mg, have_guess, max_res)
Perform FAS-FMG cycle (full approximation scheme, full multigrid).
integer, parameter, public mg_ires
Index of residual.
integer, parameter, public mg_neighb_highy
subroutine, public mg_set_neighbors_lvl(mg, lvl)
integer, parameter, public mg_iveps3
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 helmholtz_set_methods(mg)
integer, parameter, public mg_bc_continuous
Value to indicate a continuous boundary condition.
subroutine, public mg_timers_show(mg)
integer, parameter, public mg_iphi
Index of solution.
subroutine, public mg_add_children(mg, id)
subroutine, public mg_prolong(mg, lvl, iv, iv_to, method, add)
Prolong variable iv from lvl to variable iv_to at lvl+1.
integer, dimension(4), parameter, public mg_neighb_dim
integer, dimension(2, 4), parameter, public mg_child_dix
integer, parameter, public mg_spherical
Spherical coordinate system.
subroutine, public mg_timer_start(timer)
integer(i8) function, public mg_number_of_unknowns(mg)
Determine total number of unknowns (on leaves)
integer, parameter, public mg_neighb_highx
integer, parameter, public mg_bc_dirichlet
Value to indicate a Dirichlet boundary condition.
subroutine, public helmholtz_set_lambda(lambda)
integer, parameter, public mg_laplacian
Indicates a standard Laplacian.
integer, dimension(4), parameter, public mg_neighb_rev
subroutine, public ahelmholtz_set_lambda(lambda)
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_lvl_hi
Maximum allowed grid level.
integer, dimension(4), parameter, public mg_neighb_high_pm
integer, parameter, public mg_bc_neumann
Value to indicate a Neumann boundary condition.
integer, parameter, public mg_irhs
Index of right-hand side.
logical, dimension(2, 4), parameter, public mg_child_low
integer, parameter, public mg_iveps2
elemental logical function, public mg_has_children(box)
Return .true. if a box has children.
subroutine sort_sendbuf(gc, dsize)
Sort send buffers according to the idbuf array.
subroutine, public diffusion_solve_vcoeff(mg, dt, order, max_res)
Solve a diffusion equation implicitly, assuming a variable diffusion coefficient which has been store...
integer, parameter, public mg_cylindrical
Cylindrical coordinate system.
real(dp), public, protected vhelmholtz_lambda
Module for implicitly solving diffusion equations.
subroutine, public mg_restrict_buffer_size(mg, n_send, n_recv, dsize)
Specify minimum buffer size (per process) for communication.
integer, parameter, public mg_smoother_jacobi
subroutine, public laplacian_set_methods(mg)
subroutine, public mg_deallocate_storage(mg)
Deallocate all allocatable arrays.
subroutine, public ahelmholtz_set_methods(mg)
subroutine, public mg_load_balance(mg)
Load balance all boxes in the multigrid tree. Compared to mg_load_balance_simple, this method does a ...
subroutine, public mg_fill_ghost_cells_lvl(mg, lvl, iv)
Fill ghost cells at a grid level.
subroutine, public vhelmholtz_set_lambda(lambda)
subroutine, public mg_set_next_level_ids(mg, lvl)
integer, parameter, public mg_num_neighbors
integer, parameter, public mg_cartesian
Cartesian coordinate system.
integer, dimension(2, 4), parameter, public mg_child_adj_nb
subroutine, public mg_set_refinement_boundaries(boxes, level)
Create a list of refinement boundaries (from the coarse side)
integer, parameter, public mg_neighb_lowx
integer, parameter, public mg_neighb_lowy
integer, parameter, public mg_num_vars
Number of predefined multigrid variables.
subroutine subtract_mean(mg, iv, include_ghostcells)
integer, parameter, public mg_lvl_lo
Minimum allowed grid level.
subroutine, public mg_set_leaves_parents(boxes, level)
Create a list of leaves and a list of parents for a level.
subroutine, public mg_load_balance_parents(mg)
Load balance the parents (non-leafs). Assign them to the rank that has most children.
subroutine, public mg_fill_ghost_cells(mg, iv)
Fill ghost cells at all grid levels.
subroutine, public mg_restrict_lvl(mg, iv, lvl)
Restrict from lvl to lvl-1.
subroutine, public vlaplacian_set_methods(mg)
integer, parameter, public mg_iveps
Index of the variable coefficient (at cell centers)
subroutine, public mg_allocate_storage(mg)
Allocate communication buffers and local boxes for a tree that has already been created.
real(dp) function get_sum(mg, iv)
subroutine, public mg_build_rectangle(mg, domain_size, box_size, dx, r_min, periodic, n_finer)
subroutine, public mg_apply_op(mg, i_out, op)
Apply operator to the tree and store in variable i_out.
integer, parameter, public i8
Type for 64-bit integers.
subroutine, public mg_set_methods(mg)
integer, parameter, public mg_max_num_vars
Maximum number of variables.
pure integer function, dimension(2), 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_iold
Index of previous solution (used for correction)
logical, dimension(4), parameter, public mg_neighb_low
integer, parameter, public mg_max_timers
Maximum number of timers to use.
integer, parameter, public mg_smoother_gs
real(dp), public, protected helmholtz_lambda
Module for load balancing a tree (that already has been constructed). The load balancing determines w...
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...
subroutine, public mg_phi_bc_store(mg)
Store boundary conditions for the solution variable, this can speed up calculations if the same bound...
integer, dimension(4, 2), parameter, public mg_child_rev
integer, parameter, public mg_no_box
Special value that indicates there is no box.
integer, parameter, public mg_smoother_gsrb
integer function, public mg_add_timer(mg, name)
Buffer type (one is used for each pair of communicating processes)
Lists of blocks per refinement level.