Afivo  0.3
m_a2_core.f90
1 
4 module m_a2_core
5  use m_a2_types
6 
7  implicit none
8  private
9 
10  public :: a2_init
11  public :: a2_set_cc_methods
12  public :: a2_init_box
13  public :: a2_destroy
14  public :: a2_set_base
15  public :: a2_tidy_up
16  public :: a2_resize_box_storage
17  public :: a2_adjust_refinement
18  public :: a2_consistent_fluxes
19 
20 contains
21 
23  subroutine a2_init(tree, n_cell, n_var_cell, n_var_face, dr, r_min, &
24  lvl_limit, n_boxes, coarsen_to, coord, cc_names, fc_names, mem_limit_gb)
25  type(a2_t), intent(inout) :: tree
26  integer, intent(in) :: n_cell
27  integer, intent(in) :: n_var_cell
28  integer, intent(in) :: n_var_face
29  real(dp), intent(in) :: dr
31  real(dp), intent(in), optional :: r_min(2)
34  integer, intent(in), optional :: coarsen_to
36  integer, intent(in), optional :: lvl_limit
38  integer, intent(in), optional :: n_boxes
39  integer, intent(in), optional :: coord
40  real(dp), intent(in), optional :: mem_limit_gb
41 
43  character(len=*), intent(in), optional :: cc_names(:)
45  character(len=*), intent(in), optional :: fc_names(:)
46 
47  integer :: lvl_limit_a, n_boxes_a, coarsen_to_a
48  real(dp) :: r_min_a(2), gb_limit
49  integer :: n, lvl, min_lvl, coord_a, box_bytes
50 
51  ! Set default arguments if not present
52  lvl_limit_a = 30; if (present(lvl_limit)) lvl_limit_a = lvl_limit
53  n_boxes_a = 1000; if (present(n_boxes)) n_boxes_a = n_boxes
54  coarsen_to_a = -1; if (present(coarsen_to)) coarsen_to_a = coarsen_to
55  r_min_a = 0.0_dp; if (present(r_min)) r_min_a = r_min
56  coord_a = af_xyz; if (present(coord)) coord_a = coord
57  gb_limit = 16; if (present(mem_limit_gb)) gb_limit = mem_limit_gb
58 
59  if (tree%ready) stop "a2_init: tree was already initialized"
60  if (n_cell < 2) stop "a2_init: n_cell should be >= 2"
61  if (btest(n_cell, 0)) stop "a2_init: n_cell should be even"
62  if (n_var_cell <= 0) stop "a2_init: n_var_cell should be > 0"
63  if (n_var_face < 0) stop "a2_init: n_var_face should be >= 0"
64  if (n_boxes_a <= 0) stop "a2_init: n_boxes should be > 0"
65  if (lvl_limit_a <= 0) stop "a2_init: lvl_limit should be > 0"
66  if (gb_limit <= 0) stop "a2_init: mem_limit_gb should be > 0"
67 
68  allocate(tree%boxes(n_boxes_a))
69 
70  if (coarsen_to_a > 0) then
71  ! Determine number of lvls for subtree
73  min_lvl = 1 - nint(log(real(n_cell, dp)/coarsen_to_a)/log(2.0_dp))
74 
75  if (2**(1-min_lvl) * coarsen_to_a /= n_cell) &
76  stop "a2_init: cannot coarsen to given value"
77  else
78  min_lvl = 1
79  end if
80 
81  ! up to lvl_limit_a+1 to add dummies that are always of size zero
82  allocate(tree%lvls(min_lvl:lvl_limit_a+1))
83 
84  do lvl = min_lvl, lvl_limit_a+1
85  allocate(tree%lvls(lvl)%ids(0))
86  allocate(tree%lvls(lvl)%leaves(0))
87  allocate(tree%lvls(lvl)%parents(0))
88  end do
89 
90  tree%n_cell = n_cell
91  tree%n_var_cell = n_var_cell
92  tree%n_var_face = n_var_face
93  tree%r_base = r_min_a
94  tree%dr_base = dr
95  tree%lvl_limit = lvl_limit_a
96  tree%highest_id = 0
97  tree%highest_lvl = 0
98  tree%coord_t = coord_a
99 
100  ! Calculate size of a box
101  box_bytes = a2_box_bytes(n_cell, n_var_cell, n_var_face)
102  tree%box_limit = nint(gb_limit * 2.0_dp**30 / box_bytes)
103 
104  ! Set variable names
105  allocate(tree%cc_names(n_var_cell))
106  allocate(tree%fc_names(n_var_face))
107 
108  if (present(cc_names)) then
109  if (size(cc_names) /= n_var_cell) &
110  stop "a2_init: size(cc_names) /= n_var_cell"
111  tree%cc_names = cc_names
112  else
113  do n = 1, n_var_cell
114  write(tree%cc_names(n), "(A,I0)") "cc_var", n
115  end do
116  end if
117 
118  if (present(fc_names)) then
119  if (size(fc_names) /= n_var_face) &
120  stop "a2_init: size(fc_names) /= n_var_face"
121  tree%fc_names = fc_names
122  else
123  do n = 1, n_var_face
124  write(tree%fc_names(n), "(A,I0)") "flux", n
125  end do
126  end if
127 
128  ! Initialize cell-centered methods (default is the null pointer)
129  allocate(tree%cc_methods(n_var_cell))
130  allocate(tree%has_cc_method(n_var_cell))
131  tree%has_cc_method(:) = .false.
132  allocate(tree%cc_method_vars(0))
133  end subroutine a2_init
134 
136  subroutine a2_set_cc_methods(tree, iv, bc, rb, prolong, restrict)
137  use m_a2_ghostcell, only: a2_gc_interp
138  use m_a2_prolong, only: a2_prolong_linear
139  use m_a2_restrict, only: a2_restrict_box
140  type(a2_t), intent(inout) :: tree
141  integer, intent(in) :: iv
142  procedure(a2_subr_bc) :: bc
143  procedure(a2_subr_rb), optional :: rb
144  procedure(a2_subr_prolong), optional :: prolong
145  procedure(a2_subr_restrict), optional :: restrict
146  integer :: i, n
147  tree%cc_methods(iv)%bc => bc
148 
149  if (present(rb)) then
150  tree%cc_methods(iv)%rb => rb
151  else
152  tree%cc_methods(iv)%rb => a2_gc_interp
153  end if
154 
155  if (present(prolong)) then
156  tree%cc_methods(iv)%prolong => prolong
157  else
158  tree%cc_methods(iv)%prolong => a2_prolong_linear
159  end if
160 
161  if (present(restrict)) then
162  tree%cc_methods(iv)%restrict => restrict
163  else
164  tree%cc_methods(iv)%restrict => a2_restrict_box
165  end if
166 
167  tree%has_cc_method(iv) = .true.
168  n = size(tree%cc_method_vars)
169  tree%cc_method_vars = [(tree%cc_method_vars(i), i=1,n), iv]
170  end subroutine a2_set_cc_methods
171 
174  subroutine a2_destroy(tree)
175  type(a2_t), intent(inout) :: tree
176 
177  if (.not. tree%ready) stop "a2_destroy: Tree not fully initialized"
178  deallocate(tree%boxes)
179  deallocate(tree%lvls)
180  deallocate(tree%cc_names)
181  deallocate(tree%fc_names)
182  deallocate(tree%cc_methods)
183  deallocate(tree%has_cc_method)
184  deallocate(tree%cc_method_vars)
185 
186  tree%highest_id = 0
187  tree%ready = .false.
188  end subroutine a2_destroy
189 
196  subroutine a2_set_base(tree, n_boxes, ix_list, nb_list)
198  type(a2_t), intent(inout) :: tree
200  integer, intent(in) :: n_boxes
202  integer, intent(in) :: ix_list(2, n_boxes)
204  integer, intent(inout), optional :: nb_list(a2_num_neighbors, n_boxes)
205  integer :: n, id, nb, nb_id
206  integer :: ix(2), lvl, offset
207  integer :: ix_min(2), ix_max(2), nb_ix(2)
208  integer :: nb_used(a2_num_neighbors, size(ix_list, 2))
209  integer, allocatable :: id_array(:, :)
210 
211  if (n_boxes < 1) stop "a2_set_base: need at least one box"
212  if (any(ix_list < 1)) stop "a2_set_base: need all ix_list > 0"
213  if (tree%highest_id > 0) stop "a2_set_base: this tree already has boxes"
214  if (.not. allocated(tree%lvls)) stop "a2_set_base: tree not initialized"
215 
216  if (present(nb_list)) then
217  nb_used = nb_list
218  else
219  nb_used = af_no_box ! Default value
220  end if
221 
222  ! Create an array covering the coarse grid, in which boxes are indicated by
223  ! their id.
224  do n = 1, 2
225  ! -1 and +1 to also include 'neighbors' of the coarse grid
226  ix_min(n) = minval(ix_list(n, :)) - 1
227  ix_max(n) = maxval(ix_list(n, :)) + 1
228  end do
229 
230  allocate(id_array(ix_min(1):ix_max(1), ix_min(2):ix_max(2)))
231 
232  ! Store box ids in the index array covering the coarse grid
233  id_array = af_no_box
234 
235  do id = 1, n_boxes
236  ix = ix_list(:, id)
237  id_array(ix(1), ix(2)) = id
238  end do
239 
240  ! Loop over the boxes and set their neighbors
241  do id = 1, n_boxes
242  ix = ix_list(:, id)
243 
244  do nb = 1, a2_num_neighbors
245  ! Compute ix of neighbor
246  nb_ix = ix + a2_neighb_dix(:, nb)
247  nb_id = id_array(nb_ix(1), nb_ix(2))
248 
249  if (nb_id /= af_no_box) then
250  ! Neighbor present, so store id
251  nb_used(nb, id) = nb_id
252  else
253  ! A periodic or boundary condition
254  nb_id = nb_used(nb, id)
255 
256  if (nb_id > af_no_box) then
257  ! If periodic, copy connectivity information to other box
258  nb_used(a2_neighb_rev(nb), nb_id) = id
259  else if (nb_id == af_no_box) then
260  ! The value af_no_box is converted to af_phys_boundary,
261  ! indicating the default boundary condition
262  nb_used(nb, id) = af_phys_boundary
263  end if
264  end if
265 
266  end do
267  end do
268 
269  if (any(nb_used == af_no_box)) stop "a2_set_base: unresolved neighbors"
270 
271  ! Check if we have enough space, if not, increase space
272  if (n_boxes > size(tree%boxes(:))) then
273  call a2_resize_box_storage(tree, n_boxes)
274  end if
275 
276  ! Create coarser levels which are copies of lvl 1
277  do lvl = lbound(tree%lvls, 1), 1
278  deallocate(tree%lvls(lvl)%ids)
279  allocate(tree%lvls(lvl)%ids(n_boxes))
280 
281  call get_free_ids(tree, tree%lvls(lvl)%ids)
282  offset = tree%lvls(lvl)%ids(1) - 1
283 
284  do n = 1, n_boxes
285  id = tree%lvls(lvl)%ids(n)
286  ix = ix_list(:, n)
287  tree%boxes(id)%lvl = lvl
288  tree%boxes(id)%ix = ix
289  tree%boxes(id)%dr = tree%dr_base * 0.5_dp**(lvl-1)
290  tree%boxes(id)%r_min = tree%r_base + &
291  (ix - 1) * tree%dr_base * tree%n_cell
292  tree%boxes(id)%n_cell = tree%n_cell / (2**(1-lvl))
293  tree%boxes(id)%coord_t = tree%coord_t
294 
295  tree%boxes(id)%parent = af_no_box
296  tree%boxes(id)%children(:) = af_no_box ! Gets overwritten, see below
297 
298  ! Connectivity is the same for all lvls
299  where (nb_used(:, n) > af_no_box)
300  tree%boxes(id)%neighbors = nb_used(:, n) + offset
301  elsewhere
302  tree%boxes(id)%neighbors = nb_used(:, n)
303  end where
304 
305  tree%boxes(id)%neighbor_mat = af_no_box
306 
307  call a2_init_box(tree%boxes(id), tree%boxes(id)%n_cell, &
308  tree%n_var_cell, tree%n_var_face)
309  end do
310 
311  if (lvl == 1) then
312  deallocate(tree%lvls(lvl)%leaves)
313  allocate(tree%lvls(lvl)%leaves(n_boxes))
314  tree%lvls(lvl)%leaves = tree%lvls(lvl)%ids
315  else
316  deallocate(tree%lvls(lvl)%parents)
317  allocate(tree%lvls(lvl)%parents(n_boxes))
318  tree%lvls(lvl)%parents = tree%lvls(lvl)%ids
319  end if
320 
321  if (lvl > lbound(tree%lvls, 1)) then
322  tree%boxes(tree%lvls(lvl-1)%ids)%children(1) = &
323  tree%lvls(lvl)%ids
324  tree%boxes(tree%lvls(lvl)%ids)%parent = &
325  tree%lvls(lvl-1)%ids
326  end if
327  end do
328 
329  ! Set the diagonal neighbors
330  do lvl = lbound(tree%lvls, 1), 1
331  do n = 1, n_boxes
332  id = tree%lvls(lvl)%ids(n)
333  call set_neighbor_mat(tree%boxes, id)
334  end do
335  end do
336 
337  tree%highest_lvl = 1
338  tree%ready = .true.
339 
340  end subroutine a2_set_base
341 
342  subroutine set_neighbor_mat(boxes, id)
343  type(box2_t), intent(inout) :: boxes(:)
344  integer, intent(in) :: id
345  integer :: i, j, directions(2), ndir, nb_id
346 
347  do j = -1, 1; do i = -1, 1
348  if (boxes(id)%neighbor_mat(i, j) /= af_no_box) cycle
349 
350  ndir = 0
351 
352  if (i /= 0) then
353  ndir = ndir + 1
354  directions(ndir) = a2_neighb_lowx + (i + 1)/2
355  end if
356 
357  if (j /= 0) then
358  ndir = ndir + 1
359  directions(ndir) = a2_neighb_lowy + (j + 1)/2
360  end if
361 
362  boxes(id)%neighbor_mat(i, j) = &
363  find_neighb_id(boxes, id, directions(1:ndir))
364 
365  nb_id = boxes(id)%neighbor_mat(i, j)
366 
367  if (nb_id > af_no_box) then
368  boxes(nb_id)%neighbor_mat(-i, -j) = id
369  end if
370  end do; end do
371 
372  end subroutine set_neighbor_mat
373 
376  pure function find_neighb_id(boxes, id, nbs) result(nb_id)
377  type(box2_t), intent(in) :: boxes(:)
378  integer, intent(in) :: id
379  integer, intent(in) :: nbs(:) ! List of neighbor directions
380  integer :: i, j, k, nb, nb_id
381  integer :: nbs_perm(size(nbs))
382 
383  nb_id = id
384 
385  if (size(nbs) == 0) then
386  return
387  else
388  do i = 1, size(nbs)
389  nb_id = id
390 
391  ! Check if path exists starting from nbs(i)
392  do j = 1, size(nbs)
393  ! k starts at i and runs over the neighbors
394  k = 1 + mod(i + j - 2, size(nbs))
395  nb = nbs(k)
396 
397  nb_id = boxes(nb_id)%neighbors(nb)
398  if (nb_id <= af_no_box) exit
399  end do
400 
401  if (nb_id > af_no_box) exit ! Found it
402  end do
403  end if
404 
405  ! For a corner neighbor in 3D, try again using the permuted neighbor list to
406  ! covers all paths
407  if (size(nbs) == 3 .and. nb_id <= af_no_box) then
408  nbs_perm = nbs([2,1,3])
409 
410  do i = 1, size(nbs)
411  nb_id = id
412 
413  do j = 1, size(nbs)
414  k = 1 + mod(i + j - 2, size(nbs))
415  nb = nbs(k)
416 
417  nb_id = boxes(nb_id)%neighbors(nb)
418  if (nb_id <= af_no_box) exit
419  end do
420 
421  if (nb_id > af_no_box) exit ! Found it
422  end do
423  end if
424 
425  end function find_neighb_id
426 
428  subroutine a2_tidy_up(tree, max_hole_frac, n_clean_min)
430  type(a2_t), intent(inout) :: tree
432  real(dp), intent(in) :: max_hole_frac
434  integer, intent(in) :: n_clean_min
435  real(dp) :: hole_frac
436  integer :: n, lvl, id, n_clean, i, j
437  integer :: highest_id, n_used, n_stored, n_used_lvl
438  integer, allocatable :: ixs_sort(:), ixs_map(:)
439  type(box2_t), allocatable :: boxes_cpy(:)
440  integer(morton_k), allocatable :: mortons(:)
441 
442  if (.not. tree%ready) stop "Tree not ready"
443  if (max_hole_frac < 0) stop "a2_tidy_up: need max_hole_frac >= 0"
444  if (n_clean_min < 0) stop "a2_tidy_up: need n_clean_min >= 0"
445 
446  highest_id = tree%highest_id
447  n_used = a2_num_boxes_used(tree)
448  hole_frac = 1 - n_used / real(highest_id, dp)
449  n_clean = nint(hole_frac * highest_id)
450 
451  if (hole_frac > max_hole_frac .and. n_clean >= n_clean_min) then
452  allocate(boxes_cpy(n_used))
453  allocate(ixs_map(0:highest_id))
454  ixs_map(0) = 0
455  n_stored = 0
456 
457  do lvl = lbound(tree%lvls, 1), tree%highest_lvl
458  n_used_lvl = size(tree%lvls(lvl)%ids)
459  allocate(mortons(n_used_lvl))
460  allocate(ixs_sort(n_used_lvl))
461 
462  do n = 1, n_used_lvl
463  id = tree%lvls(lvl)%ids(n)
464  ! Note the -1, since our indices start at 1
465  mortons(n) = morton_from_ix2(tree%boxes(id)%ix-1)
466  end do
467 
468  call morton_rank(mortons, ixs_sort)
469  tree%lvls(lvl)%ids = tree%lvls(lvl)%ids(ixs_sort)
470 
471  do n = 1, n_used_lvl
472  id = tree%lvls(lvl)%ids(n)
473  boxes_cpy(n_stored + n) = tree%boxes(id)
474  ixs_map(tree%lvls(lvl)%ids(n)) = n_stored + n
475  end do
476 
477  tree%lvls(lvl)%ids = [(n_stored+n, n=1,n_used_lvl)]
478  call set_leaves_parents(boxes_cpy, tree%lvls(lvl))
479  n_stored = n_stored + n_used_lvl
480  deallocate(mortons)
481  deallocate(ixs_sort)
482  end do
483 
484  ! Update id's to new indices
485  do n = 1, n_used
486  boxes_cpy(n)%parent = ixs_map(boxes_cpy(n)%parent)
487  boxes_cpy(n)%children = ixs_map(boxes_cpy(n)%children)
488  where (boxes_cpy(n)%neighbors > af_no_box)
489  boxes_cpy(n)%neighbors = ixs_map(boxes_cpy(n)%neighbors)
490  end where
491 
492  do j = -1, 1; do i = -1, 1
493  if (boxes_cpy(n)%neighbor_mat(i, j) > af_no_box) then
494  boxes_cpy(n)%neighbor_mat(i, j) = &
495  ixs_map(boxes_cpy(n)%neighbor_mat(i, j))
496  end if
497  end do; end do
498  end do
499 
500  tree%boxes(1:n_used) = boxes_cpy ! Copy ordered data
501  do n = n_used+1, highest_id
502  if (tree%boxes(n)%in_use) then
503  ! Remove moved data
504  call clear_box(tree%boxes(n))
505  end if
506  end do
507 
508  tree%highest_id = n_used
509  end if
510 
511  end subroutine a2_tidy_up
512 
514  subroutine set_leaves_parents(boxes, level)
515  type(box2_t), intent(in) :: boxes(:)
516  type(lvl_t), intent(inout) :: level
517  integer :: i, id, i_leaf, i_parent
518  integer :: n_parents, n_leaves
519 
520  n_parents = count(a2_has_children(boxes(level%ids)))
521  n_leaves = size(level%ids) - n_parents
522 
523  if (n_parents /= size(level%parents)) then
524  deallocate(level%parents)
525  allocate(level%parents(n_parents))
526  end if
527 
528  if (n_leaves /= size(level%leaves)) then
529  deallocate(level%leaves)
530  allocate(level%leaves(n_leaves))
531  end if
532 
533  i_leaf = 0
534  i_parent = 0
535  do i = 1, size(level%ids)
536  id = level%ids(i)
537  if (a2_has_children(boxes(id))) then
538  i_parent = i_parent + 1
539  level%parents(i_parent) = id
540  else
541  i_leaf = i_leaf + 1
542  level%leaves(i_leaf) = id
543  end if
544  end do
545  end subroutine set_leaves_parents
546 
549  subroutine a2_init_box(box, n_cell, n_cc, n_fc)
550  type(box2_t), intent(inout) :: box
551  integer, intent(in) :: n_cell
552  integer, intent(in) :: n_cc
553  integer, intent(in) :: n_fc
554 
555  box%in_use = .true.
556 
557  allocate(box%cc(0:n_cell+1, 0:n_cell+1, n_cc))
558  allocate(box%fc(n_cell+1, n_cell+1, 2, n_fc))
559 
560  ! Initialize to zero
561  box%cc = 0
562  box%fc = 0
563  end subroutine a2_init_box
564 
566  subroutine clear_box(box)
567  type(box2_t), intent(inout) :: box
568 
569  box%in_use = .false.
570 
571  deallocate(box%cc)
572  deallocate(box%fc)
573  end subroutine clear_box
574 
575  ! Set the neighbors of id (using their parent)
576  subroutine set_neighbs_2d(boxes, id)
577  type(box2_t), intent(inout) :: boxes(:)
578  integer, intent(in) :: id
579  integer :: nb, nb_id, i, j
580 
581  do j = -1, 1; do i = -1, 1
582  if (boxes(id)%neighbor_mat(i, j) == af_no_box) then
583  nb_id = find_neighb_2d(boxes, id, [i, j])
584  if (nb_id > af_no_box) then
585  boxes(id)%neighbor_mat(i, j) = nb_id
586  boxes(nb_id)%neighbor_mat(-i, -j) = id
587  end if
588  end if
589  end do; end do
590 
591  do nb = 1, a2_num_neighbors
592  if (boxes(id)%neighbors(nb) == af_no_box) then
593  nb_id = boxes(id)%neighbor_mat(a2_neighb_dix(1, nb), &
594  a2_neighb_dix(2, nb))
595  if (nb_id > af_no_box) then
596  boxes(id)%neighbors(nb) = nb_id
597  boxes(nb_id)%neighbors(a2_neighb_rev(nb)) = id
598  end if
599  end if
600  end do
601  end subroutine set_neighbs_2d
602 
604  function find_neighb_2d(boxes, id, dix) result(nb_id)
605  type(box2_t), intent(in) :: boxes(:)
606  integer, intent(in) :: id
607  integer, intent(in) :: dix(2)
608  integer :: nb_id, p_id, c_ix, dix_c(2)
609 
610  p_id = boxes(id)%parent
611  c_ix = a2_ix_to_ichild(boxes(id)%ix)
612 
613  ! Check if neighbor is in same direction as dix is (low/high). If so, use
614  ! neighbor of parent
615  where ((dix == -1) .eqv. a2_child_low(:, c_ix))
616  dix_c = dix
617  elsewhere
618  dix_c = 0
619  end where
620 
621  p_id = boxes(p_id)%neighbor_mat(dix_c(1), dix_c(2))
622 
623  if (p_id <= af_no_box) then
624  nb_id = p_id
625  else
626  c_ix = a2_ix_to_ichild(boxes(id)%ix + dix)
627  nb_id = boxes(p_id)%children(c_ix)
628  end if
629  end function find_neighb_2d
630 
632  subroutine a2_resize_box_storage(tree, new_size)
633  type(a2_t), intent(inout) :: tree
634  integer, intent(in) :: new_size
635  type(box2_t), allocatable :: boxes_cpy(:)
636 
637  if (.not. tree%ready) stop "a2_resize_box_storage: Tree not ready"
638  if (new_size < tree%highest_id) &
639  stop "a2_resize_box_storage: Cannot shrink tree"
640 
641  ! Store boxes in larger array boxes_cpy
642  allocate(boxes_cpy(new_size))
643  boxes_cpy(1:tree%highest_id) = tree%boxes(1:tree%highest_id)
644 
645  ! Deallocate current storage
646  deallocate(tree%boxes)
647 
648  ! Use new array
649  call move_alloc(boxes_cpy, tree%boxes)
650  end subroutine a2_resize_box_storage
651 
658  subroutine a2_adjust_refinement(tree, ref_subr, ref_info, ref_buffer, keep_buffer)
659  type(a2_t), intent(inout) :: tree
660  procedure(a2_subr_ref) :: ref_subr
661  type(ref_info_t), intent(inout) :: ref_info
662  integer, intent(in), optional :: ref_buffer
663  logical, intent(in), optional :: keep_buffer
664  integer :: lvl, id, i, c_ids(a2_num_children)
665  integer :: highest_id_prev, highest_id_req
666  integer, allocatable :: ref_flags(:)
667  integer :: num_new_boxes, total_num_boxes
668  integer :: new_size, ref_buffer_val
669  logical :: keep_buffer_val
670 
671  if (.not. tree%ready) stop "Tree not ready"
672 
673  ref_buffer_val = 0 ! Default buffer width (in cells) around refinement
674  if (present(ref_buffer)) ref_buffer_val = ref_buffer
675  keep_buffer_val = .false. ! Do not use a buffer for 'keep refinement' flags
676  if (present(keep_buffer)) keep_buffer_val = keep_buffer
677 
678  if (ref_buffer_val < 0) &
679  error stop "a2_adjust_refinement: ref_buffer < 0"
680  if (ref_buffer_val > tree%n_cell) &
681  error stop "a2_adjust_refinement: ref_buffer > tree%n_cell"
682 
683  ! Check whether the boxes array contains many holes, and if this is the
684  ! case, reorganize the array
685  call a2_tidy_up(tree, 0.5_dp, 1000)
686 
687  highest_id_prev = tree%highest_id
688  allocate(ref_flags(highest_id_prev))
689 
690  ! Set refinement values for all boxes
691  call consistent_ref_flags(tree, ref_flags, ref_subr, &
692  ref_buffer_val, keep_buffer_val)
693 
694  ! Compute number of new boxes
695  num_new_boxes = a2_num_children * count(ref_flags == af_refine)
696 
697  ! Determine number of boxes that could be in use after resizing
698  total_num_boxes = a2_num_boxes_used(tree) + num_new_boxes
699 
700  if (total_num_boxes > tree%box_limit) then
701  print *, "a2_adjust_refinement: exceeding memory limit"
702  write(*, '(A,E12.2)') " memory_limit (GByte): ", &
703  tree%box_limit * 0.5_dp**30 * &
704  a2_box_bytes(tree%n_cell, tree%n_var_cell, tree%n_var_face)
705  print *, "memory_limit (boxes): ", tree%box_limit
706  print *, "required number of boxes: ", total_num_boxes
707  print *, "You can increase the memory limit in your call to a2_init"
708  print *, "by setting mem_limit_gb to a higher value (in GBytes)"
709  error stop
710  end if
711 
712  ! Resize box storage if required
713  highest_id_req = highest_id_prev + num_new_boxes
714  if (highest_id_req > size(tree%boxes)) then
715  new_size = 2 * highest_id_req ! Allocate some extra empty boxes
716  call a2_resize_box_storage(tree, new_size)
717  end if
718 
719  do lvl = 1, tree%lvl_limit-1
720  do i = 1, size(tree%lvls(lvl)%ids)
721  id = tree%lvls(lvl)%ids(i)
722 
723  if (id > highest_id_prev) then
724  cycle ! This is a newly added box
725  else if (ref_flags(id) == af_refine) then
726  ! Add children. First need to get num_children free id's
727  call get_free_ids(tree, c_ids)
728  call add_children(tree%boxes, id, c_ids, &
729  tree%n_var_cell, tree%n_var_face)
730  else if (ref_flags(id) == af_derefine) then
731  ! Remove children
732  call auto_restrict(tree, id)
733  call remove_children(tree%boxes, id)
734  end if
735  end do
736 
737  ! Update leaves / parents
738  call set_leaves_parents(tree%boxes, tree%lvls(lvl))
739 
740  ! Set next level ids to children of this level
741  call set_child_ids(tree%lvls(lvl)%parents, &
742  tree%lvls(lvl+1)%ids, tree%boxes)
743 
744  ! Update connectivity of new children (id > highest_id_prev)
745  do i = 1, size(tree%lvls(lvl+1)%ids)
746  id = tree%lvls(lvl+1)%ids(i)
747  if (id > highest_id_prev) call set_neighbs_2d(tree%boxes, id)
748  end do
749 
750  if (size(tree%lvls(lvl+1)%ids) == 0) exit
751  end do
752 
753  tree%highest_lvl = lvl
754 
755  ! We still have to update leaves and parents for the last level, which is
756  ! either lvl+1 or lvl_limit. Note that lvl+1 is empty now, but maybe it was
757  ! not not empty before, and that lvl_limit is skipped in the above loop.
758  lvl = min(lvl+1, tree%lvl_limit)
759  call set_leaves_parents(tree%boxes, tree%lvls(lvl))
760 
761  ! Set information about the refinement
762  call set_ref_info(tree, ref_flags, ref_info)
763 
764  call auto_prolong(tree, ref_info)
765 
766  end subroutine a2_adjust_refinement
767 
769  subroutine auto_restrict(tree, id)
770  type(a2_t), intent(inout) :: tree
771  integer, intent(in) :: id
772  integer :: iv, i_ch, ch_id
773 
774  if (.not. any(tree%has_cc_method(:))) return
775 
776  do iv = 1, tree%n_var_cell
777  if (tree%has_cc_method(iv)) then
778  do i_ch = 1, a2_num_children
779  ch_id = tree%boxes(id)%children(i_ch)
780  call tree%cc_methods(iv)%restrict(tree%boxes(ch_id), &
781  tree%boxes(id), iv)
782  end do
783  end if
784  end do
785  end subroutine auto_restrict
786 
788  subroutine auto_prolong(tree, ref_info)
789  use m_a2_ghostcell, only: a2_gc_box
790  type(a2_t), intent(inout) :: tree
791  type(ref_info_t), intent(in) :: ref_info
792  integer :: lvl, i, n, iv, id, p_id
793 
794  ! Skip this routine when it won't do anything
795  if (.not. any(tree%has_cc_method(:)) .or. ref_info%n_add == 0) then
796  return
797  end if
798 
799  !$omp parallel private(lvl, i, n, iv, id, p_id)
800  do lvl = 1, tree%highest_lvl
801  !$omp do
802  do i = 1, size(ref_info%lvls(lvl)%add)
803  id = ref_info%lvls(lvl)%add(i)
804  p_id = tree%boxes(id)%parent
805 
806  do n = 1, size(tree%cc_method_vars)
807  iv = tree%cc_method_vars(n)
808  call tree%cc_methods(iv)%prolong(tree%boxes(p_id), &
809  tree%boxes(id), iv)
810  end do
811  end do
812  !$omp end do
813 
814  !$omp do
815  do i = 1, size(ref_info%lvls(lvl)%add)
816  id = ref_info%lvls(lvl)%add(i)
817  call a2_gc_box(tree, id, [tree%cc_method_vars])
818  end do
819  !$omp end do
820  end do
821  !$omp end parallel
822  end subroutine auto_prolong
823 
825  subroutine set_ref_info(tree, ref_flags, ref_info)
826  type(a2_t), intent(in) :: tree
827  integer, intent(in) :: ref_flags(:)
828  type(ref_info_t), intent(inout) :: ref_info
829  integer :: id, lvl, n, n_ch
830  integer, allocatable :: ref_count(:), drf_count(:)
831 
832  n_ch = a2_num_children
833  ref_info%n_add = n_ch * count(ref_flags == af_refine)
834  ref_info%n_rm = n_ch * count(ref_flags == af_derefine)
835 
836  ! Use highest_lvl+1 here because this lvl might have been completely removed
837  if (allocated(ref_info%lvls)) deallocate(ref_info%lvls)
838  allocate(ref_info%lvls(tree%highest_lvl+1))
839  allocate(ref_count(tree%highest_lvl+1))
840  allocate(drf_count(tree%highest_lvl+1))
841 
842  ! Find the number of (de)refined boxes per level
843  ref_count = 0
844  drf_count = 0
845 
846  do id = 1, size(ref_flags)
847  lvl = tree%boxes(id)%lvl
848 
849  if (ref_flags(id) == af_refine) then
850  ref_count(lvl) = ref_count(lvl) + 1
851  else if (ref_flags(id) == af_derefine) then
852  drf_count(lvl) = drf_count(lvl) + 1
853  end if
854  end do
855 
856  ! Allocate storage per level
857  ! There can be no new children at level 1
858  allocate(ref_info%lvls(1)%add(0))
859  allocate(ref_info%lvls(1)%rm(0))
860 
861  do lvl = 2, tree%highest_lvl+1
862  n = ref_count(lvl-1) * n_ch
863  allocate(ref_info%lvls(lvl)%add(n))
864  n = drf_count(lvl-1) * n_ch
865  allocate(ref_info%lvls(lvl)%rm(n))
866  end do
867 
868  ! Set the added and removed id's per level, these are the children of the
869  ! (de)refined boxes
870  ref_count = 0
871  drf_count = 0
872 
873  do id = 1, size(ref_flags)
874  lvl = tree%boxes(id)%lvl
875 
876  if (ref_flags(id) == af_refine) then
877  ref_count(lvl) = ref_count(lvl) + 1
878  n = n_ch * (ref_count(lvl)-1) + 1
879  ref_info%lvls(lvl+1)%add(n:n+n_ch-1) = tree%boxes(id)%children
880  else if (ref_flags(id) == af_derefine) then
881  drf_count(lvl) = drf_count(lvl) + 1
882  n = n_ch * (drf_count(lvl)-1) + 1
883  ref_info%lvls(lvl+1)%rm(n:n+n_ch-1) = tree%boxes(id)%children
884  end if
885  end do
886  end subroutine set_ref_info
887 
890  subroutine get_free_ids(tree, ids)
891  type(a2_t), intent(inout) :: tree
892  integer, intent(out) :: ids(:)
893  integer :: i, highest_id_prev, n_ids
894 
895  n_ids = size(ids)
896  !$omp critical (crit_free_ids)
897  highest_id_prev = tree%highest_id
898  tree%highest_id = tree%highest_id + n_ids
899  !$omp end critical (crit_free_ids)
900 
901  ids = [(highest_id_prev + i, i=1,n_ids)]
902  end subroutine get_free_ids
903 
909  subroutine consistent_ref_flags(tree, ref_flags, ref_subr, &
910  ref_buffer, keep_buffer)
911  use omp_lib, only: omp_get_max_threads, omp_get_thread_num
912  type(a2_t), intent(inout) :: tree
913  integer, intent(inout) :: ref_flags(:)
914  procedure(a2_subr_ref) :: ref_subr
915  integer, intent(in) :: ref_buffer
916  logical, intent(in) :: keep_buffer
917 
918  integer :: lvl, i, i_ch, ch_id, id, c_ids(a2_num_children)
919  integer :: nb, p_id, nb_id, p_nb_id
920  integer :: lvl_limit, thread_id
921  integer, allocatable :: tmp_flags(:, :)
922  integer :: cell_flags(tree%n_cell, tree%n_cell)
923  integer, parameter :: unset_flag = -huge(1)
924 
925  ! Set refinement flags for each thread individually, because we sometimes
926  ! modify the refinement flags of neighbors
927  allocate(tmp_flags(size(ref_flags), omp_get_max_threads()))
928 
929  lvl_limit = tree%lvl_limit
930  tmp_flags(:, :) = unset_flag
931 
932  ! Set refinement flags on all leaves and their immediate parents (on other
933  ! boxes the flags would not matter)
934 
935  !$omp parallel private(lvl, i, id, p_id, cell_flags, thread_id, i_ch, ch_id)
936  thread_id = omp_get_thread_num() + 1
937 
938  do lvl = 1, tree%highest_lvl
939  !$omp do
940  do i = 1, size(tree%lvls(lvl)%leaves)
941  id = tree%lvls(lvl)%leaves(i)
942 
943  call ref_subr(tree%boxes(id), cell_flags)
944  call cell_to_ref_flags(cell_flags, tree%n_cell, &
945  tmp_flags(:, thread_id), tree, id, ref_buffer, keep_buffer)
946 
947  ! If the parent exists, and this is the first child which is itself
948  ! not refined, set refinement flags for the parent
949  if (tree%boxes(id)%lvl > 1) then
950  p_id = tree%boxes(id)%parent
951  do i_ch = 1, a2_ix_to_ichild(tree%boxes(id)%ix)-1
952  ch_id = tree%boxes(p_id)%children(i_ch)
953  if (.not. a2_has_children(tree%boxes(ch_id))) exit
954  end do
955 
956  if (i_ch == a2_ix_to_ichild(tree%boxes(id)%ix)) then
957  ! This is the first child which is itself not refined
958  call ref_subr(tree%boxes(p_id), cell_flags)
959  call cell_to_ref_flags(cell_flags, tree%n_cell, &
960  tmp_flags(:, thread_id), tree, p_id, ref_buffer, keep_buffer)
961  end if
962  end if
963  end do
964  !$omp end do
965  end do
966  !$omp end parallel
967 
968  ! Take the highest value over the threads
969  do i = 1, size(ref_flags)
970  ref_flags(i) = maxval(tmp_flags(i, :))
971  if (ref_flags(i) == unset_flag) ref_flags(i) = af_keep_ref
972  end do
973 
974  if (maxval(ref_flags) > af_do_ref .or. minval(ref_flags) < af_rm_ref) &
975  stop "a2_adjust_refinement: invalid refinement flag given"
976 
977  ! Cannot refine beyond max level
978  do i = 1, size(tree%lvls(lvl_limit)%ids)
979  id = tree%lvls(lvl_limit)%ids(i)
980  if (ref_flags(id) == af_do_ref) ref_flags(id) = af_keep_ref
981  end do
982 
983  ! Ensure 2-1 balance
984  do lvl = tree%highest_lvl, 1, -1
985  do i = 1, size(tree%lvls(lvl)%leaves) ! We only check leaf tree%boxes
986  id = tree%lvls(lvl)%leaves(i)
987 
988  if (ref_flags(id) == af_do_ref .or. ref_flags(id) == af_refine) then
989  ref_flags(id) = af_refine ! Mark for actual refinement
990 
991  ! Ensure we will have the necessary neighbors
992  do nb = 1, a2_num_neighbors
993  nb_id = tree%boxes(id)%neighbors(nb)
994  if (nb_id == af_no_box) then
995  ! Mark the parent containing neighbor for refinement
996  p_id = tree%boxes(id)%parent
997  p_nb_id = tree%boxes(p_id)%neighbors(nb)
998  ref_flags(p_nb_id) = af_refine
999  end if
1000  end do
1001 
1002  else if (ref_flags(id) == af_rm_ref) then
1003  ! Ensure we do not remove a required neighbor
1004  do nb = 1, a2_num_neighbors
1005  nb_id = tree%boxes(id)%neighbors(nb)
1006  if (nb_id > af_no_box) then
1007  if (a2_has_children(tree%boxes(nb_id)) .or. &
1008  ref_flags(nb_id) > af_keep_ref) then
1009  ref_flags(id) = af_keep_ref
1010  exit
1011  end if
1012  end if
1013  end do
1014  end if
1015 
1016  end do
1017  end do
1018 
1019  ! Make the (de)refinement flags consistent for blocks with children. Also
1020  ! ensure that at most one level can be removed at a time.
1021  do lvl = tree%highest_lvl-1, 1, -1
1022  do i = 1, size(tree%lvls(lvl)%parents)
1023  id = tree%lvls(lvl)%parents(i)
1024 
1025  ! Can only remove children if they are all marked for
1026  ! derefinement, and the box itself not for refinement.
1027  c_ids = tree%boxes(id)%children
1028  if (all(ref_flags(c_ids) == af_rm_ref) .and. &
1029  ref_flags(id) <= af_keep_ref) then
1030  ref_flags(id) = af_derefine
1031  else
1032  ref_flags(id) = af_keep_ref
1033  end if
1034  end do
1035  end do
1036 
1037  end subroutine consistent_ref_flags
1038 
1042  subroutine cell_to_ref_flags(cell_flags, nc, ref_flags, tree, id, &
1043  ref_buffer, keep_buffer)
1044  use m_a2_utils, only: a2_get_loc
1045  integer, intent(in) :: nc
1046  integer, intent(in) :: cell_flags(nc, nc)
1047  integer, intent(inout) :: ref_flags(:)
1048  type(a2_t), intent(in) :: tree
1049  integer, intent(in) :: id
1050  integer, intent(in) :: ref_buffer
1051  logical, intent(in) :: keep_buffer
1052  integer :: ix0(2), ix1(2), i, j, nb_id
1053 
1054  if (minval(cell_flags) < af_rm_ref .or. &
1055  maxval(cell_flags) > af_do_ref) then
1056  error stop "Error: invalid cell flags given"
1057  end if
1058 
1059  ! Check whether the box needs to be refined or keep its refinement
1060  if (any(cell_flags == af_do_ref)) then
1061  ref_flags(id) = af_do_ref
1062  else if (any(cell_flags == af_keep_ref)) then
1063  ref_flags(id) = max(ref_flags(id), af_keep_ref)
1064  else ! All flags are af_rm_ref
1065  ref_flags(id) = max(ref_flags(id), af_rm_ref)
1066  end if
1067 
1068  if (ref_buffer <= 0) return ! No need to check neighbors
1069 
1070  ! Check whether neighbors also require refinement, which happens when cells
1071  ! close to the neighbor are flagged.
1072  do j = -1, 1; do i = -1, 1
1073  if (all([i, j] == 0)) cycle
1074 
1075  nb_id = tree%boxes(id)%neighbor_mat(i, j)
1076 
1077  ! Skip neighbors that are not there
1078  if (nb_id <= af_no_box) cycle
1079 
1080  ! Compute index range relevant for neighbor
1081  ix0 = 1
1082  ix1 = nc
1083  where ([i, j] == 1)
1084  ix0 = nc - ref_buffer + 1
1085  ix1 = nc
1086  elsewhere ([i, j] == -1)
1087  ix0 = 1
1088  ix1 = ref_buffer
1089  end where
1090 
1091  if (any(cell_flags(ix0(1):ix1(1), ix0(2):ix1(2)) == af_do_ref)) then
1092  ref_flags(nb_id) = af_do_ref
1093  else if (keep_buffer .and. &
1094  any(cell_flags(ix0(1):ix1(1), ix0(2):ix1(2)) == af_keep_ref)) then
1095  ref_flags(nb_id) = max(ref_flags(nb_id), af_keep_ref)
1096  end if
1097  end do; end do
1098 
1099  end subroutine cell_to_ref_flags
1100 
1102  subroutine remove_children(boxes, id)
1103  type(box2_t), intent(inout) :: boxes(:)
1104  integer, intent(in) :: id
1105  integer :: ic, c_id, nb_id, nb_rev, nb, i, j
1106 
1107  do ic = 1, a2_num_children
1108  c_id = boxes(id)%children(ic)
1109 
1110  ! Remove from neighbors
1111  do nb = 1, a2_num_neighbors
1112  nb_id = boxes(c_id)%neighbors(nb)
1113  if (nb_id > af_no_box) then
1114  nb_rev = a2_neighb_rev(nb)
1115  boxes(nb_id)%neighbors(nb_rev) = af_no_box
1116  end if
1117  end do
1118 
1119  do j = -1, 1; do i = -1, 1
1120  nb_id = boxes(c_id)%neighbor_mat(i, j)
1121  if (nb_id > af_no_box) then
1122  boxes(nb_id)%neighbor_mat(-i, -j) = af_no_box
1123  end if
1124  end do; end do
1125 
1126  call clear_box(boxes(c_id))
1127  end do
1128 
1129  boxes(id)%children = af_no_box
1130  end subroutine remove_children
1131 
1133  subroutine add_children(boxes, id, c_ids, n_cc, n_fc)
1134  type(box2_t), intent(inout) :: boxes(:)
1135  integer, intent(in) :: id
1136  integer, intent(in) :: c_ids(a2_num_children)
1137  integer, intent(in) :: n_cc
1138  integer, intent(in) :: n_fc
1139  integer :: i, nb, child_nb(2**(2-1))
1140  integer :: c_id, c_ix_base(2), dix(2)
1141 
1142  boxes(id)%children = c_ids
1143  c_ix_base = 2 * boxes(id)%ix - 1
1144 
1145  do i = 1, a2_num_children
1146  c_id = c_ids(i)
1147  boxes(c_id)%ix = c_ix_base + a2_child_dix(:,i)
1148  boxes(c_id)%lvl = boxes(id)%lvl+1
1149  boxes(c_id)%parent = id
1150  boxes(c_id)%tag = af_init_tag
1151  boxes(c_id)%children = af_no_box
1152  boxes(c_id)%neighbors = af_no_box
1153  boxes(c_id)%neighbor_mat = af_no_box
1154  boxes(c_id)%neighbor_mat(0, 0) = c_id
1155  boxes(c_id)%n_cell = boxes(id)%n_cell
1156  boxes(c_id)%coord_t = boxes(id)%coord_t
1157  boxes(c_id)%dr = 0.5_dp * boxes(id)%dr
1158  boxes(c_id)%r_min = boxes(id)%r_min + 0.5_dp * boxes(id)%dr * &
1159  a2_child_dix(:,i) * boxes(id)%n_cell
1160 
1161  call a2_init_box(boxes(c_id), boxes(id)%n_cell, n_cc, n_fc)
1162  end do
1163 
1164  ! Set boundary conditions at children
1165  do nb = 1, a2_num_neighbors
1166  if (boxes(id)%neighbors(nb) < af_no_box) then
1167  child_nb = c_ids(a2_child_adj_nb(:, nb)) ! Neighboring children
1168  boxes(child_nb)%neighbors(nb) = boxes(id)%neighbors(nb)
1169  dix = a2_neighb_dix(:, nb)
1170  boxes(child_nb)%neighbor_mat(dix(1), dix(2)) = &
1171  boxes(id)%neighbors(nb)
1172  end if
1173  end do
1174  end subroutine add_children
1175 
1178  subroutine set_child_ids(p_ids, c_ids, boxes)
1179  integer, intent(in) :: p_ids(:)
1180  integer, allocatable, intent(inout) :: c_ids(:)
1181  type(box2_t), intent(in) :: boxes(:)
1182  integer :: i, i0, i1, n_children
1183 
1184  n_children = a2_num_children * size(p_ids)
1185  if (n_children /= size(c_ids)) then
1186  deallocate(c_ids)
1187  allocate(c_ids(n_children))
1188  end if
1189 
1190  do i = 1, size(p_ids)
1191  i1 = i * a2_num_children
1192  i0 = i1 - a2_num_children + 1
1193  c_ids(i0:i1) = boxes(p_ids(i))%children
1194  end do
1195  end subroutine set_child_ids
1196 
1198  subroutine a2_consistent_fluxes(tree, f_ixs)
1199  type(a2_t), intent(inout) :: tree
1200  integer, intent(in) :: f_ixs(:)
1201  integer :: lvl, i, id, nb, nb_id
1202 
1203  if (.not. tree%ready) stop "Tree not ready"
1204  !$omp parallel private(lvl, i, id, nb, nb_id)
1205  do lvl = lbound(tree%lvls, 1), tree%highest_lvl-1
1206  !$omp do
1207  do i = 1, size(tree%lvls(lvl)%parents)
1208  id = tree%lvls(lvl)%parents(i)
1209  do nb = 1, a2_num_neighbors
1210  nb_id = tree%boxes(id)%neighbors(nb)
1211 
1212  ! If the neighbor exists and has no children, set flux
1213  if (nb_id > af_no_box) then
1214  if (.not. a2_has_children(tree%boxes(nb_id))) then
1215  call flux_from_children(tree%boxes, id, nb, f_ixs)
1216  end if
1217  end if
1218  end do
1219  end do
1220  !$omp end do
1221  end do
1222  !$omp end parallel
1223  end subroutine a2_consistent_fluxes
1224 
1227  subroutine flux_from_children(boxes, id, nb, f_ixs)
1228  type(box2_t), intent(inout) :: boxes(:)
1229  integer, intent(in) :: id
1230  integer, intent(in) :: nb
1231  integer, intent(in) :: f_ixs(:)
1232  integer :: nc, nch, c_id, i_ch, i, ic, d
1233  integer :: n_chnb, nb_id, i_nb, ioff(2)
1234  integer :: n
1235  real(dp) :: w1, w2
1236 
1237  nc = boxes(id)%n_cell
1238  nch = ishft(nc, -1) ! nc/2
1239  d = a2_neighb_dim(nb)
1240  n_chnb = 2**(2-1)
1241  nb_id = boxes(id)%neighbors(nb)
1242 
1243  if (a2_neighb_low(nb)) then
1244  i = 1
1245  i_nb = nc+1
1246  else
1247  i = nc+1
1248  i_nb = 1
1249  end if
1250 
1251  select case (d)
1252  case (1)
1253  do ic = 1, n_chnb
1254  ! Get index of child adjacent to neighbor
1255  i_ch = a2_child_adj_nb(ic, nb)
1256  c_id = boxes(id)%children(i_ch)
1257  ! Index offset of child w.r.t. parent
1258  ioff = nch*a2_child_dix(:, i_ch)
1259  boxes(nb_id)%fc(i_nb, ioff(2)+1:ioff(2)+nch, 1, f_ixs) = 0.5_dp * ( &
1260  boxes(c_id)%fc(i, 1:nc:2, 1, f_ixs) + &
1261  boxes(c_id)%fc(i, 2:nc:2, 1, f_ixs))
1262  end do
1263  case (2)
1264  if (boxes(nb_id)%coord_t == af_cyl) then
1265  ! In cylindrical symmetry, we take the weighted average
1266  do ic = 1, n_chnb
1267  i_ch = a2_child_adj_nb(ic, nb)
1268  c_id = boxes(id)%children(i_ch)
1269  ioff = nch*a2_child_dix(:, i_ch)
1270 
1271  do n = 1, nch
1272  call a2_cyl_child_weights(boxes(nb_id), ioff(1)+n, w1, w2)
1273  boxes(nb_id)%fc(ioff(1)+n, i_nb, 2, f_ixs) = 0.5_dp * (&
1274  w1 * boxes(c_id)%fc(2*n-1, i, 2, f_ixs) + &
1275  w2 * boxes(c_id)%fc(2*n, i, 2, f_ixs))
1276  end do
1277  end do
1278  else
1279  ! Just take the average of the fine fluxes
1280  do ic = 1, n_chnb
1281  i_ch = a2_child_adj_nb(ic, nb)
1282  c_id = boxes(id)%children(i_ch)
1283  ioff = nch*a2_child_dix(:, i_ch)
1284  boxes(nb_id)%fc(ioff(1)+1:ioff(1)+nch, i_nb, 2, f_ixs) = 0.5_dp * ( &
1285  boxes(c_id)%fc(1:nc:2, i, 2, f_ixs) + &
1286  boxes(c_id)%fc(2:nc:2, i, 2, f_ixs))
1287  end do
1288  end if
1289  end select
1290  end subroutine flux_from_children
1291 
1292 end module m_a2_core
This module contains methods to convert indices to morton numbers.
Definition: m_morton.f90:7
Subroutine for prolongation.
Definition: m_a2_types.f90:197
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 the core routines of Afivo, namely those that deal with initializing and changin...
Definition: m_a2_core.f90:4
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
Subroutine for restriction.
Definition: m_a2_types.f90:207
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