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.
255 logical :: subtract_mean = .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()
282 integer :: n_timers = 0
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)
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)
314 type(
mg_t),
intent(inout) :: mg
315 integer,
intent(in) :: id
316 integer,
intent(in) :: nc
317 integer,
intent(in) :: i_out
323 type(
mg_t),
intent(inout) :: mg
324 integer,
intent(in) :: id
325 integer,
intent(in) :: nc
326 integer,
intent(in) :: redblack_cntr
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)
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(1)
568 rmin(nb_dim) = rmin(nb_dim) + box%dr(nb_dim) * nc
575 type(
mg_t),
intent(inout) :: mg
576 character(len=*),
intent(in) :: name
578 mg%n_timers = mg%n_timers + 1
586 timer%t0 = mpi_wtime()
592 timer%t = timer%t + mpi_wtime() - timer%t0
597 type(
mg_t),
intent(in) :: mg
599 real(
dp) :: tmin(mg%n_timers)
600 real(
dp) :: tmax(mg%n_timers)
601 real(
dp),
allocatable :: tmp_array(:)
603 allocate(tmp_array(mg%n_timers))
604 tmp_array(:) = mg%timers(1:mg%n_timers)%t
606 call mpi_reduce(tmp_array, tmin, mg%n_timers, &
607 mpi_double, mpi_min, 0, mg%comm, ierr)
608 call mpi_reduce(tmp_array, tmax, mg%n_timers, &
609 mpi_double, mpi_max, 0, mg%comm, ierr)
611 if (mg%my_rank == 0)
then
612 write(*,
"(A20,2A16)")
"name ",
"min(s)",
"max(s)"
613 do n = 1, mg%n_timers
614 write(*,
"(A20,2F16.6)") mg%timers(n)%name, &
624 type(
mg_t),
intent(inout) :: mg
627 if (.not. mg%is_allocated) &
628 error stop
"deallocate_storage: tree is not allocated"
633 deallocate(mg%comm_restrict%n_send)
634 deallocate(mg%comm_restrict%n_recv)
636 deallocate(mg%comm_prolong%n_send)
637 deallocate(mg%comm_prolong%n_recv)
639 deallocate(mg%comm_ghostcell%n_send)
640 deallocate(mg%comm_ghostcell%n_recv)
642 do lvl = mg%lowest_lvl, mg%highest_lvl
643 deallocate(mg%lvls(lvl)%ids)
644 deallocate(mg%lvls(lvl)%leaves)
645 deallocate(mg%lvls(lvl)%parents)
646 deallocate(mg%lvls(lvl)%ref_bnds)
647 deallocate(mg%lvls(lvl)%my_ids)
648 deallocate(mg%lvls(lvl)%my_leaves)
649 deallocate(mg%lvls(lvl)%my_parents)
650 deallocate(mg%lvls(lvl)%my_ref_bnds)
653 mg%is_allocated = .false.
655 mg%phi_bc_data_stored = .false.
662 type(
mg_t),
intent(inout) :: mg
663 integer :: i, id, lvl, nc
664 integer :: n_send(0:mg%n_cpu-1, 3)
665 integer :: n_recv(0:mg%n_cpu-1, 3)
667 integer :: n_in, n_out, n_id
669 if (.not. mg%tree_created) &
670 error stop
"allocate_storage: tree is not yet created"
672 if (mg%is_allocated) &
673 error stop
"allocate_storage: tree is already allocated"
675 do lvl = mg%lowest_lvl, mg%highest_lvl
676 nc = mg%box_size_lvl(lvl)
677 do i = 1,
size(mg%lvls(lvl)%my_ids)
678 id = mg%lvls(lvl)%my_ids(i)
679 allocate(mg%boxes(id)%cc(0:nc+1, &
683 mg%boxes(id)%cc(:, :) = 0.0_dp
687 allocate(mg%buf(0:mg%n_cpu-1))
690 n_recv(:, 1), dsize(1))
692 n_recv(:, 2), dsize(2))
694 n_recv(:, 3), dsize(3))
697 n_out = maxval(n_send(i, :) * dsize(:))
698 n_in = maxval(n_recv(i, :) * dsize(:))
699 n_id = maxval(n_send(i, :))
700 allocate(mg%buf(i)%send(n_out))
701 allocate(mg%buf(i)%recv(n_in))
702 allocate(mg%buf(i)%ix(n_id))
705 mg%is_allocated = .true.
715 type(
mg_t),
intent(inout) :: mg
716 real(
dp),
intent(in) :: dt
717 real(
dp),
intent(in) :: diffusion_coeff
718 integer,
intent(in) :: order
719 real(
dp),
intent(in) :: max_res
720 integer,
parameter :: max_its = 10
730 call set_rhs(mg, -1/(dt * diffusion_coeff), 0.0_dp)
735 call set_rhs(mg, -2/(dt * diffusion_coeff), -1.0_dp)
737 error stop
"diffusion_solve: order should be 1 or 2"
745 if (res <= max_res)
exit
749 if (n == max_its + 1)
then
750 if (mg%my_rank == 0) &
751 print *,
"Did you specify boundary conditions correctly?"
752 error stop
"diffusion_solve: no convergence"
762 type(
mg_t),
intent(inout) :: mg
763 real(
dp),
intent(in) :: dt
764 integer,
intent(in) :: order
765 real(
dp),
intent(in) :: max_res
766 integer,
parameter :: max_its = 10
776 call set_rhs(mg, -1/dt, 0.0_dp)
781 call set_rhs(mg, -2/dt, -1.0_dp)
783 error stop
"diffusion_solve: order should be 1 or 2"
791 if (res <= max_res)
exit
795 if (n == max_its + 1)
then
796 if (mg%my_rank == 0)
then
797 print *,
"Did you specify boundary conditions correctly?"
798 print *,
"Or is the variation in diffusion too large?"
800 error stop
"diffusion_solve: no convergence"
811 type(
mg_t),
intent(inout) :: mg
812 real(
dp),
intent(in) :: dt
813 integer,
intent(in) :: order
814 real(
dp),
intent(in) :: max_res
815 integer,
parameter :: max_its = 10
825 call set_rhs(mg, -1/dt, 0.0_dp)
830 call set_rhs(mg, -2/dt, -1.0_dp)
832 error stop
"diffusion_solve: order should be 1 or 2"
840 if (res <= max_res)
exit
844 if (n == max_its + 1)
then
845 if (mg%my_rank == 0)
then
846 print *,
"Did you specify boundary conditions correctly?"
847 print *,
"Or is the variation in diffusion too large?"
849 error stop
"diffusion_solve: no convergence"
853 subroutine set_rhs(mg, f1, f2)
854 type(
mg_t),
intent(inout) :: mg
855 real(
dp),
intent(in) :: f1, f2
856 integer :: lvl, i, id, nc
858 do lvl = 1, mg%highest_lvl
859 nc = mg%box_size_lvl(lvl)
860 do i = 1,
size(mg%lvls(lvl)%my_leaves)
861 id = mg%lvls(lvl)%my_leaves(i)
862 mg%boxes(id)%cc(1:nc,
mg_irhs) = &
863 f1 * mg%boxes(id)%cc(1:nc,
mg_iphi) + &
864 f2 * mg%boxes(id)%cc(1:nc,
mg_irhs)
867 end subroutine set_rhs
872 type(
mg_t),
intent(inout) :: mg
874 if (all(mg%periodic))
then
877 mg%subtract_mean = .true.
880 select case (mg%geometry_type)
884 select case (mg%smoother_type)
888 mg%box_smoother => box_gs_lpl
890 error stop
"laplacian_set_methods: unsupported smoother type"
893 error stop
"laplacian_set_methods: unsupported geometry"
899 subroutine box_gs_lpl(mg, id, nc, redblack_cntr)
900 type(
mg_t),
intent(inout) :: mg
901 integer,
intent(in) :: id
902 integer,
intent(in) :: nc
903 integer,
intent(in) :: redblack_cntr
905 real(
dp) :: idr2(1), fac
908 idr2 = 1/mg%dr(:, mg%boxes(id)%lvl)**2
909 fac = 0.5_dp / sum(idr2)
921 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
922 if (redblack) i0 = 2 - iand(redblack_cntr, 1)
926 idr2(1) * (cc(i+1, n) + cc(i-1, n)) - &
930 end subroutine box_gs_lpl
971 subroutine box_lpl(mg, id, nc, i_out)
972 type(
mg_t),
intent(inout) :: mg
973 integer,
intent(in) :: id
974 integer,
intent(in) :: nc
975 integer,
intent(in) :: i_out
979 idr2 = 1 / mg%dr(:, mg%boxes(id)%lvl)**2
981 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
984 idr2(1) * (cc(i-1, n) + cc(i+1, n) - 2 * cc(i, n))
987 end subroutine box_lpl
993 type(
mg_t),
intent(inout) :: mg
995 if (mg%n_extra_vars == 0 .and. mg%is_allocated)
then
996 error stop
"vhelmholtz_set_methods: mg%n_extra_vars == 0"
998 mg%n_extra_vars = max(1, mg%n_extra_vars)
1001 mg%subtract_mean = .false.
1006 mg%bc(:,
mg_iveps)%bc_value = 0.0_dp
1008 select case (mg%geometry_type)
1010 mg%box_op => box_vhelmh
1012 select case (mg%smoother_type)
1014 mg%box_smoother => box_gs_vhelmh
1016 error stop
"vhelmholtz_set_methods: unsupported smoother type"
1019 error stop
"vhelmholtz_set_methods: unsupported geometry"
1025 real(
dp),
intent(in) :: lambda
1028 error stop
"vhelmholtz_set_lambda: lambda < 0 not allowed"
1034 subroutine box_gs_vhelmh(mg, id, nc, redblack_cntr)
1035 type(
mg_t),
intent(inout) :: mg
1036 integer,
intent(in) :: id
1037 integer,
intent(in) :: nc
1038 integer,
intent(in) :: redblack_cntr
1039 integer :: i, i0, di
1041 real(
dp) :: idr2(2*1), u(2*1)
1042 real(
dp) :: a0, a(2*1), c(2*1)
1045 idr2(1:2*1:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1046 idr2(2:2*1:2) = idr2(1:2*1:2)
1058 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1060 if (redblack) i0 = 2 - iand(redblack_cntr, 1)
1064 u(1:2) = cc(i-1:i+1:2, n)
1065 a(1:2) = cc(i-1:i+1:2, i_eps)
1066 c(:) = 2 * a0 * a(:) / (a0 + a(:)) * idr2
1069 (sum(c(:) * u(:)) - cc(i,
mg_irhs)) / &
1073 end subroutine box_gs_vhelmh
1076 subroutine box_vhelmh(mg, id, nc, i_out)
1077 type(
mg_t),
intent(inout) :: mg
1078 integer,
intent(in) :: id
1079 integer,
intent(in) :: nc
1080 integer,
intent(in) :: i_out
1082 real(
dp) :: idr2(2*1), a0, u0, u(2*1), a(2*1)
1085 idr2(1:2*1:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1086 idr2(2:2*1:2) = idr2(1:2*1:2)
1088 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1092 a(1:2) = cc(i-1:i+1:2, i_eps)
1094 u(1:2) = cc(i-1:i+1:2, n)
1096 cc(i, i_out) = sum(2 * idr2 * &
1097 a0*a(:)/(a0 + a(:)) * (u(:) - u0)) - &
1101 end subroutine box_vhelmh
1107 type(
mg_t),
intent(inout) :: mg
1108 integer,
intent(in) :: domain_size(1)
1109 integer,
intent(in) :: box_size
1110 real(
dp),
intent(in) :: dx(1)
1111 real(
dp),
intent(in) :: r_min(1)
1112 logical,
intent(in) :: periodic(1)
1113 integer,
intent(in) :: n_finer
1114 integer :: i, lvl, n, id, nx(1), ijk_vec(1), idim
1115 integer :: boxes_per_dim(1,
mg_lvl_lo:1)
1116 integer :: periodic_offset(1)
1118 if (modulo(box_size, 2) /= 0) &
1119 error stop
"box_size should be even"
1120 if (any(modulo(domain_size, box_size) /= 0)) &
1121 error stop
"box_size does not divide domain_size"
1123 if (all(periodic))
then
1124 mg%subtract_mean = .true.
1128 mg%box_size = box_size
1129 mg%box_size_lvl(1) = box_size
1130 mg%domain_size_lvl(:, 1) = domain_size
1131 mg%first_normal_lvl = 1
1134 mg%periodic = periodic
1135 boxes_per_dim(:, :) = 0
1136 boxes_per_dim(:, 1) = domain_size / box_size
1141 if (any(modulo(nx, 2) == 1 .or. nx == mg%coarsest_grid .or. &
1142 (mg%box_size_lvl(lvl) == mg%coarsest_grid .and. &
1145 if (all(modulo(nx/mg%box_size_lvl(lvl), 2) == 0))
then
1146 mg%box_size_lvl(lvl-1) = mg%box_size_lvl(lvl)
1147 boxes_per_dim(:, lvl-1) = boxes_per_dim(:, lvl)/2
1148 mg%first_normal_lvl = lvl-1
1150 mg%box_size_lvl(lvl-1) = mg%box_size_lvl(lvl)/2
1151 boxes_per_dim(:, lvl-1) = boxes_per_dim(:, lvl)
1154 mg%dr(:, lvl-1) = mg%dr(:, lvl) * 2
1156 mg%domain_size_lvl(:, lvl-1) = nx
1163 mg%dr(:, lvl) = mg%dr(:, lvl-1) * 0.5_dp
1164 mg%box_size_lvl(lvl) = box_size
1165 mg%domain_size_lvl(:, lvl) = 2 * mg%domain_size_lvl(:, lvl-1)
1168 n = sum(product(boxes_per_dim, dim=1)) + n_finer
1169 allocate(mg%boxes(n))
1172 nx = boxes_per_dim(:, mg%lowest_lvl)
1173 periodic_offset = [nx(1)-1]
1176 mg%n_boxes = mg%n_boxes + 1
1179 mg%boxes(n)%rank = 0
1181 mg%boxes(n)%lvl = mg%lowest_lvl
1182 mg%boxes(n)%ix(:) = [i]
1183 mg%boxes(n)%r_min(:) = r_min + (mg%boxes(n)%ix(:) - 1) * &
1184 mg%box_size_lvl(mg%lowest_lvl) * mg%dr(:, mg%lowest_lvl)
1185 mg%boxes(n)%dr(:) = mg%dr(:, mg%lowest_lvl)
1190 mg%boxes(n)%neighbors(:) = [n-1, n+1]
1195 if (ijk_vec(idim) == 1)
then
1196 if (periodic(idim))
then
1197 mg%boxes(n)%neighbors(2*idim-1) = n + periodic_offset(idim)
1203 if (ijk_vec(idim) == nx(idim))
then
1204 if (periodic(idim))
then
1205 mg%boxes(n)%neighbors(2*idim) = n - periodic_offset(idim)
1213 mg%lvls(mg%lowest_lvl)%ids = [(n, n=1, mg%n_boxes)]
1216 do lvl = mg%lowest_lvl, 0
1217 if (mg%box_size_lvl(lvl+1) == mg%box_size_lvl(lvl))
then
1218 do i = 1,
size(mg%lvls(lvl)%ids)
1219 id = mg%lvls(lvl)%ids(i)
1227 do i = 1,
size(mg%lvls(lvl)%ids)
1228 id = mg%lvls(lvl)%ids(i)
1229 call add_single_child(mg, id,
size(mg%lvls(lvl)%ids))
1240 do lvl = mg%lowest_lvl, 1
1241 if (
allocated(mg%lvls(lvl)%ref_bnds)) &
1242 deallocate(mg%lvls(lvl)%ref_bnds)
1243 allocate(mg%lvls(lvl)%ref_bnds(0))
1246 mg%tree_created = .true.
1250 type(
mg_t),
intent(inout) :: mg
1251 integer,
intent(in) :: lvl
1254 do i = 1,
size(mg%lvls(lvl)%ids)
1255 id = mg%lvls(lvl)%ids(i)
1256 call set_neighbs(mg%boxes, id)
1261 type(
mg_t),
intent(inout) :: mg
1262 integer,
intent(in) :: lvl
1265 if (
allocated(mg%lvls(lvl+1)%ids)) &
1266 deallocate(mg%lvls(lvl+1)%ids)
1269 if (mg%box_size_lvl(lvl+1) == mg%box_size_lvl(lvl))
then
1271 allocate(mg%lvls(lvl+1)%ids(n))
1274 do i = 1,
size(mg%lvls(lvl)%parents)
1275 id = mg%lvls(lvl)%parents(i)
1276 mg%lvls(lvl+1)%ids(n*(i-1)+1:n*i) = mg%boxes(id)%children
1279 n =
size(mg%lvls(lvl)%parents)
1280 allocate(mg%lvls(lvl+1)%ids(n))
1283 do i = 1,
size(mg%lvls(lvl)%parents)
1284 id = mg%lvls(lvl)%parents(i)
1285 mg%lvls(lvl+1)%ids(i) = mg%boxes(id)%children(1)
1292 subroutine set_neighbs(boxes, id)
1293 type(
mg_box_t),
intent(inout) :: boxes(:)
1294 integer,
intent(in) :: id
1295 integer :: nb, nb_id
1298 if (boxes(id)%neighbors(nb) ==
mg_no_box)
then
1299 nb_id = find_neighb(boxes, id, nb)
1301 boxes(id)%neighbors(nb) = nb_id
1306 end subroutine set_neighbs
1309 function find_neighb(boxes, id, nb)
result(nb_id)
1310 type(
mg_box_t),
intent(in) :: boxes(:)
1311 integer,
intent(in) :: id
1312 integer,
intent(in) :: nb
1313 integer :: nb_id, p_id, c_ix, d, old_pid
1315 p_id = boxes(id)%parent
1323 p_id = boxes(p_id)%neighbors(nb)
1328 end function find_neighb
1332 type(
mg_box_t),
intent(in) :: boxes(:)
1333 type(
mg_lvl_t),
intent(inout) :: level
1334 integer :: i, id, i_leaf, i_parent
1335 integer :: n_parents, n_leaves
1338 n_leaves =
size(level%ids) - n_parents
1340 if (.not.
allocated(level%parents))
then
1341 allocate(level%parents(n_parents))
1342 else if (n_parents /=
size(level%parents))
then
1343 deallocate(level%parents)
1344 allocate(level%parents(n_parents))
1347 if (.not.
allocated(level%leaves))
then
1348 allocate(level%leaves(n_leaves))
1349 else if (n_leaves /=
size(level%leaves))
then
1350 deallocate(level%leaves)
1351 allocate(level%leaves(n_leaves))
1356 do i = 1,
size(level%ids)
1359 i_parent = i_parent + 1
1360 level%parents(i_parent) = id
1363 level%leaves(i_leaf) = id
1370 type(
mg_box_t),
intent(in) :: boxes(:)
1371 type(
mg_lvl_t),
intent(inout) :: level
1372 integer,
allocatable :: tmp(:)
1373 integer :: i, id, nb, nb_id, ix
1375 if (
allocated(level%ref_bnds))
deallocate(level%ref_bnds)
1377 if (
size(level%parents) == 0)
then
1379 allocate(level%ref_bnds(0))
1381 allocate(tmp(
size(level%leaves)))
1383 do i = 1,
size(level%leaves)
1384 id = level%leaves(i)
1387 nb_id = boxes(id)%neighbors(nb)
1398 allocate(level%ref_bnds(ix))
1399 level%ref_bnds(:) = tmp(1:ix)
1404 type(
mg_t),
intent(inout) :: mg
1405 integer,
intent(in) :: id
1406 integer :: lvl, i, nb, child_nb(2**(1-1))
1408 integer :: c_id, c_ix_base(1)
1411 error stop
"mg_add_children: not enough space"
1416 mg%boxes(id)%children = c_ids
1417 c_ix_base = 2 * mg%boxes(id)%ix - 1
1418 lvl = mg%boxes(id)%lvl+1
1422 mg%boxes(c_id)%rank = mg%boxes(id)%rank
1424 mg%boxes(c_id)%lvl = lvl
1425 mg%boxes(c_id)%parent = id
1428 mg%boxes(c_id)%r_min = mg%boxes(id)%r_min + &
1430 mg%boxes(c_id)%dr(:) = mg%dr(:, lvl)
1435 if (mg%boxes(id)%neighbors(nb) <
mg_no_box)
then
1437 mg%boxes(child_nb)%neighbors(nb) = mg%boxes(id)%neighbors(nb)
1442 subroutine add_single_child(mg, id, n_boxes_lvl)
1443 type(
mg_t),
intent(inout) :: mg
1444 integer,
intent(in) :: id
1445 integer,
intent(in) :: n_boxes_lvl
1446 integer :: lvl, c_id
1448 c_id = mg%n_boxes + 1
1449 mg%n_boxes = mg%n_boxes + 1
1450 mg%boxes(id)%children(1) = c_id
1451 lvl = mg%boxes(id)%lvl+1
1453 mg%boxes(c_id)%rank = mg%boxes(id)%rank
1454 mg%boxes(c_id)%ix = mg%boxes(id)%ix
1455 mg%boxes(c_id)%lvl = lvl
1456 mg%boxes(c_id)%parent = id
1459 mg%boxes(c_id)%neighbors = mg%boxes(id)%neighbors
1461 mg%boxes(c_id)%neighbors = mg%boxes(id)%neighbors + n_boxes_lvl
1463 mg%boxes(c_id)%r_min = mg%boxes(id)%r_min
1464 mg%boxes(c_id)%dr(:) = mg%dr(:, lvl)
1466 end subroutine add_single_child
1476 type(
mg_t),
intent(inout) :: mg
1477 integer :: i, id, lvl, single_cpu_lvl
1478 integer :: work_left, my_work, i_cpu
1482 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1484 do lvl = mg%lowest_lvl, single_cpu_lvl
1485 do i = 1,
size(mg%lvls(lvl)%ids)
1486 id = mg%lvls(lvl)%ids(i)
1487 mg%boxes(id)%rank = 0
1493 do lvl = single_cpu_lvl+1, mg%highest_lvl
1494 work_left =
size(mg%lvls(lvl)%ids)
1498 do i = 1,
size(mg%lvls(lvl)%ids)
1499 if ((mg%n_cpu - i_cpu - 1) * my_work >= work_left)
then
1504 my_work = my_work + 1
1505 work_left = work_left - 1
1507 id = mg%lvls(lvl)%ids(i)
1508 mg%boxes(id)%rank = i_cpu
1512 do lvl = mg%lowest_lvl, mg%highest_lvl
1513 call update_lvl_info(mg, mg%lvls(lvl))
1525 type(
mg_t),
intent(inout) :: mg
1526 integer :: i, id, lvl, single_cpu_lvl
1527 integer :: work_left, my_work(0:mg%n_cpu), i_cpu
1530 integer :: coarse_rank
1534 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1538 do lvl = mg%highest_lvl, single_cpu_lvl+1, -1
1542 do i = 1,
size(mg%lvls(lvl)%parents)
1543 id = mg%lvls(lvl)%parents(i)
1545 c_ids = mg%boxes(id)%children
1546 c_ranks = mg%boxes(c_ids)%rank
1547 i_cpu = most_popular(c_ranks, my_work, mg%n_cpu)
1548 mg%boxes(id)%rank = i_cpu
1549 my_work(i_cpu) = my_work(i_cpu) + 1
1552 work_left =
size(mg%lvls(lvl)%leaves)
1555 do i = 1,
size(mg%lvls(lvl)%leaves)
1557 if ((mg%n_cpu - i_cpu - 1) * my_work(i_cpu) >= &
1558 work_left + sum(my_work(i_cpu+1:)))
then
1562 my_work(i_cpu) = my_work(i_cpu) + 1
1563 work_left = work_left - 1
1565 id = mg%lvls(lvl)%leaves(i)
1566 mg%boxes(id)%rank = i_cpu
1571 if (single_cpu_lvl < mg%highest_lvl)
then
1572 coarse_rank = most_popular(mg%boxes(&
1573 mg%lvls(single_cpu_lvl+1)%ids)%rank, my_work, mg%n_cpu)
1578 do lvl = mg%lowest_lvl, single_cpu_lvl
1579 do i = 1,
size(mg%lvls(lvl)%ids)
1580 id = mg%lvls(lvl)%ids(i)
1581 mg%boxes(id)%rank = coarse_rank
1585 do lvl = mg%lowest_lvl, mg%highest_lvl
1586 call update_lvl_info(mg, mg%lvls(lvl))
1594 type(
mg_t),
intent(inout) :: mg
1595 integer :: i, id, lvl, n_boxes
1598 integer :: single_cpu_lvl, coarse_rank
1599 integer :: my_work(0:mg%n_cpu), i_cpu
1600 integer,
allocatable :: ranks(:)
1604 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1606 do lvl = mg%highest_lvl-1, single_cpu_lvl+1, -1
1610 do i = 1,
size(mg%lvls(lvl)%leaves)
1611 id = mg%lvls(lvl)%leaves(i)
1612 i_cpu = mg%boxes(id)%rank
1613 my_work(i_cpu) = my_work(i_cpu) + 1
1616 do i = 1,
size(mg%lvls(lvl)%parents)
1617 id = mg%lvls(lvl)%parents(i)
1619 c_ids = mg%boxes(id)%children
1620 c_ranks = mg%boxes(c_ids)%rank
1621 i_cpu = most_popular(c_ranks, my_work, mg%n_cpu)
1622 mg%boxes(id)%rank = i_cpu
1623 my_work(i_cpu) = my_work(i_cpu) + 1
1629 if (single_cpu_lvl < mg%highest_lvl)
then
1631 n_boxes =
size(mg%lvls(single_cpu_lvl+1)%ids)
1632 allocate(ranks(n_boxes))
1633 ranks(:) = mg%boxes(mg%lvls(single_cpu_lvl+1)%ids)%rank
1635 coarse_rank = most_popular(ranks, my_work, mg%n_cpu)
1641 do lvl = mg%lowest_lvl, single_cpu_lvl
1642 do i = 1,
size(mg%lvls(lvl)%ids)
1643 id = mg%lvls(lvl)%ids(i)
1644 mg%boxes(id)%rank = coarse_rank
1648 do lvl = mg%lowest_lvl, mg%highest_lvl
1649 call update_lvl_info(mg, mg%lvls(lvl))
1656 pure integer function most_popular(list, work, n_cpu)
1657 integer,
intent(in) :: list(:)
1658 integer,
intent(in) :: n_cpu
1659 integer,
intent(in) :: work(0:n_cpu-1)
1660 integer :: i, best_count, current_count
1661 integer :: my_work, best_work
1667 do i = 1,
size(list)
1668 current_count = count(list == list(i))
1669 my_work = work(list(i))
1672 if (current_count > best_count .or. &
1673 current_count == best_count .and. my_work < best_work)
then
1674 best_count = current_count
1676 most_popular = list(i)
1680 end function most_popular
1682 subroutine update_lvl_info(mg, lvl)
1683 type(
mg_t),
intent(inout) :: mg
1684 type(
mg_lvl_t),
intent(inout) :: lvl
1686 lvl%my_ids = pack(lvl%ids, &
1687 mg%boxes(lvl%ids)%rank == mg%my_rank)
1688 lvl%my_leaves = pack(lvl%leaves, &
1689 mg%boxes(lvl%leaves)%rank == mg%my_rank)
1690 lvl%my_parents = pack(lvl%parents, &
1691 mg%boxes(lvl%parents)%rank == mg%my_rank)
1692 lvl%my_ref_bnds = pack(lvl%ref_bnds, &
1693 mg%boxes(lvl%ref_bnds)%rank == mg%my_rank)
1694 end subroutine update_lvl_info
1699 type(
mg_t),
intent(inout) :: mg
1701 if (mg%n_extra_vars == 0 .and. mg%is_allocated)
then
1702 error stop
"vlaplacian_set_methods: mg%n_extra_vars == 0"
1704 mg%n_extra_vars = max(1, mg%n_extra_vars)
1707 mg%subtract_mean = .false.
1712 mg%bc(:,
mg_iveps)%bc_value = 0.0_dp
1714 select case (mg%geometry_type)
1716 mg%box_op => box_vlpl
1721 select case (mg%smoother_type)
1723 mg%box_smoother => box_gs_vlpl
1725 error stop
"vlaplacian_set_methods: unsupported smoother type"
1729 error stop
"vlaplacian_set_methods: unsupported geometry"
1735 subroutine box_gs_vlpl(mg, id, nc, redblack_cntr)
1736 type(
mg_t),
intent(inout) :: mg
1737 integer,
intent(in) :: id
1738 integer,
intent(in) :: nc
1739 integer,
intent(in) :: redblack_cntr
1740 integer :: i, i0, di
1742 real(
dp) :: idr2(2*1), u(2*1)
1743 real(
dp) :: a0, a(2*1), c(2*1)
1746 idr2(1:2*1:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1747 idr2(2:2*1:2) = idr2(1:2*1:2)
1759 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1761 if (redblack) i0 = 2 - iand(redblack_cntr, 1)
1765 u(1:2) = cc(i-1:i+1:2, n)
1766 a(1:2) = cc(i-1:i+1:2, i_eps)
1767 c(:) = 2 * a0 * a(:) / (a0 + a(:)) * idr2
1770 (sum(c(:) * u(:)) - cc(i,
mg_irhs)) / sum(c(:))
1773 end subroutine box_gs_vlpl
1776 subroutine box_vlpl(mg, id, nc, i_out)
1777 type(
mg_t),
intent(inout) :: mg
1778 integer,
intent(in) :: id
1779 integer,
intent(in) :: nc
1780 integer,
intent(in) :: i_out
1782 real(
dp) :: idr2(2*1), a0, u0, u(2*1), a(2*1)
1785 idr2(1:2*1:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1786 idr2(2:2*1:2) = idr2(1:2*1:2)
1788 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1792 a(1:2) = cc(i-1:i+1:2, i_eps)
1794 u(1:2) = cc(i-1:i+1:2, n)
1796 cc(i, i_out) = sum(2 * idr2 * &
1797 a0*a(:)/(a0 + a(:)) * (u(:) - u0))
1800 end subroutine box_vlpl
1908 type(
mg_t),
intent(inout) :: mg
1910 integer,
intent(in),
optional :: comm
1912 logical :: initialized
1914 call mpi_initialized(initialized, ierr)
1915 if (.not. initialized)
then
1919 if (
present(comm))
then
1922 mg%comm = mpi_comm_world
1925 call mpi_comm_rank(mg%comm, mg%my_rank, ierr)
1926 call mpi_comm_size(mg%comm, mg%n_cpu, ierr)
1931 type(
mg_t),
intent(inout) :: mg
1932 integer,
intent(in) :: dsize
1933 integer :: i, n_send, n_recv
1934 integer :: send_req(mg%n_cpu)
1935 integer :: recv_req(mg%n_cpu)
1941 do i = 0, mg%n_cpu - 1
1942 if (mg%buf(i)%i_send > 0)
then
1944 call sort_sendbuf(mg%buf(i), dsize)
1945 call mpi_isend(mg%buf(i)%send, mg%buf(i)%i_send, mpi_double, &
1946 i, 0, mg%comm, send_req(n_send), ierr)
1948 if (mg%buf(i)%i_recv > 0)
then
1950 call mpi_irecv(mg%buf(i)%recv, mg%buf(i)%i_recv, mpi_double, &
1951 i, 0, mg%comm, recv_req(n_recv), ierr)
1955 call mpi_waitall(n_recv, recv_req(1:n_recv), mpi_statuses_ignore, ierr)
1956 call mpi_waitall(n_send, send_req(1:n_send), mpi_statuses_ignore, ierr)
1961 subroutine sort_sendbuf(gc, dsize)
1963 type(
mg_buf_t),
intent(inout) :: gc
1964 integer,
intent(in) :: dsize
1965 integer :: ix_sort(gc%i_ix)
1966 real(
dp) :: buf_cpy(gc%i_send)
1969 call mrgrnk(gc%ix(1:gc%i_ix), ix_sort)
1971 buf_cpy = gc%send(1:gc%i_send)
1975 j = (ix_sort(n)-1) * dsize
1976 gc%send(i+1:i+dsize) = buf_cpy(j+1:j+dsize)
1978 gc%ix(1:gc%i_ix) = gc%ix(ix_sort)
1980 end subroutine sort_sendbuf
1986 type(
mg_t),
intent(inout) :: mg
1987 integer,
intent(out) :: n_send(0:mg%n_cpu-1)
1988 integer,
intent(out) :: n_recv(0:mg%n_cpu-1)
1989 integer,
intent(out) :: dsize
1990 integer :: i, id, lvl, nc
1992 allocate(mg%comm_ghostcell%n_send(0:mg%n_cpu-1, &
1993 mg%first_normal_lvl:mg%highest_lvl))
1994 allocate(mg%comm_ghostcell%n_recv(0:mg%n_cpu-1, &
1995 mg%first_normal_lvl:mg%highest_lvl))
1997 dsize = mg%box_size**(1-1)
1999 do lvl = mg%first_normal_lvl, mg%highest_lvl
2000 nc = mg%box_size_lvl(lvl)
2001 mg%buf(:)%i_send = 0
2002 mg%buf(:)%i_recv = 0
2005 do i = 1,
size(mg%lvls(lvl)%my_ids)
2006 id = mg%lvls(lvl)%my_ids(i)
2007 call buffer_ghost_cells(mg, id, nc, 1, dry_run=.true.)
2011 do i = 1,
size(mg%lvls(lvl-1)%my_ref_bnds)
2012 id = mg%lvls(lvl-1)%my_ref_bnds(i)
2013 call buffer_refinement_boundaries(mg, id, nc, 1, dry_run=.true.)
2018 mg%buf(:)%i_recv = 0
2019 do i = 1,
size(mg%lvls(lvl)%my_ids)
2020 id = mg%lvls(lvl)%my_ids(i)
2021 call set_ghost_cells(mg, id, nc, 1, dry_run=.true.)
2024 mg%comm_ghostcell%n_send(:, lvl) = mg%buf(:)%i_send/dsize
2025 mg%comm_ghostcell%n_recv(:, lvl) = mg%buf(:)%i_recv/dsize
2028 n_send = maxval(mg%comm_ghostcell%n_send, dim=2)
2029 n_recv = maxval(mg%comm_ghostcell%n_recv, dim=2)
2035 type(
mg_t),
intent(inout) :: mg
2040 do lvl = mg%lowest_lvl, mg%highest_lvl
2041 nc = mg%box_size_lvl(lvl)
2042 call mg_phi_bc_store_lvl(mg, lvl, nc)
2045 mg%phi_bc_data_stored = .true.
2048 subroutine mg_phi_bc_store_lvl(mg, lvl, nc)
2049 type(
mg_t),
intent(inout) :: mg
2050 integer,
intent(in) :: lvl
2051 integer,
intent(in) :: nc
2053 integer :: i, id, nb, nb_id, bc_type
2055 do i = 1,
size(mg%lvls(lvl)%my_ids)
2056 id = mg%lvls(lvl)%my_ids(i)
2058 nb_id = mg%boxes(id)%neighbors(nb)
2061 if (
associated(mg%bc(nb,
mg_iphi)%boundary_cond))
then
2062 call mg%bc(nb,
mg_iphi)%boundary_cond(mg%boxes(id), nc, &
2065 bc_type = mg%bc(nb,
mg_iphi)%bc_type
2066 bc = mg%bc(nb,
mg_iphi)%bc_value
2072 mg%boxes(id)%neighbors(nb) = bc_type
2075 call box_set_gc(mg%boxes(id), nb, nc,
mg_irhs, bc)
2079 end subroutine mg_phi_bc_store_lvl
2084 integer,
intent(in) :: iv
2087 do lvl = mg%lowest_lvl, mg%highest_lvl
2096 integer,
intent(in) :: lvl
2097 integer,
intent(in) :: iv
2098 integer :: i, id, dsize, nc
2100 if (lvl < mg%lowest_lvl) &
2101 error stop
"fill_ghost_cells_lvl: lvl < lowest_lvl"
2102 if (lvl > mg%highest_lvl) &
2103 error stop
"fill_ghost_cells_lvl: lvl > highest_lvl"
2105 nc = mg%box_size_lvl(lvl)
2107 if (lvl >= mg%first_normal_lvl)
then
2109 mg%buf(:)%i_send = 0
2110 mg%buf(:)%i_recv = 0
2113 do i = 1,
size(mg%lvls(lvl)%my_ids)
2114 id = mg%lvls(lvl)%my_ids(i)
2115 call buffer_ghost_cells(mg, id, nc, iv, .false.)
2119 do i = 1,
size(mg%lvls(lvl-1)%my_ref_bnds)
2120 id = mg%lvls(lvl-1)%my_ref_bnds(i)
2121 call buffer_refinement_boundaries(mg, id, nc, iv, .false.)
2126 mg%buf(:)%i_recv = mg%comm_ghostcell%n_recv(:, lvl) * dsize
2130 mg%buf(:)%i_recv = 0
2133 do i = 1,
size(mg%lvls(lvl)%my_ids)
2134 id = mg%lvls(lvl)%my_ids(i)
2135 call set_ghost_cells(mg, id, nc, iv, .false.)
2139 subroutine buffer_ghost_cells(mg, id, nc, iv, dry_run)
2140 type(
mg_t),
intent(inout) :: mg
2141 integer,
intent(in) :: id
2142 integer,
intent(in) :: nc
2143 integer,
intent(in) :: iv
2144 logical,
intent(in) :: dry_run
2145 integer :: nb, nb_id, nb_rank
2148 nb_id = mg%boxes(id)%neighbors(nb)
2152 nb_rank = mg%boxes(nb_id)%rank
2154 if (nb_rank /= mg%my_rank)
then
2155 call buffer_for_nb(mg, mg%boxes(id), nc, iv, nb_id, nb_rank, &
2160 end subroutine buffer_ghost_cells
2162 subroutine buffer_refinement_boundaries(mg, id, nc, iv, dry_run)
2163 type(
mg_t),
intent(inout) :: mg
2164 integer,
intent(in) :: id
2165 integer,
intent(in) :: nc
2166 integer,
intent(in) :: iv
2167 logical,
intent(in) :: dry_run
2168 integer :: nb, nb_id, c_ids(2**(1-1))
2169 integer :: n, c_id, c_rank
2172 nb_id = mg%boxes(id)%neighbors(nb)
2175 c_ids = mg%boxes(nb_id)%children(&
2180 c_rank = mg%boxes(c_id)%rank
2182 if (c_rank /= mg%my_rank)
then
2184 call buffer_for_fine_nb(mg, mg%boxes(id), nc, iv, c_id, &
2185 c_rank, nb, dry_run)
2191 end subroutine buffer_refinement_boundaries
2194 subroutine set_ghost_cells(mg, id, nc, iv, dry_run)
2195 type(
mg_t),
intent(inout) :: mg
2196 integer,
intent(in) :: id
2197 integer,
intent(in) :: nc
2198 integer,
intent(in) :: iv
2199 logical,
intent(in) :: dry_run
2201 integer :: nb, nb_id, nb_rank, bc_type
2204 nb_id = mg%boxes(id)%neighbors(nb)
2208 nb_rank = mg%boxes(nb_id)%rank
2210 if (nb_rank /= mg%my_rank)
then
2211 call fill_buffered_nb(mg, mg%boxes(id), nb_rank, &
2212 nb, nc, iv, dry_run)
2213 else if (.not. dry_run)
then
2214 call copy_from_nb(mg%boxes(id), mg%boxes(nb_id), &
2219 call fill_refinement_bnd(mg, id, nb, nc, iv, dry_run)
2220 else if (.not. dry_run)
then
2222 if (mg%phi_bc_data_stored .and. iv ==
mg_iphi)
then
2225 call box_get_gc(mg%boxes(id), nb, nc,
mg_irhs, bc)
2228 if (
associated(mg%bc(nb, iv)%boundary_cond))
then
2229 call mg%bc(nb, iv)%boundary_cond(mg%boxes(id), nc, iv, &
2232 bc_type = mg%bc(nb, iv)%bc_type
2233 bc = mg%bc(nb, iv)%bc_value
2237 call box_set_gc(mg%boxes(id), nb, nc, iv, bc)
2238 call bc_to_gc(mg, id, nc, iv, nb, bc_type)
2241 end subroutine set_ghost_cells
2243 subroutine fill_refinement_bnd(mg, id, nb, nc, iv, dry_run)
2244 type(
mg_t),
intent(inout) :: mg
2245 integer,
intent(in) :: id
2246 integer,
intent(in) :: nc
2247 integer,
intent(in) :: iv
2248 integer,
intent(in) :: nb
2249 logical,
intent(in) :: dry_run
2251 integer :: p_id, p_nb_id, ix_offset(1)
2252 integer :: i, dsize, p_nb_rank
2255 p_id = mg%boxes(id)%parent
2256 p_nb_id = mg%boxes(p_id)%neighbors(nb)
2257 p_nb_rank = mg%boxes(p_nb_id)%rank
2259 if (p_nb_rank /= mg%my_rank)
then
2260 i = mg%buf(p_nb_rank)%i_recv
2261 if (.not. dry_run)
then
2262 gc = reshape(mg%buf(p_nb_rank)%recv(i+1:i+dsize), shape(gc))
2264 mg%buf(p_nb_rank)%i_recv = mg%buf(p_nb_rank)%i_recv + dsize
2265 else if (.not. dry_run)
then
2267 call box_gc_for_fine_neighbor(mg%boxes(p_nb_id),
mg_neighb_rev(nb), &
2268 ix_offset, nc, iv, gc)
2271 if (.not. dry_run)
then
2272 if (
associated(mg%bc(nb, iv)%refinement_bnd))
then
2273 call mg%bc(nb, iv)%refinement_bnd(mg%boxes(id), nc, iv, nb, gc)
2275 call sides_rb(mg%boxes(id), nc, iv, nb, gc)
2278 end subroutine fill_refinement_bnd
2280 subroutine copy_from_nb(box, box_nb, nb, nc, iv)
2281 type(
mg_box_t),
intent(inout) :: box
2282 type(
mg_box_t),
intent(in) :: box_nb
2283 integer,
intent(in) :: nb
2284 integer,
intent(in) :: nc
2285 integer,
intent(in) :: iv
2288 call box_gc_for_neighbor(box_nb,
mg_neighb_rev(nb), nc, iv, gc)
2289 call box_set_gc(box, nb, nc, iv, gc)
2290 end subroutine copy_from_nb
2292 subroutine buffer_for_nb(mg, box, nc, iv, nb_id, nb_rank, nb, dry_run)
2293 type(
mg_t),
intent(inout) :: mg
2294 type(
mg_box_t),
intent(inout) :: box
2295 integer,
intent(in) :: nc
2296 integer,
intent(in) :: iv
2297 integer,
intent(in) :: nb_id
2298 integer,
intent(in) :: nb_rank
2299 integer,
intent(in) :: nb
2300 logical,
intent(in) :: dry_run
2304 i = mg%buf(nb_rank)%i_send
2307 if (.not. dry_run)
then
2308 call box_gc_for_neighbor(box, nb, nc, iv, gc)
2309 mg%buf(nb_rank)%send(i+1:i+dsize) = pack(gc, .true.)
2314 i = mg%buf(nb_rank)%i_ix
2315 if (.not. dry_run)
then
2319 mg%buf(nb_rank)%i_send = mg%buf(nb_rank)%i_send + dsize
2320 mg%buf(nb_rank)%i_ix = mg%buf(nb_rank)%i_ix + 1
2321 end subroutine buffer_for_nb
2323 subroutine buffer_for_fine_nb(mg, box, nc, iv, fine_id, fine_rank, nb, dry_run)
2324 type(
mg_t),
intent(inout) :: mg
2325 type(
mg_box_t),
intent(inout) :: box
2326 integer,
intent(in) :: nc
2327 integer,
intent(in) :: iv
2328 integer,
intent(in) :: fine_id
2329 integer,
intent(in) :: fine_rank
2330 integer,
intent(in) :: nb
2331 logical,
intent(in) :: dry_run
2332 integer :: i, dsize, ix_offset(1)
2335 i = mg%buf(fine_rank)%i_send
2338 if (.not. dry_run)
then
2340 call box_gc_for_fine_neighbor(box, nb, ix_offset, nc, iv, gc)
2341 mg%buf(fine_rank)%send(i+1:i+dsize) = pack(gc, .true.)
2346 i = mg%buf(fine_rank)%i_ix
2347 if (.not. dry_run)
then
2352 mg%buf(fine_rank)%i_send = mg%buf(fine_rank)%i_send + dsize
2353 mg%buf(fine_rank)%i_ix = mg%buf(fine_rank)%i_ix + 1
2354 end subroutine buffer_for_fine_nb
2356 subroutine fill_buffered_nb(mg, box, nb_rank, nb, nc, iv, dry_run)
2357 type(
mg_t),
intent(inout) :: mg
2358 type(
mg_box_t),
intent(inout) :: box
2359 integer,
intent(in) :: nb_rank
2360 integer,
intent(in) :: nb
2361 integer,
intent(in) :: nc
2362 integer,
intent(in) :: iv
2363 logical,
intent(in) :: dry_run
2367 i = mg%buf(nb_rank)%i_recv
2370 if (.not. dry_run)
then
2371 gc = mg%buf(nb_rank)%recv(i+1)
2372 call box_set_gc(box, nb, nc, iv, gc)
2374 mg%buf(nb_rank)%i_recv = mg%buf(nb_rank)%i_recv + dsize
2376 end subroutine fill_buffered_nb
2378 subroutine box_gc_for_neighbor(box, nb, nc, iv, gc)
2380 integer,
intent(in) :: nb, nc, iv
2381 real(
dp),
intent(out) :: gc(1)
2389 end subroutine box_gc_for_neighbor
2392 subroutine box_gc_for_fine_neighbor(box, nb, di, nc, iv, gc)
2394 integer,
intent(in) :: nb
2395 integer,
intent(in) :: di(1)
2396 integer,
intent(in) :: nc, iv
2397 real(
dp),
intent(out) :: gc(1)
2408 tmp = box%cc(nc, iv)
2416 end subroutine box_gc_for_fine_neighbor
2418 subroutine box_get_gc(box, nb, nc, iv, gc)
2420 integer,
intent(in) :: nb, nc, iv
2421 real(
dp),
intent(out) :: gc(1)
2427 gc = box%cc(nc+1, iv)
2429 end subroutine box_get_gc
2431 subroutine box_set_gc(box, nb, nc, iv, gc)
2432 type(
mg_box_t),
intent(inout) :: box
2433 integer,
intent(in) :: nb, nc, iv
2434 real(
dp),
intent(in) :: gc(1)
2438 box%cc(0, iv) = gc(1)
2440 box%cc(nc+1, iv) = gc(1)
2442 end subroutine box_set_gc
2444 subroutine bc_to_gc(mg, id, nc, iv, nb, bc_type)
2445 type(
mg_t),
intent(inout) :: mg
2446 integer,
intent(in) :: id
2447 integer,
intent(in) :: nc
2448 integer,
intent(in) :: iv
2449 integer,
intent(in) :: nb
2450 integer,
intent(in) :: bc_type
2451 real(
dp) :: c0, c1, c2, dr
2461 select case (bc_type)
2476 error stop
"bc_to_gc: unknown boundary condition"
2481 mg%boxes(id)%cc(0, iv) = &
2482 c0 * mg%boxes(id)%cc(0, iv) + &
2483 c1 * mg%boxes(id)%cc(1, iv) + &
2484 c2 * mg%boxes(id)%cc(2, iv)
2486 mg%boxes(id)%cc(nc+1, iv) = &
2487 c0 * mg%boxes(id)%cc(nc+1, iv) + &
2488 c1 * mg%boxes(id)%cc(nc, iv) + &
2489 c2 * mg%boxes(id)%cc(nc-1, iv)
2491 end subroutine bc_to_gc
2494 subroutine sides_rb(box, nc, iv, nb, gc)
2495 type(
mg_box_t),
intent(inout) :: box
2496 integer,
intent(in) :: nc
2497 integer,
intent(in) :: iv
2498 integer,
intent(in) :: nb
2500 real(
dp),
intent(in) :: gc(1)
2502 integer :: i, ix, dix
2516 box%cc(i-di, iv) = (2 * gc(1) + box%cc(i, iv))/3.0_dp
2519 end subroutine sides_rb
2525 type(
mg_t),
intent(inout) :: mg
2526 integer,
intent(out) :: n_send(0:mg%n_cpu-1)
2527 integer,
intent(out) :: n_recv(0:mg%n_cpu-1)
2528 integer,
intent(out) :: dsize
2529 integer :: lvl, min_lvl
2531 if (.not.
allocated(mg%comm_restrict%n_send))
then
2532 error stop
"Call restrict_buffer_size before prolong_buffer_size"
2535 min_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
2536 allocate(mg%comm_prolong%n_send(0:mg%n_cpu-1, &
2537 min_lvl:mg%highest_lvl))
2538 allocate(mg%comm_prolong%n_recv(0:mg%n_cpu-1, &
2539 min_lvl:mg%highest_lvl))
2541 mg%comm_prolong%n_recv(:, mg%highest_lvl) = 0
2542 mg%comm_prolong%n_send(:, mg%highest_lvl) = 0
2544 do lvl = min_lvl, mg%highest_lvl-1
2545 mg%comm_prolong%n_recv(:, lvl) = &
2546 mg%comm_restrict%n_send(:, lvl+1)
2547 mg%comm_prolong%n_send(:, lvl) = &
2548 mg%comm_restrict%n_recv(:, lvl+1)
2553 dsize = (mg%box_size)**1
2554 n_send = maxval(mg%comm_prolong%n_send, dim=2)
2555 n_recv = maxval(mg%comm_prolong%n_recv, dim=2)
2561 type(
mg_t),
intent(inout) :: mg
2562 integer,
intent(in) :: lvl
2563 integer,
intent(in) :: iv
2564 integer,
intent(in) :: iv_to
2566 logical,
intent(in) :: add
2567 integer :: i, id, dsize, nc
2569 if (lvl == mg%highest_lvl) error stop
"cannot prolong highest level"
2570 if (lvl < mg%lowest_lvl) error stop
"cannot prolong below lowest level"
2573 if (lvl >= mg%first_normal_lvl-1)
then
2574 dsize = mg%box_size**1
2575 mg%buf(:)%i_send = 0
2578 do i = 1,
size(mg%lvls(lvl)%my_ids)
2579 id = mg%lvls(lvl)%my_ids(i)
2580 call prolong_set_buffer(mg, id, mg%box_size, iv, method)
2583 mg%buf(:)%i_recv = mg%comm_prolong%n_recv(:, lvl) * dsize
2585 mg%buf(:)%i_recv = 0
2588 nc = mg%box_size_lvl(lvl+1)
2589 do i = 1,
size(mg%lvls(lvl+1)%my_ids)
2590 id = mg%lvls(lvl+1)%my_ids(i)
2591 call prolong_onto(mg, id, nc, iv, iv_to, add, method)
2598 subroutine prolong_set_buffer(mg, id, nc, iv, method)
2599 type(
mg_t),
intent(inout) :: mg
2600 integer,
intent(in) :: id
2601 integer,
intent(in) :: nc
2602 integer,
intent(in) :: iv
2604 integer :: i, dix(1)
2605 integer :: i_c, c_id, c_rank, dsize
2611 c_id = mg%boxes(id)%children(i_c)
2613 c_rank = mg%boxes(c_id)%rank
2614 if (c_rank /= mg%my_rank)
then
2616 call method(mg, id, dix, nc, iv, tmp)
2618 i = mg%buf(c_rank)%i_send
2619 mg%buf(c_rank)%send(i+1:i+dsize) = pack(tmp, .true.)
2620 mg%buf(c_rank)%i_send = mg%buf(c_rank)%i_send + dsize
2622 i = mg%buf(c_rank)%i_ix
2623 mg%buf(c_rank)%ix(i+1) = c_id
2624 mg%buf(c_rank)%i_ix = mg%buf(c_rank)%i_ix + 1
2628 end subroutine prolong_set_buffer
2631 subroutine prolong_onto(mg, id, nc, iv, iv_to, add, method)
2632 type(
mg_t),
intent(inout) :: mg
2633 integer,
intent(in) :: id
2634 integer,
intent(in) :: nc
2635 integer,
intent(in) :: iv
2636 integer,
intent(in) :: iv_to
2637 logical,
intent(in) :: add
2639 integer :: hnc, p_id, p_rank, i, dix(1), dsize
2643 p_id = mg%boxes(id)%parent
2644 p_rank = mg%boxes(p_id)%rank
2646 if (p_rank == mg%my_rank)
then
2648 call method(mg, p_id, dix, nc, iv, tmp)
2651 i = mg%buf(p_rank)%i_recv
2652 tmp = reshape(mg%buf(p_rank)%recv(i+1:i+dsize), [nc])
2653 mg%buf(p_rank)%i_recv = mg%buf(p_rank)%i_recv + dsize
2657 mg%boxes(id)%cc(1:nc, iv_to) = &
2658 mg%boxes(id)%cc(1:nc, iv_to) + tmp
2660 mg%boxes(id)%cc(1:nc, iv_to) = tmp
2663 end subroutine prolong_onto
2667 type(
mg_t),
intent(inout) :: mg
2668 integer,
intent(in) :: p_id
2669 integer,
intent(in) :: dix(1)
2670 integer,
intent(in) :: nc
2671 integer,
intent(in) :: iv
2672 real(
dp),
intent(out) :: fine(nc)
2676 real(
dp) :: f0, flx, fhx
2680 associate(crs => mg%boxes(p_id)%cc)
2684 f0 = 0.75_dp * crs(ic, iv)
2685 flx = 0.25_dp * crs(ic-1, iv)
2686 fhx = 0.25_dp * crs(ic+1, iv)
2688 fine(2*i-1) = f0 + flx
2689 fine(2*i ) = f0 + fhx
2697 type(
mg_t),
intent(inout) :: mg
2699 mg%subtract_mean = .false.
2701 select case (mg%geometry_type)
2703 mg%box_op => box_helmh
2705 select case (mg%smoother_type)
2707 mg%box_smoother => box_gs_helmh
2709 error stop
"helmholtz_set_methods: unsupported smoother type"
2712 error stop
"helmholtz_set_methods: unsupported geometry"
2718 real(
dp),
intent(in) :: lambda
2721 error stop
"helmholtz_set_lambda: lambda < 0 not allowed"
2727 subroutine box_gs_helmh(mg, id, nc, redblack_cntr)
2728 type(
mg_t),
intent(inout) :: mg
2729 integer,
intent(in) :: id
2730 integer,
intent(in) :: nc
2731 integer,
intent(in) :: redblack_cntr
2732 integer :: i, i0, di
2733 real(
dp) :: idr2(1), fac
2736 idr2 = 1/mg%dr(:, mg%boxes(id)%lvl)**2
2749 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
2750 if (redblack) i0 = 2 - iand(redblack_cntr, 1)
2753 cc(i, n) = fac * ( &
2754 idr2(1) * (cc(i+1, n) + cc(i-1, n)) - &
2758 end subroutine box_gs_helmh
2761 subroutine box_helmh(mg, id, nc, i_out)
2762 type(
mg_t),
intent(inout) :: mg
2763 integer,
intent(in) :: id
2764 integer,
intent(in) :: nc
2765 integer,
intent(in) :: i_out
2769 idr2 = 1 / mg%dr(:, mg%boxes(id)%lvl)**2
2771 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
2774 idr2(1) * (cc(i-1, n) + cc(i+1, n) - 2 * cc(i, n)) - &
2778 end subroutine box_helmh
2784 type(
mg_t),
intent(inout) :: mg
2789 select case (mg%operator_type)
2801 error stop
"mg_set_methods: unknown operator"
2807 mg%n_smoother_substeps = 2
2809 mg%n_smoother_substeps = 1
2813 subroutine check_methods(mg)
2814 type(
mg_t),
intent(inout) :: mg
2816 if (.not.
associated(mg%box_op) .or. &
2817 .not.
associated(mg%box_smoother))
then
2821 end subroutine check_methods
2823 subroutine mg_add_timers(mg)
2824 type(
mg_t),
intent(inout) :: mg
2825 timer_total_vcycle =
mg_add_timer(mg,
"mg total V-cycle")
2826 timer_total_fmg =
mg_add_timer(mg,
"mg total FMG cycle")
2828 timer_smoother_gc =
mg_add_timer(mg,
"mg smoother g.c.")
2831 timer_update_coarse =
mg_add_timer(mg,
"mg update coarse")
2832 end subroutine mg_add_timers
2836 type(
mg_t),
intent(inout) :: mg
2837 logical,
intent(in) :: have_guess
2838 real(
dp),
intent(out),
optional :: max_res
2839 integer :: lvl, i, id
2841 call check_methods(mg)
2842 if (timer_smoother == -1)
call mg_add_timers(mg)
2846 if (.not. have_guess)
then
2847 do lvl = mg%highest_lvl, mg%lowest_lvl, -1
2848 do i = 1,
size(mg%lvls(lvl)%my_ids)
2849 id = mg%lvls(lvl)%my_ids(i)
2850 mg%boxes(id)%cc(:,
mg_iphi) = 0.0_dp
2858 do lvl = mg%highest_lvl, mg%lowest_lvl+1, -1
2861 call update_coarse(mg, lvl)
2865 if (mg%subtract_mean)
then
2867 call subtract_mean(mg,
mg_irhs, .false.)
2870 do lvl = mg%lowest_lvl, mg%highest_lvl
2872 do i = 1,
size(mg%lvls(lvl)%my_ids)
2873 id = mg%lvls(lvl)%my_ids(i)
2874 mg%boxes(id)%cc(:,
mg_iold) = &
2878 if (lvl > mg%lowest_lvl)
then
2882 call correct_children(mg, lvl-1)
2890 if (lvl == mg%highest_lvl)
then
2903 type(
mg_t),
intent(inout) :: mg
2904 integer,
intent(in),
optional :: highest_lvl
2905 real(
dp),
intent(out),
optional :: max_res
2907 logical,
intent(in),
optional :: standalone
2908 integer :: lvl, min_lvl, i, max_lvl, ierr
2909 real(
dp) :: init_res, res
2910 logical :: is_standalone
2912 is_standalone = .true.
2913 if (
present(standalone)) is_standalone = standalone
2915 call check_methods(mg)
2916 if (timer_smoother == -1)
call mg_add_timers(mg)
2918 if (is_standalone) &
2921 if (mg%subtract_mean .and. .not.
present(highest_lvl))
then
2924 call subtract_mean(mg,
mg_irhs, .false.)
2927 min_lvl = mg%lowest_lvl
2928 max_lvl = mg%highest_lvl
2929 if (
present(highest_lvl)) max_lvl = highest_lvl
2932 if (is_standalone)
then
2936 do lvl = max_lvl, min_lvl+1, -1
2938 call smooth_boxes(mg, lvl, mg%n_cycle_down)
2943 call update_coarse(mg, lvl)
2948 if (.not. all(mg%boxes(mg%lvls(min_lvl)%ids)%rank == &
2949 mg%boxes(mg%lvls(min_lvl)%ids(1))%rank))
then
2950 error stop
"Multiple CPUs for coarse grid (not implemented yet)"
2953 init_res = max_residual_lvl(mg, min_lvl)
2954 do i = 1, mg%max_coarse_cycles
2955 call smooth_boxes(mg, min_lvl, mg%n_cycle_up+mg%n_cycle_down)
2956 res = max_residual_lvl(mg, min_lvl)
2957 if (res < mg%residual_coarse_rel * init_res .or. &
2958 res < mg%residual_coarse_abs)
exit
2963 do lvl = min_lvl+1, max_lvl
2967 call correct_children(mg, lvl-1)
2974 call smooth_boxes(mg, lvl, mg%n_cycle_up)
2977 if (
present(max_res))
then
2979 do lvl = min_lvl, max_lvl
2980 res = max_residual_lvl(mg, lvl)
2981 init_res = max(res, init_res)
2983 call mpi_allreduce(init_res, max_res, 1, &
2984 mpi_double, mpi_max, mg%comm, ierr)
2988 if (mg%subtract_mean)
then
2989 call subtract_mean(mg,
mg_iphi, .true.)
2992 if (is_standalone) &
2996 subroutine subtract_mean(mg, iv, include_ghostcells)
2998 type(
mg_t),
intent(inout) :: mg
2999 integer,
intent(in) :: iv
3000 logical,
intent(in) :: include_ghostcells
3001 integer :: i, id, lvl, nc, ierr
3002 real(
dp) :: sum_iv, mean_iv, volume
3005 sum_iv = get_sum(mg, iv)
3006 call mpi_allreduce(sum_iv, mean_iv, 1, &
3007 mpi_double, mpi_sum, mg%comm, ierr)
3010 volume = nc**1 * product(mg%dr(:, 1)) *
size(mg%lvls(1)%ids)
3011 mean_iv = mean_iv / volume
3013 do lvl = mg%lowest_lvl, mg%highest_lvl
3014 nc = mg%box_size_lvl(lvl)
3016 do i = 1,
size(mg%lvls(lvl)%my_ids)
3017 id = mg%lvls(lvl)%my_ids(i)
3018 if (include_ghostcells)
then
3019 mg%boxes(id)%cc(:, iv) = &
3020 mg%boxes(id)%cc(:, iv) - mean_iv
3022 mg%boxes(id)%cc(1:nc, iv) = &
3023 mg%boxes(id)%cc(1:nc, iv) - mean_iv
3027 end subroutine subtract_mean
3029 real(
dp) function get_sum(mg, iv)
3030 type(
mg_t),
intent(in) :: mg
3031 integer,
intent(in) :: iv
3032 integer :: lvl, i, id, nc
3036 do lvl = 1, mg%highest_lvl
3037 nc = mg%box_size_lvl(lvl)
3038 w = product(mg%dr(:, lvl))
3039 do i = 1,
size(mg%lvls(lvl)%my_leaves)
3040 id = mg%lvls(lvl)%my_leaves(i)
3041 get_sum = get_sum + w * &
3042 sum(mg%boxes(id)%cc(1:nc, iv))
3045 end function get_sum
3047 real(
dp) function max_residual_lvl(mg, lvl)
3048 type(
mg_t),
intent(inout) :: mg
3049 integer,
intent(in) :: lvl
3050 integer :: i, id, nc
3053 nc = mg%box_size_lvl(lvl)
3054 max_residual_lvl = 0.0_dp
3056 do i = 1,
size(mg%lvls(lvl)%my_ids)
3057 id = mg%lvls(lvl)%my_ids(i)
3058 call residual_box(mg, id, nc)
3059 res = maxval(abs(mg%boxes(id)%cc(1:nc,
mg_ires)))
3060 max_residual_lvl = max(max_residual_lvl, res)
3062 end function max_residual_lvl
3098 subroutine update_coarse(mg, lvl)
3099 type(
mg_t),
intent(inout) :: mg
3100 integer,
intent(in) :: lvl
3101 integer :: i, id, nc, nc_c
3103 nc = mg%box_size_lvl(lvl)
3104 nc_c = mg%box_size_lvl(lvl-1)
3107 do i = 1,
size(mg%lvls(lvl)%my_ids)
3108 id = mg%lvls(lvl)%my_ids(i)
3109 call residual_box(mg, id, nc)
3120 do i = 1,
size(mg%lvls(lvl-1)%my_parents)
3121 id = mg%lvls(lvl-1)%my_parents(i)
3124 call mg%box_op(mg, id, nc_c,
mg_irhs)
3127 mg%boxes(id)%cc(1:nc_c,
mg_irhs) = &
3128 mg%boxes(id)%cc(1:nc_c,
mg_irhs) + &
3129 mg%boxes(id)%cc(1:nc_c,
mg_ires)
3132 mg%boxes(id)%cc(:,
mg_iold) = &
3135 end subroutine update_coarse
3138 subroutine correct_children(mg, lvl)
3139 type(
mg_t),
intent(inout) :: mg
3140 integer,
intent(in) :: lvl
3143 do i = 1,
size(mg%lvls(lvl)%my_parents)
3144 id = mg%lvls(lvl)%my_parents(i)
3147 mg%boxes(id)%cc(:,
mg_ires) = &
3148 mg%boxes(id)%cc(:,
mg_iphi) - &
3153 end subroutine correct_children
3155 subroutine smooth_boxes(mg, lvl, n_cycle)
3156 type(
mg_t),
intent(inout) :: mg
3157 integer,
intent(in) :: lvl
3158 integer,
intent(in) :: n_cycle
3159 integer :: n, i, id, nc
3161 nc = mg%box_size_lvl(lvl)
3163 do n = 1, n_cycle * mg%n_smoother_substeps
3165 do i = 1,
size(mg%lvls(lvl)%my_ids)
3166 id = mg%lvls(lvl)%my_ids(i)
3167 call mg%box_smoother(mg, id, nc, n)
3175 end subroutine smooth_boxes
3177 subroutine residual_box(mg, id, nc)
3178 type(
mg_t),
intent(inout) :: mg
3179 integer,
intent(in) :: id
3180 integer,
intent(in) :: nc
3182 call mg%box_op(mg, id, nc,
mg_ires)
3184 mg%boxes(id)%cc(1:nc,
mg_ires) = &
3185 mg%boxes(id)%cc(1:nc,
mg_irhs) &
3186 - mg%boxes(id)%cc(1:nc,
mg_ires)
3187 end subroutine residual_box
3191 type(
mg_t),
intent(inout) :: mg
3192 integer,
intent(in) :: i_out
3194 integer :: lvl, i, id, nc
3196 do lvl = mg%lowest_lvl, mg%highest_lvl
3197 nc = mg%box_size_lvl(lvl)
3198 do i = 1,
size(mg%lvls(lvl)%my_ids)
3199 id = mg%lvls(lvl)%my_ids(i)
3200 if (
present(op))
then
3201 call op(mg, id, nc, i_out)
3203 call mg%box_op(mg, id, nc, i_out)
3213 type(
mg_t),
intent(inout) :: mg
3214 integer,
intent(out) :: n_send(0:mg%n_cpu-1)
3215 integer,
intent(out) :: n_recv(0:mg%n_cpu-1)
3216 integer,
intent(out) :: dsize
3217 integer :: n_out(0:mg%n_cpu-1, mg%first_normal_lvl:mg%highest_lvl)
3218 integer :: n_in(0:mg%n_cpu-1, mg%first_normal_lvl:mg%highest_lvl)
3219 integer :: lvl, i, id, p_id, p_rank
3220 integer :: i_c, c_id, c_rank, min_lvl
3224 min_lvl = max(mg%lowest_lvl+1, mg%first_normal_lvl)
3226 do lvl = min_lvl, mg%highest_lvl
3228 do i = 1,
size(mg%lvls(lvl-1)%my_parents)
3229 id = mg%lvls(lvl-1)%my_parents(i)
3231 c_id = mg%boxes(id)%children(i_c)
3234 c_rank = mg%boxes(c_id)%rank
3235 if (c_rank /= mg%my_rank)
then
3236 n_in(c_rank, lvl) = n_in(c_rank, lvl) + 1
3243 do i = 1,
size(mg%lvls(lvl)%my_ids)
3244 id = mg%lvls(lvl)%my_ids(i)
3246 p_id = mg%boxes(id)%parent
3247 p_rank = mg%boxes(p_id)%rank
3248 if (p_rank /= mg%my_rank)
then
3249 n_out(p_rank, lvl) = n_out(p_rank, lvl) + 1
3255 allocate(mg%comm_restrict%n_send(0:mg%n_cpu-1, &
3256 mg%first_normal_lvl:mg%highest_lvl))
3257 allocate(mg%comm_restrict%n_recv(0:mg%n_cpu-1, &
3258 mg%first_normal_lvl:mg%highest_lvl))
3259 mg%comm_restrict%n_send = n_out
3260 mg%comm_restrict%n_recv = n_in
3262 dsize = (mg%box_size/2)**1
3263 n_send = maxval(n_out, dim=2)
3264 n_recv = maxval(n_in, dim=2)
3269 type(
mg_t),
intent(inout) :: mg
3270 integer,
intent(in) :: iv
3273 do lvl = mg%highest_lvl, mg%lowest_lvl+1, -1
3281 type(
mg_t),
intent(inout) :: mg
3282 integer,
intent(in) :: iv
3283 integer,
intent(in) :: lvl
3284 integer :: i, id, dsize, nc
3286 if (lvl <= mg%lowest_lvl) error stop
"cannot restrict lvl <= lowest_lvl"
3288 nc = mg%box_size_lvl(lvl)
3290 if (lvl >= mg%first_normal_lvl)
then
3293 mg%buf(:)%i_send = 0
3296 do i = 1,
size(mg%lvls(lvl)%my_ids)
3297 id = mg%lvls(lvl)%my_ids(i)
3298 call restrict_set_buffer(mg, id, iv)
3301 mg%buf(:)%i_recv = mg%comm_restrict%n_recv(:, lvl) * dsize
3303 mg%buf(:)%i_recv = 0
3306 do i = 1,
size(mg%lvls(lvl-1)%my_parents)
3307 id = mg%lvls(lvl-1)%my_parents(i)
3308 call restrict_onto(mg, id, nc, iv)
3312 subroutine restrict_set_buffer(mg, id, iv)
3313 type(
mg_t),
intent(inout) :: mg
3314 integer,
intent(in) :: id
3315 integer,
intent(in) :: iv
3316 integer :: i, n, hnc, p_id, p_rank
3317 real(
dp) :: tmp(mg%box_size/2)
3320 p_id = mg%boxes(id)%parent
3321 p_rank = mg%boxes(p_id)%rank
3323 if (p_rank /= mg%my_rank)
then
3326 sum(mg%boxes(id)%cc(2*i-1:2*i, iv))
3331 i = mg%buf(p_rank)%i_send
3332 mg%buf(p_rank)%send(i+1:i+n) = pack(tmp, .true.)
3333 mg%buf(p_rank)%i_send = mg%buf(p_rank)%i_send + n
3336 i = mg%buf(p_rank)%i_ix
3339 mg%buf(p_rank)%i_ix = mg%buf(p_rank)%i_ix + 1
3341 end subroutine restrict_set_buffer
3343 subroutine restrict_onto(mg, id, nc, iv)
3344 type(
mg_t),
intent(inout) :: mg
3345 integer,
intent(in) :: id
3346 integer,
intent(in) :: nc
3347 integer,
intent(in) :: iv
3348 integer :: i, hnc, dsize, i_c, c_id
3349 integer :: c_rank, dix(1)
3355 c_id = mg%boxes(id)%children(i_c)
3357 c_rank = mg%boxes(c_id)%rank
3360 if (c_rank == mg%my_rank)
then
3362 mg%boxes(id)%cc(dix(1)+i, iv) = 0.5_dp * &
3363 sum(mg%boxes(c_id)%cc(2*i-1:2*i, iv))
3366 i = mg%buf(c_rank)%i_recv
3367 mg%boxes(id)%cc(dix(1)+1:dix(1)+hnc, iv) = &
3368 reshape(mg%buf(c_rank)%recv(i+1:i+dsize), [hnc])
3369 mg%buf(c_rank)%i_recv = mg%buf(c_rank)%i_recv + dsize
3373 end subroutine restrict_onto
3377 Subroutine i_mrgrnk (XDONT, IRNGT)
3384 Integer,
Dimension (:),
Intent (In) :: XDONT
3385 Integer,
Dimension (:),
Intent (Out) :: IRNGT
3387 Integer :: XVALA, XVALB
3389 Integer,
Dimension (SIZE(IRNGT)) :: JWRKT
3390 Integer :: LMTNA, LMTNC, IRNG1, IRNG2
3391 Integer :: NVAL, IIND, IWRKD, IWRK, IWRKF, JINDA, IINDA, IINDB
3393 nval = min(
SIZE(xdont),
SIZE(irngt))
3406 Do iind = 2, nval, 2
3407 If (xdont(iind-1) <= xdont(iind))
Then
3408 irngt(iind-1) = iind - 1
3411 irngt(iind-1) = iind
3412 irngt(iind) = iind - 1
3415 If (modulo(nval, 2) /= 0)
Then
3432 Do iwrkd = 0, nval - 1, 4
3433 If ((iwrkd+4) > nval)
Then
3434 If ((iwrkd+2) >= nval)
Exit
3438 If (xdont(irngt(iwrkd+2)) <= xdont(irngt(iwrkd+3)))
Exit
3442 If (xdont(irngt(iwrkd+1)) <= xdont(irngt(iwrkd+3)))
Then
3443 irng2 = irngt(iwrkd+2)
3444 irngt(iwrkd+2) = irngt(iwrkd+3)
3445 irngt(iwrkd+3) = irng2
3450 irng1 = irngt(iwrkd+1)
3451 irngt(iwrkd+1) = irngt(iwrkd+3)
3452 irngt(iwrkd+3) = irngt(iwrkd+2)
3453 irngt(iwrkd+2) = irng1
3460 If (xdont(irngt(iwrkd+2)) <= xdont(irngt(iwrkd+3))) cycle
3464 If (xdont(irngt(iwrkd+1)) <= xdont(irngt(iwrkd+3)))
Then
3465 irng2 = irngt(iwrkd+2)
3466 irngt(iwrkd+2) = irngt(iwrkd+3)
3467 If (xdont(irng2) <= xdont(irngt(iwrkd+4)))
Then
3469 irngt(iwrkd+3) = irng2
3472 irngt(iwrkd+3) = irngt(iwrkd+4)
3473 irngt(iwrkd+4) = irng2
3479 irng1 = irngt(iwrkd+1)
3480 irng2 = irngt(iwrkd+2)
3481 irngt(iwrkd+1) = irngt(iwrkd+3)
3482 If (xdont(irng1) <= xdont(irngt(iwrkd+4)))
Then
3483 irngt(iwrkd+2) = irng1
3484 If (xdont(irng2) <= xdont(irngt(iwrkd+4)))
Then
3486 irngt(iwrkd+3) = irng2
3489 irngt(iwrkd+3) = irngt(iwrkd+4)
3490 irngt(iwrkd+4) = irng2
3494 irngt(iwrkd+2) = irngt(iwrkd+4)
3495 irngt(iwrkd+3) = irng1
3496 irngt(iwrkd+4) = irng2
3511 If (lmtna >= nval)
Exit
3520 jinda = iwrkf + lmtna
3521 iwrkf = iwrkf + lmtnc
3522 If (iwrkf >= nval)
Then
3523 If (jinda >= nval)
Exit
3539 jwrkt(1:lmtna) = irngt(iwrkd:jinda)
3541 xvala = xdont(jwrkt(iinda))
3542 xvalb = xdont(irngt(iindb))
3549 If (xvala > xvalb)
Then
3550 irngt(iwrk) = irngt(iindb)
3552 If (iindb > iwrkf)
Then
3554 irngt(iwrk+1:iwrkf) = jwrkt(iinda:lmtna)
3557 xvalb = xdont(irngt(iindb))
3559 irngt(iwrk) = jwrkt(iinda)
3561 If (iinda > lmtna) exit
3562 xvala = xdont(jwrkt(iinda))
3575 End Subroutine i_mrgrnk
3580 type(
mg_t),
intent(inout) :: mg
3582 if (mg%n_extra_vars == 0 .and. mg%is_allocated)
then
3583 error stop
"ahelmholtz_set_methods: mg%n_extra_vars == 0"
3585 mg%n_extra_vars = max(1, mg%n_extra_vars)
3595 select case (mg%geometry_type)
3597 mg%box_op => box_ahelmh
3599 select case (mg%smoother_type)
3601 mg%box_smoother => box_gs_ahelmh
3603 error stop
"ahelmholtz_set_methods: unsupported smoother type"
3606 error stop
"ahelmholtz_set_methods: unsupported geometry"
3612 real(
dp),
intent(in) :: lambda
3615 error stop
"ahelmholtz_set_lambda: lambda < 0 not allowed"
3621 subroutine box_gs_ahelmh(mg, id, nc, redblack_cntr)
3622 type(
mg_t),
intent(inout) :: mg
3623 integer,
intent(in) :: id
3624 integer,
intent(in) :: nc
3625 integer,
intent(in) :: redblack_cntr
3626 integer :: i, i0, di
3628 real(
dp) :: idr2(2*1), u(2*1)
3629 real(
dp) :: a0(2*1), a(2*1), c(2*1)
3632 idr2(1:2*1:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
3633 idr2(2:2*1:2) = idr2(1:2*1:2)
3646 if (redblack) i0 = 2 - iand(redblack_cntr, 1)
3649 a0(1:2) = cc(i, i_eps1)
3650 u(1:2) = cc(i-1:i+1:2, n)
3651 a(1:2) = cc(i-1:i+1:2, i_eps1)
3652 c(:) = 2 * a0(:) * a(:) / (a0(:) + a(:)) * idr2
3655 (sum(c(:) * u(:)) - cc(i,
mg_irhs)) / &
3659 end subroutine box_gs_ahelmh
3662 subroutine box_ahelmh(mg, id, nc, i_out)
3663 type(
mg_t),
intent(inout) :: mg
3664 integer,
intent(in) :: id
3665 integer,
intent(in) :: nc
3666 integer,
intent(in) :: i_out
3668 real(
dp) :: idr2(2*1), a0(2*1), u0, u(2*1), a(2*1)
3671 idr2(1:2*1:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
3672 idr2(2:2*1:2) = idr2(1:2*1:2)
3676 a0(1:2) = cc(i, i_eps1)
3677 a(1:2) = cc(i-1:i+1:2, i_eps1)
3679 u(1:2) = cc(i-1:i+1:2, n)
3681 cc(i, i_out) = sum(2 * idr2 * &
3682 a0(:)*a(:)/(a0(:) + a(:)) * (u(:) - u0)) - &
3686 end subroutine box_ahelmh
Subroutine that performs Gauss-Seidel relaxation.
Subroutine that performs A * cc(..., i_in) = cc(..., i_out)
Subroutine that performs prolongation to a single child.
To fill ghost cells near physical boundaries.
To fill ghost cells near refinement 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, 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, 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.
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.