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 where ([i] == 1 .and. .not. periodic)
1194 where ([i] == 1 .and. periodic)
1199 where ([i] == nx .and. .not. periodic)
1203 where ([i] == nx .and. periodic)
1209 mg%lvls(mg%lowest_lvl)%ids = [(n, n=1, mg%n_boxes)]
1212 do lvl = mg%lowest_lvl, 0
1213 if (mg%box_size_lvl(lvl+1) == mg%box_size_lvl(lvl))
then
1214 do i = 1,
size(mg%lvls(lvl)%ids)
1215 id = mg%lvls(lvl)%ids(i)
1223 do i = 1,
size(mg%lvls(lvl)%ids)
1224 id = mg%lvls(lvl)%ids(i)
1225 call add_single_child(mg, id,
size(mg%lvls(lvl)%ids))
1236 do lvl = mg%lowest_lvl, 1
1237 if (
allocated(mg%lvls(lvl)%ref_bnds)) &
1238 deallocate(mg%lvls(lvl)%ref_bnds)
1239 allocate(mg%lvls(lvl)%ref_bnds(0))
1242 mg%tree_created = .true.
1246 type(
mg_t),
intent(inout) :: mg
1247 integer,
intent(in) :: lvl
1250 do i = 1,
size(mg%lvls(lvl)%ids)
1251 id = mg%lvls(lvl)%ids(i)
1252 call set_neighbs(mg%boxes, id)
1257 type(
mg_t),
intent(inout) :: mg
1258 integer,
intent(in) :: lvl
1261 if (
allocated(mg%lvls(lvl+1)%ids)) &
1262 deallocate(mg%lvls(lvl+1)%ids)
1265 if (mg%box_size_lvl(lvl+1) == mg%box_size_lvl(lvl))
then
1267 allocate(mg%lvls(lvl+1)%ids(n))
1270 do i = 1,
size(mg%lvls(lvl)%parents)
1271 id = mg%lvls(lvl)%parents(i)
1272 mg%lvls(lvl+1)%ids(n*(i-1)+1:n*i) = mg%boxes(id)%children
1275 n =
size(mg%lvls(lvl)%parents)
1276 allocate(mg%lvls(lvl+1)%ids(n))
1279 do i = 1,
size(mg%lvls(lvl)%parents)
1280 id = mg%lvls(lvl)%parents(i)
1281 mg%lvls(lvl+1)%ids(i) = mg%boxes(id)%children(1)
1288 subroutine set_neighbs(boxes, id)
1289 type(
mg_box_t),
intent(inout) :: boxes(:)
1290 integer,
intent(in) :: id
1291 integer :: nb, nb_id
1294 if (boxes(id)%neighbors(nb) ==
mg_no_box)
then
1295 nb_id = find_neighb(boxes, id, nb)
1297 boxes(id)%neighbors(nb) = nb_id
1302 end subroutine set_neighbs
1305 function find_neighb(boxes, id, nb)
result(nb_id)
1306 type(
mg_box_t),
intent(in) :: boxes(:)
1307 integer,
intent(in) :: id
1308 integer,
intent(in) :: nb
1309 integer :: nb_id, p_id, c_ix, d, old_pid
1311 p_id = boxes(id)%parent
1319 p_id = boxes(p_id)%neighbors(nb)
1324 end function find_neighb
1328 type(
mg_box_t),
intent(in) :: boxes(:)
1329 type(
mg_lvl_t),
intent(inout) :: level
1330 integer :: i, id, i_leaf, i_parent
1331 integer :: n_parents, n_leaves
1334 n_leaves =
size(level%ids) - n_parents
1336 if (.not.
allocated(level%parents))
then
1337 allocate(level%parents(n_parents))
1338 else if (n_parents /=
size(level%parents))
then
1339 deallocate(level%parents)
1340 allocate(level%parents(n_parents))
1343 if (.not.
allocated(level%leaves))
then
1344 allocate(level%leaves(n_leaves))
1345 else if (n_leaves /=
size(level%leaves))
then
1346 deallocate(level%leaves)
1347 allocate(level%leaves(n_leaves))
1352 do i = 1,
size(level%ids)
1355 i_parent = i_parent + 1
1356 level%parents(i_parent) = id
1359 level%leaves(i_leaf) = id
1366 type(
mg_box_t),
intent(in) :: boxes(:)
1367 type(
mg_lvl_t),
intent(inout) :: level
1368 integer,
allocatable :: tmp(:)
1369 integer :: i, id, nb, nb_id, ix
1371 if (
allocated(level%ref_bnds))
deallocate(level%ref_bnds)
1373 if (
size(level%parents) == 0)
then
1375 allocate(level%ref_bnds(0))
1377 allocate(tmp(
size(level%leaves)))
1379 do i = 1,
size(level%leaves)
1380 id = level%leaves(i)
1383 nb_id = boxes(id)%neighbors(nb)
1394 allocate(level%ref_bnds(ix))
1395 level%ref_bnds(:) = tmp(1:ix)
1400 type(
mg_t),
intent(inout) :: mg
1401 integer,
intent(in) :: id
1402 integer :: lvl, i, nb, child_nb(2**(1-1))
1404 integer :: c_id, c_ix_base(1)
1407 error stop
"mg_add_children: not enough space"
1412 mg%boxes(id)%children = c_ids
1413 c_ix_base = 2 * mg%boxes(id)%ix - 1
1414 lvl = mg%boxes(id)%lvl+1
1418 mg%boxes(c_id)%rank = mg%boxes(id)%rank
1420 mg%boxes(c_id)%lvl = lvl
1421 mg%boxes(c_id)%parent = id
1424 mg%boxes(c_id)%r_min = mg%boxes(id)%r_min + &
1426 mg%boxes(c_id)%dr(:) = mg%dr(:, lvl)
1431 if (mg%boxes(id)%neighbors(nb) <
mg_no_box)
then
1433 mg%boxes(child_nb)%neighbors(nb) = mg%boxes(id)%neighbors(nb)
1438 subroutine add_single_child(mg, id, n_boxes_lvl)
1439 type(
mg_t),
intent(inout) :: mg
1440 integer,
intent(in) :: id
1441 integer,
intent(in) :: n_boxes_lvl
1442 integer :: lvl, c_id
1444 c_id = mg%n_boxes + 1
1445 mg%n_boxes = mg%n_boxes + 1
1446 mg%boxes(id)%children(1) = c_id
1447 lvl = mg%boxes(id)%lvl+1
1449 mg%boxes(c_id)%rank = mg%boxes(id)%rank
1450 mg%boxes(c_id)%ix = mg%boxes(id)%ix
1451 mg%boxes(c_id)%lvl = lvl
1452 mg%boxes(c_id)%parent = id
1455 mg%boxes(c_id)%neighbors = mg%boxes(id)%neighbors
1457 mg%boxes(c_id)%neighbors = mg%boxes(id)%neighbors + n_boxes_lvl
1459 mg%boxes(c_id)%r_min = mg%boxes(id)%r_min
1460 mg%boxes(c_id)%dr(:) = mg%dr(:, lvl)
1462 end subroutine add_single_child
1472 type(
mg_t),
intent(inout) :: mg
1473 integer :: i, id, lvl, single_cpu_lvl
1474 integer :: work_left, my_work, i_cpu
1478 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1480 do lvl = mg%lowest_lvl, single_cpu_lvl
1481 do i = 1,
size(mg%lvls(lvl)%ids)
1482 id = mg%lvls(lvl)%ids(i)
1483 mg%boxes(id)%rank = 0
1489 do lvl = single_cpu_lvl+1, mg%highest_lvl
1490 work_left =
size(mg%lvls(lvl)%ids)
1494 do i = 1,
size(mg%lvls(lvl)%ids)
1495 if ((mg%n_cpu - i_cpu - 1) * my_work >= work_left)
then
1500 my_work = my_work + 1
1501 work_left = work_left - 1
1503 id = mg%lvls(lvl)%ids(i)
1504 mg%boxes(id)%rank = i_cpu
1508 do lvl = mg%lowest_lvl, mg%highest_lvl
1509 call update_lvl_info(mg, mg%lvls(lvl))
1521 type(
mg_t),
intent(inout) :: mg
1522 integer :: i, id, lvl, single_cpu_lvl
1523 integer :: work_left, my_work(0:mg%n_cpu), i_cpu
1526 integer :: coarse_rank
1530 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1534 do lvl = mg%highest_lvl, single_cpu_lvl+1, -1
1538 do i = 1,
size(mg%lvls(lvl)%parents)
1539 id = mg%lvls(lvl)%parents(i)
1541 c_ids = mg%boxes(id)%children
1542 c_ranks = mg%boxes(c_ids)%rank
1543 i_cpu = most_popular(c_ranks, my_work, mg%n_cpu)
1544 mg%boxes(id)%rank = i_cpu
1545 my_work(i_cpu) = my_work(i_cpu) + 1
1548 work_left =
size(mg%lvls(lvl)%leaves)
1551 do i = 1,
size(mg%lvls(lvl)%leaves)
1553 if ((mg%n_cpu - i_cpu - 1) * my_work(i_cpu) >= &
1554 work_left + sum(my_work(i_cpu+1:)))
then
1558 my_work(i_cpu) = my_work(i_cpu) + 1
1559 work_left = work_left - 1
1561 id = mg%lvls(lvl)%leaves(i)
1562 mg%boxes(id)%rank = i_cpu
1567 if (single_cpu_lvl < mg%highest_lvl)
then
1568 coarse_rank = most_popular(mg%boxes(&
1569 mg%lvls(single_cpu_lvl+1)%ids)%rank, my_work, mg%n_cpu)
1574 do lvl = mg%lowest_lvl, single_cpu_lvl
1575 do i = 1,
size(mg%lvls(lvl)%ids)
1576 id = mg%lvls(lvl)%ids(i)
1577 mg%boxes(id)%rank = coarse_rank
1581 do lvl = mg%lowest_lvl, mg%highest_lvl
1582 call update_lvl_info(mg, mg%lvls(lvl))
1590 type(
mg_t),
intent(inout) :: mg
1591 integer :: i, id, lvl
1594 integer :: single_cpu_lvl, coarse_rank
1595 integer :: my_work(0:mg%n_cpu), i_cpu
1599 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1601 do lvl = mg%highest_lvl-1, single_cpu_lvl+1, -1
1605 do i = 1,
size(mg%lvls(lvl)%leaves)
1606 id = mg%lvls(lvl)%leaves(i)
1607 i_cpu = mg%boxes(id)%rank
1608 my_work(i_cpu) = my_work(i_cpu) + 1
1611 do i = 1,
size(mg%lvls(lvl)%parents)
1612 id = mg%lvls(lvl)%parents(i)
1614 c_ids = mg%boxes(id)%children
1615 c_ranks = mg%boxes(c_ids)%rank
1616 i_cpu = most_popular(c_ranks, my_work, mg%n_cpu)
1617 mg%boxes(id)%rank = i_cpu
1618 my_work(i_cpu) = my_work(i_cpu) + 1
1624 if (single_cpu_lvl < mg%highest_lvl)
then
1625 coarse_rank = most_popular(mg%boxes(&
1626 mg%lvls(single_cpu_lvl+1)%ids)%rank, my_work, mg%n_cpu)
1631 do lvl = mg%lowest_lvl, single_cpu_lvl
1632 do i = 1,
size(mg%lvls(lvl)%ids)
1633 id = mg%lvls(lvl)%ids(i)
1634 mg%boxes(id)%rank = coarse_rank
1638 do lvl = mg%lowest_lvl, mg%highest_lvl
1639 call update_lvl_info(mg, mg%lvls(lvl))
1646 pure integer function most_popular(list, work, n_cpu)
1647 integer,
intent(in) :: list(:)
1648 integer,
intent(in) :: n_cpu
1649 integer,
intent(in) :: work(0:n_cpu-1)
1650 integer :: i, best_count, current_count
1651 integer :: my_work, best_work
1657 do i = 1,
size(list)
1658 current_count = count(list == list(i))
1659 my_work = work(list(i))
1662 if (current_count > best_count .or. &
1663 current_count == best_count .and. my_work < best_work)
then
1664 best_count = current_count
1666 most_popular = list(i)
1670 end function most_popular
1672 subroutine update_lvl_info(mg, lvl)
1673 type(
mg_t),
intent(inout) :: mg
1674 type(
mg_lvl_t),
intent(inout) :: lvl
1676 lvl%my_ids = pack(lvl%ids, &
1677 mg%boxes(lvl%ids)%rank == mg%my_rank)
1678 lvl%my_leaves = pack(lvl%leaves, &
1679 mg%boxes(lvl%leaves)%rank == mg%my_rank)
1680 lvl%my_parents = pack(lvl%parents, &
1681 mg%boxes(lvl%parents)%rank == mg%my_rank)
1682 lvl%my_ref_bnds = pack(lvl%ref_bnds, &
1683 mg%boxes(lvl%ref_bnds)%rank == mg%my_rank)
1684 end subroutine update_lvl_info
1689 type(
mg_t),
intent(inout) :: mg
1691 if (mg%n_extra_vars == 0 .and. mg%is_allocated)
then
1692 error stop
"vlaplacian_set_methods: mg%n_extra_vars == 0"
1694 mg%n_extra_vars = max(1, mg%n_extra_vars)
1697 mg%subtract_mean = .false.
1702 mg%bc(:,
mg_iveps)%bc_value = 0.0_dp
1704 select case (mg%geometry_type)
1706 mg%box_op => box_vlpl
1711 select case (mg%smoother_type)
1713 mg%box_smoother => box_gs_vlpl
1715 error stop
"vlaplacian_set_methods: unsupported smoother type"
1719 error stop
"vlaplacian_set_methods: unsupported geometry"
1725 subroutine box_gs_vlpl(mg, id, nc, redblack_cntr)
1726 type(
mg_t),
intent(inout) :: mg
1727 integer,
intent(in) :: id
1728 integer,
intent(in) :: nc
1729 integer,
intent(in) :: redblack_cntr
1730 integer :: i, i0, di
1732 real(
dp) :: idr2(2*1), u(2*1)
1733 real(
dp) :: a0, a(2*1), c(2*1)
1736 idr2(1:2*1:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1737 idr2(2:2*1:2) = idr2(1:2*1:2)
1749 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1751 if (redblack) i0 = 2 - iand(redblack_cntr, 1)
1755 u(1:2) = cc(i-1:i+1:2, n)
1756 a(1:2) = cc(i-1:i+1:2, i_eps)
1757 c(:) = 2 * a0 * a(:) / (a0 + a(:)) * idr2
1760 (sum(c(:) * u(:)) - cc(i,
mg_irhs)) / sum(c(:))
1763 end subroutine box_gs_vlpl
1766 subroutine box_vlpl(mg, id, nc, i_out)
1767 type(
mg_t),
intent(inout) :: mg
1768 integer,
intent(in) :: id
1769 integer,
intent(in) :: nc
1770 integer,
intent(in) :: i_out
1772 real(
dp) :: idr2(2*1), a0, u0, u(2*1), a(2*1)
1775 idr2(1:2*1:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1776 idr2(2:2*1:2) = idr2(1:2*1:2)
1778 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1782 a(1:2) = cc(i-1:i+1:2, i_eps)
1784 u(1:2) = cc(i-1:i+1:2, n)
1786 cc(i, i_out) = sum(2 * idr2 * &
1787 a0*a(:)/(a0 + a(:)) * (u(:) - u0))
1790 end subroutine box_vlpl
1898 type(
mg_t),
intent(inout) :: mg
1900 integer,
intent(in),
optional :: comm
1902 logical :: initialized
1904 call mpi_initialized(initialized, ierr)
1905 if (.not. initialized)
then
1909 if (
present(comm))
then
1912 mg%comm = mpi_comm_world
1915 call mpi_comm_rank(mg%comm, mg%my_rank, ierr)
1916 call mpi_comm_size(mg%comm, mg%n_cpu, ierr)
1921 type(
mg_t),
intent(inout) :: mg
1922 integer,
intent(in) :: dsize
1923 integer :: i, n_send, n_recv
1924 integer :: send_req(mg%n_cpu)
1925 integer :: recv_req(mg%n_cpu)
1931 do i = 0, mg%n_cpu - 1
1932 if (mg%buf(i)%i_send > 0)
then
1935 call mpi_isend(mg%buf(i)%send, mg%buf(i)%i_send, mpi_double, &
1936 i, 0, mg%comm, send_req(n_send), ierr)
1938 if (mg%buf(i)%i_recv > 0)
then
1940 call mpi_irecv(mg%buf(i)%recv, mg%buf(i)%i_recv, mpi_double, &
1941 i, 0, mg%comm, recv_req(n_recv), ierr)
1945 call mpi_waitall(n_recv, recv_req(1:n_recv), mpi_statuses_ignore, ierr)
1946 call mpi_waitall(n_send, send_req(1:n_send), mpi_statuses_ignore, ierr)
1953 type(
mg_buf_t),
intent(inout) :: gc
1954 integer,
intent(in) :: dsize
1955 integer :: ix_sort(gc%i_ix)
1956 real(dp) :: buf_cpy(gc%i_send)
1959 call mrgrnk(gc%ix(1:gc%i_ix), ix_sort)
1961 buf_cpy = gc%send(1:gc%i_send)
1965 j = (ix_sort(n)-1) * dsize
1966 gc%send(i+1:i+dsize) = buf_cpy(j+1:j+dsize)
1968 gc%ix(1:gc%i_ix) = gc%ix(ix_sort)
1976 type(
mg_t),
intent(inout) :: mg
1977 integer,
intent(out) :: n_send(0:mg%n_cpu-1)
1978 integer,
intent(out) :: n_recv(0:mg%n_cpu-1)
1979 integer,
intent(out) :: dsize
1980 integer :: i, id, lvl, nc
1982 allocate(mg%comm_ghostcell%n_send(0:mg%n_cpu-1, &
1983 mg%first_normal_lvl:mg%highest_lvl))
1984 allocate(mg%comm_ghostcell%n_recv(0:mg%n_cpu-1, &
1985 mg%first_normal_lvl:mg%highest_lvl))
1987 dsize = mg%box_size**(1-1)
1989 do lvl = mg%first_normal_lvl, mg%highest_lvl
1990 nc = mg%box_size_lvl(lvl)
1991 mg%buf(:)%i_send = 0
1992 mg%buf(:)%i_recv = 0
1995 do i = 1,
size(mg%lvls(lvl)%my_ids)
1996 id = mg%lvls(lvl)%my_ids(i)
1997 call buffer_ghost_cells(mg, id, nc, 1, dry_run=.true.)
2001 do i = 1,
size(mg%lvls(lvl-1)%my_ref_bnds)
2002 id = mg%lvls(lvl-1)%my_ref_bnds(i)
2003 call buffer_refinement_boundaries(mg, id, nc, 1, dry_run=.true.)
2008 mg%buf(:)%i_recv = 0
2009 do i = 1,
size(mg%lvls(lvl)%my_ids)
2010 id = mg%lvls(lvl)%my_ids(i)
2011 call set_ghost_cells(mg, id, nc, 1, dry_run=.true.)
2014 mg%comm_ghostcell%n_send(:, lvl) = mg%buf(:)%i_send/dsize
2015 mg%comm_ghostcell%n_recv(:, lvl) = mg%buf(:)%i_recv/dsize
2018 n_send = maxval(mg%comm_ghostcell%n_send, dim=2)
2019 n_recv = maxval(mg%comm_ghostcell%n_recv, dim=2)
2025 type(
mg_t),
intent(inout) :: mg
2030 do lvl = mg%lowest_lvl, mg%highest_lvl
2031 nc = mg%box_size_lvl(lvl)
2032 call mg_phi_bc_store_lvl(mg, lvl, nc)
2035 mg%phi_bc_data_stored = .true.
2038 subroutine mg_phi_bc_store_lvl(mg, lvl, nc)
2039 type(
mg_t),
intent(inout) :: mg
2040 integer,
intent(in) :: lvl
2041 integer,
intent(in) :: nc
2043 integer :: i, id, nb, nb_id, bc_type
2045 do i = 1,
size(mg%lvls(lvl)%my_ids)
2046 id = mg%lvls(lvl)%my_ids(i)
2048 nb_id = mg%boxes(id)%neighbors(nb)
2051 if (
associated(mg%bc(nb,
mg_iphi)%boundary_cond))
then
2052 call mg%bc(nb,
mg_iphi)%boundary_cond(mg%boxes(id), nc, &
2055 bc_type = mg%bc(nb,
mg_iphi)%bc_type
2056 bc = mg%bc(nb,
mg_iphi)%bc_value
2062 mg%boxes(id)%neighbors(nb) = bc_type
2065 call box_set_gc(mg%boxes(id), nb, nc,
mg_irhs, bc)
2069 end subroutine mg_phi_bc_store_lvl
2074 integer,
intent(in) :: iv
2077 do lvl = mg%lowest_lvl, mg%highest_lvl
2086 integer,
intent(in) :: lvl
2087 integer,
intent(in) :: iv
2088 integer :: i, id, dsize, nc
2090 if (lvl < mg%lowest_lvl) &
2091 error stop
"fill_ghost_cells_lvl: lvl < lowest_lvl"
2092 if (lvl > mg%highest_lvl) &
2093 error stop
"fill_ghost_cells_lvl: lvl > highest_lvl"
2095 nc = mg%box_size_lvl(lvl)
2097 if (lvl >= mg%first_normal_lvl)
then
2099 mg%buf(:)%i_send = 0
2100 mg%buf(:)%i_recv = 0
2103 do i = 1,
size(mg%lvls(lvl)%my_ids)
2104 id = mg%lvls(lvl)%my_ids(i)
2105 call buffer_ghost_cells(mg, id, nc, iv, .false.)
2109 do i = 1,
size(mg%lvls(lvl-1)%my_ref_bnds)
2110 id = mg%lvls(lvl-1)%my_ref_bnds(i)
2111 call buffer_refinement_boundaries(mg, id, nc, iv, .false.)
2116 mg%buf(:)%i_recv = mg%comm_ghostcell%n_recv(:, lvl) * dsize
2120 mg%buf(:)%i_recv = 0
2123 do i = 1,
size(mg%lvls(lvl)%my_ids)
2124 id = mg%lvls(lvl)%my_ids(i)
2125 call set_ghost_cells(mg, id, nc, iv, .false.)
2129 subroutine buffer_ghost_cells(mg, id, nc, iv, dry_run)
2130 type(
mg_t),
intent(inout) :: mg
2131 integer,
intent(in) :: id
2132 integer,
intent(in) :: nc
2133 integer,
intent(in) :: iv
2134 logical,
intent(in) :: dry_run
2135 integer :: nb, nb_id, nb_rank
2138 nb_id = mg%boxes(id)%neighbors(nb)
2142 nb_rank = mg%boxes(nb_id)%rank
2144 if (nb_rank /= mg%my_rank)
then
2145 call buffer_for_nb(mg, mg%boxes(id), nc, iv, nb_id, nb_rank, &
2150 end subroutine buffer_ghost_cells
2152 subroutine buffer_refinement_boundaries(mg, id, nc, iv, dry_run)
2153 type(
mg_t),
intent(inout) :: mg
2154 integer,
intent(in) :: id
2155 integer,
intent(in) :: nc
2156 integer,
intent(in) :: iv
2157 logical,
intent(in) :: dry_run
2158 integer :: nb, nb_id, c_ids(2**(1-1))
2159 integer :: n, c_id, c_rank
2162 nb_id = mg%boxes(id)%neighbors(nb)
2165 c_ids = mg%boxes(nb_id)%children(&
2170 c_rank = mg%boxes(c_id)%rank
2172 if (c_rank /= mg%my_rank)
then
2174 call buffer_for_fine_nb(mg, mg%boxes(id), nc, iv, c_id, &
2175 c_rank, nb, dry_run)
2181 end subroutine buffer_refinement_boundaries
2184 subroutine set_ghost_cells(mg, id, nc, iv, dry_run)
2185 type(
mg_t),
intent(inout) :: mg
2186 integer,
intent(in) :: id
2187 integer,
intent(in) :: nc
2188 integer,
intent(in) :: iv
2189 logical,
intent(in) :: dry_run
2191 integer :: nb, nb_id, nb_rank, bc_type
2194 nb_id = mg%boxes(id)%neighbors(nb)
2198 nb_rank = mg%boxes(nb_id)%rank
2200 if (nb_rank /= mg%my_rank)
then
2201 call fill_buffered_nb(mg, mg%boxes(id), nb_rank, &
2202 nb, nc, iv, dry_run)
2203 else if (.not. dry_run)
then
2204 call copy_from_nb(mg%boxes(id), mg%boxes(nb_id), &
2209 call fill_refinement_bnd(mg, id, nb, nc, iv, dry_run)
2210 else if (.not. dry_run)
then
2212 if (mg%phi_bc_data_stored .and. iv ==
mg_iphi)
then
2215 call box_get_gc(mg%boxes(id), nb, nc,
mg_irhs, bc)
2218 if (
associated(mg%bc(nb, iv)%boundary_cond))
then
2219 call mg%bc(nb, iv)%boundary_cond(mg%boxes(id), nc, iv, &
2222 bc_type = mg%bc(nb, iv)%bc_type
2223 bc = mg%bc(nb, iv)%bc_value
2227 call box_set_gc(mg%boxes(id), nb, nc, iv, bc)
2228 call bc_to_gc(mg, id, nc, iv, nb, bc_type)
2231 end subroutine set_ghost_cells
2233 subroutine fill_refinement_bnd(mg, id, nb, nc, iv, dry_run)
2234 type(
mg_t),
intent(inout) :: mg
2235 integer,
intent(in) :: id
2236 integer,
intent(in) :: nc
2237 integer,
intent(in) :: iv
2238 integer,
intent(in) :: nb
2239 logical,
intent(in) :: dry_run
2241 integer :: p_id, p_nb_id, ix_offset(1)
2242 integer :: i, dsize, p_nb_rank
2245 p_id = mg%boxes(id)%parent
2246 p_nb_id = mg%boxes(p_id)%neighbors(nb)
2247 p_nb_rank = mg%boxes(p_nb_id)%rank
2249 if (p_nb_rank /= mg%my_rank)
then
2250 i = mg%buf(p_nb_rank)%i_recv
2251 if (.not. dry_run)
then
2252 gc = reshape(mg%buf(p_nb_rank)%recv(i+1:i+dsize), shape(gc))
2254 mg%buf(p_nb_rank)%i_recv = mg%buf(p_nb_rank)%i_recv + dsize
2255 else if (.not. dry_run)
then
2257 call box_gc_for_fine_neighbor(mg%boxes(p_nb_id),
mg_neighb_rev(nb), &
2258 ix_offset, nc, iv, gc)
2261 if (.not. dry_run)
then
2262 if (
associated(mg%bc(nb, iv)%refinement_bnd))
then
2263 call mg%bc(nb, iv)%refinement_bnd(mg%boxes(id), nc, iv, nb, gc)
2265 call sides_rb(mg%boxes(id), nc, iv, nb, gc)
2268 end subroutine fill_refinement_bnd
2270 subroutine copy_from_nb(box, box_nb, nb, nc, iv)
2271 type(
mg_box_t),
intent(inout) :: box
2272 type(
mg_box_t),
intent(in) :: box_nb
2273 integer,
intent(in) :: nb
2274 integer,
intent(in) :: nc
2275 integer,
intent(in) :: iv
2278 call box_gc_for_neighbor(box_nb,
mg_neighb_rev(nb), nc, iv, gc)
2279 call box_set_gc(box, nb, nc, iv, gc)
2280 end subroutine copy_from_nb
2282 subroutine buffer_for_nb(mg, box, nc, iv, nb_id, nb_rank, nb, dry_run)
2283 type(
mg_t),
intent(inout) :: mg
2284 type(
mg_box_t),
intent(inout) :: box
2285 integer,
intent(in) :: nc
2286 integer,
intent(in) :: iv
2287 integer,
intent(in) :: nb_id
2288 integer,
intent(in) :: nb_rank
2289 integer,
intent(in) :: nb
2290 logical,
intent(in) :: dry_run
2294 i = mg%buf(nb_rank)%i_send
2297 if (.not. dry_run)
then
2298 call box_gc_for_neighbor(box, nb, nc, iv, gc)
2299 mg%buf(nb_rank)%send(i+1:i+dsize) = pack(gc, .true.)
2304 i = mg%buf(nb_rank)%i_ix
2305 if (.not. dry_run)
then
2309 mg%buf(nb_rank)%i_send = mg%buf(nb_rank)%i_send + dsize
2310 mg%buf(nb_rank)%i_ix = mg%buf(nb_rank)%i_ix + 1
2311 end subroutine buffer_for_nb
2313 subroutine buffer_for_fine_nb(mg, box, nc, iv, fine_id, fine_rank, nb, dry_run)
2314 type(
mg_t),
intent(inout) :: mg
2315 type(
mg_box_t),
intent(inout) :: box
2316 integer,
intent(in) :: nc
2317 integer,
intent(in) :: iv
2318 integer,
intent(in) :: fine_id
2319 integer,
intent(in) :: fine_rank
2320 integer,
intent(in) :: nb
2321 logical,
intent(in) :: dry_run
2322 integer :: i, dsize, ix_offset(1)
2325 i = mg%buf(fine_rank)%i_send
2328 if (.not. dry_run)
then
2330 call box_gc_for_fine_neighbor(box, nb, ix_offset, nc, iv, gc)
2331 mg%buf(fine_rank)%send(i+1:i+dsize) = pack(gc, .true.)
2336 i = mg%buf(fine_rank)%i_ix
2337 if (.not. dry_run)
then
2342 mg%buf(fine_rank)%i_send = mg%buf(fine_rank)%i_send + dsize
2343 mg%buf(fine_rank)%i_ix = mg%buf(fine_rank)%i_ix + 1
2344 end subroutine buffer_for_fine_nb
2346 subroutine fill_buffered_nb(mg, box, nb_rank, nb, nc, iv, dry_run)
2347 type(
mg_t),
intent(inout) :: mg
2348 type(
mg_box_t),
intent(inout) :: box
2349 integer,
intent(in) :: nb_rank
2350 integer,
intent(in) :: nb
2351 integer,
intent(in) :: nc
2352 integer,
intent(in) :: iv
2353 logical,
intent(in) :: dry_run
2357 i = mg%buf(nb_rank)%i_recv
2360 if (.not. dry_run)
then
2361 gc = mg%buf(nb_rank)%recv(i+1)
2362 call box_set_gc(box, nb, nc, iv, gc)
2364 mg%buf(nb_rank)%i_recv = mg%buf(nb_rank)%i_recv + dsize
2366 end subroutine fill_buffered_nb
2368 subroutine box_gc_for_neighbor(box, nb, nc, iv, gc)
2370 integer,
intent(in) :: nb, nc, iv
2371 real(
dp),
intent(out) :: gc(1)
2379 end subroutine box_gc_for_neighbor
2382 subroutine box_gc_for_fine_neighbor(box, nb, di, nc, iv, gc)
2384 integer,
intent(in) :: nb
2385 integer,
intent(in) :: di(1)
2386 integer,
intent(in) :: nc, iv
2387 real(
dp),
intent(out) :: gc(1)
2398 tmp = box%cc(nc, iv)
2406 end subroutine box_gc_for_fine_neighbor
2408 subroutine box_get_gc(box, nb, nc, iv, gc)
2410 integer,
intent(in) :: nb, nc, iv
2411 real(
dp),
intent(out) :: gc(1)
2417 gc = box%cc(nc+1, iv)
2419 end subroutine box_get_gc
2421 subroutine box_set_gc(box, nb, nc, iv, gc)
2422 type(
mg_box_t),
intent(inout) :: box
2423 integer,
intent(in) :: nb, nc, iv
2424 real(
dp),
intent(in) :: gc(1)
2428 box%cc(0, iv) = gc(1)
2430 box%cc(nc+1, iv) = gc(1)
2432 end subroutine box_set_gc
2434 subroutine bc_to_gc(mg, id, nc, iv, nb, bc_type)
2435 type(
mg_t),
intent(inout) :: mg
2436 integer,
intent(in) :: id
2437 integer,
intent(in) :: nc
2438 integer,
intent(in) :: iv
2439 integer,
intent(in) :: nb
2440 integer,
intent(in) :: bc_type
2441 real(
dp) :: c0, c1, c2, dr
2451 select case (bc_type)
2466 error stop
"bc_to_gc: unknown boundary condition"
2471 mg%boxes(id)%cc(0, iv) = &
2472 c0 * mg%boxes(id)%cc(0, iv) + &
2473 c1 * mg%boxes(id)%cc(1, iv) + &
2474 c2 * mg%boxes(id)%cc(2, iv)
2476 mg%boxes(id)%cc(nc+1, iv) = &
2477 c0 * mg%boxes(id)%cc(nc+1, iv) + &
2478 c1 * mg%boxes(id)%cc(nc, iv) + &
2479 c2 * mg%boxes(id)%cc(nc-1, iv)
2481 end subroutine bc_to_gc
2484 subroutine sides_rb(box, nc, iv, nb, gc)
2485 type(
mg_box_t),
intent(inout) :: box
2486 integer,
intent(in) :: nc
2487 integer,
intent(in) :: iv
2488 integer,
intent(in) :: nb
2490 real(
dp),
intent(in) :: gc(1)
2492 integer :: i, ix, dix
2506 box%cc(i-di, iv) = (2 * gc(1) + box%cc(i, iv))/3.0_dp
2509 end subroutine sides_rb
2515 type(
mg_t),
intent(inout) :: mg
2516 integer,
intent(out) :: n_send(0:mg%n_cpu-1)
2517 integer,
intent(out) :: n_recv(0:mg%n_cpu-1)
2518 integer,
intent(out) :: dsize
2519 integer :: lvl, min_lvl
2521 if (.not.
allocated(mg%comm_restrict%n_send))
then
2522 error stop
"Call restrict_buffer_size before prolong_buffer_size"
2525 min_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
2526 allocate(mg%comm_prolong%n_send(0:mg%n_cpu-1, &
2527 min_lvl:mg%highest_lvl))
2528 allocate(mg%comm_prolong%n_recv(0:mg%n_cpu-1, &
2529 min_lvl:mg%highest_lvl))
2531 mg%comm_prolong%n_recv(:, mg%highest_lvl) = 0
2532 mg%comm_prolong%n_send(:, mg%highest_lvl) = 0
2534 do lvl = min_lvl, mg%highest_lvl-1
2535 mg%comm_prolong%n_recv(:, lvl) = &
2536 mg%comm_restrict%n_send(:, lvl+1)
2537 mg%comm_prolong%n_send(:, lvl) = &
2538 mg%comm_restrict%n_recv(:, lvl+1)
2543 dsize = (mg%box_size)**1
2544 n_send = maxval(mg%comm_prolong%n_send, dim=2)
2545 n_recv = maxval(mg%comm_prolong%n_recv, dim=2)
2551 type(
mg_t),
intent(inout) :: mg
2552 integer,
intent(in) :: lvl
2553 integer,
intent(in) :: iv
2554 integer,
intent(in) :: iv_to
2555 procedure(mg_box_prolong) :: method
2556 logical,
intent(in) :: add
2557 integer :: i, id, dsize, nc
2559 if (lvl == mg%highest_lvl) error stop
"cannot prolong highest level"
2560 if (lvl < mg%lowest_lvl) error stop
"cannot prolong below lowest level"
2563 if (lvl >= mg%first_normal_lvl-1)
then
2564 dsize = mg%box_size**1
2565 mg%buf(:)%i_send = 0
2568 do i = 1,
size(mg%lvls(lvl)%my_ids)
2569 id = mg%lvls(lvl)%my_ids(i)
2570 call prolong_set_buffer(mg, id, mg%box_size, iv, method)
2573 mg%buf(:)%i_recv = mg%comm_prolong%n_recv(:, lvl) * dsize
2575 mg%buf(:)%i_recv = 0
2578 nc = mg%box_size_lvl(lvl+1)
2579 do i = 1,
size(mg%lvls(lvl+1)%my_ids)
2580 id = mg%lvls(lvl+1)%my_ids(i)
2581 call prolong_onto(mg, id, nc, iv, iv_to, add, method)
2588 subroutine prolong_set_buffer(mg, id, nc, iv, method)
2589 type(
mg_t),
intent(inout) :: mg
2590 integer,
intent(in) :: id
2591 integer,
intent(in) :: nc
2592 integer,
intent(in) :: iv
2593 procedure(mg_box_prolong) :: method
2594 integer :: i, dix(1)
2595 integer :: i_c, c_id, c_rank, dsize
2601 c_id = mg%boxes(id)%children(i_c)
2603 c_rank = mg%boxes(c_id)%rank
2604 if (c_rank /= mg%my_rank)
then
2606 call method(mg, id, dix, nc, iv, tmp)
2608 i = mg%buf(c_rank)%i_send
2609 mg%buf(c_rank)%send(i+1:i+dsize) = pack(tmp, .true.)
2610 mg%buf(c_rank)%i_send = mg%buf(c_rank)%i_send + dsize
2612 i = mg%buf(c_rank)%i_ix
2613 mg%buf(c_rank)%ix(i+1) = c_id
2614 mg%buf(c_rank)%i_ix = mg%buf(c_rank)%i_ix + 1
2618 end subroutine prolong_set_buffer
2621 subroutine prolong_onto(mg, id, nc, iv, iv_to, add, method)
2622 type(
mg_t),
intent(inout) :: mg
2623 integer,
intent(in) :: id
2624 integer,
intent(in) :: nc
2625 integer,
intent(in) :: iv
2626 integer,
intent(in) :: iv_to
2627 logical,
intent(in) :: add
2628 procedure(mg_box_prolong) :: method
2629 integer :: hnc, p_id, p_rank, i, dix(1), dsize
2633 p_id = mg%boxes(id)%parent
2634 p_rank = mg%boxes(p_id)%rank
2636 if (p_rank == mg%my_rank)
then
2638 call method(mg, p_id, dix, nc, iv, tmp)
2641 i = mg%buf(p_rank)%i_recv
2642 tmp = reshape(mg%buf(p_rank)%recv(i+1:i+dsize), [nc])
2643 mg%buf(p_rank)%i_recv = mg%buf(p_rank)%i_recv + dsize
2647 mg%boxes(id)%cc(1:nc, iv_to) = &
2648 mg%boxes(id)%cc(1:nc, iv_to) + tmp
2650 mg%boxes(id)%cc(1:nc, iv_to) = tmp
2653 end subroutine prolong_onto
2657 type(
mg_t),
intent(inout) :: mg
2658 integer,
intent(in) :: p_id
2659 integer,
intent(in) :: dix(1)
2660 integer,
intent(in) :: nc
2661 integer,
intent(in) :: iv
2662 real(
dp),
intent(out) :: fine(nc)
2666 real(
dp) :: f0, flx, fhx
2670 associate(crs => mg%boxes(p_id)%cc)
2674 f0 = 0.75_dp * crs(ic, iv)
2675 flx = 0.25_dp * crs(ic-1, iv)
2676 fhx = 0.25_dp * crs(ic+1, iv)
2678 fine(2*i-1) = f0 + flx
2679 fine(2*i ) = f0 + fhx
2687 type(
mg_t),
intent(inout) :: mg
2689 mg%subtract_mean = .false.
2691 select case (mg%geometry_type)
2693 mg%box_op => box_helmh
2695 select case (mg%smoother_type)
2697 mg%box_smoother => box_gs_helmh
2699 error stop
"helmholtz_set_methods: unsupported smoother type"
2702 error stop
"helmholtz_set_methods: unsupported geometry"
2708 real(
dp),
intent(in) :: lambda
2711 error stop
"helmholtz_set_lambda: lambda < 0 not allowed"
2717 subroutine box_gs_helmh(mg, id, nc, redblack_cntr)
2718 type(
mg_t),
intent(inout) :: mg
2719 integer,
intent(in) :: id
2720 integer,
intent(in) :: nc
2721 integer,
intent(in) :: redblack_cntr
2722 integer :: i, i0, di
2723 real(
dp) :: idr2(1), fac
2726 idr2 = 1/mg%dr(:, mg%boxes(id)%lvl)**2
2739 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
2740 if (redblack) i0 = 2 - iand(redblack_cntr, 1)
2743 cc(i, n) = fac * ( &
2744 idr2(1) * (cc(i+1, n) + cc(i-1, n)) - &
2748 end subroutine box_gs_helmh
2751 subroutine box_helmh(mg, id, nc, i_out)
2752 type(
mg_t),
intent(inout) :: mg
2753 integer,
intent(in) :: id
2754 integer,
intent(in) :: nc
2755 integer,
intent(in) :: i_out
2759 idr2 = 1 / mg%dr(:, mg%boxes(id)%lvl)**2
2761 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
2764 idr2(1) * (cc(i-1, n) + cc(i+1, n) - 2 * cc(i, n)) - &
2768 end subroutine box_helmh
2774 type(
mg_t),
intent(inout) :: mg
2779 select case (mg%operator_type)
2791 error stop
"mg_set_methods: unknown operator"
2797 mg%n_smoother_substeps = 2
2799 mg%n_smoother_substeps = 1
2803 subroutine check_methods(mg)
2804 type(
mg_t),
intent(inout) :: mg
2806 if (.not.
associated(mg%box_op) .or. &
2807 .not.
associated(mg%box_smoother))
then
2811 end subroutine check_methods
2813 subroutine mg_add_timers(mg)
2814 type(
mg_t),
intent(inout) :: mg
2815 timer_total_vcycle =
mg_add_timer(mg,
"mg total V-cycle")
2816 timer_total_fmg =
mg_add_timer(mg,
"mg total FMG cycle")
2818 timer_smoother_gc =
mg_add_timer(mg,
"mg smoother g.c.")
2821 timer_update_coarse =
mg_add_timer(mg,
"mg update coarse")
2822 end subroutine mg_add_timers
2826 type(
mg_t),
intent(inout) :: mg
2827 logical,
intent(in) :: have_guess
2828 real(
dp),
intent(out),
optional :: max_res
2829 integer :: lvl, i, id
2831 call check_methods(mg)
2832 if (timer_smoother == -1)
call mg_add_timers(mg)
2836 if (.not. have_guess)
then
2837 do lvl = mg%highest_lvl, mg%lowest_lvl, -1
2838 do i = 1,
size(mg%lvls(lvl)%my_ids)
2839 id = mg%lvls(lvl)%my_ids(i)
2840 mg%boxes(id)%cc(:,
mg_iphi) = 0.0_dp
2848 do lvl = mg%highest_lvl, mg%lowest_lvl+1, -1
2851 call update_coarse(mg, lvl)
2855 if (mg%subtract_mean)
then
2860 do lvl = mg%lowest_lvl, mg%highest_lvl
2862 do i = 1,
size(mg%lvls(lvl)%my_ids)
2863 id = mg%lvls(lvl)%my_ids(i)
2864 mg%boxes(id)%cc(:,
mg_iold) = &
2868 if (lvl > mg%lowest_lvl)
then
2872 call correct_children(mg, lvl-1)
2880 if (lvl == mg%highest_lvl)
then
2893 type(
mg_t),
intent(inout) :: mg
2894 integer,
intent(in),
optional :: highest_lvl
2895 real(
dp),
intent(out),
optional :: max_res
2897 logical,
intent(in),
optional :: standalone
2898 integer :: lvl, min_lvl, i, max_lvl, ierr
2899 real(
dp) :: init_res, res
2900 logical :: is_standalone
2902 is_standalone = .true.
2903 if (
present(standalone)) is_standalone = standalone
2905 call check_methods(mg)
2906 if (timer_smoother == -1)
call mg_add_timers(mg)
2908 if (is_standalone) &
2911 if (mg%subtract_mean .and. .not.
present(highest_lvl))
then
2917 min_lvl = mg%lowest_lvl
2918 max_lvl = mg%highest_lvl
2919 if (
present(highest_lvl)) max_lvl = highest_lvl
2922 if (is_standalone)
then
2926 do lvl = max_lvl, min_lvl+1, -1
2928 call smooth_boxes(mg, lvl, mg%n_cycle_down)
2933 call update_coarse(mg, lvl)
2938 if (.not. all(mg%boxes(mg%lvls(min_lvl)%ids)%rank == &
2939 mg%boxes(mg%lvls(min_lvl)%ids(1))%rank))
then
2940 error stop
"Multiple CPUs for coarse grid (not implemented yet)"
2943 init_res = max_residual_lvl(mg, min_lvl)
2944 do i = 1, mg%max_coarse_cycles
2945 call smooth_boxes(mg, min_lvl, mg%n_cycle_up+mg%n_cycle_down)
2946 res = max_residual_lvl(mg, min_lvl)
2947 if (res < mg%residual_coarse_rel * init_res .or. &
2948 res < mg%residual_coarse_abs)
exit
2953 do lvl = min_lvl+1, max_lvl
2957 call correct_children(mg, lvl-1)
2964 call smooth_boxes(mg, lvl, mg%n_cycle_up)
2967 if (
present(max_res))
then
2969 do lvl = min_lvl, max_lvl
2970 res = max_residual_lvl(mg, lvl)
2971 init_res = max(res, init_res)
2973 call mpi_allreduce(init_res, max_res, 1, &
2974 mpi_double, mpi_max, mg%comm, ierr)
2978 if (mg%subtract_mean)
then
2982 if (is_standalone) &
2988 type(
mg_t),
intent(inout) :: mg
2989 integer,
intent(in) :: iv
2990 logical,
intent(in) :: include_ghostcells
2991 integer :: i, id, lvl, nc, ierr
2992 real(dp) :: sum_iv, mean_iv, volume
2996 call mpi_allreduce(sum_iv, mean_iv, 1, &
2997 mpi_double, mpi_sum, mg%comm, ierr)
3000 volume = nc**1 * product(mg%dr(:, 1)) *
size(mg%lvls(1)%ids)
3001 mean_iv = mean_iv / volume
3003 do lvl = mg%lowest_lvl, mg%highest_lvl
3004 nc = mg%box_size_lvl(lvl)
3006 do i = 1,
size(mg%lvls(lvl)%my_ids)
3007 id = mg%lvls(lvl)%my_ids(i)
3008 if (include_ghostcells)
then
3009 mg%boxes(id)%cc(:, iv) = &
3010 mg%boxes(id)%cc(:, iv) - mean_iv
3012 mg%boxes(id)%cc(1:nc, iv) = &
3013 mg%boxes(id)%cc(1:nc, iv) - mean_iv
3020 type(
mg_t),
intent(in) :: mg
3021 integer,
intent(in) :: iv
3022 integer :: lvl, i, id, nc
3026 do lvl = 1, mg%highest_lvl
3027 nc = mg%box_size_lvl(lvl)
3028 w = product(mg%dr(:, lvl))
3029 do i = 1,
size(mg%lvls(lvl)%my_leaves)
3030 id = mg%lvls(lvl)%my_leaves(i)
3032 sum(mg%boxes(id)%cc(1:nc, iv))
3037 real(
dp) function max_residual_lvl(mg, lvl)
3038 type(
mg_t),
intent(inout) :: mg
3039 integer,
intent(in) :: lvl
3040 integer :: i, id, nc
3043 nc = mg%box_size_lvl(lvl)
3044 max_residual_lvl = 0.0_dp
3046 do i = 1,
size(mg%lvls(lvl)%my_ids)
3047 id = mg%lvls(lvl)%my_ids(i)
3048 call residual_box(mg, id, nc)
3049 res = maxval(abs(mg%boxes(id)%cc(1:nc,
mg_ires)))
3050 max_residual_lvl = max(max_residual_lvl, res)
3052 end function max_residual_lvl
3088 subroutine update_coarse(mg, lvl)
3089 type(
mg_t),
intent(inout) :: mg
3090 integer,
intent(in) :: lvl
3091 integer :: i, id, nc, nc_c
3093 nc = mg%box_size_lvl(lvl)
3094 nc_c = mg%box_size_lvl(lvl-1)
3097 do i = 1,
size(mg%lvls(lvl)%my_ids)
3098 id = mg%lvls(lvl)%my_ids(i)
3099 call residual_box(mg, id, nc)
3110 do i = 1,
size(mg%lvls(lvl-1)%my_parents)
3111 id = mg%lvls(lvl-1)%my_parents(i)
3114 call mg%box_op(mg, id, nc_c,
mg_irhs)
3117 mg%boxes(id)%cc(1:nc_c,
mg_irhs) = &
3118 mg%boxes(id)%cc(1:nc_c,
mg_irhs) + &
3119 mg%boxes(id)%cc(1:nc_c,
mg_ires)
3122 mg%boxes(id)%cc(:,
mg_iold) = &
3125 end subroutine update_coarse
3128 subroutine correct_children(mg, lvl)
3129 type(
mg_t),
intent(inout) :: mg
3130 integer,
intent(in) :: lvl
3133 do i = 1,
size(mg%lvls(lvl)%my_parents)
3134 id = mg%lvls(lvl)%my_parents(i)
3137 mg%boxes(id)%cc(:,
mg_ires) = &
3138 mg%boxes(id)%cc(:,
mg_iphi) - &
3143 end subroutine correct_children
3145 subroutine smooth_boxes(mg, lvl, n_cycle)
3146 type(
mg_t),
intent(inout) :: mg
3147 integer,
intent(in) :: lvl
3148 integer,
intent(in) :: n_cycle
3149 integer :: n, i, id, nc
3151 nc = mg%box_size_lvl(lvl)
3153 do n = 1, n_cycle * mg%n_smoother_substeps
3155 do i = 1,
size(mg%lvls(lvl)%my_ids)
3156 id = mg%lvls(lvl)%my_ids(i)
3157 call mg%box_smoother(mg, id, nc, n)
3165 end subroutine smooth_boxes
3167 subroutine residual_box(mg, id, nc)
3168 type(
mg_t),
intent(inout) :: mg
3169 integer,
intent(in) :: id
3170 integer,
intent(in) :: nc
3172 call mg%box_op(mg, id, nc,
mg_ires)
3174 mg%boxes(id)%cc(1:nc,
mg_ires) = &
3175 mg%boxes(id)%cc(1:nc,
mg_irhs) &
3176 - mg%boxes(id)%cc(1:nc,
mg_ires)
3177 end subroutine residual_box
3181 type(
mg_t),
intent(inout) :: mg
3182 integer,
intent(in) :: i_out
3183 procedure(mg_box_op),
optional :: op
3184 integer :: lvl, i, id, nc
3186 do lvl = mg%lowest_lvl, mg%highest_lvl
3187 nc = mg%box_size_lvl(lvl)
3188 do i = 1,
size(mg%lvls(lvl)%my_ids)
3189 id = mg%lvls(lvl)%my_ids(i)
3190 if (
present(op))
then
3191 call op(mg, id, nc, i_out)
3193 call mg%box_op(mg, id, nc, i_out)
3203 type(
mg_t),
intent(inout) :: mg
3204 integer,
intent(out) :: n_send(0:mg%n_cpu-1)
3205 integer,
intent(out) :: n_recv(0:mg%n_cpu-1)
3206 integer,
intent(out) :: dsize
3207 integer :: n_out(0:mg%n_cpu-1, mg%first_normal_lvl:mg%highest_lvl)
3208 integer :: n_in(0:mg%n_cpu-1, mg%first_normal_lvl:mg%highest_lvl)
3209 integer :: lvl, i, id, p_id, p_rank
3210 integer :: i_c, c_id, c_rank, min_lvl
3214 min_lvl = max(mg%lowest_lvl+1, mg%first_normal_lvl)
3216 do lvl = min_lvl, mg%highest_lvl
3218 do i = 1,
size(mg%lvls(lvl-1)%my_parents)
3219 id = mg%lvls(lvl-1)%my_parents(i)
3221 c_id = mg%boxes(id)%children(i_c)
3224 c_rank = mg%boxes(c_id)%rank
3225 if (c_rank /= mg%my_rank)
then
3226 n_in(c_rank, lvl) = n_in(c_rank, lvl) + 1
3233 do i = 1,
size(mg%lvls(lvl)%my_ids)
3234 id = mg%lvls(lvl)%my_ids(i)
3236 p_id = mg%boxes(id)%parent
3237 p_rank = mg%boxes(p_id)%rank
3238 if (p_rank /= mg%my_rank)
then
3239 n_out(p_rank, lvl) = n_out(p_rank, lvl) + 1
3245 allocate(mg%comm_restrict%n_send(0:mg%n_cpu-1, &
3246 mg%first_normal_lvl:mg%highest_lvl))
3247 allocate(mg%comm_restrict%n_recv(0:mg%n_cpu-1, &
3248 mg%first_normal_lvl:mg%highest_lvl))
3249 mg%comm_restrict%n_send = n_out
3250 mg%comm_restrict%n_recv = n_in
3252 dsize = (mg%box_size/2)**1
3253 n_send = maxval(n_out, dim=2)
3254 n_recv = maxval(n_in, dim=2)
3259 type(
mg_t),
intent(inout) :: mg
3260 integer,
intent(in) :: iv
3263 do lvl = mg%highest_lvl, mg%lowest_lvl+1, -1
3271 type(
mg_t),
intent(inout) :: mg
3272 integer,
intent(in) :: iv
3273 integer,
intent(in) :: lvl
3274 integer :: i, id, dsize, nc
3276 if (lvl <= mg%lowest_lvl) error stop
"cannot restrict lvl <= lowest_lvl"
3278 nc = mg%box_size_lvl(lvl)
3280 if (lvl >= mg%first_normal_lvl)
then
3283 mg%buf(:)%i_send = 0
3286 do i = 1,
size(mg%lvls(lvl)%my_ids)
3287 id = mg%lvls(lvl)%my_ids(i)
3288 call restrict_set_buffer(mg, id, iv)
3291 mg%buf(:)%i_recv = mg%comm_restrict%n_recv(:, lvl) * dsize
3293 mg%buf(:)%i_recv = 0
3296 do i = 1,
size(mg%lvls(lvl-1)%my_parents)
3297 id = mg%lvls(lvl-1)%my_parents(i)
3298 call restrict_onto(mg, id, nc, iv)
3302 subroutine restrict_set_buffer(mg, id, iv)
3303 type(
mg_t),
intent(inout) :: mg
3304 integer,
intent(in) :: id
3305 integer,
intent(in) :: iv
3306 integer :: i, n, hnc, p_id, p_rank
3307 real(
dp) :: tmp(mg%box_size/2)
3310 p_id = mg%boxes(id)%parent
3311 p_rank = mg%boxes(p_id)%rank
3313 if (p_rank /= mg%my_rank)
then
3316 sum(mg%boxes(id)%cc(2*i-1:2*i, iv))
3321 i = mg%buf(p_rank)%i_send
3322 mg%buf(p_rank)%send(i+1:i+n) = pack(tmp, .true.)
3323 mg%buf(p_rank)%i_send = mg%buf(p_rank)%i_send + n
3326 i = mg%buf(p_rank)%i_ix
3329 mg%buf(p_rank)%i_ix = mg%buf(p_rank)%i_ix + 1
3331 end subroutine restrict_set_buffer
3333 subroutine restrict_onto(mg, id, nc, iv)
3334 type(
mg_t),
intent(inout) :: mg
3335 integer,
intent(in) :: id
3336 integer,
intent(in) :: nc
3337 integer,
intent(in) :: iv
3338 integer :: i, hnc, dsize, i_c, c_id
3339 integer :: c_rank, dix(1)
3345 c_id = mg%boxes(id)%children(i_c)
3347 c_rank = mg%boxes(c_id)%rank
3350 if (c_rank == mg%my_rank)
then
3352 mg%boxes(id)%cc(dix(1)+i, iv) = 0.5_dp * &
3353 sum(mg%boxes(c_id)%cc(2*i-1:2*i, iv))
3356 i = mg%buf(c_rank)%i_recv
3357 mg%boxes(id)%cc(dix(1)+1:dix(1)+hnc, iv) = &
3358 reshape(mg%buf(c_rank)%recv(i+1:i+dsize), [hnc])
3359 mg%buf(c_rank)%i_recv = mg%buf(c_rank)%i_recv + dsize
3363 end subroutine restrict_onto
3367 Subroutine i_mrgrnk (XDONT, IRNGT)
3374 Integer,
Dimension (:),
Intent (In) :: xdont
3375 Integer,
Dimension (:),
Intent (Out) :: irngt
3377 Integer :: xvala, xvalb
3379 Integer,
Dimension (SIZE(IRNGT)) :: jwrkt
3380 Integer :: lmtna, lmtnc, irng1, irng2
3381 Integer :: nval, iind, iwrkd, iwrk, iwrkf, jinda, iinda, iindb
3383 nval = min(
SIZE(xdont),
SIZE(irngt))
3396 Do iind = 2, nval, 2
3397 If (xdont(iind-1) <= xdont(iind))
Then
3398 irngt(iind-1) = iind - 1
3401 irngt(iind-1) = iind
3402 irngt(iind) = iind - 1
3405 If (modulo(nval, 2) /= 0)
Then
3422 Do iwrkd = 0, nval - 1, 4
3423 If ((iwrkd+4) > nval)
Then
3424 If ((iwrkd+2) >= nval)
Exit
3428 If (xdont(irngt(iwrkd+2)) <= xdont(irngt(iwrkd+3)))
Exit
3432 If (xdont(irngt(iwrkd+1)) <= xdont(irngt(iwrkd+3)))
Then
3433 irng2 = irngt(iwrkd+2)
3434 irngt(iwrkd+2) = irngt(iwrkd+3)
3435 irngt(iwrkd+3) = irng2
3440 irng1 = irngt(iwrkd+1)
3441 irngt(iwrkd+1) = irngt(iwrkd+3)
3442 irngt(iwrkd+3) = irngt(iwrkd+2)
3443 irngt(iwrkd+2) = irng1
3450 If (xdont(irngt(iwrkd+2)) <= xdont(irngt(iwrkd+3))) cycle
3454 If (xdont(irngt(iwrkd+1)) <= xdont(irngt(iwrkd+3)))
Then
3455 irng2 = irngt(iwrkd+2)
3456 irngt(iwrkd+2) = irngt(iwrkd+3)
3457 If (xdont(irng2) <= xdont(irngt(iwrkd+4)))
Then
3459 irngt(iwrkd+3) = irng2
3462 irngt(iwrkd+3) = irngt(iwrkd+4)
3463 irngt(iwrkd+4) = irng2
3469 irng1 = irngt(iwrkd+1)
3470 irng2 = irngt(iwrkd+2)
3471 irngt(iwrkd+1) = irngt(iwrkd+3)
3472 If (xdont(irng1) <= xdont(irngt(iwrkd+4)))
Then
3473 irngt(iwrkd+2) = irng1
3474 If (xdont(irng2) <= xdont(irngt(iwrkd+4)))
Then
3476 irngt(iwrkd+3) = irng2
3479 irngt(iwrkd+3) = irngt(iwrkd+4)
3480 irngt(iwrkd+4) = irng2
3484 irngt(iwrkd+2) = irngt(iwrkd+4)
3485 irngt(iwrkd+3) = irng1
3486 irngt(iwrkd+4) = irng2
3501 If (lmtna >= nval)
Exit
3510 jinda = iwrkf + lmtna
3511 iwrkf = iwrkf + lmtnc
3512 If (iwrkf >= nval)
Then
3513 If (jinda >= nval)
Exit
3529 jwrkt(1:lmtna) = irngt(iwrkd:jinda)
3531 xvala = xdont(jwrkt(iinda))
3532 xvalb = xdont(irngt(iindb))
3539 If (xvala > xvalb)
Then
3540 irngt(iwrk) = irngt(iindb)
3542 If (iindb > iwrkf)
Then
3544 irngt(iwrk+1:iwrkf) = jwrkt(iinda:lmtna)
3547 xvalb = xdont(irngt(iindb))
3549 irngt(iwrk) = jwrkt(iinda)
3551 If (iinda > lmtna) exit
3552 xvala = xdont(jwrkt(iinda))
3565 End Subroutine i_mrgrnk
3570 type(
mg_t),
intent(inout) :: mg
3572 if (mg%n_extra_vars == 0 .and. mg%is_allocated)
then
3573 error stop
"ahelmholtz_set_methods: mg%n_extra_vars == 0"
3575 mg%n_extra_vars = max(1, mg%n_extra_vars)
3585 select case (mg%geometry_type)
3587 mg%box_op => box_ahelmh
3589 select case (mg%smoother_type)
3591 mg%box_smoother => box_gs_ahelmh
3593 error stop
"ahelmholtz_set_methods: unsupported smoother type"
3596 error stop
"ahelmholtz_set_methods: unsupported geometry"
3602 real(
dp),
intent(in) :: lambda
3605 error stop
"ahelmholtz_set_lambda: lambda < 0 not allowed"
3611 subroutine box_gs_ahelmh(mg, id, nc, redblack_cntr)
3612 type(
mg_t),
intent(inout) :: mg
3613 integer,
intent(in) :: id
3614 integer,
intent(in) :: nc
3615 integer,
intent(in) :: redblack_cntr
3616 integer :: i, i0, di
3618 real(
dp) :: idr2(2*1), u(2*1)
3619 real(
dp) :: a0(2*1), a(2*1), c(2*1)
3622 idr2(1:2*1:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
3623 idr2(2:2*1:2) = idr2(1:2*1:2)
3635 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
3639 if (redblack) i0 = 2 - iand(redblack_cntr, 1)
3642 a0(1:2) = cc(i, i_eps1)
3643 u(1:2) = cc(i-1:i+1:2, n)
3644 a(1:2) = cc(i-1:i+1:2, i_eps1)
3645 c(:) = 2 * a0(:) * a(:) / (a0(:) + a(:)) * idr2
3648 (sum(c(:) * u(:)) - cc(i,
mg_irhs)) / &
3652 end subroutine box_gs_ahelmh
3655 subroutine box_ahelmh(mg, id, nc, i_out)
3656 type(
mg_t),
intent(inout) :: mg
3657 integer,
intent(in) :: id
3658 integer,
intent(in) :: nc
3659 integer,
intent(in) :: i_out
3661 real(
dp) :: idr2(2*1), a0(2*1), u0, u(2*1), a(2*1)
3664 idr2(1:2*1:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
3665 idr2(2:2*1:2) = idr2(1:2*1:2)
3667 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
3671 a0(1:2) = cc(i, i_eps1)
3672 a(1:2) = cc(i-1:i+1:2, i_eps1)
3674 u(1:2) = cc(i-1:i+1:2, n)
3676 cc(i, i_out) = sum(2 * idr2 * &
3677 a0(:)*a(:)/(a0(:) + a(:)) * (u(:) - u0)) - &
3681 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.