30 integer,
parameter,
public ::
dp = kind(0.0d0)
33 integer,
parameter,
public ::
i8 = selected_int_kind(18)
111 integer,
parameter,
public ::
mg_child_dix(1, 2) = reshape([0,1], [1,2])
113 integer,
parameter,
public ::
mg_child_rev(2, 1) = reshape([2,1], [2,1])
117 logical,
parameter,
public ::
mg_child_low(1, 2) = reshape([.true., .false.], [1, 2])
138 integer,
allocatable :: leaves(:)
139 integer,
allocatable :: parents(:)
140 integer,
allocatable :: ref_bnds(:)
141 integer,
allocatable :: ids(:)
142 integer,
allocatable :: my_leaves(:)
143 integer,
allocatable :: my_parents(:)
144 integer,
allocatable :: my_ref_bnds(:)
145 integer,
allocatable :: my_ids(:)
155 integer :: children(2**1)
156 integer :: neighbors(2*1)
160 real(
dp),
allocatable :: cc(:, :)
168 integer,
allocatable :: ix(:)
169 real(
dp),
allocatable :: send(:)
170 real(
dp),
allocatable :: recv(:)
174 integer,
allocatable :: n_send(:, :)
175 integer,
allocatable :: n_recv(:, :)
180 real(
dp) :: bc_value = 0.0_dp
182 procedure(
mg_subr_bc),
pointer,
nopass :: boundary_cond => null()
184 procedure(mg_subr_rb),
pointer,
nopass :: refinement_bnd => null()
188 character(len=20) :: name
189 real(
dp) :: t = 0.0_dp
195 logical :: tree_created = .false.
197 logical :: is_allocated = .false.
199 integer :: n_extra_vars = 0
203 integer :: n_cpu = -1
205 integer :: my_rank = -1
207 integer :: box_size = -1
209 integer :: highest_lvl = -1
211 integer :: lowest_lvl = -1
214 integer :: first_normal_lvl = -1
216 integer :: n_boxes = 0
241 logical :: phi_bc_data_stored = .false.
244 logical :: periodic(1) = .false.
259 integer :: n_smoother_substeps = 1
261 integer :: n_cycle_down = 2
263 integer :: n_cycle_up = 2
265 integer :: max_coarse_cycles = 1000
266 integer :: coarsest_grid(1) = 2
268 real(
dp) :: residual_coarse_abs = 1e-8_dp
270 real(
dp) :: residual_coarse_rel = 1e-8_dp
273 procedure(mg_box_op),
pointer,
nopass :: box_op => null()
276 procedure(mg_box_gsrb),
pointer,
nopass :: box_smoother => null()
279 procedure(mg_box_prolong),
pointer,
nopass :: box_prolong => null()
282 integer :: n_timers = 0
291 type(mg_box_t),
intent(in) :: box
292 integer,
intent(in) :: nc
293 integer,
intent(in) :: iv
294 integer,
intent(in) :: nb
295 integer,
intent(out) :: bc_type
297 real(dp),
intent(out) :: bc(1)
301 subroutine mg_subr_rb(box, nc, iv, nb, cgc)
303 type(mg_box_t),
intent(inout) :: box
304 integer,
intent(in) :: nc
305 integer,
intent(in) :: iv
306 integer,
intent(in) :: nb
308 real(dp),
intent(in) :: cgc(1)
309 end subroutine mg_subr_rb
312 subroutine mg_box_op(mg, id, nc, i_out)
314 type(mg_t),
intent(inout) :: mg
315 integer,
intent(in) :: id
316 integer,
intent(in) :: nc
317 integer,
intent(in) :: i_out
318 end subroutine mg_box_op
321 subroutine mg_box_gsrb(mg, id, nc, redblack_cntr)
323 type(mg_t),
intent(inout) :: mg
324 integer,
intent(in) :: id
325 integer,
intent(in) :: nc
326 integer,
intent(in) :: redblack_cntr
327 end subroutine mg_box_gsrb
330 subroutine mg_box_prolong(mg, p_id, dix, nc, iv, fine)
332 type(mg_t),
intent(inout) :: mg
333 integer,
intent(in) :: p_id
334 integer,
intent(in) :: dix(1)
335 integer,
intent(in) :: nc
336 integer,
intent(in) :: iv
337 real(dp),
intent(out) :: fine(nc)
338 end subroutine mg_box_prolong
345 public :: mg_box_gsrb
346 public :: mg_box_prolong
450 integer :: timer_total_vcycle = -1
451 integer :: timer_total_fmg = -1
452 integer :: timer_smoother = -1
453 integer :: timer_smoother_gc = -1
454 integer :: timer_coarse = -1
455 integer :: timer_correct = -1
456 integer :: timer_update_coarse = -1
473 Integer,
Parameter :: kdp = selected_real_kind(15)
478 module procedure i_mrgrnk
508 integer,
intent(in) :: ix(1)
517 type(
mg_t),
intent(in) :: mg
518 integer,
intent(in) :: id
519 integer :: ix_offset(1)
521 if (mg%boxes(id)%lvl <= mg%first_normal_lvl)
then
524 ix_offset = iand(mg%boxes(id)%ix-1, 1) * &
525 ishft(mg%box_size, -1)
530 type(
mg_t),
intent(in) :: mg
533 do lvl = mg%first_normal_lvl, mg%highest_lvl-1
535 if (
size(mg%lvls(lvl)%leaves) /= 0 .and. &
536 size(mg%lvls(lvl)%parents) /= 0)
exit
543 type(
mg_t),
intent(in) :: mg
545 integer(i8) :: n_unknowns
548 do lvl = mg%first_normal_lvl, mg%highest_lvl
549 n_unknowns = n_unknowns +
size(mg%lvls(lvl)%leaves)
551 n_unknowns = n_unknowns * int(mg%box_size**3,
i8)
557 integer,
intent(in) :: nb
558 integer,
intent(in) :: nc
559 real(
dp),
intent(out) :: x(2)
568 rmin(nb_dim) = rmin(nb_dim) + box%dr(nb_dim) * nc
572 x(2) = rmin(1) + box%dr(1) * nc
576 type(
mg_t),
intent(inout) :: mg
577 character(len=*),
intent(in) :: name
579 mg%n_timers = mg%n_timers + 1
587 timer%t0 = mpi_wtime()
593 timer%t = timer%t + mpi_wtime() - timer%t0
598 type(
mg_t),
intent(in) :: mg
600 real(
dp) :: tmin(mg%n_timers)
601 real(
dp) :: tmax(mg%n_timers)
603 call mpi_reduce(mg%timers(1:mg%n_timers)%t, tmin, mg%n_timers, &
604 mpi_double, mpi_min, 0, mg%comm, ierr)
605 call mpi_reduce(mg%timers(1:mg%n_timers)%t, tmax, mg%n_timers, &
606 mpi_double, mpi_max, 0, mg%comm, ierr)
608 if (mg%my_rank == 0)
then
609 write(*,
"(A20,2A16)")
"name ",
"min(s)",
"max(s)"
610 do n = 1, mg%n_timers
611 write(*,
"(A20,2F16.6)") mg%timers(n)%name, &
621 type(
mg_t),
intent(inout) :: mg
624 if (.not. mg%is_allocated) &
625 error stop
"deallocate_storage: tree is not allocated"
630 deallocate(mg%comm_restrict%n_send)
631 deallocate(mg%comm_restrict%n_recv)
633 deallocate(mg%comm_prolong%n_send)
634 deallocate(mg%comm_prolong%n_recv)
636 deallocate(mg%comm_ghostcell%n_send)
637 deallocate(mg%comm_ghostcell%n_recv)
639 do lvl = mg%lowest_lvl, mg%highest_lvl
640 deallocate(mg%lvls(lvl)%ids)
641 deallocate(mg%lvls(lvl)%leaves)
642 deallocate(mg%lvls(lvl)%parents)
643 deallocate(mg%lvls(lvl)%ref_bnds)
644 deallocate(mg%lvls(lvl)%my_ids)
645 deallocate(mg%lvls(lvl)%my_leaves)
646 deallocate(mg%lvls(lvl)%my_parents)
647 deallocate(mg%lvls(lvl)%my_ref_bnds)
650 mg%is_allocated = .false.
652 mg%phi_bc_data_stored = .false.
659 type(
mg_t),
intent(inout) :: mg
660 integer :: i, id, lvl, nc
661 integer :: n_send(0:mg%n_cpu-1, 3)
662 integer :: n_recv(0:mg%n_cpu-1, 3)
664 integer :: n_in, n_out, n_id
666 if (.not. mg%tree_created) &
667 error stop
"allocate_storage: tree is not yet created"
669 if (mg%is_allocated) &
670 error stop
"allocate_storage: tree is already allocated"
672 do lvl = mg%lowest_lvl, mg%highest_lvl
673 nc = mg%box_size_lvl(lvl)
674 do i = 1,
size(mg%lvls(lvl)%my_ids)
675 id = mg%lvls(lvl)%my_ids(i)
676 allocate(mg%boxes(id)%cc(0:nc+1, &
680 mg%boxes(id)%cc(:, :) = 0.0_dp
684 allocate(mg%buf(0:mg%n_cpu-1))
687 n_recv(:, 1), dsize(1))
689 n_recv(:, 2), dsize(2))
691 n_recv(:, 3), dsize(3))
694 n_out = maxval(n_send(i, :) * dsize(:))
695 n_in = maxval(n_recv(i, :) * dsize(:))
696 n_id = maxval(n_send(i, :))
697 allocate(mg%buf(i)%send(n_out))
698 allocate(mg%buf(i)%recv(n_in))
699 allocate(mg%buf(i)%ix(n_id))
702 mg%is_allocated = .true.
712 type(
mg_t),
intent(inout) :: mg
713 real(
dp),
intent(in) :: dt
714 real(
dp),
intent(in) :: diffusion_coeff
715 integer,
intent(in) :: order
716 real(
dp),
intent(in) :: max_res
717 integer,
parameter :: max_its = 10
727 call set_rhs(mg, -1/(dt * diffusion_coeff), 0.0_dp)
732 call set_rhs(mg, -2/(dt * diffusion_coeff), -1.0_dp)
734 error stop
"diffusion_solve: order should be 1 or 2"
742 if (res <= max_res)
exit
746 if (n == max_its + 1)
then
747 if (mg%my_rank == 0) &
748 print *,
"Did you specify boundary conditions correctly?"
749 error stop
"diffusion_solve: no convergence"
759 type(
mg_t),
intent(inout) :: mg
760 real(
dp),
intent(in) :: dt
761 integer,
intent(in) :: order
762 real(
dp),
intent(in) :: max_res
763 integer,
parameter :: max_its = 10
773 call set_rhs(mg, -1/dt, 0.0_dp)
778 call set_rhs(mg, -2/dt, -1.0_dp)
780 error stop
"diffusion_solve: order should be 1 or 2"
788 if (res <= max_res)
exit
792 if (n == max_its + 1)
then
793 if (mg%my_rank == 0)
then
794 print *,
"Did you specify boundary conditions correctly?"
795 print *,
"Or is the variation in diffusion too large?"
797 error stop
"diffusion_solve: no convergence"
808 type(
mg_t),
intent(inout) :: mg
809 real(
dp),
intent(in) :: dt
810 integer,
intent(in) :: order
811 real(
dp),
intent(in) :: max_res
812 integer,
parameter :: max_its = 10
822 call set_rhs(mg, -1/dt, 0.0_dp)
827 call set_rhs(mg, -2/dt, -1.0_dp)
829 error stop
"diffusion_solve: order should be 1 or 2"
837 if (res <= max_res)
exit
841 if (n == max_its + 1)
then
842 if (mg%my_rank == 0)
then
843 print *,
"Did you specify boundary conditions correctly?"
844 print *,
"Or is the variation in diffusion too large?"
846 error stop
"diffusion_solve: no convergence"
850 subroutine set_rhs(mg, f1, f2)
851 type(
mg_t),
intent(inout) :: mg
852 real(
dp),
intent(in) :: f1, f2
853 integer :: lvl, i, id, nc
855 do lvl = 1, mg%highest_lvl
856 nc = mg%box_size_lvl(lvl)
857 do i = 1,
size(mg%lvls(lvl)%my_leaves)
858 id = mg%lvls(lvl)%my_leaves(i)
859 mg%boxes(id)%cc(1:nc,
mg_irhs) = &
860 f1 * mg%boxes(id)%cc(1:nc,
mg_iphi) + &
861 f2 * mg%boxes(id)%cc(1:nc,
mg_irhs)
864 end subroutine set_rhs
869 type(
mg_t),
intent(inout) :: mg
871 if (all(mg%periodic))
then
874 mg%subtract_mean = .true.
877 select case (mg%geometry_type)
881 select case (mg%smoother_type)
885 mg%box_smoother => box_gs_lpl
887 error stop
"laplacian_set_methods: unsupported smoother type"
890 error stop
"laplacian_set_methods: unsupported geometry"
896 subroutine box_gs_lpl(mg, id, nc, redblack_cntr)
897 type(
mg_t),
intent(inout) :: mg
898 integer,
intent(in) :: id
899 integer,
intent(in) :: nc
900 integer,
intent(in) :: redblack_cntr
902 real(
dp) :: idr2(1), fac
905 idr2 = 1/mg%dr(:, mg%boxes(id)%lvl)**2
906 fac = 0.5_dp / sum(idr2)
918 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
919 if (redblack) i0 = 2 - iand(redblack_cntr, 1)
923 idr2(1) * (cc(i+1, n) + cc(i-1, n)) - &
927 end subroutine box_gs_lpl
968 subroutine box_lpl(mg, id, nc, i_out)
969 type(
mg_t),
intent(inout) :: mg
970 integer,
intent(in) :: id
971 integer,
intent(in) :: nc
972 integer,
intent(in) :: i_out
976 idr2 = 1 / mg%dr(:, mg%boxes(id)%lvl)**2
978 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
981 idr2(1) * (cc(i-1, n) + cc(i+1, n) - 2 * cc(i, n))
984 end subroutine box_lpl
990 type(
mg_t),
intent(inout) :: mg
992 if (mg%n_extra_vars == 0 .and. mg%is_allocated)
then
993 error stop
"vhelmholtz_set_methods: mg%n_extra_vars == 0"
995 mg%n_extra_vars = max(1, mg%n_extra_vars)
998 mg%subtract_mean = .false.
1003 mg%bc(:,
mg_iveps)%bc_value = 0.0_dp
1005 select case (mg%geometry_type)
1007 mg%box_op => box_vhelmh
1009 select case (mg%smoother_type)
1011 mg%box_smoother => box_gs_vhelmh
1013 error stop
"vhelmholtz_set_methods: unsupported smoother type"
1016 error stop
"vhelmholtz_set_methods: unsupported geometry"
1022 real(
dp),
intent(in) :: lambda
1025 error stop
"vhelmholtz_set_lambda: lambda < 0 not allowed"
1031 subroutine box_gs_vhelmh(mg, id, nc, redblack_cntr)
1032 type(
mg_t),
intent(inout) :: mg
1033 integer,
intent(in) :: id
1034 integer,
intent(in) :: nc
1035 integer,
intent(in) :: redblack_cntr
1036 integer :: i, i0, di
1038 real(
dp) :: idr2(2*1), u(2*1)
1039 real(
dp) :: a0, a(2*1), c(2*1)
1042 idr2(1:2*1:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1043 idr2(2:2*1:2) = idr2(1:2*1:2)
1055 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1057 if (redblack) i0 = 2 - iand(redblack_cntr, 1)
1061 u(1:2) = cc(i-1:i+1:2, n)
1062 a(1:2) = cc(i-1:i+1:2, i_eps)
1063 c(:) = 2 * a0 * a(:) / (a0 + a(:)) * idr2
1066 (sum(c(:) * u(:)) - cc(i,
mg_irhs)) / &
1070 end subroutine box_gs_vhelmh
1073 subroutine box_vhelmh(mg, id, nc, i_out)
1074 type(
mg_t),
intent(inout) :: mg
1075 integer,
intent(in) :: id
1076 integer,
intent(in) :: nc
1077 integer,
intent(in) :: i_out
1079 real(
dp) :: idr2(2*1), a0, u0, u(2*1), a(2*1)
1082 idr2(1:2*1:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1083 idr2(2:2*1:2) = idr2(1:2*1:2)
1085 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1089 a(1:2) = cc(i-1:i+1:2, i_eps)
1091 u(1:2) = cc(i-1:i+1:2, n)
1093 cc(i, i_out) = sum(2 * idr2 * &
1094 a0*a(:)/(a0 + a(:)) * (u(:) - u0)) - &
1098 end subroutine box_vhelmh
1104 type(
mg_t),
intent(inout) :: mg
1105 integer,
intent(in) :: domain_size(1)
1106 integer,
intent(in) :: box_size
1107 real(
dp),
intent(in) :: dx(1)
1108 real(
dp),
intent(in) :: r_min(1)
1109 logical,
intent(in) :: periodic(1)
1110 integer,
intent(in) :: n_finer
1111 integer :: i, lvl, n, id, nx(1)
1112 integer :: boxes_per_dim(1,
mg_lvl_lo:1)
1113 integer :: periodic_offset(1)
1115 if (modulo(box_size, 2) /= 0) &
1116 error stop
"box_size should be even"
1117 if (any(modulo(domain_size, box_size) /= 0)) &
1118 error stop
"box_size does not divide domain_size"
1120 if (all(periodic))
then
1121 mg%subtract_mean = .true.
1125 mg%box_size = box_size
1126 mg%box_size_lvl(1) = box_size
1127 mg%domain_size_lvl(:, 1) = domain_size
1128 mg%first_normal_lvl = 1
1131 mg%periodic = periodic
1132 boxes_per_dim(:, :) = 0
1133 boxes_per_dim(:, 1) = domain_size / box_size
1138 if (any(modulo(nx, 2) == 1 .or. nx == mg%coarsest_grid .or. &
1139 (mg%box_size_lvl(lvl) == mg%coarsest_grid .and. &
1142 if (all(modulo(nx/mg%box_size_lvl(lvl), 2) == 0))
then
1143 mg%box_size_lvl(lvl-1) = mg%box_size_lvl(lvl)
1144 boxes_per_dim(:, lvl-1) = boxes_per_dim(:, lvl)/2
1145 mg%first_normal_lvl = lvl-1
1147 mg%box_size_lvl(lvl-1) = mg%box_size_lvl(lvl)/2
1148 boxes_per_dim(:, lvl-1) = boxes_per_dim(:, lvl)
1151 mg%dr(:, lvl-1) = mg%dr(:, lvl) * 2
1153 mg%domain_size_lvl(:, lvl-1) = nx
1160 mg%dr(:, lvl) = mg%dr(:, lvl-1) * 0.5_dp
1161 mg%box_size_lvl(lvl) = box_size
1162 mg%domain_size_lvl(:, lvl) = 2 * mg%domain_size_lvl(:, lvl-1)
1165 n = sum(product(boxes_per_dim, dim=1)) + n_finer
1166 allocate(mg%boxes(n))
1169 nx = boxes_per_dim(:, mg%lowest_lvl)
1170 periodic_offset = [nx(1)-1]
1173 mg%n_boxes = mg%n_boxes + 1
1176 mg%boxes(n)%rank = 0
1178 mg%boxes(n)%lvl = mg%lowest_lvl
1179 mg%boxes(n)%ix(:) = [i]
1180 mg%boxes(n)%r_min(:) = r_min + (mg%boxes(n)%ix(:) - 1) * &
1181 mg%box_size_lvl(mg%lowest_lvl) * mg%dr(:, mg%lowest_lvl)
1182 mg%boxes(n)%dr(:) = mg%dr(:, mg%lowest_lvl)
1187 mg%boxes(n)%neighbors(:) = [n-1, n+1]
1190 if(i==1 .and. .not.periodic(1))
then
1193 if(i==1 .and. periodic(1))
then
1194 mg%boxes(n)%neighbors(1) = n + periodic_offset(1)
1196 if(i==nx(1) .and. .not.periodic(1))
then
1199 if(i==nx(1) .and. periodic(1))
then
1200 mg%boxes(n)%neighbors(2) = n - periodic_offset(1)
1221 mg%lvls(mg%lowest_lvl)%ids = [(n, n=1, mg%n_boxes)]
1224 do lvl = mg%lowest_lvl, 0
1225 if (mg%box_size_lvl(lvl+1) == mg%box_size_lvl(lvl))
then
1226 do i = 1,
size(mg%lvls(lvl)%ids)
1227 id = mg%lvls(lvl)%ids(i)
1235 do i = 1,
size(mg%lvls(lvl)%ids)
1236 id = mg%lvls(lvl)%ids(i)
1237 call add_single_child(mg, id,
size(mg%lvls(lvl)%ids))
1248 do lvl = mg%lowest_lvl, 1
1249 if (
allocated(mg%lvls(lvl)%ref_bnds)) &
1250 deallocate(mg%lvls(lvl)%ref_bnds)
1251 allocate(mg%lvls(lvl)%ref_bnds(0))
1254 mg%tree_created = .true.
1258 type(
mg_t),
intent(inout) :: mg
1259 integer,
intent(in) :: lvl
1262 do i = 1,
size(mg%lvls(lvl)%ids)
1263 id = mg%lvls(lvl)%ids(i)
1264 call set_neighbs(mg%boxes, id)
1269 type(
mg_t),
intent(inout) :: mg
1270 integer,
intent(in) :: lvl
1273 if (
allocated(mg%lvls(lvl+1)%ids)) &
1274 deallocate(mg%lvls(lvl+1)%ids)
1277 if (mg%box_size_lvl(lvl+1) == mg%box_size_lvl(lvl))
then
1279 allocate(mg%lvls(lvl+1)%ids(n))
1282 do i = 1,
size(mg%lvls(lvl)%parents)
1283 id = mg%lvls(lvl)%parents(i)
1284 mg%lvls(lvl+1)%ids(n*(i-1)+1:n*i) = mg%boxes(id)%children
1287 n =
size(mg%lvls(lvl)%parents)
1288 allocate(mg%lvls(lvl+1)%ids(n))
1291 do i = 1,
size(mg%lvls(lvl)%parents)
1292 id = mg%lvls(lvl)%parents(i)
1293 mg%lvls(lvl+1)%ids(i) = mg%boxes(id)%children(1)
1300 subroutine set_neighbs(boxes, id)
1301 type(
mg_box_t),
intent(inout) :: boxes(:)
1302 integer,
intent(in) :: id
1303 integer :: nb, nb_id
1306 if (boxes(id)%neighbors(nb) ==
mg_no_box)
then
1307 nb_id = find_neighb(boxes, id, nb)
1309 boxes(id)%neighbors(nb) = nb_id
1314 end subroutine set_neighbs
1317 function find_neighb(boxes, id, nb)
result(nb_id)
1318 type(
mg_box_t),
intent(in) :: boxes(:)
1319 integer,
intent(in) :: id
1320 integer,
intent(in) :: nb
1321 integer :: nb_id, p_id, c_ix, d, old_pid
1323 p_id = boxes(id)%parent
1331 p_id = boxes(p_id)%neighbors(nb)
1336 end function find_neighb
1340 type(
mg_box_t),
intent(in) :: boxes(:)
1341 type(
mg_lvl_t),
intent(inout) :: level
1342 integer :: i, id, i_leaf, i_parent
1343 integer :: n_parents, n_leaves
1346 n_leaves =
size(level%ids) - n_parents
1348 if (.not.
allocated(level%parents))
then
1349 allocate(level%parents(n_parents))
1350 else if (n_parents /=
size(level%parents))
then
1351 deallocate(level%parents)
1352 allocate(level%parents(n_parents))
1355 if (.not.
allocated(level%leaves))
then
1356 allocate(level%leaves(n_leaves))
1357 else if (n_leaves /=
size(level%leaves))
then
1358 deallocate(level%leaves)
1359 allocate(level%leaves(n_leaves))
1364 do i = 1,
size(level%ids)
1367 i_parent = i_parent + 1
1368 level%parents(i_parent) = id
1371 level%leaves(i_leaf) = id
1378 type(
mg_box_t),
intent(in) :: boxes(:)
1379 type(
mg_lvl_t),
intent(inout) :: level
1380 integer,
allocatable :: tmp(:)
1381 integer :: i, id, nb, nb_id, ix
1383 if (
allocated(level%ref_bnds))
deallocate(level%ref_bnds)
1385 if (
size(level%parents) == 0)
then
1387 allocate(level%ref_bnds(0))
1389 allocate(tmp(
size(level%leaves)))
1391 do i = 1,
size(level%leaves)
1392 id = level%leaves(i)
1395 nb_id = boxes(id)%neighbors(nb)
1406 allocate(level%ref_bnds(ix))
1407 level%ref_bnds(:) = tmp(1:ix)
1412 type(
mg_t),
intent(inout) :: mg
1413 integer,
intent(in) :: id
1414 integer :: lvl, i, nb, child_nb(2**(1-1))
1416 integer :: c_id, c_ix_base(1)
1419 error stop
"mg_add_children: not enough space"
1424 mg%boxes(id)%children = c_ids
1425 c_ix_base = 2 * mg%boxes(id)%ix - 1
1426 lvl = mg%boxes(id)%lvl+1
1430 mg%boxes(c_id)%rank = mg%boxes(id)%rank
1432 mg%boxes(c_id)%lvl = lvl
1433 mg%boxes(c_id)%parent = id
1436 mg%boxes(c_id)%r_min = mg%boxes(id)%r_min + &
1438 mg%boxes(c_id)%dr(:) = mg%dr(:, lvl)
1443 if (mg%boxes(id)%neighbors(nb) <
mg_no_box)
then
1445 mg%boxes(child_nb)%neighbors(nb) = mg%boxes(id)%neighbors(nb)
1450 subroutine add_single_child(mg, id, n_boxes_lvl)
1451 type(
mg_t),
intent(inout) :: mg
1452 integer,
intent(in) :: id
1453 integer,
intent(in) :: n_boxes_lvl
1454 integer :: lvl, c_id
1456 c_id = mg%n_boxes + 1
1457 mg%n_boxes = mg%n_boxes + 1
1458 mg%boxes(id)%children(1) = c_id
1459 lvl = mg%boxes(id)%lvl+1
1461 mg%boxes(c_id)%rank = mg%boxes(id)%rank
1462 mg%boxes(c_id)%ix = mg%boxes(id)%ix
1463 mg%boxes(c_id)%lvl = lvl
1464 mg%boxes(c_id)%parent = id
1467 mg%boxes(c_id)%neighbors = mg%boxes(id)%neighbors
1469 mg%boxes(c_id)%neighbors = mg%boxes(id)%neighbors + n_boxes_lvl
1471 mg%boxes(c_id)%r_min = mg%boxes(id)%r_min
1472 mg%boxes(c_id)%dr(:) = mg%dr(:, lvl)
1474 end subroutine add_single_child
1484 type(
mg_t),
intent(inout) :: mg
1485 integer :: i, id, lvl, single_cpu_lvl
1486 integer :: work_left, my_work, i_cpu
1490 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1492 do lvl = mg%lowest_lvl, single_cpu_lvl
1493 do i = 1,
size(mg%lvls(lvl)%ids)
1494 id = mg%lvls(lvl)%ids(i)
1495 mg%boxes(id)%rank = 0
1501 do lvl = single_cpu_lvl+1, mg%highest_lvl
1502 work_left =
size(mg%lvls(lvl)%ids)
1506 do i = 1,
size(mg%lvls(lvl)%ids)
1507 if ((mg%n_cpu - i_cpu - 1) * my_work >= work_left)
then
1512 my_work = my_work + 1
1513 work_left = work_left - 1
1515 id = mg%lvls(lvl)%ids(i)
1516 mg%boxes(id)%rank = i_cpu
1520 do lvl = mg%lowest_lvl, mg%highest_lvl
1521 call update_lvl_info(mg, mg%lvls(lvl))
1533 type(
mg_t),
intent(inout) :: mg
1534 integer :: i, id, lvl, single_cpu_lvl
1535 integer :: work_left, my_work(0:mg%n_cpu), i_cpu
1538 integer :: coarse_rank
1542 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1546 do lvl = mg%highest_lvl, single_cpu_lvl+1, -1
1550 do i = 1,
size(mg%lvls(lvl)%parents)
1551 id = mg%lvls(lvl)%parents(i)
1553 c_ids = mg%boxes(id)%children
1554 c_ranks = mg%boxes(c_ids)%rank
1555 i_cpu = most_popular(c_ranks, my_work, mg%n_cpu)
1556 mg%boxes(id)%rank = i_cpu
1557 my_work(i_cpu) = my_work(i_cpu) + 1
1560 work_left =
size(mg%lvls(lvl)%leaves)
1563 do i = 1,
size(mg%lvls(lvl)%leaves)
1565 if ((mg%n_cpu - i_cpu - 1) * my_work(i_cpu) >= &
1566 work_left + sum(my_work(i_cpu+1:)))
then
1570 my_work(i_cpu) = my_work(i_cpu) + 1
1571 work_left = work_left - 1
1573 id = mg%lvls(lvl)%leaves(i)
1574 mg%boxes(id)%rank = i_cpu
1579 if (single_cpu_lvl < mg%highest_lvl)
then
1580 coarse_rank = most_popular(mg%boxes(&
1581 mg%lvls(single_cpu_lvl+1)%ids)%rank, my_work, mg%n_cpu)
1586 do lvl = mg%lowest_lvl, single_cpu_lvl
1587 do i = 1,
size(mg%lvls(lvl)%ids)
1588 id = mg%lvls(lvl)%ids(i)
1589 mg%boxes(id)%rank = coarse_rank
1593 do lvl = mg%lowest_lvl, mg%highest_lvl
1594 call update_lvl_info(mg, mg%lvls(lvl))
1602 type(
mg_t),
intent(inout) :: mg
1603 integer :: i, id, lvl
1606 integer :: single_cpu_lvl, coarse_rank
1607 integer :: my_work(0:mg%n_cpu), i_cpu
1611 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1613 do lvl = mg%highest_lvl-1, single_cpu_lvl+1, -1
1617 do i = 1,
size(mg%lvls(lvl)%leaves)
1618 id = mg%lvls(lvl)%leaves(i)
1619 i_cpu = mg%boxes(id)%rank
1620 my_work(i_cpu) = my_work(i_cpu) + 1
1623 do i = 1,
size(mg%lvls(lvl)%parents)
1624 id = mg%lvls(lvl)%parents(i)
1626 c_ids = mg%boxes(id)%children
1627 c_ranks = mg%boxes(c_ids)%rank
1628 i_cpu = most_popular(c_ranks, my_work, mg%n_cpu)
1629 mg%boxes(id)%rank = i_cpu
1630 my_work(i_cpu) = my_work(i_cpu) + 1
1636 if (single_cpu_lvl < mg%highest_lvl)
then
1637 coarse_rank = most_popular(mg%boxes(&
1638 mg%lvls(single_cpu_lvl+1)%ids)%rank, my_work, mg%n_cpu)
1643 do lvl = mg%lowest_lvl, single_cpu_lvl
1644 do i = 1,
size(mg%lvls(lvl)%ids)
1645 id = mg%lvls(lvl)%ids(i)
1646 mg%boxes(id)%rank = coarse_rank
1650 do lvl = mg%lowest_lvl, mg%highest_lvl
1651 call update_lvl_info(mg, mg%lvls(lvl))
1658 pure integer function most_popular(list, work, n_cpu)
1659 integer,
intent(in) :: list(:)
1660 integer,
intent(in) :: n_cpu
1661 integer,
intent(in) :: work(0:n_cpu-1)
1662 integer :: i, best_count, current_count
1663 integer :: my_work, best_work
1669 do i = 1,
size(list)
1670 current_count = count(list == list(i))
1671 my_work = work(list(i))
1674 if (current_count > best_count .or. &
1675 current_count == best_count .and. my_work < best_work)
then
1676 best_count = current_count
1678 most_popular = list(i)
1682 end function most_popular
1684 subroutine update_lvl_info(mg, lvl)
1685 type(
mg_t),
intent(inout) :: mg
1686 type(
mg_lvl_t),
intent(inout) :: lvl
1688 lvl%my_ids = pack(lvl%ids, &
1689 mg%boxes(lvl%ids)%rank == mg%my_rank)
1690 lvl%my_leaves = pack(lvl%leaves, &
1691 mg%boxes(lvl%leaves)%rank == mg%my_rank)
1692 lvl%my_parents = pack(lvl%parents, &
1693 mg%boxes(lvl%parents)%rank == mg%my_rank)
1694 lvl%my_ref_bnds = pack(lvl%ref_bnds, &
1695 mg%boxes(lvl%ref_bnds)%rank == mg%my_rank)
1696 end subroutine update_lvl_info
1701 type(
mg_t),
intent(inout) :: mg
1703 if (mg%n_extra_vars == 0 .and. mg%is_allocated)
then
1704 error stop
"vlaplacian_set_methods: mg%n_extra_vars == 0"
1706 mg%n_extra_vars = max(1, mg%n_extra_vars)
1709 mg%subtract_mean = .false.
1714 mg%bc(:,
mg_iveps)%bc_value = 0.0_dp
1716 select case (mg%geometry_type)
1718 mg%box_op => box_vlpl
1723 select case (mg%smoother_type)
1725 mg%box_smoother => box_gs_vlpl
1727 error stop
"vlaplacian_set_methods: unsupported smoother type"
1731 error stop
"vlaplacian_set_methods: unsupported geometry"
1737 subroutine box_gs_vlpl(mg, id, nc, redblack_cntr)
1738 type(
mg_t),
intent(inout) :: mg
1739 integer,
intent(in) :: id
1740 integer,
intent(in) :: nc
1741 integer,
intent(in) :: redblack_cntr
1742 integer :: i, i0, di
1744 real(
dp) :: idr2(2*1), u(2*1)
1745 real(
dp) :: a0, a(2*1), c(2*1)
1748 idr2(1:2*1:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1749 idr2(2:2*1:2) = idr2(1:2*1:2)
1761 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1763 if (redblack) i0 = 2 - iand(redblack_cntr, 1)
1767 u(1:2) = cc(i-1:i+1:2, n)
1768 a(1:2) = cc(i-1:i+1:2, i_eps)
1769 c(:) = 2 * a0 * a(:) / (a0 + a(:)) * idr2
1772 (sum(c(:) * u(:)) - cc(i,
mg_irhs)) / sum(c(:))
1775 end subroutine box_gs_vlpl
1778 subroutine box_vlpl(mg, id, nc, i_out)
1779 type(
mg_t),
intent(inout) :: mg
1780 integer,
intent(in) :: id
1781 integer,
intent(in) :: nc
1782 integer,
intent(in) :: i_out
1784 real(
dp) :: idr2(2*1), a0, u0, u(2*1), a(2*1)
1787 idr2(1:2*1:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1788 idr2(2:2*1:2) = idr2(1:2*1:2)
1790 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1794 a(1:2) = cc(i-1:i+1:2, i_eps)
1796 u(1:2) = cc(i-1:i+1:2, n)
1798 cc(i, i_out) = sum(2 * idr2 * &
1799 a0*a(:)/(a0 + a(:)) * (u(:) - u0))
1802 end subroutine box_vlpl
1910 type(
mg_t),
intent(inout) :: mg
1912 integer,
intent(in),
optional :: comm
1914 logical :: initialized
1916 call mpi_initialized(initialized, ierr)
1917 if (.not. initialized)
then
1921 if (
present(comm))
then
1924 mg%comm = mpi_comm_world
1927 call mpi_comm_rank(mg%comm, mg%my_rank, ierr)
1928 call mpi_comm_size(mg%comm, mg%n_cpu, ierr)
1933 type(
mg_t),
intent(inout) :: mg
1934 integer,
intent(in) :: dsize
1935 integer :: i, n_send, n_recv
1936 integer :: send_req(mg%n_cpu)
1937 integer :: recv_req(mg%n_cpu)
1943 do i = 0, mg%n_cpu - 1
1944 if (mg%buf(i)%i_send > 0)
then
1947 call mpi_isend(mg%buf(i)%send, mg%buf(i)%i_send, mpi_double, &
1948 i, 0, mg%comm, send_req(n_send), ierr)
1950 if (mg%buf(i)%i_recv > 0)
then
1952 call mpi_irecv(mg%buf(i)%recv, mg%buf(i)%i_recv, mpi_double, &
1953 i, 0, mg%comm, recv_req(n_recv), ierr)
1957 call mpi_waitall(n_recv, recv_req(1:n_recv), mpi_statuses_ignore, ierr)
1958 call mpi_waitall(n_send, send_req(1:n_send), mpi_statuses_ignore, ierr)
1965 type(
mg_buf_t),
intent(inout) :: gc
1966 integer,
intent(in) :: dsize
1967 integer :: ix_sort(gc%i_ix)
1968 real(dp) :: buf_cpy(gc%i_send)
1971 call mrgrnk(gc%ix(1:gc%i_ix), ix_sort)
1973 buf_cpy = gc%send(1:gc%i_send)
1977 j = (ix_sort(n)-1) * dsize
1978 gc%send(i+1:i+dsize) = buf_cpy(j+1:j+dsize)
1980 gc%ix(1:gc%i_ix) = gc%ix(ix_sort)
1988 type(
mg_t),
intent(inout) :: mg
1989 integer,
intent(out) :: n_send(0:mg%n_cpu-1)
1990 integer,
intent(out) :: n_recv(0:mg%n_cpu-1)
1991 integer,
intent(out) :: dsize
1992 integer :: i, id, lvl, nc
1994 allocate(mg%comm_ghostcell%n_send(0:mg%n_cpu-1, &
1995 mg%first_normal_lvl:mg%highest_lvl))
1996 allocate(mg%comm_ghostcell%n_recv(0:mg%n_cpu-1, &
1997 mg%first_normal_lvl:mg%highest_lvl))
1999 dsize = mg%box_size**(1-1)
2001 do lvl = mg%first_normal_lvl, mg%highest_lvl
2002 nc = mg%box_size_lvl(lvl)
2003 mg%buf(:)%i_send = 0
2004 mg%buf(:)%i_recv = 0
2007 do i = 1,
size(mg%lvls(lvl)%my_ids)
2008 id = mg%lvls(lvl)%my_ids(i)
2009 call buffer_ghost_cells(mg, id, nc, 1, dry_run=.true.)
2013 do i = 1,
size(mg%lvls(lvl-1)%my_ref_bnds)
2014 id = mg%lvls(lvl-1)%my_ref_bnds(i)
2015 call buffer_refinement_boundaries(mg, id, nc, 1, dry_run=.true.)
2020 mg%buf(:)%i_recv = 0
2021 do i = 1,
size(mg%lvls(lvl)%my_ids)
2022 id = mg%lvls(lvl)%my_ids(i)
2023 call set_ghost_cells(mg, id, nc, 1, dry_run=.true.)
2026 mg%comm_ghostcell%n_send(:, lvl) = mg%buf(:)%i_send/dsize
2027 mg%comm_ghostcell%n_recv(:, lvl) = mg%buf(:)%i_recv/dsize
2030 n_send = maxval(mg%comm_ghostcell%n_send, dim=2)
2031 n_recv = maxval(mg%comm_ghostcell%n_recv, dim=2)
2037 type(
mg_t),
intent(inout) :: mg
2042 do lvl = mg%lowest_lvl, mg%highest_lvl
2043 nc = mg%box_size_lvl(lvl)
2044 call mg_phi_bc_store_lvl(mg, lvl, nc)
2047 mg%phi_bc_data_stored = .true.
2050 subroutine mg_phi_bc_store_lvl(mg, lvl, nc)
2051 type(
mg_t),
intent(inout) :: mg
2052 integer,
intent(in) :: lvl
2053 integer,
intent(in) :: nc
2055 integer :: i, id, nb, nb_id, bc_type
2057 do i = 1,
size(mg%lvls(lvl)%my_ids)
2058 id = mg%lvls(lvl)%my_ids(i)
2060 nb_id = mg%boxes(id)%neighbors(nb)
2063 if (
associated(mg%bc(nb,
mg_iphi)%boundary_cond))
then
2064 call mg%bc(nb,
mg_iphi)%boundary_cond(mg%boxes(id), nc, &
2067 bc_type = mg%bc(nb,
mg_iphi)%bc_type
2068 bc = mg%bc(nb,
mg_iphi)%bc_value
2074 mg%boxes(id)%neighbors(nb) = bc_type
2077 call box_set_gc(mg%boxes(id), nb, nc,
mg_irhs, bc)
2081 end subroutine mg_phi_bc_store_lvl
2086 integer,
intent(in) :: iv
2089 do lvl = mg%lowest_lvl, mg%highest_lvl
2098 integer,
intent(in) :: lvl
2099 integer,
intent(in) :: iv
2100 integer :: i, id, dsize, nc
2102 if (lvl < mg%lowest_lvl) &
2103 error stop
"fill_ghost_cells_lvl: lvl < lowest_lvl"
2104 if (lvl > mg%highest_lvl) &
2105 error stop
"fill_ghost_cells_lvl: lvl > highest_lvl"
2107 nc = mg%box_size_lvl(lvl)
2109 if (lvl >= mg%first_normal_lvl)
then
2111 mg%buf(:)%i_send = 0
2112 mg%buf(:)%i_recv = 0
2115 do i = 1,
size(mg%lvls(lvl)%my_ids)
2116 id = mg%lvls(lvl)%my_ids(i)
2117 call buffer_ghost_cells(mg, id, nc, iv, .false.)
2121 do i = 1,
size(mg%lvls(lvl-1)%my_ref_bnds)
2122 id = mg%lvls(lvl-1)%my_ref_bnds(i)
2123 call buffer_refinement_boundaries(mg, id, nc, iv, .false.)
2128 mg%buf(:)%i_recv = mg%comm_ghostcell%n_recv(:, lvl) * dsize
2132 mg%buf(:)%i_recv = 0
2135 do i = 1,
size(mg%lvls(lvl)%my_ids)
2136 id = mg%lvls(lvl)%my_ids(i)
2137 call set_ghost_cells(mg, id, nc, iv, .false.)
2141 subroutine buffer_ghost_cells(mg, id, nc, iv, dry_run)
2142 type(
mg_t),
intent(inout) :: mg
2143 integer,
intent(in) :: id
2144 integer,
intent(in) :: nc
2145 integer,
intent(in) :: iv
2146 logical,
intent(in) :: dry_run
2147 integer :: nb, nb_id, nb_rank
2150 nb_id = mg%boxes(id)%neighbors(nb)
2154 nb_rank = mg%boxes(nb_id)%rank
2156 if (nb_rank /= mg%my_rank)
then
2157 call buffer_for_nb(mg, mg%boxes(id), nc, iv, nb_id, nb_rank, &
2162 end subroutine buffer_ghost_cells
2164 subroutine buffer_refinement_boundaries(mg, id, nc, iv, dry_run)
2165 type(
mg_t),
intent(inout) :: mg
2166 integer,
intent(in) :: id
2167 integer,
intent(in) :: nc
2168 integer,
intent(in) :: iv
2169 logical,
intent(in) :: dry_run
2170 integer :: nb, nb_id, c_ids(2**(1-1))
2171 integer :: n, c_id, c_rank
2174 nb_id = mg%boxes(id)%neighbors(nb)
2177 c_ids = mg%boxes(nb_id)%children(&
2182 c_rank = mg%boxes(c_id)%rank
2184 if (c_rank /= mg%my_rank)
then
2186 call buffer_for_fine_nb(mg, mg%boxes(id), nc, iv, c_id, &
2187 c_rank, nb, dry_run)
2193 end subroutine buffer_refinement_boundaries
2196 subroutine set_ghost_cells(mg, id, nc, iv, dry_run)
2197 type(
mg_t),
intent(inout) :: mg
2198 integer,
intent(in) :: id
2199 integer,
intent(in) :: nc
2200 integer,
intent(in) :: iv
2201 logical,
intent(in) :: dry_run
2203 integer :: nb, nb_id, nb_rank, bc_type
2206 nb_id = mg%boxes(id)%neighbors(nb)
2210 nb_rank = mg%boxes(nb_id)%rank
2212 if (nb_rank /= mg%my_rank)
then
2213 call fill_buffered_nb(mg, mg%boxes(id), nb_rank, &
2214 nb, nc, iv, dry_run)
2215 else if (.not. dry_run)
then
2216 call copy_from_nb(mg%boxes(id), mg%boxes(nb_id), &
2221 call fill_refinement_bnd(mg, id, nb, nc, iv, dry_run)
2222 else if (.not. dry_run)
then
2224 if (mg%phi_bc_data_stored .and. iv ==
mg_iphi)
then
2227 call box_get_gc(mg%boxes(id), nb, nc,
mg_irhs, bc)
2230 if (
associated(mg%bc(nb, iv)%boundary_cond))
then
2231 call mg%bc(nb, iv)%boundary_cond(mg%boxes(id), nc, iv, &
2234 bc_type = mg%bc(nb, iv)%bc_type
2235 bc = mg%bc(nb, iv)%bc_value
2239 call box_set_gc(mg%boxes(id), nb, nc, iv, bc)
2240 call bc_to_gc(mg, id, nc, iv, nb, bc_type)
2243 end subroutine set_ghost_cells
2245 subroutine fill_refinement_bnd(mg, id, nb, nc, iv, dry_run)
2246 type(
mg_t),
intent(inout) :: mg
2247 integer,
intent(in) :: id
2248 integer,
intent(in) :: nc
2249 integer,
intent(in) :: iv
2250 integer,
intent(in) :: nb
2251 logical,
intent(in) :: dry_run
2253 integer :: p_id, p_nb_id, ix_offset(1)
2254 integer :: i, dsize, p_nb_rank
2257 p_id = mg%boxes(id)%parent
2258 p_nb_id = mg%boxes(p_id)%neighbors(nb)
2259 p_nb_rank = mg%boxes(p_nb_id)%rank
2261 if (p_nb_rank /= mg%my_rank)
then
2262 i = mg%buf(p_nb_rank)%i_recv
2263 if (.not. dry_run)
then
2264 gc = reshape(mg%buf(p_nb_rank)%recv(i+1:i+dsize), shape(gc))
2266 mg%buf(p_nb_rank)%i_recv = mg%buf(p_nb_rank)%i_recv + dsize
2267 else if (.not. dry_run)
then
2269 call box_gc_for_fine_neighbor(mg%boxes(p_nb_id),
mg_neighb_rev(nb), &
2270 ix_offset, nc, iv, gc)
2273 if (.not. dry_run)
then
2274 if (
associated(mg%bc(nb, iv)%refinement_bnd))
then
2275 call mg%bc(nb, iv)%refinement_bnd(mg%boxes(id), nc, iv, nb, gc)
2277 call sides_rb(mg%boxes(id), nc, iv, nb, gc)
2280 end subroutine fill_refinement_bnd
2282 subroutine copy_from_nb(box, box_nb, nb, nc, iv)
2283 type(
mg_box_t),
intent(inout) :: box
2284 type(
mg_box_t),
intent(in) :: box_nb
2285 integer,
intent(in) :: nb
2286 integer,
intent(in) :: nc
2287 integer,
intent(in) :: iv
2290 call box_gc_for_neighbor(box_nb,
mg_neighb_rev(nb), nc, iv, gc)
2291 call box_set_gc(box, nb, nc, iv, gc)
2292 end subroutine copy_from_nb
2294 subroutine buffer_for_nb(mg, box, nc, iv, nb_id, nb_rank, nb, dry_run)
2295 type(
mg_t),
intent(inout) :: mg
2296 type(
mg_box_t),
intent(inout) :: box
2297 integer,
intent(in) :: nc
2298 integer,
intent(in) :: iv
2299 integer,
intent(in) :: nb_id
2300 integer,
intent(in) :: nb_rank
2301 integer,
intent(in) :: nb
2302 logical,
intent(in) :: dry_run
2306 i = mg%buf(nb_rank)%i_send
2309 if (.not. dry_run)
then
2310 call box_gc_for_neighbor(box, nb, nc, iv, gc)
2311 mg%buf(nb_rank)%send(i+1:i+dsize) = pack(gc, .true.)
2316 i = mg%buf(nb_rank)%i_ix
2317 if (.not. dry_run)
then
2321 mg%buf(nb_rank)%i_send = mg%buf(nb_rank)%i_send + dsize
2322 mg%buf(nb_rank)%i_ix = mg%buf(nb_rank)%i_ix + 1
2323 end subroutine buffer_for_nb
2325 subroutine buffer_for_fine_nb(mg, box, nc, iv, fine_id, fine_rank, nb, dry_run)
2326 type(
mg_t),
intent(inout) :: mg
2327 type(
mg_box_t),
intent(inout) :: box
2328 integer,
intent(in) :: nc
2329 integer,
intent(in) :: iv
2330 integer,
intent(in) :: fine_id
2331 integer,
intent(in) :: fine_rank
2332 integer,
intent(in) :: nb
2333 logical,
intent(in) :: dry_run
2334 integer :: i, dsize, ix_offset(1)
2337 i = mg%buf(fine_rank)%i_send
2340 if (.not. dry_run)
then
2342 call box_gc_for_fine_neighbor(box, nb, ix_offset, nc, iv, gc)
2343 mg%buf(fine_rank)%send(i+1:i+dsize) = pack(gc, .true.)
2348 i = mg%buf(fine_rank)%i_ix
2349 if (.not. dry_run)
then
2354 mg%buf(fine_rank)%i_send = mg%buf(fine_rank)%i_send + dsize
2355 mg%buf(fine_rank)%i_ix = mg%buf(fine_rank)%i_ix + 1
2356 end subroutine buffer_for_fine_nb
2358 subroutine fill_buffered_nb(mg, box, nb_rank, nb, nc, iv, dry_run)
2359 type(
mg_t),
intent(inout) :: mg
2360 type(
mg_box_t),
intent(inout) :: box
2361 integer,
intent(in) :: nb_rank
2362 integer,
intent(in) :: nb
2363 integer,
intent(in) :: nc
2364 integer,
intent(in) :: iv
2365 logical,
intent(in) :: dry_run
2369 i = mg%buf(nb_rank)%i_recv
2372 if (.not. dry_run)
then
2373 gc = mg%buf(nb_rank)%recv(i+1)
2374 call box_set_gc(box, nb, nc, iv, gc)
2376 mg%buf(nb_rank)%i_recv = mg%buf(nb_rank)%i_recv + dsize
2378 end subroutine fill_buffered_nb
2380 subroutine box_gc_for_neighbor(box, nb, nc, iv, gc)
2382 integer,
intent(in) :: nb, nc, iv
2383 real(
dp),
intent(out) :: gc(1)
2391 end subroutine box_gc_for_neighbor
2394 subroutine box_gc_for_fine_neighbor(box, nb, di, nc, iv, gc)
2396 integer,
intent(in) :: nb
2397 integer,
intent(in) :: di(1)
2398 integer,
intent(in) :: nc, iv
2399 real(
dp),
intent(out) :: gc(1)
2410 tmp = box%cc(nc, iv)
2418 end subroutine box_gc_for_fine_neighbor
2420 subroutine box_get_gc(box, nb, nc, iv, gc)
2422 integer,
intent(in) :: nb, nc, iv
2423 real(
dp),
intent(out) :: gc(1)
2429 gc = box%cc(nc+1, iv)
2431 end subroutine box_get_gc
2433 subroutine box_set_gc(box, nb, nc, iv, gc)
2434 type(
mg_box_t),
intent(inout) :: box
2435 integer,
intent(in) :: nb, nc, iv
2436 real(
dp),
intent(in) :: gc(1)
2440 box%cc(0, iv) = gc(1)
2442 box%cc(nc+1, iv) = gc(1)
2444 end subroutine box_set_gc
2446 subroutine bc_to_gc(mg, id, nc, iv, nb, bc_type)
2447 type(
mg_t),
intent(inout) :: mg
2448 integer,
intent(in) :: id
2449 integer,
intent(in) :: nc
2450 integer,
intent(in) :: iv
2451 integer,
intent(in) :: nb
2452 integer,
intent(in) :: bc_type
2453 real(
dp) :: c0, c1, c2, dr
2463 select case (bc_type)
2478 error stop
"bc_to_gc: unknown boundary condition"
2483 mg%boxes(id)%cc(0, iv) = &
2484 c0 * mg%boxes(id)%cc(0, iv) + &
2485 c1 * mg%boxes(id)%cc(1, iv) + &
2486 c2 * mg%boxes(id)%cc(2, iv)
2488 mg%boxes(id)%cc(nc+1, iv) = &
2489 c0 * mg%boxes(id)%cc(nc+1, iv) + &
2490 c1 * mg%boxes(id)%cc(nc, iv) + &
2491 c2 * mg%boxes(id)%cc(nc-1, iv)
2493 end subroutine bc_to_gc
2496 subroutine sides_rb(box, nc, iv, nb, gc)
2497 type(
mg_box_t),
intent(inout) :: box
2498 integer,
intent(in) :: nc
2499 integer,
intent(in) :: iv
2500 integer,
intent(in) :: nb
2502 real(
dp),
intent(in) :: gc(1)
2504 integer :: i, ix, dix
2518 box%cc(i-di, iv) = (2 * gc(1) + box%cc(i, iv))/3.0_dp
2521 end subroutine sides_rb
2527 type(
mg_t),
intent(inout) :: mg
2528 integer,
intent(out) :: n_send(0:mg%n_cpu-1)
2529 integer,
intent(out) :: n_recv(0:mg%n_cpu-1)
2530 integer,
intent(out) :: dsize
2531 integer :: lvl, min_lvl
2533 if (.not.
allocated(mg%comm_restrict%n_send))
then
2534 error stop
"Call restrict_buffer_size before prolong_buffer_size"
2537 min_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
2538 allocate(mg%comm_prolong%n_send(0:mg%n_cpu-1, &
2539 min_lvl:mg%highest_lvl))
2540 allocate(mg%comm_prolong%n_recv(0:mg%n_cpu-1, &
2541 min_lvl:mg%highest_lvl))
2543 mg%comm_prolong%n_recv(:, mg%highest_lvl) = 0
2544 mg%comm_prolong%n_send(:, mg%highest_lvl) = 0
2546 do lvl = min_lvl, mg%highest_lvl-1
2547 mg%comm_prolong%n_recv(:, lvl) = &
2548 mg%comm_restrict%n_send(:, lvl+1)
2549 mg%comm_prolong%n_send(:, lvl) = &
2550 mg%comm_restrict%n_recv(:, lvl+1)
2555 dsize = (mg%box_size)**1
2556 n_send = maxval(mg%comm_prolong%n_send, dim=2)
2557 n_recv = maxval(mg%comm_prolong%n_recv, dim=2)
2563 type(
mg_t),
intent(inout) :: mg
2564 integer,
intent(in) :: lvl
2565 integer,
intent(in) :: iv
2566 integer,
intent(in) :: iv_to
2567 procedure(mg_box_prolong) :: method
2568 logical,
intent(in) :: add
2569 integer :: i, id, dsize, nc
2571 if (lvl == mg%highest_lvl) error stop
"cannot prolong highest level"
2572 if (lvl < mg%lowest_lvl) error stop
"cannot prolong below lowest level"
2575 if (lvl >= mg%first_normal_lvl-1)
then
2576 dsize = mg%box_size**1
2577 mg%buf(:)%i_send = 0
2580 do i = 1,
size(mg%lvls(lvl)%my_ids)
2581 id = mg%lvls(lvl)%my_ids(i)
2582 call prolong_set_buffer(mg, id, mg%box_size, iv, method)
2585 mg%buf(:)%i_recv = mg%comm_prolong%n_recv(:, lvl) * dsize
2587 mg%buf(:)%i_recv = 0
2590 nc = mg%box_size_lvl(lvl+1)
2591 do i = 1,
size(mg%lvls(lvl+1)%my_ids)
2592 id = mg%lvls(lvl+1)%my_ids(i)
2593 call prolong_onto(mg, id, nc, iv, iv_to, add, method)
2600 subroutine prolong_set_buffer(mg, id, nc, iv, method)
2601 type(
mg_t),
intent(inout) :: mg
2602 integer,
intent(in) :: id
2603 integer,
intent(in) :: nc
2604 integer,
intent(in) :: iv
2605 procedure(mg_box_prolong) :: method
2606 integer :: i, dix(1)
2607 integer :: i_c, c_id, c_rank, dsize
2613 c_id = mg%boxes(id)%children(i_c)
2615 c_rank = mg%boxes(c_id)%rank
2616 if (c_rank /= mg%my_rank)
then
2618 call method(mg, id, dix, nc, iv, tmp)
2620 i = mg%buf(c_rank)%i_send
2621 mg%buf(c_rank)%send(i+1:i+dsize) = pack(tmp, .true.)
2622 mg%buf(c_rank)%i_send = mg%buf(c_rank)%i_send + dsize
2624 i = mg%buf(c_rank)%i_ix
2625 mg%buf(c_rank)%ix(i+1) = c_id
2626 mg%buf(c_rank)%i_ix = mg%buf(c_rank)%i_ix + 1
2630 end subroutine prolong_set_buffer
2633 subroutine prolong_onto(mg, id, nc, iv, iv_to, add, method)
2634 type(
mg_t),
intent(inout) :: mg
2635 integer,
intent(in) :: id
2636 integer,
intent(in) :: nc
2637 integer,
intent(in) :: iv
2638 integer,
intent(in) :: iv_to
2639 logical,
intent(in) :: add
2640 procedure(mg_box_prolong) :: method
2641 integer :: hnc, p_id, p_rank, i, dix(1), dsize
2645 p_id = mg%boxes(id)%parent
2646 p_rank = mg%boxes(p_id)%rank
2648 if (p_rank == mg%my_rank)
then
2650 call method(mg, p_id, dix, nc, iv, tmp)
2653 i = mg%buf(p_rank)%i_recv
2654 tmp = reshape(mg%buf(p_rank)%recv(i+1:i+dsize), [nc])
2655 mg%buf(p_rank)%i_recv = mg%buf(p_rank)%i_recv + dsize
2659 mg%boxes(id)%cc(1:nc, iv_to) = &
2660 mg%boxes(id)%cc(1:nc, iv_to) + tmp
2662 mg%boxes(id)%cc(1:nc, iv_to) = tmp
2665 end subroutine prolong_onto
2669 type(
mg_t),
intent(inout) :: mg
2670 integer,
intent(in) :: p_id
2671 integer,
intent(in) :: dix(1)
2672 integer,
intent(in) :: nc
2673 integer,
intent(in) :: iv
2674 real(
dp),
intent(out) :: fine(nc)
2678 real(
dp) :: f0, flx, fhx
2682 associate(crs => mg%boxes(p_id)%cc)
2686 f0 = 0.75_dp * crs(ic, iv)
2687 flx = 0.25_dp * crs(ic-1, iv)
2688 fhx = 0.25_dp * crs(ic+1, iv)
2690 fine(2*i-1) = f0 + flx
2691 fine(2*i ) = f0 + fhx
2699 type(
mg_t),
intent(inout) :: mg
2701 mg%subtract_mean = .false.
2703 select case (mg%geometry_type)
2705 mg%box_op => box_helmh
2707 select case (mg%smoother_type)
2709 mg%box_smoother => box_gs_helmh
2711 error stop
"helmholtz_set_methods: unsupported smoother type"
2714 error stop
"helmholtz_set_methods: unsupported geometry"
2720 real(
dp),
intent(in) :: lambda
2723 error stop
"helmholtz_set_lambda: lambda < 0 not allowed"
2729 subroutine box_gs_helmh(mg, id, nc, redblack_cntr)
2730 type(
mg_t),
intent(inout) :: mg
2731 integer,
intent(in) :: id
2732 integer,
intent(in) :: nc
2733 integer,
intent(in) :: redblack_cntr
2734 integer :: i, i0, di
2735 real(
dp) :: idr2(1), fac
2738 idr2 = 1/mg%dr(:, mg%boxes(id)%lvl)**2
2751 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
2752 if (redblack) i0 = 2 - iand(redblack_cntr, 1)
2755 cc(i, n) = fac * ( &
2756 idr2(1) * (cc(i+1, n) + cc(i-1, n)) - &
2760 end subroutine box_gs_helmh
2763 subroutine box_helmh(mg, id, nc, i_out)
2764 type(
mg_t),
intent(inout) :: mg
2765 integer,
intent(in) :: id
2766 integer,
intent(in) :: nc
2767 integer,
intent(in) :: i_out
2771 idr2 = 1 / mg%dr(:, mg%boxes(id)%lvl)**2
2773 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
2776 idr2(1) * (cc(i-1, n) + cc(i+1, n) - 2 * cc(i, n)) - &
2780 end subroutine box_helmh
2786 type(
mg_t),
intent(inout) :: mg
2791 select case (mg%operator_type)
2803 error stop
"mg_set_methods: unknown operator"
2809 mg%n_smoother_substeps = 2
2811 mg%n_smoother_substeps = 1
2815 subroutine check_methods(mg)
2816 type(
mg_t),
intent(inout) :: mg
2818 if (.not.
associated(mg%box_op) .or. &
2819 .not.
associated(mg%box_smoother))
then
2823 end subroutine check_methods
2825 subroutine mg_add_timers(mg)
2826 type(
mg_t),
intent(inout) :: mg
2827 timer_total_vcycle =
mg_add_timer(mg,
"mg total V-cycle")
2828 timer_total_fmg =
mg_add_timer(mg,
"mg total FMG cycle")
2830 timer_smoother_gc =
mg_add_timer(mg,
"mg smoother g.c.")
2833 timer_update_coarse =
mg_add_timer(mg,
"mg update coarse")
2834 end subroutine mg_add_timers
2838 type(
mg_t),
intent(inout) :: mg
2839 logical,
intent(in) :: have_guess
2840 real(
dp),
intent(out),
optional :: max_res
2841 integer :: lvl, i, id
2843 call check_methods(mg)
2844 if (timer_smoother == -1)
call mg_add_timers(mg)
2848 if (.not. have_guess)
then
2849 do lvl = mg%highest_lvl, mg%lowest_lvl, -1
2850 do i = 1,
size(mg%lvls(lvl)%my_ids)
2851 id = mg%lvls(lvl)%my_ids(i)
2852 mg%boxes(id)%cc(:,
mg_iphi) = 0.0_dp
2860 do lvl = mg%highest_lvl, mg%lowest_lvl+1, -1
2863 call update_coarse(mg, lvl)
2867 if (mg%subtract_mean)
then
2872 do lvl = mg%lowest_lvl, mg%highest_lvl
2874 do i = 1,
size(mg%lvls(lvl)%my_ids)
2875 id = mg%lvls(lvl)%my_ids(i)
2876 mg%boxes(id)%cc(:,
mg_iold) = &
2880 if (lvl > mg%lowest_lvl)
then
2884 call correct_children(mg, lvl-1)
2892 if (lvl == mg%highest_lvl)
then
2905 type(
mg_t),
intent(inout) :: mg
2906 integer,
intent(in),
optional :: highest_lvl
2907 real(
dp),
intent(out),
optional :: max_res
2909 logical,
intent(in),
optional :: standalone
2910 integer :: lvl, min_lvl, i, max_lvl, ierr
2911 real(
dp) :: init_res, res
2912 logical :: is_standalone
2914 is_standalone = .true.
2915 if (
present(standalone)) is_standalone = standalone
2917 call check_methods(mg)
2918 if (timer_smoother == -1)
call mg_add_timers(mg)
2920 if (is_standalone) &
2923 if (mg%subtract_mean .and. .not.
present(highest_lvl))
then
2929 min_lvl = mg%lowest_lvl
2930 max_lvl = mg%highest_lvl
2931 if (
present(highest_lvl)) max_lvl = highest_lvl
2934 if (is_standalone)
then
2938 do lvl = max_lvl, min_lvl+1, -1
2940 call smooth_boxes(mg, lvl, mg%n_cycle_down)
2945 call update_coarse(mg, lvl)
2950 if (.not. all(mg%boxes(mg%lvls(min_lvl)%ids)%rank == &
2951 mg%boxes(mg%lvls(min_lvl)%ids(1))%rank))
then
2952 error stop
"Multiple CPUs for coarse grid (not implemented yet)"
2955 init_res = max_residual_lvl(mg, min_lvl)
2956 do i = 1, mg%max_coarse_cycles
2957 call smooth_boxes(mg, min_lvl, mg%n_cycle_up+mg%n_cycle_down)
2958 res = max_residual_lvl(mg, min_lvl)
2959 if (res < mg%residual_coarse_rel * init_res .or. &
2960 res < mg%residual_coarse_abs)
exit
2965 do lvl = min_lvl+1, max_lvl
2969 call correct_children(mg, lvl-1)
2976 call smooth_boxes(mg, lvl, mg%n_cycle_up)
2979 if (
present(max_res))
then
2981 do lvl = min_lvl, max_lvl
2982 res = max_residual_lvl(mg, lvl)
2983 init_res = max(res, init_res)
2985 call mpi_allreduce(init_res, max_res, 1, &
2986 mpi_double, mpi_max, mg%comm, ierr)
2990 if (mg%subtract_mean)
then
2994 if (is_standalone) &
3000 type(
mg_t),
intent(inout) :: mg
3001 integer,
intent(in) :: iv
3002 logical,
intent(in) :: include_ghostcells
3003 integer :: i, id, lvl, nc, ierr
3004 real(dp) :: sum_iv, mean_iv, volume
3008 call mpi_allreduce(sum_iv, mean_iv, 1, &
3009 mpi_double, mpi_sum, mg%comm, ierr)
3012 volume = nc**1 * product(mg%dr(:, 1)) *
size(mg%lvls(1)%ids)
3013 mean_iv = mean_iv / volume
3015 do lvl = mg%lowest_lvl, mg%highest_lvl
3016 nc = mg%box_size_lvl(lvl)
3018 do i = 1,
size(mg%lvls(lvl)%my_ids)
3019 id = mg%lvls(lvl)%my_ids(i)
3020 if (include_ghostcells)
then
3021 mg%boxes(id)%cc(:, iv) = &
3022 mg%boxes(id)%cc(:, iv) - mean_iv
3024 mg%boxes(id)%cc(1:nc, iv) = &
3025 mg%boxes(id)%cc(1:nc, iv) - mean_iv
3032 type(
mg_t),
intent(in) :: mg
3033 integer,
intent(in) :: iv
3034 integer :: lvl, i, id, nc
3038 do lvl = 1, mg%highest_lvl
3039 nc = mg%box_size_lvl(lvl)
3040 w = product(mg%dr(:, lvl))
3041 do i = 1,
size(mg%lvls(lvl)%my_leaves)
3042 id = mg%lvls(lvl)%my_leaves(i)
3044 sum(mg%boxes(id)%cc(1:nc, iv))
3049 real(
dp) function max_residual_lvl(mg, lvl)
3050 type(
mg_t),
intent(inout) :: mg
3051 integer,
intent(in) :: lvl
3052 integer :: i, id, nc
3055 nc = mg%box_size_lvl(lvl)
3056 max_residual_lvl = 0.0_dp
3058 do i = 1,
size(mg%lvls(lvl)%my_ids)
3059 id = mg%lvls(lvl)%my_ids(i)
3060 call residual_box(mg, id, nc)
3061 res = maxval(abs(mg%boxes(id)%cc(1:nc,
mg_ires)))
3062 max_residual_lvl = max(max_residual_lvl, res)
3064 end function max_residual_lvl
3100 subroutine update_coarse(mg, lvl)
3101 type(
mg_t),
intent(inout) :: mg
3102 integer,
intent(in) :: lvl
3103 integer :: i, id, nc, nc_c
3105 nc = mg%box_size_lvl(lvl)
3106 nc_c = mg%box_size_lvl(lvl-1)
3109 do i = 1,
size(mg%lvls(lvl)%my_ids)
3110 id = mg%lvls(lvl)%my_ids(i)
3111 call residual_box(mg, id, nc)
3122 do i = 1,
size(mg%lvls(lvl-1)%my_parents)
3123 id = mg%lvls(lvl-1)%my_parents(i)
3126 call mg%box_op(mg, id, nc_c,
mg_irhs)
3129 mg%boxes(id)%cc(1:nc_c,
mg_irhs) = &
3130 mg%boxes(id)%cc(1:nc_c,
mg_irhs) + &
3131 mg%boxes(id)%cc(1:nc_c,
mg_ires)
3134 mg%boxes(id)%cc(:,
mg_iold) = &
3137 end subroutine update_coarse
3140 subroutine correct_children(mg, lvl)
3141 type(
mg_t),
intent(inout) :: mg
3142 integer,
intent(in) :: lvl
3145 do i = 1,
size(mg%lvls(lvl)%my_parents)
3146 id = mg%lvls(lvl)%my_parents(i)
3149 mg%boxes(id)%cc(:,
mg_ires) = &
3150 mg%boxes(id)%cc(:,
mg_iphi) - &
3155 end subroutine correct_children
3157 subroutine smooth_boxes(mg, lvl, n_cycle)
3158 type(
mg_t),
intent(inout) :: mg
3159 integer,
intent(in) :: lvl
3160 integer,
intent(in) :: n_cycle
3161 integer :: n, i, id, nc
3163 nc = mg%box_size_lvl(lvl)
3165 do n = 1, n_cycle * mg%n_smoother_substeps
3167 do i = 1,
size(mg%lvls(lvl)%my_ids)
3168 id = mg%lvls(lvl)%my_ids(i)
3169 call mg%box_smoother(mg, id, nc, n)
3177 end subroutine smooth_boxes
3179 subroutine residual_box(mg, id, nc)
3180 type(
mg_t),
intent(inout) :: mg
3181 integer,
intent(in) :: id
3182 integer,
intent(in) :: nc
3184 call mg%box_op(mg, id, nc,
mg_ires)
3186 mg%boxes(id)%cc(1:nc,
mg_ires) = &
3187 mg%boxes(id)%cc(1:nc,
mg_irhs) &
3188 - mg%boxes(id)%cc(1:nc,
mg_ires)
3189 end subroutine residual_box
3193 type(
mg_t),
intent(inout) :: mg
3194 integer,
intent(in) :: i_out
3195 procedure(mg_box_op),
optional :: op
3196 integer :: lvl, i, id, nc
3198 do lvl = mg%lowest_lvl, mg%highest_lvl
3199 nc = mg%box_size_lvl(lvl)
3200 do i = 1,
size(mg%lvls(lvl)%my_ids)
3201 id = mg%lvls(lvl)%my_ids(i)
3202 if (
present(op))
then
3203 call op(mg, id, nc, i_out)
3205 call mg%box_op(mg, id, nc, i_out)
3215 type(
mg_t),
intent(inout) :: mg
3216 integer,
intent(out) :: n_send(0:mg%n_cpu-1)
3217 integer,
intent(out) :: n_recv(0:mg%n_cpu-1)
3218 integer,
intent(out) :: dsize
3219 integer :: n_out(0:mg%n_cpu-1, mg%first_normal_lvl:mg%highest_lvl)
3220 integer :: n_in(0:mg%n_cpu-1, mg%first_normal_lvl:mg%highest_lvl)
3221 integer :: lvl, i, id, p_id, p_rank
3222 integer :: i_c, c_id, c_rank, min_lvl
3226 min_lvl = max(mg%lowest_lvl+1, mg%first_normal_lvl)
3228 do lvl = min_lvl, mg%highest_lvl
3230 do i = 1,
size(mg%lvls(lvl-1)%my_parents)
3231 id = mg%lvls(lvl-1)%my_parents(i)
3233 c_id = mg%boxes(id)%children(i_c)
3236 c_rank = mg%boxes(c_id)%rank
3237 if (c_rank /= mg%my_rank)
then
3238 n_in(c_rank, lvl) = n_in(c_rank, lvl) + 1
3245 do i = 1,
size(mg%lvls(lvl)%my_ids)
3246 id = mg%lvls(lvl)%my_ids(i)
3248 p_id = mg%boxes(id)%parent
3249 p_rank = mg%boxes(p_id)%rank
3250 if (p_rank /= mg%my_rank)
then
3251 n_out(p_rank, lvl) = n_out(p_rank, lvl) + 1
3257 allocate(mg%comm_restrict%n_send(0:mg%n_cpu-1, &
3258 mg%first_normal_lvl:mg%highest_lvl))
3259 allocate(mg%comm_restrict%n_recv(0:mg%n_cpu-1, &
3260 mg%first_normal_lvl:mg%highest_lvl))
3261 mg%comm_restrict%n_send = n_out
3262 mg%comm_restrict%n_recv = n_in
3264 dsize = (mg%box_size/2)**1
3265 n_send = maxval(n_out, dim=2)
3266 n_recv = maxval(n_in, dim=2)
3271 type(
mg_t),
intent(inout) :: mg
3272 integer,
intent(in) :: iv
3275 do lvl = mg%highest_lvl, mg%lowest_lvl+1, -1
3283 type(
mg_t),
intent(inout) :: mg
3284 integer,
intent(in) :: iv
3285 integer,
intent(in) :: lvl
3286 integer :: i, id, dsize, nc
3288 if (lvl <= mg%lowest_lvl) error stop
"cannot restrict lvl <= lowest_lvl"
3290 nc = mg%box_size_lvl(lvl)
3292 if (lvl >= mg%first_normal_lvl)
then
3295 mg%buf(:)%i_send = 0
3298 do i = 1,
size(mg%lvls(lvl)%my_ids)
3299 id = mg%lvls(lvl)%my_ids(i)
3300 call restrict_set_buffer(mg, id, iv)
3303 mg%buf(:)%i_recv = mg%comm_restrict%n_recv(:, lvl) * dsize
3305 mg%buf(:)%i_recv = 0
3308 do i = 1,
size(mg%lvls(lvl-1)%my_parents)
3309 id = mg%lvls(lvl-1)%my_parents(i)
3310 call restrict_onto(mg, id, nc, iv)
3314 subroutine restrict_set_buffer(mg, id, iv)
3315 type(
mg_t),
intent(inout) :: mg
3316 integer,
intent(in) :: id
3317 integer,
intent(in) :: iv
3318 integer :: i, n, hnc, p_id, p_rank
3319 real(
dp) :: tmp(mg%box_size/2)
3322 p_id = mg%boxes(id)%parent
3323 p_rank = mg%boxes(p_id)%rank
3325 if (p_rank /= mg%my_rank)
then
3328 sum(mg%boxes(id)%cc(2*i-1:2*i, iv))
3333 i = mg%buf(p_rank)%i_send
3334 mg%buf(p_rank)%send(i+1:i+n) = pack(tmp, .true.)
3335 mg%buf(p_rank)%i_send = mg%buf(p_rank)%i_send + n
3338 i = mg%buf(p_rank)%i_ix
3341 mg%buf(p_rank)%i_ix = mg%buf(p_rank)%i_ix + 1
3343 end subroutine restrict_set_buffer
3345 subroutine restrict_onto(mg, id, nc, iv)
3346 type(
mg_t),
intent(inout) :: mg
3347 integer,
intent(in) :: id
3348 integer,
intent(in) :: nc
3349 integer,
intent(in) :: iv
3350 integer :: i, hnc, dsize, i_c, c_id
3351 integer :: c_rank, dix(1)
3357 c_id = mg%boxes(id)%children(i_c)
3359 c_rank = mg%boxes(c_id)%rank
3362 if (c_rank == mg%my_rank)
then
3364 mg%boxes(id)%cc(dix(1)+i, iv) = 0.5_dp * &
3365 sum(mg%boxes(c_id)%cc(2*i-1:2*i, iv))
3368 i = mg%buf(c_rank)%i_recv
3369 mg%boxes(id)%cc(dix(1)+1:dix(1)+hnc, iv) = &
3370 reshape(mg%buf(c_rank)%recv(i+1:i+dsize), [hnc])
3371 mg%buf(c_rank)%i_recv = mg%buf(c_rank)%i_recv + dsize
3375 end subroutine restrict_onto
3379 Subroutine i_mrgrnk (XDONT, IRNGT)
3386 Integer,
Dimension (:),
Intent (In) :: xdont
3387 Integer,
Dimension (:),
Intent (Out) :: irngt
3389 Integer :: xvala, xvalb
3391 Integer,
Dimension (SIZE(IRNGT)) :: jwrkt
3392 Integer :: lmtna, lmtnc, irng1, irng2
3393 Integer :: nval, iind, iwrkd, iwrk, iwrkf, jinda, iinda, iindb
3395 nval = min(
SIZE(xdont),
SIZE(irngt))
3408 Do iind = 2, nval, 2
3409 If (xdont(iind-1) <= xdont(iind))
Then
3410 irngt(iind-1) = iind - 1
3413 irngt(iind-1) = iind
3414 irngt(iind) = iind - 1
3417 If (modulo(nval, 2) /= 0)
Then
3434 Do iwrkd = 0, nval - 1, 4
3435 If ((iwrkd+4) > nval)
Then
3436 If ((iwrkd+2) >= nval)
Exit
3440 If (xdont(irngt(iwrkd+2)) <= xdont(irngt(iwrkd+3)))
Exit
3444 If (xdont(irngt(iwrkd+1)) <= xdont(irngt(iwrkd+3)))
Then
3445 irng2 = irngt(iwrkd+2)
3446 irngt(iwrkd+2) = irngt(iwrkd+3)
3447 irngt(iwrkd+3) = irng2
3452 irng1 = irngt(iwrkd+1)
3453 irngt(iwrkd+1) = irngt(iwrkd+3)
3454 irngt(iwrkd+3) = irngt(iwrkd+2)
3455 irngt(iwrkd+2) = irng1
3462 If (xdont(irngt(iwrkd+2)) <= xdont(irngt(iwrkd+3))) cycle
3466 If (xdont(irngt(iwrkd+1)) <= xdont(irngt(iwrkd+3)))
Then
3467 irng2 = irngt(iwrkd+2)
3468 irngt(iwrkd+2) = irngt(iwrkd+3)
3469 If (xdont(irng2) <= xdont(irngt(iwrkd+4)))
Then
3471 irngt(iwrkd+3) = irng2
3474 irngt(iwrkd+3) = irngt(iwrkd+4)
3475 irngt(iwrkd+4) = irng2
3481 irng1 = irngt(iwrkd+1)
3482 irng2 = irngt(iwrkd+2)
3483 irngt(iwrkd+1) = irngt(iwrkd+3)
3484 If (xdont(irng1) <= xdont(irngt(iwrkd+4)))
Then
3485 irngt(iwrkd+2) = irng1
3486 If (xdont(irng2) <= xdont(irngt(iwrkd+4)))
Then
3488 irngt(iwrkd+3) = irng2
3491 irngt(iwrkd+3) = irngt(iwrkd+4)
3492 irngt(iwrkd+4) = irng2
3496 irngt(iwrkd+2) = irngt(iwrkd+4)
3497 irngt(iwrkd+3) = irng1
3498 irngt(iwrkd+4) = irng2
3513 If (lmtna >= nval)
Exit
3522 jinda = iwrkf + lmtna
3523 iwrkf = iwrkf + lmtnc
3524 If (iwrkf >= nval)
Then
3525 If (jinda >= nval)
Exit
3541 jwrkt(1:lmtna) = irngt(iwrkd:jinda)
3543 xvala = xdont(jwrkt(iinda))
3544 xvalb = xdont(irngt(iindb))
3551 If (xvala > xvalb)
Then
3552 irngt(iwrk) = irngt(iindb)
3554 If (iindb > iwrkf)
Then
3556 irngt(iwrk+1:iwrkf) = jwrkt(iinda:lmtna)
3559 xvalb = xdont(irngt(iindb))
3561 irngt(iwrk) = jwrkt(iinda)
3563 If (iinda > lmtna) exit
3564 xvala = xdont(jwrkt(iinda))
3577 End Subroutine i_mrgrnk
3582 type(
mg_t),
intent(inout) :: mg
3584 if (mg%n_extra_vars == 0 .and. mg%is_allocated)
then
3585 error stop
"ahelmholtz_set_methods: mg%n_extra_vars == 0"
3587 mg%n_extra_vars = max(1, mg%n_extra_vars)
3597 select case (mg%geometry_type)
3599 mg%box_op => box_ahelmh
3601 select case (mg%smoother_type)
3603 mg%box_smoother => box_gs_ahelmh
3605 error stop
"ahelmholtz_set_methods: unsupported smoother type"
3608 error stop
"ahelmholtz_set_methods: unsupported geometry"
3614 real(
dp),
intent(in) :: lambda
3617 error stop
"ahelmholtz_set_lambda: lambda < 0 not allowed"
3623 subroutine box_gs_ahelmh(mg, id, nc, redblack_cntr)
3624 type(
mg_t),
intent(inout) :: mg
3625 integer,
intent(in) :: id
3626 integer,
intent(in) :: nc
3627 integer,
intent(in) :: redblack_cntr
3628 integer :: i, i0, di
3630 real(
dp) :: idr2(2*1), u(2*1)
3631 real(
dp) :: a0(2*1), a(2*1), c(2*1)
3634 idr2(1:2*1:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
3635 idr2(2:2*1:2) = idr2(1:2*1:2)
3647 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
3651 if (redblack) i0 = 2 - iand(redblack_cntr, 1)
3654 a0(1:2) = cc(i, i_eps1)
3655 u(1:2) = cc(i-1:i+1:2, n)
3656 a(1:2) = cc(i-1:i+1:2, i_eps1)
3657 c(:) = 2 * a0(:) * a(:) / (a0(:) + a(:)) * idr2
3660 (sum(c(:) * u(:)) - cc(i,
mg_irhs)) / &
3664 end subroutine box_gs_ahelmh
3667 subroutine box_ahelmh(mg, id, nc, i_out)
3668 type(
mg_t),
intent(inout) :: mg
3669 integer,
intent(in) :: id
3670 integer,
intent(in) :: nc
3671 integer,
intent(in) :: i_out
3673 real(
dp) :: idr2(2*1), a0(2*1), u0, u(2*1), a(2*1)
3676 idr2(1:2*1:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
3677 idr2(2:2*1:2) = idr2(1:2*1:2)
3679 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
3683 a0(1:2) = cc(i, i_eps1)
3684 a(1:2) = cc(i-1:i+1:2, i_eps1)
3686 u(1:2) = cc(i-1:i+1:2, n)
3688 cc(i, i_out) = sum(2 * idr2 * &
3689 a0(:)*a(:)/(a0(:) + a(:)) * (u(:) - u0)) - &
3693 end subroutine box_ahelmh
To fill ghost cells near physical boundaries.
integer(i8) function, public mg_number_of_unknowns(mg)
Determine total number of unknowns (on leaves)
integer, parameter, public mg_iphi
Index of solution.
integer, parameter, public i8
Type for 64-bit integers.
subroutine subtract_mean(mg, iv, include_ghostcells)
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 mg_fill_ghost_cells_lvl(mg, lvl, iv)
Fill ghost cells at a grid level.
integer, parameter, public mg_iveps3
integer, dimension(2, 1), parameter, public mg_child_rev
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_bc_neumann
Value to indicate a Neumann boundary condition.
logical, dimension(1, 2), parameter, public mg_child_low
integer, parameter, public mg_cylindrical
Cylindrical coordinate system.
integer, parameter, public mg_num_children
subroutine, public mg_restrict_buffer_size(mg, n_send, n_recv, dsize)
Specify minimum buffer size (per process) for communication.
integer, parameter, public mg_lvl_hi
Maximum allowed grid level.
integer, parameter, public mg_laplacian
Indicates a standard Laplacian.
integer, parameter, public mg_cartesian
Cartesian coordinate system.
subroutine, public mg_apply_op(mg, i_out, op)
Apply operator to the tree and store in variable i_out.
integer, parameter, public mg_physical_boundary
Special value that indicates there is a physical boundary.
elemental logical function, public mg_has_children(box)
Return .true. if a box has children.
subroutine, public mg_timer_end(timer)
integer, parameter, public mg_num_vars
Number of predefined multigrid variables.
integer, parameter, public mg_smoother_gsrb
integer, parameter, public mg_iveps
Index of the variable coefficient (at cell centers)
subroutine sort_sendbuf(gc, dsize)
Sort send buffers according to the idbuf array.
subroutine, public mg_set_methods(mg)
integer, parameter, public mg_ahelmholtz
Indicates a anisotropic-coefficient Helmholtz equation.
integer, dimension(1, 2), parameter, public mg_neighb_dix
subroutine, public vhelmholtz_set_methods(mg)
real(dp), public, protected vhelmholtz_lambda
Module for implicitly solving diffusion equations.
integer, parameter, public mg_no_box
Special value that indicates there is no box.
integer, parameter, public mg_lvl_lo
Minimum allowed grid level.
subroutine, public mg_restrict_lvl(mg, iv, lvl)
Restrict from lvl to lvl-1.
subroutine, public helmholtz_set_methods(mg)
subroutine, public mg_fill_ghost_cells(mg, iv)
Fill ghost cells at all grid levels.
integer, parameter, public mg_smoother_jacobi
subroutine, public mg_build_rectangle(mg, domain_size, box_size, dx, r_min, periodic, n_finer)
pure integer function, dimension(1), 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,...
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 vhelmholtz_set_lambda(lambda)
subroutine, public mg_ghost_cell_buffer_size(mg, n_send, n_recv, dsize)
Specify minimum buffer size (per process) for communication.
subroutine, public mg_timers_show(mg)
integer, parameter, public mg_max_num_vars
Maximum number of variables.
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...
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_restrict(mg, iv)
Restrict all levels.
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_fas_fmg(mg, have_guess, max_res)
Perform FAS-FMG cycle (full approximation scheme, full multigrid).
subroutine, public helmholtz_set_lambda(lambda)
integer, parameter, public mg_iveps1
Indexes of anisotropic variable coefficients.
subroutine, public mg_add_children(mg, id)
subroutine, public laplacian_set_methods(mg)
subroutine, public mg_set_refinement_boundaries(boxes, level)
Create a list of refinement boundaries (from the coarse side)
integer, dimension(2), parameter, public mg_neighb_high_pm
subroutine, public mg_prolong_buffer_size(mg, n_send, n_recv, dsize)
Specify minimum buffer size (per process) for communication.
subroutine, public mg_set_next_level_ids(mg, lvl)
subroutine, public mg_set_neighbors_lvl(mg, lvl)
integer, dimension(2), parameter, public mg_neighb_rev
integer, parameter, public dp
Type of reals.
integer, parameter, public mg_bc_dirichlet
Value to indicate a Dirichlet boundary condition.
integer, parameter, public mg_iveps2
integer, parameter, public mg_vlaplacian
Indicates a variable-coefficient Laplacian.
integer, parameter, public mg_helmholtz
Indicates a constant-coefficient Helmholtz equation.
pure integer function, public mg_highest_uniform_lvl(mg)
subroutine, public mg_allocate_storage(mg)
Allocate communication buffers and local boxes for a tree that has already been created.
subroutine, public diffusion_solve_acoeff(mg, dt, order, max_res)
Solve a diffusion equation implicitly, assuming anisotropic diffusion coefficient which has been stor...
integer, parameter, public mg_ndim
Problem dimension.
logical, dimension(2), parameter, public mg_neighb_low
integer, parameter, public mg_smoother_gs
subroutine, public mg_timer_start(timer)
subroutine, public vlaplacian_set_methods(mg)
integer, parameter, public mg_neighb_highx
integer, parameter, public mg_irhs
Index of right-hand side.
subroutine, public mg_deallocate_storage(mg)
Deallocate all allocatable arrays.
subroutine, public mg_get_face_coords(box, nb, nc, x)
Get coordinates at the face of a box.
integer, parameter, public mg_neighb_lowx
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_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.
integer, dimension(1, 2), parameter, public mg_child_adj_nb
subroutine, public ahelmholtz_set_lambda(lambda)
integer, dimension(2), parameter, public mg_neighb_dim
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_spherical
Spherical coordinate system.
integer function, public mg_add_timer(mg, name)
subroutine, public mg_fas_vcycle(mg, highest_lvl, max_res, standalone)
Perform FAS V-cycle (full approximation scheme).
integer, dimension(1, 2), parameter, public mg_child_dix
integer, parameter, public mg_bc_continuous
Value to indicate a continuous boundary condition.
real(dp) function get_sum(mg, iv)
integer, parameter, public mg_max_timers
Maximum number of timers to use.
integer, parameter, public mg_num_neighbors
subroutine, public ahelmholtz_set_methods(mg)
integer, parameter, public mg_ires
Index of residual.
integer, parameter, public mg_iold
Index of previous solution (used for correction)
subroutine, public sort_and_transfer_buffers(mg, dsize)
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_vhelmholtz
Indicates a variable-coefficient Helmholtz equation.
subroutine, public mg_phi_bc_store(mg)
Store boundary conditions for the solution variable, this can speed up calculations if the same bound...
Buffer type (one is used for each pair of communicating processes)
Lists of blocks per refinement level.