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