Afivo  0.3
m_af_multigrid.f90
1 !> This module contains the geometric multigrid routines that come with Afivo
2 !>
3 !> @todo How to use box tag with different types of operators?
5 #include "../src/cpp_macros.h"
6  use m_af_types
7  use m_af_stencil
10 
11  implicit none
12  private
13 
14  public :: mg_t
15  public :: mg_init
16  public :: mg_use
17  public :: mg_destroy
18  public :: mg_fas_fmg
19  public :: mg_fas_vcycle
20 
21  ! Methods for level set functions
22  public :: mg_lsf_dist_linear
23  public :: mg_lsf_dist_gss
24 
25  ! Set tag for each box, depending on operator
26  public :: mg_set_box_tag
27  public :: mg_set_operators_lvl
28  public :: mg_set_operators_tree
29  public :: mg_update_operator_stencil
30 
31  ! Methods for normal Laplacian
32  public :: mg_box_lpl_gradient
33  public :: mg_sides_rb
34 
35  ! To compute the gradient of the solution
36  public :: mg_compute_phi_gradient
37  public :: mg_compute_field_norm
38  public :: mg_box_field_norm
39 
40 contains
41 
42  !> Check multigrid options or set them to default
43  subroutine mg_init(tree, mg)
44  use m_af_core, only: af_set_cc_methods
45  type(af_t), intent(inout) :: tree !< Tree to do multigrid on
46  type(mg_t), intent(inout) :: mg !< Multigrid options
47 
48  if (mg%i_phi < 0) stop "mg_init: i_phi not set"
49  if (mg%i_tmp < 0) stop "mg_init: i_tmp not set"
50  if (mg%i_rhs < 0) stop "mg_init: i_rhs not set"
51 
52  if (.not. associated(mg%sides_bc)) stop "mg_init: sides_bc not set"
53  if (.not. tree%ready) error stop "mg_init: tree not initialized"
54 
55  ! Check whether methods are set, otherwise use default (for laplacian)
56  if (.not. associated(mg%box_op)) mg%box_op => mg_auto_op
57  ! if (.not. associated(mg%box_stencil)) mg%box_stencil => mg_auto_stencil
58  if (.not. associated(mg%box_gsrb)) mg%box_gsrb => mg_auto_gsrb
59  if (.not. associated(mg%box_corr)) mg%box_corr => mg_auto_corr
60  if (.not. associated(mg%box_rstr)) mg%box_rstr => mg_auto_rstr
61  if (.not. associated(mg%sides_rb)) mg%sides_rb => mg_auto_rb
62 
63  ! By default, store new operator and prolongation stencils
64  if (mg%operator_key == af_stencil_none) then
65  tree%n_stencil_keys_stored = tree%n_stencil_keys_stored + 1
66  mg%operator_key = tree%n_stencil_keys_stored
67  end if
68 
69  if (mg%prolongation_key == af_stencil_none) then
70  tree%n_stencil_keys_stored = tree%n_stencil_keys_stored + 1
71  mg%prolongation_key = tree%n_stencil_keys_stored
72  end if
73 
74  if (mg%i_lsf /= -1) then
75  error stop "Set tree%mg_i_lsf instead of mg%i_lsf"
76  else if (iand(mg%operator_mask, mg_lsf_box) > 0) then
77  mg%i_lsf = tree%mg_i_lsf
78  end if
79 
80  if (mg%i_eps /= -1) then
81  error stop "Set tree%mg_i_eps instead of mg%i_eps"
82  else if (iand(mg%operator_mask, mg_veps_box+mg_ceps_box) > 0) then
83  mg%i_eps = tree%mg_i_eps
84  end if
85 
86  if (mg%i_lsf /= -1) then
87  if (.not. associated(mg%lsf_dist)) &
88  mg%lsf_dist => mg_lsf_dist_linear
89  if (associated(mg%lsf_dist, mg_lsf_dist_gss) .and. .not. &
90  associated(mg%lsf)) then
91  error stop "mg_lsf_dist_gss requires mg%lsf to be set"
92  end if
93  end if
94 
95  call mg_set_operators_lvl(tree, mg, 1)
96  call coarse_solver_initialize(tree, mg)
97 
98  if (mg%i_lsf /= -1) then
99  call check_coarse_representation_lsf(tree, mg)
100  end if
101 
102  if (.not. tree%has_cc_method(mg%i_phi)) then
103  ! Set the proper methods for the phi variable
104  call af_set_cc_methods(tree, mg%i_phi, mg%sides_bc, mg%sides_rb)
105  end if
106 
107  mg%initialized = .true.
108 
109  end subroutine mg_init
110 
111  subroutine mg_destroy(mg)
112  type(mg_t), intent(inout) :: mg !< Multigrid options
113  if (.not. mg%initialized) error stop "mg%initialized is false"
114  call coarse_solver_destroy(mg%csolver)
115  end subroutine mg_destroy
116 
117  !> Make sure box tags and operators are set
118  subroutine mg_use(tree, mg)
119  type(af_t), intent(inout) :: tree
120  type(mg_t), intent(in), target :: mg !< Multigrid options
121 
122  if (.not. mg%initialized) error stop "mg%initialized is false"
123  tree%mg_current_operator_mask = mg%operator_mask
124 
125  call mg_set_operators_tree(tree, mg)
126  end subroutine mg_use
127 
128  !> To be called at the end of a multigrid solve
129  subroutine done_with_mg(tree)
130  type(af_t), intent(inout) :: tree
131  tree%mg_current_operator_mask = -1
132  end subroutine done_with_mg
133 
134  !> Perform FAS-FMG cycle (full approximation scheme, full multigrid). Note
135  !> that this routine needs valid ghost cells (for i_phi) on input, and gives
136  !> back valid ghost cells on output
137  subroutine mg_fas_fmg(tree, mg, set_residual, have_guess)
138  use m_af_utils, only: af_boxes_copy_cc
139  type(af_t), intent(inout) :: tree !< Tree to do multigrid on
140  type(mg_t), intent(inout) :: mg !< Multigrid options
141  logical, intent(in) :: set_residual !< If true, store residual in i_tmp
142  logical, intent(in) :: have_guess !< If false, start from phi = 0
143  integer :: lvl
144 
145  call mg_use(tree, mg)
146 
147  if (have_guess) then
148  do lvl = tree%highest_lvl, 2, -1
149  ! Set rhs on coarse grid and restrict phi
150  call set_coarse_phi_rhs(tree, lvl, mg)
151  end do
152  else
153  call init_phi_rhs(tree, mg)
154  end if
155 
156  ! Handle level 1 grid
157  lvl = 1
158  call af_boxes_copy_cc(tree%boxes, tree%lvls(lvl)%ids, &
159  mg%i_phi, mg%i_tmp)
160  call mg_fas_vcycle(tree, mg, set_residual .and. &
161  lvl == tree%highest_lvl, lvl, standalone=.false.)
162 
163  do lvl = 2, tree%highest_lvl
164  ! Store phi_old in tmp
165  call af_boxes_copy_cc(tree%boxes, tree%lvls(lvl)%ids, &
166  mg%i_phi, mg%i_tmp)
167 
168  ! Correct solution at this lvl using lvl-1 data
169  ! phi = phi + prolong(phi_coarse - phi_old_coarse)
170  call correct_children(tree%boxes, tree%lvls(lvl-1)%parents, mg)
171 
172  ! Update ghost cells
173  call af_gc_lvl(tree, lvl, [mg%i_phi])
174 
175  call mg_fas_vcycle(tree, mg, set_residual .and. &
176  lvl == tree%highest_lvl, lvl, standalone=.false.)
177  end do
178 
179  call done_with_mg(tree)
180  end subroutine mg_fas_fmg
181 
182  !> Perform FAS V-cycle (full approximation scheme). Note that this routine
183  !> needs valid ghost cells (for i_phi) on input, and gives back valid ghost
184  !> cells on output
185  subroutine mg_fas_vcycle(tree, mg, set_residual, highest_lvl, standalone)
186  use m_af_utils, only: af_tree_sum_cc
187  type(af_t), intent(inout) :: tree !< Tree to do multigrid on
188  type(mg_t), intent(in) :: mg !< Multigrid options
189  logical, intent(in) :: set_residual !< If true, store residual in i_tmp
190  integer, intent(in), optional :: highest_lvl !< Maximum level for V-cycle
191  logical, intent(in), optional :: standalone !< False if called by other cycle
192  integer :: lvl, i, id, max_lvl
193  logical :: by_itself
194  real(dp) :: sum_phi, mean_phi
195 
196  by_itself = .true.; if (present(standalone)) by_itself = standalone
197 
198  if (by_itself) then
199  call mg_use(tree, mg)
200  end if
201 
202  max_lvl = tree%highest_lvl
203  if (present(highest_lvl)) max_lvl = highest_lvl
204 
205  do lvl = max_lvl, 2, -1
206  ! Downwards relaxation
207  call gsrb_boxes(tree, lvl, mg, mg_cycle_down)
208 
209  ! Set rhs on coarse grid, restrict phi, and copy i_phi to i_tmp for the
210  ! correction later
211  call update_coarse(tree, lvl, mg)
212  end do
213 
214  call solve_coarse_grid(tree, mg)
215 
216  ! Do the upwards part of the v-cycle in the tree
217  do lvl = 2, max_lvl
218  ! Correct solution at this lvl using lvl-1 data
219  ! phi = phi + prolong(phi_coarse - phi_old_coarse)
220  call correct_children(tree%boxes, tree%lvls(lvl-1)%parents, mg)
221 
222  ! Have to fill ghost cells after correction
223  call af_gc_lvl(tree, lvl, [mg%i_phi])
224 
225  ! Upwards relaxation
226  call gsrb_boxes(tree, lvl, mg, mg_cycle_up)
227  end do
228 
229  if (set_residual) then
230  !$omp parallel private(lvl, i, id)
231  do lvl = 1, max_lvl
232  !$omp do
233  do i = 1, size(tree%lvls(lvl)%ids)
234  id = tree%lvls(lvl)%ids(i)
235  call residual_box(tree%boxes(id), mg)
236  end do
237  !$omp end do nowait
238  end do
239  !$omp end parallel
240  end if
241 
242  ! Subtract the mean of phi, for example when doing a fully periodic
243  ! simulation. Note that the integrated r.h.s. term should also be zero then.
244  if (mg%subtract_mean) then
245  call af_tree_sum_cc(tree, mg%i_phi, sum_phi)
246  mean_phi = sum_phi / af_total_volume(tree)
247  !$omp parallel private(lvl, i, id)
248  do lvl = 1, max_lvl
249  !$omp do
250  do i = 1, size(tree%lvls(lvl)%ids)
251  id = tree%lvls(lvl)%ids(i)
252  tree%boxes(id)%cc(dtimes(:), mg%i_phi) = &
253  tree%boxes(id)%cc(dtimes(:), mg%i_phi) - mean_phi
254  end do
255  !$omp end do nowait
256  end do
257  !$omp end parallel
258  end if
259 
260  if (by_itself) then
261  call done_with_mg(tree)
262  end if
263 
264  end subroutine mg_fas_vcycle
265 
266  subroutine solve_coarse_grid(tree, mg)
267  use omp_lib
268  type(af_t), intent(inout) :: tree !< Tree to do multigrid on
269  type(mg_t), intent(in) :: mg !< Multigrid options
270  integer :: num_iterations, max_threads
271  integer :: n_unknowns
272 
273  call coarse_solver_set_rhs_phi(tree, mg)
274  n_unknowns = product(tree%coarse_grid_size)
275 
276  if (n_unknowns < mg%csolver%min_unknowns_for_openmp) then
277  ! Use single thread if there are too few unknowns
278  max_threads = omp_get_max_threads()
279  call omp_set_num_threads(1)
280  end if
281 
282  call coarse_solver(mg%csolver, num_iterations)
283  call coarse_solver_get_phi(tree, mg)
284 
285  ! Set ghost cells for the new coarse grid solution
286  call af_gc_lvl(tree, 1, [mg%i_phi])
287 
288  if (n_unknowns < mg%csolver%min_unknowns_for_openmp) then
289  call omp_set_num_threads(max_threads)
290  end if
291  end subroutine solve_coarse_grid
292 
293  !> Fill ghost cells near refinement boundaries which preserves diffusive fluxes.
294  subroutine mg_sides_rb(boxes, id, nb, iv)
295  type(box_t), intent(inout) :: boxes(:) !< List of all boxes
296  integer, intent(in) :: id !< Id of box
297  integer, intent(in) :: nb !< Ghost cell direction
298  integer, intent(in) :: iv !< Ghost cell variable
299  integer :: nc, ix, dix, ijk, di, co(ndim)
300  integer :: hnc, p_id, p_nb_id
301 #if NDIM == 1
302  real(dp) :: tmp
303  real(dp) :: gc
304 #elif NDIM == 2
305  integer :: dj
306  real(dp) :: tmp(0:boxes(id)%n_cell/2+1)
307  real(dp) :: gc(boxes(id)%n_cell)
308 #elif NDIM == 3
309  integer :: dj, dk
310  real(dp) :: tmp(0:boxes(id)%n_cell/2+1, 0:boxes(id)%n_cell/2+1)
311  real(dp) :: gc(boxes(id)%n_cell, boxes(id)%n_cell)
312 #endif
313 #if NDIM > 1
314  real(dp) :: grad(ndim-1)
315 #endif
316 
317  nc = boxes(id)%n_cell
318  hnc = nc/2
319 
320  p_id = boxes(id)%parent
321  p_nb_id = boxes(p_id)%neighbors(nb)
322  co = af_get_child_offset(boxes(id))
323 
324  associate(box => boxes(p_nb_id))
325  ! First fill a temporary array with data next to the fine grid
326  select case (nb)
327 #if NDIM == 1
328  case (af_neighb_lowx)
329  tmp = box%cc(nc, iv)
330  case (af_neighb_highx)
331  tmp = box%cc(1, iv)
332 #elif NDIM == 2
333  case (af_neighb_lowx)
334  tmp = box%cc(nc, co(2):co(2)+hnc+1, iv)
335  case (af_neighb_highx)
336  tmp = box%cc(1, co(2):co(2)+hnc+1, iv)
337  case (af_neighb_lowy)
338  tmp = box%cc(co(1):co(1)+hnc+1, nc, iv)
339  case (af_neighb_highy)
340  tmp = box%cc(co(1):co(1)+hnc+1, 1, iv)
341 #elif NDIM == 3
342  case (af_neighb_lowx)
343  tmp = box%cc(nc, co(2):co(2)+hnc+1, co(3):co(3)+hnc+1, iv)
344  case (af_neighb_highx)
345  tmp = box%cc(1, co(2):co(2)+hnc+1, co(3):co(3)+hnc+1, iv)
346  case (af_neighb_lowy)
347  tmp = box%cc(co(1):co(1)+hnc+1, nc, co(3):co(3)+hnc+1, iv)
348  case (af_neighb_highy)
349  tmp = box%cc(co(1):co(1)+hnc+1, 1, co(3):co(3)+hnc+1, iv)
350  case (af_neighb_lowz)
351  tmp = box%cc(co(1):co(1)+hnc+1, co(2):co(2)+hnc+1, nc, iv)
352  case (af_neighb_highz)
353  tmp = box%cc(co(1):co(1)+hnc+1, co(2):co(2)+hnc+1, 1, iv)
354 #endif
355  case default
356  error stop "mg_sides_rb: wrong argument for nb"
357  end select
358  end associate
359 
360  ! Now interpolate the coarse grid data to obtain values 'straight' next to
361  ! the fine grid points
362 #if NDIM == 1
363  gc = tmp
364 #elif NDIM == 2
365  do i = 1, hnc
366  grad(1) = 0.125_dp * (tmp(i+1) - tmp(i-1))
367  gc(2*i-1) = tmp(i) - grad(1)
368  gc(2*i) = tmp(i) + grad(1)
369  end do
370 #elif NDIM == 3
371  do j = 1, hnc
372  do i = 1, hnc
373  grad(1) = 0.125_dp * (tmp(i+1, j) - tmp(i-1, j))
374  grad(2) = 0.125_dp * (tmp(i, j+1) - tmp(i, j-1))
375  gc(2*i-1, 2*j-1) = tmp(i, j) - grad(1) - grad(2)
376  gc(2*i, 2*j-1) = tmp(i, j) + grad(1) - grad(2)
377  gc(2*i-1, 2*j) = tmp(i, j) - grad(1) + grad(2)
378  gc(2*i, 2*j) = tmp(i, j) + grad(1) + grad(2)
379  end do
380  end do
381 #endif
382 
383  if (af_neighb_low(nb)) then
384  ix = 1
385  dix = 1
386  else
387  ix = nc
388  dix = -1
389  end if
390 
391  select case (af_neighb_dim(nb))
392 #if NDIM == 1
393  case (1)
394  i = ix
395  di = dix
396  boxes(id)%cc(i-di, iv) = 0.5_dp * gc &
397  + 0.75_dp * boxes(id)%cc(i, iv) &
398  - 0.25_dp * boxes(id)%cc(i+di, iv)
399 #elif NDIM == 2
400  case (1)
401  i = ix
402  di = dix
403  do j = 1, nc
404  dj = -1 + 2 * iand(j, 1)
405  boxes(id)%cc(i-di, j, iv) = 0.5_dp * gc(j) &
406  + 0.75_dp * boxes(id)%cc(i, j, iv) &
407  - 0.25_dp * boxes(id)%cc(i+di, j, iv)
408  end do
409  case (2)
410  j = ix
411  dj = dix
412  do i = 1, nc
413  di = -1 + 2 * iand(i, 1)
414  boxes(id)%cc(i, j-dj, iv) = 0.5_dp * gc(i) &
415  + 0.75_dp * boxes(id)%cc(i, j, iv) &
416  - 0.25_dp * boxes(id)%cc(i, j+dj, iv)
417  end do
418 #elif NDIM == 3
419  case (1)
420  i = ix
421  di = dix
422  do k = 1, nc
423  dk = -1 + 2 * iand(k, 1)
424  do j = 1, nc
425  dj = -1 + 2 * iand(j, 1)
426  boxes(id)%cc(i-di, j, k, iv) = &
427  0.5_dp * gc(j, k) + &
428  0.75_dp * boxes(id)%cc(i, j, k, iv) - &
429  0.25_dp * boxes(id)%cc(i+di, j, k, iv)
430  end do
431  end do
432  case (2)
433  j = ix
434  dj = dix
435  do k = 1, nc
436  dk = -1 + 2 * iand(k, 1)
437  do i = 1, nc
438  di = -1 + 2 * iand(i, 1)
439  boxes(id)%cc(i, j-dj, k, iv) = &
440  0.5_dp * gc(i, k) + &
441  0.75_dp * boxes(id)%cc(i, j, k, iv) - &
442  0.25_dp * boxes(id)%cc(i, j+dj, k, iv)
443  end do
444  end do
445  case (3)
446  k = ix
447  dk = dix
448  do j = 1, nc
449  dj = -1 + 2 * iand(j, 1)
450  do i = 1, nc
451  di = -1 + 2 * iand(i, 1)
452  boxes(id)%cc(i, j, k-dk, iv) = &
453  0.5_dp * gc(i, j) + &
454  0.75_dp * boxes(id)%cc(i, j, k, iv) - &
455  0.25_dp * boxes(id)%cc(i, j, k+dk, iv)
456  end do
457  end do
458 #endif
459  end select
460 
461  end subroutine mg_sides_rb
462 
463  !> Fill ghost cells near refinement boundaries which preserves diffusive
464  !> fluxes. This routine does not do interpolation of coarse grid values.
465  !> Basically, we extrapolate from the fine cells to a corner point, and then
466  !> take the average between this corner point and a coarse neighbor to fill
467  !> ghost cells for the fine cells.
468  subroutine mg_sides_rb_extrap(boxes, id, nb, iv)
469  type(box_t), intent(inout) :: boxes(:) !< List of all boxes
470  integer, intent(in) :: id !< Id of box
471  integer, intent(in) :: nb !< Ghost cell direction
472  integer, intent(in) :: iv !< Ghost cell variable
473  integer :: nc, ix, dix, IJK, di
474 #if NDIM > 1
475  integer :: dj
476 #endif
477 #if NDIM > 2
478  integer :: dk
479 #endif
480 
481  nc = boxes(id)%n_cell
482 
483  if (af_neighb_low(nb)) then
484  ix = 1
485  dix = 1
486  else
487  ix = nc
488  dix = -1
489  end if
490 
491  call af_gc_prolong_copy(boxes, id, nb, iv, 0)
492 
493  select case (af_neighb_dim(nb))
494 #if NDIM == 1
495  case (1)
496  i = ix
497  di = dix
498  boxes(id)%cc(i-di, iv) = 0.5_dp * boxes(id)%cc(i-di, iv) &
499  + 0.75_dp * boxes(id)%cc(i, iv) &
500  - 0.25_dp * boxes(id)%cc(i+di, iv)
501 #elif NDIM == 2
502  case (1)
503  i = ix
504  di = dix
505  do j = 1, nc
506  dj = -1 + 2 * iand(j, 1)
507 
508  ! Bilinear extrapolation (using 4 points)
509  boxes(id)%cc(i-di, j, iv) = 0.5_dp * boxes(id)%cc(i-di, j, iv) + &
510  1.125_dp * boxes(id)%cc(i, j, iv) - 0.375_dp * &
511  (boxes(id)%cc(i+di, j, iv) + boxes(id)%cc(i, j+dj, iv)) &
512  + 0.125_dp * boxes(id)%cc(i+di, j+dj, iv)
513 
514  ! Extrapolation using 3 points
515  ! boxes(id)%cc(i-di, j, iv) = 0.5_dp * boxes(id)%cc(i-di, j, iv) + &
516  ! boxes(id)%cc(i, j, iv) - 0.25_dp * &
517  ! (boxes(id)%cc(i+di, j, iv) + boxes(id)%cc(i, j+dj, iv))
518 
519  ! Extrapolation using 2 points
520  ! boxes(id)%cc(i-di, j, iv) = 0.5_dp * boxes(id)%cc(i-di, j, iv) + &
521  ! 0.75_dp * boxes(id)%cc(i, j, iv) - 0.25_dp * &
522  ! boxes(id)%cc(i+di, j+dj, iv)
523  end do
524  case (2)
525  j = ix
526  dj = dix
527  do i = 1, nc
528  di = -1 + 2 * iand(i, 1)
529 
530  ! Bilinear extrapolation (using 4 points)
531  boxes(id)%cc(i, j-dj, iv) = 0.5_dp * boxes(id)%cc(i, j-dj, iv) + &
532  1.125_dp * boxes(id)%cc(i, j, iv) - 0.375_dp * &
533  (boxes(id)%cc(i+di, j, iv) + boxes(id)%cc(i, j+dj, iv)) &
534  + 0.125_dp * boxes(id)%cc(i+di, j+dj, iv)
535 
536  ! Extrapolation using 2 points
537  ! boxes(id)%cc(i, j-dj, iv) = 0.5_dp * boxes(id)%cc(i, j-dj, iv) + &
538  ! 0.75_dp * boxes(id)%cc(i, j, iv) - 0.25_dp * &
539  ! boxes(id)%cc(i+di, j+dj, iv)
540  end do
541 #elif NDIM == 3
542  case (1)
543  i = ix
544  di = dix
545  do k = 1, nc
546  dk = -1 + 2 * iand(k, 1)
547  do j = 1, nc
548  dj = -1 + 2 * iand(j, 1)
549  ! Trilinear extrapolation (using 8 points)
550  ! boxes(id)%cc(i-di, j, k, iv) = &
551  ! 0.5_dp * boxes(id)%cc(i-di, j, k, iv) + 0.0625_dp * (&
552  ! 27 * boxes(id)%cc(i, j, k, iv) &
553  ! - 9 * boxes(id)%cc(i+di, j, k, iv) &
554  ! - 9 * boxes(id)%cc(i, j+dj, k, iv) &
555  ! - 9 * boxes(id)%cc(i, j, k+dk, iv) &
556  ! + 3 * boxes(id)%cc(i+di, j+dj, k, iv) &
557  ! + 3 * boxes(id)%cc(i+di, j, k+dk, iv) &
558  ! + 3 * boxes(id)%cc(i, j+dj, k+dk, iv) &
559  ! - 1 * boxes(id)%cc(i+di, j+dj, k+dk, iv))
560 
561  ! Extrapolation using 2 points
562  boxes(id)%cc(i-di, j, k, iv) = &
563  0.5_dp * boxes(id)%cc(i-di, j, k, iv) + &
564  0.75_dp * boxes(id)%cc(i, j, k, iv) - &
565  0.25_dp * boxes(id)%cc(i+di, j+dj, k+dk, iv)
566  end do
567  end do
568  case (2)
569  j = ix
570  dj = dix
571  do k = 1, nc
572  dk = -1 + 2 * iand(k, 1)
573  do i = 1, nc
574  di = -1 + 2 * iand(i, 1)
575 
576  ! boxes(id)%cc(i, j-dj, k, iv) = &
577  ! 0.5_dp * boxes(id)%cc(i, j-dj, k, iv) + 0.0625_dp * (&
578  ! 27 * boxes(id)%cc(i, j, k, iv) &
579  ! - 9 * boxes(id)%cc(i+di, j, k, iv) &
580  ! - 9 * boxes(id)%cc(i, j+dj, k, iv) &
581  ! - 9 * boxes(id)%cc(i, j, k+dk, iv) &
582  ! + 3 * boxes(id)%cc(i+di, j+dj, k, iv) &
583  ! + 3 * boxes(id)%cc(i+di, j, k+dk, iv) &
584  ! + 3 * boxes(id)%cc(i, j+dj, k+dk, iv) &
585  ! - 1 * boxes(id)%cc(i+di, j+dj, k+dk, iv))
586 
587  boxes(id)%cc(i, j-dj, k, iv) = &
588  0.5_dp * boxes(id)%cc(i, j-dj, k, iv) + &
589  0.75_dp * boxes(id)%cc(i, j, k, iv) - &
590  0.25_dp * boxes(id)%cc(i+di, j+dj, k+dk, iv)
591  end do
592  end do
593  case (3)
594  k = ix
595  dk = dix
596  do j = 1, nc
597  dj = -1 + 2 * iand(j, 1)
598  do i = 1, nc
599  di = -1 + 2 * iand(i, 1)
600 
601  ! boxes(id)%cc(i, j, k-dk, iv) = &
602  ! 0.5_dp * boxes(id)%cc(i, j, k-dk, iv) + 0.0625_dp * (&
603  ! 27 * boxes(id)%cc(i, j, k, iv) &
604  ! - 9 * boxes(id)%cc(i+di, j, k, iv) &
605  ! - 9 * boxes(id)%cc(i, j+dj, k, iv) &
606  ! - 9 * boxes(id)%cc(i, j, k+dk, iv) &
607  ! + 3 * boxes(id)%cc(i+di, j+dj, k, iv) &
608  ! + 3 * boxes(id)%cc(i+di, j, k+dk, iv) &
609  ! + 3 * boxes(id)%cc(i, j+dj, k+dk, iv) &
610  ! - 1 * boxes(id)%cc(i+di, j+dj, k+dk, iv))
611 
612  boxes(id)%cc(i, j, k-dk, iv) = &
613  0.5_dp * boxes(id)%cc(i, j, k-dk, iv) + &
614  0.75_dp * boxes(id)%cc(i, j, k, iv) - &
615  0.25_dp * boxes(id)%cc(i+di, j+dj, k+dk, iv)
616  end do
617  end do
618 #endif
619  end select
620 
621  end subroutine mg_sides_rb_extrap
622 
623  ! Sets phi = phi + prolong(phi_coarse - phi_old_coarse)
624  subroutine correct_children(boxes, ids, mg)
625  type(box_t), intent(inout) :: boxes(:) !< List of all boxes
626  integer, intent(in) :: ids(:) !< Operate on these boxes
627  type(mg_t), intent(in) :: mg !< Multigrid options
628  integer :: i, id, nc, i_c, c_id
629 
630  !$omp parallel do private(id, nc, i_c, c_id)
631  do i = 1, size(ids)
632  id = ids(i)
633  nc = boxes(id)%n_cell
634 
635  ! Store the correction in i_tmp
636  boxes(id)%cc(dtimes(:), mg%i_tmp) = boxes(id)%cc(dtimes(:), mg%i_phi) - &
637  boxes(id)%cc(dtimes(:), mg%i_tmp)
638 
639  do i_c = 1, af_num_children
640  c_id = boxes(id)%children(i_c)
641  if (c_id == af_no_box) cycle
642  call mg%box_corr(boxes(id), boxes(c_id), mg)
643  end do
644  end do
645  !$omp end parallel do
646  end subroutine correct_children
647 
648  subroutine gsrb_boxes(tree, lvl, mg, type_cycle)
649  type(af_t), intent(inout) :: tree !< Tree containing full grid
650  type(mg_t), intent(in) :: mg !< Multigrid options
651  integer, intent(in) :: lvl !< Operate on this refinement level
652  integer, intent(in) :: type_cycle !< Type of cycle to perform
653  integer :: n, i, n_cycle
654  logical :: use_corners
655 
656  select case (type_cycle)
657  case (mg_cycle_down)
658  n_cycle = mg%n_cycle_down
659  case (mg_cycle_up)
660  n_cycle = mg%n_cycle_up
661  case default
662  error stop "gsrb_boxes: invalid cycle type"
663  end select
664 
665  associate(ids => tree%lvls(lvl)%ids)
666  !$omp parallel private(n, i)
667  do n = 1, 2 * n_cycle
668  !$omp do
669  do i = 1, size(ids)
670  call mg%box_gsrb(tree%boxes(ids(i)), n, mg)
671  end do
672  !$omp end do
673 
674  ! If corner ghost cells are not required, only store them during the
675  ! final upward cycle
676  use_corners = mg%use_corners .or. &
677  (type_cycle /= mg_cycle_down .and. n == 2 * n_cycle)
678 
679  !$omp do
680  do i = 1, size(ids)
681  call af_gc_box(tree, ids(i), [mg%i_phi], use_corners)
682  end do
683  !$omp end do
684  end do
685  !$omp end parallel
686  end associate
687  end subroutine gsrb_boxes
688 
689  ! Set rhs on coarse grid, restrict phi, and copy i_phi to i_tmp for the
690  ! correction later
691  subroutine update_coarse(tree, lvl, mg)
692  use m_af_utils, only: af_box_add_cc, af_box_copy_cc
693  type(af_t), intent(inout) :: tree !< Tree containing full grid
694  integer, intent(in) :: lvl !< Update coarse values at lvl-1
695  type(mg_t), intent(in) :: mg !< Multigrid options
696  integer :: i, id, p_id, nc
697  real(dp), allocatable :: tmp(DTIMES(:))
698 
699  id = tree%lvls(lvl)%ids(1)
700  nc = tree%n_cell
701  allocate(tmp(dtimes(1:nc)))
702 
703  ! Restrict phi and the residual
704  !$omp parallel do private(id, p_id, tmp)
705  do i = 1, size(tree%lvls(lvl)%ids)
706  id = tree%lvls(lvl)%ids(i)
707  p_id = tree%boxes(id)%parent
708 
709  ! Copy the data currently in i_tmp, and restore it later (i_tmp holds the
710  ! previous state of i_phi)
711  tmp = tree%boxes(id)%cc(dtimes(1:nc), mg%i_tmp)
712  call residual_box(tree%boxes(id), mg)
713  call mg%box_rstr(tree%boxes(id), tree%boxes(p_id), mg%i_tmp, mg)
714  call mg%box_rstr(tree%boxes(id), tree%boxes(p_id), mg%i_phi, mg)
715  tree%boxes(id)%cc(dtimes(1:nc), mg%i_tmp) = tmp
716  end do
717  !$omp end parallel do
718 
719  call af_gc_lvl(tree, lvl-1, [mg%i_phi])
720 
721  ! Set rhs_c = laplacian(phi_c) + restrict(res) where it is refined, and
722  ! store current coarse phi in tmp.
723 
724  !$omp parallel do private(id)
725  do i = 1, size(tree%lvls(lvl-1)%parents)
726  id = tree%lvls(lvl-1)%parents(i)
727 
728  ! Set rhs = L phi
729  call mg%box_op(tree%boxes(id), mg%i_rhs, mg)
730 
731  ! Add tmp (the fine grid residual) to rhs
732  call af_box_add_cc(tree%boxes(id), mg%i_tmp, mg%i_rhs)
733 
734  ! Story a copy of phi in tmp
735  call af_box_copy_cc(tree%boxes(id), mg%i_phi, mg%i_tmp)
736  end do
737  !$omp end parallel do
738  end subroutine update_coarse
739 
740  !> This routine performs the same as update_coarse, but it ignores the tmp
741  !> variable
742  subroutine set_coarse_phi_rhs(tree, lvl, mg)
743  use m_af_utils, only: af_box_add_cc
744  type(af_t), intent(inout) :: tree !< Tree containing full grid
745  integer, intent(in) :: lvl !< Update coarse values at lvl-1
746  type(mg_t), intent(in) :: mg !< Multigrid options
747  integer :: i, id, p_id
748 
749  ! Fill ghost cells here to be sure
750  if (lvl == tree%highest_lvl) then
751  call af_gc_lvl(tree, lvl, [mg%i_phi])
752  end if
753 
754  !$omp parallel do private(id, p_id)
755  do i = 1, size(tree%lvls(lvl)%ids)
756  id = tree%lvls(lvl)%ids(i)
757  p_id = tree%boxes(id)%parent
758 
759  call residual_box(tree%boxes(id), mg)
760  call mg%box_rstr(tree%boxes(id), tree%boxes(p_id), mg%i_tmp, mg)
761  call mg%box_rstr(tree%boxes(id), tree%boxes(p_id), mg%i_phi, mg)
762  end do
763  !$omp end parallel do
764 
765  call af_gc_lvl(tree, lvl-1, [mg%i_phi])
766 
767  ! Set rhs_c = laplacian(phi_c) + restrict(res) where it is refined
768 
769  !$omp parallel do private(id)
770  do i = 1, size(tree%lvls(lvl-1)%parents)
771  id = tree%lvls(lvl-1)%parents(i)
772  call mg%box_op(tree%boxes(id), mg%i_rhs, mg)
773  call af_box_add_cc(tree%boxes(id), mg%i_tmp, mg%i_rhs)
774  end do
775  !$omp end parallel do
776  end subroutine set_coarse_phi_rhs
777 
778  !> Set the initial guess for phi and restrict the rhs
779  subroutine init_phi_rhs(tree, mg)
780  use m_af_utils, only: af_box_clear_cc
781  type(af_t), intent(inout) :: tree !< Full grid
782  type(mg_t), intent(in) :: mg !< Multigrid options
783  integer :: i, id, p_id, lvl
784 
785  !$omp parallel private(lvl, i, id, p_id)
786  do lvl = tree%highest_lvl, 1+1, -1
787  !$omp do
788  do i = 1, size(tree%lvls(lvl)%ids)
789  id = tree%lvls(lvl)%ids(i)
790  call af_box_clear_cc(tree%boxes(id), mg%i_phi)
791  if (lvl > 1) then
792  p_id = tree%boxes(id)%parent
793  call mg%box_rstr(tree%boxes(id), tree%boxes(p_id), mg%i_rhs, mg)
794  end if
795  end do
796  !$omp end do
797  end do
798  !$omp end parallel
799  end subroutine init_phi_rhs
800 
801  subroutine residual_box(box, mg)
802  type(box_t), intent(inout) :: box !< Operate on this box
803  type(mg_t), intent(in) :: mg !< Multigrid options
804  integer :: nc
805 
806  call mg%box_op(box, mg%i_tmp, mg)
807  nc = box%n_cell
808  box%cc(dtimes(1:nc), mg%i_tmp) = box%cc(dtimes(1:nc), mg%i_rhs) &
809  - box%cc(dtimes(1:nc), mg%i_tmp)
810  end subroutine residual_box
811 
812  !> Based on the box type, apply a Gauss-Seidel relaxation scheme
813  subroutine mg_auto_gsrb(box, redblack_cntr, mg)
814  type(box_t), intent(inout) :: box !< Box to operate on
815  integer, intent(in) :: redblack_cntr !< Iteration count
816  type(mg_t), intent(in) :: mg !< Multigrid options
817 
818  call af_stencil_gsrb_box(box, mg%operator_key, redblack_cntr, &
819  mg%i_phi, mg%i_rhs)
820  end subroutine mg_auto_gsrb
821 
822  !> Store operator stencil for a box
823  subroutine mg_store_operator_stencil(box, mg, ix)
824  type(box_t), intent(inout) :: box
825  type(mg_t), intent(in) :: mg
826  !> Index of the stencil. If equal to af_stencil_none, store a new stencil
827  integer, intent(inout) :: ix
828 
829  if (ix == af_stencil_none) then
830  call af_stencil_prepare_store(box, mg%operator_key, ix)
831  end if
832 
833  select case (mg%operator_type)
834  case (mg_normal_operator)
835  call mg_box_lpl_stencil(box, mg, ix)
836  case (mg_lsf_operator)
837  call mg_box_lsf_stencil(box, mg, ix)
838  case (mg_eps_operator)
839  call mg_box_lpld_stencil(box, mg, ix)
840  case (mg_auto_operator)
841  ! Use box tag to set operator
842  select case (iand(box%tag, mg%operator_mask))
843  case (mg_normal_box)
844  call mg_box_lpl_stencil(box, mg, ix)
845  case (mg_lsf_box)
846  call mg_box_lsf_stencil(box, mg, ix)
847  case (mg_veps_box, mg_ceps_box)
848  call mg_box_lpld_stencil(box, mg, ix)
849  case (mg_veps_box+mg_lsf_box, mg_ceps_box+mg_lsf_box)
850  call mg_box_lpld_lsf_stencil(box, mg, ix)
851  case default
852  error stop "mg_store_operator_stencil: unknown box tag"
853  end select
854  case default
855  error stop "mg_store_operator_stencil: unknown mg%operator_type"
856  end select
857 
858  call af_stencil_check_box(box, mg%operator_key, ix)
859  end subroutine mg_store_operator_stencil
860 
861  !> Store prolongation stencil for a box
862  subroutine mg_store_prolongation_stencil(tree, id, mg)
863  type(af_t), intent(inout) :: tree
864  integer, intent(in) :: id !< Id of box
865  type(mg_t), intent(in) :: mg
866  integer :: ix, p_id
867 
868  call af_stencil_prepare_store(tree%boxes(id), mg%prolongation_key, ix)
869 
870  p_id = tree%boxes(id)%parent
871  if (p_id <= af_no_box) error stop "Box does not have parent"
872 
873  select case (mg%prolongation_type)
874  case (mg_prolong_linear)
875  call mg_box_prolong_linear_stencil(tree%boxes(id), &
876  tree%boxes(p_id), mg, ix)
877  case (mg_prolong_sparse)
878  call mg_box_prolong_sparse_stencil(tree%boxes(id), &
879  tree%boxes(p_id), mg, ix)
880  case (mg_prolong_auto)
881  ! Use box tag
882  associate(box=>tree%boxes(id), box_p=>tree%boxes(p_id))
883  select case (iand(box%tag, mg%operator_mask))
884  case (mg_normal_box, mg_ceps_box)
885  call mg_box_prolong_linear_stencil(box, box_p, mg, ix)
886  case (mg_lsf_box, mg_ceps_box+mg_lsf_box)
887  if (mg%lsf_use_custom_prolongation) then
888  call mg_box_prolong_lsf_stencil(box, box_p, mg, ix)
889  else
890  call mg_box_prolong_linear_stencil(box, box_p, mg, ix)
891  end if
892  case (mg_veps_box, mg_veps_box + mg_lsf_box)
893  call mg_box_prolong_eps_stencil(box, box_p, mg, ix)
894  case default
895  error stop "mg_store_prolongation_stencil: unknown box tag"
896  end select
897  end associate
898  case default
899  error stop "mg_store_prolongation_stencil: unknown mg%prolongation_type"
900  end select
901 
902  call af_stencil_check_box(tree%boxes(id), mg%prolongation_key, ix)
903  end subroutine mg_store_prolongation_stencil
904 
905  !> Based on the box type, apply the approriate operator
906  subroutine mg_auto_op(box, i_out, mg)
907  type(box_t), intent(inout) :: box !< Operate on this box
908  integer, intent(in) :: i_out !< Index of output variable
909  type(mg_t), intent(in) :: mg !< Multigrid options
910 
911  call af_stencil_apply_box(box, mg%operator_key, mg%i_phi, i_out)
912  end subroutine mg_auto_op
913 
914  !> Restriction operator
915  subroutine mg_auto_rstr(box_c, box_p, iv, mg)
916  type(box_t), intent(in) :: box_c !< Child box
917  type(box_t), intent(inout) :: box_p !< Parent box
918  integer, intent(in) :: iv !< Index of variable
919  type(mg_t), intent(in) :: mg !< Multigrid options
920 
921  ! Always apply standard restriction
922  call mg_box_rstr_lpl(box_c, box_p, iv, mg)
923  end subroutine mg_auto_rstr
924 
925  !> Set ghost cells near refinement boundaries
926  subroutine mg_auto_rb(boxes, id, nb, iv, op_mask)
927  type(box_t), intent(inout) :: boxes(:) !< List of all boxes
928  integer, intent(in) :: id !< Id of box
929  integer, intent(in) :: nb !< Ghost cell direction
930  integer, intent(in) :: iv !< Ghost cell variable
931  integer, intent(in) :: op_mask !< Operator mask
932 
933  select case (iand(boxes(id)%tag, op_mask))
934  case (mg_veps_box)
935  ! With a variable coefficients, use local extrapolation for ghost cells
936  call mg_sides_rb_extrap(boxes, id, nb, iv)
937  case default
938  call mg_sides_rb(boxes, id, nb, iv)
939  end select
940  end subroutine mg_auto_rb
941 
942  !> Based on the box type, correct the solution of the children
943  subroutine mg_auto_corr(box_p, box_c, mg)
944  type(box_t), intent(inout) :: box_c !< Child box
945  type(box_t), intent(in) :: box_p !< Parent box
946  type(mg_t), intent(in) :: mg !< Multigrid options
947 
948  call af_stencil_prolong_box(box_p, box_c, mg%prolongation_key, &
949  mg%i_tmp, mg%i_phi, .true.)
950  end subroutine mg_auto_corr
951 
952  !> Check where the level-set function could have a root by computing the
953  !> numerical gradient
954  subroutine get_possible_lsf_root_mask(box, nc, dmax, mg, root_mask)
955  type(box_t), intent(in) :: box !< Box to operate on
956  real(dp), intent(in) :: dmax !< Maximal distance to consider
957  integer, intent(in) :: nc !< Box size
958  type(mg_t), intent(in) :: mg !< Multigrid options
959  !> Whether there could be a root
960  logical, intent(out) :: root_mask(DTIMES(nc))
961  integer :: IJK
962  real(dp) :: gradnorm, rr(NDIM)
963 
964  if (.not. associated(mg%lsf)) error stop "mg%lsf not set"
965 
966  ! Compute gradient
967  do kji_do(1, nc)
968  rr = af_r_cc(box, [ijk])
969  gradnorm = norm2(numerical_gradient(mg%lsf, rr))
970  root_mask(ijk) = (abs(box%cc(ijk, mg%i_lsf)) < dmax * gradnorm * &
971  mg%lsf_gradient_safety_factor)
972  end do; close_do
973  end subroutine get_possible_lsf_root_mask
974 
975  !> Check if the level set function could have zeros, and store distances for
976  !> the neighboring cells
977  subroutine store_lsf_distance_matrix(box, nc, mg, boundary)
978  type(box_t), intent(inout) :: box !< Box to operate on
979  integer, intent(in) :: nc !< Box size
980  type(mg_t), intent(in) :: mg !< Multigrid options
981  logical, intent(out) :: boundary !< Whether a boundary is found
982  logical :: root_mask(DTIMES(nc))
983  real(dp) :: dd(2*NDIM), a(NDIM)
984  integer :: ixs(NDIM, nc**NDIM), IJK, ix, n
985  integer :: n_mask, m
986  real(dp) :: v(2*NDIM, nc**NDIM)
987 #if NDIM > 1
988  integer :: nb, dim, i_step, n_steps
989  real(dp) :: dist, gradient(NDIM), dvec(NDIM)
990  real(dp) :: x(NDIM), step_size(NDIM), min_dr
991 
992  min_dr = minval(box%dr)
993 #endif
994 
995  n = 0
996  boundary = .false.
997 
998  call get_possible_lsf_root_mask(box, nc, norm2(box%dr), mg, root_mask)
999  n_mask = count(root_mask)
1000 
1001  if (n_mask > 0) then
1002  ! Store mask of where potential roots are
1003  call af_stencil_prepare_store(box, mg_lsf_mask_key, ix)
1004  box%stencils(ix)%stype = stencil_sparse
1005  box%stencils(ix)%shape = af_stencil_mask
1006  call af_stencil_allocate_coeff(box%stencils(ix), box%n_cell, &
1007  n_sparse=n_mask)
1008 
1009  m = 0
1010  do kji_do(1, nc)
1011  if (root_mask(ijk)) then
1012  m = m + 1
1013  box%stencils(ix)%sparse_ix(:, m) = [ijk]
1014  end if
1015  end do; close_do
1016  else
1017  return
1018  end if
1019 
1020  ! Compute distances
1021  do kji_do(1, nc)
1022  if (root_mask(ijk)) then
1023  a = af_r_cc(box, [ijk])
1024 #if NDIM == 1
1025  dd(1) = mg%lsf_dist(a, af_r_cc(box, [i-1]), mg)
1026  dd(2) = mg%lsf_dist(a, af_r_cc(box, [i+1]), mg)
1027 #elif NDIM == 2
1028  dd(1) = mg%lsf_dist(a, af_r_cc(box, [i-1, j]), mg)
1029  dd(2) = mg%lsf_dist(a, af_r_cc(box, [i+1, j]), mg)
1030  dd(3) = mg%lsf_dist(a, af_r_cc(box, [i, j-1]), mg)
1031  dd(4) = mg%lsf_dist(a, af_r_cc(box, [i, j+1]), mg)
1032 #elif NDIM == 3
1033  dd(1) = mg%lsf_dist(a, af_r_cc(box, [i-1, j, k]), mg)
1034  dd(2) = mg%lsf_dist(a, af_r_cc(box, [i+1, j, k]), mg)
1035  dd(3) = mg%lsf_dist(a, af_r_cc(box, [i, j-1, k]), mg)
1036  dd(4) = mg%lsf_dist(a, af_r_cc(box, [i, j+1, k]), mg)
1037  dd(5) = mg%lsf_dist(a, af_r_cc(box, [i, j, k-1]), mg)
1038  dd(6) = mg%lsf_dist(a, af_r_cc(box, [i, j, k+1]), mg)
1039 #endif
1040 
1041 #if NDIM > 1
1042  ! If no boundaries are found, search along the gradient of the level
1043  ! set function to check if there is a boundary nearby
1044  if (min_dr > mg%lsf_length_scale .and. all(dd >= 1)) then
1045  n_steps = ceiling(min_dr/mg%lsf_length_scale)
1046  step_size = sign(mg%lsf_length_scale, box%cc(ijk, mg%i_lsf))
1047  x = a
1048 
1049  do i_step = 1, n_steps
1050  gradient = numerical_gradient(mg%lsf, x)
1051  gradient = gradient/max(norm2(gradient), 1e-50_dp) ! unit vector
1052 
1053  ! Search in direction towards zero
1054  x = x - gradient * step_size
1055  if (mg%lsf(x) * box%cc(ijk, mg%i_lsf) <= 0) exit
1056  end do
1057 
1058  dist = mg%lsf_dist(a, x, mg)
1059 
1060  if (dist < 1) then
1061  ! Rescale
1062  dist = dist * norm2(x - a)/min_dr
1063  dvec = x - a
1064 
1065  ! Select closest direction
1066  dim = maxloc(abs(dvec), dim=1)
1067  nb = 2 * dim - 1
1068  if (dvec(dim) > 0) nb = nb + 1
1069 
1070  dd(nb) = dist
1071  end if
1072  end if
1073 #endif
1074  else
1075  dd(:) = 1.0_dp
1076  end if
1077 
1078  ! Only store distances for boundaries
1079  if (any(dd < 1.0_dp)) then
1080  n = n + 1
1081  ixs(:, n) = [ijk]
1082  v(:, n) = dd
1083  end if
1084  end do; close_do
1085 
1086  if (n > 0) then
1087  boundary = .true.
1088  call af_stencil_prepare_store(box, mg_lsf_distance_key, ix)
1089  box%stencils(ix)%stype = stencil_sparse
1090  box%stencils(ix)%shape = af_stencil_246
1091  call af_stencil_allocate_coeff(box%stencils(ix), box%n_cell, &
1092  n_sparse=n)
1093  box%stencils(ix)%sparse_ix(:, :) = ixs(:, 1:n)
1094  box%stencils(ix)%sparse_v(:, :) = v(:, 1:n)
1095  end if
1096 
1097  end subroutine store_lsf_distance_matrix
1098 
1099  !> Set tag (box type) for a box in the tree
1100  subroutine mg_set_box_tag(tree, id, mg, new_lsf, new_eps)
1101  type(af_t), intent(inout) :: tree
1102  integer, intent(in) :: id
1103  type(mg_t), intent(in) :: mg
1104  logical, intent(in) :: new_lsf !< Whether the lsf has changed
1105  logical, intent(in) :: new_eps !< Whether epsilon has changed
1106  logical :: has_lsf, update_lsf, update_eps
1107  real(dp) :: a, b
1108 
1109  associate(box => tree%boxes(id))
1110  if (box%tag == af_init_tag) then
1111  box%tag = mg_normal_box
1112  update_lsf = .true.
1113  update_eps = .true.
1114  else
1115  update_lsf = new_lsf
1116  update_eps = new_eps
1117 
1118  ! Remove flags for updated variables
1119  if (new_lsf) box%tag = iand(box%tag, not(mg_lsf_box))
1120  if (new_eps) box%tag = iand(box%tag, not(ior(mg_veps_box, mg_ceps_box)))
1121  end if
1122 
1123  if (tree%mg_i_lsf /= -1 .and. update_lsf) then
1124  call store_lsf_distance_matrix(box, box%n_cell, mg, has_lsf)
1125  if (has_lsf) then
1126  ! Add bits indicating a level set function
1127  box%tag = box%tag + mg_lsf_box
1128  end if
1129  end if
1130 
1131  if (tree%mg_i_eps /= -1 .and. update_eps) then
1132  a = minval(box%cc(dtimes(:), tree%mg_i_eps))
1133  b = maxval(box%cc(dtimes(:), tree%mg_i_eps))
1134 
1135  if (b > a) then
1136  ! Variable coefficient
1137  box%tag = box%tag + mg_veps_box
1138  else if (maxval(abs([a, b] - 1)) > 1e-8_dp) then
1139  ! Constant coefficient (but not equal to one)
1140  box%tag = box%tag + mg_ceps_box
1141  end if
1142  end if
1143  end associate
1144 
1145  end subroutine mg_set_box_tag
1146 
1147  subroutine mg_set_operators_lvl(tree, mg, lvl)
1148  type(af_t), intent(inout) :: tree
1149  type(mg_t), intent(in) :: mg
1150  integer, intent(in) :: lvl
1151  integer :: i, id, n
1152 
1153  !$omp parallel do private(i, id, n)
1154  do i = 1, size(tree%lvls(lvl)%ids)
1155  id = tree%lvls(lvl)%ids(i)
1156  associate(box => tree%boxes(id))
1157 
1158  if (box%tag == af_init_tag) then
1159  ! We could use the tag of the parent box, but sometimes a part of a
1160  ! sharp feature can only be detected in the children
1161  call mg_set_box_tag(tree, id, mg, .true., .true.)
1162  end if
1163 
1164  ! Check if stencils are available
1165  n = af_stencil_index(box, mg%operator_key)
1166  if (n == af_stencil_none) then
1167  call mg_store_operator_stencil(box, mg, n)
1168  end if
1169 
1170  ! Compute right-hand side correction for internal boundaries
1171  if (allocated(box%stencils(n)%f)) then
1172  box%stencils(n)%bc_correction = box%stencils(n)%f * &
1173  mg_lsf_boundary_value(box, mg)
1174  end if
1175 
1176  if (lvl > 1) then
1177  n = af_stencil_index(box, mg%prolongation_key)
1178  if (n == af_stencil_none) then
1179  call mg_store_prolongation_stencil(tree, id, mg)
1180  end if
1181  end if
1182  end associate
1183  end do
1184  !$omp end parallel do
1185  end subroutine mg_set_operators_lvl
1186 
1187  !> Update stencil for an operator, because (part of) the coefficients have changed
1188  subroutine mg_update_operator_stencil(tree, mg, new_lsf, new_eps)
1189  type(af_t), intent(inout) :: tree
1190  type(mg_t), intent(inout) :: mg
1191  logical, intent(in) :: new_lsf !< Whether the lsf has changed
1192  logical, intent(in) :: new_eps !< Whether epsilon has changed
1193  integer :: lvl, i, id, n
1194 
1195  !$omp parallel private(lvl, i, id, n)
1196  do lvl = 1, tree%highest_lvl
1197  !$omp do
1198  do i = 1, size(tree%lvls(lvl)%ids)
1199  id = tree%lvls(lvl)%ids(i)
1200  associate(box => tree%boxes(id))
1201  n = af_stencil_index(box, mg%operator_key)
1202 
1203  ! Update box tag
1204  call mg_set_box_tag(tree, id, mg, new_lsf, new_eps)
1205 
1206  call mg_store_operator_stencil(box, mg, n)
1207  end associate
1208  end do
1209  !$omp end do
1210  end do
1211  !$omp end parallel
1212 
1213  call coarse_solver_update_matrix(tree, mg)
1214  end subroutine mg_update_operator_stencil
1215 
1216  subroutine mg_set_operators_tree(tree, mg)
1217  type(af_t), intent(inout) :: tree
1218  type(mg_t), intent(in) :: mg
1219  integer :: lvl
1220 
1221  do lvl = 1, tree%highest_lvl
1222  call mg_set_operators_lvl(tree, mg, lvl)
1223  end do
1224  end subroutine mg_set_operators_tree
1225 
1226  !> Restriction of child box (box_c) to its parent (box_p)
1227  subroutine mg_box_rstr_lpl(box_c, box_p, iv, mg)
1228  use m_af_restrict, only: af_restrict_box
1229  type(box_t), intent(in) :: box_c !< Child box to restrict
1230  type(box_t), intent(inout) :: box_p !< Parent box to restrict to
1231  integer, intent(in) :: iv !< Variable to restrict
1232  type(mg_t), intent(in) :: mg !< Multigrid options
1233 
1234  if (iv == mg%i_phi) then
1235  ! Don't use geometry for restriction, since this is inconsistent with the
1236  ! filling of ghost cells near refinement boundaries
1237  call af_restrict_box(box_c, box_p, [iv], use_geometry=.false.)
1238  else
1239  ! For the right-hand side, use the geometry
1240  call af_restrict_box(box_c, box_p, [iv], use_geometry=.true.)
1241  end if
1242  end subroutine mg_box_rstr_lpl
1243 
1244  !> Store the matrix stencil for each cell of the box. The order of the stencil
1245  !> is (i, j), (i-1, j), (i+1, j), (i, j-1), (i, j+1) (e.g., -4, 1, 1, 1, 1)
1246  subroutine mg_box_lpl_stencil(box, mg, ix)
1247  type(box_t), intent(inout) :: box
1248  type(mg_t), intent(in) :: mg
1249  integer, intent(in) :: ix !< Stencil index
1250  real(dp) :: inv_dr2(NDIM)
1251  integer :: idim
1252 
1253  box%stencils(ix)%shape = af_stencil_357
1254  box%stencils(ix)%stype = stencil_constant
1255  box%stencils(ix)%cylindrical_gradient = (box%coord_t == af_cyl)
1256  inv_dr2 = 1 / box%dr**2
1257  call af_stencil_allocate_coeff(box%stencils(ix), box%n_cell)
1258 
1259  do idim = 1, ndim
1260  box%stencils(ix)%c(2*idim:2*idim+1) = inv_dr2(idim)
1261  end do
1262  box%stencils(ix)%c(1) = -sum(box%stencils(ix)%c(2:)) - mg%helmholtz_lambda
1263 
1264  end subroutine mg_box_lpl_stencil
1265 
1266  !> Store linear prolongation stencil for standard Laplacian
1267  subroutine mg_box_prolong_linear_stencil(box, box_p, mg, ix)
1268  type(box_t), intent(inout) :: box !< Current box
1269  type(box_t), intent(in) :: box_p !< Parent box
1270  type(mg_t), intent(in) :: mg
1271  integer, intent(in) :: ix !< Stencil index
1272 
1273  box%stencils(ix)%shape = af_stencil_p248
1274  box%stencils(ix)%stype = stencil_constant
1275  call af_stencil_allocate_coeff(box%stencils(ix), box%n_cell)
1276 
1277 #if NDIM == 1
1278  box%stencils(ix)%c(:) = [0.75_dp, 0.25_dp]
1279 #elif NDIM == 2
1280  box%stencils(ix)%c(:) = [9, 3, 3, 1] / 16.0_dp
1281 #elif NDIM == 3
1282  box%stencils(ix)%c(:) = [27, 9, 9, 3, 9, 3, 3, 1] / 64.0_dp
1283 #endif
1284  end subroutine mg_box_prolong_linear_stencil
1285 
1286  !> Store sparse linear prolongation stencil for standard Laplacian
1287  subroutine mg_box_prolong_sparse_stencil(box, box_p, mg, ix)
1288  type(box_t), intent(inout) :: box !< Current box
1289  type(box_t), intent(in) :: box_p !< Parent box
1290  type(mg_t), intent(in) :: mg
1291  integer, intent(in) :: ix !< Stencil index
1292 
1293  box%stencils(ix)%shape = af_stencil_p234
1294  box%stencils(ix)%stype = stencil_constant
1295  call af_stencil_allocate_coeff(box%stencils(ix), box%n_cell)
1296 
1297 #if NDIM == 1
1298  box%stencils(ix)%c(:) = [0.75_dp, 0.25_dp]
1299 #elif NDIM == 2
1300  box%stencils(ix)%c(:) = [0.5_dp, 0.25_dp, 0.25_dp]
1301 #elif NDIM == 3
1302  box%stencils(ix)%c(:) = [0.25_dp, 0.25_dp, 0.25_dp, 0.25_dp]
1303 #endif
1304  end subroutine mg_box_prolong_sparse_stencil
1305 
1306  !> Store prolongation stencil for standard Laplacian with variable coefficient
1307  !> that can jump at cell faces
1308  subroutine mg_box_prolong_eps_stencil(box, box_p, mg, ix)
1309  type(box_t), intent(inout) :: box !< Current box
1310  type(box_t), intent(in) :: box_p !< Parent box
1311  type(mg_t), intent(in) :: mg
1312  integer, intent(in) :: ix !< Stencil index
1313  real(dp) :: a0, a(NDIM)
1314  integer :: i_eps, nc
1315  logical :: success
1316  integer :: IJK, IJK_(c1)
1317  integer :: IJK_(c2), ix_offset(NDIM)
1318 #if NDIM == 3
1319  real(dp), parameter :: third = 1/3.0_dp
1320 #endif
1321 
1322  nc = box%n_cell
1323  box%stencils(ix)%shape = af_stencil_p234
1324  box%stencils(ix)%stype = stencil_variable
1325  ix_offset = af_get_child_offset(box)
1326  call af_stencil_allocate_coeff(box%stencils(ix), box%n_cell)
1327 
1328  i_eps = mg%i_eps
1329 
1330  associate(v => box%stencils(ix)%v)
1331  ! In these loops, we calculate the closest coarse index (_c1), and the
1332  ! one-but-closest (_c2). The fine cell lies in between.
1333 #if NDIM == 1
1334  do i = 1, nc
1335  i_c1 = ix_offset(1) + ishft(i+1, -1) ! (i+1)/2
1336  i_c2 = i_c1 + 1 - 2 * iand(i, 1) ! even: +1, odd: -1
1337 
1338  a0 = box_p%cc(i_c1, i_eps)
1339  a(1) = box_p%cc(i_c2, i_eps)
1340 
1341  ! Get value of phi at coarse cell faces, and average
1342  v(:, ijk) = [a0, a(1)] / (a0 + a(1))
1343  end do
1344 #elif NDIM == 2
1345  do j = 1, nc
1346  j_c1 = ix_offset(2) + ishft(j+1, -1) ! (j+1)/2
1347  j_c2 = j_c1 + 1 - 2 * iand(j, 1) ! even: +1, odd: -1
1348  do i = 1, nc
1349  i_c1 = ix_offset(1) + ishft(i+1, -1) ! (i+1)/2
1350  i_c2 = i_c1 + 1 - 2 * iand(i, 1) ! even: +1, odd: -1
1351 
1352  a0 = box_p%cc(i_c1, j_c1, i_eps)
1353  a(1) = box_p%cc(i_c2, j_c1, i_eps)
1354  a(2) = box_p%cc(i_c1, j_c2, i_eps)
1355 
1356  ! Get value of phi at coarse cell faces, and average
1357  v(1, ijk) = 0.5_dp * sum(a0 / (a0 + a(:)))
1358  v(2:, ijk) = 0.5_dp * a(:) / (a0 + a(:))
1359  end do
1360  end do
1361 #elif NDIM == 3
1362  do k = 1, nc
1363  k_c1 = ix_offset(3) + ishft(k+1, -1) ! (k+1)/2
1364  k_c2 = k_c1 + 1 - 2 * iand(k, 1) ! even: +1, odd: -1
1365  do j = 1, nc
1366  j_c1 = ix_offset(2) + ishft(j+1, -1) ! (j+1)/2
1367  j_c2 = j_c1 + 1 - 2 * iand(j, 1) ! even: +1, odd: -1
1368  do i = 1, nc
1369  i_c1 = ix_offset(1) + ishft(i+1, -1) ! (i+1)/2
1370  i_c2 = i_c1 + 1 - 2 * iand(i, 1) ! even: +1, odd: -1
1371 
1372  a0 = box_p%cc(i_c1, j_c1, k_c1, i_eps)
1373  a(1) = box_p%cc(i_c2, j_c1, k_c1, i_eps)
1374  a(2) = box_p%cc(i_c1, j_c2, k_c1, i_eps)
1375  a(3) = box_p%cc(i_c1, j_c1, k_c2, i_eps)
1376 
1377  ! Get value of phi at coarse cell faces, and average
1378  v(1, ijk) = third * sum((a0 - 0.5_dp * a(:))/(a0 + a(:)))
1379  v(2:, ijk) = 0.5_dp * a(:) / (a0 + a(:))
1380  end do
1381  end do
1382  end do
1383 #endif
1384  end associate
1385 
1386  call af_stencil_try_constant(box, ix, epsilon(1.0_dp), success)
1387 
1388  end subroutine mg_box_prolong_eps_stencil
1389 
1390  !> Store prolongation stencil for standard Laplacian with level set function
1391  !> for internal boundaries
1392  subroutine mg_box_prolong_lsf_stencil(box, box_p, mg, ix)
1393  type(box_t), intent(inout) :: box !< Current box
1394  type(box_t), intent(in) :: box_p !< Parent box
1395  type(mg_t), intent(in) :: mg
1396  integer, intent(in) :: ix !< Stencil index
1397  real(dp) :: dd(NDIM+1), a(NDIM)
1398  integer :: i_lsf, nc, ix_mask
1399  logical :: success
1400  integer :: IJK, IJK_(c1), n, n_mask
1401  integer :: IJK_(c2), ix_offset(NDIM)
1402 
1403  nc = box%n_cell
1404  box%stencils(ix)%shape = af_stencil_p234
1405  box%stencils(ix)%stype = stencil_variable
1406  ix_offset = af_get_child_offset(box)
1407  i_lsf = mg%i_lsf
1408  call af_stencil_allocate_coeff(box%stencils(ix), box%n_cell)
1409 
1410  ix_mask = af_stencil_index(box, mg_lsf_mask_key)
1411  if (ix_mask == af_stencil_none) error stop "No LSF root mask stored"
1412  n_mask = size(box%stencils(ix_mask)%sparse_ix, 2)
1413 
1414  associate(v => box%stencils(ix)%v)
1415  ! In these loops, we calculate the closest coarse index (_c1), and the
1416  ! one-but-closest (_c2). The fine cell lies in between.
1417 #if NDIM == 1
1418  v(1, :) = 0.75_dp
1419  v(2, :) = 0.25_dp
1420 
1421  do n = 1, n_mask
1422  i = box%stencils(ix_mask)%sparse_ix(1, n)
1423  i_c1 = ix_offset(1) + ishft(i+1, -1) ! (i+1)/2
1424  i_c2 = i_c1 + 1 - 2 * iand(i, 1) ! even: +1, odd: -1
1425 
1426  a = af_r_cc(box, [ijk])
1427  dd(1) = mg%lsf_dist(a, af_r_cc(box_p, [i_c1]), mg)
1428  dd(2) = mg%lsf_dist(a, af_r_cc(box_p, [i_c2]), mg)
1429 
1430  v(:, ijk) = [3 * dd(2), dd(1)]
1431  v(:, ijk) = v(:, ijk) / sum(v(:, ijk))
1432  where (dd < 1) v(:, ijk) = 0
1433  end do
1434 #elif NDIM == 2
1435  v(1, :, :) = 0.5_dp
1436  v(2, :, :) = 0.25_dp
1437  v(3, :, :) = 0.25_dp
1438 
1439  do n = 1, n_mask
1440  i = box%stencils(ix_mask)%sparse_ix(1, n)
1441  j = box%stencils(ix_mask)%sparse_ix(2, n)
1442 
1443  j_c1 = ix_offset(2) + ishft(j+1, -1) ! (j+1)/2
1444  j_c2 = j_c1 + 1 - 2 * iand(j, 1) ! even: +1, odd: -1
1445  i_c1 = ix_offset(1) + ishft(i+1, -1) ! (i+1)/2
1446  i_c2 = i_c1 + 1 - 2 * iand(i, 1) ! even: +1, odd: -1
1447 
1448  a = af_r_cc(box, [ijk])
1449  dd(1) = mg%lsf_dist(a, af_r_cc(box_p, [i_c1, j_c1]), mg)
1450  dd(2) = mg%lsf_dist(a, af_r_cc(box_p, [i_c2, j_c1]), mg)
1451  dd(3) = mg%lsf_dist(a, af_r_cc(box_p, [i_c1, j_c2]), mg)
1452 
1453  v(:, ijk) = [2 * dd(2) * dd(3), dd(1) * dd(3), dd(1) * dd(2)]
1454  v(:, ijk) = v(:, ijk) / sum(v(:, ijk))
1455  where (dd < 1) v(:, ijk) = 0
1456  end do
1457 #elif NDIM == 3
1458  v(:, :, :, :) = 0.25_dp
1459 
1460  do n = 1, n_mask
1461  i = box%stencils(ix_mask)%sparse_ix(1, n)
1462  j = box%stencils(ix_mask)%sparse_ix(2, n)
1463  k = box%stencils(ix_mask)%sparse_ix(3, n)
1464 
1465  k_c1 = ix_offset(3) + ishft(k+1, -1) ! (k+1)/2
1466  k_c2 = k_c1 + 1 - 2 * iand(k, 1) ! even: +1, odd: -1
1467  j_c1 = ix_offset(2) + ishft(j+1, -1) ! (j+1)/2
1468  j_c2 = j_c1 + 1 - 2 * iand(j, 1) ! even: +1, odd: -1
1469  i_c1 = ix_offset(1) + ishft(i+1, -1) ! (i+1)/2
1470  i_c2 = i_c1 + 1 - 2 * iand(i, 1) ! even: +1, odd: -1
1471 
1472  a = af_r_cc(box, [ijk])
1473  dd(1) = mg%lsf_dist(a, af_r_cc(box_p, [i_c1, j_c1, k_c1]), mg)
1474  dd(2) = mg%lsf_dist(a, af_r_cc(box_p, [i_c2, j_c1, k_c1]), mg)
1475  dd(3) = mg%lsf_dist(a, af_r_cc(box_p, [i_c1, j_c2, k_c1]), mg)
1476  dd(4) = mg%lsf_dist(a, af_r_cc(box_p, [i_c1, j_c1, k_c2]), mg)
1477 
1478  v(:, ijk) = [dd(2) * dd(3) * dd(4), &
1479  dd(1) * dd(3) * dd(4), dd(1) * dd(2) * dd(4), &
1480  dd(1) * dd(2) * dd(3)]
1481  v(:, ijk) = v(:, ijk) / sum(v(:, ijk))
1482  where (dd < 1) v(:, ijk) = 0
1483  end do
1484 #endif
1485  end associate
1486 
1487  call af_stencil_try_constant(box, ix, epsilon(1.0_dp), success)
1488 
1489  end subroutine mg_box_prolong_lsf_stencil
1490 
1491  !> Store the matrix stencil for each cell of the box. The order of the stencil
1492  !> is (i, j), (i-1, j), (i+1, j), (i, j-1), (i, j+1) (e.g., -4, 1, 1, 1, 1)
1493  subroutine mg_box_lpld_stencil(box, mg, ix)
1494  type(box_t), intent(inout) :: box
1495  type(mg_t), intent(in) :: mg
1496  integer, intent(in) :: ix !< Index of the stencil
1497  integer :: IJK, nc
1498  real(dp) :: idr2(2*NDIM), a0, a(2*NDIM)
1499  logical :: success
1500 
1501  nc = box%n_cell
1502  idr2(1:2*ndim:2) = 1/box%dr**2
1503  idr2(2:2*ndim:2) = idr2(1:2*ndim:2)
1504 
1505  box%stencils(ix)%shape = af_stencil_357
1506  box%stencils(ix)%stype = stencil_variable
1507  box%stencils(ix)%cylindrical_gradient = (box%coord_t == af_cyl)
1508  call af_stencil_allocate_coeff(box%stencils(ix), box%n_cell)
1509 
1510  associate(cc => box%cc, n => mg%i_phi, i_eps => mg%i_eps)
1511  do kji_do(1, nc)
1512 #if NDIM == 1
1513  a0 = box%cc(i, i_eps)
1514  a(1:2) = box%cc(i-1:i+1:2, i_eps)
1515 #elif NDIM == 2
1516  a0 = box%cc(i, j, i_eps)
1517  a(1:2) = box%cc(i-1:i+1:2, j, i_eps)
1518  a(3:4) = box%cc(i, j-1:j+1:2, i_eps)
1519 #elif NDIM == 3
1520  a0 = box%cc(i, j, k, i_eps)
1521  a(1:2) = box%cc(i-1:i+1:2, j, k, i_eps)
1522  a(3:4) = box%cc(i, j-1:j+1:2, k, i_eps)
1523  a(5:6) = box%cc(i, j, k-1:k+1:2, i_eps)
1524 #endif
1525  box%stencils(ix)%v(2:, ijk) = idr2 * 2 * a0*a(:)/(a0 + a(:))
1526  box%stencils(ix)%v(1, ijk) = -sum(box%stencils(ix)%v(2:, ijk))
1527  end do; close_do
1528  end associate
1529 
1530  call af_stencil_try_constant(box, ix, epsilon(1.0_dp), success)
1531 
1532  end subroutine mg_box_lpld_stencil
1533 
1534  !> Store stencil for a box with variable coefficient and level set function
1535  subroutine mg_box_lpld_lsf_stencil(box, mg, ix)
1536  type(box_t), intent(inout) :: box
1537  type(mg_t), intent(in) :: mg
1538  integer, intent(in) :: ix !< Index of the stencil
1539  integer :: IJK, nc
1540  real(dp) :: idr2(2*NDIM), a0, a(2*NDIM), dr2(NDIM)
1541  integer :: n, m, idim, s_ix(NDIM), ix_dist
1542  real(dp) :: dd(2*NDIM)
1543  real(dp), allocatable :: all_distances(:, DTIMES(:))
1544  logical :: success
1545 
1546  nc = box%n_cell
1547  idr2(1:2*ndim:2) = 1/box%dr**2
1548  idr2(2:2*ndim:2) = idr2(1:2*ndim:2)
1549  dr2 = box%dr**2
1550 
1551  box%stencils(ix)%shape = af_stencil_357
1552  box%stencils(ix)%stype = stencil_variable
1553  ! A custom correction for cylindrical geometry could be more accurate. This
1554  ! would require the derivation of a discretization for cells in which both
1555  ! epsilon changes and a boundary is present.
1556  box%stencils(ix)%cylindrical_gradient = (box%coord_t == af_cyl)
1557  call af_stencil_allocate_coeff(box%stencils(ix), box%n_cell, use_f=.true.)
1558  allocate(all_distances(2*ndim, dtimes(nc)))
1559 
1560  box%stencils(ix)%f = 0.0_dp
1561  ! Distance 1 indicates no boundary
1562  all_distances = 1.0_dp
1563 
1564  ix_dist = af_stencil_index(box, mg_lsf_distance_key)
1565  if (ix_dist == af_stencil_none) error stop "No distances stored"
1566 
1567  ! Use sparse storage of boundary distances to update all_distances
1568  do n = 1, size(box%stencils(ix_dist)%sparse_ix, 2)
1569  s_ix = box%stencils(ix_dist)%sparse_ix(:, n)
1570  all_distances(:, dindex(s_ix)) = &
1571  box%stencils(ix_dist)%sparse_v(:, n)
1572  end do
1573 
1574  associate(cc => box%cc, n => mg%i_phi, i_eps => mg%i_eps)
1575  do kji_do(1, nc)
1576  dd = all_distances(:, ijk)
1577 
1578 #if NDIM == 1
1579  a0 = box%cc(i, i_eps)
1580  a(1:2) = box%cc(i-1:i+1:2, i_eps)
1581 #elif NDIM == 2
1582  a0 = box%cc(i, j, i_eps)
1583  a(1:2) = box%cc(i-1:i+1:2, j, i_eps)
1584  a(3:4) = box%cc(i, j-1:j+1:2, i_eps)
1585 #elif NDIM == 3
1586  a0 = box%cc(i, j, k, i_eps)
1587  a(1:2) = box%cc(i-1:i+1:2, j, k, i_eps)
1588  a(3:4) = box%cc(i, j-1:j+1:2, k, i_eps)
1589  a(5:6) = box%cc(i, j, k-1:k+1:2, i_eps)
1590 #endif
1591  ! Generalized Laplacian for neighbors at distance dd * dx
1592  do idim = 1, ndim
1593  box%stencils(ix)%v(1+2*idim-1, ijk) = 1 / &
1594  (0.5_dp * dr2(idim) * (dd(2*idim-1) + dd(2*idim)) * &
1595  dd(2*idim-1))
1596  box%stencils(ix)%v(1+2*idim, ijk) = 1 / &
1597  (0.5_dp * dr2(idim) * (dd(2*idim-1) + dd(2*idim)) * &
1598  dd(2*idim))
1599  end do
1600 
1601  ! Account for permittivity. If there is an electrode boundary, assume
1602  ! the permittivity is constant up to the boundary.
1603  where (dd(:) < 1.0_dp) a(:) = a0
1604 
1605  box%stencils(ix)%v(2:, ijk) = box%stencils(ix)%v(2:, ijk) * &
1606  2 * a0*a(:)/(a0 + a(:))
1607 
1608  box%stencils(ix)%v(1, ijk) = -sum(box%stencils(ix)%v(2:, ijk))
1609 
1610  ! Move internal boundaries to right-hand side
1611  do m = 1, 2 * ndim
1612  if (dd(m) < 1.0_dp) then
1613  box%stencils(ix)%f(ijk) = box%stencils(ix)%f(ijk) - &
1614  box%stencils(ix)%v(m+1, ijk)
1615  box%stencils(ix)%v(m+1, ijk) = 0.0_dp
1616  end if
1617  end do
1618  end do; close_do
1619  end associate
1620 
1621  call af_stencil_try_constant(box, ix, epsilon(1.0_dp), success)
1622 
1623  end subroutine mg_box_lpld_lsf_stencil
1624 
1625  !> Compute distance to boundary starting at point a going to point b, in
1626  !> the range from [0, 1], with 1 meaning there is no boundary
1627  function mg_lsf_dist_linear(a, b, mg) result(dist)
1628  real(dp), intent(in) :: a(ndim) !< Start point
1629  real(dp), intent(in) :: b(ndim) !< End point
1630  type(mg_t), intent(in) :: mg
1631  real(dp) :: dist, lsf_a, lsf_b
1632 
1633  lsf_a = mg%lsf(a)
1634  lsf_b = mg%lsf(b)
1635 
1636  if (lsf_a * lsf_b < 0) then
1637  ! There is a boundary between the points
1638  dist = lsf_a / (lsf_a - lsf_b)
1639  dist = max(dist, mg%lsf_min_rel_distance)
1640  else
1641  dist = 1.0_dp
1642  end if
1643  end function mg_lsf_dist_linear
1644 
1645  !> Find root of f in the interval [a, b]. If f(a) and f(b) have different
1646  !> signs, apply bisection directly. Else, first find the (assumed to be)
1647  !> unique local minimum/maximum to determine a bracket. Return relative
1648  !> location of root, or 1 if there is no root.
1649  function mg_lsf_dist_gss(a, b, mg) result(dist)
1650  real(dp), intent(in) :: a(ndim) !< Start point
1651  real(dp), intent(in) :: b(ndim) !< End point
1652  type(mg_t), intent(in) :: mg
1653  real(dp) :: bracket(ndim, 2), b_new(ndim)
1654  real(dp) :: dist, r_root(ndim), lsf_a, lsf_b
1655  integer, parameter :: max_iter = 100
1656 
1657  lsf_a = mg%lsf(a)
1658  lsf_b = mg%lsf(b)
1659  dist = 1.0_dp
1660 
1661  if (lsf_a * lsf_b <= 0) then
1662  r_root = bisection(mg%lsf, a, b, mg%lsf_tol, max_iter)
1663  else
1664  ! Determine bracket using Golden section search
1665  bracket = gss(mg%lsf, a, b, minimization=(lsf_a >= 0), &
1666  tol=mg%lsf_tol, find_bracket=.true.)
1667 
1668  ! Take one of the endpoints of the bracket
1669  if (mg%lsf(bracket(:, 1)) * lsf_a <= 0) then
1670  b_new = bracket(:, 1)
1671  else
1672  b_new = bracket(:, 2)
1673  end if
1674 
1675  if (mg%lsf(b_new) * lsf_a > 0) then
1676  return ! No root
1677  else
1678  r_root = bisection(mg%lsf, a, b_new, mg%lsf_tol, max_iter)
1679  end if
1680  end if
1681 
1682  dist = norm2(r_root - a)/norm2(b-a)
1683  dist = max(dist, mg%lsf_min_rel_distance)
1684  end function mg_lsf_dist_gss
1685 
1686  !> Simple bisection
1687  function bisection(f, in_a, in_b, tol, max_iter) result(c)
1688  procedure(mg_func_lsf) :: f
1689  real(dp), intent(in) :: in_a(ndim), in_b(ndim), tol
1690  integer, intent(in) :: max_iter
1691  real(dp) :: a(ndim), b(ndim), c(ndim), fc
1692  integer :: n
1693 
1694  a = in_a
1695  b = in_b
1696 
1697  do n = 1, max_iter
1698  c = 0.5 * (a + b)
1699  fc = f(c)
1700  if (0.5 * norm2(b-a) < tol .or. abs(fc) <= 0) exit
1701 
1702  if (fc * f(a) >= 0) then
1703  a = c
1704  else
1705  b = c
1706  end if
1707  end do
1708  end function bisection
1709 
1710  !> Golden-section search on a line between a and b. Given a function f with a
1711  !> single local minimum/maximum in the interval [a,b], gss returns a subset
1712  !> interval [c,d] that contains the minimum/maximum with d-c <= tol. Adapted
1713  !> from https://en.wikipedia.org/wiki/Golden-section_search
1714  function gss(f, in_a, in_b, minimization, tol, find_bracket) result(bracket)
1715  procedure(mg_func_lsf) :: f !< Function to minimize/maximize
1716  real(dp), intent(in) :: in_a(ndim) !< Start coordinate
1717  real(dp), intent(in) :: in_b(ndim) !< End coordinate
1718  !> Whether to perform minimization or maximization
1719  logical, intent(in) :: minimization
1720  real(dp), intent(in) :: tol !< Absolute tolerance
1721  logical, intent(in) :: find_bracket !< Whether to search for a bracket
1722  real(dp) :: bracket(ndim, 2)
1723  real(dp) :: a(ndim), b(ndim), c(ndim), d(ndim)
1724  real(dp) :: h(ndim), yc, yd, ya
1725  real(dp) :: invphi, invphi2
1726  integer :: n, k
1727 
1728  invphi = (sqrt(5.0_dp) - 1) / 2 ! 1 / phi
1729  invphi2 = (3 - sqrt(5.0_dp)) / 2 ! 1 / phi^2
1730 
1731  a = in_a
1732  b = in_b
1733  h = b - a
1734 
1735  if (norm2(h) <= tol) then
1736  bracket(:, 1) = a
1737  bracket(:, 2) = b
1738  return
1739  end if
1740 
1741  ! Required steps to achieve tolerance
1742  n = int(ceiling(log(tol / norm2(h)) / log(invphi)))
1743 
1744  c = a + invphi2 * h
1745  d = a + invphi * h
1746  ya = f(a) ! To search for bracket
1747  yc = f(c)
1748  yd = f(d)
1749 
1750  do k = 1, n-1
1751  if ((yc < yd) .eqv. minimization) then
1752  b = d
1753  d = c
1754  yd = yc
1755  h = invphi * h
1756  c = a + invphi2 * h
1757  yc = f(c)
1758  else
1759  a = c
1760  c = d
1761  yc = yd
1762  h = invphi * h
1763  d = a + invphi * h
1764  yd = f(d)
1765  end if
1766 
1767  ! Exit early if we are only searching for a bracket
1768  if (find_bracket .and. ya * yc <= 0 .and. ya * yd <= 0) exit
1769  end do
1770 
1771  if ((yc < yd) .eqv. minimization) then
1772  bracket(:, 1) = a
1773  bracket(:, 2) = d
1774  else
1775  bracket(:, 1) = c
1776  bracket(:, 2) = b
1777  end if
1778  end function gss
1779 
1780  !> Store the matrix stencil for each cell of the box. The order of the stencil
1781  !> is (i, j), (i-1, j), (i+1, j), (i, j-1), (i, j+1) (e.g., -4, 1, 1, 1, 1)
1782  subroutine mg_box_lsf_stencil(box, mg, ix)
1783  type(box_t), intent(inout) :: box
1784  type(mg_t), intent(in) :: mg
1785  integer, intent(in) :: ix !< Index of stencil
1786  integer :: IJK, n, nc, idim
1787  integer :: s_ix(NDIM), ix_dist
1788  real(dp) :: dd(2*NDIM), dr2(NDIM)
1789  real(dp), allocatable :: all_distances(:, DTIMES(:))
1790 #if NDIM == 2
1791  real(dp) :: tmp
1792 #endif
1793 
1794  nc = box%n_cell
1795  dr2 = box%dr**2
1796 
1797  ix_dist = af_stencil_index(box, mg_lsf_distance_key)
1798  if (ix_dist == af_stencil_none) error stop "No distances stored"
1799 
1800  ! Use stored distances to construct stencil
1801  box%stencils(ix)%shape = af_stencil_357
1802  box%stencils(ix)%stype = stencil_variable
1803  ! Perform a custom correction in cylindrical coordinates
1804  box%stencils(ix)%cylindrical_gradient = .false.
1805  call af_stencil_allocate_coeff(box%stencils(ix), box%n_cell, use_f=.true.)
1806  box%stencils(ix)%f = 0.0_dp
1807 
1808  allocate(all_distances(2*ndim, dtimes(nc)))
1809 
1810  ! Distance 1 indicates no boundary
1811  all_distances = 1.0_dp
1812 
1813  ! Use sparse storage of boundary distances to update all_distances
1814  do n = 1, size(box%stencils(ix_dist)%sparse_ix, 2)
1815  s_ix = box%stencils(ix_dist)%sparse_ix(:, n)
1816  all_distances(:, dindex(s_ix)) = &
1817  box%stencils(ix_dist)%sparse_v(:, n)
1818  end do
1819 
1820  do kji_do(1, nc)
1821  dd = all_distances(:, ijk)
1822 
1823  ! Generalized Laplacian for neighbors at distance dd * dx
1824  do idim = 1, ndim
1825  box%stencils(ix)%v(1+2*idim-1, ijk) = 1 / &
1826  (0.5_dp * dr2(idim) * (dd(2*idim-1) + dd(2*idim)) * &
1827  dd(2*idim-1))
1828  box%stencils(ix)%v(1+2*idim, ijk) = 1 / &
1829  (0.5_dp * dr2(idim) * (dd(2*idim-1) + dd(2*idim)) * &
1830  dd(2*idim))
1831  end do
1832 
1833 #if NDIM == 2
1834  if (box%coord_t == af_cyl) then
1835  ! Add correction for cylindrical coordinate system. This is a
1836  ! discretization of 1/r d/dr phi.
1837  tmp = 1/(box%dr(1) * (dd(1) + dd(2)) * af_cyl_radius_cc(box, i))
1838  box%stencils(ix)%v(2, ijk) = box%stencils(ix)%v(2, ijk) - tmp
1839  box%stencils(ix)%v(3, ijk) = box%stencils(ix)%v(3, ijk) + tmp
1840  end if
1841 #endif
1842  box%stencils(ix)%v(1, ijk) = -sum(box%stencils(ix)%v(2:, ijk))
1843 
1844  ! Move internal boundaries to right-hand side
1845  do n = 1, 2 * ndim
1846  if (dd(n) < 1.0_dp) then
1847  box%stencils(ix)%f(ijk) = box%stencils(ix)%f(ijk) - &
1848  box%stencils(ix)%v(n+1, ijk)
1849  box%stencils(ix)%v(n+1, ijk) = 0.0_dp
1850  end if
1851  end do
1852  end do; close_do
1853 
1854  end subroutine mg_box_lsf_stencil
1855 
1856  !> Compute the gradient of the potential and store in face-centered variables
1857  subroutine mg_compute_phi_gradient(tree, mg, i_fc, fac, i_norm)
1858  type(af_t), intent(inout) :: tree
1859  type(mg_t), intent(in) :: mg
1860  integer, intent(in) :: i_fc !< Face-centered indices
1861  real(dp), intent(in) :: fac !< Multiply with this factor
1862  !> If present, store norm in this cell-centered variable
1863  integer, intent(in), optional :: i_norm
1864  integer :: lvl, i, id
1865 
1866  !$omp parallel private(lvl, i, id)
1867  do lvl = 1, tree%highest_lvl
1868  !$omp do
1869  do i = 1, size(tree%lvls(lvl)%ids)
1870  id = tree%lvls(lvl)%ids(i)
1871  select case (iand(tree%boxes(id)%tag, mg%operator_mask))
1872  case (mg_normal_box, mg_ceps_box)
1873  call mg_box_lpl_gradient(tree, id, mg, i_fc, fac)
1874  case (mg_lsf_box, mg_ceps_box+mg_lsf_box, mg_veps_box+mg_lsf_box)
1875  ! @todo is this okay for the case mg_veps_box+mg_lsf_box?
1876  if (af_has_children(tree%boxes(id))) then
1877  !> @todo Solution on coarse grid can lead to large gradient due
1878  !> to inconsistencies with level set function
1879  call mg_box_lpl_gradient(tree, id, mg, i_fc, fac)
1880  else
1881  call mg_box_lpllsf_gradient(tree, id, mg, i_fc, fac)
1882  end if
1883  case (mg_veps_box)
1884  ! Should call surface_correct_field_fc afterwards
1885  call mg_box_lpl_gradient(tree, id, mg, i_fc, fac)
1886  case (af_init_tag)
1887  error stop "box tag not set"
1888  case default
1889  error stop "unknown box tag"
1890  end select
1891 
1892  if (present(i_norm)) then
1893  call mg_box_field_norm(tree, id, i_fc, i_norm)
1894  end if
1895  end do
1896  !$omp end do nowait
1897  end do
1898  !$omp end parallel
1899  end subroutine mg_compute_phi_gradient
1900 
1901  !> Compute the gradient of the potential
1902  subroutine mg_box_lpl_gradient(tree, id, mg, i_fc, fac)
1903  type(af_t), intent(inout) :: tree
1904  integer, intent(in) :: id
1905  type(mg_t), intent(in) :: mg
1906  integer, intent(in) :: i_fc !< Face-centered indices
1907  real(dp), intent(in) :: fac !< Multiply with this factor
1908  integer :: nc, i_phi, i_eps
1909  real(dp) :: inv_dr(ndim)
1910 
1911  associate(box => tree%boxes(id), cc => tree%boxes(id)%cc)
1912  nc = box%n_cell
1913  i_phi = mg%i_phi
1914  inv_dr = fac / box%dr
1915 
1916 #if NDIM == 1
1917  box%fc(1:nc+1, 1, i_fc) = inv_dr(1) * &
1918  (cc(1:nc+1, i_phi) - cc(0:nc, i_phi))
1919 #elif NDIM == 2
1920  box%fc(1:nc+1, 1:nc, 1, i_fc) = inv_dr(1) * &
1921  (cc(1:nc+1, 1:nc, i_phi) - cc(0:nc, 1:nc, i_phi))
1922  box%fc(1:nc, 1:nc+1, 2, i_fc) = inv_dr(2) * &
1923  (cc(1:nc, 1:nc+1, i_phi) - cc(1:nc, 0:nc, i_phi))
1924 #elif NDIM == 3
1925  box%fc(1:nc+1, 1:nc, 1:nc, 1, i_fc) = inv_dr(1) * &
1926  (cc(1:nc+1, 1:nc, 1:nc, i_phi) - &
1927  cc(0:nc, 1:nc, 1:nc, i_phi))
1928  box%fc(1:nc, 1:nc+1, 1:nc, 2, i_fc) = inv_dr(2) * &
1929  (cc(1:nc, 1:nc+1, 1:nc, i_phi) - &
1930  cc(1:nc, 0:nc, 1:nc, i_phi))
1931  box%fc(1:nc, 1:nc, 1:nc+1, 3, i_fc) = inv_dr(3) * &
1932  (cc(1:nc, 1:nc, 1:nc+1, i_phi) - &
1933  cc(1:nc, 1:nc, 0:nc, i_phi))
1934 #endif
1935 
1936  if (iand(box%tag, mg%operator_mask) == mg_veps_box) then
1937  ! Compute fields at the boundaries of the box, where eps can change
1938  i_eps = mg%i_eps
1939 
1940 #if NDIM == 1
1941  box%fc(1, 1, i_fc) = 2 * inv_dr(1) * &
1942  (cc(1, i_phi) - cc(0, i_phi)) * &
1943  cc(0, i_eps) / &
1944  (cc(1, i_eps) + cc(0, i_eps))
1945  box%fc(nc+1, 1, i_fc) = 2 * inv_dr(1) * &
1946  (cc(nc+1, i_phi) - cc(nc, i_phi)) * &
1947  cc(nc+1, i_eps) / &
1948  (cc(nc+1, i_eps) + cc(nc, i_eps))
1949 #elif NDIM == 2
1950  box%fc(1, 1:nc, 1, i_fc) = 2 * inv_dr(1) * &
1951  (cc(1, 1:nc, i_phi) - cc(0, 1:nc, i_phi)) * &
1952  cc(0, 1:nc, i_eps) / &
1953  (cc(1, 1:nc, i_eps) + cc(0, 1:nc, i_eps))
1954  box%fc(nc+1, 1:nc, 1, i_fc) = 2 * inv_dr(1) * &
1955  (cc(nc+1, 1:nc, i_phi) - cc(nc, 1:nc, i_phi)) * &
1956  cc(nc+1, 1:nc, i_eps) / &
1957  (cc(nc+1, 1:nc, i_eps) + cc(nc, 1:nc, i_eps))
1958  box%fc(1:nc, 1, 2, i_fc) = 2 * inv_dr(2) * &
1959  (cc(1:nc, 1, i_phi) - cc(1:nc, 0, i_phi)) * &
1960  cc(1:nc, 0, i_eps) / &
1961  (cc(1:nc, 1, i_eps) + cc(1:nc, 0, i_eps))
1962  box%fc(1:nc, nc+1, 2, i_fc) = 2 * inv_dr(2) * &
1963  (cc(1:nc, nc+1, i_phi) - cc(1:nc, nc, i_phi)) * &
1964  cc(1:nc, nc+1, i_eps) / &
1965  (cc(1:nc, nc+1, i_eps) + cc(1:nc, nc, i_eps))
1966 #elif NDIM == 3
1967  box%fc(1, 1:nc, 1:nc, 1, i_fc) = 2 * inv_dr(1) * &
1968  (cc(1, 1:nc, 1:nc, i_phi) - cc(0, 1:nc, 1:nc, i_phi)) * &
1969  cc(0, 1:nc, 1:nc, i_eps) / &
1970  (cc(1, 1:nc, 1:nc, i_eps) + cc(0, 1:nc, 1:nc, i_eps))
1971  box%fc(nc+1, 1:nc, 1:nc, 1, i_fc) = 2 * inv_dr(1) * &
1972  (cc(nc+1, 1:nc, 1:nc, i_phi) - cc(nc, 1:nc, 1:nc, i_phi)) * &
1973  cc(nc+1, 1:nc, 1:nc, i_eps) / &
1974  (cc(nc+1, 1:nc, 1:nc, i_eps) + cc(nc, 1:nc, 1:nc, i_eps))
1975  box%fc(1:nc, 1, 1:nc, 2, i_fc) = 2 * inv_dr(2) * &
1976  (cc(1:nc, 1, 1:nc, i_phi) - cc(1:nc, 0, 1:nc, i_phi)) * &
1977  cc(1:nc, 0, 1:nc, i_eps) / &
1978  (cc(1:nc, 1, 1:nc, i_eps) + cc(1:nc, 0, 1:nc, i_eps))
1979  box%fc(1:nc, nc+1, 1:nc, 2, i_fc) = 2 * inv_dr(2) * &
1980  (cc(1:nc, nc+1, 1:nc, i_phi) - cc(1:nc, nc, 1:nc, i_phi)) * &
1981  cc(1:nc, nc+1, 1:nc, i_eps) / &
1982  (cc(1:nc, nc+1, 1:nc, i_eps) + cc(1:nc, nc, 1:nc, i_eps))
1983  box%fc(1:nc, 1:nc, 1, 3, i_fc) = 2 * inv_dr(3) * &
1984  (cc(1:nc, 1:nc, 1, i_phi) - cc(1:nc, 1:nc, 0, i_phi)) * &
1985  cc(1:nc, 1:nc, 0, i_eps) / &
1986  (cc(1:nc, 1:nc, 1, i_eps) + cc(1:nc, 1:nc, 0, i_eps))
1987  box%fc(1:nc, 1:nc, nc+1, 3, i_fc) = 2 * inv_dr(3) * &
1988  (cc(1:nc, 1:nc, nc+1, i_phi) - cc(1:nc, 1:nc, nc, i_phi)) * &
1989  cc(1:nc, 1:nc, nc+1, i_eps) / &
1990  (cc(1:nc, 1:nc, nc+1, i_eps) + cc(1:nc, 1:nc, nc, i_eps))
1991 #endif
1992  end if
1993  end associate
1994  end subroutine mg_box_lpl_gradient
1995 
1996  !> Compute norm of face-centered variable
1997  subroutine mg_compute_field_norm(tree, i_fc, i_norm)
1998  type(af_t), intent(inout) :: tree
1999  integer, intent(in) :: i_fc !< Index of face-centered variable
2000  integer, intent(in) :: i_norm !< Index of cell-centered variable
2001  integer :: lvl, i, id
2002 
2003  !$omp parallel private(lvl, i, id)
2004  do lvl = 1, tree%highest_lvl
2005  !$omp do
2006  do i = 1, size(tree%lvls(lvl)%ids)
2007  id = tree%lvls(lvl)%ids(i)
2008  call mg_box_field_norm(tree, id, i_fc, i_norm)
2009  end do
2010  !$omp end do nowait
2011  end do
2012  !$omp end parallel
2013  end subroutine mg_compute_field_norm
2014 
2015  subroutine mg_box_field_norm(tree, id, i_fc, i_norm)
2016  type(af_t), intent(inout) :: tree
2017  integer, intent(in) :: id
2018  integer, intent(in) :: i_fc !< Face-centered indices
2019  !> Store norm in this cell-centered variable
2020  integer, intent(in) :: i_norm
2021  integer :: nc
2022 
2023  associate(box => tree%boxes(id))
2024  nc = box%n_cell
2025 #if NDIM == 1
2026  box%cc(1:nc, i_norm) = 0.5_dp * sqrt(&
2027  (box%fc(1:nc, 1, i_fc) + &
2028  box%fc(2:nc+1, 1, i_fc))**2)
2029 #elif NDIM == 2
2030  box%cc(1:nc, 1:nc, i_norm) = 0.5_dp * sqrt(&
2031  (box%fc(1:nc, 1:nc, 1, i_fc) + &
2032  box%fc(2:nc+1, 1:nc, 1, i_fc))**2 + &
2033  (box%fc(1:nc, 1:nc, 2, i_fc) + &
2034  box%fc(1:nc, 2:nc+1, 2, i_fc))**2)
2035 #elif NDIM == 3
2036  box%cc(1:nc, 1:nc, 1:nc, i_norm) = 0.5_dp * sqrt(&
2037  (box%fc(1:nc, 1:nc, 1:nc, 1, i_fc) + &
2038  box%fc(2:nc+1, 1:nc, 1:nc, 1, i_fc))**2 + &
2039  (box%fc(1:nc, 1:nc, 1:nc, 2, i_fc) + &
2040  box%fc(1:nc, 2:nc+1, 1:nc, 2, i_fc))**2 + &
2041  (box%fc(1:nc, 1:nc, 1:nc, 3, i_fc) + &
2042  box%fc(1:nc, 1:nc, 2:nc+1, 3, i_fc))**2)
2043 #endif
2044  end associate
2045  end subroutine mg_box_field_norm
2046 
2047  !> Compute the gradient of the potential with a level set function and store
2048  !> in face-centered variables. The gradients are computed from the positive
2049  !> side of the level set function.
2050  subroutine mg_box_lpllsf_gradient(tree, id, mg, i_fc, fac)
2051  type(af_t), intent(inout) :: tree
2052  integer, intent(in) :: id
2053  type(mg_t), intent(in) :: mg
2054  integer, intent(in) :: i_fc !< Face-centered indices
2055  real(dp), intent(in) :: fac !< Multiply with this factor
2056  integer :: IJK
2057  integer :: n, nc, i_phi, ix_dist
2058  real(dp) :: inv_dr(NDIM), dd(2*NDIM)
2059  real(dp) :: bc(DTIMES(tree%n_cell))
2060 
2061  ! Compute regular values, correct part of them below
2062  call mg_box_lpl_gradient(tree, id, mg, i_fc, fac)
2063 
2064  ix_dist = af_stencil_index(tree%boxes(id), mg_lsf_distance_key)
2065  if (ix_dist == af_stencil_none) error stop "No distances stored"
2066 
2067  associate(box => tree%boxes(id), cc => tree%boxes(id)%cc)
2068  nc = box%n_cell
2069  i_phi = mg%i_phi
2070  inv_dr = fac / box%dr
2071  bc = mg_lsf_boundary_value(box, mg)
2072 
2073  ! Use sparse storage of boundary distances
2074  do n = 1, size(box%stencils(ix_dist)%sparse_ix, 2)
2075  dd = box%stencils(ix_dist)%sparse_v(:, n)
2076 
2077 #if NDIM == 1
2078  i = box%stencils(ix_dist)%sparse_ix(1, n)
2079 
2080  if (dd(1) < 1 .and. cc(ijk, mg%i_lsf) >= 0) then
2081  box%fc(i, 1, i_fc) = inv_dr(1) * &
2082  (cc(i, i_phi) - bc(ijk)) / dd(1)
2083  end if
2084  if (dd(2) < 1 .and. cc(ijk, mg%i_lsf) >= 0) then
2085  box%fc(i+1, 1, i_fc) = inv_dr(1) * &
2086  (bc(ijk) - cc(i, i_phi)) / dd(2)
2087  end if
2088 #elif NDIM == 2
2089  i = box%stencils(ix_dist)%sparse_ix(1, n)
2090  j = box%stencils(ix_dist)%sparse_ix(2, n)
2091 
2092  if (dd(1) < 1 .and. cc(ijk, mg%i_lsf) >= 0) then
2093  box%fc(i, j, 1, i_fc) = inv_dr(1) * &
2094  (cc(i, j, i_phi) - bc(ijk)) / dd(1)
2095  end if
2096  if (dd(2) < 1 .and. cc(ijk, mg%i_lsf) >= 0) then
2097  box%fc(i+1, j, 1, i_fc) = inv_dr(1) * &
2098  (bc(ijk) - cc(i, j, i_phi)) / dd(2)
2099  end if
2100  if (dd(3) < 1 .and. cc(ijk, mg%i_lsf) >= 0) then
2101  box%fc(i, j, 2, i_fc) = inv_dr(2) * &
2102  (cc(i, j, i_phi) - bc(ijk)) / dd(3)
2103  end if
2104  if (dd(4) < 1 .and. cc(ijk, mg%i_lsf) >= 0) then
2105  box%fc(i, j+1, 2, i_fc) = inv_dr(2) * &
2106  (bc(ijk) - cc(i, j, i_phi)) / dd(4)
2107  end if
2108 #elif NDIM == 3
2109  i = box%stencils(ix_dist)%sparse_ix(1, n)
2110  j = box%stencils(ix_dist)%sparse_ix(2, n)
2111  k = box%stencils(ix_dist)%sparse_ix(3, n)
2112 
2113  if (dd(1) < 1 .and. cc(ijk, mg%i_lsf) >= 0) then
2114  box%fc(i, j, k, 1, i_fc) = inv_dr(1) * &
2115  (cc(ijk, i_phi) - bc(ijk)) / dd(1)
2116  end if
2117  if (dd(2) < 1 .and. cc(ijk, mg%i_lsf) >= 0) then
2118  box%fc(i+1, j, k, 1, i_fc) = inv_dr(1) * &
2119  (bc(ijk) - cc(ijk, i_phi)) / dd(2)
2120  end if
2121  if (dd(3) < 1 .and. cc(ijk, mg%i_lsf) >= 0) then
2122  box%fc(i, j, k, 2, i_fc) = inv_dr(2) * &
2123  (cc(ijk, i_phi) - bc(ijk)) / dd(3)
2124  end if
2125  if (dd(4) < 1 .and. cc(ijk, mg%i_lsf) >= 0) then
2126  box%fc(i, j+1, k, 2, i_fc) = inv_dr(2) * &
2127  (bc(ijk) - cc(ijk, i_phi)) / dd(4)
2128  end if
2129  if (dd(5) < 1 .and. cc(ijk, mg%i_lsf) >= 0) then
2130  box%fc(i, j, k, 3, i_fc) = inv_dr(3) * &
2131  (cc(ijk, i_phi) - bc(ijk)) / dd(5)
2132  end if
2133  if (dd(6) < 1 .and. cc(ijk, mg%i_lsf) >= 0) then
2134  box%fc(i, j, k+1, 3, i_fc) = inv_dr(3) * &
2135  (bc(ijk) - cc(ijk, i_phi)) / dd(6)
2136  end if
2137 #endif
2138  end do
2139  end associate
2140  end subroutine mg_box_lpllsf_gradient
2141 
2142  !> This method checks whether the level set function is properly defined on
2143  !> the coarse grid
2144  subroutine check_coarse_representation_lsf(tree, mg)
2145  type(af_t), intent(in) :: tree
2146  type(mg_t), intent(in) :: mg
2147  integer :: i, id, ix
2148 
2149  do i = 1, size(tree%lvls(1)%ids)
2150  id = tree%lvls(1)%ids(i)
2151  ix = af_stencil_index(tree%boxes(id), mg_lsf_distance_key)
2152  if (ix > af_stencil_none) exit
2153  end do
2154 
2155  if (i == size(tree%lvls(1)%ids)+1) then
2156  print *, "No roots found for level set function on coarse grid"
2157  print *, "you should probably use a finer coarse grid"
2158  error stop "level set function not resolved on coarse grid"
2159  end if
2160 
2161  end subroutine check_coarse_representation_lsf
2162 
2163  !> Get amplitude of numerical gradient of level set function
2164  function numerical_gradient(f, r) result(gradient)
2165  procedure(mg_func_lsf) :: f
2166  real(dp), intent(in) :: r(ndim)
2167  real(dp), parameter :: sqrteps = sqrt(epsilon(1.0_dp))
2168  real(dp), parameter :: min_stepsize = epsilon(1.0_dp)
2169  real(dp) :: r_eval(ndim), gradient(ndim)
2170  real(dp) :: stepsize(ndim), flo, fhi
2171  integer :: idim
2172 
2173  stepsize = max(min_stepsize, sqrteps * abs(r))
2174  r_eval = r
2175 
2176  do idim = 1, ndim
2177  ! Sample function at (r - step_idim) and (r + step_idim)
2178  r_eval(idim) = r(idim) - stepsize(idim)
2179  flo = f(r_eval)
2180 
2181  r_eval(idim) = r(idim) + stepsize(idim)
2182  fhi = f(r_eval)
2183 
2184  ! Use central difference scheme
2185  gradient(idim) = (fhi - flo)/(2 * stepsize(idim))
2186 
2187  ! Reset to original coordinate
2188  r_eval(idim) = r(idim)
2189  end do
2190  end function numerical_gradient
2191 
2192 end module m_af_multigrid
This module contains the core routines of Afivo, namely those that deal with initializing and changin...
Definition: m_af_core.f90:3
This module contains routines related to the filling of ghost cells. Note that corner ghost cells are...
This module contains the geometric multigrid routines that come with Afivo.
This module contains routines for restriction: going from fine to coarse variables.
This module contains functionality for dealing with numerical stencils.
Definition: m_af_stencil.f90:2
This module contains the basic types and constants that are used in the NDIM-dimensional version of A...
Definition: m_af_types.f90:3
This module contains all kinds of different 'helper' routines for Afivo. If the number of routines fo...
Definition: m_af_utils.f90:4
Module to solve elliptic PDEs on the coarse grid. This module contains an interface to Hypre,...
Type which stores all the boxes and levels, as well as some information about the number of boxes,...
Definition: m_af_types.f90:326
The basic building block of afivo: a box with cell-centered and face centered data,...
Definition: m_af_types.f90:286
Type to store multigrid options in.
Definition: m_af_types.f90:572