11 public :: a2_set_cc_methods
16 public :: a2_resize_box_storage
17 public :: a2_adjust_refinement
18 public :: a2_consistent_fluxes
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
43 character(len=*),
intent(in),
optional :: cc_names(:)
45 character(len=*),
intent(in),
optional :: fc_names(:)
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
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
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" 68 allocate(tree%boxes(n_boxes_a))
70 if (coarsen_to_a > 0)
then 73 min_lvl = 1 - nint(log(
real(n_cell, dp)/coarsen_to_a)/log(2.0_dp))
75 if (2**(1-min_lvl) * coarsen_to_a /= n_cell) &
76 stop
"a2_init: cannot coarsen to given value" 82 allocate(tree%lvls(min_lvl:lvl_limit_a+1))
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))
91 tree%n_var_cell = n_var_cell
92 tree%n_var_face = n_var_face
95 tree%lvl_limit = lvl_limit_a
98 tree%coord_t = coord_a
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)
105 allocate(tree%cc_names(n_var_cell))
106 allocate(tree%fc_names(n_var_face))
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
114 write(tree%cc_names(n),
"(A,I0)")
"cc_var", n
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
124 write(tree%fc_names(n),
"(A,I0)")
"flux", n
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
136 subroutine a2_set_cc_methods(tree, iv, bc, rb, prolong, restrict)
140 type(
a2_t),
intent(inout) :: tree
141 integer,
intent(in) :: iv
147 tree%cc_methods(iv)%bc => bc
149 if (
present(rb))
then 150 tree%cc_methods(iv)%rb => rb
152 tree%cc_methods(iv)%rb => a2_gc_interp
155 if (
present(prolong))
then 156 tree%cc_methods(iv)%prolong => prolong
158 tree%cc_methods(iv)%prolong => a2_prolong_linear
161 if (
present(restrict))
then 162 tree%cc_methods(iv)%restrict => restrict
164 tree%cc_methods(iv)%restrict => a2_restrict_box
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
174 subroutine a2_destroy(tree)
175 type(
a2_t),
intent(inout) :: tree
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)
188 end subroutine a2_destroy
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(:, :)
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" 216 if (
present(nb_list))
then 226 ix_min(n) = minval(ix_list(n, :)) - 1
227 ix_max(n) = maxval(ix_list(n, :)) + 1
230 allocate(id_array(ix_min(1):ix_max(1), ix_min(2):ix_max(2)))
237 id_array(ix(1), ix(2)) = id
244 do nb = 1, a2_num_neighbors
246 nb_ix = ix + a2_neighb_dix(:, nb)
247 nb_id = id_array(nb_ix(1), nb_ix(2))
249 if (nb_id /= af_no_box)
then 251 nb_used(nb, id) = nb_id
254 nb_id = nb_used(nb, id)
256 if (nb_id > af_no_box)
then 258 nb_used(a2_neighb_rev(nb), nb_id) = id
259 else if (nb_id == af_no_box)
then 262 nb_used(nb, id) = af_phys_boundary
269 if (any(nb_used == af_no_box)) stop
"a2_set_base: unresolved neighbors" 272 if (n_boxes >
size(tree%boxes(:)))
then 273 call a2_resize_box_storage(tree, n_boxes)
277 do lvl = lbound(tree%lvls, 1), 1
278 deallocate(tree%lvls(lvl)%ids)
279 allocate(tree%lvls(lvl)%ids(n_boxes))
281 call get_free_ids(tree, tree%lvls(lvl)%ids)
282 offset = tree%lvls(lvl)%ids(1) - 1
285 id = tree%lvls(lvl)%ids(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
295 tree%boxes(id)%parent = af_no_box
296 tree%boxes(id)%children(:) = af_no_box
299 where (nb_used(:, n) > af_no_box)
300 tree%boxes(id)%neighbors = nb_used(:, n) + offset
302 tree%boxes(id)%neighbors = nb_used(:, n)
305 tree%boxes(id)%neighbor_mat = af_no_box
307 call a2_init_box(tree%boxes(id), tree%boxes(id)%n_cell, &
308 tree%n_var_cell, tree%n_var_face)
312 deallocate(tree%lvls(lvl)%leaves)
313 allocate(tree%lvls(lvl)%leaves(n_boxes))
314 tree%lvls(lvl)%leaves = tree%lvls(lvl)%ids
316 deallocate(tree%lvls(lvl)%parents)
317 allocate(tree%lvls(lvl)%parents(n_boxes))
318 tree%lvls(lvl)%parents = tree%lvls(lvl)%ids
321 if (lvl > lbound(tree%lvls, 1))
then 322 tree%boxes(tree%lvls(lvl-1)%ids)%children(1) = &
324 tree%boxes(tree%lvls(lvl)%ids)%parent = &
330 do lvl = lbound(tree%lvls, 1), 1
332 id = tree%lvls(lvl)%ids(n)
333 call set_neighbor_mat(tree%boxes, id)
340 end subroutine a2_set_base
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
347 do j = -1, 1;
do i = -1, 1
348 if (boxes(id)%neighbor_mat(i, j) /= af_no_box) cycle
354 directions(ndir) = a2_neighb_lowx + (i + 1)/2
359 directions(ndir) = a2_neighb_lowy + (j + 1)/2
362 boxes(id)%neighbor_mat(i, j) = &
363 find_neighb_id(boxes, id, directions(1:ndir))
365 nb_id = boxes(id)%neighbor_mat(i, j)
367 if (nb_id > af_no_box)
then 368 boxes(nb_id)%neighbor_mat(-i, -j) = id
372 end subroutine set_neighbor_mat
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(:)
380 integer :: i, j, k, nb, nb_id
381 integer :: nbs_perm(size(nbs))
385 if (
size(nbs) == 0)
then 394 k = 1 + mod(i + j - 2,
size(nbs))
397 nb_id = boxes(nb_id)%neighbors(nb)
398 if (nb_id <= af_no_box)
exit 401 if (nb_id > af_no_box)
exit 407 if (
size(nbs) == 3 .and. nb_id <= af_no_box)
then 408 nbs_perm = nbs([2,1,3])
414 k = 1 + mod(i + j - 2,
size(nbs))
417 nb_id = boxes(nb_id)%neighbors(nb)
418 if (nb_id <= af_no_box)
exit 421 if (nb_id > af_no_box)
exit 425 end function find_neighb_id
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(:)
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" 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)
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))
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))
463 id = tree%lvls(lvl)%ids(n)
465 mortons(n) = morton_from_ix2(tree%boxes(id)%ix-1)
468 call morton_rank(mortons, ixs_sort)
469 tree%lvls(lvl)%ids = tree%lvls(lvl)%ids(ixs_sort)
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
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
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)
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))
500 tree%boxes(1:n_used) = boxes_cpy
501 do n = n_used+1, highest_id
502 if (tree%boxes(n)%in_use)
then 504 call clear_box(tree%boxes(n))
508 tree%highest_id = n_used
511 end subroutine a2_tidy_up
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
520 n_parents = count(a2_has_children(boxes(level%ids)))
521 n_leaves =
size(level%ids) - n_parents
523 if (n_parents /=
size(level%parents))
then 524 deallocate(level%parents)
525 allocate(level%parents(n_parents))
528 if (n_leaves /=
size(level%leaves))
then 529 deallocate(level%leaves)
530 allocate(level%leaves(n_leaves))
535 do i = 1,
size(level%ids)
537 if (a2_has_children(boxes(id)))
then 538 i_parent = i_parent + 1
539 level%parents(i_parent) = id
542 level%leaves(i_leaf) = id
545 end subroutine set_leaves_parents
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
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))
563 end subroutine a2_init_box
566 subroutine clear_box(box)
567 type(box2_t),
intent(inout) :: box
573 end subroutine clear_box
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
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
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
601 end subroutine set_neighbs_2d
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)
610 p_id = boxes(id)%parent
611 c_ix = a2_ix_to_ichild(boxes(id)%ix)
615 where ((dix == -1) .eqv. a2_child_low(:, c_ix))
621 p_id = boxes(p_id)%neighbor_mat(dix_c(1), dix_c(2))
623 if (p_id <= af_no_box)
then 626 c_ix = a2_ix_to_ichild(boxes(id)%ix + dix)
627 nb_id = boxes(p_id)%children(c_ix)
629 end function find_neighb_2d
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(:)
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" 642 allocate(boxes_cpy(new_size))
643 boxes_cpy(1:tree%highest_id) = tree%boxes(1:tree%highest_id)
646 deallocate(tree%boxes)
649 call move_alloc(boxes_cpy, tree%boxes)
650 end subroutine a2_resize_box_storage
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
671 if (.not. tree%ready) stop
"Tree not ready" 674 if (
present(ref_buffer)) ref_buffer_val = ref_buffer
675 keep_buffer_val = .false.
676 if (
present(keep_buffer)) keep_buffer_val = keep_buffer
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" 685 call a2_tidy_up(tree, 0.5_dp, 1000)
687 highest_id_prev = tree%highest_id
688 allocate(ref_flags(highest_id_prev))
691 call consistent_ref_flags(tree, ref_flags, ref_subr, &
692 ref_buffer_val, keep_buffer_val)
695 num_new_boxes = a2_num_children * count(ref_flags == af_refine)
698 total_num_boxes = a2_num_boxes_used(tree) + num_new_boxes
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)" 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
716 call a2_resize_box_storage(tree, new_size)
719 do lvl = 1, tree%lvl_limit-1
720 do i = 1,
size(tree%lvls(lvl)%ids)
721 id = tree%lvls(lvl)%ids(i)
723 if (id > highest_id_prev)
then 725 else if (ref_flags(id) == af_refine)
then 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 732 call auto_restrict(tree, id)
733 call remove_children(tree%boxes, id)
738 call set_leaves_parents(tree%boxes, tree%lvls(lvl))
741 call set_child_ids(tree%lvls(lvl)%parents, &
742 tree%lvls(lvl+1)%ids, tree%boxes)
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)
750 if (
size(tree%lvls(lvl+1)%ids) == 0)
exit 753 tree%highest_lvl = lvl
758 lvl = min(lvl+1, tree%lvl_limit)
759 call set_leaves_parents(tree%boxes, tree%lvls(lvl))
762 call set_ref_info(tree, ref_flags, ref_info)
764 call auto_prolong(tree, ref_info)
766 end subroutine a2_adjust_refinement
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
774 if (.not. any(tree%has_cc_method(:)))
return 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), &
785 end subroutine auto_restrict
788 subroutine auto_prolong(tree, ref_info)
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
795 if (.not. any(tree%has_cc_method(:)) .or. ref_info%n_add == 0)
then 800 do lvl = 1, tree%highest_lvl
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
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), &
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])
822 end subroutine auto_prolong
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(:)
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)
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))
846 do id = 1,
size(ref_flags)
847 lvl = tree%boxes(id)%lvl
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
858 allocate(ref_info%lvls(1)%add(0))
859 allocate(ref_info%lvls(1)%rm(0))
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))
873 do id = 1,
size(ref_flags)
874 lvl = tree%boxes(id)%lvl
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
886 end subroutine set_ref_info
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
897 highest_id_prev = tree%highest_id
898 tree%highest_id = tree%highest_id + n_ids
901 ids = [(highest_id_prev + i, i=1,n_ids)]
902 end subroutine get_free_ids
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
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)
927 allocate(tmp_flags(
size(ref_flags), omp_get_max_threads()))
929 lvl_limit = tree%lvl_limit
930 tmp_flags(:, :) = unset_flag
936 thread_id = omp_get_thread_num() + 1
938 do lvl = 1, tree%highest_lvl
940 do i = 1,
size(tree%lvls(lvl)%leaves)
941 id = tree%lvls(lvl)%leaves(i)
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)
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 956 if (i_ch == a2_ix_to_ichild(tree%boxes(id)%ix))
then 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)
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
974 if (maxval(ref_flags) > af_do_ref .or. minval(ref_flags) < af_rm_ref) &
975 stop
"a2_adjust_refinement: invalid refinement flag given" 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
984 do lvl = tree%highest_lvl, 1, -1
985 do i = 1,
size(tree%lvls(lvl)%leaves)
986 id = tree%lvls(lvl)%leaves(i)
988 if (ref_flags(id) == af_do_ref .or. ref_flags(id) == af_refine)
then 989 ref_flags(id) = af_refine
992 do nb = 1, a2_num_neighbors
993 nb_id = tree%boxes(id)%neighbors(nb)
994 if (nb_id == af_no_box)
then 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
1002 else if (ref_flags(id) == af_rm_ref)
then 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
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)
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
1032 ref_flags(id) = af_keep_ref
1037 end subroutine consistent_ref_flags
1042 subroutine cell_to_ref_flags(cell_flags, nc, ref_flags, tree, id, &
1043 ref_buffer, keep_buffer)
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
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" 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)
1065 ref_flags(id) = max(ref_flags(id), af_rm_ref)
1068 if (ref_buffer <= 0)
return 1072 do j = -1, 1;
do i = -1, 1
1073 if (all([i, j] == 0)) cycle
1075 nb_id = tree%boxes(id)%neighbor_mat(i, j)
1078 if (nb_id <= af_no_box) cycle
1084 ix0 = nc - ref_buffer + 1
1086 elsewhere ([i, j] == -1)
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)
1099 end subroutine cell_to_ref_flags
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
1107 do ic = 1, a2_num_children
1108 c_id = boxes(id)%children(ic)
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
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
1126 call clear_box(boxes(c_id))
1129 boxes(id)%children = af_no_box
1130 end subroutine remove_children
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)
1142 boxes(id)%children = c_ids
1143 c_ix_base = 2 * boxes(id)%ix - 1
1145 do i = 1, a2_num_children
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
1161 call a2_init_box(boxes(c_id), boxes(id)%n_cell, n_cc, n_fc)
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))
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)
1174 end subroutine add_children
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
1184 n_children = a2_num_children *
size(p_ids)
1185 if (n_children /=
size(c_ids))
then 1187 allocate(c_ids(n_children))
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
1195 end subroutine set_child_ids
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
1203 if (.not. tree%ready) stop
"Tree not ready" 1205 do lvl = lbound(tree%lvls, 1), tree%highest_lvl-1
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)
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)
1223 end subroutine a2_consistent_fluxes
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)
1237 nc = boxes(id)%n_cell
1239 d = a2_neighb_dim(nb)
1241 nb_id = boxes(id)%neighbors(nb)
1243 if (a2_neighb_low(nb))
then 1255 i_ch = a2_child_adj_nb(ic, nb)
1256 c_id = boxes(id)%children(i_ch)
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))
1264 if (boxes(nb_id)%coord_t == af_cyl)
then 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)
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))
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))
1290 end subroutine flux_from_children
This module contains methods to convert indices to morton numbers.
Subroutine for prolongation.
This module contains all kinds of different 'helper' routines for Afivo. If the number of routines fo...
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...
This module contains the basic types and constants that are used in the 2-dimensional version of Afiv...
To fill ghost cells near physical boundaries.
This module contains the core routines of Afivo, namely those that deal with initializing and changin...
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...
Subroutine for restriction.
To fill ghost cells near refinement boundaries.
The basic building block of afivo: a box with cell-centered and face centered data, and information about its position, neighbors, children etc.