MPI-AMRVAC 3.1
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
m_octree_mg_3d.t
Go to the documentation of this file.
1
2
3! Single module generated from the octree-mg sources.
4! This file can be easier to include in existing projects.
5!
6! Notes:
7! 1. The module name is here extended by _1d, _2d or _3d
8! 2. The free space Poisson solver is not included here.
9! 3. It is best to make changes in the original repository at
10! https://github.com/jannisteunissen/octree-mg
11! 4. This file can be generated as follows:
12! cd octree-mg/single_module
13! ./to_single_module.sh
14!
15! The modules can be compiled with:
16! mpif90 -c m_octree_mg_1d.f90 [other options]
17! mpif90 -c m_octree_mg_2d.f90 [other options]
18! mpif90 -c m_octree_mg_3d.f90 [other options]
19! mpif90 -c m_octree_mg.f90 -cpp -DNDIM=<1,2,3> [other options]
20
21
23 use mpi
24 implicit none
25 private
26
27 !! File ../src/m_data_structures.f90
28
29 !> Type of reals
30 integer, parameter, public :: dp = kind(0.0d0)
31
32 !> Type for 64-bit integers
33 integer, parameter, public :: i8 = selected_int_kind(18)
34
35 !> Indicates a standard Laplacian
36 integer, parameter, public :: mg_laplacian = 1
37
38 !> Indicates a variable-coefficient Laplacian
39 integer, parameter, public :: mg_vlaplacian = 2
40
41 !> Indicates a constant-coefficient Helmholtz equation
42 integer, parameter, public :: mg_helmholtz = 3
43
44 !> Indicates a variable-coefficient Helmholtz equation
45 integer, parameter, public :: mg_vhelmholtz = 4
46
47 !> Indicates a anisotropic-coefficient Helmholtz equation
48 integer, parameter, public :: mg_ahelmholtz = 5
49
50 !> Cartesian coordinate system
51 integer, parameter, public :: mg_cartesian = 1
52 !> Cylindrical coordinate system
53 integer, parameter, public :: mg_cylindrical = 2
54 !> Spherical coordinate system
55 integer, parameter, public :: mg_spherical = 3
56
57 integer, parameter, public :: mg_smoother_gs = 1
58 integer, parameter, public :: mg_smoother_gsrb = 2
59 integer, parameter, public :: mg_smoother_jacobi = 3
60
61 !> Problem dimension
62 integer, parameter, public :: mg_ndim = 3
63
64 !> Number of predefined multigrid variables
65 integer, parameter, public :: mg_num_vars = 4
66 !> Maximum number of variables
67 integer, parameter, public :: mg_max_num_vars = 10
68 !> Index of solution
69 integer, parameter, public :: mg_iphi = 1
70 !> Index of right-hand side
71 integer, parameter, public :: mg_irhs = 2
72 !> Index of previous solution (used for correction)
73 integer, parameter, public :: mg_iold = 3
74 !> Index of residual
75 integer, parameter, public :: mg_ires = 4
76
77 !> Index of the variable coefficient (at cell centers)
78 integer, parameter, public :: mg_iveps = 5
79
80 !> Indexes of anisotropic variable coefficients
81 integer, parameter, public :: mg_iveps1 = 5
82 integer, parameter, public :: mg_iveps2 = 6
83 integer, parameter, public :: mg_iveps3 = 7
84
85 !> Minimum allowed grid level
86 integer, parameter, public :: mg_lvl_lo = -20
87 !> Maximum allowed grid level
88 integer, parameter, public :: mg_lvl_hi = 20
89
90 !> Value to indicate a Dirichlet boundary condition
91 integer, parameter, public :: mg_bc_dirichlet = -10
92
93 !> Value to indicate a Neumann boundary condition
94 integer, parameter, public :: mg_bc_neumann = -11
95
96 !> Value to indicate a continuous boundary condition
97 integer, parameter, public :: mg_bc_continuous = -12
98
99 !> Special value that indicates there is no box
100 integer, parameter, public :: mg_no_box = 0
101 !> Special value that indicates there is a physical boundary
102 integer, parameter, public :: mg_physical_boundary = -1
103
104 !> Maximum number of timers to use
105 integer, parameter, public :: mg_max_timers = 20
106
107 ! Numbering of children (same location as **corners**)
108 integer, parameter, public :: mg_num_children = 8
109
110 ! Index offset for each child
111 integer, parameter, public :: mg_child_dix(3, 8) = reshape( &
112 [0,0,0, 1,0,0, 0,1,0, 1,1,0, &
113 0,0,1, 1,0,1, 0,1,1, 1,1,1], [3,8])
114 ! Reverse child index in each direction
115 integer, parameter, public :: mg_child_rev(8, 3) = reshape( &
116 [2,1,4,3,6,5,8,7, 3,4,1,2,7,8,5,6, 5,6,7,8,1,2,3,4], [8,3])
117 ! Children adjacent to a neighbor
118 integer, parameter, public :: mg_child_adj_nb(4, 6) = reshape( &
119 [1,3,5,7, 2,4,6,8, 1,2,5,6, 3,4,7,8, 1,2,3,4, 5,6,7,8], [4,6])
120 ! Which children have a low index per dimension
121 logical, parameter, public :: mg_child_low(3, 8) = reshape([ &
122 .true., .true., .true., .false., .true., .true., &
123 .true., .false., .true., .false., .false., .true., &
124 .true., .true., .false., .false., .true., .false., &
125 .true., .false., .false., .false., .false., .false.], [3, 8])
126
127 ! Neighbor topology information
128 integer, parameter, public :: mg_num_neighbors = 6
129 integer, parameter, public :: mg_neighb_lowx = 1
130 integer, parameter, public :: mg_neighb_highx = 2
131 integer, parameter, public :: mg_neighb_lowy = 3
132 integer, parameter, public :: mg_neighb_highy = 4
133 integer, parameter, public :: mg_neighb_lowz = 5
134 integer, parameter, public :: mg_neighb_highz = 6
135 ! Index offsets of neighbors
136 integer, parameter, public :: mg_neighb_dix(3, 6) = reshape( &
137 [-1,0,0, 1,0,0, 0,-1,0, 0,1,0, 0,0,-1, 0,0,1], [3,6])
138 ! Which neighbors have a lower index
139 logical, parameter, public :: mg_neighb_low(6) = &
140 [.true., .false., .true., .false., .true., .false.]
141 ! Opposite of nb_low, but now as -1,1 integers
142 integer, parameter, public :: mg_neighb_high_pm(6) = [-1, 1, -1, 1, -1, 1]
143 ! Reverse neighbors
144 integer, parameter, public :: mg_neighb_rev(6) = [2, 1, 4, 3, 6, 5]
145 ! Direction (dimension) for a neighbor
146 integer, parameter, public :: mg_neighb_dim(6) = [1, 1, 2, 2, 3, 3]
147
148 !> Lists of blocks per refinement level
149 type, public :: mg_lvl_t
150 integer, allocatable :: leaves(:)
151 integer, allocatable :: parents(:)
152 integer, allocatable :: ref_bnds(:)
153 integer, allocatable :: ids(:)
154 integer, allocatable :: my_leaves(:)
155 integer, allocatable :: my_parents(:)
156 integer, allocatable :: my_ref_bnds(:)
157 integer, allocatable :: my_ids(:)
158 end type mg_lvl_t
159
160 !> Box data structure
161 type, public :: mg_box_t
162 integer :: rank !< Which process owns this box
163 integer :: id !< Box id (index in boxes(:) array)
164 integer :: lvl !< Refinement level
165 integer :: ix(3) !< Spatial index
166 integer :: parent !< Id of parent
167 integer :: children(2**3) !< Ids of children
168 integer :: neighbors(2*3) !< Ids of neighbors
169 real(dp) :: r_min(3) !< Minimum coordinate
170 real(dp) :: dr(3) !< Grid spacing
171 !> Cell-centered data
172 real(dp), allocatable :: cc(:, :, :, :)
173 end type mg_box_t
174
175 !> Buffer type (one is used for each pair of communicating processes)
176 type, public :: mg_buf_t
177 integer :: i_send !< Index in send array
178 integer :: i_recv
179 integer :: i_ix
180 integer, allocatable :: ix(:) !< Will be used to sort the data
181 real(dp), allocatable :: send(:)
182 real(dp), allocatable :: recv(:)
183 end type mg_buf_t
184
185 type, public :: mg_comm_t
186 integer, allocatable :: n_send(:, :)
187 integer, allocatable :: n_recv(:, :)
188 end type mg_comm_t
189
190 type, public :: mg_bc_t
191 integer :: bc_type = mg_bc_dirichlet !< Type of boundary condition
192 real(dp) :: bc_value = 0.0_dp !< Value (for e.g. Dirichlet or Neumann)
193 !> To set user-defined boundary conditions (overrides bc(:))
194 procedure(mg_subr_bc), pointer, nopass :: boundary_cond => null()
195 !> To set a user-defined refinement boundary method
196 procedure(mg_subr_rb), pointer, nopass :: refinement_bnd => null()
197 end type mg_bc_t
198
199 type, public :: mg_timer_t
200 character(len=20) :: name
201 real(dp) :: t = 0.0_dp
202 real(dp) :: t0
203 end type mg_timer_t
204
205 type, public :: mg_t
206 !> Whether the multigrid tree structure has been created
207 logical :: tree_created = .false.
208 !> Whether storage has been allocated for boxes
209 logical :: is_allocated = .false.
210 !> Number of extra cell-centered variable (e.g., for coefficients)
211 integer :: n_extra_vars = 0
212 !> MPI communicator
213 integer :: comm = -1
214 !> Number of MPI tasks
215 integer :: n_cpu = -1
216 !> MPI rank of this task
217 integer :: my_rank = -1
218 !> Size of boxes in cells, be equal for all dimensions
219 integer :: box_size = -1
220 !> Highest grid level in the tree
221 integer :: highest_lvl = -1
222 !> Lowest grid level in the tree
223 integer :: lowest_lvl = -1
224 !> First normal level of the quadtree/octree, at coarser levels parents
225 !> have only one child
226 integer :: first_normal_lvl = -1
227 !> Total number of boxes in the tree (among all processes)
228 integer :: n_boxes = 0
229 !> Size of boxes per level (differs for coarsest levels)
230 integer :: box_size_lvl(mg_lvl_lo:mg_lvl_hi)
231 !> Size of domain per level (if uniformly refined)
232 integer :: domain_size_lvl(3, mg_lvl_lo:mg_lvl_hi)
233 !> Grid spacing per level
234 real(dp) :: dr(3, mg_lvl_lo:mg_lvl_hi)
235 !> Minimum coordinates
236 real(dp) :: r_min(3)
237 !> List of all levels
239 !> Array with all boxes in the tree. Only boxes owned by this task are
240 !> actually allocated
241 type(mg_box_t), allocatable :: boxes(:)
242 !> Buffer for communication with each other task
243 type(mg_buf_t), allocatable :: buf(:)
244
245 !> Communication info for restriction
246 type(mg_comm_t) :: comm_restrict
247 !> Communication info for prolongation
248 type(mg_comm_t) :: comm_prolong
249 !> Communication info for ghost cell filling
250 type(mg_comm_t) :: comm_ghostcell
251
252 !> Whether boundary condition data has been stored for mg solution
253 logical :: phi_bc_data_stored = .false.
254
255 !> Whether a dimension is periodic
256 logical :: periodic(3) = .false.
257
258 !> To store pre-defined boundary conditions per direction per variable
260
261 !> Type of operator
262 integer :: operator_type = mg_laplacian
263 !> Type of grid geometry
264 integer :: geometry_type = mg_cartesian
265
266 !> Whether the mean has to be subtracted from the multigrid solution
267 logical :: subtract_mean = .false.
268 !> Type of multigrid smoother
269 integer :: smoother_type = mg_smoother_gs
270 !> Number of substeps for the smoother (for GSRB this is 2)
271 integer :: n_smoother_substeps = 1
272 !> Number of cycles when doing downwards relaxation
273 integer :: n_cycle_down = 2
274 !> Number of cycles when doing upwards relaxation
275 integer :: n_cycle_up = 2
276 !> Maximum number of cycles on the coarse grid
277 integer :: max_coarse_cycles = 1000
278 integer :: coarsest_grid(3) = 2
279 !> Stop coarse grid when max. residual is smaller than this
280 real(dp) :: residual_coarse_abs = 1e-8_dp
281 !> Stop coarse grid when residual has been reduced by this factor
282 real(dp) :: residual_coarse_rel = 1e-8_dp
283
284 !> Multigrid operator (e.g., Laplacian)
285 procedure(mg_box_op), pointer, nopass :: box_op => null()
286
287 !> Multigrid smoother
288 procedure(mg_box_gsrb), pointer, nopass :: box_smoother => null()
289
290 !> Multigrid prolongation method
291 procedure(mg_box_prolong), pointer, nopass :: box_prolong => null()
292
293 !> Number of timers
294 integer :: n_timers = 0
295 !> Values for the timers
296 type(mg_timer_t) :: timers(mg_max_timers)
297 end type mg_t
298
299 interface
300 !> To fill ghost cells near physical boundaries
301 subroutine mg_subr_bc(box, nc, iv, nb, bc_type, bc)
302 import
303 type(mg_box_t), intent(in) :: box
304 integer, intent(in) :: nc
305 integer, intent(in) :: iv !< Index of variable
306 integer, intent(in) :: nb !< Direction
307 integer, intent(out) :: bc_type !< Type of b.c.
308 !> Boundary values
309 real(dp), intent(out) :: bc(nc, nc)
310 end subroutine mg_subr_bc
311
312 !> To fill ghost cells near refinement boundaries
313 subroutine mg_subr_rb(box, nc, iv, nb, cgc)
314 import
315 type(mg_box_t), intent(inout) :: box
316 integer, intent(in) :: nc
317 integer, intent(in) :: iv !< Index of variable
318 integer, intent(in) :: nb !< Direction
319 !> Coarse data
320 real(dp), intent(in) :: cgc(nc, nc)
321 end subroutine mg_subr_rb
322
323 !> Subroutine that performs A * cc(..., i_in) = cc(..., i_out)
324 subroutine mg_box_op(mg, id, nc, i_out)
325 import
326 type(mg_t), intent(inout) :: mg
327 integer, intent(in) :: id
328 integer, intent(in) :: nc
329 integer, intent(in) :: i_out
330 end subroutine mg_box_op
331
332 !> Subroutine that performs Gauss-Seidel relaxation
333 subroutine mg_box_gsrb(mg, id, nc, redblack_cntr)
334 import
335 type(mg_t), intent(inout) :: mg
336 integer, intent(in) :: id
337 integer, intent(in) :: nc
338 integer, intent(in) :: redblack_cntr
339 end subroutine mg_box_gsrb
340
341 !> Subroutine that performs prolongation to a single child
342 subroutine mg_box_prolong(mg, p_id, dix, nc, iv, fine)
343 import
344 type(mg_t), intent(inout) :: mg
345 integer, intent(in) :: p_id !< Id of parent
346 integer, intent(in) :: dix(3) !< Offset of child in parent grid
347 integer, intent(in) :: nc !< Child grid size
348 integer, intent(in) :: iv !< Prolong from this variable
349 real(dp), intent(out) :: fine(nc, nc, nc) !< Prolonged values
350 end subroutine mg_box_prolong
351 end interface
352
353 ! Public methods
354 public :: mg_subr_bc
355 public :: mg_subr_rb
356 public :: mg_box_op
357 public :: mg_box_gsrb
358 public :: mg_box_prolong
359 public :: mg_has_children
360 public :: mg_ix_to_ichild
361 public :: mg_get_child_offset
362 public :: mg_highest_uniform_lvl
363 public :: mg_number_of_unknowns
364 public :: mg_get_face_coords
365 public :: mg_add_timer
366 public :: mg_timer_start
367 public :: mg_timer_end
368 public :: mg_timers_show
369
370 !! File ../src/m_allocate_storage.f90
371
372 public :: mg_allocate_storage
373 public :: mg_deallocate_storage
374
375 !! File ../src/m_diffusion.f90
376
377!> Module for implicitly solving diffusion equations
378
379 public :: diffusion_solve
380 public :: diffusion_solve_vcoeff
381 public :: diffusion_solve_acoeff
382
383 !! File ../src/m_laplacian.f90
384
385!> Module which contains multigrid procedures for a Laplacian operator
386
387 public :: laplacian_set_methods
388
389 !! File ../src/m_vhelmholtz.f90
390
391!> Module which contains multigrid procedures for a Helmholtz operator of the
392!> form: div(D grad(phi)) - lambda*phi = f, where D has a smooth spatial
393!> variation
394
395 !> The lambda used for the Helmholtz equation (should be >= 0)
396 real(dp), public, protected :: vhelmholtz_lambda = 0.0_dp
397
398 public :: vhelmholtz_set_methods
399 public :: vhelmholtz_set_lambda
400
401 !! File ../src/m_build_tree.f90
402
403 ! Public methods
404 public :: mg_build_rectangle
405 public :: mg_add_children
406 public :: mg_set_leaves_parents
407 public :: mg_set_next_level_ids
409 public :: mg_set_neighbors_lvl
410
411 !! File ../src/m_load_balance.f90
412!> Module for load balancing a tree (that already has been constructed). The
413!> load balancing determines which ranks (MPI processes) allocated physical
414!> storage for boxes. The tree structure itself is present on all processes.
415
416 ! Public methods
417 public :: mg_load_balance_simple
418 public :: mg_load_balance
420
421 !! File ../src/m_vlaplacian.f90
422
423!> Module which contains multigrid procedures for a variable-coefficient
424!> Laplacian operator, assuming the variation is smooth
425
426 public :: vlaplacian_set_methods
427
428 !! File ../src/m_communication.f90
429
430 ! Public methods
431 public :: mg_comm_init
433
434 !! File ../src/m_ghost_cells.f90
435
436 ! Public methods
438 public :: mg_fill_ghost_cells
440 public :: mg_phi_bc_store
441
442 !! File ../src/m_prolong.f90
443
444 ! Public methods
445 public :: mg_prolong
446 public :: mg_prolong_buffer_size
447 public :: mg_prolong_sparse
448
449 !! File ../src/m_helmholtz.f90
450
451!> Module which contains multigrid procedures for a Helmholtz operator of the
452!> form: laplacian(phi) - lambda*phi = f
453
454 !> The lambda used for the Helmholtz equation (should be >= 0)
455 real(dp), public, protected :: helmholtz_lambda = 0.0_dp
456
457 public :: helmholtz_set_methods
458 public :: helmholtz_set_lambda
459
460 !! File ../src/m_multigrid.f90
461
462 integer :: timer_total_vcycle = -1
463 integer :: timer_total_fmg = -1
464 integer :: timer_smoother = -1
465 integer :: timer_smoother_gc = -1
466 integer :: timer_coarse = -1
467 integer :: timer_correct = -1
468 integer :: timer_update_coarse = -1
469
470 ! Public methods
471 public :: mg_fas_vcycle
472 public :: mg_fas_fmg
473 public :: mg_set_methods
474 public :: mg_apply_op
475
476 !! File ../src/m_restrict.f90
477
478 ! Public methods
479 public :: mg_restrict
480 public :: mg_restrict_lvl
482
483 !! File ../src/m_mrgrnk.f90
484
485 Integer, Parameter :: kdp = selected_real_kind(15)
486 public :: mrgrnk
487 private :: kdp
488 private :: i_mrgrnk
489 interface mrgrnk
490 module procedure i_mrgrnk
491 end interface mrgrnk
492
493 !! File ../src/m_ahelmholtz.f90
494
495!> Module which contains multigrid procedures for a Helmholtz operator of the
496!> form: div(D grad(phi)) - lambda*phi = f, where D has a smooth spatial
497!> variation and a component in each spatial direction
498
499 !> The lambda used for the Helmholtz equation (should be >= 0)
500 real(dp), public, protected :: ahelmholtz_lambda = 0.0_dp
501
502 public :: ahelmholtz_set_methods
503 public :: ahelmholtz_set_lambda
504contains
505
506 !! File ../src/m_data_structures.f90
507
508 !> Return .true. if a box has children
509 elemental logical function mg_has_children(box)
510 type(mg_box_t), intent(in) :: box
511
512 ! Boxes are either fully refined or not, so we only need to check one of the
513 ! children
514 mg_has_children = (box%children(1) /= mg_no_box)
515 end function mg_has_children
516
517 !> Compute the child index for a box with spatial index ix. With child index
518 !> we mean the index in the children(:) array of its parent.
519 integer function mg_ix_to_ichild(ix)
520 integer, intent(in) :: ix(3) !< Spatial index of the box
521 ! The index can range from 1 (all ix odd) and 2**$D (all ix even)
522 mg_ix_to_ichild = 8 - 4 * iand(ix(3), 1) - &
523 2 * iand(ix(2), 1) - iand(ix(1), 1)
524 end function mg_ix_to_ichild
525
526 !> Get the offset of a box with respect to its parent (e.g. in 2d, there can
527 !> be a child at offset 0,0, one at n_cell/2,0, one at 0,n_cell/2 and one at
528 !> n_cell/2, n_cell/2)
529 pure function mg_get_child_offset(mg, id) result(ix_offset)
530 type(mg_t), intent(in) :: mg
531 integer, intent(in) :: id
532 integer :: ix_offset(3)
533
534 if (mg%boxes(id)%lvl <= mg%first_normal_lvl) then
535 ix_offset(:) = 0
536 else
537 ix_offset = iand(mg%boxes(id)%ix-1, 1) * &
538 ishft(mg%box_size, -1) ! * n_cell / 2
539 end if
540 end function mg_get_child_offset
541
542 pure function mg_highest_uniform_lvl(mg) result(lvl)
543 type(mg_t), intent(in) :: mg
544 integer :: lvl
545
546 do lvl = mg%first_normal_lvl, mg%highest_lvl-1
547 ! Exit if a grid is partially refined
548 if (size(mg%lvls(lvl)%leaves) /= 0 .and. &
549 size(mg%lvls(lvl)%parents) /= 0) exit
550 end do
551 ! If the loop did not exit, we get lvl equals mg%highest_lvl
552 end function mg_highest_uniform_lvl
553
554 !> Determine total number of unknowns (on leaves)
555 function mg_number_of_unknowns(mg) result(n_unknowns)
556 type(mg_t), intent(in) :: mg
557 integer :: lvl
558 integer(i8) :: n_unknowns
559
560 n_unknowns = 0
561 do lvl = mg%first_normal_lvl, mg%highest_lvl
562 n_unknowns = n_unknowns + size(mg%lvls(lvl)%leaves)
563 end do
564 n_unknowns = n_unknowns * int(mg%box_size**3, i8)
565 end function mg_number_of_unknowns
566
567 !> Get coordinates at the face of a box
568 subroutine mg_get_face_coords(box, nb, nc, x)
569 type(mg_box_t), intent(in) :: box
570 integer, intent(in) :: nb
571 integer, intent(in) :: nc
572 real(dp), intent(out) :: x(nc, nc, 3)
573 integer :: i, j, ixs(3-1)
574 integer :: nb_dim
575 real(dp) :: rmin(3)
576
577 nb_dim = mg_neighb_dim(nb)
578
579 ! Determine directions perpendicular to neighbor
580 ixs = [(i, i = 1, 3-1)]
581 ixs(nb_dim:) = ixs(nb_dim:) + 1
582
583 rmin = box%r_min
584 if (.not. mg_neighb_low(nb)) then
585 rmin(nb_dim) = rmin(nb_dim) + box%dr(nb_dim) * nc
586 end if
587
588 do j = 1, nc
589 do i = 1, nc
590 x(i, j, :) = rmin
591 x(i, j, ixs) = x(i, j, ixs) + ([i, j] - 0.5d0) * box%dr(ixs)
592 end do
593 end do
594 end subroutine mg_get_face_coords
595
596 integer function mg_add_timer(mg, name)
597 type(mg_t), intent(inout) :: mg
598 character(len=*), intent(in) :: name
599
600 mg%n_timers = mg%n_timers + 1
601 mg_add_timer = mg%n_timers
602 mg%timers(mg_add_timer)%name = name
603 end function mg_add_timer
604
605 subroutine mg_timer_start(timer)
606 use mpi
607 type(mg_timer_t), intent(inout) :: timer
608 timer%t0 = mpi_wtime()
609 end subroutine mg_timer_start
610
611 subroutine mg_timer_end(timer)
612 use mpi
613 type(mg_timer_t), intent(inout) :: timer
614 timer%t = timer%t + mpi_wtime() - timer%t0
615 end subroutine mg_timer_end
616
617 subroutine mg_timers_show(mg)
618 use mpi
619 type(mg_t), intent(in) :: mg
620 integer :: n, ierr
621 real(dp) :: tmin(mg%n_timers)
622 real(dp) :: tmax(mg%n_timers)
623 real(dp), allocatable :: tmp_array(:)
624
625 allocate(tmp_array(mg%n_timers))
626 tmp_array(:) = mg%timers(1:mg%n_timers)%t
627
628 call mpi_reduce(tmp_array, tmin, mg%n_timers, &
629 mpi_double, mpi_min, 0, mg%comm, ierr)
630 call mpi_reduce(tmp_array, tmax, mg%n_timers, &
631 mpi_double, mpi_max, 0, mg%comm, ierr)
632
633 if (mg%my_rank == 0) then
634 write(*, "(A20,2A16)") "name ", "min(s)", "max(s)"
635 do n = 1, mg%n_timers
636 write(*, "(A20,2F16.6)") mg%timers(n)%name, &
637 tmin(n), tmax(n)
638 end do
639 end if
640 end subroutine mg_timers_show
641
642 !! File ../src/m_allocate_storage.f90
643
644 !> Deallocate all allocatable arrays
646 type(mg_t), intent(inout) :: mg
647 integer :: lvl
648
649 if (.not. mg%is_allocated) &
650 error stop "deallocate_storage: tree is not allocated"
651
652 deallocate(mg%boxes)
653 deallocate(mg%buf)
654
655 deallocate(mg%comm_restrict%n_send)
656 deallocate(mg%comm_restrict%n_recv)
657
658 deallocate(mg%comm_prolong%n_send)
659 deallocate(mg%comm_prolong%n_recv)
660
661 deallocate(mg%comm_ghostcell%n_send)
662 deallocate(mg%comm_ghostcell%n_recv)
663
664 do lvl = mg%lowest_lvl, mg%highest_lvl
665 deallocate(mg%lvls(lvl)%ids)
666 deallocate(mg%lvls(lvl)%leaves)
667 deallocate(mg%lvls(lvl)%parents)
668 deallocate(mg%lvls(lvl)%ref_bnds)
669 deallocate(mg%lvls(lvl)%my_ids)
670 deallocate(mg%lvls(lvl)%my_leaves)
671 deallocate(mg%lvls(lvl)%my_parents)
672 deallocate(mg%lvls(lvl)%my_ref_bnds)
673 end do
674
675 mg%is_allocated = .false.
676 mg%n_boxes = 0
677 mg%phi_bc_data_stored = .false.
678 end subroutine mg_deallocate_storage
679
680 !> Allocate communication buffers and local boxes for a tree that has already
681 !> been created
682 subroutine mg_allocate_storage(mg)
683
684 type(mg_t), intent(inout) :: mg
685 integer :: i, id, lvl, nc
686 integer :: n_send(0:mg%n_cpu-1, 3)
687 integer :: n_recv(0:mg%n_cpu-1, 3)
688 integer :: dsize(3)
689 integer :: n_in, n_out, n_id
690
691 if (.not. mg%tree_created) &
692 error stop "allocate_storage: tree is not yet created"
693
694 if (mg%is_allocated) &
695 error stop "allocate_storage: tree is already allocated"
696
697 do lvl = mg%lowest_lvl, mg%highest_lvl
698 nc = mg%box_size_lvl(lvl)
699 do i = 1, size(mg%lvls(lvl)%my_ids)
700 id = mg%lvls(lvl)%my_ids(i)
701 allocate(mg%boxes(id)%cc(0:nc+1, 0:nc+1, 0:nc+1, &
702 mg_num_vars + mg%n_extra_vars))
703
704 ! Set all initial values to zero
705 mg%boxes(id)%cc(:, :, :, :) = 0.0_dp
706 end do
707 end do
708
709 allocate(mg%buf(0:mg%n_cpu-1))
710
711 call mg_ghost_cell_buffer_size(mg, n_send(:, 1), &
712 n_recv(:, 1), dsize(1))
713 call mg_restrict_buffer_size(mg, n_send(:, 2), &
714 n_recv(:, 2), dsize(2))
715 call mg_prolong_buffer_size(mg, n_send(:, 3), &
716 n_recv(:, 3), dsize(3))
717
718 do i = 0, mg%n_cpu-1
719 n_out = maxval(n_send(i, :) * dsize(:))
720 n_in = maxval(n_recv(i, :) * dsize(:))
721 n_id = maxval(n_send(i, :))
722 allocate(mg%buf(i)%send(n_out))
723 allocate(mg%buf(i)%recv(n_in))
724 allocate(mg%buf(i)%ix(n_id))
725 end do
726
727 mg%is_allocated = .true.
728 end subroutine mg_allocate_storage
729
730 !! File ../src/m_diffusion.f90
731
732 !> Solve a diffusion equation implicitly, assuming a constant diffusion
733 !> coefficient. The solution at time t should be stored in mg_iphi, which is
734 !> on output replaced by the solution at time t+dt.
735 subroutine diffusion_solve(mg, dt, diffusion_coeff, order, max_res)
736
737 type(mg_t), intent(inout) :: mg
738 real(dp), intent(in) :: dt
739 real(dp), intent(in) :: diffusion_coeff
740 integer, intent(in) :: order
741 real(dp), intent(in) :: max_res
742 integer, parameter :: max_its = 10
743 integer :: n
744 real(dp) :: res
745
746 mg%operator_type = mg_helmholtz
747 call mg_set_methods(mg)
748
749 select case (order)
750 case (1)
751 call helmholtz_set_lambda(1/(dt * diffusion_coeff))
752 call set_rhs(mg, -1/(dt * diffusion_coeff), 0.0_dp)
753 case (2)
754 call helmholtz_set_lambda(0.0d0)
755 call mg_apply_op(mg, mg_irhs)
756 call helmholtz_set_lambda(2/(dt * diffusion_coeff))
757 call set_rhs(mg, -2/(dt * diffusion_coeff), -1.0_dp)
758 case default
759 error stop "diffusion_solve: order should be 1 or 2"
760 end select
761
762 ! Start with an FMG cycle
763 call mg_fas_fmg(mg, .true., max_res=res)
764
765 ! Add V-cycles if necessary
766 do n = 1, max_its
767 if (res <= max_res) exit
768 call mg_fas_vcycle(mg, max_res=res)
769 end do
770
771 if (n == max_its + 1) then
772 if (mg%my_rank == 0) &
773 print *, "Did you specify boundary conditions correctly?"
774 error stop "diffusion_solve: no convergence"
775 end if
776 end subroutine diffusion_solve
777
778 !> Solve a diffusion equation implicitly, assuming a variable diffusion
779 !> coefficient which has been stored in mg_iveps (also on coarse grids). The
780 !> solution at time t should be stored in mg_iphi, which is on output replaced
781 !> by the solution at time t+dt.
782 subroutine diffusion_solve_vcoeff(mg, dt, order, max_res)
783
784 type(mg_t), intent(inout) :: mg
785 real(dp), intent(in) :: dt
786 integer, intent(in) :: order
787 real(dp), intent(in) :: max_res
788 integer, parameter :: max_its = 10
789 integer :: n
790 real(dp) :: res
791
792 mg%operator_type = mg_vhelmholtz
793 call mg_set_methods(mg)
794
795 select case (order)
796 case (1)
797 call vhelmholtz_set_lambda(1/dt)
798 call set_rhs(mg, -1/dt, 0.0_dp)
799 case (2)
800 call vhelmholtz_set_lambda(0.0d0)
801 call mg_apply_op(mg, mg_irhs)
802 call vhelmholtz_set_lambda(2/dt)
803 call set_rhs(mg, -2/dt, -1.0_dp)
804 case default
805 error stop "diffusion_solve: order should be 1 or 2"
806 end select
807
808 ! Start with an FMG cycle
809 call mg_fas_fmg(mg, .true., max_res=res)
810
811 ! Add V-cycles if necessary
812 do n = 1, max_its
813 if (res <= max_res) exit
814 call mg_fas_vcycle(mg, max_res=res)
815 end do
816
817 if (n == max_its + 1) then
818 if (mg%my_rank == 0) then
819 print *, "Did you specify boundary conditions correctly?"
820 print *, "Or is the variation in diffusion too large?"
821 end if
822 error stop "diffusion_solve: no convergence"
823 end if
824 end subroutine diffusion_solve_vcoeff
825
826 !> Solve a diffusion equation implicitly, assuming anisotropic diffusion
827 !> coefficient which has been stored in mg_iveps1, mg_iveps2, mg_iveps3
828 !> (also on coarse grids). The
829 !> solution at time t should be stored in mg_iphi, which is on output replaced
830 !> by the solution at time t+dt.
831 subroutine diffusion_solve_acoeff(mg, dt, order, max_res)
832
833 type(mg_t), intent(inout) :: mg
834 real(dp), intent(in) :: dt
835 integer, intent(in) :: order
836 real(dp), intent(in) :: max_res
837 integer, parameter :: max_its = 10
838 integer :: n
839 real(dp) :: res
840
841 mg%operator_type = mg_ahelmholtz
842 call mg_set_methods(mg)
843
844 select case (order)
845 case (1)
846 call ahelmholtz_set_lambda(1/dt)
847 call set_rhs(mg, -1/dt, 0.0_dp)
848 case (2)
849 call ahelmholtz_set_lambda(0.0d0)
850 call mg_apply_op(mg, mg_irhs)
851 call ahelmholtz_set_lambda(2/dt)
852 call set_rhs(mg, -2/dt, -1.0_dp)
853 case default
854 error stop "diffusion_solve: order should be 1 or 2"
855 end select
856
857 ! Start with an FMG cycle
858 call mg_fas_fmg(mg, .true., max_res=res)
859
860 ! Add V-cycles if necessary
861 do n = 1, max_its
862 if (res <= max_res) exit
863 call mg_fas_vcycle(mg, max_res=res)
864 end do
865
866 if (n == max_its + 1) then
867 if (mg%my_rank == 0) then
868 print *, "Did you specify boundary conditions correctly?"
869 print *, "Or is the variation in diffusion too large?"
870 end if
871 error stop "diffusion_solve: no convergence"
872 end if
873 end subroutine diffusion_solve_acoeff
874
875 subroutine set_rhs(mg, f1, f2)
876 type(mg_t), intent(inout) :: mg
877 real(dp), intent(in) :: f1, f2
878 integer :: lvl, i, id, nc
879
880 do lvl = 1, mg%highest_lvl
881 nc = mg%box_size_lvl(lvl)
882 do i = 1, size(mg%lvls(lvl)%my_leaves)
883 id = mg%lvls(lvl)%my_leaves(i)
884 mg%boxes(id)%cc(1:nc, 1:nc, 1:nc, mg_irhs) = &
885 f1 * mg%boxes(id)%cc(1:nc, 1:nc, 1:nc, mg_iphi) + &
886 f2 * mg%boxes(id)%cc(1:nc, 1:nc, 1:nc, mg_irhs)
887 end do
888 end do
889 end subroutine set_rhs
890
891 !! File ../src/m_laplacian.f90
892
894 type(mg_t), intent(inout) :: mg
895
896 if (all(mg%periodic)) then
897 ! For a fully periodic Laplacian, remove the mean from the rhs and phi so
898 ! that a unique and periodic solution can be found
899 mg%subtract_mean = .true.
900 end if
901
902 select case (mg%geometry_type)
903 case (mg_cartesian)
904 mg%box_op => box_lpl
905
906 select case (mg%smoother_type)
907 ! case (smoother_jacobi)
908 ! mg%box_smoother => box_jacobi_lpl
910 mg%box_smoother => box_gs_lpl
911 case default
912 error stop "laplacian_set_methods: unsupported smoother type"
913 end select
914 case default
915 error stop "laplacian_set_methods: unsupported geometry"
916 end select
917
918 end subroutine laplacian_set_methods
919
920 !> Perform Gauss-Seidel relaxation on box for a Laplacian operator
921 subroutine box_gs_lpl(mg, id, nc, redblack_cntr)
922 type(mg_t), intent(inout) :: mg
923 integer, intent(in) :: id
924 integer, intent(in) :: nc
925 integer, intent(in) :: redblack_cntr !< Iteration counter
926 integer :: i, j, k, i0, di
927 real(dp) :: idr2(3), fac
928 logical :: redblack
929 real(dp), parameter :: sixth = 1/6.0_dp
930
931 idr2 = 1/mg%dr(:, mg%boxes(id)%lvl)**2
932 fac = 0.5_dp / sum(idr2)
933 i0 = 1
934
935 redblack = (mg%smoother_type == mg_smoother_gsrb)
936 if (redblack) then
937 di = 2
938 else
939 di = 1
940 end if
941
942 ! The parity of redblack_cntr determines which cells we use. If
943 ! redblack_cntr is even, we use the even cells and vice versa.
944 associate(cc => mg%boxes(id)%cc, n => mg_iphi)
945 do k = 1, nc
946 do j = 1, nc
947 if (redblack) &
948 i0 = 2 - iand(ieor(redblack_cntr, k+j), 1)
949 do i = i0, nc, di
950 cc(i, j, k, n) = fac * ( &
951 idr2(1) * (cc(i+1, j, k, n) + cc(i-1, j, k, n)) + &
952 idr2(2) * (cc(i, j+1, k, n) + cc(i, j-1, k, n)) + &
953 idr2(3) * (cc(i, j, k+1, n) + cc(i, j, k-1, n)) - &
954 cc(i, j, k, mg_irhs))
955 end do
956 end do
957 end do
958 end associate
959 end subroutine box_gs_lpl
960
961! !> Perform Jacobi relaxation on box for a Laplacian operator
962! subroutine box_jacobi_lpl(mg, id, nc, cntr)
963! type(mg_t), intent(inout) :: mg
964! integer, intent(in) :: id
965! integer, intent(in) :: nc
966! integer, intent(in) :: cntr !< Not used
967! integer :: i, j, k
968! real(dp), parameter :: w = 2.0_dp / 3
969! real(dp) :: tmp(0:nc+1, 0:nc+1, 0:nc+1)
970! real(dp) :: dr2
971! #if 3 == 3
972! real(dp), parameter :: sixth = 1/6.0_dp
973! #endif
974
975! dr2 = mg%dr(mg%boxes(id)%lvl)**2
976
977! associate (box => mg%boxes(id))
978! tmp = box%cc(:, :, :, mg_iphi)
979! do j=1, nc; do i=1, nc; do k=1, nc
980! #if 3 == 2
981! box%cc(i, j, mg_iphi) = (1-w) * box%cc(i, j, mg_iphi) + &
982! 0.25_dp * w * ( &
983! tmp(i+1, j) + tmp(i-1, j) + &
984! tmp(i, j+1) + tmp(i, j-1) - &
985! dr2 * box%cc(i, j, mg_irhs))
986! #elif 3 == 3
987! box%cc(i, j, k, mg_iphi) = (1-w) * &
988! box%cc(i, j, k, mg_iphi) + &
989! sixth * w * ( &
990! tmp(i+1, j, k) + tmp(i-1, j, k) + &
991! tmp(i, j+1, k) + tmp(i, j-1, k) + &
992! tmp(i, j, k+1) + tmp(i, j, k-1) - &
993! dr2 * box%cc(i, j, k, mg_irhs))
994! #endif
995! end do; end do; end do
996! end associate
997! end subroutine box_jacobi_lpl
998
999 !> Perform Laplacian operator on a box
1000 subroutine box_lpl(mg, id, nc, i_out)
1001 type(mg_t), intent(inout) :: mg
1002 integer, intent(in) :: id
1003 integer, intent(in) :: nc
1004 integer, intent(in) :: i_out !< Index of variable to store Laplacian in
1005 integer :: i, j, k
1006 real(dp) :: idr2(3)
1007
1008 idr2 = 1 / mg%dr(:, mg%boxes(id)%lvl)**2
1009
1010 associate(cc => mg%boxes(id)%cc, n => mg_iphi)
1011 do k = 1, nc
1012 do j = 1, nc
1013 do i = 1, nc
1014 cc(i, j, k, i_out) = &
1015 idr2(1) * (cc(i-1, j, k, n) + cc(i+1, j, k, n) &
1016 - 2 * cc(i, j, k, n)) &
1017 + idr2(2) * (cc(i, j-1, k, n) + cc(i, j+1, k, n) &
1018 - 2 * cc(i, j, k, n)) &
1019 + idr2(3) * (cc(i, j, k-1, n) + cc(i, j, k+1, n) &
1020 - 2 * cc(i, j, k, n))
1021 end do
1022 end do
1023 end do
1024 end associate
1025 end subroutine box_lpl
1026
1027
1028 !! File ../src/m_vhelmholtz.f90
1029
1031 type(mg_t), intent(inout) :: mg
1032
1033 if (mg%n_extra_vars == 0 .and. mg%is_allocated) then
1034 error stop "vhelmholtz_set_methods: mg%n_extra_vars == 0"
1035 else
1036 mg%n_extra_vars = max(1, mg%n_extra_vars)
1037 end if
1038
1039 mg%subtract_mean = .false.
1040
1041 ! Use Neumann zero boundary conditions for the variable coefficient, since
1042 ! it is needed in ghost cells.
1043 mg%bc(:, mg_iveps)%bc_type = mg_bc_neumann
1044 mg%bc(:, mg_iveps)%bc_value = 0.0_dp
1045
1046 select case (mg%geometry_type)
1047 case (mg_cartesian)
1048 mg%box_op => box_vhelmh
1049
1050 select case (mg%smoother_type)
1052 mg%box_smoother => box_gs_vhelmh
1053 case default
1054 error stop "vhelmholtz_set_methods: unsupported smoother type"
1055 end select
1056 case default
1057 error stop "vhelmholtz_set_methods: unsupported geometry"
1058 end select
1059
1060 end subroutine vhelmholtz_set_methods
1061
1062 subroutine vhelmholtz_set_lambda(lambda)
1063 real(dp), intent(in) :: lambda
1064
1065 if (lambda < 0) &
1066 error stop "vhelmholtz_set_lambda: lambda < 0 not allowed"
1067
1068 vhelmholtz_lambda = lambda
1069 end subroutine vhelmholtz_set_lambda
1070
1071 !> Perform Gauss-Seidel relaxation on box for a Helmholtz operator
1072 subroutine box_gs_vhelmh(mg, id, nc, redblack_cntr)
1073 type(mg_t), intent(inout) :: mg
1074 integer, intent(in) :: id
1075 integer, intent(in) :: nc
1076 integer, intent(in) :: redblack_cntr !< Iteration counter
1077 integer :: i, j, k, i0, di
1078 logical :: redblack
1079 real(dp) :: idr2(2*3), u(2*3)
1080 real(dp) :: a0, a(2*3), c(2*3)
1081
1082 ! Duplicate 1/dr^2 array to multiply neighbor values
1083 idr2(1:2*3:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1084 idr2(2:2*3:2) = idr2(1:2*3:2)
1085 i0 = 1
1086
1087 redblack = (mg%smoother_type == mg_smoother_gsrb)
1088 if (redblack) then
1089 di = 2
1090 else
1091 di = 1
1092 end if
1093
1094 ! The parity of redblack_cntr determines which cells we use. If
1095 ! redblack_cntr is even, we use the even cells and vice versa.
1096 associate(cc => mg%boxes(id)%cc, n => mg_iphi, &
1097 i_eps => mg_iveps)
1098 do k = 1, nc
1099 do j = 1, nc
1100 if (redblack) &
1101 i0 = 2 - iand(ieor(redblack_cntr, k+j), 1)
1102 do i = i0, nc, di
1103 a0 = cc(i, j, k, i_eps)
1104 u(1:2) = cc(i-1:i+1:2, j, k, n)
1105 a(1:2) = cc(i-1:i+1:2, j, k, i_eps)
1106 u(3:4) = cc(i, j-1:j+1:2, k, n)
1107 a(3:4) = cc(i, j-1:j+1:2, k, i_eps)
1108 u(5:6) = cc(i, j, k-1:k+1:2, n)
1109 a(5:6) = cc(i, j, k-1:k+1:2, i_eps)
1110 c(:) = 2 * a0 * a(:) / (a0 + a(:)) * idr2
1111
1112 cc(i, j, k, n) = (sum(c(:) * u(:)) - &
1113 cc(i, j, k, mg_irhs)) / &
1114 (sum(c(:)) + vhelmholtz_lambda)
1115 end do
1116 end do
1117 end do
1118 end associate
1119 end subroutine box_gs_vhelmh
1120
1121 !> Perform Helmholtz operator on a box
1122 subroutine box_vhelmh(mg, id, nc, i_out)
1123 type(mg_t), intent(inout) :: mg
1124 integer, intent(in) :: id
1125 integer, intent(in) :: nc
1126 integer, intent(in) :: i_out !< Index of variable to store Helmholtz in
1127 integer :: i, j, k
1128 real(dp) :: idr2(2*3), a0, u0, u(2*3), a(2*3)
1129
1130 ! Duplicate 1/dr^2 array to multiply neighbor values
1131 idr2(1:2*3:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1132 idr2(2:2*3:2) = idr2(1:2*3:2)
1133
1134 associate(cc => mg%boxes(id)%cc, n => mg_iphi, &
1135 i_eps => mg_iveps)
1136 do k = 1, nc
1137 do j = 1, nc
1138 do i = 1, nc
1139 u0 = cc(i, j, k, n)
1140 a0 = cc(i, j, k, i_eps)
1141 u(1:2) = cc(i-1:i+1:2, j, k, n)
1142 u(3:4) = cc(i, j-1:j+1:2, k, n)
1143 u(5:6) = cc(i, j, k-1:k+1:2, n)
1144 a(1:2) = cc(i-1:i+1:2, j, k, i_eps)
1145 a(3:4) = cc(i, j-1:j+1:2, k, i_eps)
1146 a(5:6) = cc(i, j, k-1:k+1:2, i_eps)
1147
1148 cc(i, j, k, i_out) = sum(2 * idr2 * &
1149 a0*a(:)/(a0 + a(:)) * (u(:) - u0)) - &
1151 end do
1152 end do
1153 end do
1154 end associate
1155 end subroutine box_vhelmh
1156
1157 !! File ../src/m_build_tree.f90
1158
1159 subroutine mg_build_rectangle(mg, domain_size, box_size, dx, r_min, &
1160 periodic, n_finer)
1161 type(mg_t), intent(inout) :: mg
1162 integer, intent(in) :: domain_size(3)
1163 integer, intent(in) :: box_size
1164 real(dp), intent(in) :: dx(3)
1165 real(dp), intent(in) :: r_min(3)
1166 logical, intent(in) :: periodic(3)
1167 integer, intent(in) :: n_finer
1168 integer :: i, j, k, lvl, n, id, nx(3), ijk_vec(3), idim
1169 integer :: boxes_per_dim(3, mg_lvl_lo:1)
1170 integer :: periodic_offset(3)
1171
1172 if (modulo(box_size, 2) /= 0) &
1173 error stop "box_size should be even"
1174 if (any(modulo(domain_size, box_size) /= 0)) &
1175 error stop "box_size does not divide domain_size"
1176
1177 if (all(periodic)) then
1178 mg%subtract_mean = .true.
1179 end if
1180
1181 nx = domain_size
1182 mg%box_size = box_size
1183 mg%box_size_lvl(1) = box_size
1184 mg%domain_size_lvl(:, 1) = domain_size
1185 mg%first_normal_lvl = 1
1186 mg%dr(:, 1) = dx
1187 mg%r_min(:) = r_min
1188 mg%periodic = periodic
1189 boxes_per_dim(:, :) = 0
1190 boxes_per_dim(:, 1) = domain_size / box_size
1191
1192 do lvl = 1, mg_lvl_lo+1, -1
1193 ! For a Gauss-Seidel (non red-black) smoother, we should avoid boxes
1194 ! containing a single cell
1195 if (any(modulo(nx, 2) == 1 .or. nx == mg%coarsest_grid .or. &
1196 (mg%box_size_lvl(lvl) == mg%coarsest_grid .and. &
1197 mg%smoother_type == mg_smoother_gs))) exit
1198
1199 if (all(modulo(nx/mg%box_size_lvl(lvl), 2) == 0)) then
1200 mg%box_size_lvl(lvl-1) = mg%box_size_lvl(lvl)
1201 boxes_per_dim(:, lvl-1) = boxes_per_dim(:, lvl)/2
1202 mg%first_normal_lvl = lvl-1
1203 else
1204 mg%box_size_lvl(lvl-1) = mg%box_size_lvl(lvl)/2
1205 boxes_per_dim(:, lvl-1) = boxes_per_dim(:, lvl)
1206 end if
1207
1208 mg%dr(:, lvl-1) = mg%dr(:, lvl) * 2
1209 nx = nx / 2
1210 mg%domain_size_lvl(:, lvl-1) = nx
1211 end do
1212
1213 mg%lowest_lvl = lvl
1214 mg%highest_lvl = 1
1215
1216 do lvl = 2, mg_lvl_hi
1217 mg%dr(:, lvl) = mg%dr(:, lvl-1) * 0.5_dp
1218 mg%box_size_lvl(lvl) = box_size
1219 mg%domain_size_lvl(:, lvl) = 2 * mg%domain_size_lvl(:, lvl-1)
1220 end do
1221
1222 n = sum(product(boxes_per_dim, dim=1)) + n_finer
1223 allocate(mg%boxes(n))
1224
1225 ! Create lowest level
1226 nx = boxes_per_dim(:, mg%lowest_lvl)
1227 periodic_offset = [nx(1)-1, (nx(2)-1)*nx(1), &
1228 (nx(3)-1) * nx(2) * nx(1)]
1229
1230 do k=1,nx(3); do j=1,nx(2); do i=1,nx(1)
1231 mg%n_boxes = mg%n_boxes + 1
1232 n = mg%n_boxes
1233
1234 mg%boxes(n)%rank = 0
1235 mg%boxes(n)%id = n
1236 mg%boxes(n)%lvl = mg%lowest_lvl
1237 mg%boxes(n)%ix(:) = [i, j, k]
1238 mg%boxes(n)%r_min(:) = r_min + (mg%boxes(n)%ix(:) - 1) * &
1239 mg%box_size_lvl(mg%lowest_lvl) * mg%dr(:, mg%lowest_lvl)
1240 mg%boxes(n)%dr(:) = mg%dr(:, mg%lowest_lvl)
1241 mg%boxes(n)%parent = mg_no_box
1242 mg%boxes(n)%children(:) = mg_no_box
1243
1244 ! Set default neighbors
1245 mg%boxes(n)%neighbors(:) = [n-1, n+1, n-nx(1), n+nx(1), &
1246 n-nx(1)*nx(2), n+nx(1)*nx(2)]
1247
1248 ! Handle boundaries
1249 ijk_vec = [i, j, k]
1250 do idim = 1, 3
1251 if (ijk_vec(idim) == 1) then
1252 if (periodic(idim)) then
1253 mg%boxes(n)%neighbors(2*idim-1) = n + periodic_offset(idim)
1254 else
1255 mg%boxes(n)%neighbors(2*idim-1) = mg_physical_boundary
1256 end if
1257 end if
1258
1259 if (ijk_vec(idim) == nx(idim)) then
1260 if (periodic(idim)) then
1261 mg%boxes(n)%neighbors(2*idim) = n - periodic_offset(idim)
1262 else
1263 mg%boxes(n)%neighbors(2*idim) = mg_physical_boundary
1264 end if
1265 end if
1266 end do
1267 end do; end do; end do
1268
1269 mg%lvls(mg%lowest_lvl)%ids = [(n, n=1, mg%n_boxes)]
1270
1271 ! Add higher levels
1272 do lvl = mg%lowest_lvl, 0
1273 if (mg%box_size_lvl(lvl+1) == mg%box_size_lvl(lvl)) then
1274 do i = 1, size(mg%lvls(lvl)%ids)
1275 id = mg%lvls(lvl)%ids(i)
1276 call mg_add_children(mg, id)
1277 end do
1278
1279 call mg_set_leaves_parents(mg%boxes, mg%lvls(lvl))
1280 call mg_set_next_level_ids(mg, lvl)
1281 call mg_set_neighbors_lvl(mg, lvl+1)
1282 else
1283 do i = 1, size(mg%lvls(lvl)%ids)
1284 id = mg%lvls(lvl)%ids(i)
1285 call add_single_child(mg, id, size(mg%lvls(lvl)%ids))
1286 end do
1287
1288 call mg_set_leaves_parents(mg%boxes, mg%lvls(lvl))
1289 call mg_set_next_level_ids(mg, lvl)
1290 end if
1291 end do
1292
1293 call mg_set_leaves_parents(mg%boxes, mg%lvls(1))
1294
1295 ! No refinement boundaries
1296 do lvl = mg%lowest_lvl, 1
1297 if (allocated(mg%lvls(lvl)%ref_bnds)) &
1298 deallocate(mg%lvls(lvl)%ref_bnds)
1299 allocate(mg%lvls(lvl)%ref_bnds(0))
1300 end do
1301
1302 mg%tree_created = .true.
1303 end subroutine mg_build_rectangle
1304
1305 subroutine mg_set_neighbors_lvl(mg, lvl)
1306 type(mg_t), intent(inout) :: mg
1307 integer, intent(in) :: lvl
1308 integer :: i, id
1309
1310 do i = 1, size(mg%lvls(lvl)%ids)
1311 id = mg%lvls(lvl)%ids(i)
1312 call set_neighbs(mg%boxes, id)
1313 end do
1314 end subroutine mg_set_neighbors_lvl
1315
1316 subroutine mg_set_next_level_ids(mg, lvl)
1317 type(mg_t), intent(inout) :: mg
1318 integer, intent(in) :: lvl
1319 integer :: n, i, id
1320
1321 if (allocated(mg%lvls(lvl+1)%ids)) &
1322 deallocate(mg%lvls(lvl+1)%ids)
1323
1324 ! Set next level ids to children of this level
1325 if (mg%box_size_lvl(lvl+1) == mg%box_size_lvl(lvl)) then
1326 n = mg_num_children * size(mg%lvls(lvl)%parents)
1327 allocate(mg%lvls(lvl+1)%ids(n))
1328
1329 n = mg_num_children
1330 do i = 1, size(mg%lvls(lvl)%parents)
1331 id = mg%lvls(lvl)%parents(i)
1332 mg%lvls(lvl+1)%ids(n*(i-1)+1:n*i) = mg%boxes(id)%children
1333 end do
1334 else
1335 n = size(mg%lvls(lvl)%parents)
1336 allocate(mg%lvls(lvl+1)%ids(n))
1337
1338 n = 1
1339 do i = 1, size(mg%lvls(lvl)%parents)
1340 id = mg%lvls(lvl)%parents(i)
1341 mg%lvls(lvl+1)%ids(i) = mg%boxes(id)%children(1)
1342 end do
1343 end if
1344
1345 end subroutine mg_set_next_level_ids
1346
1347 ! Set the neighbors of id (using their parent)
1348 subroutine set_neighbs(boxes, id)
1349 type(mg_box_t), intent(inout) :: boxes(:)
1350 integer, intent(in) :: id
1351 integer :: nb, nb_id
1352
1353 do nb = 1, mg_num_neighbors
1354 if (boxes(id)%neighbors(nb) == mg_no_box) then
1355 nb_id = find_neighb(boxes, id, nb)
1356 if (nb_id > mg_no_box) then
1357 boxes(id)%neighbors(nb) = nb_id
1358 boxes(nb_id)%neighbors(mg_neighb_rev(nb)) = id
1359 end if
1360 end if
1361 end do
1362 end subroutine set_neighbs
1363
1364 !> Get the id of neighbor nb of boxes(id), through its parent
1365 function find_neighb(boxes, id, nb) result(nb_id)
1366 type(mg_box_t), intent(in) :: boxes(:) !< List with all the boxes
1367 integer, intent(in) :: id !< Box whose neighbor we are looking for
1368 integer, intent(in) :: nb !< Neighbor index
1369 integer :: nb_id, p_id, c_ix, d, old_pid
1370
1371 p_id = boxes(id)%parent
1372 old_pid = p_id
1373 c_ix = mg_ix_to_ichild(boxes(id)%ix)
1374 d = mg_neighb_dim(nb)
1375
1376 ! Check if neighbor is in same direction as ix is (low/high). If so,
1377 ! use neighbor of parent
1378 if (mg_child_low(d, c_ix) .eqv. mg_neighb_low(nb)) then
1379 p_id = boxes(p_id)%neighbors(nb)
1380 end if
1381
1382 ! The child ix of the neighbor is reversed in direction d
1383 nb_id = boxes(p_id)%children(mg_child_rev(c_ix, d))
1384 end function find_neighb
1385
1386 !> Create a list of leaves and a list of parents for a level
1387 subroutine mg_set_leaves_parents(boxes, level)
1388 type(mg_box_t), intent(in) :: boxes(:) !< List of boxes
1389 type(mg_lvl_t), intent(inout) :: level !< Level type which contains the indices of boxes
1390 integer :: i, id, i_leaf, i_parent
1391 integer :: n_parents, n_leaves
1392
1393 n_parents = count(mg_has_children(boxes(level%ids)))
1394 n_leaves = size(level%ids) - n_parents
1395
1396 if (.not. allocated(level%parents)) then
1397 allocate(level%parents(n_parents))
1398 else if (n_parents /= size(level%parents)) then
1399 deallocate(level%parents)
1400 allocate(level%parents(n_parents))
1401 end if
1402
1403 if (.not. allocated(level%leaves)) then
1404 allocate(level%leaves(n_leaves))
1405 else if (n_leaves /= size(level%leaves)) then
1406 deallocate(level%leaves)
1407 allocate(level%leaves(n_leaves))
1408 end if
1409
1410 i_leaf = 0
1411 i_parent = 0
1412 do i = 1, size(level%ids)
1413 id = level%ids(i)
1414 if (mg_has_children(boxes(id))) then
1415 i_parent = i_parent + 1
1416 level%parents(i_parent) = id
1417 else
1418 i_leaf = i_leaf + 1
1419 level%leaves(i_leaf) = id
1420 end if
1421 end do
1422 end subroutine mg_set_leaves_parents
1423
1424 !> Create a list of refinement boundaries (from the coarse side)
1425 subroutine mg_set_refinement_boundaries(boxes, level)
1426 type(mg_box_t), intent(in) :: boxes(:)
1427 type(mg_lvl_t), intent(inout) :: level
1428 integer, allocatable :: tmp(:)
1429 integer :: i, id, nb, nb_id, ix
1430
1431 if (allocated(level%ref_bnds)) deallocate(level%ref_bnds)
1432
1433 if (size(level%parents) == 0) then
1434 ! There are no refinement boundaries
1435 allocate(level%ref_bnds(0))
1436 else
1437 allocate(tmp(size(level%leaves)))
1438 ix = 0
1439 do i = 1, size(level%leaves)
1440 id = level%leaves(i)
1441
1442 do nb = 1, mg_num_neighbors
1443 nb_id = boxes(id)%neighbors(nb)
1444 if (nb_id > mg_no_box) then
1445 if (mg_has_children(boxes(nb_id))) then
1446 ix = ix + 1
1447 tmp(ix) = id
1448 exit
1449 end if
1450 end if
1451 end do
1452 end do
1453
1454 allocate(level%ref_bnds(ix))
1455 level%ref_bnds(:) = tmp(1:ix)
1456 end if
1457 end subroutine mg_set_refinement_boundaries
1458
1459 subroutine mg_add_children(mg, id)
1460 type(mg_t), intent(inout) :: mg
1461 integer, intent(in) :: id !< Id of box that gets children
1462 integer :: lvl, i, nb, child_nb(2**(3-1))
1463 integer :: c_ids(mg_num_children)
1464 integer :: c_id, c_ix_base(3)
1465
1466 if (mg%n_boxes + mg_num_children > size(mg%boxes)) then
1467 error stop "mg_add_children: not enough space"
1468 end if
1469
1470 c_ids = [(mg%n_boxes+i, i=1,mg_num_children)]
1471 mg%n_boxes = mg%n_boxes + mg_num_children
1472 mg%boxes(id)%children = c_ids
1473 c_ix_base = 2 * mg%boxes(id)%ix - 1
1474 lvl = mg%boxes(id)%lvl+1
1475
1476 do i = 1, mg_num_children
1477 c_id = c_ids(i)
1478 mg%boxes(c_id)%rank = mg%boxes(id)%rank
1479 mg%boxes(c_id)%ix = c_ix_base + mg_child_dix(:, i)
1480 mg%boxes(c_id)%lvl = lvl
1481 mg%boxes(c_id)%parent = id
1482 mg%boxes(c_id)%children = mg_no_box
1483 mg%boxes(c_id)%neighbors = mg_no_box
1484 mg%boxes(c_id)%r_min = mg%boxes(id)%r_min + &
1485 mg%dr(:, lvl) * mg_child_dix(:, i) * mg%box_size
1486 mg%boxes(c_id)%dr(:) = mg%dr(:, lvl)
1487 end do
1488
1489 ! Set boundary conditions at children
1490 do nb = 1, mg_num_neighbors
1491 if (mg%boxes(id)%neighbors(nb) < mg_no_box) then
1492 child_nb = c_ids(mg_child_adj_nb(:, nb)) ! Neighboring children
1493 mg%boxes(child_nb)%neighbors(nb) = mg%boxes(id)%neighbors(nb)
1494 end if
1495 end do
1496 end subroutine mg_add_children
1497
1498 subroutine add_single_child(mg, id, n_boxes_lvl)
1499 type(mg_t), intent(inout) :: mg
1500 integer, intent(in) :: id !< Id of box that gets children
1501 integer, intent(in) :: n_boxes_lvl
1502 integer :: lvl, c_id
1503
1504 c_id = mg%n_boxes + 1
1505 mg%n_boxes = mg%n_boxes + 1
1506 mg%boxes(id)%children(1) = c_id
1507 lvl = mg%boxes(id)%lvl+1
1508
1509 mg%boxes(c_id)%rank = mg%boxes(id)%rank
1510 mg%boxes(c_id)%ix = mg%boxes(id)%ix
1511 mg%boxes(c_id)%lvl = lvl
1512 mg%boxes(c_id)%parent = id
1513 mg%boxes(c_id)%children = mg_no_box
1514 where (mg%boxes(id)%neighbors == mg_physical_boundary)
1515 mg%boxes(c_id)%neighbors = mg%boxes(id)%neighbors
1516 elsewhere
1517 mg%boxes(c_id)%neighbors = mg%boxes(id)%neighbors + n_boxes_lvl
1518 end where
1519 mg%boxes(c_id)%r_min = mg%boxes(id)%r_min
1520 mg%boxes(c_id)%dr(:) = mg%dr(:, lvl)
1521
1522 end subroutine add_single_child
1523
1524 !! File ../src/m_load_balance.f90
1525
1526 !> Load balance all boxes in the multigrid tree, by simply distributing the
1527 !> load per grid level. This method will only work well for uniform grids.
1528 !>
1529 !> Note that in a typical application the load balancing of the leaves is
1530 !> already determined, then mg_load_balance_parents can be used.
1532 type(mg_t), intent(inout) :: mg
1533 integer :: i, id, lvl, single_cpu_lvl
1534 integer :: work_left, my_work, i_cpu
1535
1536 ! Up to this level, all boxes have to be on a single processor because they
1537 ! have a different size and the communication routines do not support this
1538 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1539
1540 do lvl = mg%lowest_lvl, single_cpu_lvl
1541 do i = 1, size(mg%lvls(lvl)%ids)
1542 id = mg%lvls(lvl)%ids(i)
1543 mg%boxes(id)%rank = 0
1544 end do
1545 end do
1546
1547 ! Distribute the boxes equally. Due to the way the mesh is constructed, the
1548 ! mg%lvls(lvl)%ids array already contains a Morton-like ordering.
1549 do lvl = single_cpu_lvl+1, mg%highest_lvl
1550 work_left = size(mg%lvls(lvl)%ids)
1551 my_work = 0
1552 i_cpu = 0
1553
1554 do i = 1, size(mg%lvls(lvl)%ids)
1555 if ((mg%n_cpu - i_cpu - 1) * my_work >= work_left) then
1556 i_cpu = i_cpu + 1
1557 my_work = 0
1558 end if
1559
1560 my_work = my_work + 1
1561 work_left = work_left - 1
1562
1563 id = mg%lvls(lvl)%ids(i)
1564 mg%boxes(id)%rank = i_cpu
1565 end do
1566 end do
1567
1568 do lvl = mg%lowest_lvl, mg%highest_lvl
1569 call update_lvl_info(mg, mg%lvls(lvl))
1570 end do
1571
1572 end subroutine mg_load_balance_simple
1573
1574 !> Load balance all boxes in the multigrid tree. Compared to
1575 !> mg_load_balance_simple, this method does a better job of setting the ranks
1576 !> of parent boxes
1577 !>
1578 !> Note that in a typical application the load balancing of the leaves is
1579 !> already determined, then mg_load_balance_parents can be used.
1580 subroutine mg_load_balance(mg)
1581 type(mg_t), intent(inout) :: mg
1582 integer :: i, id, lvl, single_cpu_lvl
1583 integer :: work_left, my_work(0:mg%n_cpu), i_cpu
1584 integer :: c_ids(mg_num_children)
1585 integer :: c_ranks(mg_num_children)
1586 integer :: coarse_rank
1587
1588 ! Up to this level, all boxes have to be on a single processor because they
1589 ! have a different size and the communication routines do not support this
1590 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1591
1592 ! Distribute the boxes equally. Due to the way the mesh is constructed, the
1593 ! mg%lvls(lvl)%ids array already contains a Morton-like ordering.
1594 do lvl = mg%highest_lvl, single_cpu_lvl+1, -1
1595 ! For parents determine the rank based on their child ranks
1596 my_work(:) = 0
1597
1598 do i = 1, size(mg%lvls(lvl)%parents)
1599 id = mg%lvls(lvl)%parents(i)
1600
1601 c_ids = mg%boxes(id)%children
1602 c_ranks = mg%boxes(c_ids)%rank
1603 i_cpu = most_popular(c_ranks, my_work, mg%n_cpu)
1604 mg%boxes(id)%rank = i_cpu
1605 my_work(i_cpu) = my_work(i_cpu) + 1
1606 end do
1607
1608 work_left = size(mg%lvls(lvl)%leaves)
1609 i_cpu = 0
1610
1611 do i = 1, size(mg%lvls(lvl)%leaves)
1612 ! Skip this CPU if it already has enough work
1613 if ((mg%n_cpu - i_cpu - 1) * my_work(i_cpu) >= &
1614 work_left + sum(my_work(i_cpu+1:))) then
1615 i_cpu = i_cpu + 1
1616 end if
1617
1618 my_work(i_cpu) = my_work(i_cpu) + 1
1619 work_left = work_left - 1
1620
1621 id = mg%lvls(lvl)%leaves(i)
1622 mg%boxes(id)%rank = i_cpu
1623 end do
1624 end do
1625
1626 ! Determine most popular CPU for coarse grids
1627 if (single_cpu_lvl < mg%highest_lvl) then
1628 coarse_rank = most_popular(mg%boxes(&
1629 mg%lvls(single_cpu_lvl+1)%ids)%rank, my_work, mg%n_cpu)
1630 else
1631 coarse_rank = 0
1632 end if
1633
1634 do lvl = mg%lowest_lvl, single_cpu_lvl
1635 do i = 1, size(mg%lvls(lvl)%ids)
1636 id = mg%lvls(lvl)%ids(i)
1637 mg%boxes(id)%rank = coarse_rank
1638 end do
1639 end do
1640
1641 do lvl = mg%lowest_lvl, mg%highest_lvl
1642 call update_lvl_info(mg, mg%lvls(lvl))
1643 end do
1644
1645 end subroutine mg_load_balance
1646
1647 !> Load balance the parents (non-leafs). Assign them to the rank that has most
1648 !> children.
1650 type(mg_t), intent(inout) :: mg
1651 integer :: i, id, lvl, n_boxes
1652 integer :: c_ids(mg_num_children)
1653 integer :: c_ranks(mg_num_children)
1654 integer :: single_cpu_lvl, coarse_rank
1655 integer :: my_work(0:mg%n_cpu), i_cpu
1656 integer, allocatable :: ranks(:)
1657
1658 ! Up to this level, all boxes have to be on a single processor because they
1659 ! have a different size and the communication routines do not support this
1660 single_cpu_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
1661
1662 do lvl = mg%highest_lvl-1, single_cpu_lvl+1, -1
1663 my_work(:) = 0
1664
1665 ! Determine amount of work for the leaves
1666 do i = 1, size(mg%lvls(lvl)%leaves)
1667 id = mg%lvls(lvl)%leaves(i)
1668 i_cpu = mg%boxes(id)%rank
1669 my_work(i_cpu) = my_work(i_cpu) + 1
1670 end do
1671
1672 do i = 1, size(mg%lvls(lvl)%parents)
1673 id = mg%lvls(lvl)%parents(i)
1674
1675 c_ids = mg%boxes(id)%children
1676 c_ranks = mg%boxes(c_ids)%rank
1677 i_cpu = most_popular(c_ranks, my_work, mg%n_cpu)
1678 mg%boxes(id)%rank = i_cpu
1679 my_work(i_cpu) = my_work(i_cpu) + 1
1680 end do
1681
1682 end do
1683
1684 ! Determine most popular CPU for coarse grids
1685 if (single_cpu_lvl < mg%highest_lvl) then
1686 ! Get ranks of boxes at single_cpu_lvl+1
1687 n_boxes = size(mg%lvls(single_cpu_lvl+1)%ids)
1688 allocate(ranks(n_boxes))
1689 ranks(:) = mg%boxes(mg%lvls(single_cpu_lvl+1)%ids)%rank
1690
1691 coarse_rank = most_popular(ranks, my_work, mg%n_cpu)
1692 deallocate(ranks)
1693 else
1694 coarse_rank = 0
1695 end if
1696
1697 do lvl = mg%lowest_lvl, single_cpu_lvl
1698 do i = 1, size(mg%lvls(lvl)%ids)
1699 id = mg%lvls(lvl)%ids(i)
1700 mg%boxes(id)%rank = coarse_rank
1701 end do
1702 end do
1703
1704 do lvl = mg%lowest_lvl, mg%highest_lvl
1705 call update_lvl_info(mg, mg%lvls(lvl))
1706 end do
1707
1708 end subroutine mg_load_balance_parents
1709
1710 !> Determine most popular rank in the list. In case of ties, assign the rank
1711 !> with the least work.
1712 pure integer function most_popular(list, work, n_cpu)
1713 integer, intent(in) :: list(:) !< List of MPI ranks
1714 integer, intent(in) :: n_cpu
1715 integer, intent(in) :: work(0:n_cpu-1) !< Existing work per rank
1716 integer :: i, best_count, current_count
1717 integer :: my_work, best_work
1718
1719 best_count = 0
1720 best_work = 0
1721 most_popular = -1
1722
1723 do i = 1, size(list)
1724 current_count = count(list == list(i))
1725 my_work = work(list(i))
1726
1727 ! In case of ties, select task with lowest work
1728 if (current_count > best_count .or. &
1729 current_count == best_count .and. my_work < best_work) then
1730 best_count = current_count
1731 best_work = my_work
1732 most_popular = list(i)
1733 end if
1734 end do
1735
1736 end function most_popular
1737
1738 subroutine update_lvl_info(mg, lvl)
1739 type(mg_t), intent(inout) :: mg
1740 type(mg_lvl_t), intent(inout) :: lvl
1741
1742 lvl%my_ids = pack(lvl%ids, &
1743 mg%boxes(lvl%ids)%rank == mg%my_rank)
1744 lvl%my_leaves = pack(lvl%leaves, &
1745 mg%boxes(lvl%leaves)%rank == mg%my_rank)
1746 lvl%my_parents = pack(lvl%parents, &
1747 mg%boxes(lvl%parents)%rank == mg%my_rank)
1748 lvl%my_ref_bnds = pack(lvl%ref_bnds, &
1749 mg%boxes(lvl%ref_bnds)%rank == mg%my_rank)
1750 end subroutine update_lvl_info
1751
1752 !! File ../src/m_vlaplacian.f90
1753
1755 type(mg_t), intent(inout) :: mg
1756
1757 if (mg%n_extra_vars == 0 .and. mg%is_allocated) then
1758 error stop "vlaplacian_set_methods: mg%n_extra_vars == 0"
1759 else
1760 mg%n_extra_vars = max(1, mg%n_extra_vars)
1761 end if
1762
1763 mg%subtract_mean = .false.
1764
1765 ! Use Neumann zero boundary conditions for the variable coefficient, since
1766 ! it is needed in ghost cells.
1767 mg%bc(:, mg_iveps)%bc_type = mg_bc_neumann
1768 mg%bc(:, mg_iveps)%bc_value = 0.0_dp
1769
1770 select case (mg%geometry_type)
1771 case (mg_cartesian)
1772 mg%box_op => box_vlpl
1773
1774 ! TODO: test whether a custom prolongation works better
1775 ! mg%box_prolong => vlpl_prolong
1776
1777 select case (mg%smoother_type)
1779 mg%box_smoother => box_gs_vlpl
1780 case default
1781 error stop "vlaplacian_set_methods: unsupported smoother type"
1782 end select
1783
1784 case default
1785 error stop "vlaplacian_set_methods: unsupported geometry"
1786 end select
1787
1788 end subroutine vlaplacian_set_methods
1789
1790 !> Perform Gauss-Seidel relaxation on box for a Laplacian operator
1791 subroutine box_gs_vlpl(mg, id, nc, redblack_cntr)
1792 type(mg_t), intent(inout) :: mg
1793 integer, intent(in) :: id
1794 integer, intent(in) :: nc
1795 integer, intent(in) :: redblack_cntr !< Iteration counter
1796 integer :: i, j, k, i0, di
1797 logical :: redblack
1798 real(dp) :: idr2(2*3), u(2*3)
1799 real(dp) :: a0, a(2*3), c(2*3)
1800
1801 ! Duplicate 1/dr^2 array to multiply neighbor values
1802 idr2(1:2*3:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1803 idr2(2:2*3:2) = idr2(1:2*3:2)
1804 i0 = 1
1805
1806 redblack = (mg%smoother_type == mg_smoother_gsrb)
1807 if (redblack) then
1808 di = 2
1809 else
1810 di = 1
1811 end if
1812
1813 ! The parity of redblack_cntr determines which cells we use. If
1814 ! redblack_cntr is even, we use the even cells and vice versa.
1815 associate(cc => mg%boxes(id)%cc, n => mg_iphi, &
1816 i_eps => mg_iveps)
1817 do k = 1, nc
1818 do j = 1, nc
1819 if (redblack) &
1820 i0 = 2 - iand(ieor(redblack_cntr, k+j), 1)
1821 do i = i0, nc, di
1822 a0 = cc(i, j, k, i_eps)
1823 u(1:2) = cc(i-1:i+1:2, j, k, n)
1824 a(1:2) = cc(i-1:i+1:2, j, k, i_eps)
1825 u(3:4) = cc(i, j-1:j+1:2, k, n)
1826 a(3:4) = cc(i, j-1:j+1:2, k, i_eps)
1827 u(5:6) = cc(i, j, k-1:k+1:2, n)
1828 a(5:6) = cc(i, j, k-1:k+1:2, i_eps)
1829 c(:) = 2 * a0 * a(:) / (a0 + a(:)) * idr2
1830
1831 cc(i, j, k, n) = (sum(c(:) * u(:)) - &
1832 cc(i, j, k, mg_irhs)) / sum(c(:))
1833 end do
1834 end do
1835 end do
1836 end associate
1837 end subroutine box_gs_vlpl
1838
1839 !> Perform Laplacian operator on a box
1840 subroutine box_vlpl(mg, id, nc, i_out)
1841 type(mg_t), intent(inout) :: mg
1842 integer, intent(in) :: id
1843 integer, intent(in) :: nc
1844 integer, intent(in) :: i_out !< Index of variable to store Laplacian in
1845 integer :: i, j, k
1846 real(dp) :: idr2(2*3), a0, u0, u(2*3), a(2*3)
1847
1848 ! Duplicate 1/dr^2 array to multiply neighbor values
1849 idr2(1:2*3:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
1850 idr2(2:2*3:2) = idr2(1:2*3:2)
1851
1852 associate(cc => mg%boxes(id)%cc, n => mg_iphi, &
1853 i_eps => mg_iveps)
1854 do k = 1, nc
1855 do j = 1, nc
1856 do i = 1, nc
1857 u0 = cc(i, j, k, n)
1858 a0 = cc(i, j, k, i_eps)
1859 u(1:2) = cc(i-1:i+1:2, j, k, n)
1860 u(3:4) = cc(i, j-1:j+1:2, k, n)
1861 u(5:6) = cc(i, j, k-1:k+1:2, n)
1862 a(1:2) = cc(i-1:i+1:2, j, k, i_eps)
1863 a(3:4) = cc(i, j-1:j+1:2, k, i_eps)
1864 a(5:6) = cc(i, j, k-1:k+1:2, i_eps)
1865
1866 cc(i, j, k, i_out) = sum(2 * idr2 * &
1867 a0*a(:)/(a0 + a(:)) * (u(:) - u0))
1868 end do
1869 end do
1870 end do
1871 end associate
1872 end subroutine box_vlpl
1873
1874 !> Prolong from a parent to a child with index offset dix. This method could
1875 !> sometimes work better than the default prolongation, which does not take
1876 !> the variation in epsilon into account
1877! subroutine vlpl_prolong(mg, p_id, dix, nc, iv, fine)
1878! type(mg_t), intent(inout) :: mg
1879! integer, intent(in) :: p_id !< Id of parent
1880! integer, intent(in) :: dix(3) !< Offset of child in parent grid
1881! integer, intent(in) :: nc !< Child grid size
1882! integer, intent(in) :: iv !< Prolong from this variable
1883! real(dp), intent(out) :: fine(nc, nc, nc) !< Prolonged values
1884
1885! integer :: i, j, k, hnc
1886! #if 3 == 2
1887! integer :: ic, jc
1888! real(dp) :: f0, flx, fhx, fly, fhy
1889! real(dp) :: c0, clx, chx, cly, chy
1890! #elif 3 == 3
1891! integer :: ic, jc, kc
1892! real(dp) :: f0, flx, fhx, fly, fhy, flz, fhz
1893! real(dp) :: c0, clx, chx, cly, chy, clz, chz
1894! #endif
1895
1896! hnc = nc/2
1897
1898! associate (crs => mg%boxes(p_id)%cc, &
1899! i_eps => mg_iveps)
1900! #if 3 == 2
1901! do j = 1, hnc
1902! jc = j + dix(2)
1903! do i = 1, hnc
1904! ic = i + dix(1)
1905
1906! f0 = crs(ic, jc, iv)
1907! flx = crs(ic-1, jc, iv)
1908! fhx = crs(ic+1, jc, iv)
1909! fly = crs(ic, jc-1, iv)
1910! fhy = crs(ic, jc+1, iv)
1911
1912! c0 = 2 * crs(ic, jc, i_eps)
1913! clx = crs(ic-1, jc, i_eps)
1914! chx = crs(ic+1, jc, i_eps)
1915! cly = crs(ic, jc-1, i_eps)
1916! chy = crs(ic, jc+1, i_eps)
1917
1918! fine(2*i-1, 2*j-1) = (f0*c0 + flx*clx + fly*cly) / &
1919! (c0 + clx + cly)
1920! fine(2*i , 2*j-1) = (f0*c0 + fhx*chx + fly*cly) / &
1921! (c0 + chx + cly)
1922! fine(2*i-1, 2*j) = (f0*c0 + flx*clx + fhy*chy) / &
1923! (c0 + clx + chy)
1924! fine(2*i , 2*j) = (f0*c0 + fhx*chx + fhy*chy) / &
1925! (c0 + chx + chy)
1926! end do
1927! end do
1928! #elif 3 == 3
1929! do k = 1, hnc
1930! kc = k + dix(3)
1931! do j = 1, hnc
1932! jc = j + dix(2)
1933! do i = 1, hnc
1934! ic = i + dix(1)
1935
1936! f0 = crs(ic, jc, kc, iv)
1937! flx = crs(ic-1, jc, kc, iv)
1938! fhx = crs(ic+1, jc, kc, iv)
1939! fly = crs(ic, jc-1, kc, iv)
1940! fhy = crs(ic, jc+1, kc, iv)
1941! flz = crs(ic, jc, kc-1, iv)
1942! fhz = crs(ic, jc, kc+1, iv)
1943
1944! c0 = crs(ic, jc, kc, i_eps)
1945! clx = crs(ic-1, jc, kc, i_eps)
1946! chx = crs(ic+1, jc, kc, i_eps)
1947! cly = crs(ic, jc-1, kc, i_eps)
1948! chy = crs(ic, jc+1, kc, i_eps)
1949! clz = crs(ic, jc, kc-1, i_eps)
1950! chz = crs(ic, jc, kc+1, i_eps)
1951
1952! fine(2*i-1, 2*j-1, 2*k-1) = (f0*c0 + flx*clx + fly*cly + flz*clz) / &
1953! (c0 + clx + cly + clz)
1954! fine(2*i, 2*j-1, 2*k-1) = (f0*c0 + fhx*chx + fly*cly + flz*clz) / &
1955! (c0 + chx + cly + clz)
1956! fine(2*i-1, 2*j, 2*k-1) = (f0*c0 + flx*clx + fhy*chy + flz*clz) / &
1957! (c0 + clx + chy + clz)
1958! fine(2*i, 2*j, 2*k-1) = (f0*c0 + fhx*chx + fhy*chy + flz*clz) / &
1959! (c0 + chx + chy + clz)
1960! fine(2*i-1, 2*j-1, 2*k) = (f0*c0 + flx*clx + fly*cly + fhz*chz) / &
1961! (c0 + clx + cly + chz)
1962! fine(2*i, 2*j-1, 2*k) = (f0*c0 + fhx*chx + fly*cly + fhz*chz) / &
1963! (c0 + chx + cly + chz)
1964! fine(2*i-1, 2*j, 2*k) = (f0*c0 + flx*clx + fhy*chy + fhz*chz) / &
1965! (c0 + clx + chy + chz)
1966! fine(2*i, 2*j, 2*k) = (f0*c0 + fhx*chx + fhy*chy + fhz*chz) / &
1967! (c0 + chx + chy + chz)
1968! end do
1969! end do
1970! end do
1971! #endif
1972! end associate
1973! end subroutine vlpl_prolong
1974
1975 !! File ../src/m_communication.f90
1976
1977 !> Initialize MPI if needed, and store MPI information
1978 subroutine mg_comm_init(mg, comm)
1979 use mpi
1980 type(mg_t), intent(inout) :: mg
1981 !> MPI communicator (default: MPI_COMM_WORLD)
1982 integer, intent(in), optional :: comm
1983 integer :: ierr
1984 logical :: initialized
1985
1986 call mpi_initialized(initialized, ierr)
1987 if (.not. initialized) then
1988 call mpi_init(ierr)
1989 end if
1990
1991 if (present(comm)) then
1992 mg%comm = comm
1993 else
1994 mg%comm = mpi_comm_world
1995 end if
1996
1997 call mpi_comm_rank(mg%comm, mg%my_rank, ierr)
1998 call mpi_comm_size(mg%comm, mg%n_cpu, ierr)
1999 end subroutine mg_comm_init
2000
2001 subroutine sort_and_transfer_buffers(mg, dsize)
2002 use mpi
2003 type(mg_t), intent(inout) :: mg
2004 integer, intent(in) :: dsize
2005 integer :: i, n_send, n_recv
2006 integer :: send_req(mg%n_cpu)
2007 integer :: recv_req(mg%n_cpu)
2008 integer :: ierr
2009
2010 n_send = 0
2011 n_recv = 0
2012
2013 do i = 0, mg%n_cpu - 1
2014 if (mg%buf(i)%i_send > 0) then
2015 n_send = n_send + 1
2016 call sort_sendbuf(mg%buf(i), dsize)
2017 call mpi_isend(mg%buf(i)%send, mg%buf(i)%i_send, mpi_double, &
2018 i, 0, mg%comm, send_req(n_send), ierr)
2019 end if
2020 if (mg%buf(i)%i_recv > 0) then
2021 n_recv = n_recv + 1
2022 call mpi_irecv(mg%buf(i)%recv, mg%buf(i)%i_recv, mpi_double, &
2023 i, 0, mg%comm, recv_req(n_recv), ierr)
2024 end if
2025 end do
2026
2027 call mpi_waitall(n_recv, recv_req(1:n_recv), mpi_statuses_ignore, ierr)
2028 call mpi_waitall(n_send, send_req(1:n_send), mpi_statuses_ignore, ierr)
2029
2030 end subroutine sort_and_transfer_buffers
2031
2032 !> Sort send buffers according to the idbuf array
2033 subroutine sort_sendbuf(gc, dsize)
2034
2035 type(mg_buf_t), intent(inout) :: gc
2036 integer, intent(in) :: dsize !< Size of send buffer elements
2037 integer :: ix_sort(gc%i_ix)
2038 real(dp) :: buf_cpy(gc%i_send)
2039 integer :: i, j, n
2040
2041 call mrgrnk(gc%ix(1:gc%i_ix), ix_sort)
2042
2043 buf_cpy = gc%send(1:gc%i_send)
2044
2045 do n = 1, gc%i_ix
2046 i = (n-1) * dsize
2047 j = (ix_sort(n)-1) * dsize
2048 gc%send(i+1:i+dsize) = buf_cpy(j+1:j+dsize)
2049 end do
2050 gc%ix(1:gc%i_ix) = gc%ix(ix_sort)
2051
2052 end subroutine sort_sendbuf
2053
2054 !! File ../src/m_ghost_cells.f90
2055
2056 !> Specify minimum buffer size (per process) for communication
2057 subroutine mg_ghost_cell_buffer_size(mg, n_send, n_recv, dsize)
2058 type(mg_t), intent(inout) :: mg
2059 integer, intent(out) :: n_send(0:mg%n_cpu-1)
2060 integer, intent(out) :: n_recv(0:mg%n_cpu-1)
2061 integer, intent(out) :: dsize
2062 integer :: i, id, lvl, nc
2063
2064 allocate(mg%comm_ghostcell%n_send(0:mg%n_cpu-1, &
2065 mg%first_normal_lvl:mg%highest_lvl))
2066 allocate(mg%comm_ghostcell%n_recv(0:mg%n_cpu-1, &
2067 mg%first_normal_lvl:mg%highest_lvl))
2068
2069 dsize = mg%box_size**(3-1)
2070
2071 do lvl = mg%first_normal_lvl, mg%highest_lvl
2072 nc = mg%box_size_lvl(lvl)
2073 mg%buf(:)%i_send = 0
2074 mg%buf(:)%i_recv = 0
2075 mg%buf(:)%i_ix = 0
2076
2077 do i = 1, size(mg%lvls(lvl)%my_ids)
2078 id = mg%lvls(lvl)%my_ids(i)
2079 call buffer_ghost_cells(mg, id, nc, 1, dry_run=.true.)
2080 end do
2081
2082 if (lvl > 1) then
2083 do i = 1, size(mg%lvls(lvl-1)%my_ref_bnds)
2084 id = mg%lvls(lvl-1)%my_ref_bnds(i)
2085 call buffer_refinement_boundaries(mg, id, nc, 1, dry_run=.true.)
2086 end do
2087 end if
2088
2089 ! Set ghost cells to received data
2090 mg%buf(:)%i_recv = 0
2091 do i = 1, size(mg%lvls(lvl)%my_ids)
2092 id = mg%lvls(lvl)%my_ids(i)
2093 call set_ghost_cells(mg, id, nc, 1, dry_run=.true.)
2094 end do
2095
2096 mg%comm_ghostcell%n_send(:, lvl) = mg%buf(:)%i_send/dsize
2097 mg%comm_ghostcell%n_recv(:, lvl) = mg%buf(:)%i_recv/dsize
2098 end do
2099
2100 n_send = maxval(mg%comm_ghostcell%n_send, dim=2)
2101 n_recv = maxval(mg%comm_ghostcell%n_recv, dim=2)
2102 end subroutine mg_ghost_cell_buffer_size
2103
2104 !> Store boundary conditions for the solution variable, this can speed up
2105 !> calculations if the same boundary conditions are re-used.
2106 subroutine mg_phi_bc_store(mg)
2107 type(mg_t), intent(inout) :: mg
2108 integer :: lvl, nc
2109
2110 nc = mg%box_size
2111
2112 do lvl = mg%lowest_lvl, mg%highest_lvl
2113 nc = mg%box_size_lvl(lvl)
2114 call mg_phi_bc_store_lvl(mg, lvl, nc)
2115 end do
2116
2117 mg%phi_bc_data_stored = .true.
2118 end subroutine mg_phi_bc_store
2119
2120 subroutine mg_phi_bc_store_lvl(mg, lvl, nc)
2121 type(mg_t), intent(inout) :: mg
2122 integer, intent(in) :: lvl
2123 integer, intent(in) :: nc
2124 real(dp) :: bc(nc, nc)
2125 integer :: i, id, nb, nb_id, bc_type
2126
2127 do i = 1, size(mg%lvls(lvl)%my_ids)
2128 id = mg%lvls(lvl)%my_ids(i)
2129 do nb = 1, mg_num_neighbors
2130 nb_id = mg%boxes(id)%neighbors(nb)
2131 if (nb_id < mg_no_box) then
2132 ! Physical boundary
2133 if (associated(mg%bc(nb, mg_iphi)%boundary_cond)) then
2134 call mg%bc(nb, mg_iphi)%boundary_cond(mg%boxes(id), nc, &
2135 mg_iphi, nb, bc_type, bc)
2136 else
2137 bc_type = mg%bc(nb, mg_iphi)%bc_type
2138 bc = mg%bc(nb, mg_iphi)%bc_value
2139 end if
2140
2141 ! Store the boundary condition type. This is not globally set in
2142 ! the tree, but all negative values are treated the same in
2143 ! other parts of the code
2144 mg%boxes(id)%neighbors(nb) = bc_type
2145
2146 ! Store ghost cell data in the right-hand side
2147 call box_set_gc(mg%boxes(id), nb, nc, mg_irhs, bc)
2148 end if
2149 end do
2150 end do
2151 end subroutine mg_phi_bc_store_lvl
2152
2153 !> Fill ghost cells at all grid levels
2154 subroutine mg_fill_ghost_cells(mg, iv)
2155 type(mg_t) :: mg
2156 integer, intent(in) :: iv !< Index of variable
2157 integer :: lvl
2158
2159 do lvl = mg%lowest_lvl, mg%highest_lvl
2160 call mg_fill_ghost_cells_lvl(mg, lvl, iv)
2161 end do
2162 end subroutine mg_fill_ghost_cells
2163
2164 !> Fill ghost cells at a grid level
2165 subroutine mg_fill_ghost_cells_lvl(mg, lvl, iv)
2166
2167 type(mg_t) :: mg
2168 integer, intent(in) :: lvl
2169 integer, intent(in) :: iv !< Index of variable
2170 integer :: i, id, dsize, nc
2171
2172 if (lvl < mg%lowest_lvl) &
2173 error stop "fill_ghost_cells_lvl: lvl < lowest_lvl"
2174 if (lvl > mg%highest_lvl) &
2175 error stop "fill_ghost_cells_lvl: lvl > highest_lvl"
2176
2177 nc = mg%box_size_lvl(lvl)
2178
2179 if (lvl >= mg%first_normal_lvl) then
2180 dsize = nc**(3-1)
2181 mg%buf(:)%i_send = 0
2182 mg%buf(:)%i_recv = 0
2183 mg%buf(:)%i_ix = 0
2184
2185 do i = 1, size(mg%lvls(lvl)%my_ids)
2186 id = mg%lvls(lvl)%my_ids(i)
2187 call buffer_ghost_cells(mg, id, nc, iv, .false.)
2188 end do
2189
2190 if (lvl > 1) then
2191 do i = 1, size(mg%lvls(lvl-1)%my_ref_bnds)
2192 id = mg%lvls(lvl-1)%my_ref_bnds(i)
2193 call buffer_refinement_boundaries(mg, id, nc, iv, .false.)
2194 end do
2195 end if
2196
2197 ! Transfer data between processes
2198 mg%buf(:)%i_recv = mg%comm_ghostcell%n_recv(:, lvl) * dsize
2199 call sort_and_transfer_buffers(mg, dsize)
2200
2201 ! Set ghost cells to received data
2202 mg%buf(:)%i_recv = 0
2203 end if
2204
2205 do i = 1, size(mg%lvls(lvl)%my_ids)
2206 id = mg%lvls(lvl)%my_ids(i)
2207 call set_ghost_cells(mg, id, nc, iv, .false.)
2208 end do
2209 end subroutine mg_fill_ghost_cells_lvl
2210
2211 subroutine buffer_ghost_cells(mg, id, nc, iv, dry_run)
2212 type(mg_t), intent(inout) :: mg
2213 integer, intent(in) :: id
2214 integer, intent(in) :: nc
2215 integer, intent(in) :: iv
2216 logical, intent(in) :: dry_run
2217 integer :: nb, nb_id, nb_rank
2218
2219 do nb = 1, mg_num_neighbors
2220 nb_id = mg%boxes(id)%neighbors(nb)
2221
2222 if (nb_id > mg_no_box) then
2223 ! There is a neighbor
2224 nb_rank = mg%boxes(nb_id)%rank
2225
2226 if (nb_rank /= mg%my_rank) then
2227 call buffer_for_nb(mg, mg%boxes(id), nc, iv, nb_id, nb_rank, &
2228 nb, dry_run)
2229 end if
2230 end if
2231 end do
2232 end subroutine buffer_ghost_cells
2233
2234 subroutine buffer_refinement_boundaries(mg, id, nc, iv, dry_run)
2235 type(mg_t), intent(inout) :: mg
2236 integer, intent(in) :: id
2237 integer, intent(in) :: nc
2238 integer, intent(in) :: iv
2239 logical, intent(in) :: dry_run
2240 integer :: nb, nb_id, c_ids(2**(3-1))
2241 integer :: n, c_id, c_rank
2242
2243 do nb = 1, mg_num_neighbors
2244 nb_id = mg%boxes(id)%neighbors(nb)
2245 if (nb_id > mg_no_box) then
2246 if (mg_has_children(mg%boxes(nb_id))) then
2247 c_ids = mg%boxes(nb_id)%children(&
2249
2250 do n = 1, mg_num_children/2
2251 c_id = c_ids(n)
2252 c_rank = mg%boxes(c_id)%rank
2253
2254 if (c_rank /= mg%my_rank) then
2255 ! Send all coarse ghost cells
2256 call buffer_for_fine_nb(mg, mg%boxes(id), nc, iv, c_id, &
2257 c_rank, nb, dry_run)
2258 end if
2259 end do
2260 end if
2261 end if
2262 end do
2263 end subroutine buffer_refinement_boundaries
2264
2265 !> The routine that actually fills the ghost cells
2266 subroutine set_ghost_cells(mg, id, nc, iv, dry_run)
2267 type(mg_t), intent(inout) :: mg
2268 integer, intent(in) :: id
2269 integer, intent(in) :: nc
2270 integer, intent(in) :: iv
2271 logical, intent(in) :: dry_run
2272 real(dp) :: bc(nc, nc)
2273 integer :: nb, nb_id, nb_rank, bc_type
2274
2275 do nb = 1, mg_num_neighbors
2276 nb_id = mg%boxes(id)%neighbors(nb)
2277
2278 if (nb_id > mg_no_box) then
2279 ! There is a neighbor
2280 nb_rank = mg%boxes(nb_id)%rank
2281
2282 if (nb_rank /= mg%my_rank) then
2283 call fill_buffered_nb(mg, mg%boxes(id), nb_rank, &
2284 nb, nc, iv, dry_run)
2285 else if (.not. dry_run) then
2286 call copy_from_nb(mg%boxes(id), mg%boxes(nb_id), &
2287 nb, nc, iv)
2288 end if
2289 else if (nb_id == mg_no_box) then
2290 ! Refinement boundary
2291 call fill_refinement_bnd(mg, id, nb, nc, iv, dry_run)
2292 else if (.not. dry_run) then
2293 ! Physical boundary
2294 if (mg%phi_bc_data_stored .and. iv == mg_iphi) then
2295 ! Copy the boundary conditions stored in the ghost cells of the
2296 ! right-hand side
2297 call box_get_gc(mg%boxes(id), nb, nc, mg_irhs, bc)
2298 bc_type = nb_id
2299 else
2300 if (associated(mg%bc(nb, iv)%boundary_cond)) then
2301 call mg%bc(nb, iv)%boundary_cond(mg%boxes(id), nc, iv, &
2302 nb, bc_type, bc)
2303 else
2304 bc_type = mg%bc(nb, iv)%bc_type
2305 bc = mg%bc(nb, iv)%bc_value
2306 end if
2307 end if
2308
2309 call box_set_gc(mg%boxes(id), nb, nc, iv, bc)
2310 call bc_to_gc(mg, id, nc, iv, nb, bc_type)
2311 end if
2312 end do
2313 end subroutine set_ghost_cells
2314
2315 subroutine fill_refinement_bnd(mg, id, nb, nc, iv, dry_run)
2316 type(mg_t), intent(inout) :: mg
2317 integer, intent(in) :: id
2318 integer, intent(in) :: nc
2319 integer, intent(in) :: iv
2320 integer, intent(in) :: nb
2321 logical, intent(in) :: dry_run
2322 real(dp) :: gc(nc, nc)
2323 integer :: p_id, p_nb_id, ix_offset(3)
2324 integer :: i, dsize, p_nb_rank
2325
2326 dsize = nc**(3-1)
2327 p_id = mg%boxes(id)%parent
2328 p_nb_id = mg%boxes(p_id)%neighbors(nb)
2329 p_nb_rank = mg%boxes(p_nb_id)%rank
2330
2331 if (p_nb_rank /= mg%my_rank) then
2332 i = mg%buf(p_nb_rank)%i_recv
2333 if (.not. dry_run) then
2334 gc = reshape(mg%buf(p_nb_rank)%recv(i+1:i+dsize), shape(gc))
2335 end if
2336 mg%buf(p_nb_rank)%i_recv = mg%buf(p_nb_rank)%i_recv + dsize
2337 else if (.not. dry_run) then
2338 ix_offset = mg_get_child_offset(mg, id)
2339 call box_gc_for_fine_neighbor(mg%boxes(p_nb_id), mg_neighb_rev(nb), &
2340 ix_offset, nc, iv, gc)
2341 end if
2342
2343 if (.not. dry_run) then
2344 if (associated(mg%bc(nb, iv)%refinement_bnd)) then
2345 call mg%bc(nb, iv)%refinement_bnd(mg%boxes(id), nc, iv, nb, gc)
2346 else
2347 call sides_rb(mg%boxes(id), nc, iv, nb, gc)
2348 end if
2349 end if
2350 end subroutine fill_refinement_bnd
2351
2352 subroutine copy_from_nb(box, box_nb, nb, nc, iv)
2353 type(mg_box_t), intent(inout) :: box
2354 type(mg_box_t), intent(in) :: box_nb
2355 integer, intent(in) :: nb
2356 integer, intent(in) :: nc
2357 integer, intent(in) :: iv
2358 real(dp) :: gc(nc, nc)
2359
2360 call box_gc_for_neighbor(box_nb, mg_neighb_rev(nb), nc, iv, gc)
2361 call box_set_gc(box, nb, nc, iv, gc)
2362 end subroutine copy_from_nb
2363
2364 subroutine buffer_for_nb(mg, box, nc, iv, nb_id, nb_rank, nb, dry_run)
2365 type(mg_t), intent(inout) :: mg
2366 type(mg_box_t), intent(inout) :: box
2367 integer, intent(in) :: nc
2368 integer, intent(in) :: iv
2369 integer, intent(in) :: nb_id
2370 integer, intent(in) :: nb_rank
2371 integer, intent(in) :: nb
2372 logical, intent(in) :: dry_run
2373 integer :: i, dsize
2374 real(dp) :: gc(nc, nc)
2375
2376 i = mg%buf(nb_rank)%i_send
2377 dsize = nc**(3-1)
2378
2379 if (.not. dry_run) then
2380 call box_gc_for_neighbor(box, nb, nc, iv, gc)
2381 mg%buf(nb_rank)%send(i+1:i+dsize) = pack(gc, .true.)
2382 end if
2383
2384 ! Later the buffer is sorted, using the fact that loops go from low to high
2385 ! box id, and we fill ghost cells according to the neighbor order
2386 i = mg%buf(nb_rank)%i_ix
2387 if (.not. dry_run) then
2388 mg%buf(nb_rank)%ix(i+1) = mg_num_neighbors * nb_id + mg_neighb_rev(nb)
2389 end if
2390
2391 mg%buf(nb_rank)%i_send = mg%buf(nb_rank)%i_send + dsize
2392 mg%buf(nb_rank)%i_ix = mg%buf(nb_rank)%i_ix + 1
2393 end subroutine buffer_for_nb
2394
2395 subroutine buffer_for_fine_nb(mg, box, nc, iv, fine_id, fine_rank, nb, dry_run)
2396 type(mg_t), intent(inout) :: mg
2397 type(mg_box_t), intent(inout) :: box
2398 integer, intent(in) :: nc
2399 integer, intent(in) :: iv
2400 integer, intent(in) :: fine_id
2401 integer, intent(in) :: fine_rank
2402 integer, intent(in) :: nb
2403 logical, intent(in) :: dry_run
2404 integer :: i, dsize, ix_offset(3)
2405 real(dp) :: gc(nc, nc)
2406
2407 i = mg%buf(fine_rank)%i_send
2408 dsize = nc**(3-1)
2409
2410 if (.not. dry_run) then
2411 ix_offset = mg_get_child_offset(mg, fine_id)
2412 call box_gc_for_fine_neighbor(box, nb, ix_offset, nc, iv, gc)
2413 mg%buf(fine_rank)%send(i+1:i+dsize) = pack(gc, .true.)
2414 end if
2415
2416 ! Later the buffer is sorted, using the fact that loops go from low to high
2417 ! box id, and we fill ghost cells according to the neighbor order
2418 i = mg%buf(fine_rank)%i_ix
2419 if (.not. dry_run) then
2420 mg%buf(fine_rank)%ix(i+1) = mg_num_neighbors * fine_id + &
2421 mg_neighb_rev(nb)
2422 end if
2423
2424 mg%buf(fine_rank)%i_send = mg%buf(fine_rank)%i_send + dsize
2425 mg%buf(fine_rank)%i_ix = mg%buf(fine_rank)%i_ix + 1
2426 end subroutine buffer_for_fine_nb
2427
2428 subroutine fill_buffered_nb(mg, box, nb_rank, nb, nc, iv, dry_run)
2429 type(mg_t), intent(inout) :: mg
2430 type(mg_box_t), intent(inout) :: box
2431 integer, intent(in) :: nb_rank
2432 integer, intent(in) :: nb
2433 integer, intent(in) :: nc
2434 integer, intent(in) :: iv
2435 logical, intent(in) :: dry_run
2436 integer :: i, dsize
2437 real(dp) :: gc(nc, nc)
2438
2439 i = mg%buf(nb_rank)%i_recv
2440 dsize = nc**(3-1)
2441
2442 if (.not. dry_run) then
2443 gc = reshape(mg%buf(nb_rank)%recv(i+1:i+dsize), shape(gc))
2444 call box_set_gc(box, nb, nc, iv, gc)
2445 end if
2446 mg%buf(nb_rank)%i_recv = mg%buf(nb_rank)%i_recv + dsize
2447
2448 end subroutine fill_buffered_nb
2449
2450 subroutine box_gc_for_neighbor(box, nb, nc, iv, gc)
2451 type(mg_box_t), intent(in) :: box
2452 integer, intent(in) :: nb, nc, iv
2453 real(dp), intent(out) :: gc(nc, nc)
2454
2455 select case (nb)
2456 case (mg_neighb_lowx)
2457 gc = box%cc(1, 1:nc, 1:nc, iv)
2458 case (mg_neighb_highx)
2459 gc = box%cc(nc, 1:nc, 1:nc, iv)
2460 case (mg_neighb_lowy)
2461 gc = box%cc(1:nc, 1, 1:nc, iv)
2462 case (mg_neighb_highy)
2463 gc = box%cc(1:nc, nc, 1:nc, iv)
2464 case (mg_neighb_lowz)
2465 gc = box%cc(1:nc, 1:nc, 1, iv)
2466 case (mg_neighb_highz)
2467 gc = box%cc(1:nc, 1:nc, nc, iv)
2468 end select
2469 end subroutine box_gc_for_neighbor
2470
2471 !> Get ghost cells for a fine neighbor
2472 subroutine box_gc_for_fine_neighbor(box, nb, di, nc, iv, gc)
2473 type(mg_box_t), intent(in) :: box
2474 integer, intent(in) :: nb !< Direction of fine neighbor
2475 integer, intent(in) :: di(3) !< Index offset of fine neighbor
2476 integer, intent(in) :: nc, iv
2477 real(dp), intent(out) :: gc(nc, nc)
2478 real(dp) :: tmp(0:nc/2+1, 0:nc/2+1), grad(3-1)
2479 integer :: i, j, hnc
2480
2481 hnc = nc/2
2482
2483 ! First fill a temporary array with data next to the fine grid
2484 select case (nb)
2485 case (mg_neighb_lowx)
2486 tmp = box%cc(1, di(2):di(2)+hnc+1, di(3):di(3)+hnc+1, iv)
2487 case (mg_neighb_highx)
2488 tmp = box%cc(nc, di(2):di(2)+hnc+1, di(3):di(3)+hnc+1, iv)
2489 case (mg_neighb_lowy)
2490 tmp = box%cc(di(1):di(1)+hnc+1, 1, di(3):di(3)+hnc+1, iv)
2491 case (mg_neighb_highy)
2492 tmp = box%cc(di(1):di(1)+hnc+1, nc, di(3):di(3)+hnc+1, iv)
2493 case (mg_neighb_lowz)
2494 tmp = box%cc(di(1):di(1)+hnc+1, di(2):di(2)+hnc+1, 1, iv)
2495 case (mg_neighb_highz)
2496 tmp = box%cc(di(1):di(1)+hnc+1, di(2):di(2)+hnc+1, nc, iv)
2497 case default
2498 error stop
2499 end select
2500
2501 ! Now interpolate the coarse grid data to obtain values 'straight' next to
2502 ! the fine grid points
2503 do j = 1, hnc
2504 do i = 1, hnc
2505 grad(1) = 0.125_dp * (tmp(i+1, j) - tmp(i-1, j))
2506 grad(2) = 0.125_dp * (tmp(i, j+1) - tmp(i, j-1))
2507 gc(2*i-1, 2*j-1) = tmp(i, j) - grad(1) - grad(2)
2508 gc(2*i, 2*j-1) = tmp(i, j) + grad(1) - grad(2)
2509 gc(2*i-1, 2*j) = tmp(i, j) - grad(1) + grad(2)
2510 gc(2*i, 2*j) = tmp(i, j) + grad(1) + grad(2)
2511 end do
2512 end do
2513 end subroutine box_gc_for_fine_neighbor
2514
2515 subroutine box_get_gc(box, nb, nc, iv, gc)
2516 type(mg_box_t), intent(in) :: box
2517 integer, intent(in) :: nb, nc, iv
2518 real(dp), intent(out) :: gc(nc, nc)
2519
2520 select case (nb)
2521 case (mg_neighb_lowx)
2522 gc = box%cc(0, 1:nc, 1:nc, iv)
2523 case (mg_neighb_highx)
2524 gc = box%cc(nc+1, 1:nc, 1:nc, iv)
2525 case (mg_neighb_lowy)
2526 gc = box%cc(1:nc, 0, 1:nc, iv)
2527 case (mg_neighb_highy)
2528 gc = box%cc(1:nc, nc+1, 1:nc, iv)
2529 case (mg_neighb_lowz)
2530 gc = box%cc(1:nc, 1:nc, 0, iv)
2531 case (mg_neighb_highz)
2532 gc = box%cc(1:nc, 1:nc, nc+1, iv)
2533 end select
2534 end subroutine box_get_gc
2535
2536 subroutine box_set_gc(box, nb, nc, iv, gc)
2537 type(mg_box_t), intent(inout) :: box
2538 integer, intent(in) :: nb, nc, iv
2539 real(dp), intent(in) :: gc(nc, nc)
2540
2541 select case (nb)
2542 case (mg_neighb_lowx)
2543 box%cc(0, 1:nc, 1:nc, iv) = gc
2544 case (mg_neighb_highx)
2545 box%cc(nc+1, 1:nc, 1:nc, iv) = gc
2546 case (mg_neighb_lowy)
2547 box%cc(1:nc, 0, 1:nc, iv) = gc
2548 case (mg_neighb_highy)
2549 box%cc(1:nc, nc+1, 1:nc, iv) = gc
2550 case (mg_neighb_lowz)
2551 box%cc(1:nc, 1:nc, 0, iv) = gc
2552 case (mg_neighb_highz)
2553 box%cc(1:nc, 1:nc, nc+1, iv) = gc
2554 end select
2555 end subroutine box_set_gc
2556
2557 subroutine bc_to_gc(mg, id, nc, iv, nb, bc_type)
2558 type(mg_t), intent(inout) :: mg
2559 integer, intent(in) :: id
2560 integer, intent(in) :: nc
2561 integer, intent(in) :: iv
2562 integer, intent(in) :: nb !< Neighbor direction
2563 integer, intent(in) :: bc_type !< Type of b.c.
2564 real(dp) :: c0, c1, c2, dr
2565
2566 ! If we call the interior point x1, x2 and the ghost point x0, then a
2567 ! Dirichlet boundary value b can be imposed as:
2568 ! x0 = -x1 + 2*b
2569 ! A Neumann b.c. can be imposed as:
2570 ! x0 = x1 +/- dx * b
2571 ! A continuous boundary (same slope) as:
2572 ! x0 = 2 * x1 - x2
2573 ! Below, we set coefficients to handle these cases
2574 select case (bc_type)
2575 case (mg_bc_dirichlet)
2576 c0 = 2
2577 c1 = -1
2578 c2 = 0
2579 case (mg_bc_neumann)
2580 dr = mg%dr(mg_neighb_dim(nb), mg%boxes(id)%lvl)
2581 c0 = dr * mg_neighb_high_pm(nb) ! This gives a + or - sign
2582 c1 = 1
2583 c2 = 0
2584 case (mg_bc_continuous)
2585 c0 = 0
2586 c1 = 2
2587 c2 = -1
2588 case default
2589 error stop "bc_to_gc: unknown boundary condition"
2590 end select
2591
2592 select case (nb)
2593 case (mg_neighb_lowx)
2594 mg%boxes(id)%cc(0, 1:nc, 1:nc, iv) = &
2595 c0 * mg%boxes(id)%cc(0, 1:nc, 1:nc, iv) + &
2596 c1 * mg%boxes(id)%cc(1, 1:nc, 1:nc, iv) + &
2597 c2 * mg%boxes(id)%cc(2, 1:nc, 1:nc, iv)
2598 case (mg_neighb_highx)
2599 mg%boxes(id)%cc(nc+1, 1:nc, 1:nc, iv) = &
2600 c0 * mg%boxes(id)%cc(nc+1, 1:nc, 1:nc, iv) + &
2601 c1 * mg%boxes(id)%cc(nc, 1:nc, 1:nc, iv) + &
2602 c2 * mg%boxes(id)%cc(nc-1, 1:nc, 1:nc, iv)
2603 case (mg_neighb_lowy)
2604 mg%boxes(id)%cc(1:nc, 0, 1:nc, iv) = &
2605 c0 * mg%boxes(id)%cc(1:nc, 0, 1:nc, iv) + &
2606 c1 * mg%boxes(id)%cc(1:nc, 1, 1:nc, iv) + &
2607 c2 * mg%boxes(id)%cc(1:nc, 2, 1:nc, iv)
2608 case (mg_neighb_highy)
2609 mg%boxes(id)%cc(1:nc, nc+1, 1:nc, iv) = &
2610 c0 * mg%boxes(id)%cc(1:nc, nc+1, 1:nc, iv) + &
2611 c1 * mg%boxes(id)%cc(1:nc, nc, 1:nc, iv) + &
2612 c2 * mg%boxes(id)%cc(1:nc, nc-1, 1:nc, iv)
2613 case (mg_neighb_lowz)
2614 mg%boxes(id)%cc(1:nc, 1:nc, 0, iv) = &
2615 c0 * mg%boxes(id)%cc(1:nc, 1:nc, 0, iv) + &
2616 c1 * mg%boxes(id)%cc(1:nc, 1:nc, 1, iv) + &
2617 c2 * mg%boxes(id)%cc(1:nc, 1:nc, 2, iv)
2618 case (mg_neighb_highz)
2619 mg%boxes(id)%cc(1:nc, 1:nc, nc+1, iv) = &
2620 c0 * mg%boxes(id)%cc(1:nc, 1:nc, nc+1, iv) + &
2621 c1 * mg%boxes(id)%cc(1:nc, 1:nc, nc, iv) + &
2622 c2 * mg%boxes(id)%cc(1:nc, 1:nc, nc-1, iv)
2623 end select
2624 end subroutine bc_to_gc
2625
2626 !> Fill ghost cells near refinement boundaries which preserves diffusive fluxes.
2627 subroutine sides_rb(box, nc, iv, nb, gc)
2628 type(mg_box_t), intent(inout) :: box
2629 integer, intent(in) :: nc
2630 integer, intent(in) :: iv
2631 integer, intent(in) :: nb !< Ghost cell direction
2632 !> Interpolated coarse grid ghost cell data (but not yet in the nb direction)
2633 real(dp), intent(in) :: gc(nc, nc)
2634 integer :: di, dj, dk
2635 integer :: i, j, k, ix, dix
2636
2637 if (mg_neighb_low(nb)) then
2638 ix = 1
2639 dix = 1
2640 else
2641 ix = nc
2642 dix = -1
2643 end if
2644
2645 select case (mg_neighb_dim(nb))
2646 case (1)
2647 i = ix
2648 di = dix
2649 do k = 1, nc
2650 dk = -1 + 2 * iand(k, 1)
2651 do j = 1, nc
2652 dj = -1 + 2 * iand(j, 1)
2653 box%cc(i-di, j, k, iv) = 0.5_dp * gc(j, k) &
2654 + 0.75_dp * box%cc(i, j, k, iv) &
2655 - 0.25_dp * box%cc(i+di, j, k, iv)
2656 end do
2657 end do
2658 case (2)
2659 j = ix
2660 dj = dix
2661 do k = 1, nc
2662 dk = -1 + 2 * iand(k, 1)
2663 do i = 1, nc
2664 di = -1 + 2 * iand(i, 1)
2665 box%cc(i, j-dj, k, iv) = 0.5_dp * gc(i, k) &
2666 + 0.75_dp * box%cc(i, j, k, iv) &
2667 - 0.25_dp * box%cc(i, j+dj, k, iv)
2668 end do
2669 end do
2670 case (3)
2671 k = ix
2672 dk = dix
2673 do j = 1, nc
2674 dj = -1 + 2 * iand(j, 1)
2675 do i = 1, nc
2676 di = -1 + 2 * iand(i, 1)
2677 box%cc(i, j, k-dk, iv) = 0.5_dp * gc(i, j) &
2678 + 0.75_dp * box%cc(i, j, k, iv) &
2679 - 0.25_dp * box%cc(i, j, k+dk, iv)
2680 end do
2681 end do
2682 end select
2683
2684 end subroutine sides_rb
2685
2686 !! File ../src/m_prolong.f90
2687
2688 !> Specify minimum buffer size (per process) for communication
2689 subroutine mg_prolong_buffer_size(mg, n_send, n_recv, dsize)
2690 type(mg_t), intent(inout) :: mg
2691 integer, intent(out) :: n_send(0:mg%n_cpu-1)
2692 integer, intent(out) :: n_recv(0:mg%n_cpu-1)
2693 integer, intent(out) :: dsize
2694 integer :: lvl, min_lvl
2695
2696 if (.not. allocated(mg%comm_restrict%n_send)) then
2697 error stop "Call restrict_buffer_size before prolong_buffer_size"
2698 end if
2699
2700 min_lvl = max(mg%first_normal_lvl-1, mg%lowest_lvl)
2701 allocate(mg%comm_prolong%n_send(0:mg%n_cpu-1, &
2702 min_lvl:mg%highest_lvl))
2703 allocate(mg%comm_prolong%n_recv(0:mg%n_cpu-1, &
2704 min_lvl:mg%highest_lvl))
2705
2706 mg%comm_prolong%n_recv(:, mg%highest_lvl) = 0
2707 mg%comm_prolong%n_send(:, mg%highest_lvl) = 0
2708
2709 do lvl = min_lvl, mg%highest_lvl-1
2710 mg%comm_prolong%n_recv(:, lvl) = &
2711 mg%comm_restrict%n_send(:, lvl+1)
2712 mg%comm_prolong%n_send(:, lvl) = &
2713 mg%comm_restrict%n_recv(:, lvl+1)
2714 end do
2715
2716 ! Send fine grid points, because this is more flexible than sending coarse
2717 ! grid points (e.g., when multiple variables are used for interpolation)
2718 dsize = (mg%box_size)**3
2719 n_send = maxval(mg%comm_prolong%n_send, dim=2)
2720 n_recv = maxval(mg%comm_prolong%n_recv, dim=2)
2721 end subroutine mg_prolong_buffer_size
2722
2723 !> Prolong variable iv from lvl to variable iv_to at lvl+1
2724 subroutine mg_prolong(mg, lvl, iv, iv_to, method, add)
2725
2726 type(mg_t), intent(inout) :: mg
2727 integer, intent(in) :: lvl !< Level to prolong from
2728 integer, intent(in) :: iv !< Source variable
2729 integer, intent(in) :: iv_to !< Target variable
2730 procedure(mg_box_prolong) :: method !< Prolongation method
2731 logical, intent(in) :: add !< If true, add to current values
2732 integer :: i, id, dsize, nc
2733
2734 if (lvl == mg%highest_lvl) error stop "cannot prolong highest level"
2735 if (lvl < mg%lowest_lvl) error stop "cannot prolong below lowest level"
2736
2737 ! Below the first normal level, all boxes are on the same CPU
2738 if (lvl >= mg%first_normal_lvl-1) then
2739 dsize = mg%box_size**3
2740 mg%buf(:)%i_send = 0
2741 mg%buf(:)%i_ix = 0
2742
2743 do i = 1, size(mg%lvls(lvl)%my_ids)
2744 id = mg%lvls(lvl)%my_ids(i)
2745 call prolong_set_buffer(mg, id, mg%box_size, iv, method)
2746 end do
2747
2748 mg%buf(:)%i_recv = mg%comm_prolong%n_recv(:, lvl) * dsize
2749 call sort_and_transfer_buffers(mg, dsize)
2750 mg%buf(:)%i_recv = 0
2751 end if
2752
2753 nc = mg%box_size_lvl(lvl+1)
2754 do i = 1, size(mg%lvls(lvl+1)%my_ids)
2755 id = mg%lvls(lvl+1)%my_ids(i)
2756 call prolong_onto(mg, id, nc, iv, iv_to, add, method)
2757 end do
2758 end subroutine mg_prolong
2759
2760 !> In case the fine grid is on a different CPU, perform the prolongation and
2761 !> store the fine-grid values in the send buffer.
2762 !>
2763 subroutine prolong_set_buffer(mg, id, nc, iv, method)
2764 type(mg_t), intent(inout) :: mg
2765 integer, intent(in) :: id
2766 integer, intent(in) :: nc
2767 integer, intent(in) :: iv
2768 procedure(mg_box_prolong) :: method
2769 integer :: i, dix(3)
2770 integer :: i_c, c_id, c_rank, dsize
2771 real(dp) :: tmp(nc, nc, nc)
2772
2773 dsize = nc**3
2774
2775 do i_c = 1, mg_num_children
2776 c_id = mg%boxes(id)%children(i_c)
2777 if (c_id > mg_no_box) then
2778 c_rank = mg%boxes(c_id)%rank
2779 if (c_rank /= mg%my_rank) then
2780 dix = mg_get_child_offset(mg, c_id)
2781 call method(mg, id, dix, nc, iv, tmp)
2782
2783 i = mg%buf(c_rank)%i_send
2784 mg%buf(c_rank)%send(i+1:i+dsize) = pack(tmp, .true.)
2785 mg%buf(c_rank)%i_send = mg%buf(c_rank)%i_send + dsize
2786
2787 i = mg%buf(c_rank)%i_ix
2788 mg%buf(c_rank)%ix(i+1) = c_id
2789 mg%buf(c_rank)%i_ix = mg%buf(c_rank)%i_ix + 1
2790 end if
2791 end if
2792 end do
2793 end subroutine prolong_set_buffer
2794
2795 !> Prolong onto a child box
2796 subroutine prolong_onto(mg, id, nc, iv, iv_to, add, method)
2797 type(mg_t), intent(inout) :: mg
2798 integer, intent(in) :: id
2799 integer, intent(in) :: nc
2800 integer, intent(in) :: iv !< Prolong from this variable
2801 integer, intent(in) :: iv_to !< Prolong to this variable
2802 logical, intent(in) :: add !< If true, add to current values
2803 procedure(mg_box_prolong) :: method
2804 integer :: hnc, p_id, p_rank, i, dix(3), dsize
2805 real(dp) :: tmp(nc, nc, nc)
2806
2807 hnc = nc/2
2808 p_id = mg%boxes(id)%parent
2809 p_rank = mg%boxes(p_id)%rank
2810
2811 if (p_rank == mg%my_rank) then
2812 dix = mg_get_child_offset(mg, id)
2813 call method(mg, p_id, dix, nc, iv, tmp)
2814 else
2815 dsize = nc**3
2816 i = mg%buf(p_rank)%i_recv
2817 tmp = reshape(mg%buf(p_rank)%recv(i+1:i+dsize), [nc, nc, nc])
2818 mg%buf(p_rank)%i_recv = mg%buf(p_rank)%i_recv + dsize
2819 end if
2820
2821 if (add) then
2822 mg%boxes(id)%cc(1:nc, 1:nc, 1:nc, iv_to) = &
2823 mg%boxes(id)%cc(1:nc, 1:nc, 1:nc, iv_to) + tmp
2824 else
2825 mg%boxes(id)%cc(1:nc, 1:nc, 1:nc, iv_to) = tmp
2826 end if
2827
2828 end subroutine prolong_onto
2829
2830 !> Prolong from a parent to a child with index offset dix
2831 subroutine mg_prolong_sparse(mg, p_id, dix, nc, iv, fine)
2832 type(mg_t), intent(inout) :: mg
2833 integer, intent(in) :: p_id !< Id of parent
2834 integer, intent(in) :: dix(3) !< Offset of child in parent grid
2835 integer, intent(in) :: nc !< Child grid size
2836 integer, intent(in) :: iv !< Prolong from this variable
2837 real(dp), intent(out) :: fine(nc, nc, nc) !< Prolonged values
2838
2839 integer :: i, j, k, hnc
2840 integer :: ic, jc, kc
2841 real(dp) :: f0, flx, fhx, fly, fhy, flz, fhz
2842
2843 hnc = nc/2
2844
2845 associate(crs => mg%boxes(p_id)%cc)
2846 do k = 1, hnc
2847 kc = k + dix(3)
2848 do j = 1, hnc
2849 jc = j + dix(2)
2850 do i = 1, hnc
2851 ic = i + dix(1)
2852
2853 f0 = 0.25_dp * crs(ic, jc, kc, iv)
2854 flx = 0.25_dp * crs(ic-1, jc, kc, iv)
2855 fhx = 0.25_dp * crs(ic+1, jc, kc, iv)
2856 fly = 0.25_dp * crs(ic, jc-1, kc, iv)
2857 fhy = 0.25_dp * crs(ic, jc+1, kc, iv)
2858 flz = 0.25_dp * crs(ic, jc, kc-1, iv)
2859 fhz = 0.25_dp * crs(ic, jc, kc+1, iv)
2860
2861 fine(2*i-1, 2*j-1, 2*k-1) = f0 + flx + fly + flz
2862 fine(2*i, 2*j-1, 2*k-1) = f0 + fhx + fly + flz
2863 fine(2*i-1, 2*j, 2*k-1) = f0 + flx + fhy + flz
2864 fine(2*i, 2*j, 2*k-1) = f0 + fhx + fhy + flz
2865 fine(2*i-1, 2*j-1, 2*k) = f0 + flx + fly + fhz
2866 fine(2*i, 2*j-1, 2*k) = f0 + fhx + fly + fhz
2867 fine(2*i-1, 2*j, 2*k) = f0 + flx + fhy + fhz
2868 fine(2*i, 2*j, 2*k) = f0 + fhx + fhy + fhz
2869 end do
2870 end do
2871 end do
2872 end associate
2873 end subroutine mg_prolong_sparse
2874
2875 !! File ../src/m_helmholtz.f90
2876
2878 type(mg_t), intent(inout) :: mg
2879
2880 mg%subtract_mean = .false.
2881
2882 select case (mg%geometry_type)
2883 case (mg_cartesian)
2884 mg%box_op => box_helmh
2885
2886 select case (mg%smoother_type)
2888 mg%box_smoother => box_gs_helmh
2889 case default
2890 error stop "helmholtz_set_methods: unsupported smoother type"
2891 end select
2892 case default
2893 error stop "helmholtz_set_methods: unsupported geometry"
2894 end select
2895
2896 end subroutine helmholtz_set_methods
2897
2898 subroutine helmholtz_set_lambda(lambda)
2899 real(dp), intent(in) :: lambda
2900
2901 if (lambda < 0) &
2902 error stop "helmholtz_set_lambda: lambda < 0 not allowed"
2903
2904 helmholtz_lambda = lambda
2905 end subroutine helmholtz_set_lambda
2906
2907 !> Perform Gauss-Seidel relaxation on box for a Helmholtz operator
2908 subroutine box_gs_helmh(mg, id, nc, redblack_cntr)
2909 type(mg_t), intent(inout) :: mg
2910 integer, intent(in) :: id
2911 integer, intent(in) :: nc
2912 integer, intent(in) :: redblack_cntr !< Iteration counter
2913 integer :: i, j, k, i0, di
2914 real(dp) :: idr2(3), fac
2915 logical :: redblack
2916
2917 idr2 = 1/mg%dr(:, mg%boxes(id)%lvl)**2
2918 fac = 1.0_dp / (2 * sum(idr2) + helmholtz_lambda)
2919 i0 = 1
2920
2921 redblack = (mg%smoother_type == mg_smoother_gsrb)
2922 if (redblack) then
2923 di = 2
2924 else
2925 di = 1
2926 end if
2927
2928 ! The parity of redblack_cntr determines which cells we use. If
2929 ! redblack_cntr is even, we use the even cells and vice versa.
2930 associate(cc => mg%boxes(id)%cc, n => mg_iphi)
2931 do k = 1, nc
2932 do j = 1, nc
2933 if (redblack) &
2934 i0 = 2 - iand(ieor(redblack_cntr, k+j), 1)
2935 do i = i0, nc, di
2936 cc(i, j, k, n) = fac * ( &
2937 idr2(1) * (cc(i+1, j, k, n) + cc(i-1, j, k, n)) + &
2938 idr2(2) * (cc(i, j+1, k, n) + cc(i, j-1, k, n)) + &
2939 idr2(3) * (cc(i, j, k+1, n) + cc(i, j, k-1, n)) - &
2940 cc(i, j, k, mg_irhs))
2941 end do
2942 end do
2943 end do
2944 end associate
2945 end subroutine box_gs_helmh
2946
2947 !> Perform Helmholtz operator on a box
2948 subroutine box_helmh(mg, id, nc, i_out)
2949 type(mg_t), intent(inout) :: mg
2950 integer, intent(in) :: id
2951 integer, intent(in) :: nc
2952 integer, intent(in) :: i_out !< Index of variable to store Helmholtz in
2953 integer :: i, j, k
2954 real(dp) :: idr2(3)
2955
2956 idr2 = 1 / mg%dr(:, mg%boxes(id)%lvl)**2
2957
2958 associate(cc => mg%boxes(id)%cc, n => mg_iphi)
2959 do k = 1, nc
2960 do j = 1, nc
2961 do i = 1, nc
2962 cc(i, j, k, i_out) = &
2963 idr2(1) * (cc(i-1, j, k, n) + cc(i+1, j, k, n) &
2964 - 2 * cc(i, j, k, n)) &
2965 + idr2(2) * (cc(i, j-1, k, n) + cc(i, j+1, k, n) &
2966 - 2 * cc(i, j, k, n)) &
2967 + idr2(3) * (cc(i, j, k-1, n) + cc(i, j, k+1, n) &
2968 - 2 * cc(i, j, k, n)) - &
2969 helmholtz_lambda * cc(i, j, k, n)
2970 end do
2971 end do
2972 end do
2973 end associate
2974 end subroutine box_helmh
2975
2976 !! File ../src/m_multigrid.f90
2977
2978 subroutine mg_set_methods(mg)
2979
2980 type(mg_t), intent(inout) :: mg
2981
2982 ! Set default prolongation method (routines below can override this)
2983 mg%box_prolong => mg_prolong_sparse
2984
2985 select case (mg%operator_type)
2986 case (mg_laplacian)
2987 call laplacian_set_methods(mg)
2988 case (mg_vlaplacian)
2989 call vlaplacian_set_methods(mg)
2990 case (mg_helmholtz)
2991 call helmholtz_set_methods(mg)
2992 case (mg_vhelmholtz)
2993 call vhelmholtz_set_methods(mg)
2994 case (mg_ahelmholtz)
2995 call ahelmholtz_set_methods(mg)
2996 case default
2997 error stop "mg_set_methods: unknown operator"
2998 end select
2999
3000 ! For red-black, perform two smoothing sub-steps so that all unknowns are
3001 ! updated per cycle
3002 if (mg%smoother_type == mg_smoother_gsrb) then
3003 mg%n_smoother_substeps = 2
3004 else
3005 mg%n_smoother_substeps = 1
3006 end if
3007 end subroutine mg_set_methods
3008
3009 subroutine check_methods(mg)
3010 type(mg_t), intent(inout) :: mg
3011
3012 if (.not. associated(mg%box_op) .or. &
3013 .not. associated(mg%box_smoother)) then
3014 call mg_set_methods(mg)
3015 end if
3016
3017 end subroutine check_methods
3018
3019 subroutine mg_add_timers(mg)
3020 type(mg_t), intent(inout) :: mg
3021 timer_total_vcycle = mg_add_timer(mg, "mg total V-cycle")
3022 timer_total_fmg = mg_add_timer(mg, "mg total FMG cycle")
3023 timer_smoother = mg_add_timer(mg, "mg smoother")
3024 timer_smoother_gc = mg_add_timer(mg, "mg smoother g.c.")
3025 timer_coarse = mg_add_timer(mg, "mg coarse")
3026 timer_correct = mg_add_timer(mg, "mg correct")
3027 timer_update_coarse = mg_add_timer(mg, "mg update coarse")
3028 end subroutine mg_add_timers
3029
3030 !> Perform FAS-FMG cycle (full approximation scheme, full multigrid).
3031 subroutine mg_fas_fmg(mg, have_guess, max_res)
3032 type(mg_t), intent(inout) :: mg
3033 logical, intent(in) :: have_guess !< If false, start from phi = 0
3034 real(dp), intent(out), optional :: max_res !< Store max(abs(residual))
3035 integer :: lvl, i, id
3036
3037 call check_methods(mg)
3038 if (timer_smoother == -1) call mg_add_timers(mg)
3039
3040 call mg_timer_start(mg%timers(timer_total_fmg))
3041
3042 if (.not. have_guess) then
3043 do lvl = mg%highest_lvl, mg%lowest_lvl, -1
3044 do i = 1, size(mg%lvls(lvl)%my_ids)
3045 id = mg%lvls(lvl)%my_ids(i)
3046 mg%boxes(id)%cc(:, :, :, mg_iphi) = 0.0_dp
3047 end do
3048 end do
3049 end if
3050
3051 ! Ensure ghost cells are filled correctly
3052 call mg_fill_ghost_cells_lvl(mg, mg%highest_lvl, mg_iphi)
3053
3054 do lvl = mg%highest_lvl, mg%lowest_lvl+1, -1
3055 ! Set rhs on coarse grid and restrict phi
3056 call mg_timer_start(mg%timers(timer_update_coarse))
3057 call update_coarse(mg, lvl)
3058 call mg_timer_end(mg%timers(timer_update_coarse))
3059 end do
3060
3061 if (mg%subtract_mean) then
3062 ! For fully periodic solutions, the mean source term has to be zero
3063 call subtract_mean(mg, mg_irhs, .false.)
3064 end if
3065
3066 do lvl = mg%lowest_lvl, mg%highest_lvl
3067 ! Store phi_old
3068 do i = 1, size(mg%lvls(lvl)%my_ids)
3069 id = mg%lvls(lvl)%my_ids(i)
3070 mg%boxes(id)%cc(:, :, :, mg_iold) = &
3071 mg%boxes(id)%cc(:, :, :, mg_iphi)
3072 end do
3073
3074 if (lvl > mg%lowest_lvl) then
3075 ! Correct solution at this lvl using lvl-1 data
3076 ! phi = phi + prolong(phi_coarse - phi_old_coarse)
3077 call mg_timer_start(mg%timers(timer_correct))
3078 call correct_children(mg, lvl-1)
3079 call mg_timer_end(mg%timers(timer_correct))
3080
3081 ! Update ghost cells
3082 call mg_fill_ghost_cells_lvl(mg, lvl, mg_iphi)
3083 end if
3084
3085 ! Perform V-cycle, possibly set residual on last iteration
3086 if (lvl == mg%highest_lvl) then
3087 call mg_fas_vcycle(mg, lvl, max_res, standalone=.false.)
3088 else
3089 call mg_fas_vcycle(mg, lvl, standalone=.false.)
3090 end if
3091 end do
3092
3093 call mg_timer_end(mg%timers(timer_total_fmg))
3094 end subroutine mg_fas_fmg
3095
3096 !> Perform FAS V-cycle (full approximation scheme).
3097 subroutine mg_fas_vcycle(mg, highest_lvl, max_res, standalone)
3098 use mpi
3099 type(mg_t), intent(inout) :: mg
3100 integer, intent(in), optional :: highest_lvl !< Maximum level for V-cycle
3101 real(dp), intent(out), optional :: max_res !< Store max(abs(residual))
3102 !> Whether the V-cycle is called by itself (default: true)
3103 logical, intent(in), optional :: standalone
3104 integer :: lvl, min_lvl, i, max_lvl, ierr
3105 real(dp) :: init_res, res
3106 logical :: is_standalone
3107
3108 is_standalone = .true.
3109 if (present(standalone)) is_standalone = standalone
3110
3111 call check_methods(mg)
3112 if (timer_smoother == -1) call mg_add_timers(mg)
3113
3114 if (is_standalone) &
3115 call mg_timer_start(mg%timers(timer_total_vcycle))
3116
3117 if (mg%subtract_mean .and. .not. present(highest_lvl)) then
3118 ! Assume that this is a stand-alone call. For fully periodic solutions,
3119 ! ensure the mean source term is zero.
3120 call subtract_mean(mg, mg_irhs, .false.)
3121 end if
3122
3123 min_lvl = mg%lowest_lvl
3124 max_lvl = mg%highest_lvl
3125 if (present(highest_lvl)) max_lvl = highest_lvl
3126
3127 ! Ensure ghost cells are filled correctly
3128 if (is_standalone) then
3129 call mg_fill_ghost_cells_lvl(mg, max_lvl, mg_iphi)
3130 end if
3131
3132 do lvl = max_lvl, min_lvl+1, -1
3133 ! Downwards relaxation
3134 call smooth_boxes(mg, lvl, mg%n_cycle_down)
3135
3136 ! Set rhs on coarse grid, restrict phi, and copy mg_iphi to mg_iold for the
3137 ! correction later
3138 call mg_timer_start(mg%timers(timer_update_coarse))
3139 call update_coarse(mg, lvl)
3140 call mg_timer_end(mg%timers(timer_update_coarse))
3141 end do
3142
3143 call mg_timer_start(mg%timers(timer_coarse))
3144 if (.not. all(mg%boxes(mg%lvls(min_lvl)%ids)%rank == &
3145 mg%boxes(mg%lvls(min_lvl)%ids(1))%rank)) then
3146 error stop "Multiple CPUs for coarse grid (not implemented yet)"
3147 end if
3148
3149 init_res = max_residual_lvl(mg, min_lvl)
3150 do i = 1, mg%max_coarse_cycles
3151 call smooth_boxes(mg, min_lvl, mg%n_cycle_up+mg%n_cycle_down)
3152 res = max_residual_lvl(mg, min_lvl)
3153 if (res < mg%residual_coarse_rel * init_res .or. &
3154 res < mg%residual_coarse_abs) exit
3155 end do
3156 call mg_timer_end(mg%timers(timer_coarse))
3157
3158 ! Do the upwards part of the v-cycle in the tree
3159 do lvl = min_lvl+1, max_lvl
3160 ! Correct solution at this lvl using lvl-1 data
3161 ! phi = phi + prolong(phi_coarse - phi_old_coarse)
3162 call mg_timer_start(mg%timers(timer_correct))
3163 call correct_children(mg, lvl-1)
3164
3165 ! Have to fill ghost cells after correction
3166 call mg_fill_ghost_cells_lvl(mg, lvl, mg_iphi)
3167 call mg_timer_end(mg%timers(timer_correct))
3168
3169 ! Upwards relaxation
3170 call smooth_boxes(mg, lvl, mg%n_cycle_up)
3171 end do
3172
3173 if (present(max_res)) then
3174 init_res = 0.0_dp
3175 do lvl = min_lvl, max_lvl
3176 res = max_residual_lvl(mg, lvl)
3177 init_res = max(res, init_res)
3178 end do
3179 call mpi_allreduce(init_res, max_res, 1, &
3180 mpi_double, mpi_max, mg%comm, ierr)
3181 end if
3182
3183 ! Subtract mean(phi) from phi
3184 if (mg%subtract_mean) then
3185 call subtract_mean(mg, mg_iphi, .true.)
3186 end if
3187
3188 if (is_standalone) &
3189 call mg_timer_end(mg%timers(timer_total_vcycle))
3190 end subroutine mg_fas_vcycle
3191
3192 subroutine subtract_mean(mg, iv, include_ghostcells)
3193 use mpi
3194 type(mg_t), intent(inout) :: mg
3195 integer, intent(in) :: iv
3196 logical, intent(in) :: include_ghostcells
3197 integer :: i, id, lvl, nc, ierr
3198 real(dp) :: sum_iv, mean_iv, volume
3199
3200 nc = mg%box_size
3201 sum_iv = get_sum(mg, iv)
3202 call mpi_allreduce(sum_iv, mean_iv, 1, &
3203 mpi_double, mpi_sum, mg%comm, ierr)
3204
3205 ! Divide by total grid volume to get mean
3206 volume = nc**3 * product(mg%dr(:, 1)) * size(mg%lvls(1)%ids)
3207 mean_iv = mean_iv / volume
3208
3209 do lvl = mg%lowest_lvl, mg%highest_lvl
3210 nc = mg%box_size_lvl(lvl)
3211
3212 do i = 1, size(mg%lvls(lvl)%my_ids)
3213 id = mg%lvls(lvl)%my_ids(i)
3214 if (include_ghostcells) then
3215 mg%boxes(id)%cc(:, :, :, iv) = &
3216 mg%boxes(id)%cc(:, :, :, iv) - mean_iv
3217 else
3218 mg%boxes(id)%cc(1:nc, 1:nc, 1:nc, iv) = &
3219 mg%boxes(id)%cc(1:nc, 1:nc, 1:nc, iv) - mean_iv
3220 end if
3221 end do
3222 end do
3223 end subroutine subtract_mean
3224
3225 real(dp) function get_sum(mg, iv)
3226 type(mg_t), intent(in) :: mg
3227 integer, intent(in) :: iv
3228 integer :: lvl, i, id, nc
3229 real(dp) :: w
3230
3231 get_sum = 0.0_dp
3232 do lvl = 1, mg%highest_lvl
3233 nc = mg%box_size_lvl(lvl)
3234 w = product(mg%dr(:, lvl)) ! Adjust for non-Cartesian cases
3235 do i = 1, size(mg%lvls(lvl)%my_leaves)
3236 id = mg%lvls(lvl)%my_leaves(i)
3237 get_sum = get_sum + w * &
3238 sum(mg%boxes(id)%cc(1:nc, 1:nc, 1:nc, iv))
3239 end do
3240 end do
3241 end function get_sum
3242
3243 real(dp) function max_residual_lvl(mg, lvl)
3244 type(mg_t), intent(inout) :: mg
3245 integer, intent(in) :: lvl
3246 integer :: i, id, nc
3247 real(dp) :: res
3248
3249 nc = mg%box_size_lvl(lvl)
3250 max_residual_lvl = 0.0_dp
3251
3252 do i = 1, size(mg%lvls(lvl)%my_ids)
3253 id = mg%lvls(lvl)%my_ids(i)
3254 call residual_box(mg, id, nc)
3255 res = maxval(abs(mg%boxes(id)%cc(1:nc, 1:nc, 1:nc, mg_ires)))
3256 max_residual_lvl = max(max_residual_lvl, res)
3257 end do
3258 end function max_residual_lvl
3259
3260 ! subroutine solve_coarse_grid(mg)
3261 ! use m_fishpack
3262 ! type(mg_t), intent(inout) :: mg
3263
3264 ! real(dp) :: rhs(mg%box_size, mg%box_size, mg%box_size)
3265 ! real(dp) :: rmin(3), rmax(3)
3266 ! integer :: nc, nx(3), my_boxes, total_boxes
3267
3268 ! my_boxes = size(mg%lvls(1)%my_ids)
3269 ! total_boxes = size(mg%lvls(1)%ids)
3270 ! nc = mg%box_size
3271
3272 ! if (my_boxes == total_boxes) then
3273 ! nx(:) = nc
3274 ! rmin = [0.0_dp, 0.0_dp, 0.0_dp]
3275 ! rmax = mg%dr(1) * [nc, nc, nc]
3276 ! rhs = mg%boxes(1)%cc(1:nc, 1:nc, 1:nc, mg_irhs)
3277
3278 ! #if 3 == 2
3279 ! call fishpack_2d(nx, rhs, mg%bc, rmin, rmax)
3280 ! #elif 3 == 3
3281 ! call fishpack_3d(nx, rhs, mg%bc, rmin, rmax)
3282 ! #endif
3283
3284 ! mg%boxes(1)%cc(1:nc, 1:nc, 1:nc, mg_iphi) = rhs
3285 ! else if (my_boxes > 0) then
3286 ! error stop "Boxes at level 1 at different processors"
3287 ! end if
3288
3289 ! call fill_ghost_cells_lvl(mg, 1)
3290 ! end subroutine solve_coarse_grid
3291
3292 ! Set rhs on coarse grid, restrict phi, and copy mg_iphi to mg_iold for the
3293 ! correction later
3294 subroutine update_coarse(mg, lvl)
3295 type(mg_t), intent(inout) :: mg !< Tree containing full grid
3296 integer, intent(in) :: lvl !< Update coarse values at lvl-1
3297 integer :: i, id, nc, nc_c
3298
3299 nc = mg%box_size_lvl(lvl)
3300 nc_c = mg%box_size_lvl(lvl-1)
3301
3302 ! Compute residual
3303 do i = 1, size(mg%lvls(lvl)%my_ids)
3304 id = mg%lvls(lvl)%my_ids(i)
3305 call residual_box(mg, id, nc)
3306 end do
3307
3308 ! Restrict phi and the residual
3309 call mg_restrict_lvl(mg, mg_iphi, lvl)
3310 call mg_restrict_lvl(mg, mg_ires, lvl)
3311
3312 call mg_fill_ghost_cells_lvl(mg, lvl-1, mg_iphi)
3313
3314 ! Set rhs_c = laplacian(phi_c) + restrict(res) where it is refined, and
3315 ! store current coarse phi in old.
3316 do i = 1, size(mg%lvls(lvl-1)%my_parents)
3317 id = mg%lvls(lvl-1)%my_parents(i)
3318
3319 ! Set rhs = L phi
3320 call mg%box_op(mg, id, nc_c, mg_irhs)
3321
3322 ! Add the fine grid residual to rhs
3323 mg%boxes(id)%cc(1:nc_c, 1:nc_c, 1:nc_c, mg_irhs) = &
3324 mg%boxes(id)%cc(1:nc_c, 1:nc_c, 1:nc_c, mg_irhs) + &
3325 mg%boxes(id)%cc(1:nc_c, 1:nc_c, 1:nc_c, mg_ires)
3326
3327 ! Story a copy of phi
3328 mg%boxes(id)%cc(:, :, :, mg_iold) = &
3329 mg%boxes(id)%cc(:, :, :, mg_iphi)
3330 end do
3331 end subroutine update_coarse
3332
3333 ! Sets phi = phi + prolong(phi_coarse - phi_old_coarse)
3334 subroutine correct_children(mg, lvl)
3335 type(mg_t), intent(inout) :: mg
3336 integer, intent(in) :: lvl
3337 integer :: i, id
3338
3339 do i = 1, size(mg%lvls(lvl)%my_parents)
3340 id = mg%lvls(lvl)%my_parents(i)
3341
3342 ! Store the correction in mg_ires
3343 mg%boxes(id)%cc(:, :, :, mg_ires) = &
3344 mg%boxes(id)%cc(:, :, :, mg_iphi) - &
3345 mg%boxes(id)%cc(:, :, :, mg_iold)
3346 end do
3347
3348 call mg_prolong(mg, lvl, mg_ires, mg_iphi, mg%box_prolong, add=.true.)
3349 end subroutine correct_children
3350
3351 subroutine smooth_boxes(mg, lvl, n_cycle)
3352 type(mg_t), intent(inout) :: mg
3353 integer, intent(in) :: lvl
3354 integer, intent(in) :: n_cycle !< Number of cycles to perform
3355 integer :: n, i, id, nc
3356
3357 nc = mg%box_size_lvl(lvl)
3358
3359 do n = 1, n_cycle * mg%n_smoother_substeps
3360 call mg_timer_start(mg%timers(timer_smoother))
3361 do i = 1, size(mg%lvls(lvl)%my_ids)
3362 id = mg%lvls(lvl)%my_ids(i)
3363 call mg%box_smoother(mg, id, nc, n)
3364 end do
3365 call mg_timer_end(mg%timers(timer_smoother))
3366
3367 call mg_timer_start(mg%timers(timer_smoother_gc))
3368 call mg_fill_ghost_cells_lvl(mg, lvl, mg_iphi)
3369 call mg_timer_end(mg%timers(timer_smoother_gc))
3370 end do
3371 end subroutine smooth_boxes
3372
3373 subroutine residual_box(mg, id, nc)
3374 type(mg_t), intent(inout) :: mg
3375 integer, intent(in) :: id
3376 integer, intent(in) :: nc
3377
3378 call mg%box_op(mg, id, nc, mg_ires)
3379
3380 mg%boxes(id)%cc(1:nc, 1:nc, 1:nc, mg_ires) = &
3381 mg%boxes(id)%cc(1:nc, 1:nc, 1:nc, mg_irhs) &
3382 - mg%boxes(id)%cc(1:nc, 1:nc, 1:nc, mg_ires)
3383 end subroutine residual_box
3384
3385 !> Apply operator to the tree and store in variable i_out
3386 subroutine mg_apply_op(mg, i_out, op)
3387 type(mg_t), intent(inout) :: mg
3388 integer, intent(in) :: i_out
3389 procedure(mg_box_op), optional :: op
3390 integer :: lvl, i, id, nc
3391
3392 do lvl = mg%lowest_lvl, mg%highest_lvl
3393 nc = mg%box_size_lvl(lvl)
3394 do i = 1, size(mg%lvls(lvl)%my_ids)
3395 id = mg%lvls(lvl)%my_ids(i)
3396 if (present(op)) then
3397 call op(mg, id, nc, i_out)
3398 else
3399 call mg%box_op(mg, id, nc, i_out)
3400 end if
3401 end do
3402 end do
3403 end subroutine mg_apply_op
3404
3405 !! File ../src/m_restrict.f90
3406
3407 !> Specify minimum buffer size (per process) for communication
3408 subroutine mg_restrict_buffer_size(mg, n_send, n_recv, dsize)
3409 type(mg_t), intent(inout) :: mg
3410 integer, intent(out) :: n_send(0:mg%n_cpu-1)
3411 integer, intent(out) :: n_recv(0:mg%n_cpu-1)
3412 integer, intent(out) :: dsize
3413 integer :: n_out(0:mg%n_cpu-1, mg%first_normal_lvl:mg%highest_lvl)
3414 integer :: n_in(0:mg%n_cpu-1, mg%first_normal_lvl:mg%highest_lvl)
3415 integer :: lvl, i, id, p_id, p_rank
3416 integer :: i_c, c_id, c_rank, min_lvl
3417
3418 n_out(:, :) = 0
3419 n_in(:, :) = 0
3420 min_lvl = max(mg%lowest_lvl+1, mg%first_normal_lvl)
3421
3422 do lvl = min_lvl, mg%highest_lvl
3423 ! Number of messages to receive (at lvl-1)
3424 do i = 1, size(mg%lvls(lvl-1)%my_parents)
3425 id = mg%lvls(lvl-1)%my_parents(i)
3426 do i_c = 1, mg_num_children
3427 c_id = mg%boxes(id)%children(i_c)
3428
3429 if (c_id > mg_no_box) then
3430 c_rank = mg%boxes(c_id)%rank
3431 if (c_rank /= mg%my_rank) then
3432 n_in(c_rank, lvl) = n_in(c_rank, lvl) + 1
3433 end if
3434 end if
3435 end do
3436 end do
3437
3438 ! Number of messages to send
3439 do i = 1, size(mg%lvls(lvl)%my_ids)
3440 id = mg%lvls(lvl)%my_ids(i)
3441
3442 p_id = mg%boxes(id)%parent
3443 p_rank = mg%boxes(p_id)%rank
3444 if (p_rank /= mg%my_rank) then
3445 n_out(p_rank, lvl) = n_out(p_rank, lvl) + 1
3446 end if
3447
3448 end do
3449 end do
3450
3451 allocate(mg%comm_restrict%n_send(0:mg%n_cpu-1, &
3452 mg%first_normal_lvl:mg%highest_lvl))
3453 allocate(mg%comm_restrict%n_recv(0:mg%n_cpu-1, &
3454 mg%first_normal_lvl:mg%highest_lvl))
3455 mg%comm_restrict%n_send = n_out
3456 mg%comm_restrict%n_recv = n_in
3457
3458 dsize = (mg%box_size/2)**3
3459 n_send = maxval(n_out, dim=2)
3460 n_recv = maxval(n_in, dim=2)
3461 end subroutine mg_restrict_buffer_size
3462
3463 !> Restrict all levels
3464 subroutine mg_restrict(mg, iv)
3465 type(mg_t), intent(inout) :: mg
3466 integer, intent(in) :: iv
3467 integer :: lvl
3468
3469 do lvl = mg%highest_lvl, mg%lowest_lvl+1, -1
3470 call mg_restrict_lvl(mg, iv, lvl)
3471 end do
3472 end subroutine mg_restrict
3473
3474 !> Restrict from lvl to lvl-1
3475 subroutine mg_restrict_lvl(mg, iv, lvl)
3476
3477 type(mg_t), intent(inout) :: mg
3478 integer, intent(in) :: iv
3479 integer, intent(in) :: lvl
3480 integer :: i, id, dsize, nc
3481
3482 if (lvl <= mg%lowest_lvl) error stop "cannot restrict lvl <= lowest_lvl"
3483
3484 nc = mg%box_size_lvl(lvl)
3485
3486 if (lvl >= mg%first_normal_lvl) then
3487 dsize = (nc/2)**3
3488
3489 mg%buf(:)%i_send = 0
3490 mg%buf(:)%i_ix = 0
3491
3492 do i = 1, size(mg%lvls(lvl)%my_ids)
3493 id = mg%lvls(lvl)%my_ids(i)
3494 call restrict_set_buffer(mg, id, iv)
3495 end do
3496
3497 mg%buf(:)%i_recv = mg%comm_restrict%n_recv(:, lvl) * dsize
3498 call sort_and_transfer_buffers(mg, dsize)
3499 mg%buf(:)%i_recv = 0
3500 end if
3501
3502 do i = 1, size(mg%lvls(lvl-1)%my_parents)
3503 id = mg%lvls(lvl-1)%my_parents(i)
3504 call restrict_onto(mg, id, nc, iv)
3505 end do
3506 end subroutine mg_restrict_lvl
3507
3508 subroutine restrict_set_buffer(mg, id, iv)
3509 type(mg_t), intent(inout) :: mg
3510 integer, intent(in) :: id
3511 integer, intent(in) :: iv
3512 integer :: i, j, k, n, hnc, p_id, p_rank
3513 real(dp) :: tmp(mg%box_size/2, mg%box_size/2, mg%box_size/2)
3514
3515 hnc = mg%box_size/2
3516 p_id = mg%boxes(id)%parent
3517 p_rank = mg%boxes(p_id)%rank
3518
3519 if (p_rank /= mg%my_rank) then
3520 do k = 1, hnc
3521 do j = 1, hnc
3522 do i = 1, hnc
3523 tmp(i, j, k) = 0.125_dp * sum(mg%boxes(id)%cc(2*i-1:2*i, &
3524 2*j-1:2*j, 2*k-1:2*k, iv))
3525 end do
3526 end do
3527 end do
3528
3529 ! Buffer
3530 n = size(tmp)
3531 i = mg%buf(p_rank)%i_send
3532 mg%buf(p_rank)%send(i+1:i+n) = pack(tmp, .true.)
3533 mg%buf(p_rank)%i_send = mg%buf(p_rank)%i_send + n
3534
3535 ! To later sort the send buffer according to parent order
3536 i = mg%buf(p_rank)%i_ix
3537 n = mg_ix_to_ichild(mg%boxes(id)%ix)
3538 mg%buf(p_rank)%ix(i+1) = mg_num_children * p_id + n
3539 mg%buf(p_rank)%i_ix = mg%buf(p_rank)%i_ix + 1
3540 end if
3541 end subroutine restrict_set_buffer
3542
3543 subroutine restrict_onto(mg, id, nc, iv)
3544 type(mg_t), intent(inout) :: mg
3545 integer, intent(in) :: id
3546 integer, intent(in) :: nc
3547 integer, intent(in) :: iv
3548 integer :: i, j, k, hnc, dsize, i_c, c_id
3549 integer :: c_rank, dix(3)
3550
3551 hnc = nc/2
3552 dsize = hnc**3
3553
3554 do i_c = 1, mg_num_children
3555 c_id = mg%boxes(id)%children(i_c)
3556 if (c_id == mg_no_box) cycle ! For coarsened grid
3557 c_rank = mg%boxes(c_id)%rank
3558 dix = mg_get_child_offset(mg, c_id)
3559
3560 if (c_rank == mg%my_rank) then
3561 do j=1, hnc; do i=1, hnc; do k=1, hnc
3562 mg%boxes(id)%cc(dix(1)+i, dix(2)+j, dix(3)+k, iv) = &
3563 0.125_dp * sum(mg%boxes(c_id)%cc(2*i-1:2*i, &
3564 2*j-1:2*j, 2*k-1:2*k, iv))
3565 end do; end do; end do
3566 else
3567 i = mg%buf(c_rank)%i_recv
3568 mg%boxes(id)%cc(dix(1)+1:dix(1)+hnc, &
3569 dix(2)+1:dix(2)+hnc, dix(3)+1:dix(3)+hnc, iv) = &
3570 reshape(mg%buf(c_rank)%recv(i+1:i+dsize), [hnc, hnc, hnc])
3571 mg%buf(c_rank)%i_recv = mg%buf(c_rank)%i_recv + dsize
3572 end if
3573 end do
3574
3575 end subroutine restrict_onto
3576
3577 !! File ../src/m_mrgrnk.f90
3578
3579 Subroutine i_mrgrnk (XDONT, IRNGT)
3580 ! __________________________________________________________
3581 ! MRGRNK = Merge-sort ranking of an array
3582 ! For performance reasons, the first 2 passes are taken
3583 ! out of the standard loop, and use dedicated coding.
3584 ! __________________________________________________________
3585 ! __________________________________________________________
3586 Integer, Dimension (:), Intent (In) :: XDONT
3587 Integer, Dimension (:), Intent (Out) :: IRNGT
3588 ! __________________________________________________________
3589 Integer :: XVALA, XVALB
3590 !
3591 Integer, Dimension (SIZE(IRNGT)) :: JWRKT
3592 Integer :: LMTNA, LMTNC, IRNG1, IRNG2
3593 Integer :: NVAL, IIND, IWRKD, IWRK, IWRKF, JINDA, IINDA, IINDB
3594 !
3595 nval = min(SIZE(xdont), SIZE(irngt))
3596 Select Case (nval)
3597 Case (:0)
3598 Return
3599 Case (1)
3600 irngt(1) = 1
3601 Return
3602 Case Default
3603 Continue
3604 End Select
3605 !
3606 ! Fill-in the index array, creating ordered couples
3607 !
3608 Do iind = 2, nval, 2
3609 If (xdont(iind-1) <= xdont(iind)) Then
3610 irngt(iind-1) = iind - 1
3611 irngt(iind) = iind
3612 Else
3613 irngt(iind-1) = iind
3614 irngt(iind) = iind - 1
3615 End If
3616 End Do
3617 If (modulo(nval, 2) /= 0) Then
3618 irngt(nval) = nval
3619 End If
3620 !
3621 ! We will now have ordered subsets A - B - A - B - ...
3622 ! and merge A and B couples into C - C - ...
3623 !
3624 lmtna = 2
3625 lmtnc = 4
3626 !
3627 ! First iteration. The length of the ordered subsets goes from 2 to 4
3628 !
3629 Do
3630 If (nval <= 2) Exit
3631 !
3632 ! Loop on merges of A and B into C
3633 !
3634 Do iwrkd = 0, nval - 1, 4
3635 If ((iwrkd+4) > nval) Then
3636 If ((iwrkd+2) >= nval) Exit
3637 !
3638 ! 1 2 3
3639 !
3640 If (xdont(irngt(iwrkd+2)) <= xdont(irngt(iwrkd+3))) Exit
3641 !
3642 ! 1 3 2
3643 !
3644 If (xdont(irngt(iwrkd+1)) <= xdont(irngt(iwrkd+3))) Then
3645 irng2 = irngt(iwrkd+2)
3646 irngt(iwrkd+2) = irngt(iwrkd+3)
3647 irngt(iwrkd+3) = irng2
3648 !
3649 ! 3 1 2
3650 !
3651 Else
3652 irng1 = irngt(iwrkd+1)
3653 irngt(iwrkd+1) = irngt(iwrkd+3)
3654 irngt(iwrkd+3) = irngt(iwrkd+2)
3655 irngt(iwrkd+2) = irng1
3656 End If
3657 Exit
3658 End If
3659 !
3660 ! 1 2 3 4
3661 !
3662 If (xdont(irngt(iwrkd+2)) <= xdont(irngt(iwrkd+3))) cycle
3663 !
3664 ! 1 3 x x
3665 !
3666 If (xdont(irngt(iwrkd+1)) <= xdont(irngt(iwrkd+3))) Then
3667 irng2 = irngt(iwrkd+2)
3668 irngt(iwrkd+2) = irngt(iwrkd+3)
3669 If (xdont(irng2) <= xdont(irngt(iwrkd+4))) Then
3670 ! 1 3 2 4
3671 irngt(iwrkd+3) = irng2
3672 Else
3673 ! 1 3 4 2
3674 irngt(iwrkd+3) = irngt(iwrkd+4)
3675 irngt(iwrkd+4) = irng2
3676 End If
3677 !
3678 ! 3 x x x
3679 !
3680 Else
3681 irng1 = irngt(iwrkd+1)
3682 irng2 = irngt(iwrkd+2)
3683 irngt(iwrkd+1) = irngt(iwrkd+3)
3684 If (xdont(irng1) <= xdont(irngt(iwrkd+4))) Then
3685 irngt(iwrkd+2) = irng1
3686 If (xdont(irng2) <= xdont(irngt(iwrkd+4))) Then
3687 ! 3 1 2 4
3688 irngt(iwrkd+3) = irng2
3689 Else
3690 ! 3 1 4 2
3691 irngt(iwrkd+3) = irngt(iwrkd+4)
3692 irngt(iwrkd+4) = irng2
3693 End If
3694 Else
3695 ! 3 4 1 2
3696 irngt(iwrkd+2) = irngt(iwrkd+4)
3697 irngt(iwrkd+3) = irng1
3698 irngt(iwrkd+4) = irng2
3699 End If
3700 End If
3701 End Do
3702 !
3703 ! The Cs become As and Bs
3704 !
3705 lmtna = 4
3706 Exit
3707 End Do
3708 !
3709 ! Iteration loop. Each time, the length of the ordered subsets
3710 ! is doubled.
3711 !
3712 Do
3713 If (lmtna >= nval) Exit
3714 iwrkf = 0
3715 lmtnc = 2 * lmtnc
3716 !
3717 ! Loop on merges of A and B into C
3718 !
3719 Do
3720 iwrk = iwrkf
3721 iwrkd = iwrkf + 1
3722 jinda = iwrkf + lmtna
3723 iwrkf = iwrkf + lmtnc
3724 If (iwrkf >= nval) Then
3725 If (jinda >= nval) Exit
3726 iwrkf = nval
3727 End If
3728 iinda = 1
3729 iindb = jinda + 1
3730 !
3731 ! Shortcut for the case when the max of A is smaller
3732 ! than the min of B. This line may be activated when the
3733 ! initial set is already close to sorted.
3734 !
3735 ! IF (XDONT(IRNGT(JINDA)) <= XDONT(IRNGT(IINDB))) CYCLE
3736 !
3737 ! One steps in the C subset, that we build in the final rank array
3738 !
3739 ! Make a copy of the rank array for the merge iteration
3740 !
3741 jwrkt(1:lmtna) = irngt(iwrkd:jinda)
3742 !
3743 xvala = xdont(jwrkt(iinda))
3744 xvalb = xdont(irngt(iindb))
3745 !
3746 Do
3747 iwrk = iwrk + 1
3748 !
3749 ! We still have unprocessed values in both A and B
3750 !
3751 If (xvala > xvalb) Then
3752 irngt(iwrk) = irngt(iindb)
3753 iindb = iindb + 1
3754 If (iindb > iwrkf) Then
3755 ! Only A still with unprocessed values
3756 irngt(iwrk+1:iwrkf) = jwrkt(iinda:lmtna)
3757 Exit
3758 End If
3759 xvalb = xdont(irngt(iindb))
3760 Else
3761 irngt(iwrk) = jwrkt(iinda)
3762 iinda = iinda + 1
3763 If (iinda > lmtna) exit! Only B still with unprocessed values
3764 xvala = xdont(jwrkt(iinda))
3765 End If
3766 !
3767 End Do
3768 End Do
3769 !
3770 ! The Cs become As and Bs
3771 !
3772 lmtna = 2 * lmtna
3773 End Do
3774 !
3775 Return
3776 !
3777 End Subroutine i_mrgrnk
3778
3779 !! File ../src/m_ahelmholtz.f90
3780
3782 type(mg_t), intent(inout) :: mg
3783
3784 if (mg%n_extra_vars == 0 .and. mg%is_allocated) then
3785 error stop "ahelmholtz_set_methods: mg%n_extra_vars == 0"
3786 else
3787 mg%n_extra_vars = max(3, mg%n_extra_vars)
3788 end if
3789
3790 ! Use Neumann zero boundary conditions for the variable coefficient, since
3791 ! it is needed in ghost cells.
3792 mg%bc(:, mg_iveps1)%bc_type = mg_bc_neumann
3793 mg%bc(:, mg_iveps1)%bc_value = 0.0_dp
3794
3795 mg%bc(:, mg_iveps2)%bc_type = mg_bc_neumann
3796 mg%bc(:, mg_iveps2)%bc_value = 0.0_dp
3797
3798 mg%bc(:, mg_iveps3)%bc_type = mg_bc_neumann
3799 mg%bc(:, mg_iveps3)%bc_value = 0.0_dp
3800
3801 select case (mg%geometry_type)
3802 case (mg_cartesian)
3803 mg%box_op => box_ahelmh
3804
3805 select case (mg%smoother_type)
3807 mg%box_smoother => box_gs_ahelmh
3808 case default
3809 error stop "ahelmholtz_set_methods: unsupported smoother type"
3810 end select
3811 case default
3812 error stop "ahelmholtz_set_methods: unsupported geometry"
3813 end select
3814
3815 end subroutine ahelmholtz_set_methods
3816
3817 subroutine ahelmholtz_set_lambda(lambda)
3818 real(dp), intent(in) :: lambda
3819
3820 if (lambda < 0) &
3821 error stop "ahelmholtz_set_lambda: lambda < 0 not allowed"
3822
3823 ahelmholtz_lambda = lambda
3824 end subroutine ahelmholtz_set_lambda
3825
3826 !> Perform Gauss-Seidel relaxation on box for a Helmholtz operator
3827 subroutine box_gs_ahelmh(mg, id, nc, redblack_cntr)
3828 type(mg_t), intent(inout) :: mg
3829 integer, intent(in) :: id
3830 integer, intent(in) :: nc
3831 integer, intent(in) :: redblack_cntr !< Iteration counter
3832 integer :: i, j, k, i0, di
3833 logical :: redblack
3834 real(dp) :: idr2(2*3), u(2*3)
3835 real(dp) :: a0(2*3), a(2*3), c(2*3)
3836
3837 ! Duplicate 1/dr^2 array to multiply neighbor values
3838 idr2(1:2*3:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
3839 idr2(2:2*3:2) = idr2(1:2*3:2)
3840 i0 = 1
3841
3842 redblack = (mg%smoother_type == mg_smoother_gsrb)
3843 if (redblack) then
3844 di = 2
3845 else
3846 di = 1
3847 end if
3848
3849 ! The parity of redblack_cntr determines which cells we use. If
3850 ! redblack_cntr is even, we use the even cells and vice versa.
3851 associate(cc => mg%boxes(id)%cc, n => mg_iphi, &
3852 i_eps1 => mg_iveps1, &
3853 i_eps2 => mg_iveps2, &
3854 i_eps3 => mg_iveps3)
3855
3856 do k = 1, nc
3857 do j = 1, nc
3858 if (redblack) &
3859 i0 = 2 - iand(ieor(redblack_cntr, k+j), 1)
3860 do i = i0, nc, di
3861 a0(1:2) = cc(i, j, k, i_eps1)
3862 a0(3:4) = cc(i, j, k, i_eps2)
3863 a0(4:5) = cc(i, j, k, i_eps3)
3864 u(1:2) = cc(i-1:i+1:2, j, k, n)
3865 a(1:2) = cc(i-1:i+1:2, j, k, i_eps1)
3866 u(3:4) = cc(i, j-1:j+1:2, k, n)
3867 a(3:4) = cc(i, j-1:j+1:2, k, i_eps2)
3868 u(5:6) = cc(i, j, k-1:k+1:2, n)
3869 a(5:6) = cc(i, j, k-1:k+1:2, i_eps3)
3870 c(:) = 2 * a0(:) * a(:) / (a0(:) + a(:)) * idr2
3871
3872 cc(i, j, k, n) = (sum(c(:) * u(:)) - &
3873 cc(i, j, k, mg_irhs)) / &
3874 (sum(c(:)) + ahelmholtz_lambda)
3875 end do
3876 end do
3877 end do
3878 end associate
3879 end subroutine box_gs_ahelmh
3880
3881 !> Perform Helmholtz operator on a box
3882 subroutine box_ahelmh(mg, id, nc, i_out)
3883 type(mg_t), intent(inout) :: mg
3884 integer, intent(in) :: id
3885 integer, intent(in) :: nc
3886 integer, intent(in) :: i_out !< Index of variable to store Helmholtz in
3887 integer :: i, j, k
3888 real(dp) :: idr2(2*3), a0(2*3), u0, u(2*3), a(2*3)
3889
3890 ! Duplicate 1/dr^2 array to multiply neighbor values
3891 idr2(1:2*3:2) = 1/mg%dr(:, mg%boxes(id)%lvl)**2
3892 idr2(2:2*3:2) = idr2(1:2*3:2)
3893
3894 associate(cc => mg%boxes(id)%cc, n => mg_iphi, &
3895 i_eps1 => mg_iveps1, &
3896 i_eps2 => mg_iveps2, &
3897 i_eps3 => mg_iveps3)
3898 do k = 1, nc
3899 do j = 1, nc
3900 do i = 1, nc
3901 u0 = cc(i, j, k, n)
3902 a0(1:2) = cc(i, j, k, i_eps1)
3903 a0(3:4) = cc(i, j, k, i_eps2)
3904 a0(5:6) = cc(i, j, k, i_eps3)
3905 u(1:2) = cc(i-1:i+1:2, j, k, n)
3906 u(3:4) = cc(i, j-1:j+1:2, k, n)
3907 u(5:6) = cc(i, j, k-1:k+1:2, n)
3908 a(1:2) = cc(i-1:i+1:2, j, k, i_eps1)
3909 a(3:4) = cc(i, j-1:j+1:2, k, i_eps2)
3910 a(5:6) = cc(i, j, k-1:k+1:2, i_eps3)
3911
3912 cc(i, j, k, i_out) = sum(2 * idr2 * &
3913 a0(:)*a(:)/(a0(:) + a(:)) * (u(:) - u0)) - &
3915 end do
3916 end do
3917 end do
3918 end associate
3919 end subroutine box_ahelmh
3920
3921end module m_octree_mg_3d
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 helmholtz_set_lambda(lambda)
subroutine, public mg_set_methods(mg)
subroutine, public mg_restrict_buffer_size(mg, n_send, n_recv, dsize)
Specify minimum buffer size (per process) for communication.
integer, parameter, public mg_irhs
Index of right-hand side.
integer, parameter, public mg_vhelmholtz
Indicates a variable-coefficient Helmholtz equation.
integer, dimension(4, 6), parameter, public mg_child_adj_nb
integer, parameter, public mg_ahelmholtz
Indicates a anisotropic-coefficient Helmholtz equation.
integer, dimension(3, 6), parameter, public mg_neighb_dix
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...
subroutine, public mg_fas_fmg(mg, have_guess, max_res)
Perform FAS-FMG cycle (full approximation scheme, full multigrid).
integer, parameter, public mg_smoother_gsrb
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_num_children
subroutine, public mg_timers_show(mg)
integer, parameter, public mg_max_timers
Maximum number of timers to use.
subroutine, public mg_fas_vcycle(mg, highest_lvl, max_res, standalone)
Perform FAS V-cycle (full approximation scheme).
subroutine, public vhelmholtz_set_methods(mg)
integer, parameter, public mg_bc_dirichlet
Value to indicate a Dirichlet boundary condition.
integer, parameter, public mg_iveps
Index of the variable coefficient (at cell centers)
subroutine, public mg_load_balance_parents(mg)
Load balance the parents (non-leafs). Assign them to the rank that has most children.
integer, dimension(3, 8), parameter, public mg_child_dix
subroutine, public mg_phi_bc_store(mg)
Store boundary conditions for the solution variable, this can speed up calculations if the same bound...
integer(i8) function, public mg_number_of_unknowns(mg)
Determine total number of unknowns (on leaves)
integer, parameter, public mg_vlaplacian
Indicates a variable-coefficient Laplacian.
integer, parameter, public mg_cylindrical
Cylindrical coordinate system.
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_build_rectangle(mg, domain_size, box_size, dx, r_min, periodic, n_finer)
subroutine, public vhelmholtz_set_lambda(lambda)
integer, parameter, public mg_ires
Index of residual.
integer, parameter, public mg_smoother_gs
subroutine, public laplacian_set_methods(mg)
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_ghost_cell_buffer_size(mg, n_send, n_recv, dsize)
Specify minimum buffer size (per process) for communication.
subroutine, public mg_set_neighbors_lvl(mg, lvl)
integer, parameter, public mg_smoother_jacobi
integer, parameter, public mg_neighb_lowy
integer, parameter, public mg_bc_continuous
Value to indicate a continuous boundary condition.
subroutine, public mg_set_leaves_parents(boxes, level)
Create a list of leaves and a list of parents for a level.
subroutine, public helmholtz_set_methods(mg)
subroutine, public mg_add_children(mg, id)
integer, parameter, public mg_lvl_lo
Minimum allowed grid level.
integer, parameter, public mg_num_neighbors
integer, parameter, public mg_neighb_highy
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_iold
Index of previous solution (used for correction)
integer, parameter, public mg_bc_neumann
Value to indicate a Neumann boundary condition.
integer, dimension(6), parameter, public mg_neighb_high_pm
integer, parameter, public mg_ndim
Problem dimension.
integer, parameter, public mg_iphi
Index of solution.
integer, parameter, public mg_helmholtz
Indicates a constant-coefficient Helmholtz equation.
subroutine, public mg_allocate_storage(mg)
Allocate communication buffers and local boxes for a tree that has already been created.
subroutine, public mg_timer_end(timer)
integer, parameter, public mg_num_vars
Number of predefined multigrid variables.
subroutine, public ahelmholtz_set_methods(mg)
real(dp), public, protected vhelmholtz_lambda
Module for implicitly solving diffusion equations.
subroutine, public mg_restrict(mg, iv)
Restrict all levels.
integer, parameter, public mg_neighb_lowx
subroutine, public mg_set_next_level_ids(mg, lvl)
integer, parameter, public mg_physical_boundary
Special value that indicates there is a physical boundary.
integer, dimension(6), parameter, public mg_neighb_rev
integer, parameter, public mg_spherical
Spherical coordinate system.
integer, parameter, public mg_laplacian
Indicates a standard Laplacian.
subroutine, public mg_get_face_coords(box, nb, nc, x)
Get coordinates at the face of a box.
subroutine, public mg_timer_start(timer)
subroutine, public mg_prolong_buffer_size(mg, n_send, n_recv, dsize)
Specify minimum buffer size (per process) for communication.
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...
integer, parameter, public mg_neighb_highx
integer, parameter, public mg_cartesian
Cartesian coordinate system.
integer, parameter, public mg_iveps2
integer, parameter, public i8
Type for 64-bit integers.
integer, parameter, public mg_iveps1
Indexes of anisotropic variable coefficients.
subroutine, public mg_fill_ghost_cells_lvl(mg, lvl, iv)
Fill ghost cells at a grid level.
integer, parameter, public mg_neighb_lowz
subroutine, public diffusion_solve_vcoeff(mg, dt, order, max_res)
Solve a diffusion equation implicitly, assuming a variable diffusion coefficient which has been store...
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 ...
integer, parameter, public mg_lvl_hi
Maximum allowed grid level.
subroutine, public vlaplacian_set_methods(mg)
logical, dimension(6), parameter, public mg_neighb_low
integer, parameter, public mg_iveps3
elemental logical function, public mg_has_children(box)
Return .true. if a box has children.
subroutine, public mg_deallocate_storage(mg)
Deallocate all allocatable arrays.
real(dp), public, protected helmholtz_lambda
Module for load balancing a tree (that already has been constructed). The load balancing determines w...
subroutine, public mg_set_refinement_boundaries(boxes, level)
Create a list of refinement boundaries (from the coarse side)
pure integer function, dimension(3), 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_no_box
Special value that indicates there is no box.
subroutine, public mg_restrict_lvl(mg, iv, lvl)
Restrict from lvl to lvl-1.
subroutine, public diffusion_solve_acoeff(mg, dt, order, max_res)
Solve a diffusion equation implicitly, assuming anisotropic diffusion coefficient which has been stor...
pure integer function, public mg_highest_uniform_lvl(mg)
integer, dimension(6), parameter, public mg_neighb_dim
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 ahelmholtz_set_lambda(lambda)
subroutine, public mg_fill_ghost_cells(mg, iv)
Fill ghost cells at all grid levels.
integer function, public mg_add_timer(mg, name)
subroutine, public mg_apply_op(mg, i_out, op)
Apply operator to the tree and store in variable i_out.
integer, dimension(8, 3), parameter, public mg_child_rev
logical, dimension(3, 8), parameter, public mg_child_low
integer, parameter, public mg_max_num_vars
Maximum number of variables.
integer, parameter, public dp
Type of reals.
subroutine, public sort_and_transfer_buffers(mg, dsize)
integer, parameter, public mg_neighb_highz
Box data structure.
Buffer type (one is used for each pair of communicating processes)
Lists of blocks per refinement level.