Afivo  0.3
m_a2_multigrid.f90
1 
4  use m_a2_types
5 
6  implicit none
7  private
8 
9  ! The mg module supports different multigrid operators, and uses these tags to
10  ! identify boxes / operators
11  integer, parameter, public :: mg_normal_box = 1
12  integer, parameter, public :: mg_lsf_box = 2
13  integer, parameter, public :: mg_ceps_box = 3
14  integer, parameter, public :: mg_veps_box = 4
15 
16  ! Labels for the different steps of a multigrid cycle
17  integer, parameter :: mg_cycle_down = 1
18  integer, parameter :: mg_cycle_base = 2
19  integer, parameter :: mg_cycle_up = 3
20 
22  type, public :: mg2_t
23  integer :: i_phi = -1
24  integer :: i_rhs = -1
25  integer :: i_tmp = -1
26 
27  integer :: i_eps = -1
28  integer :: i_lsf = -1
29  integer :: i_bval = -1
30 
31  integer :: n_cycle_down = -1
32  integer :: n_cycle_up = -1
33  integer :: n_cycle_base = -1
34 
35  logical :: initialized = .false.
36  logical :: use_corners = .false.
37  logical :: subtract_mean = .false.
38 
40  procedure(a2_subr_bc), pointer, nopass :: sides_bc => null()
41 
43  procedure(a2_subr_rb), pointer, nopass :: sides_rb => null()
44 
46  procedure(mg2_box_op), pointer, nopass :: box_op => null()
47 
49  procedure(mg2_box_gsrb), pointer, nopass :: box_gsrb => null()
50 
52  procedure(mg2_box_corr), pointer, nopass :: box_corr => null()
53 
55  procedure(mg2_box_rstr), pointer, nopass :: box_rstr => null()
56  end type mg2_t
57 
58  abstract interface
59 
60  subroutine mg2_box_op(box, i_out, mg)
61  import
62  type(box2_t), intent(inout) :: box
63  type(mg2_t), intent(in) :: mg
64  integer, intent(in) :: i_out
65  end subroutine mg2_box_op
66 
68  subroutine mg2_box_gsrb(box, redblack_cntr, mg)
69  import
70  type(box2_t), intent(inout) :: box
71  type(mg2_t), intent(in) :: mg
72  integer, intent(in) :: redblack_cntr
73  end subroutine mg2_box_gsrb
74 
75  subroutine mg2_box_corr(box_p, box_c, mg)
76  import
77  type(box2_t), intent(inout) :: box_c
78  type(box2_t), intent(in) :: box_p
79  type(mg2_t), intent(in) :: mg
80  end subroutine mg2_box_corr
81 
82  subroutine mg2_box_rstr(box_c, box_p, iv, mg)
83  import
84  type(box2_t), intent(in) :: box_c
85  type(box2_t), intent(inout) :: box_p
86  integer, intent(in) :: iv
87  type(mg2_t), intent(in) :: mg
88  end subroutine mg2_box_rstr
89  end interface
90 
91  public :: mg2_init_mg
92  public :: mg2_fas_fmg
93  public :: mg2_fas_vcycle
94  public :: mg2_box_op
95  public :: mg2_box_gsrb
96  public :: mg2_box_corr
97  public :: mg2_box_rstr
98 
99  ! Automatic selection of operators
100  public :: mg2_set_box_tag
101  public :: mg2_auto_op
102  public :: mg2_auto_gsrb
103  public :: mg2_auto_corr
104  public :: mg2_auto_rstr
105 
106  ! Methods for normal Laplacian
107  public :: mg2_box_lpl
108  public :: mg2_box_gsrb_lpl
109  public :: mg2_box_corr_lpl
110  public :: mg2_box_rstr_lpl
111  public :: mg2_sides_rb
112 
113  ! Methods for Laplacian with jump in coefficient between boxes
114  public :: mg2_box_lpld
115  public :: mg2_box_gsrb_lpld
116  public :: mg2_box_corr_lpld
117 
118  ! Methods for normal Laplacian with internal boundary conditions (LSF)
119  public :: mg2_box_lpllsf
120  public :: mg2_box_gsrb_lpllsf
121  public :: mg2_box_corr_lpllsf
122  public :: mg2_box_rstr_lpllsf
123 
124  public :: mg2_box_clpl
125  public :: mg2_box_gsrb_clpl
126  public :: mg2_box_clpld
127  public :: mg2_box_gsrb_clpld
128 
129 contains
130 
132  subroutine mg2_init_mg(mg)
133  type(mg2_t), intent(inout) :: mg
134 
135  if (mg%i_phi < 0) stop "mg2_init_mg: i_phi not set"
136  if (mg%i_tmp < 0) stop "mg2_init_mg: i_tmp not set"
137  if (mg%i_rhs < 0) stop "mg2_init_mg: i_rhs not set"
138  if (mg%i_lsf * mg%i_bval < 0) &
139  stop "mg2_init_mg: you have to set both i_lsf and i_bval"
140 
141  if (.not. associated(mg%sides_bc)) stop "mg2_init_mg: sides_bc not set"
142 
143  ! Check whether these are set, otherwise use default
144  if (mg%n_cycle_down < 0) mg%n_cycle_down = 2
145  if (mg%n_cycle_up < 0) mg%n_cycle_up = 2
146  if (mg%n_cycle_base < 0) mg%n_cycle_base = 4
147 
148  ! Check whether methods are set, otherwise use default (for laplacian)
149  if (.not. associated(mg%sides_rb)) mg%sides_rb => mg2_sides_rb
150  if (.not. associated(mg%box_op)) mg%box_op => mg2_box_lpl
151  if (.not. associated(mg%box_gsrb)) mg%box_gsrb => mg2_box_gsrb_lpl
152  if (.not. associated(mg%box_corr)) mg%box_corr => mg2_box_corr_lpl
153  if (.not. associated(mg%box_rstr)) mg%box_rstr => mg2_box_rstr_lpl
154 
155  mg%initialized = .true.
156  end subroutine mg2_init_mg
157 
158  subroutine check_mg(mg)
159  type(mg2_t), intent(in) :: mg
160  if (.not. mg%initialized) stop "check_mg: you haven't called mg2_init_mg"
161  end subroutine check_mg
162 
166  subroutine mg2_fas_fmg(tree, mg, set_residual, have_guess)
167  use m_a2_ghostcell, only: a2_gc_ids
168  use m_a2_utils, only: a2_boxes_copy_cc
169  type(a2_t), intent(inout) :: tree
170  type(mg2_t), intent(in) :: mg
171  logical, intent(in) :: set_residual
172  logical, intent(in) :: have_guess
173  integer :: lvl, min_lvl
174 
175  call check_mg(mg) ! Check whether mg options are set
176 
177  min_lvl = lbound(tree%lvls, 1)
178 
179  if (have_guess) then
180  do lvl = tree%highest_lvl, min_lvl+1, -1
181  ! Set rhs on coarse grid and restrict phi
182  call set_coarse_phi_rhs(tree, lvl, mg)
183  end do
184  else
185  call init_phi_rhs(tree, mg)
186  end if
187 
188  do lvl = min_lvl, tree%highest_lvl
189  ! Store phi_old in tmp
190  call a2_boxes_copy_cc(tree%boxes, tree%lvls(lvl)%ids, &
191  mg%i_phi, mg%i_tmp)
192 
193  if (lvl > min_lvl) then
194  ! Correct solution at this lvl using lvl-1 data
195  ! phi = phi + prolong(phi_coarse - phi_old_coarse)
196  call correct_children(tree%boxes, tree%lvls(lvl-1)%parents, mg)
197 
198  ! Update ghost cells
199  call a2_gc_ids(tree, tree%lvls(lvl)%ids, mg%i_phi, &
200  mg%sides_rb, mg%sides_bc)
201  end if
202 
203  ! Perform V-cycle, only set residual on last iteration
204  call mg2_fas_vcycle(tree, mg, &
205  set_residual .and. lvl == tree%highest_lvl, lvl)
206  end do
207  end subroutine mg2_fas_fmg
208 
212  subroutine mg2_fas_vcycle(tree, mg, set_residual, highest_lvl)
213  use m_a2_ghostcell, only: a2_gc_ids
214  use m_a2_utils, only: a2_tree_sum_cc
215  type(a2_t), intent(inout) :: tree
216  type(mg2_t), intent(in) :: mg
217  logical, intent(in) :: set_residual
218  integer, intent(in), optional :: highest_lvl
219  integer :: lvl, min_lvl, i, id, max_lvl
220  real(dp) :: sum_phi, mean_phi
221 
222  call check_mg(mg) ! Check whether mg options are set
223  min_lvl = lbound(tree%lvls, 1)
224  max_lvl = tree%highest_lvl
225  if (present(highest_lvl)) max_lvl = highest_lvl
226 
227  do lvl = max_lvl, min_lvl+1, -1
228  ! Downwards relaxation
229  call gsrb_boxes(tree, tree%lvls(lvl)%ids, mg, mg_cycle_down)
230 
231  ! Set rhs on coarse grid, restrict phi, and copy i_phi to i_tmp for the
232  ! correction later
233  call update_coarse(tree, lvl, mg)
234  end do
235 
236  lvl = min_lvl
237  call gsrb_boxes(tree, tree%lvls(lvl)%ids, mg, mg_cycle_base)
238 
239  ! Do the upwards part of the v-cycle in the tree
240  do lvl = min_lvl+1, max_lvl
241  ! Correct solution at this lvl using lvl-1 data
242  ! phi = phi + prolong(phi_coarse - phi_old_coarse)
243  call correct_children(tree%boxes, tree%lvls(lvl-1)%parents, mg)
244 
245  ! Have to fill ghost cells after correction
246  call a2_gc_ids(tree, tree%lvls(lvl)%ids, mg%i_phi, &
247  mg%sides_rb, mg%sides_bc)
248 
249  ! Upwards relaxation
250  call gsrb_boxes(tree, tree%lvls(lvl)%ids, mg, mg_cycle_up)
251  end do
252 
253  if (set_residual) then
254  !$omp parallel private(lvl, i, id)
255  do lvl = min_lvl, max_lvl
256  !$omp do
257  do i = 1, size(tree%lvls(lvl)%ids)
258  id = tree%lvls(lvl)%ids(i)
259  call residual_box(tree%boxes(id), mg)
260  end do
261  !$omp end do nowait
262  end do
263  !$omp end parallel
264  end if
265 
266  ! Subtract the mean of phi, for example when doing a fully periodic
267  ! simulation. Note that the integrated r.h.s. term should also be zero then.
268  if (mg%subtract_mean) then
269  call a2_tree_sum_cc(tree, mg%i_phi, sum_phi)
270  mean_phi = sum_phi / a2_total_volume(tree)
271  !$omp parallel private(lvl, i, id)
272  do lvl = min_lvl, max_lvl
273  !$omp do
274  do i = 1, size(tree%lvls(lvl)%ids)
275  id = tree%lvls(lvl)%ids(i)
276  tree%boxes(id)%cc(:, :, mg%i_phi) = &
277  tree%boxes(id)%cc(:, :, mg%i_phi) - mean_phi
278  end do
279  !$omp end do nowait
280  end do
281  !$omp end parallel
282  end if
283 
284  end subroutine mg2_fas_vcycle
285 
287  subroutine mg2_sides_rb(boxes, id, nb, iv)
288  use m_a2_ghostcell, only: a2_gc_prolong_copy
289  type(box2_t), intent(inout) :: boxes(:)
290  integer, intent(in) :: id
291  integer, intent(in) :: nb
292  integer, intent(in) :: iv
293  integer :: nc, ix, dix, i, di, j, dj, co(2)
294  integer :: hnc, p_id, p_nb_id
295  real(dp) :: grad(2-1)
296  real(dp) :: tmp(0:boxes(id)%n_cell/2+1)
297  real(dp) :: gc(boxes(id)%n_cell)
298 
299  nc = boxes(id)%n_cell
300  hnc = nc/2
301 
302  p_id = boxes(id)%parent
303  p_nb_id = boxes(p_id)%neighbors(nb)
304  co = a2_get_child_offset(boxes(id))
305 
306  associate(box => boxes(p_nb_id))
307  ! First fill a temporary array with data next to the fine grid
308  select case (nb)
309  case (a2_neighb_lowx)
310  tmp = box%cc(nc, co(2):co(2)+hnc+1, iv)
311  case (a2_neighb_highx)
312  tmp = box%cc(1, co(2):co(2)+hnc+1, iv)
313  case (a2_neighb_lowy)
314  tmp = box%cc(co(1):co(1)+hnc+1, nc, iv)
315  case (a2_neighb_highy)
316  tmp = box%cc(co(1):co(1)+hnc+1, 1, iv)
317  end select
318  end associate
319 
320  ! Now interpolate the coarse grid data to obtain values 'straight' next to
321  ! the fine grid points
322  do i = 1, hnc
323  grad(1) = 0.125_dp * (tmp(i+1) - tmp(i-1))
324  gc(2*i-1) = tmp(i) - grad(1)
325  gc(2*i) = tmp(i) + grad(1)
326  end do
327 
328  if (a2_neighb_low(nb)) then
329  ix = 1
330  dix = 1
331  else
332  ix = nc
333  dix = -1
334  end if
335 
336  select case (a2_neighb_dim(nb))
337  case (1)
338  i = ix
339  di = dix
340  do j = 1, nc
341  dj = -1 + 2 * iand(j, 1)
342  boxes(id)%cc(i-di, j, iv) = 0.5_dp * gc(j) &
343  + 0.75_dp * boxes(id)%cc(i, j, iv) &
344  - 0.25_dp * boxes(id)%cc(i+di, j, iv)
345  end do
346  case (2)
347  j = ix
348  dj = dix
349  do i = 1, nc
350  di = -1 + 2 * iand(i, 1)
351  boxes(id)%cc(i, j-dj, iv) = 0.5_dp * gc(i) &
352  + 0.75_dp * boxes(id)%cc(i, j, iv) &
353  - 0.25_dp * boxes(id)%cc(i, j+dj, iv)
354  end do
355  end select
356 
357  end subroutine mg2_sides_rb
358 
364  subroutine mg2_sides_rb_old(boxes, id, nb, iv)
365  use m_a2_ghostcell, only: a2_gc_prolong_copy
366  type(box2_t), intent(inout) :: boxes(:)
367  integer, intent(in) :: id
368  integer, intent(in) :: nb
369  integer, intent(in) :: iv
370  integer :: nc, ix, dix, i, di, j, dj
371 
372  nc = boxes(id)%n_cell
373 
374  if (a2_neighb_low(nb)) then
375  ix = 1
376  dix = 1
377  else
378  ix = nc
379  dix = -1
380  end if
381 
382  call a2_gc_prolong_copy(boxes, id, nb, iv)
383 
384  select case (a2_neighb_dim(nb))
385  case (1)
386  i = ix
387  di = dix
388  do j = 1, nc
389  dj = -1 + 2 * iand(j, 1)
390 
391  ! Bilinear extrapolation (using 4 points)
392  boxes(id)%cc(i-di, j, iv) = 0.5_dp * boxes(id)%cc(i-di, j, iv) + &
393  1.125_dp * boxes(id)%cc(i, j, iv) - 0.375_dp * &
394  (boxes(id)%cc(i+di, j, iv) + boxes(id)%cc(i, j+dj, iv)) &
395  + 0.125_dp * boxes(id)%cc(i+di, j+dj, iv)
396 
397  ! Extrapolation using 3 points
398  ! boxes(id)%cc(i-di, j, iv) = 0.5_dp * boxes(id)%cc(i-di, j, iv) + &
399  ! boxes(id)%cc(i, j, iv) - 0.25_dp * &
400  ! (boxes(id)%cc(i+di, j, iv) + boxes(id)%cc(i, j+dj, iv))
401 
402  ! Extrapolation using 2 points
403  ! boxes(id)%cc(i-di, j, iv) = 0.5_dp * boxes(id)%cc(i-di, j, iv) + &
404  ! 0.75_dp * boxes(id)%cc(i, j, iv) - 0.25_dp * &
405  ! boxes(id)%cc(i+di, j+dj, iv)
406  end do
407  case (2)
408  j = ix
409  dj = dix
410  do i = 1, nc
411  di = -1 + 2 * iand(i, 1)
412 
413  ! Bilinear extrapolation (using 4 points)
414  boxes(id)%cc(i, j-dj, iv) = 0.5_dp * boxes(id)%cc(i, j-dj, iv) + &
415  1.125_dp * boxes(id)%cc(i, j, iv) - 0.375_dp * &
416  (boxes(id)%cc(i+di, j, iv) + boxes(id)%cc(i, j+dj, iv)) &
417  + 0.125_dp * boxes(id)%cc(i+di, j+dj, iv)
418 
419  ! Extrapolation using 2 points
420  ! boxes(id)%cc(i, j-dj, iv) = 0.5_dp * boxes(id)%cc(i, j-dj, iv) + &
421  ! 0.75_dp * boxes(id)%cc(i, j, iv) - 0.25_dp * &
422  ! boxes(id)%cc(i+di, j+dj, iv)
423  end do
424  end select
425 
426  end subroutine mg2_sides_rb_old
427 
428  ! Sets phi = phi + prolong(phi_coarse - phi_old_coarse)
429  subroutine correct_children(boxes, ids, mg)
430  type(box2_t), intent(inout) :: boxes(:)
431  integer, intent(in) :: ids(:)
432  type(mg2_t), intent(in) :: mg
433  integer :: i, id, nc, i_c, c_id
434 
435  !$omp parallel do private(id, nc, i_c, c_id)
436  do i = 1, size(ids)
437  id = ids(i)
438  nc = boxes(id)%n_cell
439 
440  ! Store the correction in i_tmp
441  boxes(id)%cc(:, :, mg%i_tmp) = boxes(id)%cc(:, :, mg%i_phi) - &
442  boxes(id)%cc(:, :, mg%i_tmp)
443 
444  do i_c = 1, a2_num_children
445  c_id = boxes(id)%children(i_c)
446  if (c_id == af_no_box) cycle
447  call mg%box_corr(boxes(id), boxes(c_id), mg)
448  end do
449  end do
450  !$omp end parallel do
451  end subroutine correct_children
452 
453  subroutine gsrb_boxes(tree, ids, mg, type_cycle)
454  use m_a2_ghostcell, only: a2_gc_box
455  type(a2_t), intent(inout) :: tree
456  type(mg2_t), intent(in) :: mg
457  integer, intent(in) :: ids(:)
458  integer, intent(in) :: type_cycle
459  integer :: n, i, n_cycle
460  logical :: use_corners
461 
462  select case (type_cycle)
463  case (mg_cycle_down)
464  n_cycle = mg%n_cycle_down
465  case (mg_cycle_up)
466  n_cycle = mg%n_cycle_up
467  case (mg_cycle_base)
468  n_cycle = mg%n_cycle_base
469  case default
470  error stop "gsrb_boxes: invalid cycle type"
471  end select
472 
473  !$omp parallel private(n, i)
474  do n = 1, 2 * n_cycle
475  !$omp do
476  do i = 1, size(ids)
477  call mg%box_gsrb(tree%boxes(ids(i)), n, mg)
478  end do
479  !$omp end do
480 
481  use_corners = mg%use_corners .or. &
482  (type_cycle /= mg_cycle_down .and. n == 2 * n_cycle)
483 
484  !$omp do
485  do i = 1, size(ids)
486  call a2_gc_box(tree, ids(i), mg%i_phi, mg%sides_rb, &
487  mg%sides_bc, use_corners)
488  end do
489  !$omp end do
490  end do
491  !$omp end parallel
492  end subroutine gsrb_boxes
493 
494  ! Set rhs on coarse grid, restrict phi, and copy i_phi to i_tmp for the
495  ! correction later
496  subroutine update_coarse(tree, lvl, mg)
497  use m_a2_utils, only: a2_n_cell, a2_box_add_cc, a2_box_copy_cc
498  use m_a2_ghostcell, only: a2_gc_ids
499  type(a2_t), intent(inout) :: tree
500  integer, intent(in) :: lvl
501  type(mg2_t), intent(in) :: mg
502  integer :: i, id, p_id, nc
503  real(dp), allocatable :: tmp(:,:)
504 
505  id = tree%lvls(lvl)%ids(1)
506  nc = a2_n_cell(tree, lvl)
507  allocate(tmp(1:nc, 1:nc))
508 
509  ! Restrict phi and the residual
510  !$omp parallel do private(id, p_id, tmp)
511  do i = 1, size(tree%lvls(lvl)%ids)
512  id = tree%lvls(lvl)%ids(i)
513  p_id = tree%boxes(id)%parent
514 
515  ! Copy the data currently in i_tmp, and restore it later (i_tmp holds the
516  ! previous state of i_phi)
517  tmp = tree%boxes(id)%cc(1:nc, 1:nc, mg%i_tmp)
518  call residual_box(tree%boxes(id), mg)
519  call mg%box_rstr(tree%boxes(id), tree%boxes(p_id), mg%i_tmp, mg)
520  call mg%box_rstr(tree%boxes(id), tree%boxes(p_id), mg%i_phi, mg)
521  tree%boxes(id)%cc(1:nc, 1:nc, mg%i_tmp) = tmp
522  end do
523  !$omp end parallel do
524 
525  call a2_gc_ids(tree, tree%lvls(lvl-1)%ids, mg%i_phi, &
526  mg%sides_rb, mg%sides_bc)
527 
528  ! Set rhs_c = laplacian(phi_c) + restrict(res) where it is refined, and
529  ! store current coarse phi in tmp.
530 
531  !$omp parallel do private(id)
532  do i = 1, size(tree%lvls(lvl-1)%parents)
533  id = tree%lvls(lvl-1)%parents(i)
534 
535  ! Set rhs = L phi
536  call mg%box_op(tree%boxes(id), mg%i_rhs, mg)
537 
538  ! Add tmp (the fine grid residual) to rhs
539  call a2_box_add_cc(tree%boxes(id), mg%i_tmp, mg%i_rhs)
540 
541  ! Story a copy of phi in tmp
542  call a2_box_copy_cc(tree%boxes(id), mg%i_phi, mg%i_tmp)
543  end do
544  !$omp end parallel do
545  end subroutine update_coarse
546 
549  subroutine set_coarse_phi_rhs(tree, lvl, mg)
550  use m_a2_ghostcell, only: a2_gc_ids
551  use m_a2_utils, only: a2_box_add_cc
552  type(a2_t), intent(inout) :: tree
553  integer, intent(in) :: lvl
554  type(mg2_t), intent(in) :: mg
555  integer :: i, id, p_id
556 
557  ! Fill ghost cells here to be sure
558  if (lvl == tree%highest_lvl) then
559  call a2_gc_ids(tree, tree%lvls(lvl)%ids, mg%i_phi, &
560  mg%sides_rb, mg%sides_bc)
561  end if
562 
563  !$omp parallel do private(id, p_id)
564  do i = 1, size(tree%lvls(lvl)%ids)
565  id = tree%lvls(lvl)%ids(i)
566  p_id = tree%boxes(id)%parent
567 
568  call residual_box(tree%boxes(id), mg)
569  call mg%box_rstr(tree%boxes(id), tree%boxes(p_id), mg%i_tmp, mg)
570  call mg%box_rstr(tree%boxes(id), tree%boxes(p_id), mg%i_phi, mg)
571  end do
572  !$omp end parallel do
573 
574  call a2_gc_ids(tree, tree%lvls(lvl-1)%ids, mg%i_phi, &
575  mg%sides_rb, mg%sides_bc)
576 
577  ! Set rhs_c = laplacian(phi_c) + restrict(res) where it is refined
578 
579  !$omp parallel do private(id)
580  do i = 1, size(tree%lvls(lvl-1)%parents)
581  id = tree%lvls(lvl-1)%parents(i)
582  call mg%box_op(tree%boxes(id), mg%i_rhs, mg)
583  call a2_box_add_cc(tree%boxes(id), mg%i_tmp, mg%i_rhs)
584  end do
585  !$omp end parallel do
586  end subroutine set_coarse_phi_rhs
587 
589  subroutine init_phi_rhs(tree, mg)
590  use m_a2_utils, only: a2_box_clear_cc
591  type(a2_t), intent(inout) :: tree
592  type(mg2_t), intent(in) :: mg
593  integer :: i, id, p_id, lvl, min_lvl
594 
595  ! Start from phi = 0 and restrict rhs
596  min_lvl = lbound(tree%lvls, 1)
597 
598  !$omp parallel private(lvl, i, id, p_id)
599  do lvl = tree%highest_lvl, min_lvl+1, -1
600  !$omp do
601  do i = 1, size(tree%lvls(lvl)%ids)
602  id = tree%lvls(lvl)%ids(i)
603  call a2_box_clear_cc(tree%boxes(id), mg%i_phi)
604  if (lvl > min_lvl) then
605  p_id = tree%boxes(id)%parent
606  call mg%box_rstr(tree%boxes(id), tree%boxes(p_id), mg%i_rhs, mg)
607  end if
608  end do
609  !$omp end do
610  end do
611  !$omp end parallel
612  end subroutine init_phi_rhs
613 
614  subroutine residual_box(box, mg)
615  type(box2_t), intent(inout) :: box
616  type(mg2_t), intent(in) :: mg
617  integer :: nc
618 
619  call mg%box_op(box, mg%i_tmp, mg)
620  nc = box%n_cell
621  box%cc(1:nc, 1:nc, mg%i_tmp) = box%cc(1:nc, 1:nc, mg%i_rhs) &
622  - box%cc(1:nc, 1:nc, mg%i_tmp)
623  end subroutine residual_box
624 
626  subroutine mg2_auto_gsrb(box, redblack_cntr, mg)
627  type(box2_t), intent(inout) :: box
628  integer, intent(in) :: redblack_cntr
629  type(mg2_t), intent(in) :: mg
630 
631  if (box%tag == af_init_tag) call mg2_set_box_tag(box, mg)
632 
633  select case(box%tag)
634  case (mg_normal_box)
635  if (box%coord_t == af_cyl) then
636  call mg2_box_gsrb_clpl(box, redblack_cntr, mg)
637  else
638  call mg2_box_gsrb_lpl(box, redblack_cntr, mg)
639  end if
640  case (mg_lsf_box)
641  call mg2_box_gsrb_lpllsf(box, redblack_cntr, mg)
642  case (mg_veps_box, mg_ceps_box)
643  if (box%coord_t == af_cyl) then
644  call mg2_box_gsrb_clpld(box, redblack_cntr, mg)
645  else
646  call mg2_box_gsrb_lpld(box, redblack_cntr, mg)
647  end if
648  end select
649  end subroutine mg2_auto_gsrb
650 
652  subroutine mg2_auto_op(box, i_out, mg)
653  type(box2_t), intent(inout) :: box
654  integer, intent(in) :: i_out
655  type(mg2_t), intent(in) :: mg
656 
657  if (box%tag == af_init_tag) call mg2_set_box_tag(box, mg)
658 
659  select case(box%tag)
660  case (mg_normal_box)
661  if (box%coord_t == af_cyl) then
662  call mg2_box_clpl(box, i_out, mg)
663  else
664  call mg2_box_lpl(box, i_out, mg)
665  end if
666  case (mg_lsf_box)
667  call mg2_box_lpllsf(box, i_out, mg)
668  case (mg_veps_box, mg_ceps_box)
669  if (box%coord_t == af_cyl) then
670  call mg2_box_clpld(box, i_out, mg)
671  else
672  call mg2_box_lpld(box, i_out, mg)
673  end if
674  end select
675  end subroutine mg2_auto_op
676 
678  subroutine mg2_auto_rstr(box_c, box_p, iv, mg)
679  type(box2_t), intent(in) :: box_c
680  type(box2_t), intent(inout) :: box_p
681  integer, intent(in) :: iv
682  type(mg2_t), intent(in) :: mg
683 
684  ! We can only restrict after gsrb, so tag should always be set
685  if (box_c%tag == af_init_tag) stop "mg2_auto_rstr: box_c tag not set"
686 
687  select case(box_c%tag)
688  case (mg_normal_box, mg_veps_box, mg_ceps_box)
689  call mg2_box_rstr_lpl(box_c, box_p, iv, mg)
690  case (mg_lsf_box)
691  call mg2_box_rstr_lpllsf(box_c, box_p, iv, mg)
692  end select
693  end subroutine mg2_auto_rstr
694 
696  subroutine mg2_auto_corr(box_p, box_c, mg)
697  type(box2_t), intent(inout) :: box_c
698  type(box2_t), intent(in) :: box_p
699  type(mg2_t), intent(in) :: mg
700 
701  if (box_c%tag == af_init_tag) call mg2_set_box_tag(box_c, mg)
702 
703  select case(box_c%tag)
704  case (mg_normal_box)
705  call mg2_box_corr_lpl(box_p, box_c, mg)
706  case (mg_lsf_box)
707  call mg2_box_corr_lpllsf(box_p, box_c, mg)
708  case (mg_veps_box, mg_ceps_box)
709  call mg2_box_corr_lpld(box_p, box_c, mg)
710  end select
711  end subroutine mg2_auto_corr
712 
713  subroutine mg2_set_box_tag(box, mg)
714  type(box2_t), intent(inout) :: box
715  type(mg2_t), intent(in) :: mg
716  real(dp) :: a, b
717  logical :: is_lsf, is_deps, is_eps
718 
719  is_lsf = .false.
720  is_eps = .false.
721  is_deps = .false.
722 
723  if (mg%i_lsf /= -1) then
724  is_lsf = minval(box%cc(:, :, mg%i_lsf)) * &
725  maxval(box%cc(:, :, mg%i_lsf)) < 0
726  end if
727 
728  if (mg%i_eps /= -1) then
729  a = minval(box%cc(:, :, mg%i_eps))
730  b = maxval(box%cc(:, :, mg%i_eps))
731  is_deps = (b > a)
732  if (.not. is_deps) is_eps = (a < 1 .or. a > 1)
733  end if
734 
735  if (count([is_lsf, is_eps, is_deps]) > 1) &
736  stop "mg2_set_box_tag: Cannot set lsf and eps tag for same box"
737 
738  box%tag = mg_normal_box
739  if (is_lsf) box%tag = mg_lsf_box
740  if (is_eps) box%tag = mg_ceps_box
741  if (is_deps) box%tag = mg_veps_box
742  end subroutine mg2_set_box_tag
743 
744  subroutine mg2_box_corr_lpl(box_p, box_c, mg)
746  type(box2_t), intent(inout) :: box_c
747  type(box2_t), intent(in) :: box_p
748  type(mg2_t), intent(in) :: mg
749 
750  call a2_prolong_linear(box_p, box_c, mg%i_tmp, mg%i_phi, add=.true.)
751  end subroutine mg2_box_corr_lpl
752 
754  subroutine mg2_box_gsrb_lpl(box, redblack_cntr, mg)
755  type(box2_t), intent(inout) :: box
756  integer, intent(in) :: redblack_cntr
757  type(mg2_t), intent(in) :: mg
758  integer :: i, i0, j, nc, i_phi, i_rhs
759  real(dp) :: dx2
760 
761  dx2 = box%dr**2
762  nc = box%n_cell
763  i_phi = mg%i_phi
764  i_rhs = mg%i_rhs
765 
766  ! The parity of redblack_cntr determines which cells we use. If
767  ! redblack_cntr is even, we use the even cells and vice versa.
768  do j = 1, nc
769  i0 = 2 - iand(ieor(redblack_cntr, j), 1)
770  do i = i0, nc, 2
771  box%cc(i, j, i_phi) = 0.25_dp * ( &
772  box%cc(i+1, j, i_phi) + box%cc(i-1, j, i_phi) + &
773  box%cc(i, j+1, i_phi) + box%cc(i, j-1, i_phi) - &
774  dx2 * box%cc(i, j, i_rhs))
775  end do
776  end do
777  end subroutine mg2_box_gsrb_lpl
778 
780  subroutine mg2_box_lpl(box, i_out, mg)
781  type(box2_t), intent(inout) :: box
782  integer, intent(in) :: i_out
783  type(mg2_t), intent(in) :: mg
784  integer :: i, j, nc, i_phi
785  real(dp) :: inv_dr_sq
786 
787  nc = box%n_cell
788  inv_dr_sq = 1 / box%dr**2
789  i_phi = mg%i_phi
790 
791  do j = 1, nc
792  do i = 1, nc
793  box%cc(i, j, i_out) = inv_dr_sq * (box%cc(i-1, j, i_phi) + &
794  box%cc(i+1, j, i_phi) + box%cc(i, j-1, i_phi) + &
795  box%cc(i, j+1, i_phi) - 4 * box%cc(i, j, i_phi))
796  end do
797  end do
798  end subroutine mg2_box_lpl
799 
801  subroutine mg2_box_rstr_lpl(box_c, box_p, iv, mg)
802  use m_a2_restrict, only: a2_restrict_box
803  type(box2_t), intent(in) :: box_c
804  type(box2_t), intent(inout) :: box_p
805  integer, intent(in) :: iv
806  type(mg2_t), intent(in) :: mg
807 
808  ! Don't use geometry for restriction, since this is inconsistent with the
809  ! filling of ghost cells near refinement boundaries
810  call a2_restrict_box(box_c, box_p, iv, use_geometry=.false.)
811  end subroutine mg2_box_rstr_lpl
812 
815  subroutine mg2_box_gsrb_lpld(box, redblack_cntr, mg)
816  type(box2_t), intent(inout) :: box
817  integer, intent(in) :: redblack_cntr
818  type(mg2_t), intent(in) :: mg
819  integer :: i, i0, j, nc, i_phi, i_eps, i_rhs
820  real(dp) :: dx2, u(2*2), a0, a(2*2), c(2*2)
821 
822  dx2 = box%dr**2
823  nc = box%n_cell
824  i_phi = mg%i_phi
825  i_eps = mg%i_eps
826  i_rhs = mg%i_rhs
827 
828  ! The parity of redblack_cntr determines which cells we use. If
829  ! redblack_cntr is even, we use the even cells and vice versa.
830  do j = 1, nc
831  i0 = 2 - iand(ieor(redblack_cntr, j), 1)
832  do i = i0, nc, 2
833  a0 = box%cc(i, j, i_eps) ! value of eps at i,j
834  u(1:2) = box%cc(i-1:i+1:2, j, i_phi) ! values at neighbors
835  a(1:2) = box%cc(i-1:i+1:2, j, i_eps)
836  u(3:4) = box%cc(i, j-1:j+1:2, i_phi)
837  a(3:4) = box%cc(i, j-1:j+1:2, i_eps)
838  c(:) = 2 * a0 * a(:) / (a0 + a(:))
839 
840  box%cc(i, j, i_phi) = &
841  (sum(c(:) * u(:)) - dx2 * box%cc(i, j, i_rhs)) / sum(c(:))
842  end do
843  end do
844  end subroutine mg2_box_gsrb_lpld
845 
847  subroutine mg2_box_lpld(box, i_out, mg)
848  type(box2_t), intent(inout) :: box
849  integer, intent(in) :: i_out
850  type(mg2_t), intent(in) :: mg
851  integer :: i, j, nc, i_phi, i_eps
852  real(dp) :: inv_dr_sq, a0, u0, u(2*2), a(2*2)
853 
854  nc = box%n_cell
855  inv_dr_sq = 1 / box%dr**2
856  i_phi = mg%i_phi
857  i_eps = mg%i_eps
858 
859  do j = 1, nc
860  do i = 1, nc
861  u0 = box%cc(i, j, i_phi)
862  a0 = box%cc(i, j, i_eps)
863  u(1:2) = box%cc(i-1:i+1:2, j, i_phi)
864  u(3:4) = box%cc(i, j-1:j+1:2, i_phi)
865  a(1:2) = box%cc(i-1:i+1:2, j, i_eps)
866  a(3:4) = box%cc(i, j-1:j+1:2, i_eps)
867 
868  box%cc(i, j, i_out) = inv_dr_sq * 2 * &
869  sum(a0*a(:)/(a0 + a(:)) * (u(:) - u0))
870  end do
871  end do
872 
873  end subroutine mg2_box_lpld
874 
877  subroutine mg2_box_corr_lpld(box_p, box_c, mg)
878  type(box2_t), intent(inout) :: box_c
879  type(box2_t), intent(in) :: box_p
880  type(mg2_t), intent(in) :: mg
881  integer :: ix_offset(2), i_phi, i_corr, i_eps
882  integer :: nc, i, j, i_c1, i_c2, j_c1, j_c2
883  real(dp) :: u0, u(2), a0, a(2)
884 
885  nc = box_c%n_cell
886  ix_offset = a2_get_child_offset(box_c)
887  i_phi = mg%i_phi
888  i_corr = mg%i_tmp
889  i_eps = mg%i_eps
890 
891  ! In these loops, we calculate the closest coarse index (_c1), and the
892  ! one-but-closest (_c2). The fine cell lies in between.
893  do j = 1, nc
894  j_c1 = ix_offset(2) + ishft(j+1, -1) ! (j+1)/2
895  j_c2 = j_c1 + 1 - 2 * iand(j, 1) ! even: +1, odd: -1
896  do i = 1, nc
897  i_c1 = ix_offset(1) + ishft(i+1, -1) ! (i+1)/2
898  i_c2 = i_c1 + 1 - 2 * iand(i, 1) ! even: +1, odd: -1
899 
900  u0 = box_p%cc(i_c1, j_c1, i_corr)
901  a0 = box_p%cc(i_c1, j_c1, i_eps)
902  u(1) = box_p%cc(i_c2, j_c1, i_corr)
903  u(2) = box_p%cc(i_c1, j_c2, i_corr)
904  a(1) = box_p%cc(i_c2, j_c1, i_eps)
905  a(2) = box_p%cc(i_c1, j_c2, i_eps)
906 
907  ! Get value of phi at coarse cell faces, and average
908  box_c%cc(i, j, i_phi) = box_c%cc(i, j, i_phi) + 0.5_dp * &
909  sum( (a0*u0 + a(:)*u(:)) / (a0 + a(:)) )
910  end do
911  end do
912  end subroutine mg2_box_corr_lpld
913 
914  ! Below: multigrid operators for internal boundary conditions. A level set
915  ! function defines the location of the interface(s).
916 
918  subroutine lsf_dist_val(lsf_val_bval_a, lsf_val_bval_b, dist, val)
919 
920  real(dp), intent(in) :: lsf_val_bval_a(3)
922  real(dp), intent(in) :: lsf_val_bval_b(3)
924  real(dp), intent(out) :: dist
926  real(dp), intent(out) :: val
927  real(dp) :: lsf_a, lsf_b, bval_a, bval_b
928 
929  lsf_a = lsf_val_bval_a(1)
930  lsf_b = lsf_val_bval_b(1)
931 
932  if (lsf_a * lsf_b < 0) then
933  ! There is a boundary between the points
934  dist = lsf_a / (lsf_a - lsf_b)
935  bval_a = lsf_val_bval_a(3)
936  bval_b = lsf_val_bval_b(3)
937 
938  ! Interpolate between boundary values
939  val = bval_a * (1-dist) + bval_b * dist
940  else
941  ! Simply use the value at b
942  dist = 1
943  val = lsf_val_bval_b(2)
944  end if
945  end subroutine lsf_dist_val
946 
947  subroutine mg2_box_corr_lpllsf(box_p, box_c, mg)
948  type(box2_t), intent(inout) :: box_c
949  type(box2_t), intent(in) :: box_p
950  type(mg2_t), intent(in) :: mg
951  integer :: i_phi, i_corr, i_lsf, ix_offset(2)
952  integer :: nc, i, j, i_c1, i_c2, j_c1, j_c2
953  real(dp) :: v_a(3), v_b(3), val(2+1), dist(2+1), c(2+1)
954 
955  nc = box_c%n_cell
956  ix_offset = a2_get_child_offset(box_c)
957  i_phi = mg%i_phi
958  i_corr = mg%i_tmp
959  i_lsf = mg%i_lsf
960 
961  ! In these loops, we calculate the closest coarse index (_c1), and the
962  ! one-but-closest (_c2). The fine cell lies in between.
963  do j = 1, nc
964  j_c1 = ix_offset(2) + ishft(j+1, -1) ! (j+1)/2
965  j_c2 = j_c1 + 1 - 2 * iand(j, 1) ! even: +1, odd: -1
966  do i = 1, nc
967  i_c1 = ix_offset(1) + ishft(i+1, -1) ! (i+1)/2
968  i_c2 = i_c1 + 1 - 2 * iand(i, 1) ! even: +1, odd: -1
969 
970  v_a(1:2) = box_c%cc(i, j, [i_lsf, i_corr])
971  v_a(3) = 0.0_dp ! Boundary value for correction is 0
972  v_b(3) = 0.0_dp ! Idem
973  v_b(1:2) = box_p%cc(i_c1, j_c1, [i_lsf, i_corr])
974  call lsf_dist_val(v_a, v_b, dist(1), val(1))
975  v_b(1:2) = box_p%cc(i_c2, j_c1, [i_lsf, i_corr])
976  call lsf_dist_val(v_a, v_b, dist(2), val(2))
977  v_b(1:2) = box_p%cc(i_c1, j_c2, [i_lsf, i_corr])
978  call lsf_dist_val(v_a, v_b, dist(3), val(3))
979 
980  ! This expresses general interpolation between 3 points (on the lines
981  ! between the fine and the 3 coarse values).
982  c(1) = 2 * dist(2) * dist(3)
983  c(2) = dist(1) * dist(3)
984  c(3) = dist(1) * dist(2)
985  box_c%cc(i, j, i_phi) = box_c%cc(i, j, i_phi) + sum(c * val)/sum(c)
986  end do
987  end do
988  end subroutine mg2_box_corr_lpllsf
989 
991  subroutine mg2_box_gsrb_lpllsf(box, redblack_cntr, mg)
992  type(box2_t), intent(inout) :: box
993  integer, intent(in) :: redblack_cntr
994  type(mg2_t), intent(in) :: mg
995  integer :: i, i0, j, nc, i_phi, i_rhs, i_lsf, i_bval
996  real(dp) :: dx2, dd(2*2), val(2*2), v_a(3), v_b(3)
997 
998  dx2 = box%dr**2
999  nc = box%n_cell
1000  i_phi = mg%i_phi
1001  i_rhs = mg%i_rhs
1002  i_lsf = mg%i_lsf
1003  i_bval = mg%i_bval
1004 
1005  ! The parity of redblack_cntr determines which cells we use. If
1006  ! redblack_cntr is even, we use the even cells and vice versa.
1007  do j = 1, nc
1008  i0 = 2 - iand(ieor(redblack_cntr, j), 1)
1009  do i = i0, nc, 2
1010  v_a = box%cc(i, j, [i_lsf, i_phi, i_bval])
1011  v_b = box%cc(i-1, j, [i_lsf, i_phi, i_bval])
1012  call lsf_dist_val(v_a, v_b, dd(1), val(1))
1013  v_b = box%cc(i+1, j, [i_lsf, i_phi, i_bval])
1014  call lsf_dist_val(v_a, v_b, dd(2), val(2))
1015  v_b = box%cc(i, j-1, [i_lsf, i_phi, i_bval])
1016  call lsf_dist_val(v_a, v_b, dd(3), val(3))
1017  v_b = box%cc(i, j+1, [i_lsf, i_phi, i_bval])
1018  call lsf_dist_val(v_a, v_b, dd(4), val(4))
1019 
1020  ! Solve for generalized Laplacian (see routine mg2_box_lpllsf)
1021  box%cc(i, j, i_phi) = 1 / &
1022  (dd(1) * dd(2) + dd(3) * dd(4)) * ( &
1023  (dd(2) * val(1) + dd(1) * val(2)) * &
1024  dd(3) * dd(4) / (dd(1) + dd(2)) + &
1025  (dd(4) * val(3) + dd(3) * val(4)) * &
1026  dd(1) * dd(2) / (dd(3) + dd(4)) - &
1027  0.5_dp * product(dd) * dx2 * box%cc(i, j, i_rhs))
1028  end do
1029  end do
1030  end subroutine mg2_box_gsrb_lpllsf
1031 
1033  subroutine mg2_box_lpllsf(box, i_out, mg)
1034  type(box2_t), intent(inout) :: box
1035  integer, intent(in) :: i_out
1036  type(mg2_t), intent(in) :: mg
1037  integer :: i, j, nc, i_phi, i_lsf, i_bval
1038  real(dp) :: inv_dr_sq, dd(2*2), val(2*2)
1039  real(dp) :: f0, v_a(3), v_b(3)
1040 
1041  nc = box%n_cell
1042  inv_dr_sq = 1 / box%dr**2
1043  i_phi = mg%i_phi
1044  i_lsf = mg%i_lsf
1045  i_bval = mg%i_bval
1046 
1047  do j = 1, nc
1048  do i = 1, nc
1049  v_a = box%cc(i, j, [i_lsf, i_phi, i_bval])
1050  v_b = box%cc(i-1, j, [i_lsf, i_phi, i_bval])
1051  call lsf_dist_val(v_a, v_b, dd(1), val(1))
1052  v_b = box%cc(i+1, j, [i_lsf, i_phi, i_bval])
1053  call lsf_dist_val(v_a, v_b, dd(2), val(2))
1054  v_b = box%cc(i, j-1, [i_lsf, i_phi, i_bval])
1055  call lsf_dist_val(v_a, v_b, dd(3), val(3))
1056  v_b = box%cc(i, j+1, [i_lsf, i_phi, i_bval])
1057  call lsf_dist_val(v_a, v_b, dd(4), val(4))
1058 
1059  ! Generalized Laplacian for neighbors at distance dd * dx
1060  f0 = box%cc(i, j, i_phi)
1061  box%cc(i, j, i_out) = 2 * inv_dr_sq * ( &
1062  (dd(2) * val(1) + dd(1) * val(2) - (dd(1)+dd(2)) * f0) / &
1063  ((dd(1) + dd(2)) * dd(1) * dd(2)) + &
1064  (dd(4) * val(3) + dd(3) * val(4) - (dd(3)+dd(4)) * f0) / &
1065  ((dd(3) + dd(4)) * dd(3) * dd(4)))
1066  end do
1067  end do
1068  end subroutine mg2_box_lpllsf
1069 
1071  subroutine mg2_box_rstr_lpllsf(box_c, box_p, iv, mg)
1072  type(box2_t), intent(in) :: box_c
1073  type(box2_t), intent(inout) :: box_p
1074  integer, intent(in) :: iv
1075  type(mg2_t), intent(in) :: mg
1076  integer :: i, j, i_f, j_f, i_c, j_c
1077  integer :: hnc, ix_offset(2), n_ch
1078  logical :: child_mask(2, 2)
1079 
1080  hnc = ishft(box_c%n_cell, -1) ! n_cell / 2
1081  ix_offset = a2_get_child_offset(box_c)
1082 
1083  do j = 1, hnc
1084  j_c = ix_offset(2) + j
1085  j_f = 2 * j - 1
1086  do i = 1, hnc
1087  i_c = ix_offset(1) + i
1088  i_f = 2 * i - 1
1089 
1090  child_mask = (box_p%cc(i_c, j_c, mg%i_lsf) * &
1091  box_c%cc(i_f:i_f+1, j_f:j_f+1, mg%i_lsf) > 0)
1092  n_ch = count(child_mask)
1093 
1094  if (n_ch < a2_num_children .and. n_ch > 0) then
1095  box_p%cc(i_c, j_c, iv) = 1 / n_ch * &
1096  sum(box_c%cc(i_f:i_f+1, j_f:j_f+1, iv), mask=child_mask)
1097  else ! Take average of children
1098  box_p%cc(i_c, j_c, iv) = 0.25_dp * &
1099  sum(box_c%cc(i_f:i_f+1, j_f:j_f+1, iv))
1100  end if
1101  end do
1102  end do
1103  end subroutine mg2_box_rstr_lpllsf
1104 
1106  subroutine mg2_box_gsrb_clpl(box, redblack_cntr, mg)
1107  type(box2_t), intent(inout) :: box
1108  integer, intent(in) :: redblack_cntr
1109  type(mg2_t), intent(in) :: mg
1110  integer :: i, i0, j, nc, i_phi, i_rhs, ioff
1111  real(dp) :: dx2, rfac(2)
1112 
1113  dx2 = box%dr**2
1114  nc = box%n_cell
1115  i_phi = mg%i_phi
1116  i_rhs = mg%i_rhs
1117  ioff = (box%ix(1)-1) * nc
1118 
1119  ! The parity of redblack_cntr determines which cells we use. If
1120  ! redblack_cntr is even, we use the even cells and vice versa.
1121  do j = 1, nc
1122  i0 = 2 - iand(ieor(redblack_cntr, j), 1)
1123  do i = i0, nc, 2
1124  rfac = [i+ioff-1, i+ioff] / (i+ioff-0.5_dp)
1125  box%cc(i, j, i_phi) = 0.25_dp * ( &
1126  rfac(1) * box%cc(i-1, j, i_phi) + &
1127  rfac(2) * box%cc(i+1, j, i_phi) + &
1128  box%cc(i, j+1, i_phi) + box%cc(i, j-1, i_phi) - &
1129  dx2 * box%cc(i, j, i_rhs))
1130  end do
1131  end do
1132  end subroutine mg2_box_gsrb_clpl
1133 
1135  subroutine mg2_box_clpl(box, i_out, mg)
1136  type(box2_t), intent(inout) :: box
1137  integer, intent(in) :: i_out
1138  type(mg2_t), intent(in) :: mg
1139  integer :: i, j, nc, i_phi, ioff
1140  real(dp) :: inv_dr_sq, rfac(2)
1141 
1142  nc = box%n_cell
1143  inv_dr_sq = 1 / box%dr**2
1144  i_phi = mg%i_phi
1145  ioff = (box%ix(1)-1) * nc
1146 
1147  do j = 1, nc
1148  do i = 1, nc
1149  rfac = [i+ioff-1, i+ioff] / (i+ioff-0.5_dp)
1150  box%cc(i, j, i_out) = ( &
1151  rfac(1) * box%cc(i-1, j, i_phi) + &
1152  rfac(2) * box%cc(i+1, j, i_phi) + &
1153  box%cc(i, j-1, i_phi) + box%cc(i, j+1, i_phi) - &
1154  4 * box%cc(i, j, i_phi)) * inv_dr_sq
1155  end do
1156  end do
1157  end subroutine mg2_box_clpl
1158 
1160  subroutine mg2_box_clpld(box, i_out, mg)
1161  type(box2_t), intent(inout) :: box
1162  integer, intent(in) :: i_out
1163  type(mg2_t), intent(in) :: mg
1164  integer :: i, j, nc, i_phi, i_eps, ioff
1165  real(dp) :: inv_dr_sq, a0, u0, u(4), a(4), rfac(4)
1166 
1167  nc = box%n_cell
1168  inv_dr_sq = 1 / box%dr**2
1169  i_phi = mg%i_phi
1170  i_eps = mg%i_eps
1171  ioff = (box%ix(1)-1) * nc
1172 
1173  do j = 1, nc
1174  do i = 1, nc
1175  rfac(1:2) = [i+ioff-1, i+ioff] / (i+ioff-0.5_dp)
1176  rfac(3:4) = 1
1177  u0 = box%cc(i, j, i_phi)
1178  a0 = box%cc(i, j, i_eps)
1179  u(1:2) = box%cc(i-1:i+1:2, j, i_phi)
1180  u(3:4) = box%cc(i, j-1:j+1:2, i_phi)
1181  a(1:2) = box%cc(i-1:i+1:2, j, i_eps)
1182  a(3:4) = box%cc(i, j-1:j+1:2, i_eps)
1183 
1184  box%cc(i, j, i_out) = inv_dr_sq * 2 * &
1185  sum(rfac*a0*a(:)/(a0 + a(:)) * (u(:) - u0))
1186  end do
1187  end do
1188  end subroutine mg2_box_clpld
1189 
1192  subroutine mg2_box_gsrb_clpld(box, redblack_cntr, mg)
1193  type(box2_t), intent(inout) :: box
1194  integer, intent(in) :: redblack_cntr
1195  type(mg2_t), intent(in) :: mg
1196  integer :: i, i0, j, nc, i_phi, i_eps, i_rhs, ioff
1197  real(dp) :: dx2, u(4), a0, a(4), c(4), rfac(4)
1198 
1199  dx2 = box%dr**2
1200  nc = box%n_cell
1201  i_phi = mg%i_phi
1202  i_eps = mg%i_eps
1203  i_rhs = mg%i_rhs
1204  ioff = (box%ix(1)-1) * nc
1205 
1206  ! The parity of redblack_cntr determines which cells we use. If
1207  ! redblack_cntr is even, we use the even cells and vice versa.
1208  do j = 1, nc
1209  i0 = 2 - iand(ieor(redblack_cntr, j), 1)
1210  do i = i0, nc, 2
1211  rfac(1:2) = [i+ioff-1, i+ioff] / (i+ioff-0.5_dp)
1212  rfac(3:4) = 1
1213  a0 = box%cc(i, j, i_eps) ! value of eps at i,j
1214  u(1:2) = box%cc(i-1:i+1:2, j, i_phi) ! values at neighbors
1215  a(1:2) = box%cc(i-1:i+1:2, j, i_eps)
1216  u(3:4) = box%cc(i, j-1:j+1:2, i_phi)
1217  a(3:4) = box%cc(i, j-1:j+1:2, i_eps)
1218  c(:) = 2 * a0 * a(:) / (a0 + a(:))
1219 
1220  box%cc(i, j, i_phi) = (sum(c(:) * rfac * u(:)) &
1221  - dx2 * box%cc(i, j, i_rhs)) / sum(c(:) * rfac)
1222  end do
1223  end do
1224  end subroutine mg2_box_gsrb_clpld
1225 
1226 end module m_a2_multigrid
Subroutine that performs A * cc(..., i_in) = cc(..., i_out)
Type to store multigrid options in.
This module contains all kinds of different &#39;helper&#39; routines for Afivo. If the number of routines fo...
Definition: m_a2_utils.f90:5
This module contains routines related to the filling of ghost cells. Note that corner ghost cells are...
Type which stores all the boxes and levels, as well as some information about the number of boxes...
Definition: m_a2_types.f90:93
This module contains the basic types and constants that are used in the 2-dimensional version of Afiv...
Definition: m_a2_types.f90:5
To fill ghost cells near physical boundaries.
Definition: m_a2_types.f90:177
This module contains routines for restriction: going from fine to coarse variables.
This module contains the routines related to prolongation: going from coarse to fine variables...
Definition: m_a2_prolong.f90:4
This module contains the geometric multigrid routines that come with Afivo.
To fill ghost cells near refinement boundaries.
Definition: m_a2_types.f90:168
The basic building block of afivo: a box with cell-centered and face centered data, and information about its position, neighbors, children etc.
Definition: m_a2_types.f90:71