30 integer,
parameter,
public ::
dp = kind(0.0d0)
33 integer,
parameter,
public ::
i8 = selected_int_kind(18)
111 integer,
parameter,
public ::
mg_child_dix(2, 4) = reshape([0,0,1,0,0,1,1,1], [2,4])
113 integer,
parameter,
public ::
mg_child_rev(4, 2) = reshape([2,1,4,3,3,4,1,2], [4,2])
115 integer,
parameter,
public ::
mg_child_adj_nb(2, 4) = reshape([1,3,2,4,1,2,3,4], [2,4])
117 logical,
parameter,
public ::
mg_child_low(2, 4) = reshape([.true., .true., &
118 .false., .true., .true., .false., .false., .false.], [2, 4])
128 integer,
parameter,
public ::
mg_neighb_dix(2, 4) = reshape([-1,0,1,0,0,-1,0,1], [2,4])
130 logical,
parameter,
public ::
mg_neighb_low(4) = [.true., .false., .true., .false.]
141 integer,
allocatable :: leaves(:)
142 integer,
allocatable :: parents(:)
143 integer,
allocatable :: ref_bnds(:)
144 integer,
allocatable :: ids(:)
145 integer,
allocatable :: my_leaves(:)
146 integer,
allocatable :: my_parents(:)
147 integer,
allocatable :: my_ref_bnds(:)
148 integer,
allocatable :: my_ids(:)
158 integer :: children(2**2)
159 integer :: neighbors(2*2)
163 real(
dp),
allocatable :: cc(:, :, :)
171 integer,
allocatable :: ix(:)
172 real(
dp),
allocatable :: send(:)
173 real(
dp),
allocatable :: recv(:)
177 integer,
allocatable :: n_send(:, :)
178 integer,
allocatable :: n_recv(:, :)
183 real(
dp) :: bc_value = 0.0_dp
185 procedure(
mg_subr_bc),
pointer,
nopass :: boundary_cond => null()
187 procedure(
mg_subr_rb),
pointer,
nopass :: refinement_bnd => null()
191 character(len=20) :: name
192 real(
dp) :: t = 0.0_dp
198 logical :: tree_created = .false.
200 logical :: is_allocated = .false.
202 integer :: n_extra_vars = 0
206 integer :: n_cpu = -1
208 integer :: my_rank = -1
210 integer :: box_size = -1
212 integer :: highest_lvl = -1
214 integer :: lowest_lvl = -1
217 integer :: first_normal_lvl = -1
219 integer :: n_boxes = 0
244 logical :: phi_bc_data_stored = .false.
247 logical :: periodic(2) = .false.
258 logical :: subtract_mean = .false.
262 integer :: n_smoother_substeps = 1
264 integer :: n_cycle_down = 2
266 integer :: n_cycle_up = 2
268 integer :: max_coarse_cycles = 1000
269 integer :: coarsest_grid(2) = 2
271 real(
dp) :: residual_coarse_abs = 1e-8_dp
273 real(
dp) :: residual_coarse_rel = 1e-8_dp
276 procedure(
mg_box_op),
pointer,
nopass :: box_op => null()
285 integer :: n_timers = 0
295 integer,
intent(in) :: nc
296 integer,
intent(in) :: iv
297 integer,
intent(in) :: nb
298 integer,
intent(out) :: bc_type
300 real(dp),
intent(out) :: bc(nc)
306 type(
mg_box_t),
intent(inout) :: box
307 integer,
intent(in) :: nc
308 integer,
intent(in) :: iv
309 integer,
intent(in) :: nb
311 real(dp),
intent(in) :: cgc(nc)
317 type(
mg_t),
intent(inout) :: mg
318 integer,
intent(in) :: id
319 integer,
intent(in) :: nc
320 integer,
intent(in) :: i_out
326 type(
mg_t),
intent(inout) :: mg
327 integer,
intent(in) :: id
328 integer,
intent(in) :: nc
329 integer,
intent(in) :: redblack_cntr
335 type(
mg_t),
intent(inout) :: mg
336 integer,
intent(in) :: p_id
337 integer,
intent(in) :: dix(2)
338 integer,
intent(in) :: nc
339 integer,
intent(in) :: iv
340 real(dp),
intent(out) :: fine(nc, nc)
453 integer :: timer_total_vcycle = -1
454 integer :: timer_total_fmg = -1
455 integer :: timer_smoother = -1
456 integer :: timer_smoother_gc = -1
457 integer :: timer_coarse = -1
458 integer :: timer_correct = -1
459 integer :: timer_update_coarse = -1
476 Integer,
Parameter :: kdp = selected_real_kind(15)
481 module procedure i_mrgrnk
511 integer,
intent(in) :: ix(2)
520 type(
mg_t),
intent(in) :: mg
521 integer,
intent(in) :: id
522 integer :: ix_offset(2)
524 if (mg%boxes(id)%lvl <= mg%first_normal_lvl)
then
527 ix_offset = iand(mg%boxes(id)%ix-1, 1) * &
528 ishft(mg%box_size, -1)
533 type(
mg_t),
intent(in) :: mg
536 do lvl = mg%first_normal_lvl, mg%highest_lvl-1
538 if (
size(mg%lvls(lvl)%leaves) /= 0 .and. &
539 size(mg%lvls(lvl)%parents) /= 0)
exit
546 type(
mg_t),
intent(in) :: mg
548 integer(i8) :: n_unknowns
551 do lvl = mg%first_normal_lvl, mg%highest_lvl
552 n_unknowns = n_unknowns +
size(mg%lvls(lvl)%leaves)
554 n_unknowns = n_unknowns * int(mg%box_size**3,
i8)
560 integer,
intent(in) :: nb
561 integer,
intent(in) :: nc
562 real(
dp),
intent(out) :: x(nc, 2)
563 integer :: i, ixs(2-1)
570 ixs = [(i, i = 1, 2-1)]
571 ixs(nb_dim:) = ixs(nb_dim:) + 1
575 rmin(nb_dim) = rmin(nb_dim) + box%dr(nb_dim) * nc
580 x(i, ixs(1)) = x(i, ixs(1)) + (i-0.5d0) * box%dr(ixs(1))
585 type(
mg_t),
intent(inout) :: mg
586 character(len=*),
intent(in) :: name
588 mg%n_timers = mg%n_timers + 1
596 timer%t0 = mpi_wtime()
602 timer%t = timer%t + mpi_wtime() - timer%t0
607 type(
mg_t),
intent(in) :: mg
609 real(
dp) :: tmin(mg%n_timers)
610 real(
dp) :: tmax(mg%n_timers)
611 real(
dp),
allocatable :: tmp_array(:)
613 allocate(tmp_array(mg%n_timers))
614 tmp_array(:) = mg%timers(1:mg%n_timers)%t
616 call mpi_reduce(tmp_array, tmin, mg%n_timers, &
617 mpi_double, mpi_min, 0, mg%comm, ierr)
618 call mpi_reduce(tmp_array, tmax, mg%n_timers, &
619 mpi_double, mpi_max, 0, mg%comm, ierr)
621 if (mg%my_rank == 0)
then
622 write(*,
"(A20,2A16)")
"name ",
"min(s)",
"max(s)"
623 do n = 1, mg%n_timers
624 write(*,
"(A20,2F16.6)") mg%timers(n)%name, &
634 type(
mg_t),
intent(inout) :: mg
637 if (.not. mg%is_allocated) &
638 error stop
"deallocate_storage: tree is not allocated"
643 deallocate(mg%comm_restrict%n_send)
644 deallocate(mg%comm_restrict%n_recv)
646 deallocate(mg%comm_prolong%n_send)
647 deallocate(mg%comm_prolong%n_recv)
649 deallocate(mg%comm_ghostcell%n_send)
650 deallocate(mg%comm_ghostcell%n_recv)
652 do lvl = mg%lowest_lvl, mg%highest_lvl
653 deallocate(mg%lvls(lvl)%ids)
654 deallocate(mg%lvls(lvl)%leaves)
655 deallocate(mg%lvls(lvl)%parents)
656 deallocate(mg%lvls(lvl)%ref_bnds)
657 deallocate(mg%lvls(lvl)%my_ids)
658 deallocate(mg%lvls(lvl)%my_leaves)
659 deallocate(mg%lvls(lvl)%my_parents)
660 deallocate(mg%lvls(lvl)%my_ref_bnds)
663 mg%is_allocated = .false.
665 mg%phi_bc_data_stored = .false.
672 type(
mg_t),
intent(inout) :: mg
673 integer :: i, id, lvl, nc
674 integer :: n_send(0:mg%n_cpu-1, 3)
675 integer :: n_recv(0:mg%n_cpu-1, 3)
677 integer :: n_in, n_out, n_id
679 if (.not. mg%tree_created) &
680 error stop
"allocate_storage: tree is not yet created"
682 if (mg%is_allocated) &
683 error stop
"allocate_storage: tree is already allocated"
685 do lvl = mg%lowest_lvl, mg%highest_lvl
686 nc = mg%box_size_lvl(lvl)
687 do i = 1,
size(mg%lvls(lvl)%my_ids)
688 id = mg%lvls(lvl)%my_ids(i)
689 allocate(mg%boxes(id)%cc(0:nc+1, 0:nc+1, &
693 mg%boxes(id)%cc(:, :, :) = 0.0_dp
697 allocate(mg%buf(0:mg%n_cpu-1))
700 n_recv(:, 1), dsize(1))
702 n_recv(:, 2), dsize(2))
704 n_recv(:, 3), dsize(3))
707 n_out = maxval(n_send(i, :) * dsize(:))
708 n_in = maxval(n_recv(i, :) * dsize(:))
709 n_id = maxval(n_send(i, :))
710 allocate(mg%buf(i)%send(n_out))
711 allocate(mg%buf(i)%recv(n_in))
712 allocate(mg%buf(i)%ix(n_id))
715 mg%is_allocated = .true.
725 type(
mg_t),
intent(inout) :: mg
726 real(
dp),
intent(in) :: dt
727 real(
dp),
intent(in) :: diffusion_coeff
728 integer,
intent(in) :: order
729 real(
dp),
intent(in) :: max_res
730 integer,
parameter :: max_its = 10
740 call set_rhs(mg, -1/(dt * diffusion_coeff), 0.0_dp)
745 call set_rhs(mg, -2/(dt * diffusion_coeff), -1.0_dp)
747 error stop
"diffusion_solve: order should be 1 or 2"
755 if (res <= max_res)
exit
759 if (n == max_its + 1)
then
760 if (mg%my_rank == 0) &
761 print *,
"Did you specify boundary conditions correctly?"
762 error stop
"diffusion_solve: no convergence"
772 type(
mg_t),
intent(inout) :: mg
773 real(
dp),
intent(in) :: dt
774 integer,
intent(in) :: order
775 real(
dp),
intent(in) :: max_res
776 integer,
parameter :: max_its = 10
786 call set_rhs(mg, -1/dt, 0.0_dp)
791 call set_rhs(mg, -2/dt, -1.0_dp)
793 error stop
"diffusion_solve: order should be 1 or 2"
801 if (res <= max_res)
exit
805 if (n == max_its + 1)
then
806 if (mg%my_rank == 0)
then
807 print *,
"Did you specify boundary conditions correctly?"
808 print *,
"Or is the variation in diffusion too large?"
810 error stop
"diffusion_solve: no convergence"
821 type(
mg_t),
intent(inout) :: mg
822 real(
dp),
intent(in) :: dt
823 integer,
intent(in) :: order
824 real(
dp),
intent(in) :: max_res
825 integer,
parameter :: max_its = 100
835 call set_rhs(mg, -1/dt, 0.0_dp)
840 call set_rhs(mg, -2/dt, -1.0_dp)
842 error stop
"diffusion_solve: order should be 1 or 2"
851 if (res <= max_res)
exit
855 if (n == max_its + 1)
then
856 if (mg%my_rank == 0)
then
857 print *,
"Did you specify boundary conditions correctly?"
858 print *,
"Or is the variation in diffusion too large?"
860 error stop
"diffusion_solve: no convergence"
864 subroutine set_rhs(mg, f1, f2)
865 type(
mg_t),
intent(inout) :: mg
866 real(
dp),
intent(in) :: f1, f2
867 integer :: lvl, i, id, nc
869 do lvl = 1, mg%highest_lvl
870 nc = mg%box_size_lvl(lvl)
871 do i = 1,
size(mg%lvls(lvl)%my_leaves)
872 id = mg%lvls(lvl)%my_leaves(i)
873 mg%boxes(id)%cc(1:nc, 1:nc,
mg_irhs) = &
874 f1 * mg%boxes(id)%cc(1:nc, 1:nc,
mg_iphi) + &
875 f2 * mg%boxes(id)%cc(1:nc, 1:nc,
mg_irhs)
878 end subroutine set_rhs
883 type(
mg_t),
intent(inout) :: mg
885 if (all(mg%periodic))
then
888 mg%subtract_mean = .true.
891 select case (mg%geometry_type)
895 select case (mg%smoother_type)
899 mg%box_smoother => box_gs_lpl
901 error stop
"laplacian_set_methods: unsupported smoother type"
904 mg%box_op => box_clpl
906 select case (mg%smoother_type)
908 mg%box_smoother => box_gs_clpl
910 error stop
"laplacian_set_methods: unsupported smoother type"
913 error stop
"laplacian_set_methods: unsupported geometry"
919 subroutine box_gs_lpl(mg, id, nc, redblack_cntr)
920 type(
mg_t),
intent(inout) :: mg
921 integer,
intent(in) :: id
922 integer,
intent(in) :: nc
923 integer,
intent(in) :: redblack_cntr
924 integer :: i, j, i0, di
925 real(
dp) :: idr2(2), fac
928 idr2 = 1/mg%dr(:, mg%boxes(id)%lvl)**2
929 fac = 0.5_dp / sum(idr2)
941 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
944 i0 = 2 - iand(ieor(redblack_cntr, j), 1)
947 cc(i, j, n) = fac * ( &
948 idr2(1) * (cc(i+1, j, n) + cc(i-1, j, n)) + &
949 idr2(2) * (cc(i, j+1, n) + cc(i, j-1, n)) - &
954 end subroutine box_gs_lpl
995 subroutine box_lpl(mg, id, nc, i_out)
996 type(
mg_t),
intent(inout) :: mg
997 integer,
intent(in) :: id
998 integer,
intent(in) :: nc
999 integer,
intent(in) :: i_out
1003 idr2 = 1 / mg%dr(:, mg%boxes(id)%lvl)**2
1005 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
1009 idr2(1) * (cc(i-1, j, n) + cc(i+1, j, n) - 2 * cc(i, j, n)) + &
1010 idr2(2) * (cc(i, j-1, n) + cc(i, j+1, n) - 2 * cc(i, j, n))
1014 end subroutine box_lpl
1018 subroutine box_clpl(mg, id, nc, i_out)
1019 type(
mg_t),
intent(inout) :: mg
1020 integer,
intent(in) :: id
1021 integer,
intent(in) :: nc
1022 integer,
intent(in) :: i_out
1024 real(
dp) :: dr(2), idr2(2)
1025 real(
dp) :: r_face(nc+1), r_inv(nc)
1027 dr = mg%dr(:, mg%boxes(id)%lvl)
1029 r_face = mg%boxes(id)%r_min(1) + dr(1) * [(i, i=0,nc)]
1030 r_inv = 1/(mg%boxes(id)%r_min(1) + dr(1) * [(i-0.5_dp, i=1,nc)])
1032 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
1035 cc(i, j, i_out) = idr2(1) * (&
1036 r_face(i) * r_inv(i) * cc(i-1, j, n) + &
1037 r_face(i+1) * r_inv(i) * cc(i+1, j, n) &
1038 - 2 * cc(i, j, n)) &
1039 + idr2(2) * (cc(i, j-1, n) + cc(i, j+1, n) - 2 * cc(i, j, n))
1043 end subroutine box_clpl
1048 subroutine box_gs_clpl(mg, id, nc, redblack_cntr)
1049 type(
mg_t),
intent(inout) :: mg
1050 integer,
intent(in) :: id
1051 integer,
intent(in) :: nc
1052 integer,
intent(in) :: redblack_cntr
1053 integer :: i, j, i0, di
1055 real(
dp) :: idr2(2), dr(2), dr2(2), fac
1056 real(
dp) :: r_face(nc+1), r_inv(nc)
1058 dr = mg%dr(:, mg%boxes(id)%lvl)
1061 fac = 0.5_dp / sum(idr2)
1062 r_face = mg%boxes(id)%r_min(1) + dr(1) * [(i, i=0,nc)]
1063 r_inv = 1/(mg%boxes(id)%r_min(1) + dr(1) * [(i-0.5_dp, i=1,nc)])
1075 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
1078 i0 = 2 - iand(ieor(redblack_cntr, j), 1)
1081 cc(i, j, n) = fac * (idr2(1) * &
1082 (r_face(i+1) * r_inv(i) * cc(i+1, j, n) + &
1083 r_face(i) * r_inv(i) * cc(i-1, j, n)) + &
1084 idr2(2) * (cc(i, j+1, n) + cc(i, j-1, n)) &
1089 end subroutine box_gs_clpl
1094 type(
mg_t),
intent(inout) :: mg
1096 if (mg%n_extra_vars == 0 .and. mg%is_allocated)
then
1097 error stop
"vhelmholtz_set_methods: mg%n_extra_vars == 0"
1099 mg%n_extra_vars = max(1, mg%n_extra_vars)
1102 mg%subtract_mean = .false.
1107 mg%bc(:,
mg_iveps)%bc_value = 0.0_dp
1109 select case (mg%geometry_type)
1111 mg%box_op => box_vhelmh
1113 select case (mg%smoother_type)
1115 mg%box_smoother => box_gs_vhelmh
1117 error stop
"vhelmholtz_set_methods: unsupported smoother type"
1120 error stop
"vhelmholtz_set_methods: unsupported geometry"
1126 real(
dp),
intent(in) :: lambda
1129 error stop
"vhelmholtz_set_lambda: lambda < 0 not allowed"
1135 subroutine box_gs_vhelmh(mg, id, nc, redblack_cntr)
1136 type(
mg_t),
intent(inout) :: mg
1137 integer,
intent(in) :: id
1138 integer,
intent(in) :: nc
1139 integer,
intent(in) :: redblack_cntr
1140 integer :: i, j, i0, di
1142 real(
dp) :: idr2(2*2), u(2*2)
1143 real(
dp) :: a0, a(2*2), c(2*2)
1146 idr2(1:2*2:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1147 idr2(2:2*2:2) = idr2(1:2*2:2)
1159 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1163 i0 = 2 - iand(ieor(redblack_cntr, j), 1)
1166 a0 = cc(i, j, i_eps)
1167 u(1:2) = cc(i-1:i+1:2, j, n)
1168 a(1:2) = cc(i-1:i+1:2, j, i_eps)
1169 u(3:4) = cc(i, j-1:j+1:2, n)
1170 a(3:4) = cc(i, j-1:j+1:2, i_eps)
1171 c(:) = 2 * a0 * a(:) / (a0 + a(:)) * idr2
1174 (sum(c(:) * u(:)) - cc(i, j,
mg_irhs)) / &
1179 end subroutine box_gs_vhelmh
1182 subroutine box_vhelmh(mg, id, nc, i_out)
1183 type(
mg_t),
intent(inout) :: mg
1184 integer,
intent(in) :: id
1185 integer,
intent(in) :: nc
1186 integer,
intent(in) :: i_out
1188 real(
dp) :: idr2(2*2), a0, u0, u(2*2), a(2*2)
1191 idr2(1:2*2:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1192 idr2(2:2*2:2) = idr2(1:2*2:2)
1194 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1198 a0 = cc(i, j, i_eps)
1199 a(1:2) = cc(i-1:i+1:2, j, i_eps)
1200 a(3:4) = cc(i, j-1:j+1:2, i_eps)
1202 u(1:2) = cc(i-1:i+1:2, j, n)
1203 u(3:4) = cc(i, j-1:j+1:2, n)
1205 cc(i, j, i_out) = sum(2 * idr2 * &
1206 a0*a(:)/(a0 + a(:)) * (u(:) - u0)) - &
1211 end subroutine box_vhelmh
1217 type(
mg_t),
intent(inout) :: mg
1218 integer,
intent(in) :: domain_size(2)
1219 integer,
intent(in) :: box_size
1220 real(
dp),
intent(in) :: dx(2)
1221 real(
dp),
intent(in) :: r_min(2)
1222 logical,
intent(in) :: periodic(2)
1223 integer,
intent(in) :: n_finer
1224 integer :: i, j, lvl, n, id, nx(2), ijk_vec(2), idim
1225 integer :: boxes_per_dim(2,
mg_lvl_lo:1)
1226 integer :: periodic_offset(2)
1228 if (modulo(box_size, 2) /= 0) &
1229 error stop
"box_size should be even"
1230 if (any(modulo(domain_size, box_size) /= 0)) &
1231 error stop
"box_size does not divide domain_size"
1233 if (all(periodic))
then
1234 mg%subtract_mean = .true.
1238 mg%box_size = box_size
1239 mg%box_size_lvl(1) = box_size
1240 mg%domain_size_lvl(:, 1) = domain_size
1241 mg%first_normal_lvl = 1
1244 mg%periodic = periodic
1245 boxes_per_dim(:, :) = 0
1246 boxes_per_dim(:, 1) = domain_size / box_size
1251 if (any(modulo(nx, 2) == 1 .or. nx == mg%coarsest_grid .or. &
1252 (mg%box_size_lvl(lvl) == mg%coarsest_grid .and. &
1255 if (all(modulo(nx/mg%box_size_lvl(lvl), 2) == 0))
then
1256 mg%box_size_lvl(lvl-1) = mg%box_size_lvl(lvl)
1257 boxes_per_dim(:, lvl-1) = boxes_per_dim(:, lvl)/2
1258 mg%first_normal_lvl = lvl-1
1260 mg%box_size_lvl(lvl-1) = mg%box_size_lvl(lvl)/2
1261 boxes_per_dim(:, lvl-1) = boxes_per_dim(:, lvl)
1264 mg%dr(:, lvl-1) = mg%dr(:, lvl) * 2
1266 mg%domain_size_lvl(:, lvl-1) = nx
1273 mg%dr(:, lvl) = mg%dr(:, lvl-1) * 0.5_dp
1274 mg%box_size_lvl(lvl) = box_size
1275 mg%domain_size_lvl(:, lvl) = 2 * mg%domain_size_lvl(:, lvl-1)
1278 n = sum(product(boxes_per_dim, dim=1)) + n_finer
1279 allocate(mg%boxes(n))
1282 nx = boxes_per_dim(:, mg%lowest_lvl)
1283 periodic_offset = [nx(1)-1, (nx(2)-1)*nx(1)]
1285 do j=1,nx(2);
do i=1,nx(1)
1286 mg%n_boxes = mg%n_boxes + 1
1289 mg%boxes(n)%rank = 0
1291 mg%boxes(n)%lvl = mg%lowest_lvl
1292 mg%boxes(n)%ix(:) = [i, j]
1293 mg%boxes(n)%r_min(:) = r_min + (mg%boxes(n)%ix(:) - 1) * &
1294 mg%box_size_lvl(mg%lowest_lvl) * mg%dr(:, mg%lowest_lvl)
1295 mg%boxes(n)%dr(:) = mg%dr(:, mg%lowest_lvl)
1300 mg%boxes(n)%neighbors(:) = [n-1, n+1, n-nx(1), n+nx(1)]
1305 if (ijk_vec(idim) == 1)
then
1306 if (periodic(idim))
then
1307 mg%boxes(n)%neighbors(2*idim-1) = n + periodic_offset(idim)
1313 if (ijk_vec(idim) == nx(idim))
then
1314 if (periodic(idim))
then
1315 mg%boxes(n)%neighbors(2*idim) = n - periodic_offset(idim)
1323 mg%lvls(mg%lowest_lvl)%ids = [(n, n=1, mg%n_boxes)]
1326 do lvl = mg%lowest_lvl, 0
1327 if (mg%box_size_lvl(lvl+1) == mg%box_size_lvl(lvl))
then
1328 do i = 1,
size(mg%lvls(lvl)%ids)
1329 id = mg%lvls(lvl)%ids(i)
1337 do i = 1,
size(mg%lvls(lvl)%ids)
1338 id = mg%lvls(lvl)%ids(i)
1339 call add_single_child(mg, id,
size(mg%lvls(lvl)%ids))
1350 do lvl = mg%lowest_lvl, 1
1351 if (
allocated(mg%lvls(lvl)%ref_bnds)) &
1352 deallocate(mg%lvls(lvl)%ref_bnds)
1353 allocate(mg%lvls(lvl)%ref_bnds(0))
1356 mg%tree_created = .true.
1360 type(
mg_t),
intent(inout) :: mg
1361 integer,
intent(in) :: lvl
1364 do i = 1,
size(mg%lvls(lvl)%ids)
1365 id = mg%lvls(lvl)%ids(i)
1366 call set_neighbs(mg%boxes, id)
1371 type(
mg_t),
intent(inout) :: mg
1372 integer,
intent(in) :: lvl
1375 if (
allocated(mg%lvls(lvl+1)%ids)) &
1376 deallocate(mg%lvls(lvl+1)%ids)
1379 if (mg%box_size_lvl(lvl+1) == mg%box_size_lvl(lvl))
then
1381 allocate(mg%lvls(lvl+1)%ids(n))
1384 do i = 1,
size(mg%lvls(lvl)%parents)
1385 id = mg%lvls(lvl)%parents(i)
1386 mg%lvls(lvl+1)%ids(n*(i-1)+1:n*i) = mg%boxes(id)%children
1389 n =
size(mg%lvls(lvl)%parents)
1390 allocate(mg%lvls(lvl+1)%ids(n))
1393 do i = 1,
size(mg%lvls(lvl)%parents)
1394 id = mg%lvls(lvl)%parents(i)
1395 mg%lvls(lvl+1)%ids(i) = mg%boxes(id)%children(1)
1402 subroutine set_neighbs(boxes, id)
1403 type(
mg_box_t),
intent(inout) :: boxes(:)
1404 integer,
intent(in) :: id
1405 integer :: nb, nb_id
1408 if (boxes(id)%neighbors(nb) ==
mg_no_box)
then
1409 nb_id = find_neighb(boxes, id, nb)
1411 boxes(id)%neighbors(nb) = nb_id
1416 end subroutine set_neighbs
1419 function find_neighb(boxes, id, nb)
result(nb_id)
1420 type(
mg_box_t),
intent(in) :: boxes(:)
1421 integer,
intent(in) :: id
1422 integer,
intent(in) :: nb
1423 integer :: nb_id, p_id, c_ix, d, old_pid
1425 p_id = boxes(id)%parent
1433 p_id = boxes(p_id)%neighbors(nb)
1438 end function find_neighb
1442 type(
mg_box_t),
intent(in) :: boxes(:)
1443 type(
mg_lvl_t),
intent(inout) :: level
1444 integer :: i, id, i_leaf, i_parent
1445 integer :: n_parents, n_leaves
1448 n_leaves =
size(level%ids) - n_parents
1450 if (.not.
allocated(level%parents))
then
1451 allocate(level%parents(n_parents))
1452 else if (n_parents /=
size(level%parents))
then
1453 deallocate(level%parents)
1454 allocate(level%parents(n_parents))
1457 if (.not.
allocated(level%leaves))
then
1458 allocate(level%leaves(n_leaves))
1459 else if (n_leaves /=
size(level%leaves))
then
1460 deallocate(level%leaves)
1461 allocate(level%leaves(n_leaves))
1466 do i = 1,
size(level%ids)
1469 i_parent = i_parent + 1
1470 level%parents(i_parent) = id
1473 level%leaves(i_leaf) = id
1480 type(
mg_box_t),
intent(in) :: boxes(:)
1481 type(
mg_lvl_t),
intent(inout) :: level
1482 integer,
allocatable :: tmp(:)
1483 integer :: i, id, nb, nb_id, ix
1485 if (
allocated(level%ref_bnds))
deallocate(level%ref_bnds)
1487 if (
size(level%parents) == 0)
then
1489 allocate(level%ref_bnds(0))
1491 allocate(tmp(
size(level%leaves)))
1493 do i = 1,
size(level%leaves)
1494 id = level%leaves(i)
1497 nb_id = boxes(id)%neighbors(nb)
1508 allocate(level%ref_bnds(ix))
1509 level%ref_bnds(:) = tmp(1:ix)
1514 type(
mg_t),
intent(inout) :: mg
1515 integer,
intent(in) :: id
1516 integer :: lvl, i, nb, child_nb(2**(2-1))
1518 integer :: c_id, c_ix_base(2)
1521 error stop
"mg_add_children: not enough space"
1526 mg%boxes(id)%children = c_ids
1527 c_ix_base = 2 * mg%boxes(id)%ix - 1
1528 lvl = mg%boxes(id)%lvl+1
1532 mg%boxes(c_id)%rank = mg%boxes(id)%rank
1534 mg%boxes(c_id)%lvl = lvl
1535 mg%boxes(c_id)%parent = id
1538 mg%boxes(c_id)%r_min = mg%boxes(id)%r_min + &
1540 mg%boxes(c_id)%dr(:) = mg%dr(:, lvl)
1545 if (mg%boxes(id)%neighbors(nb) <
mg_no_box)
then
1547 mg%boxes(child_nb)%neighbors(nb) = mg%boxes(id)%neighbors(nb)
1552 subroutine add_single_child(mg, id, n_boxes_lvl)
1553 type(
mg_t),
intent(inout) :: mg
1554 integer,
intent(in) :: id
1555 integer,
intent(in) :: n_boxes_lvl
1556 integer :: lvl, c_id
1558 c_id = mg%n_boxes + 1
1559 mg%n_boxes = mg%n_boxes + 1
1560 mg%boxes(id)%children(1) = c_id
1561 lvl = mg%boxes(id)%lvl+1
1563 mg%boxes(c_id)%rank = mg%boxes(id)%rank
1564 mg%boxes(c_id)%ix = mg%boxes(id)%ix
1565 mg%boxes(c_id)%lvl = lvl
1566 mg%boxes(c_id)%parent = id
1569 mg%boxes(c_id)%neighbors = mg%boxes(id)%neighbors
1571 mg%boxes(c_id)%neighbors = mg%boxes(id)%neighbors + n_boxes_lvl
1573 mg%boxes(c_id)%r_min = mg%boxes(id)%r_min
1574 mg%boxes(c_id)%dr(:) = mg%dr(:, lvl)
1576 end subroutine add_single_child
1586 type(
mg_t),
intent(inout) :: mg
1587 integer :: i, id, lvl, single_cpu_lvl
1588 integer :: work_left, my_work, i_cpu
1592 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1594 do lvl = mg%lowest_lvl, single_cpu_lvl
1595 do i = 1,
size(mg%lvls(lvl)%ids)
1596 id = mg%lvls(lvl)%ids(i)
1597 mg%boxes(id)%rank = 0
1603 do lvl = single_cpu_lvl+1, mg%highest_lvl
1604 work_left =
size(mg%lvls(lvl)%ids)
1608 do i = 1,
size(mg%lvls(lvl)%ids)
1609 if ((mg%n_cpu - i_cpu - 1) * my_work >= work_left)
then
1614 my_work = my_work + 1
1615 work_left = work_left - 1
1617 id = mg%lvls(lvl)%ids(i)
1618 mg%boxes(id)%rank = i_cpu
1622 do lvl = mg%lowest_lvl, mg%highest_lvl
1623 call update_lvl_info(mg, mg%lvls(lvl))
1635 type(
mg_t),
intent(inout) :: mg
1636 integer :: i, id, lvl, single_cpu_lvl
1637 integer :: work_left, my_work(0:mg%n_cpu), i_cpu
1640 integer :: coarse_rank
1644 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1648 do lvl = mg%highest_lvl, single_cpu_lvl+1, -1
1652 do i = 1,
size(mg%lvls(lvl)%parents)
1653 id = mg%lvls(lvl)%parents(i)
1655 c_ids = mg%boxes(id)%children
1656 c_ranks = mg%boxes(c_ids)%rank
1657 i_cpu = most_popular(c_ranks, my_work, mg%n_cpu)
1658 mg%boxes(id)%rank = i_cpu
1659 my_work(i_cpu) = my_work(i_cpu) + 1
1662 work_left =
size(mg%lvls(lvl)%leaves)
1665 do i = 1,
size(mg%lvls(lvl)%leaves)
1667 if ((mg%n_cpu - i_cpu - 1) * my_work(i_cpu) >= &
1668 work_left + sum(my_work(i_cpu+1:)))
then
1672 my_work(i_cpu) = my_work(i_cpu) + 1
1673 work_left = work_left - 1
1675 id = mg%lvls(lvl)%leaves(i)
1676 mg%boxes(id)%rank = i_cpu
1681 if (single_cpu_lvl < mg%highest_lvl)
then
1682 coarse_rank = most_popular(mg%boxes(&
1683 mg%lvls(single_cpu_lvl+1)%ids)%rank, my_work, mg%n_cpu)
1688 do lvl = mg%lowest_lvl, single_cpu_lvl
1689 do i = 1,
size(mg%lvls(lvl)%ids)
1690 id = mg%lvls(lvl)%ids(i)
1691 mg%boxes(id)%rank = coarse_rank
1695 do lvl = mg%lowest_lvl, mg%highest_lvl
1696 call update_lvl_info(mg, mg%lvls(lvl))
1704 type(
mg_t),
intent(inout) :: mg
1705 integer :: i, id, lvl, n_boxes
1708 integer :: single_cpu_lvl, coarse_rank
1709 integer :: my_work(0:mg%n_cpu), i_cpu
1710 integer,
allocatable :: ranks(:)
1714 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1716 do lvl = mg%highest_lvl-1, single_cpu_lvl+1, -1
1720 do i = 1,
size(mg%lvls(lvl)%leaves)
1721 id = mg%lvls(lvl)%leaves(i)
1722 i_cpu = mg%boxes(id)%rank
1723 my_work(i_cpu) = my_work(i_cpu) + 1
1726 do i = 1,
size(mg%lvls(lvl)%parents)
1727 id = mg%lvls(lvl)%parents(i)
1729 c_ids = mg%boxes(id)%children
1730 c_ranks = mg%boxes(c_ids)%rank
1731 i_cpu = most_popular(c_ranks, my_work, mg%n_cpu)
1732 mg%boxes(id)%rank = i_cpu
1733 my_work(i_cpu) = my_work(i_cpu) + 1
1739 if (single_cpu_lvl < mg%highest_lvl)
then
1741 n_boxes =
size(mg%lvls(single_cpu_lvl+1)%ids)
1742 allocate(ranks(n_boxes))
1743 ranks(:) = mg%boxes(mg%lvls(single_cpu_lvl+1)%ids)%rank
1745 coarse_rank = most_popular(ranks, my_work, mg%n_cpu)
1751 do lvl = mg%lowest_lvl, single_cpu_lvl
1752 do i = 1,
size(mg%lvls(lvl)%ids)
1753 id = mg%lvls(lvl)%ids(i)
1754 mg%boxes(id)%rank = coarse_rank
1758 do lvl = mg%lowest_lvl, mg%highest_lvl
1759 call update_lvl_info(mg, mg%lvls(lvl))
1766 pure integer function most_popular(list, work, n_cpu)
1767 integer,
intent(in) :: list(:)
1768 integer,
intent(in) :: n_cpu
1769 integer,
intent(in) :: work(0:n_cpu-1)
1770 integer :: i, best_count, current_count
1771 integer :: my_work, best_work
1777 do i = 1,
size(list)
1778 current_count = count(list == list(i))
1779 my_work = work(list(i))
1782 if (current_count > best_count .or. &
1783 current_count == best_count .and. my_work < best_work)
then
1784 best_count = current_count
1786 most_popular = list(i)
1790 end function most_popular
1792 subroutine update_lvl_info(mg, lvl)
1793 type(
mg_t),
intent(inout) :: mg
1794 type(
mg_lvl_t),
intent(inout) :: lvl
1796 lvl%my_ids = pack(lvl%ids, &
1797 mg%boxes(lvl%ids)%rank == mg%my_rank)
1798 lvl%my_leaves = pack(lvl%leaves, &
1799 mg%boxes(lvl%leaves)%rank == mg%my_rank)
1800 lvl%my_parents = pack(lvl%parents, &
1801 mg%boxes(lvl%parents)%rank == mg%my_rank)
1802 lvl%my_ref_bnds = pack(lvl%ref_bnds, &
1803 mg%boxes(lvl%ref_bnds)%rank == mg%my_rank)
1804 end subroutine update_lvl_info
1809 type(
mg_t),
intent(inout) :: mg
1811 if (mg%n_extra_vars == 0 .and. mg%is_allocated)
then
1812 error stop
"vlaplacian_set_methods: mg%n_extra_vars == 0"
1814 mg%n_extra_vars = max(1, mg%n_extra_vars)
1817 mg%subtract_mean = .false.
1822 mg%bc(:,
mg_iveps)%bc_value = 0.0_dp
1824 select case (mg%geometry_type)
1826 mg%box_op => box_vlpl
1831 select case (mg%smoother_type)
1833 mg%box_smoother => box_gs_vlpl
1835 error stop
"vlaplacian_set_methods: unsupported smoother type"
1839 error stop
"vlaplacian_set_methods: unsupported geometry"
1845 subroutine box_gs_vlpl(mg, id, nc, redblack_cntr)
1846 type(
mg_t),
intent(inout) :: mg
1847 integer,
intent(in) :: id
1848 integer,
intent(in) :: nc
1849 integer,
intent(in) :: redblack_cntr
1850 integer :: i, j, i0, di
1852 real(
dp) :: idr2(2*2), u(2*2)
1853 real(
dp) :: a0, a(2*2), c(2*2)
1856 idr2(1:2*2:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1857 idr2(2:2*2:2) = idr2(1:2*2:2)
1869 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1873 i0 = 2 - iand(ieor(redblack_cntr, j), 1)
1876 a0 = cc(i, j, i_eps)
1877 u(1:2) = cc(i-1:i+1:2, j, n)
1878 a(1:2) = cc(i-1:i+1:2, j, i_eps)
1879 u(3:4) = cc(i, j-1:j+1:2, n)
1880 a(3:4) = cc(i, j-1:j+1:2, i_eps)
1881 c(:) = 2 * a0 * a(:) / (a0 + a(:)) * idr2
1884 (sum(c(:) * u(:)) - cc(i, j,
mg_irhs)) / sum(c(:))
1888 end subroutine box_gs_vlpl
1891 subroutine box_vlpl(mg, id, nc, i_out)
1892 type(
mg_t),
intent(inout) :: mg
1893 integer,
intent(in) :: id
1894 integer,
intent(in) :: nc
1895 integer,
intent(in) :: i_out
1897 real(
dp) :: idr2(2*2), a0, u0, u(2*2), a(2*2)
1900 idr2(1:2*2:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1901 idr2(2:2*2:2) = idr2(1:2*2:2)
1903 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
1907 a0 = cc(i, j, i_eps)
1908 a(1:2) = cc(i-1:i+1:2, j, i_eps)
1909 a(3:4) = cc(i, j-1:j+1:2, i_eps)
1911 u(1:2) = cc(i-1:i+1:2, j, n)
1912 u(3:4) = cc(i, j-1:j+1:2, n)
1914 cc(i, j, i_out) = sum(2 * idr2 * &
1915 a0*a(:)/(a0 + a(:)) * (u(:) - u0))
1919 end subroutine box_vlpl
2027 type(
mg_t),
intent(inout) :: mg
2029 integer,
intent(in),
optional :: comm
2031 logical :: initialized
2033 call mpi_initialized(initialized, ierr)
2034 if (.not. initialized)
then
2038 if (
present(comm))
then
2041 mg%comm = mpi_comm_world
2044 call mpi_comm_rank(mg%comm, mg%my_rank, ierr)
2045 call mpi_comm_size(mg%comm, mg%n_cpu, ierr)
2050 type(
mg_t),
intent(inout) :: mg
2051 integer,
intent(in) :: dsize
2052 integer :: i, n_send, n_recv
2053 integer :: send_req(mg%n_cpu)
2054 integer :: recv_req(mg%n_cpu)
2060 do i = 0, mg%n_cpu - 1
2061 if (mg%buf(i)%i_send > 0)
then
2063 call sort_sendbuf(mg%buf(i), dsize)
2064 call mpi_isend(mg%buf(i)%send, mg%buf(i)%i_send, mpi_double, &
2065 i, 0, mg%comm, send_req(n_send), ierr)
2067 if (mg%buf(i)%i_recv > 0)
then
2069 call mpi_irecv(mg%buf(i)%recv, mg%buf(i)%i_recv, mpi_double, &
2070 i, 0, mg%comm, recv_req(n_recv), ierr)
2074 call mpi_waitall(n_recv, recv_req(1:n_recv), mpi_statuses_ignore, ierr)
2075 call mpi_waitall(n_send, send_req(1:n_send), mpi_statuses_ignore, ierr)
2080 subroutine sort_sendbuf(gc, dsize)
2082 type(
mg_buf_t),
intent(inout) :: gc
2083 integer,
intent(in) :: dsize
2084 integer :: ix_sort(gc%i_ix)
2085 real(
dp) :: buf_cpy(gc%i_send)
2088 call mrgrnk(gc%ix(1:gc%i_ix), ix_sort)
2090 buf_cpy = gc%send(1:gc%i_send)
2094 j = (ix_sort(n)-1) * dsize
2095 gc%send(i+1:i+dsize) = buf_cpy(j+1:j+dsize)
2097 gc%ix(1:gc%i_ix) = gc%ix(ix_sort)
2099 end subroutine sort_sendbuf
2105 type(
mg_t),
intent(inout) :: mg
2106 integer,
intent(out) :: n_send(0:mg%n_cpu-1)
2107 integer,
intent(out) :: n_recv(0:mg%n_cpu-1)
2108 integer,
intent(out) :: dsize
2109 integer :: i, id, lvl, nc
2111 allocate(mg%comm_ghostcell%n_send(0:mg%n_cpu-1, &
2112 mg%first_normal_lvl:mg%highest_lvl))
2113 allocate(mg%comm_ghostcell%n_recv(0:mg%n_cpu-1, &
2114 mg%first_normal_lvl:mg%highest_lvl))
2116 dsize = mg%box_size**(2-1)
2118 do lvl = mg%first_normal_lvl, mg%highest_lvl
2119 nc = mg%box_size_lvl(lvl)
2120 mg%buf(:)%i_send = 0
2121 mg%buf(:)%i_recv = 0
2124 do i = 1,
size(mg%lvls(lvl)%my_ids)
2125 id = mg%lvls(lvl)%my_ids(i)
2126 call buffer_ghost_cells(mg, id, nc, 1, dry_run=.true.)
2130 do i = 1,
size(mg%lvls(lvl-1)%my_ref_bnds)
2131 id = mg%lvls(lvl-1)%my_ref_bnds(i)
2132 call buffer_refinement_boundaries(mg, id, nc, 1, dry_run=.true.)
2137 mg%buf(:)%i_recv = 0
2138 do i = 1,
size(mg%lvls(lvl)%my_ids)
2139 id = mg%lvls(lvl)%my_ids(i)
2140 call set_ghost_cells(mg, id, nc, 1, dry_run=.true.)
2143 mg%comm_ghostcell%n_send(:, lvl) = mg%buf(:)%i_send/dsize
2144 mg%comm_ghostcell%n_recv(:, lvl) = mg%buf(:)%i_recv/dsize
2147 n_send = maxval(mg%comm_ghostcell%n_send, dim=2)
2148 n_recv = maxval(mg%comm_ghostcell%n_recv, dim=2)
2154 type(
mg_t),
intent(inout) :: mg
2159 do lvl = mg%lowest_lvl, mg%highest_lvl
2160 nc = mg%box_size_lvl(lvl)
2161 call mg_phi_bc_store_lvl(mg, lvl, nc)
2164 mg%phi_bc_data_stored = .true.
2167 subroutine mg_phi_bc_store_lvl(mg, lvl, nc)
2168 type(
mg_t),
intent(inout) :: mg
2169 integer,
intent(in) :: lvl
2170 integer,
intent(in) :: nc
2172 integer :: i, id, nb, nb_id, bc_type
2174 do i = 1,
size(mg%lvls(lvl)%my_ids)
2175 id = mg%lvls(lvl)%my_ids(i)
2177 nb_id = mg%boxes(id)%neighbors(nb)
2180 if (
associated(mg%bc(nb,
mg_iphi)%boundary_cond))
then
2181 call mg%bc(nb,
mg_iphi)%boundary_cond(mg%boxes(id), nc, &
2184 bc_type = mg%bc(nb,
mg_iphi)%bc_type
2185 bc = mg%bc(nb,
mg_iphi)%bc_value
2191 mg%boxes(id)%neighbors(nb) = bc_type
2194 call box_set_gc(mg%boxes(id), nb, nc,
mg_irhs, bc)
2198 end subroutine mg_phi_bc_store_lvl
2203 integer,
intent(in) :: iv
2206 do lvl = mg%lowest_lvl, mg%highest_lvl
2215 integer,
intent(in) :: lvl
2216 integer,
intent(in) :: iv
2217 integer :: i, id, dsize, nc
2219 if (lvl < mg%lowest_lvl) &
2220 error stop
"fill_ghost_cells_lvl: lvl < lowest_lvl"
2221 if (lvl > mg%highest_lvl) &
2222 error stop
"fill_ghost_cells_lvl: lvl > highest_lvl"
2224 nc = mg%box_size_lvl(lvl)
2226 if (lvl >= mg%first_normal_lvl)
then
2228 mg%buf(:)%i_send = 0
2229 mg%buf(:)%i_recv = 0
2232 do i = 1,
size(mg%lvls(lvl)%my_ids)
2233 id = mg%lvls(lvl)%my_ids(i)
2234 call buffer_ghost_cells(mg, id, nc, iv, .false.)
2238 do i = 1,
size(mg%lvls(lvl-1)%my_ref_bnds)
2239 id = mg%lvls(lvl-1)%my_ref_bnds(i)
2240 call buffer_refinement_boundaries(mg, id, nc, iv, .false.)
2245 mg%buf(:)%i_recv = mg%comm_ghostcell%n_recv(:, lvl) * dsize
2249 mg%buf(:)%i_recv = 0
2252 do i = 1,
size(mg%lvls(lvl)%my_ids)
2253 id = mg%lvls(lvl)%my_ids(i)
2254 call set_ghost_cells(mg, id, nc, iv, .false.)
2258 subroutine buffer_ghost_cells(mg, id, nc, iv, dry_run)
2259 type(
mg_t),
intent(inout) :: mg
2260 integer,
intent(in) :: id
2261 integer,
intent(in) :: nc
2262 integer,
intent(in) :: iv
2263 logical,
intent(in) :: dry_run
2264 integer :: nb, nb_id, nb_rank
2267 nb_id = mg%boxes(id)%neighbors(nb)
2271 nb_rank = mg%boxes(nb_id)%rank
2273 if (nb_rank /= mg%my_rank)
then
2274 call buffer_for_nb(mg, mg%boxes(id), nc, iv, nb_id, nb_rank, &
2279 end subroutine buffer_ghost_cells
2281 subroutine buffer_refinement_boundaries(mg, id, nc, iv, dry_run)
2282 type(
mg_t),
intent(inout) :: mg
2283 integer,
intent(in) :: id
2284 integer,
intent(in) :: nc
2285 integer,
intent(in) :: iv
2286 logical,
intent(in) :: dry_run
2287 integer :: nb, nb_id, c_ids(2**(2-1))
2288 integer :: n, c_id, c_rank
2291 nb_id = mg%boxes(id)%neighbors(nb)
2294 c_ids = mg%boxes(nb_id)%children(&
2299 c_rank = mg%boxes(c_id)%rank
2301 if (c_rank /= mg%my_rank)
then
2303 call buffer_for_fine_nb(mg, mg%boxes(id), nc, iv, c_id, &
2304 c_rank, nb, dry_run)
2310 end subroutine buffer_refinement_boundaries
2313 subroutine set_ghost_cells(mg, id, nc, iv, dry_run)
2314 type(
mg_t),
intent(inout) :: mg
2315 integer,
intent(in) :: id
2316 integer,
intent(in) :: nc
2317 integer,
intent(in) :: iv
2318 logical,
intent(in) :: dry_run
2320 integer :: nb, nb_id, nb_rank, bc_type
2323 nb_id = mg%boxes(id)%neighbors(nb)
2327 nb_rank = mg%boxes(nb_id)%rank
2329 if (nb_rank /= mg%my_rank)
then
2330 call fill_buffered_nb(mg, mg%boxes(id), nb_rank, &
2331 nb, nc, iv, dry_run)
2332 else if (.not. dry_run)
then
2333 call copy_from_nb(mg%boxes(id), mg%boxes(nb_id), &
2338 call fill_refinement_bnd(mg, id, nb, nc, iv, dry_run)
2339 else if (.not. dry_run)
then
2341 if (mg%phi_bc_data_stored .and. iv ==
mg_iphi)
then
2344 call box_get_gc(mg%boxes(id), nb, nc,
mg_irhs, bc)
2347 if (
associated(mg%bc(nb, iv)%boundary_cond))
then
2348 call mg%bc(nb, iv)%boundary_cond(mg%boxes(id), nc, iv, &
2351 bc_type = mg%bc(nb, iv)%bc_type
2352 bc = mg%bc(nb, iv)%bc_value
2356 call box_set_gc(mg%boxes(id), nb, nc, iv, bc)
2357 call bc_to_gc(mg, id, nc, iv, nb, bc_type)
2360 end subroutine set_ghost_cells
2362 subroutine fill_refinement_bnd(mg, id, nb, nc, iv, dry_run)
2363 type(
mg_t),
intent(inout) :: mg
2364 integer,
intent(in) :: id
2365 integer,
intent(in) :: nc
2366 integer,
intent(in) :: iv
2367 integer,
intent(in) :: nb
2368 logical,
intent(in) :: dry_run
2370 integer :: p_id, p_nb_id, ix_offset(2)
2371 integer :: i, dsize, p_nb_rank
2374 p_id = mg%boxes(id)%parent
2375 p_nb_id = mg%boxes(p_id)%neighbors(nb)
2376 p_nb_rank = mg%boxes(p_nb_id)%rank
2378 if (p_nb_rank /= mg%my_rank)
then
2379 i = mg%buf(p_nb_rank)%i_recv
2380 if (.not. dry_run)
then
2381 gc = reshape(mg%buf(p_nb_rank)%recv(i+1:i+dsize), shape(gc))
2383 mg%buf(p_nb_rank)%i_recv = mg%buf(p_nb_rank)%i_recv + dsize
2384 else if (.not. dry_run)
then
2386 call box_gc_for_fine_neighbor(mg%boxes(p_nb_id),
mg_neighb_rev(nb), &
2387 ix_offset, nc, iv, gc)
2390 if (.not. dry_run)
then
2391 if (
associated(mg%bc(nb, iv)%refinement_bnd))
then
2392 call mg%bc(nb, iv)%refinement_bnd(mg%boxes(id), nc, iv, nb, gc)
2394 call sides_rb(mg%boxes(id), nc, iv, nb, gc)
2397 end subroutine fill_refinement_bnd
2399 subroutine copy_from_nb(box, box_nb, nb, nc, iv)
2400 type(
mg_box_t),
intent(inout) :: box
2401 type(
mg_box_t),
intent(in) :: box_nb
2402 integer,
intent(in) :: nb
2403 integer,
intent(in) :: nc
2404 integer,
intent(in) :: iv
2407 call box_gc_for_neighbor(box_nb,
mg_neighb_rev(nb), nc, iv, gc)
2408 call box_set_gc(box, nb, nc, iv, gc)
2409 end subroutine copy_from_nb
2411 subroutine buffer_for_nb(mg, box, nc, iv, nb_id, nb_rank, nb, dry_run)
2412 type(
mg_t),
intent(inout) :: mg
2413 type(
mg_box_t),
intent(inout) :: box
2414 integer,
intent(in) :: nc
2415 integer,
intent(in) :: iv
2416 integer,
intent(in) :: nb_id
2417 integer,
intent(in) :: nb_rank
2418 integer,
intent(in) :: nb
2419 logical,
intent(in) :: dry_run
2423 i = mg%buf(nb_rank)%i_send
2426 if (.not. dry_run)
then
2427 call box_gc_for_neighbor(box, nb, nc, iv, gc)
2428 mg%buf(nb_rank)%send(i+1:i+dsize) = pack(gc, .true.)
2433 i = mg%buf(nb_rank)%i_ix
2434 if (.not. dry_run)
then
2438 mg%buf(nb_rank)%i_send = mg%buf(nb_rank)%i_send + dsize
2439 mg%buf(nb_rank)%i_ix = mg%buf(nb_rank)%i_ix + 1
2440 end subroutine buffer_for_nb
2442 subroutine buffer_for_fine_nb(mg, box, nc, iv, fine_id, fine_rank, nb, dry_run)
2443 type(
mg_t),
intent(inout) :: mg
2444 type(
mg_box_t),
intent(inout) :: box
2445 integer,
intent(in) :: nc
2446 integer,
intent(in) :: iv
2447 integer,
intent(in) :: fine_id
2448 integer,
intent(in) :: fine_rank
2449 integer,
intent(in) :: nb
2450 logical,
intent(in) :: dry_run
2451 integer :: i, dsize, ix_offset(2)
2454 i = mg%buf(fine_rank)%i_send
2457 if (.not. dry_run)
then
2459 call box_gc_for_fine_neighbor(box, nb, ix_offset, nc, iv, gc)
2460 mg%buf(fine_rank)%send(i+1:i+dsize) = pack(gc, .true.)
2465 i = mg%buf(fine_rank)%i_ix
2466 if (.not. dry_run)
then
2471 mg%buf(fine_rank)%i_send = mg%buf(fine_rank)%i_send + dsize
2472 mg%buf(fine_rank)%i_ix = mg%buf(fine_rank)%i_ix + 1
2473 end subroutine buffer_for_fine_nb
2475 subroutine fill_buffered_nb(mg, box, nb_rank, nb, nc, iv, dry_run)
2476 type(
mg_t),
intent(inout) :: mg
2477 type(
mg_box_t),
intent(inout) :: box
2478 integer,
intent(in) :: nb_rank
2479 integer,
intent(in) :: nb
2480 integer,
intent(in) :: nc
2481 integer,
intent(in) :: iv
2482 logical,
intent(in) :: dry_run
2486 i = mg%buf(nb_rank)%i_recv
2489 if (.not. dry_run)
then
2490 gc = reshape(mg%buf(nb_rank)%recv(i+1:i+dsize), shape(gc))
2491 call box_set_gc(box, nb, nc, iv, gc)
2493 mg%buf(nb_rank)%i_recv = mg%buf(nb_rank)%i_recv + dsize
2495 end subroutine fill_buffered_nb
2497 subroutine box_gc_for_neighbor(box, nb, nc, iv, gc)
2499 integer,
intent(in) :: nb, nc, iv
2500 real(
dp),
intent(out) :: gc(nc)
2504 gc = box%cc(1, 1:nc, iv)
2506 gc = box%cc(nc, 1:nc, iv)
2508 gc = box%cc(1:nc, 1, iv)
2510 gc = box%cc(1:nc, nc, iv)
2512 end subroutine box_gc_for_neighbor
2515 subroutine box_gc_for_fine_neighbor(box, nb, di, nc, iv, gc)
2517 integer,
intent(in) :: nb
2518 integer,
intent(in) :: di(2)
2519 integer,
intent(in) :: nc, iv
2520 real(
dp),
intent(out) :: gc(nc)
2521 real(
dp) :: tmp(0:nc/2+1), grad(2-1)
2529 tmp = box%cc(1, di(2):di(2)+hnc+1, iv)
2531 tmp = box%cc(nc, di(2):di(2)+hnc+1, iv)
2533 tmp = box%cc(di(1):di(1)+hnc+1, 1, iv)
2535 tmp = box%cc(di(1):di(1)+hnc+1, nc, iv)
2543 grad(1) = 0.125_dp * (tmp(i+1) - tmp(i-1))
2544 gc(2*i-1) = tmp(i) - grad(1)
2545 gc(2*i) = tmp(i) + grad(1)
2547 end subroutine box_gc_for_fine_neighbor
2549 subroutine box_get_gc(box, nb, nc, iv, gc)
2551 integer,
intent(in) :: nb, nc, iv
2552 real(
dp),
intent(out) :: gc(nc)
2556 gc = box%cc(0, 1:nc, iv)
2558 gc = box%cc(nc+1, 1:nc, iv)
2560 gc = box%cc(1:nc, 0, iv)
2562 gc = box%cc(1:nc, nc+1, iv)
2564 end subroutine box_get_gc
2566 subroutine box_set_gc(box, nb, nc, iv, gc)
2567 type(
mg_box_t),
intent(inout) :: box
2568 integer,
intent(in) :: nb, nc, iv
2569 real(
dp),
intent(in) :: gc(nc)
2573 box%cc(0, 1:nc, iv) = gc
2575 box%cc(nc+1, 1:nc, iv) = gc
2577 box%cc(1:nc, 0, iv) = gc
2579 box%cc(1:nc, nc+1, iv) = gc
2581 end subroutine box_set_gc
2583 subroutine bc_to_gc(mg, id, nc, iv, nb, bc_type)
2584 type(
mg_t),
intent(inout) :: mg
2585 integer,
intent(in) :: id
2586 integer,
intent(in) :: nc
2587 integer,
intent(in) :: iv
2588 integer,
intent(in) :: nb
2589 integer,
intent(in) :: bc_type
2590 real(
dp) :: c0, c1, c2, dr
2600 select case (bc_type)
2615 error stop
"bc_to_gc: unknown boundary condition"
2620 mg%boxes(id)%cc(0, 1:nc, iv) = &
2621 c0 * mg%boxes(id)%cc(0, 1:nc, iv) + &
2622 c1 * mg%boxes(id)%cc(1, 1:nc, iv) + &
2623 c2 * mg%boxes(id)%cc(2, 1:nc, iv)
2625 mg%boxes(id)%cc(nc+1, 1:nc, iv) = &
2626 c0 * mg%boxes(id)%cc(nc+1, 1:nc, iv) + &
2627 c1 * mg%boxes(id)%cc(nc, 1:nc, iv) + &
2628 c2 * mg%boxes(id)%cc(nc-1, 1:nc, iv)
2630 mg%boxes(id)%cc(1:nc, 0, iv) = &
2631 c0 * mg%boxes(id)%cc(1:nc, 0, iv) + &
2632 c1 * mg%boxes(id)%cc(1:nc, 1, iv) + &
2633 c2 * mg%boxes(id)%cc(1:nc, 2, iv)
2635 mg%boxes(id)%cc(1:nc, nc+1, iv) = &
2636 c0 * mg%boxes(id)%cc(1:nc, nc+1, iv) + &
2637 c1 * mg%boxes(id)%cc(1:nc, nc, iv) + &
2638 c2 * mg%boxes(id)%cc(1:nc, nc-1, iv)
2640 end subroutine bc_to_gc
2643 subroutine sides_rb(box, nc, iv, nb, gc)
2644 type(
mg_box_t),
intent(inout) :: box
2645 integer,
intent(in) :: nc
2646 integer,
intent(in) :: iv
2647 integer,
intent(in) :: nb
2649 real(
dp),
intent(in) :: gc(nc)
2651 integer :: i, j, ix, dix
2667 dj = -1 + 2 * iand(j, 1)
2668 box%cc(i-di, j, iv) = 0.5_dp * gc(j) &
2669 + 0.75_dp * box%cc(i, j, iv) &
2670 - 0.25_dp * box%cc(i+di, j, iv)
2676 di = -1 + 2 * iand(i, 1)
2677 box%cc(i, j-dj, iv) = 0.5_dp * gc(i) &
2678 + 0.75_dp * box%cc(i, j, iv) &
2679 - 0.25_dp * box%cc(i, j+dj, iv)
2683 end subroutine sides_rb
2689 type(
mg_t),
intent(inout) :: mg
2690 integer,
intent(out) :: n_send(0:mg%n_cpu-1)
2691 integer,
intent(out) :: n_recv(0:mg%n_cpu-1)
2692 integer,
intent(out) :: dsize
2693 integer :: lvl, min_lvl
2695 if (.not.
allocated(mg%comm_restrict%n_send))
then
2696 error stop
"Call restrict_buffer_size before prolong_buffer_size"
2699 min_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
2700 allocate(mg%comm_prolong%n_send(0:mg%n_cpu-1, &
2701 min_lvl:mg%highest_lvl))
2702 allocate(mg%comm_prolong%n_recv(0:mg%n_cpu-1, &
2703 min_lvl:mg%highest_lvl))
2705 mg%comm_prolong%n_recv(:, mg%highest_lvl) = 0
2706 mg%comm_prolong%n_send(:, mg%highest_lvl) = 0
2708 do lvl = min_lvl, mg%highest_lvl-1
2709 mg%comm_prolong%n_recv(:, lvl) = &
2710 mg%comm_restrict%n_send(:, lvl+1)
2711 mg%comm_prolong%n_send(:, lvl) = &
2712 mg%comm_restrict%n_recv(:, lvl+1)
2717 dsize = (mg%box_size)**2
2718 n_send = maxval(mg%comm_prolong%n_send, dim=2)
2719 n_recv = maxval(mg%comm_prolong%n_recv, dim=2)
2725 type(
mg_t),
intent(inout) :: mg
2726 integer,
intent(in) :: lvl
2727 integer,
intent(in) :: iv
2728 integer,
intent(in) :: iv_to
2730 logical,
intent(in) :: add
2731 integer :: i, id, dsize, nc
2733 if (lvl == mg%highest_lvl) error stop
"cannot prolong highest level"
2734 if (lvl < mg%lowest_lvl) error stop
"cannot prolong below lowest level"
2737 if (lvl >= mg%first_normal_lvl-1)
then
2738 dsize = mg%box_size**2
2739 mg%buf(:)%i_send = 0
2742 do i = 1,
size(mg%lvls(lvl)%my_ids)
2743 id = mg%lvls(lvl)%my_ids(i)
2744 call prolong_set_buffer(mg, id, mg%box_size, iv, method)
2747 mg%buf(:)%i_recv = mg%comm_prolong%n_recv(:, lvl) * dsize
2749 mg%buf(:)%i_recv = 0
2752 nc = mg%box_size_lvl(lvl+1)
2753 do i = 1,
size(mg%lvls(lvl+1)%my_ids)
2754 id = mg%lvls(lvl+1)%my_ids(i)
2755 call prolong_onto(mg, id, nc, iv, iv_to, add, method)
2762 subroutine prolong_set_buffer(mg, id, nc, iv, method)
2763 type(
mg_t),
intent(inout) :: mg
2764 integer,
intent(in) :: id
2765 integer,
intent(in) :: nc
2766 integer,
intent(in) :: iv
2768 integer :: i, dix(2)
2769 integer :: i_c, c_id, c_rank, dsize
2770 real(
dp) :: tmp(nc, nc)
2775 c_id = mg%boxes(id)%children(i_c)
2777 c_rank = mg%boxes(c_id)%rank
2778 if (c_rank /= mg%my_rank)
then
2780 call method(mg, id, dix, nc, iv, tmp)
2782 i = mg%buf(c_rank)%i_send
2783 mg%buf(c_rank)%send(i+1:i+dsize) = pack(tmp, .true.)
2784 mg%buf(c_rank)%i_send = mg%buf(c_rank)%i_send + dsize
2786 i = mg%buf(c_rank)%i_ix
2787 mg%buf(c_rank)%ix(i+1) = c_id
2788 mg%buf(c_rank)%i_ix = mg%buf(c_rank)%i_ix + 1
2792 end subroutine prolong_set_buffer
2795 subroutine prolong_onto(mg, id, nc, iv, iv_to, add, method)
2796 type(
mg_t),
intent(inout) :: mg
2797 integer,
intent(in) :: id
2798 integer,
intent(in) :: nc
2799 integer,
intent(in) :: iv
2800 integer,
intent(in) :: iv_to
2801 logical,
intent(in) :: add
2803 integer :: hnc, p_id, p_rank, i, dix(2), dsize
2804 real(
dp) :: tmp(nc, nc)
2807 p_id = mg%boxes(id)%parent
2808 p_rank = mg%boxes(p_id)%rank
2810 if (p_rank == mg%my_rank)
then
2812 call method(mg, p_id, dix, nc, iv, tmp)
2815 i = mg%buf(p_rank)%i_recv
2816 tmp = reshape(mg%buf(p_rank)%recv(i+1:i+dsize), [nc, nc])
2817 mg%buf(p_rank)%i_recv = mg%buf(p_rank)%i_recv + dsize
2821 mg%boxes(id)%cc(1:nc, 1:nc, iv_to) = &
2822 mg%boxes(id)%cc(1:nc, 1:nc, iv_to) + tmp
2824 mg%boxes(id)%cc(1:nc, 1:nc, iv_to) = tmp
2827 end subroutine prolong_onto
2831 type(
mg_t),
intent(inout) :: mg
2832 integer,
intent(in) :: p_id
2833 integer,
intent(in) :: dix(2)
2834 integer,
intent(in) :: nc
2835 integer,
intent(in) :: iv
2836 real(
dp),
intent(out) :: fine(nc, nc)
2838 integer :: i, j, hnc
2840 real(
dp) :: f0, flx, fhx, fly, fhy
2844 associate(crs => mg%boxes(p_id)%cc)
2850 f0 = 0.5_dp * crs(ic, jc, iv)
2851 flx = 0.25_dp * crs(ic-1, jc, iv)
2852 fhx = 0.25_dp * crs(ic+1, jc, iv)
2853 fly = 0.25_dp * crs(ic, jc-1, iv)
2854 fhy = 0.25_dp * crs(ic, jc+1, iv)
2856 fine(2*i-1, 2*j-1) = f0 + flx + fly
2857 fine(2*i , 2*j-1) = f0 + fhx + fly
2858 fine(2*i-1, 2*j) = f0 + flx + fhy
2859 fine(2*i , 2*j) = f0 + fhx + fhy
2868 type(
mg_t),
intent(inout) :: mg
2870 mg%subtract_mean = .false.
2872 select case (mg%geometry_type)
2874 mg%box_op => box_helmh
2876 select case (mg%smoother_type)
2878 mg%box_smoother => box_gs_helmh
2880 error stop
"helmholtz_set_methods: unsupported smoother type"
2883 error stop
"helmholtz_set_methods: unsupported geometry"
2889 real(
dp),
intent(in) :: lambda
2892 error stop
"helmholtz_set_lambda: lambda < 0 not allowed"
2898 subroutine box_gs_helmh(mg, id, nc, redblack_cntr)
2899 type(
mg_t),
intent(inout) :: mg
2900 integer,
intent(in) :: id
2901 integer,
intent(in) :: nc
2902 integer,
intent(in) :: redblack_cntr
2903 integer :: i, j, i0, di
2904 real(
dp) :: idr2(2), fac
2907 idr2 = 1/mg%dr(:, mg%boxes(id)%lvl)**2
2920 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
2923 i0 = 2 - iand(ieor(redblack_cntr, j), 1)
2926 cc(i, j, n) = fac * ( &
2927 idr2(1) * (cc(i+1, j, n) + cc(i-1, j, n)) + &
2928 idr2(2) * (cc(i, j+1, n) + cc(i, j-1, n)) - &
2933 end subroutine box_gs_helmh
2936 subroutine box_helmh(mg, id, nc, i_out)
2937 type(
mg_t),
intent(inout) :: mg
2938 integer,
intent(in) :: id
2939 integer,
intent(in) :: nc
2940 integer,
intent(in) :: i_out
2944 idr2 = 1 / mg%dr(:, mg%boxes(id)%lvl)**2
2946 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi)
2950 idr2(1) * (cc(i-1, j, n) + cc(i+1, j, n) - 2 * cc(i, j, n)) + &
2951 idr2(2) * (cc(i, j-1, n) + cc(i, j+1, n) - 2 * cc(i, j, n)) - &
2956 end subroutine box_helmh
2962 type(
mg_t),
intent(inout) :: mg
2967 select case (mg%operator_type)
2979 error stop
"mg_set_methods: unknown operator"
2985 mg%n_smoother_substeps = 2
2987 mg%n_smoother_substeps = 1
2991 subroutine check_methods(mg)
2992 type(
mg_t),
intent(inout) :: mg
2994 if (.not.
associated(mg%box_op) .or. &
2995 .not.
associated(mg%box_smoother))
then
2999 end subroutine check_methods
3001 subroutine mg_add_timers(mg)
3002 type(
mg_t),
intent(inout) :: mg
3003 timer_total_vcycle =
mg_add_timer(mg,
"mg total V-cycle")
3004 timer_total_fmg =
mg_add_timer(mg,
"mg total FMG cycle")
3006 timer_smoother_gc =
mg_add_timer(mg,
"mg smoother g.c.")
3009 timer_update_coarse =
mg_add_timer(mg,
"mg update coarse")
3010 end subroutine mg_add_timers
3014 type(
mg_t),
intent(inout) :: mg
3015 logical,
intent(in) :: have_guess
3016 real(
dp),
intent(out),
optional :: max_res
3017 integer :: lvl, i, id
3019 call check_methods(mg)
3020 if (timer_smoother == -1)
call mg_add_timers(mg)
3024 if (.not. have_guess)
then
3025 do lvl = mg%highest_lvl, mg%lowest_lvl, -1
3026 do i = 1,
size(mg%lvls(lvl)%my_ids)
3027 id = mg%lvls(lvl)%my_ids(i)
3028 mg%boxes(id)%cc(:, :,
mg_iphi) = 0.0_dp
3036 do lvl = mg%highest_lvl, mg%lowest_lvl+1, -1
3039 call update_coarse(mg, lvl)
3043 if (mg%subtract_mean)
then
3045 call subtract_mean(mg,
mg_irhs, .false.)
3048 do lvl = mg%lowest_lvl, mg%highest_lvl
3050 do i = 1,
size(mg%lvls(lvl)%my_ids)
3051 id = mg%lvls(lvl)%my_ids(i)
3052 mg%boxes(id)%cc(:, :,
mg_iold) = &
3053 mg%boxes(id)%cc(:, :,
mg_iphi)
3056 if (lvl > mg%lowest_lvl)
then
3060 call correct_children(mg, lvl-1)
3068 if (lvl == mg%highest_lvl)
then
3081 type(
mg_t),
intent(inout) :: mg
3082 integer,
intent(in),
optional :: highest_lvl
3083 real(
dp),
intent(out),
optional :: max_res
3085 logical,
intent(in),
optional :: standalone
3086 integer :: lvl, min_lvl, i, max_lvl, ierr
3087 real(
dp) :: init_res, res
3088 logical :: is_standalone
3090 is_standalone = .true.
3091 if (
present(standalone)) is_standalone = standalone
3093 call check_methods(mg)
3094 if (timer_smoother == -1)
call mg_add_timers(mg)
3096 if (is_standalone) &
3099 if (mg%subtract_mean .and. .not.
present(highest_lvl))
then
3102 call subtract_mean(mg,
mg_irhs, .false.)
3105 min_lvl = mg%lowest_lvl
3106 max_lvl = mg%highest_lvl
3107 if (
present(highest_lvl)) max_lvl = highest_lvl
3110 if (is_standalone)
then
3114 do lvl = max_lvl, min_lvl+1, -1
3116 call smooth_boxes(mg, lvl, mg%n_cycle_down)
3121 call update_coarse(mg, lvl)
3126 if (.not. all(mg%boxes(mg%lvls(min_lvl)%ids)%rank == &
3127 mg%boxes(mg%lvls(min_lvl)%ids(1))%rank))
then
3128 error stop
"Multiple CPUs for coarse grid (not implemented yet)"
3131 init_res = max_residual_lvl(mg, min_lvl)
3132 do i = 1, mg%max_coarse_cycles
3133 call smooth_boxes(mg, min_lvl, mg%n_cycle_up+mg%n_cycle_down)
3134 res = max_residual_lvl(mg, min_lvl)
3135 if (res < mg%residual_coarse_rel * init_res .or. &
3136 res < mg%residual_coarse_abs)
exit
3141 do lvl = min_lvl+1, max_lvl
3145 call correct_children(mg, lvl-1)
3152 call smooth_boxes(mg, lvl, mg%n_cycle_up)
3155 if (
present(max_res))
then
3157 do lvl = min_lvl, max_lvl
3158 res = max_residual_lvl(mg, lvl)
3159 init_res = max(res, init_res)
3161 call mpi_allreduce(init_res, max_res, 1, &
3162 mpi_double, mpi_max, mg%comm, ierr)
3166 if (mg%subtract_mean)
then
3167 call subtract_mean(mg,
mg_iphi, .true.)
3170 if (is_standalone) &
3174 subroutine subtract_mean(mg, iv, include_ghostcells)
3176 type(
mg_t),
intent(inout) :: mg
3177 integer,
intent(in) :: iv
3178 logical,
intent(in) :: include_ghostcells
3179 integer :: i, id, lvl, nc, ierr
3180 real(
dp) :: sum_iv, mean_iv, volume
3183 sum_iv = get_sum(mg, iv)
3184 call mpi_allreduce(sum_iv, mean_iv, 1, &
3185 mpi_double, mpi_sum, mg%comm, ierr)
3188 volume = nc**2 * product(mg%dr(:, 1)) *
size(mg%lvls(1)%ids)
3189 mean_iv = mean_iv / volume
3191 do lvl = mg%lowest_lvl, mg%highest_lvl
3192 nc = mg%box_size_lvl(lvl)
3194 do i = 1,
size(mg%lvls(lvl)%my_ids)
3195 id = mg%lvls(lvl)%my_ids(i)
3196 if (include_ghostcells)
then
3197 mg%boxes(id)%cc(:, :, iv) = &
3198 mg%boxes(id)%cc(:, :, iv) - mean_iv
3200 mg%boxes(id)%cc(1:nc, 1:nc, iv) = &
3201 mg%boxes(id)%cc(1:nc, 1:nc, iv) - mean_iv
3205 end subroutine subtract_mean
3207 real(
dp) function get_sum(mg, iv)
3208 type(
mg_t),
intent(in) :: mg
3209 integer,
intent(in) :: iv
3210 integer :: lvl, i, id, nc
3214 do lvl = 1, mg%highest_lvl
3215 nc = mg%box_size_lvl(lvl)
3216 w = product(mg%dr(:, lvl))
3217 do i = 1,
size(mg%lvls(lvl)%my_leaves)
3218 id = mg%lvls(lvl)%my_leaves(i)
3219 get_sum = get_sum + w * &
3220 sum(mg%boxes(id)%cc(1:nc, 1:nc, iv))
3223 end function get_sum
3225 real(
dp) function max_residual_lvl(mg, lvl)
3226 type(
mg_t),
intent(inout) :: mg
3227 integer,
intent(in) :: lvl
3228 integer :: i, id, nc
3231 nc = mg%box_size_lvl(lvl)
3232 max_residual_lvl = 0.0_dp
3234 do i = 1,
size(mg%lvls(lvl)%my_ids)
3235 id = mg%lvls(lvl)%my_ids(i)
3236 call residual_box(mg, id, nc)
3237 res = maxval(abs(mg%boxes(id)%cc(1:nc, 1:nc,
mg_ires)))
3238 max_residual_lvl = max(max_residual_lvl, res)
3240 end function max_residual_lvl
3276 subroutine update_coarse(mg, lvl)
3277 type(
mg_t),
intent(inout) :: mg
3278 integer,
intent(in) :: lvl
3279 integer :: i, id, nc, nc_c
3281 nc = mg%box_size_lvl(lvl)
3282 nc_c = mg%box_size_lvl(lvl-1)
3285 do i = 1,
size(mg%lvls(lvl)%my_ids)
3286 id = mg%lvls(lvl)%my_ids(i)
3287 call residual_box(mg, id, nc)
3298 do i = 1,
size(mg%lvls(lvl-1)%my_parents)
3299 id = mg%lvls(lvl-1)%my_parents(i)
3302 call mg%box_op(mg, id, nc_c,
mg_irhs)
3305 mg%boxes(id)%cc(1:nc_c, 1:nc_c,
mg_irhs) = &
3306 mg%boxes(id)%cc(1:nc_c, 1:nc_c,
mg_irhs) + &
3307 mg%boxes(id)%cc(1:nc_c, 1:nc_c,
mg_ires)
3310 mg%boxes(id)%cc(:, :,
mg_iold) = &
3311 mg%boxes(id)%cc(:, :,
mg_iphi)
3313 end subroutine update_coarse
3316 subroutine correct_children(mg, lvl)
3317 type(
mg_t),
intent(inout) :: mg
3318 integer,
intent(in) :: lvl
3321 do i = 1,
size(mg%lvls(lvl)%my_parents)
3322 id = mg%lvls(lvl)%my_parents(i)
3325 mg%boxes(id)%cc(:, :,
mg_ires) = &
3326 mg%boxes(id)%cc(:, :,
mg_iphi) - &
3327 mg%boxes(id)%cc(:, :,
mg_iold)
3331 end subroutine correct_children
3333 subroutine smooth_boxes(mg, lvl, n_cycle)
3334 type(
mg_t),
intent(inout) :: mg
3335 integer,
intent(in) :: lvl
3336 integer,
intent(in) :: n_cycle
3337 integer :: n, i, id, nc
3339 nc = mg%box_size_lvl(lvl)
3341 do n = 1, n_cycle * mg%n_smoother_substeps
3343 do i = 1,
size(mg%lvls(lvl)%my_ids)
3344 id = mg%lvls(lvl)%my_ids(i)
3345 call mg%box_smoother(mg, id, nc, n)
3353 end subroutine smooth_boxes
3355 subroutine residual_box(mg, id, nc)
3356 type(
mg_t),
intent(inout) :: mg
3357 integer,
intent(in) :: id
3358 integer,
intent(in) :: nc
3360 call mg%box_op(mg, id, nc,
mg_ires)
3362 mg%boxes(id)%cc(1:nc, 1:nc,
mg_ires) = &
3363 mg%boxes(id)%cc(1:nc, 1:nc,
mg_irhs) &
3364 - mg%boxes(id)%cc(1:nc, 1:nc,
mg_ires)
3365 end subroutine residual_box
3369 type(
mg_t),
intent(inout) :: mg
3370 integer,
intent(in) :: i_out
3372 integer :: lvl, i, id, nc
3374 do lvl = mg%lowest_lvl, mg%highest_lvl
3375 nc = mg%box_size_lvl(lvl)
3376 do i = 1,
size(mg%lvls(lvl)%my_ids)
3377 id = mg%lvls(lvl)%my_ids(i)
3378 if (
present(op))
then
3379 call op(mg, id, nc, i_out)
3381 call mg%box_op(mg, id, nc, i_out)
3391 type(
mg_t),
intent(inout) :: mg
3392 integer,
intent(out) :: n_send(0:mg%n_cpu-1)
3393 integer,
intent(out) :: n_recv(0:mg%n_cpu-1)
3394 integer,
intent(out) :: dsize
3395 integer :: n_out(0:mg%n_cpu-1, mg%first_normal_lvl:mg%highest_lvl)
3396 integer :: n_in(0:mg%n_cpu-1, mg%first_normal_lvl:mg%highest_lvl)
3397 integer :: lvl, i, id, p_id, p_rank
3398 integer :: i_c, c_id, c_rank, min_lvl
3402 min_lvl = max(mg%lowest_lvl+1, mg%first_normal_lvl)
3404 do lvl = min_lvl, mg%highest_lvl
3406 do i = 1,
size(mg%lvls(lvl-1)%my_parents)
3407 id = mg%lvls(lvl-1)%my_parents(i)
3409 c_id = mg%boxes(id)%children(i_c)
3412 c_rank = mg%boxes(c_id)%rank
3413 if (c_rank /= mg%my_rank)
then
3414 n_in(c_rank, lvl) = n_in(c_rank, lvl) + 1
3421 do i = 1,
size(mg%lvls(lvl)%my_ids)
3422 id = mg%lvls(lvl)%my_ids(i)
3424 p_id = mg%boxes(id)%parent
3425 p_rank = mg%boxes(p_id)%rank
3426 if (p_rank /= mg%my_rank)
then
3427 n_out(p_rank, lvl) = n_out(p_rank, lvl) + 1
3433 allocate(mg%comm_restrict%n_send(0:mg%n_cpu-1, &
3434 mg%first_normal_lvl:mg%highest_lvl))
3435 allocate(mg%comm_restrict%n_recv(0:mg%n_cpu-1, &
3436 mg%first_normal_lvl:mg%highest_lvl))
3437 mg%comm_restrict%n_send = n_out
3438 mg%comm_restrict%n_recv = n_in
3440 dsize = (mg%box_size/2)**2
3441 n_send = maxval(n_out, dim=2)
3442 n_recv = maxval(n_in, dim=2)
3447 type(
mg_t),
intent(inout) :: mg
3448 integer,
intent(in) :: iv
3451 do lvl = mg%highest_lvl, mg%lowest_lvl+1, -1
3459 type(
mg_t),
intent(inout) :: mg
3460 integer,
intent(in) :: iv
3461 integer,
intent(in) :: lvl
3462 integer :: i, id, dsize, nc
3464 if (lvl <= mg%lowest_lvl) error stop
"cannot restrict lvl <= lowest_lvl"
3466 nc = mg%box_size_lvl(lvl)
3468 if (lvl >= mg%first_normal_lvl)
then
3471 mg%buf(:)%i_send = 0
3474 do i = 1,
size(mg%lvls(lvl)%my_ids)
3475 id = mg%lvls(lvl)%my_ids(i)
3476 call restrict_set_buffer(mg, id, iv)
3479 mg%buf(:)%i_recv = mg%comm_restrict%n_recv(:, lvl) * dsize
3481 mg%buf(:)%i_recv = 0
3484 do i = 1,
size(mg%lvls(lvl-1)%my_parents)
3485 id = mg%lvls(lvl-1)%my_parents(i)
3486 call restrict_onto(mg, id, nc, iv)
3490 subroutine restrict_set_buffer(mg, id, iv)
3491 type(
mg_t),
intent(inout) :: mg
3492 integer,
intent(in) :: id
3493 integer,
intent(in) :: iv
3494 integer :: i, j, n, hnc, p_id, p_rank
3495 real(
dp) :: tmp(mg%box_size/2, mg%box_size/2)
3498 p_id = mg%boxes(id)%parent
3499 p_rank = mg%boxes(p_id)%rank
3501 if (p_rank /= mg%my_rank)
then
3504 tmp(i, j) = 0.25_dp * &
3505 sum(mg%boxes(id)%cc(2*i-1:2*i, 2*j-1:2*j, iv))
3511 i = mg%buf(p_rank)%i_send
3512 mg%buf(p_rank)%send(i+1:i+n) = pack(tmp, .true.)
3513 mg%buf(p_rank)%i_send = mg%buf(p_rank)%i_send + n
3516 i = mg%buf(p_rank)%i_ix
3519 mg%buf(p_rank)%i_ix = mg%buf(p_rank)%i_ix + 1
3521 end subroutine restrict_set_buffer
3523 subroutine restrict_onto(mg, id, nc, iv)
3524 type(
mg_t),
intent(inout) :: mg
3525 integer,
intent(in) :: id
3526 integer,
intent(in) :: nc
3527 integer,
intent(in) :: iv
3528 integer :: i, j, hnc, dsize, i_c, c_id
3529 integer :: c_rank, dix(2)
3535 c_id = mg%boxes(id)%children(i_c)
3537 c_rank = mg%boxes(c_id)%rank
3540 if (c_rank == mg%my_rank)
then
3541 do j=1, hnc;
do i=1, hnc
3542 mg%boxes(id)%cc(dix(1)+i, dix(2)+j, iv) = 0.25_dp * &
3543 sum(mg%boxes(c_id)%cc(2*i-1:2*i, 2*j-1:2*j, iv))
3546 i = mg%buf(c_rank)%i_recv
3547 mg%boxes(id)%cc(dix(1)+1:dix(1)+hnc, &
3548 dix(2)+1:dix(2)+hnc, iv) = &
3549 reshape(mg%buf(c_rank)%recv(i+1:i+dsize), [hnc, hnc])
3550 mg%buf(c_rank)%i_recv = mg%buf(c_rank)%i_recv + dsize
3554 end subroutine restrict_onto
3558 Subroutine i_mrgrnk (XDONT, IRNGT)
3565 Integer,
Dimension (:),
Intent (In) :: XDONT
3566 Integer,
Dimension (:),
Intent (Out) :: IRNGT
3568 Integer :: XVALA, XVALB
3570 Integer,
Dimension (SIZE(IRNGT)) :: JWRKT
3571 Integer :: LMTNA, LMTNC, IRNG1, IRNG2
3572 Integer :: NVAL, IIND, IWRKD, IWRK, IWRKF, JINDA, IINDA, IINDB
3574 nval = min(
SIZE(xdont),
SIZE(irngt))
3587 Do iind = 2, nval, 2
3588 If (xdont(iind-1) <= xdont(iind))
Then
3589 irngt(iind-1) = iind - 1
3592 irngt(iind-1) = iind
3593 irngt(iind) = iind - 1
3596 If (modulo(nval, 2) /= 0)
Then
3613 Do iwrkd = 0, nval - 1, 4
3614 If ((iwrkd+4) > nval)
Then
3615 If ((iwrkd+2) >= nval)
Exit
3619 If (xdont(irngt(iwrkd+2)) <= xdont(irngt(iwrkd+3)))
Exit
3623 If (xdont(irngt(iwrkd+1)) <= xdont(irngt(iwrkd+3)))
Then
3624 irng2 = irngt(iwrkd+2)
3625 irngt(iwrkd+2) = irngt(iwrkd+3)
3626 irngt(iwrkd+3) = irng2
3631 irng1 = irngt(iwrkd+1)
3632 irngt(iwrkd+1) = irngt(iwrkd+3)
3633 irngt(iwrkd+3) = irngt(iwrkd+2)
3634 irngt(iwrkd+2) = irng1
3641 If (xdont(irngt(iwrkd+2)) <= xdont(irngt(iwrkd+3))) cycle
3645 If (xdont(irngt(iwrkd+1)) <= xdont(irngt(iwrkd+3)))
Then
3646 irng2 = irngt(iwrkd+2)
3647 irngt(iwrkd+2) = irngt(iwrkd+3)
3648 If (xdont(irng2) <= xdont(irngt(iwrkd+4)))
Then
3650 irngt(iwrkd+3) = irng2
3653 irngt(iwrkd+3) = irngt(iwrkd+4)
3654 irngt(iwrkd+4) = irng2
3660 irng1 = irngt(iwrkd+1)
3661 irng2 = irngt(iwrkd+2)
3662 irngt(iwrkd+1) = irngt(iwrkd+3)
3663 If (xdont(irng1) <= xdont(irngt(iwrkd+4)))
Then
3664 irngt(iwrkd+2) = irng1
3665 If (xdont(irng2) <= xdont(irngt(iwrkd+4)))
Then
3667 irngt(iwrkd+3) = irng2
3670 irngt(iwrkd+3) = irngt(iwrkd+4)
3671 irngt(iwrkd+4) = irng2
3675 irngt(iwrkd+2) = irngt(iwrkd+4)
3676 irngt(iwrkd+3) = irng1
3677 irngt(iwrkd+4) = irng2
3692 If (lmtna >= nval)
Exit
3701 jinda = iwrkf + lmtna
3702 iwrkf = iwrkf + lmtnc
3703 If (iwrkf >= nval)
Then
3704 If (jinda >= nval)
Exit
3720 jwrkt(1:lmtna) = irngt(iwrkd:jinda)
3722 xvala = xdont(jwrkt(iinda))
3723 xvalb = xdont(irngt(iindb))
3730 If (xvala > xvalb)
Then
3731 irngt(iwrk) = irngt(iindb)
3733 If (iindb > iwrkf)
Then
3735 irngt(iwrk+1:iwrkf) = jwrkt(iinda:lmtna)
3738 xvalb = xdont(irngt(iindb))
3740 irngt(iwrk) = jwrkt(iinda)
3742 If (iinda > lmtna) exit
3743 xvala = xdont(jwrkt(iinda))
3756 End Subroutine i_mrgrnk
3761 type(
mg_t),
intent(inout) :: mg
3763 if (mg%n_extra_vars == 0 .and. mg%is_allocated)
then
3764 error stop
"ahelmholtz_set_methods: mg%n_extra_vars == 0"
3766 mg%n_extra_vars = max(2, mg%n_extra_vars)
3778 select case (mg%geometry_type)
3780 mg%box_op => box_ahelmh
3782 select case (mg%smoother_type)
3784 mg%box_smoother => box_gs_ahelmh
3786 error stop
"ahelmholtz_set_methods: unsupported smoother type"
3789 error stop
"ahelmholtz_set_methods: unsupported geometry"
3795 real(
dp),
intent(in) :: lambda
3798 error stop
"ahelmholtz_set_lambda: lambda < 0 not allowed"
3804 subroutine box_gs_ahelmh(mg, id, nc, redblack_cntr)
3805 type(
mg_t),
intent(inout) :: mg
3806 integer,
intent(in) :: id
3807 integer,
intent(in) :: nc
3808 integer,
intent(in) :: redblack_cntr
3809 integer :: i, j, i0, di
3811 real(
dp) :: idr2(2*2), u(2*2)
3812 real(
dp) :: a0(2*2), a(2*2), c(2*2)
3815 idr2(1:2*2:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
3816 idr2(2:2*2:2) = idr2(1:2*2:2)
3828 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
3834 i0 = 2 - iand(ieor(redblack_cntr, j), 1)
3837 a0(1:2) = cc(i, j, i_eps1)
3838 a0(3:4) = cc(i, j, i_eps2)
3839 u(1:2) = cc(i-1:i+1:2, j, n)
3840 a(1:2) = cc(i-1:i+1:2, j, i_eps1)
3841 u(3:4) = cc(i, j-1:j+1:2, n)
3842 a(3:4) = cc(i, j-1:j+1:2, i_eps2)
3843 c(:) = 2 * a0(:) * a(:) / (a0(:) + a(:)) * idr2
3846 (sum(c(:) * u(:)) - cc(i, j,
mg_irhs)) / &
3851 end subroutine box_gs_ahelmh
3854 subroutine box_ahelmh(mg, id, nc, i_out)
3855 type(
mg_t),
intent(inout) :: mg
3856 integer,
intent(in) :: id
3857 integer,
intent(in) :: nc
3858 integer,
intent(in) :: i_out
3860 real(
dp) :: idr2(2*2), a0(2*2), u0, u(2*2), a(2*2)
3863 idr2(1:2*2:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
3864 idr2(2:2*2:2) = idr2(1:2*2:2)
3866 associate(cc => mg%boxes(id)%cc, n =>
mg_iphi, &
3871 a0(1:2) = cc(i, j, i_eps1)
3872 a0(3:4) = cc(i, j, i_eps2)
3873 a(1:2) = cc(i-1:i+1:2, j, i_eps1)
3874 a(3:4) = cc(i, j-1:j+1:2, i_eps2)
3876 u(1:2) = cc(i-1:i+1:2, j, n)
3877 u(3:4) = cc(i, j-1:j+1:2, n)
3879 cc(i, j, i_out) = sum(2 * idr2 * &
3880 a0(:)*a(:)/(a0(:) + a(:)) * (u(:) - u0)) - &
3885 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.
subroutine, public mg_comm_init(mg, comm)
Prolong from a parent to a child with index offset dix. This method could sometimes work better than ...
subroutine, public mg_fas_vcycle(mg, highest_lvl, max_res, standalone)
Perform FAS V-cycle (full approximation scheme).
subroutine, public vhelmholtz_set_methods(mg)
subroutine, public mg_ghost_cell_buffer_size(mg, n_send, n_recv, dsize)
Specify minimum buffer size (per process) for communication.
integer, parameter, public mg_num_children
subroutine, public mg_timer_end(timer)
subroutine, public mg_restrict(mg, iv)
Restrict all levels.
integer, parameter, public mg_vhelmholtz
Indicates a variable-coefficient Helmholtz equation.
integer, parameter, public mg_iveps1
Indexes of anisotropic variable coefficients.
integer, parameter, public mg_ahelmholtz
Indicates a anisotropic-coefficient Helmholtz equation.
integer, parameter, public mg_vlaplacian
Indicates a variable-coefficient Laplacian.
integer, dimension(2, 4), parameter, public mg_neighb_dix
integer, parameter, public mg_helmholtz
Indicates a constant-coefficient Helmholtz equation.
integer, parameter, public mg_physical_boundary
Special value that indicates there is a physical boundary.
subroutine, public mg_prolong_sparse(mg, p_id, dix, nc, iv, fine)
Prolong from a parent to a child with index offset dix.
subroutine, public mg_get_face_coords(box, nb, nc, x)
Get coordinates at the face of a box.
subroutine, public sort_and_transfer_buffers(mg, dsize)
integer, parameter, public dp
Type of reals.
pure integer function, public mg_highest_uniform_lvl(mg)
integer function, public mg_ix_to_ichild(ix)
Compute the child index for a box with spatial index ix. With child index we mean the index in the ch...
integer, parameter, public mg_ndim
Problem dimension.
subroutine, public mg_prolong_buffer_size(mg, n_send, n_recv, dsize)
Specify minimum buffer size (per process) for communication.
subroutine, public diffusion_solve_acoeff(mg, dt, order, max_res)
Solve a diffusion equation implicitly, assuming anisotropic diffusion coefficient which has been stor...
subroutine, public mg_fas_fmg(mg, have_guess, max_res)
Perform FAS-FMG cycle (full approximation scheme, full multigrid).
integer, parameter, public mg_ires
Index of residual.
integer, parameter, public mg_neighb_highy
subroutine, public mg_set_neighbors_lvl(mg, lvl)
integer, parameter, public mg_iveps3
subroutine, public mg_load_balance_simple(mg)
Load balance all boxes in the multigrid tree, by simply distributing the load per grid level....
subroutine, public helmholtz_set_methods(mg)
integer, parameter, public mg_bc_continuous
Value to indicate a continuous boundary condition.
subroutine, public mg_timers_show(mg)
integer, parameter, public mg_iphi
Index of solution.
subroutine, public mg_add_children(mg, id)
subroutine, public mg_prolong(mg, lvl, iv, iv_to, method, add)
Prolong variable iv from lvl to variable iv_to at lvl+1.
integer, dimension(4), parameter, public mg_neighb_dim
integer, dimension(2, 4), parameter, public mg_child_dix
integer, parameter, public mg_spherical
Spherical coordinate system.
subroutine, public mg_timer_start(timer)
integer(i8) function, public mg_number_of_unknowns(mg)
Determine total number of unknowns (on leaves)
integer, parameter, public mg_neighb_highx
integer, parameter, public mg_bc_dirichlet
Value to indicate a Dirichlet boundary condition.
subroutine, public helmholtz_set_lambda(lambda)
integer, parameter, public mg_laplacian
Indicates a standard Laplacian.
integer, dimension(4), parameter, public mg_neighb_rev
subroutine, public ahelmholtz_set_lambda(lambda)
real(dp), public, protected ahelmholtz_lambda
Module which contains multigrid procedures for a Helmholtz operator of the form: div(D grad(phi)) - l...
integer, parameter, public mg_lvl_hi
Maximum allowed grid level.
integer, dimension(4), parameter, public mg_neighb_high_pm
integer, parameter, public mg_bc_neumann
Value to indicate a Neumann boundary condition.
integer, parameter, public mg_irhs
Index of right-hand side.
logical, dimension(2, 4), parameter, public mg_child_low
integer, parameter, public mg_iveps2
elemental logical function, public mg_has_children(box)
Return .true. if a box has children.
subroutine, public diffusion_solve_vcoeff(mg, dt, order, max_res)
Solve a diffusion equation implicitly, assuming a variable diffusion coefficient which has been store...
integer, parameter, public mg_cylindrical
Cylindrical coordinate system.
real(dp), public, protected vhelmholtz_lambda
Module for implicitly solving diffusion equations.
subroutine, public mg_restrict_buffer_size(mg, n_send, n_recv, dsize)
Specify minimum buffer size (per process) for communication.
integer, parameter, public mg_smoother_jacobi
subroutine, public laplacian_set_methods(mg)
subroutine, public mg_deallocate_storage(mg)
Deallocate all allocatable arrays.
subroutine, public ahelmholtz_set_methods(mg)
subroutine, public mg_load_balance(mg)
Load balance all boxes in the multigrid tree. Compared to mg_load_balance_simple, this method does a ...
subroutine, public mg_fill_ghost_cells_lvl(mg, lvl, iv)
Fill ghost cells at a grid level.
subroutine, public vhelmholtz_set_lambda(lambda)
subroutine, public mg_set_next_level_ids(mg, lvl)
integer, parameter, public mg_num_neighbors
integer, parameter, public mg_cartesian
Cartesian coordinate system.
integer, dimension(2, 4), parameter, public mg_child_adj_nb
subroutine, public mg_set_refinement_boundaries(boxes, level)
Create a list of refinement boundaries (from the coarse side)
integer, parameter, public mg_neighb_lowx
integer, parameter, public mg_neighb_lowy
integer, parameter, public mg_num_vars
Number of predefined multigrid variables.
integer, parameter, public mg_lvl_lo
Minimum allowed grid level.
subroutine, public mg_set_leaves_parents(boxes, level)
Create a list of leaves and a list of parents for a level.
subroutine, public mg_load_balance_parents(mg)
Load balance the parents (non-leafs). Assign them to the rank that has most children.
subroutine, public mg_fill_ghost_cells(mg, iv)
Fill ghost cells at all grid levels.
subroutine, public mg_restrict_lvl(mg, iv, lvl)
Restrict from lvl to lvl-1.
subroutine, public vlaplacian_set_methods(mg)
integer, parameter, public mg_iveps
Index of the variable coefficient (at cell centers)
subroutine, public mg_allocate_storage(mg)
Allocate communication buffers and local boxes for a tree that has already been created.
subroutine, public mg_build_rectangle(mg, domain_size, box_size, dx, r_min, periodic, n_finer)
subroutine, public mg_apply_op(mg, i_out, op)
Apply operator to the tree and store in variable i_out.
integer, parameter, public i8
Type for 64-bit integers.
subroutine, public mg_set_methods(mg)
integer, parameter, public mg_max_num_vars
Maximum number of variables.
pure integer function, dimension(2), public mg_get_child_offset(mg, id)
Get the offset of a box with respect to its parent (e.g. in 2d, there can be a child at offset 0,...
integer, parameter, public mg_iold
Index of previous solution (used for correction)
logical, dimension(4), parameter, public mg_neighb_low
integer, parameter, public mg_max_timers
Maximum number of timers to use.
integer, parameter, public mg_smoother_gs
real(dp), public, protected helmholtz_lambda
Module for load balancing a tree (that already has been constructed). The load balancing determines w...
subroutine, public diffusion_solve(mg, dt, diffusion_coeff, order, max_res)
Solve a diffusion equation implicitly, assuming a constant diffusion coefficient. The solution at tim...
subroutine, public mg_phi_bc_store(mg)
Store boundary conditions for the solution variable, this can speed up calculations if the same bound...
integer, dimension(4, 2), parameter, public mg_child_rev
integer, parameter, public mg_no_box
Special value that indicates there is no box.
integer, parameter, public mg_smoother_gsrb
integer function, public mg_add_timer(mg, name)
Buffer type (one is used for each pair of communicating processes)
Lists of blocks per refinement level.