Afivo 0.3
Loading...
Searching...
No Matches
m_af_core.f90
1!> This module contains the core routines of Afivo, namely those that deal with
2!> initializing and changing the quadtree/octree mesh.
4#include "cpp_macros.h"
5 use m_af_types
6
7 implicit none
8 private
9
10 public :: af_add_cc_variable
11 public :: af_add_fc_variable
12 public :: af_find_cc_variable
13 public :: af_find_fc_variable
14 public :: af_init
15 public :: af_set_cc_methods
16 public :: af_init_box
17 public :: af_destroy
18 public :: af_adjust_refinement
19 public :: af_refine_up_to_lvl
20 public :: af_consistent_fluxes
21
22contains
23
24 !> Add cell-centered variable
25 !> @todo ix as third argument?
26 subroutine af_add_cc_variable(tree, name, write_out, n_copies, &
27 ix, write_binary)
28 !> Tree to add variable to
29 type(af_t), intent(inout) :: tree
30 !> Name of the variable
31 character(len=*), intent(in) :: name
32 !> Include variable in output
33 logical, intent(in), optional :: write_out
34 !> Include variable in binary output (for restarting)
35 logical, intent(in), optional :: write_binary
36 !> How many copies of variable to store (default: 1)
37 integer, intent(in), optional :: n_copies
38 !> On output: index of variable
39 integer, intent(out), optional :: ix
40
41 integer :: n, ncpy
42 logical :: writeout, writebin
43
44 ncpy = 1; if (present(n_copies)) ncpy = n_copies
45 writeout = .true.; if (present(write_out)) writeout = write_out
46 writebin = .true.; if (present(write_binary)) writebin = write_binary
47
48 if (ncpy < 1) error stop "af_add_cc_variable: n_copies < 1"
49
50 if (tree%n_var_cell + ncpy > af_max_num_vars) then
51 print *, "af_max_num_vars:", af_max_num_vars
52 print *, "Cannot add ", name
53 error stop "Too many cc variables"
54 end if
55
56 do n = 1, ncpy
57 tree%n_var_cell = tree%n_var_cell + 1
58 if (n == 1) then
59 if (present(ix)) ix = tree%n_var_cell
60 tree%cc_names(tree%n_var_cell) = name
61 tree%cc_write_output(tree%n_var_cell) = writeout
62 tree%cc_write_binary(tree%n_var_cell) = writebin
63 tree%cc_num_copies(tree%n_var_cell) = ncpy
64 else
65 write(tree%cc_names(tree%n_var_cell), "(A,I0)") &
66 trim(name) // '_', n
67 tree%cc_write_output(tree%n_var_cell) = .false.
68 tree%cc_write_binary(tree%n_var_cell) = .false.
69 tree%cc_num_copies(tree%n_var_cell) = 0
70 end if
71 end do
72
73 end subroutine af_add_cc_variable
74
75 !> Add face-centered variable
76 subroutine af_add_fc_variable(tree, name, ix, write_binary)
77 !> Tree to add variable to
78 type(af_t), intent(inout) :: tree
79 !> Name of the variable
80 character(len=*), intent(in) :: name
81 !> On output: index of variable
82 integer, intent(out), optional :: ix
83 !> Include variable in binary output
84 logical, intent(in), optional :: write_binary
85 logical :: writebin
86
87 writebin = .true.; if (present(write_binary)) writebin = write_binary
88
89 if (tree%n_var_face + 1 > af_max_num_vars) then
90 print *, "af_max_num_vars:", af_max_num_vars
91 print *, "Cannot add ", name
92 error stop "Too many fc variables"
93 end if
94
95 tree%n_var_face = tree%n_var_face + 1
96 tree%fc_names(tree%n_var_face) = name
97 tree%fc_write_binary(tree%n_var_face) = writebin
98 if (present(ix)) ix = tree%n_var_face
99 end subroutine af_add_fc_variable
100
101 !> Find index of cell-centered variable
102 integer function af_find_cc_variable(tree, name)
103 type(af_t), intent(in) :: tree
104 character(len=*), intent(in) :: name
105 integer :: n
106
107 do n = 1, tree%n_var_cell
108 if (tree%cc_names(n) == name) exit
109 end do
110
111 if (n == tree%n_var_cell+1) then
112 print *, "variable name: ", trim(name)
113 error stop "af_find_cc_variable: variable not found"
114 end if
115
116 af_find_cc_variable = n
117 end function af_find_cc_variable
118
119 !> Find index of face-centered variable
120 integer function af_find_fc_variable(tree, name)
121 type(af_t), intent(in) :: tree
122 character(len=*), intent(in) :: name
123 integer :: n
124
125 do n = 1, tree%n_var_face
126 if (tree%fc_names(n) == name) exit
127 end do
128
129 if (n == tree%n_var_face+1) then
130 print *, "variable name: ", trim(name)
131 error stop "af_find_fc_variable: variable not found"
132 end if
133
134 af_find_fc_variable = n
135 end function af_find_fc_variable
136
137 !> Initialize a NDIM-d octree/quadtree grid
138 subroutine af_init(tree, n_cell, r_max, grid_size, periodic, r_min, coord, &
139 mem_limit_gb, box_limit)
140 type(af_t), intent(inout) :: tree !< The tree to initialize
141 integer, intent(in) :: n_cell !< Boxes have n_cell^dim cells
142 real(dp), intent(in) :: r_max(ndim) !< Maximal coordinates of the domain
143 integer, intent(in) :: grid_size(ndim) !< Size of the coarse grid
144 logical, intent(in), optional :: periodic(ndim) !< True for periodic dimensions
145 real(dp), intent(in), optional :: r_min(ndim) !< Lowest coordinate, default is (0., 0., 0.)
146 integer, intent(in), optional :: coord !< Select coordinate type
147 real(dp), intent(in), optional :: mem_limit_gb !< Memory limit in GByte
148 !> Maximum number of boxes (overrides mem_limit_gb)
149 integer, intent(in), optional :: box_limit
150
151 real(dp) :: r_min_a(ndim), gb_limit
152 integer :: lvl, coord_a, box_bytes
153
154 ! Set default arguments if not present
155 r_min_a = 0.0_dp; if (present(r_min)) r_min_a = r_min
156 coord_a = af_xyz; if (present(coord)) coord_a = coord
157 gb_limit = 4; if (present(mem_limit_gb)) gb_limit = mem_limit_gb
158
159 if (tree%ready) stop "af_init: tree was already initialized"
160 if (n_cell < 2) stop "af_init: n_cell should be >= 2"
161 if (btest(n_cell, 0)) stop "af_init: n_cell should be even"
162 if (gb_limit <= 0) stop "af_init: mem_limit_gb should be > 0"
163 if (coord_a == af_cyl .and. ndim /= 2) stop "af_init: cyl. coords only in 2d"
164 if (tree%n_var_cell <= 0) stop "af_init: no cell-centered variables present"
165
166 do lvl = af_min_lvl, af_max_lvl
167 allocate(tree%lvls(lvl)%ids(0))
168 allocate(tree%lvls(lvl)%leaves(0))
169 allocate(tree%lvls(lvl)%parents(0))
170 end do
171
172 tree%n_cell = n_cell
173 tree%r_base = r_min_a
174 tree%dr_base = (r_max - r_min_a) / grid_size
175 tree%highest_id = 0
176 tree%highest_lvl = 0
177 tree%coord_t = coord_a
178
179 if (present(box_limit)) then
180 if (box_limit <= 0) stop "af_init: box_limit should be > 0"
181 tree%box_limit = box_limit
182 else
183 ! Calculate size of a box
184 box_bytes = af_box_bytes(n_cell, tree%n_var_cell, tree%n_var_face)
185 tree%box_limit = nint(gb_limit * 2.0_dp**30 / box_bytes)
186 end if
187
188 ! Allocate the full list of boxes
189 allocate(tree%boxes(tree%box_limit))
190
191 ! This list can probably be a bit smaller
192 tree%n_removed_ids = 0
193 allocate(tree%removed_ids(tree%box_limit))
194
195 ! Initialize list of cell-centered variables with methods
196 if (.not. allocated(tree%cc_auto_vars)) &
197 allocate(tree%cc_auto_vars(0))
198 if (.not. allocated(tree%cc_func_vars)) &
199 allocate(tree%cc_func_vars(0))
200
201 call af_set_coarse_grid(tree, grid_size, periodic)
202
203 end subroutine af_init
204
205 !> Create the coarse grid
206 subroutine af_set_coarse_grid(tree, coarse_grid_size, periodic_dims)
207 !> Tree for which we set the base
208 type(af_t), intent(inout) :: tree
209 !> Size of coarse grid (in cells)
210 integer, intent(in) :: coarse_grid_size(NDIM)
211 !> Whether dimensions are periodic (default: false)
212 logical, intent(in), optional :: periodic_dims(NDIM)
213 logical :: periodic(NDIM)
214 integer :: nx(NDIM), ix(NDIM), IJK, id, n_boxes, nb
215 integer :: n, iv
216 integer, allocatable :: id_array(DTIMES(:))
217
218 if (tree%highest_id > 0) &
219 error stop "af_set_coarse_grid: this tree already has boxes"
220 if (.not. allocated(tree%boxes)) &
221 error stop "af_set_coarse_grid: tree not initialized"
222 if (any(coarse_grid_size < tree%n_cell)) &
223 error stop "af_set_coarse_grid: coarse_grid_size < tree%n_cell"
224 if (any(modulo(coarse_grid_size, tree%n_cell) /= 0)) &
225 error stop "af_set_coarse_grid: coarse_grid_size not divisible by tree%n_cell"
226
227 periodic(:) = .false.; if (present(periodic_dims)) periodic = periodic_dims
228
229 tree%coarse_grid_size(1:ndim) = coarse_grid_size
230 tree%periodic(1:ndim) = periodic
231 tree%ready = .true.
232
233 nx = coarse_grid_size / tree%n_cell
234 n_boxes = product(nx)
235
236 ! For easy lookup of box neighbors
237 call create_index_array(nx, periodic, id_array)
238
239 ! Check if we have enough space
240 if (n_boxes > size(tree%boxes(:))) &
241 error stop "Not enough memory available for coarse grid"
242
243 ! Create level 1
244 deallocate(tree%lvls(1)%ids)
245 allocate(tree%lvls(1)%ids(n_boxes))
246
247 ! The ids are simply 1, 2, 3, ..., N
248 call get_free_ids(tree, tree%lvls(1)%ids)
249 tree%lvls(1)%leaves = tree%lvls(1)%ids
250
251 ! Loop over the boxes and set their neighbors
252#if NDIM == 1
253 do i = 1, nx(1)
254 id = id_array(ijk)
255 tree%boxes(id)%lvl = 1
256 tree%boxes(id)%ix = [ijk]
257 tree%boxes(id)%dr = tree%dr_base
258 tree%boxes(id)%r_min = tree%r_base + &
259 (tree%boxes(id)%ix - 1) * tree%dr_base * tree%n_cell
260 tree%boxes(id)%n_cell = tree%n_cell
261 tree%boxes(id)%coord_t = tree%coord_t
262
263 tree%boxes(id)%parent = af_no_box
264 tree%boxes(id)%children(:) = af_no_box
265
266 ! Connectivity
267 do nb = 1, af_num_neighbors
268 ix = [ijk] + af_neighb_dix(:, nb)
269 tree%boxes(id)%neighbors(nb) = id_array(ix(1))
270 end do
271 tree%boxes(id)%neighbor_mat = id_array(i-1:i+1)
272
273 call af_init_box(tree, id)
274 end do
275#elif NDIM == 2
276 do j = 1, nx(2)
277 do i = 1, nx(1)
278 id = id_array(ijk)
279 tree%boxes(id)%lvl = 1
280 tree%boxes(id)%ix = [ijk]
281 tree%boxes(id)%dr = tree%dr_base
282 tree%boxes(id)%r_min = tree%r_base + &
283 (tree%boxes(id)%ix - 1) * tree%dr_base * tree%n_cell
284 tree%boxes(id)%n_cell = tree%n_cell
285 tree%boxes(id)%coord_t = tree%coord_t
286
287 tree%boxes(id)%parent = af_no_box
288 tree%boxes(id)%children(:) = af_no_box
289
290 ! Connectivity
291 do nb = 1, af_num_neighbors
292 ix = [ijk] + af_neighb_dix(:, nb)
293 tree%boxes(id)%neighbors(nb) = id_array(ix(1), ix(2))
294 end do
295 tree%boxes(id)%neighbor_mat = id_array(i-1:i+1, j-1:j+1)
296
297 call af_init_box(tree, id)
298 end do
299 end do
300#elif NDIM == 3
301 do k = 1, nx(3)
302 do j = 1, nx(2)
303 do i = 1, nx(1)
304 id = id_array(ijk)
305 tree%boxes(id)%lvl = 1
306 tree%boxes(id)%ix = [ijk]
307 tree%boxes(id)%dr = tree%dr_base
308 tree%boxes(id)%r_min = tree%r_base + &
309 (tree%boxes(id)%ix - 1) * tree%dr_base * tree%n_cell
310 tree%boxes(id)%n_cell = tree%n_cell
311 tree%boxes(id)%coord_t = tree%coord_t
312
313 tree%boxes(id)%parent = af_no_box
314 tree%boxes(id)%children(:) = af_no_box
315
316 ! Connectivity
317 do nb = 1, af_num_neighbors
318 ix = [ijk] + af_neighb_dix(:, nb)
319 tree%boxes(id)%neighbors(nb) = id_array(ix(1), ix(2), ix(3))
320 end do
321 tree%boxes(id)%neighbor_mat = id_array(i-1:i+1, j-1:j+1, k-1:k+1)
322
323 call af_init_box(tree, id)
324 end do
325 end do
326 end do
327#endif
328
329 tree%highest_lvl = 1
330
331 ! Set values for variables with a 'funcval'
332 do i = 1, size(tree%lvls(1)%ids)
333 id = tree%lvls(1)%ids(i)
334 do n = 1, size(tree%cc_func_vars)
335 iv = tree%cc_func_vars(n)
336 call tree%cc_methods(iv)%funcval(tree%boxes(id), iv)
337 end do
338 end do
339
340 end subroutine af_set_coarse_grid
341
342 !> Set the methods for a cell-centered variable
343 subroutine af_set_cc_methods(tree, iv, bc, rb, prolong, restrict, &
344 bc_custom, funcval, prolong_limiter)
345 use m_af_ghostcell, only: af_gc_interp
346 use m_af_prolong, only: af_prolong_linear
347 use m_af_restrict, only: af_restrict_box
348 use m_af_limiters
349 type(af_t), intent(inout) :: tree !< Tree to operate on
350 integer, intent(in) :: iv !< Index of variable
351 procedure(af_subr_bc), optional :: bc !< Boundary condition method
352 procedure(af_subr_rb), optional :: rb !< Refinement boundary method
353 procedure(af_subr_prolong), optional :: prolong !< Prolongation method
354 procedure(af_subr_restrict), optional :: restrict !< Restriction method
355 procedure(af_subr_bc_custom), optional :: bc_custom !< Custom b.c. method
356 procedure(af_subr_funcval), optional :: funcval !< Variable defined by function
357 !< Type of limiter to use for prolongation (of values or ghost cells)
358 integer, intent(in), optional :: prolong_limiter
359 integer :: i
360
361 if (tree%has_cc_method(iv)) then
362 print *, "Cannot call af_set_cc_methods twice for ", &
363 trim(tree%cc_names(iv))
364 error stop
365 end if
366
367 ! Set methods for the variable and its copies
368 do i = iv, iv + tree%cc_num_copies(iv) - 1
369 if (present(bc)) then
370 tree%cc_methods(i)%bc => bc
371 else if (present(bc_custom)) then
372 tree%cc_methods(i)%bc_custom => bc_custom
373 else if (.not. present(funcval)) then
374 error stop "af_set_cc_methods: bc, bc_custom or funcval required"
375 end if
376
377 if (present(funcval)) then
378 tree%cc_methods(i)%funcval => funcval
379 end if
380
381 if (present(rb)) then
382 tree%cc_methods(i)%rb => rb
383 else
384 tree%cc_methods(i)%rb => af_gc_interp
385 end if
386
387 if (present(prolong)) then
388 tree%cc_methods(i)%prolong => prolong
389 else
390 tree%cc_methods(i)%prolong => af_prolong_linear
391 end if
392
393 if (present(restrict)) then
394 tree%cc_methods(i)%restrict => restrict
395 else
396 tree%cc_methods(i)%restrict => af_restrict_box
397 end if
398
399 if (present(prolong_limiter)) then
400 tree%cc_methods(i)%prolong_limiter = prolong_limiter
401 else if (ndim < 3) then
402 tree%cc_methods(i)%prolong_limiter = af_limiter_mc_t
403 else
404 ! To ensure the interpolation of ghost cells near refinement
405 ! boundaries is non-negative and does not create new maxima in 3D,
406 ! this limiter can be used
407 tree%cc_methods(i)%prolong_limiter = af_limiter_gminmod43_t
408 end if
409
410 tree%has_cc_method(i) = .true.
411 end do
412
413 if (.not. allocated(tree%cc_auto_vars)) &
414 allocate(tree%cc_auto_vars(0))
415 if (.not. allocated(tree%cc_func_vars)) &
416 allocate(tree%cc_func_vars(0))
417
418
419 ! Append only original variable, so that the copies are not automatically
420 ! prolongated etc.
421 if (present(funcval)) then
422 tree%cc_func_vars = [tree%cc_func_vars, iv]
423 else
424 tree%cc_auto_vars = [tree%cc_auto_vars, iv]
425 end if
426
427 end subroutine af_set_cc_methods
428
429 !> "Destroy" the data in a tree. Since we don't use pointers, you can also
430 !> just let a tree get out of scope
431 subroutine af_destroy(tree)
432 type(af_t), intent(out) :: tree
433 end subroutine af_destroy
434
435 !> Create an array for easy lookup of indices
436 subroutine create_index_array(nx, periodic, id_array)
437 integer, intent(in) :: nx(NDIM)
438 logical, intent(in) :: periodic(NDIM)
439 integer, intent(inout), allocatable :: id_array(DTIMES(:))
440 integer :: IJK
441
442#if NDIM == 1
443 allocate(id_array(0:nx(1)+1))
444#elif NDIM == 2
445 allocate(id_array(0:nx(1)+1, 0:nx(2)+1))
446#elif NDIM == 3
447 allocate(id_array(0:nx(1)+1, 0:nx(2)+1, 0:nx(3)+1))
448#endif
449
450 id_array = af_phys_boundary
451
452#if NDIM == 1
453 do i = 1, nx(1)
454 id_array(i) = i
455 end do
456
457 if (periodic(1)) then
458 id_array(0) = id_array(nx(1))
459 id_array(nx(1)+1) = id_array(1)
460 end if
461#elif NDIM == 2
462 do j = 1, nx(2)
463 do i = 1, nx(1)
464 id_array(i, j) = (j-1) * nx(1) + i
465 end do
466 end do
467
468 if (periodic(1)) then
469 id_array(0, :) = id_array(nx(1), :)
470 id_array(nx(1)+1, :) = id_array(1, :)
471 end if
472
473 if (periodic(2)) then
474 id_array(:, 0) = id_array(:, nx(2))
475 id_array(:, nx(2)+1) = id_array(:, 1)
476 end if
477#elif NDIM == 3
478 do k = 1, nx(3)
479 do j = 1, nx(2)
480 do i = 1, nx(1)
481 id_array(i, j, k) = (k-1) * nx(2) * nx(1) + (j-1) * nx(1) + i
482 end do
483 end do
484 end do
485
486 if (periodic(1)) then
487 id_array(0, :, :) = id_array(nx(1), :, :)
488 id_array(nx(1)+1, :, :) = id_array(1, :, :)
489 end if
490
491 if (periodic(2)) then
492 id_array(:, 0, :) = id_array(:, nx(2), :)
493 id_array(:, nx(2)+1, :) = id_array(:, 1, :)
494 end if
495
496 if (periodic(3)) then
497 id_array(:, :, 0) = id_array(:, :, nx(3))
498 id_array(:, :, nx(3)+1) = id_array(:, :, 1)
499 end if
500#endif
501 end subroutine create_index_array
502
503 !> Create a list of leaves and a list of parents for a level
504 subroutine set_leaves_parents(boxes, level)
505 type(box_t), intent(in) :: boxes(:) !< List of boxes
506 type(lvl_t), intent(inout) :: level !< Level type which contains the indices of boxes
507 integer :: i, id, i_leaf, i_parent
508 integer :: n_parents, n_leaves
509
510 n_parents = count(af_has_children(boxes(level%ids)))
511 n_leaves = size(level%ids) - n_parents
512
513 if (n_parents /= size(level%parents)) then
514 deallocate(level%parents)
515 allocate(level%parents(n_parents))
516 end if
517
518 if (n_leaves /= size(level%leaves)) then
519 deallocate(level%leaves)
520 allocate(level%leaves(n_leaves))
521 end if
522
523 i_leaf = 0
524 i_parent = 0
525 do i = 1, size(level%ids)
526 id = level%ids(i)
527 if (af_has_children(boxes(id))) then
528 i_parent = i_parent + 1
529 level%parents(i_parent) = id
530 else
531 i_leaf = i_leaf + 1
532 level%leaves(i_leaf) = id
533 end if
534 end do
535 end subroutine set_leaves_parents
536
537 !> Mark box as active and allocate data storage for a box, for its cell- and
538 !> face-centered data
539 subroutine af_init_box(tree, id)
540 type(af_t), intent(inout) :: tree !< Tree
541 integer, intent(in) :: id !< Box id
542 integer :: nc, ix, nb
543 logical :: new_box
544
545 associate(box => tree%boxes(id))
546 nc = tree%n_cell
547 box%in_use = .true.
548 new_box = .not. allocated(box%cc)
549
550 if (new_box) then
551 allocate(box%cc(dtimes(0:nc+1), tree%n_var_cell))
552 allocate(box%fc(dtimes(nc+1), ndim, tree%n_var_face))
553 end if
554
555 ! Initialize to zero
556 box%cc = 0
557 box%fc = 0
558
559 ! Allocate storage for boundary conditions
560 box%n_bc = count(box%neighbors < af_no_box)
561 allocate(box%bc_index_to_nb(box%n_bc))
562 allocate(box%bc_coords(ndim, nc**(ndim-1), box%n_bc))
563 allocate(box%bc_val(nc**(ndim-1), tree%n_var_cell, box%n_bc))
564 allocate(box%bc_type(tree%n_var_cell, box%n_bc))
565 box%bc_val = 0
566 box%bc_type = 0
567
568 ! Set face coordinates
569 ix = 0
570 do nb = 1, af_num_neighbors
571 if (box%neighbors(nb) < af_no_box) then
572 ix = ix + 1
573 box%bc_index_to_nb(ix) = nb
574 box%nb_to_bc_index(nb) = ix
575 call af_get_face_coords(box, nb, box%bc_coords(:, :, ix))
576 end if
577 end do
578 end associate
579 end subroutine af_init_box
580
581 !> Mark box as inactive, but keep storage for cell- and face-centered data to
582 !> avoid reallocating this
583 subroutine af_deactivate_box(box)
584 type(box_t), intent(inout) :: box
585
586 box%in_use = .false.
587 box%tag = af_init_tag
588 box%n_stencils = 0
589 if (allocated(box%stencils)) deallocate(box%stencils)
590 deallocate(box%bc_index_to_nb, box%bc_coords, &
591 box%bc_val, box%bc_type)
592 end subroutine af_deactivate_box
593
594 ! Set the neighbors of id (using their parent)
595 subroutine set_neighbs(boxes, id)
596 type(box_t), intent(inout) :: boxes(:)
597 integer, intent(in) :: id
598 integer :: nb, nb_id, IJK
599
600 do kji_do(-1, 1)
601 if (boxes(id)%neighbor_mat(ijk) == af_no_box) then
602 nb_id = find_neighb(boxes, id, [ijk])
603 if (nb_id > af_no_box) then
604 boxes(id)%neighbor_mat(ijk) = nb_id
605#if NDIM == 1
606 boxes(nb_id)%neighbor_mat(-i) = id
607#elif NDIM == 2
608 boxes(nb_id)%neighbor_mat(-i, -j) = id
609#elif NDIM == 3
610 boxes(nb_id)%neighbor_mat(-i, -j, -k) = id
611#endif
612 end if
613 end if
614 end do; close_do
615
616 do nb = 1, af_num_neighbors
617 if (boxes(id)%neighbors(nb) == af_no_box) then
618#if NDIM == 1
619 nb_id = boxes(id)%neighbor_mat(af_neighb_dix(1, nb))
620#elif NDIM == 2
621 nb_id = boxes(id)%neighbor_mat(af_neighb_dix(1, nb), &
622 af_neighb_dix(2, nb))
623#elif NDIM == 3
624 nb_id = boxes(id)%neighbor_mat(af_neighb_dix(1, nb), &
625 af_neighb_dix(2, nb), af_neighb_dix(3, nb))
626#endif
627 if (nb_id > af_no_box) then
628 boxes(id)%neighbors(nb) = nb_id
629 boxes(nb_id)%neighbors(af_neighb_rev(nb)) = id
630 end if
631 end if
632 end do
633 end subroutine set_neighbs
634
635 !> Get the id of all neighbors of boxes(id), through its parent
636 function find_neighb(boxes, id, dix) result(nb_id)
637 type(box_t), intent(in) :: boxes(:) !< List with all the boxes
638 integer, intent(in) :: id !< Box whose neighbor we are looking for
639 integer, intent(in) :: dix(ndim)
640 integer :: nb_id, p_id, c_ix, dix_c(ndim)
641
642 p_id = boxes(id)%parent
643 c_ix = af_ix_to_ichild(boxes(id)%ix)
644
645 ! Check if neighbor is in same direction as dix is (low/high). If so, use
646 ! neighbor of parent
647 where ((dix == -1) .eqv. af_child_low(:, c_ix))
648 dix_c = dix
649 elsewhere
650 dix_c = 0
651 end where
652
653 p_id = boxes(p_id)%neighbor_mat(dindex(dix_c))
654
655 if (p_id <= af_no_box) then
656 nb_id = p_id
657 else
658 c_ix = af_ix_to_ichild(boxes(id)%ix + dix)
659 nb_id = boxes(p_id)%children(c_ix)
660 end if
661 end function find_neighb
662
663 !> Refine a new tree up to a given refinement lvl
664 subroutine af_refine_up_to_lvl(tree, lvl)
665 type(af_t), intent(inout) :: tree !< The tree to adjust
666 integer, intent(in) :: lvl !< Refine up to this lvl
667 type(ref_info_t) :: ref_info
668 integer :: n
669
670 if (tree%highest_lvl < 1) error stop "tree not initialized"
671 if (tree%highest_lvl > 1) error stop "tree already refined"
672
673 do n = 1, lvl-1
674 call af_adjust_refinement(tree, always_refine, ref_info)
675 end do
676 end subroutine af_refine_up_to_lvl
677
678 subroutine always_refine(box, cell_flags)
679 type(box_t), intent(in) :: box
680 integer, intent(out) :: cell_flags(DTIMES(box%n_cell))
681 cell_flags = af_do_ref
682 end subroutine always_refine
683
684 !> Adjust the refinement of a tree using the user-supplied ref_subr. The
685 !> optional argument ref_buffer controls over how many cells neighbors are
686 !> affected by refinement flags.
687 !>
688 !> On input, the tree should be balanced. On output, the tree is still
689 !> balanced, and its refinement is updated (with at most one level per call).
690 subroutine af_adjust_refinement(tree, ref_subr, ref_info, ref_buffer, &
691 ref_links)
692 type(af_t), intent(inout) :: tree !< The tree to adjust
693 procedure(af_subr_ref) :: ref_subr !< Refinement function
694 type(ref_info_t), intent(inout) :: ref_info !< Information about refinement
695 integer, intent(in), optional :: ref_buffer !< Buffer width (in cells)
696 !> Lists of linked boxes which should have the same refinement
697 integer, intent(in), optional :: ref_links(:, :)
698 integer :: lvl, id, i, c_ids(af_num_children), i_ch
699 integer :: i_add, i_rm, n_ch, n_add
700 integer, allocatable :: ref_flags(:)
701 integer :: ref_buffer_val
702
703 if (.not. tree%ready) stop "Tree not ready"
704
705 ref_buffer_val = 0 ! Default buffer width (in cells) around refinement
706 if (present(ref_buffer)) ref_buffer_val = ref_buffer
707
708 if (ref_buffer_val < 0) &
709 error stop "af_adjust_refinement: ref_buffer < 0"
710 if (ref_buffer_val > tree%n_cell) &
711 error stop "af_adjust_refinement: ref_buffer > tree%n_cell"
712
713 allocate(ref_flags(tree%highest_id))
714
715 ! Set refinement values for all boxes. Only two flags are used below:
716 ! af_refine and af_derefine. Other values are ignored.
717 call consistent_ref_flags(tree, ref_flags, ref_subr, &
718 ref_buffer_val, ref_links)
719
720 ! To store ids of removed boxes
721 n_ch = af_num_children
722 ref_info%n_rm = n_ch * count(ref_flags == af_derefine)
723 if (allocated(ref_info%rm)) deallocate(ref_info%rm)
724 allocate(ref_info%rm(ref_info%n_rm))
725
726 ! To store ids of new boxes per level
727 ref_info%n_add = n_ch * count(ref_flags == af_refine)
728 if (allocated(ref_info%lvls)) deallocate(ref_info%lvls)
729 allocate(ref_info%lvls(tree%highest_lvl+1))
730
731 ! There can be no new children at level 1
732 allocate(ref_info%lvls(1)%add(0))
733
734 do lvl = 1, tree%highest_lvl
735 ! Number of newly added boxes to the next level
736 n_add = n_ch * count(ref_flags(tree%lvls(lvl)%ids) == af_refine)
737 allocate(ref_info%lvls(lvl+1)%add(n_add))
738 end do
739
740 i_rm = 0
741
742 do lvl = 1, af_max_lvl-1 ! The loop exits when it encounters an empty level
743 i_add = 0
744
745 do i = 1, size(tree%lvls(lvl)%ids)
746 id = tree%lvls(lvl)%ids(i)
747
748 if (id > size(ref_flags)) then
749 cycle ! This is a newly added box
750 else if (ref_flags(id) == af_refine) then
751 ! Add children. First need to get num_children free id's
752 call get_free_ids(tree, c_ids)
753 call add_children(tree, id, c_ids)
754 ref_info%lvls(lvl+1)%add(i_add+1:i_add+n_ch) = &
755 tree%boxes(id)%children
756 i_add = i_add + n_ch
757 else if (ref_flags(id) == af_derefine) then
758 ! Remove children
759 call auto_restrict(tree, id)
760 ref_info%rm(i_rm+1:i_rm+n_ch) = tree%boxes(id)%children
761 i_rm = i_rm + n_ch
762 call remove_children(tree, id)
763 end if
764 end do
765
766 ! Update leaves / parents
767 call set_leaves_parents(tree%boxes, tree%lvls(lvl))
768
769 ! Set next level ids to children of this level
770 call set_child_ids(tree%lvls(lvl)%parents, &
771 tree%lvls(lvl+1)%ids, tree%boxes)
772
773 ! Update connectivity of new children
774 do i = 1, size(tree%lvls(lvl)%parents)
775 id = tree%lvls(lvl)%parents(i)
776 if (ref_flags(id) == af_refine) then
777 do i_ch = 1, af_num_children
778 call set_neighbs(tree%boxes, tree%boxes(id)%children(i_ch))
779 end do
780 end if
781 end do
782
783 if (size(tree%lvls(lvl+1)%ids) == 0) exit
784 end do
785
786 tree%highest_lvl = lvl
787
788 ! Update the list of removed boxes. We do this at the end so that they are
789 ! not re-used in the loop above.
790 i = tree%n_removed_ids
791 tree%removed_ids(i+1:i+ref_info%n_rm) = ref_info%rm(:)
792 tree%n_removed_ids = tree%n_removed_ids + ref_info%n_rm
793
794 ! Set the highest id in use
795 do id = tree%highest_id, 1, -1
796 if (tree%boxes(id)%in_use) exit
797 end do
798 tree%highest_id = id
799
800 ! Clean up list of removed boxes
801 i_rm = tree%n_removed_ids
802 i = count(tree%removed_ids(1:i_rm) <= tree%highest_id)
803 tree%removed_ids(1:i) = pack(tree%removed_ids(1:i_rm), &
804 mask=tree%removed_ids(1:i_rm) <= tree%highest_id)
805 tree%n_removed_ids = i
806
807 ! We still have to update leaves and parents for the last level, which is
808 ! either lvl+1 or af_max_lvl. Note that lvl+1 is empty now, but maybe it was
809 ! not not empty before, and that af_max_lvl is skipped in the above loop.
810 lvl = min(lvl+1, af_max_lvl)
811 call set_leaves_parents(tree%boxes, tree%lvls(lvl))
812
813 call auto_prolong(tree, ref_info)
814
815 end subroutine af_adjust_refinement
816
817 !> Try to automatically restrict to box with index id
818 subroutine auto_restrict(tree, id)
819 type(af_t), intent(inout) :: tree
820 integer, intent(in) :: id
821 integer :: i, iv, i_ch, ch_id
822
823 if (.not. any(tree%has_cc_method(:))) return
824
825 do i_ch = 1, af_num_children
826 ch_id = tree%boxes(id)%children(i_ch)
827 do i = 1, size(tree%cc_auto_vars)
828 iv = tree%cc_auto_vars(i)
829 call tree%cc_methods(iv)%restrict(tree%boxes(ch_id), &
830 tree%boxes(id), [iv])
831 end do
832 end do
833 end subroutine auto_restrict
834
835 !> Try to automatically prolong to all new boxes
836 subroutine auto_prolong(tree, ref_info)
837 use m_af_ghostcell, only: af_gc_box
838 type(af_t), intent(inout) :: tree
839 type(ref_info_t), intent(in) :: ref_info
840 integer :: lvl, i, n, iv, id, p_id
841
842 ! Skip this routine when it won't do anything
843 if (.not. any(tree%has_cc_method(:)) .or. ref_info%n_add == 0) then
844 return
845 end if
846
847 !$omp parallel private(lvl, i, n, iv, id, p_id)
848 do lvl = 1, tree%highest_lvl
849 !$omp do
850 do i = 1, size(ref_info%lvls(lvl)%add)
851 id = ref_info%lvls(lvl)%add(i)
852 p_id = tree%boxes(id)%parent
853
854 do n = 1, size(tree%cc_auto_vars)
855 iv = tree%cc_auto_vars(n)
856 call tree%cc_methods(iv)%prolong(tree%boxes(p_id), &
857 tree%boxes(id), iv, limiter=tree%cc_methods(iv)%prolong_limiter)
858 end do
859 do n = 1, size(tree%cc_func_vars)
860 iv = tree%cc_func_vars(n)
861 call tree%cc_methods(iv)%funcval(tree%boxes(id), iv)
862 end do
863 end do
864 !$omp end do
865
866 !$omp do
867 do i = 1, size(ref_info%lvls(lvl)%add)
868 id = ref_info%lvls(lvl)%add(i)
869 call af_gc_box(tree, id, [tree%cc_auto_vars])
870 end do
871 !$omp end do
872 end do
873 !$omp end parallel
874 end subroutine auto_prolong
875
876 !> Get free ids from the boxes(:) array to store new boxes in. These ids are
877 !> always consecutive.
878 subroutine get_free_ids(tree, ids)
879 type(af_t), intent(inout) :: tree
880 integer, intent(out) :: ids(:) !< Array which will be filled with free box ids
881 integer :: i, highest_id_prev, n_ids
882
883 n_ids = size(ids)
884
885 !> @todo when doing AMR in parallel, perhaps move some of the code outside
886 !> the critical construct
887
888 !$omp critical (crit_free_ids)
889 if (n_ids <= tree%n_removed_ids) then
890 ! Re-use removed boxes
891 do i = 1, n_ids
892 ids(i) = tree%removed_ids(tree%n_removed_ids-n_ids+i)
893 end do
894 tree%n_removed_ids = tree%n_removed_ids - n_ids
895 else
896 ! Add new boxes at the end of the list
897 highest_id_prev = tree%highest_id
898 tree%highest_id = tree%highest_id + n_ids
899
900 if (tree%highest_id > size(tree%boxes)) then
901 print *, "get_free_ids: exceeding memory limit"
902 write(*, '(A,E12.2)') " memory_limit (GByte): ", &
903 tree%box_limit * 0.5_dp**30 * &
904 af_box_bytes(tree%n_cell, tree%n_var_cell, tree%n_var_face)
905 print *, "memory_limit (boxes): ", tree%box_limit
906 print *, "You can increase the memory limit in your call to af_init"
907 print *, "by setting mem_limit_gb to a higher value (in GBytes)"
908 error stop
909 end if
910
911 ids = [(highest_id_prev + i, i=1,n_ids)]
912 end if
913 !$omp end critical (crit_free_ids)
914
915 end subroutine get_free_ids
916
917 !> Given the refinement function, return consistent refinement flags, that
918 !> ensure that the tree is still balanced. Furthermore, it cannot derefine the
919 !> base level, and it cannot refine above af_max_lvl. The argument
920 !> ref_flags is changed: for boxes that will be refined it holds af_refine,
921 !> for boxes that will be derefined it holds af_derefine
922 subroutine consistent_ref_flags(tree, ref_flags, ref_subr, &
923 ref_buffer, ref_links)
924 use omp_lib, only: omp_get_max_threads, omp_get_thread_num
925 type(af_t), intent(inout) :: tree !< Tree for which we set refinement flags
926 integer, intent(inout) :: ref_flags(:) !< List of refinement flags for all boxes(:)
927 procedure(af_subr_ref) :: ref_subr !< User-supplied refinement function.
928 integer, intent(in) :: ref_buffer !< Buffer width (in cells)
929 !> Lists of linked boxes which should have the same refinement
930 integer, intent(in), optional :: ref_links(:, :)
931 integer :: lvl, i, i_ch, ch_id, id
932 integer :: p_id
933 integer :: thread_id
934 integer, allocatable :: tmp_flags(:, :)
935 integer :: cell_flags(DTIMES(tree%n_cell))
936 integer, parameter :: unset_flag = -huge(1)
937
938 ! Set refinement flags for each thread individually, because we sometimes
939 ! modify the refinement flags of neighbors
940 allocate(tmp_flags(size(ref_flags), omp_get_max_threads()))
941
942 tmp_flags(:, :) = unset_flag
943
944 ! Set refinement flags on all leaves and their immediate parents (on other
945 ! boxes the flags would not matter)
946
947 !$omp parallel private(lvl, i, id, p_id, cell_flags, thread_id, i_ch, ch_id)
948 thread_id = omp_get_thread_num() + 1
949
950 do lvl = 1, tree%highest_lvl
951 !$omp do
952 do i = 1, size(tree%lvls(lvl)%leaves)
953 id = tree%lvls(lvl)%leaves(i)
954
955 call ref_subr(tree%boxes(id), cell_flags)
956 call cell_to_ref_flags(cell_flags, tree%n_cell, &
957 tmp_flags(:, thread_id), tree, id, ref_buffer)
958
959 ! If the parent exists, and this is the first child which is itself
960 ! not refined, set refinement flags for the parent
961 if (tree%boxes(id)%lvl > 1) then
962 p_id = tree%boxes(id)%parent
963 do i_ch = 1, af_ix_to_ichild(tree%boxes(id)%ix)-1
964 ch_id = tree%boxes(p_id)%children(i_ch)
965 if (.not. af_has_children(tree%boxes(ch_id))) exit
966 end do
967
968 if (i_ch == af_ix_to_ichild(tree%boxes(id)%ix)) then
969 ! This is the first child which is itself not refined
970 call ref_subr(tree%boxes(p_id), cell_flags)
971 call cell_to_ref_flags(cell_flags, tree%n_cell, &
972 tmp_flags(:, thread_id), tree, p_id, ref_buffer)
973 end if
974 end if
975 end do
976 !$omp end do
977 end do
978 !$omp end parallel
979
980 ! Take the highest value over the threads
981 do i = 1, size(ref_flags)
982 ref_flags(i) = maxval(tmp_flags(i, :))
983 if (ref_flags(i) == unset_flag) ref_flags(i) = af_keep_ref
984 end do
985
986 if (maxval(ref_flags) > af_do_ref .or. minval(ref_flags) < af_rm_ref) &
987 stop "af_adjust_refinement: invalid refinement flag given"
988
989 ! Cannot refine beyond max level
990 do i = 1, size(tree%lvls(af_max_lvl)%ids)
991 id = tree%lvls(af_max_lvl)%ids(i)
992 if (ref_flags(id) == af_do_ref) ref_flags(id) = af_keep_ref
993 end do
994
995 call ensure_two_one_balance(tree, ref_flags)
996 call handle_derefinement_flags(tree, ref_flags)
997
998 if (present(ref_links)) then
999 do i = 1, size(ref_links, 2)
1000 ref_flags(ref_links(:, i)) = maxval(ref_flags(ref_links(:, i)))
1001 end do
1002 call ensure_two_one_balance(tree, ref_flags)
1003 call handle_derefinement_flags(tree, ref_flags)
1004 end if
1005
1006 end subroutine consistent_ref_flags
1007
1008 !> Adjust refinement flags to ensure 2-1 balance is maintained
1009 subroutine ensure_two_one_balance(tree, ref_flags)
1010 type(af_t), intent(inout) :: tree
1011 integer, intent(inout) :: ref_flags(:)
1012 integer :: lvl, i, id, nb, nb_id
1013 integer :: p_id, p_nb_id
1014
1015 ! Ensure 2-1 balance
1016 do lvl = tree%highest_lvl, 1, -1
1017 do i = 1, size(tree%lvls(lvl)%leaves) ! We only check leaf tree%boxes
1018 id = tree%lvls(lvl)%leaves(i)
1019
1020 if (ref_flags(id) == af_do_ref .or. ref_flags(id) == af_refine) then
1021 ref_flags(id) = af_refine ! Mark for actual refinement
1022
1023 ! Ensure we will have the necessary neighbors
1024 do nb = 1, af_num_neighbors
1025 nb_id = tree%boxes(id)%neighbors(nb)
1026 if (nb_id == af_no_box) then
1027 ! Mark the parent containing neighbor for refinement
1028 p_id = tree%boxes(id)%parent
1029 p_nb_id = tree%boxes(p_id)%neighbors(nb)
1030 ref_flags(p_nb_id) = af_refine
1031 end if
1032 end do
1033
1034 else if (ref_flags(id) == af_rm_ref) then
1035 ! Ensure we do not remove a required neighbor
1036 do nb = 1, af_num_neighbors
1037 nb_id = tree%boxes(id)%neighbors(nb)
1038 if (nb_id > af_no_box) then
1039 if (af_has_children(tree%boxes(nb_id)) .or. &
1040 ref_flags(nb_id) > af_keep_ref) then
1041 ref_flags(id) = af_keep_ref
1042 exit
1043 end if
1044 end if
1045 end do
1046 end if
1047
1048 end do
1049 end do
1050 end subroutine ensure_two_one_balance
1051
1052 subroutine handle_derefinement_flags(tree, ref_flags)
1053 type(af_t), intent(inout) :: tree
1054 integer, intent(inout) :: ref_flags(:)
1055 integer :: lvl, i, id, c_ids(af_num_children)
1056
1057 ! Make the (de)refinement flags consistent for blocks with children
1058 do lvl = tree%highest_lvl-1, 1, -1
1059 do i = 1, size(tree%lvls(lvl)%parents)
1060 id = tree%lvls(lvl)%parents(i)
1061 c_ids = tree%boxes(id)%children
1062
1063 ! Only consider boxes for which at least one child is a leaf
1064 if (all(af_has_children(tree%boxes(c_ids)))) cycle
1065
1066 ! Can only remove children if they are all marked for
1067 ! derefinement, and the box itself not for refinement.
1068 if (all(ref_flags(c_ids) == af_rm_ref) .and. &
1069 ref_flags(id) <= af_keep_ref) then
1070 ref_flags(id) = af_derefine
1071 else
1072 ref_flags(id) = af_keep_ref
1073 ! The children cannot be removed. This information is useful when
1074 ! the modify_refinement() routine is used. Make sure not to
1075 ! override previously set derefinement flags.
1076 where (ref_flags(c_ids) /= af_derefine)
1077 ref_flags(c_ids) = max(ref_flags(c_ids), af_keep_ref)
1078 end where
1079 end if
1080 end do
1081 end do
1082
1083 end subroutine handle_derefinement_flags
1084
1085 !> Given the cell refinement flags of a box, set the refinement flag for that
1086 !> box and potentially also its neighbors (in case of refinement near a
1087 !> boundary).
1088 subroutine cell_to_ref_flags(cell_flags, nc, ref_flags, tree, id, &
1089 ref_buffer)
1090 use m_af_utils, only: af_get_loc
1091 integer, intent(in) :: nc !< n_cell for the box
1092 integer, intent(in) :: cell_flags(DTIMES(nc)) !< Cell refinement flags
1093 integer, intent(inout) :: ref_flags(:) !< Box refinement flags for this thread
1094 type(af_t), intent(in) :: tree !< Full tree
1095 integer, intent(in) :: id !< Which box is considered
1096 integer, intent(in) :: ref_buffer !< Buffer cells around refinement
1097 integer :: ix0(NDIM), ix1(NDIM), IJK, nb_id
1098
1099 if (minval(cell_flags) < af_rm_ref .or. &
1100 maxval(cell_flags) > af_do_ref) then
1101 error stop "Error: invalid cell flags given"
1102 end if
1103
1104 ! Check whether the box needs to be refined or keep its refinement
1105 if (any(cell_flags == af_do_ref)) then
1106 ref_flags(id) = af_do_ref
1107 else if (any(cell_flags == af_keep_ref)) then
1108 ref_flags(id) = max(ref_flags(id), af_keep_ref)
1109 else ! All flags are af_rm_ref
1110 ref_flags(id) = max(ref_flags(id), af_rm_ref)
1111 end if
1112
1113 if (ref_buffer <= 0) return ! No need to check neighbors
1114
1115 ! Check whether neighbors also require refinement, which happens when cells
1116 ! close to the neighbor are flagged.
1117 do kji_do(-1,1)
1118 if (all([ijk] == 0)) cycle
1119
1120 nb_id = tree%boxes(id)%neighbor_mat(ijk)
1121
1122 ! Skip neighbors that are not there
1123 if (nb_id <= af_no_box) cycle
1124
1125 ! Compute index range relevant for neighbor
1126 ix0 = 1
1127 ix1 = nc
1128 where ([ijk] == 1)
1129 ix0 = nc - ref_buffer + 1
1130 ix1 = nc
1131 elsewhere ([ijk] == -1)
1132 ix0 = 1
1133 ix1 = ref_buffer
1134 end where
1135
1136 if (any(cell_flags(dslice(ix0, ix1)) == af_do_ref)) then
1137 ref_flags(nb_id) = af_do_ref
1138 end if
1139 end do; close_do
1140
1141 end subroutine cell_to_ref_flags
1142
1143 !> Remove the children of box id
1144 subroutine remove_children(tree, id)
1145 type(af_t), intent(inout) :: tree
1146 integer, intent(in) :: id !< Id of box whose children will be removed
1147 integer :: ic, c_id, nb_id, nb_rev, nb, IJK
1148
1149 do ic = 1, af_num_children
1150 c_id = tree%boxes(id)%children(ic)
1151
1152 ! Remove from neighbors
1153 do nb = 1, af_num_neighbors
1154 nb_id = tree%boxes(c_id)%neighbors(nb)
1155 if (nb_id > af_no_box) then
1156 nb_rev = af_neighb_rev(nb)
1157 tree%boxes(nb_id)%neighbors(nb_rev) = af_no_box
1158 end if
1159 end do
1160
1161 do kji_do(-1,1)
1162 nb_id = tree%boxes(c_id)%neighbor_mat(ijk)
1163 if (nb_id > af_no_box) then
1164#if NDIM == 1
1165 tree%boxes(nb_id)%neighbor_mat(-i) = af_no_box
1166#elif NDIM == 2
1167 tree%boxes(nb_id)%neighbor_mat(-i, -j) = af_no_box
1168#elif NDIM == 3
1169 tree%boxes(nb_id)%neighbor_mat(-i, -j, -k) = af_no_box
1170#endif
1171 end if
1172 end do; close_do
1173
1174 call af_deactivate_box(tree%boxes(c_id))
1175 end do
1176
1177 tree%boxes(id)%children = af_no_box
1178 end subroutine remove_children
1179
1180 !> Add children to box id, using the indices in c_ids
1181 subroutine add_children(tree, id, c_ids)
1182 type(af_t), intent(inout) :: tree !< Tree
1183 integer, intent(in) :: id !< Id of box that gets children
1184 integer, intent(in) :: c_ids(af_num_children) !< Free ids for the children
1185 integer :: i, nb, child_nb(2**(NDIM-1))
1186 integer :: c_id, c_ix_base(NDIM), dix(NDIM)
1187
1188 associate(boxes => tree%boxes)
1189 boxes(id)%children = c_ids
1190 c_ix_base = 2 * boxes(id)%ix - 1
1191
1192 do i = 1, af_num_children
1193 c_id = c_ids(i)
1194 boxes(c_id)%ix = c_ix_base + af_child_dix(:,i)
1195 boxes(c_id)%lvl = boxes(id)%lvl+1
1196 boxes(c_id)%parent = id
1197 boxes(c_id)%tag = af_init_tag
1198 boxes(c_id)%children = af_no_box
1199 boxes(c_id)%neighbors = af_no_box
1200 boxes(c_id)%neighbor_mat = af_no_box
1201 boxes(c_id)%neighbor_mat(dtimes(0)) = c_id
1202 boxes(c_id)%n_cell = boxes(id)%n_cell
1203 boxes(c_id)%coord_t = boxes(id)%coord_t
1204 boxes(c_id)%dr = 0.5_dp * boxes(id)%dr
1205 boxes(c_id)%r_min = boxes(id)%r_min + 0.5_dp * boxes(id)%dr * &
1206 af_child_dix(:,i) * boxes(id)%n_cell
1207 end do
1208
1209 ! Set boundary conditions at children
1210 do nb = 1, af_num_neighbors
1211 if (boxes(id)%neighbors(nb) < af_no_box) then
1212 child_nb = c_ids(af_child_adj_nb(:, nb)) ! Neighboring children
1213 boxes(child_nb)%neighbors(nb) = boxes(id)%neighbors(nb)
1214 dix = af_neighb_dix(:, nb)
1215 boxes(child_nb)%neighbor_mat(dindex(dix)) = &
1216 boxes(id)%neighbors(nb)
1217 end if
1218 end do
1219 end associate
1220
1221 ! Have to call this after setting boundary conditions
1222 do i = 1, af_num_children
1223 call af_init_box(tree, c_ids(i))
1224 end do
1225
1226 end subroutine add_children
1227
1228 !> Create a list c_ids(:) of all the children of p_ids(:). This is used after
1229 !> a level has been refined.
1230 subroutine set_child_ids(p_ids, c_ids, boxes)
1231 integer, intent(in) :: p_ids(:) !< All the parents ids
1232 integer, allocatable, intent(inout) :: c_ids(:) !< Output: all the children's ids
1233 type(box_t), intent(in) :: boxes(:) !< List of all the boxes
1234 integer :: i, i0, i1, n_children
1235
1236 n_children = af_num_children * size(p_ids)
1237 if (n_children /= size(c_ids)) then
1238 deallocate(c_ids)
1239 allocate(c_ids(n_children))
1240 end if
1241
1242 do i = 1, size(p_ids)
1243 i1 = i * af_num_children
1244 i0 = i1 - af_num_children + 1
1245 c_ids(i0:i1) = boxes(p_ids(i))%children
1246 end do
1247 end subroutine set_child_ids
1248
1249 !> Restrict fluxes from children to parents on refinement boundaries.
1250 subroutine af_consistent_fluxes(tree, f_ixs)
1251 type(af_t), intent(inout) :: tree !< Tree to operate on
1252 integer, intent(in) :: f_ixs(:) !< Indices of the fluxes
1253 integer :: lvl, i, id, nb, nb_id
1254
1255 if (.not. tree%ready) stop "Tree not ready"
1256 !$omp parallel private(lvl, i, id, nb, nb_id)
1257 do lvl = 1, tree%highest_lvl-1
1258 !$omp do
1259 do i = 1, size(tree%lvls(lvl)%parents)
1260 id = tree%lvls(lvl)%parents(i)
1261 do nb = 1, af_num_neighbors
1262 nb_id = tree%boxes(id)%neighbors(nb)
1263
1264 ! If the neighbor exists and has no children, set flux
1265 if (nb_id > af_no_box) then
1266 if (.not. af_has_children(tree%boxes(nb_id))) then
1267 call flux_from_children(tree%boxes, id, nb, f_ixs)
1268 end if
1269 end if
1270 end do
1271 end do
1272 !$omp end do
1273 end do
1274 !$omp end parallel
1275 end subroutine af_consistent_fluxes
1276
1277 !> The neighbor nb has no children and id does, so set flux on the neighbor
1278 !> from our children. This ensures flux consistency at refinement boundary.
1279 subroutine flux_from_children(boxes, id, nb, f_ixs)
1280 type(box_t), intent(inout) :: boxes(:) !< List of all the boxes
1281 integer, intent(in) :: id !< Id of box for which we set fluxes
1282 integer, intent(in) :: nb !< Direction in which fluxes are set
1283 integer, intent(in) :: f_ixs(:) !< Indices of the fluxes
1284 integer :: nc, nch, c_id, i_ch, i, ic, d
1285 integer :: n_chnb, nb_id, i_nb
1286#if NDIM > 1
1287 integer :: ioff(NDIM)
1288#endif
1289#if NDIM == 2
1290 integer :: n
1291 real(dp) :: w1, w2
1292#endif
1293
1294
1295 nc = boxes(id)%n_cell
1296 nch = ishft(nc, -1) ! nc/2
1297 d = af_neighb_dim(nb)
1298 n_chnb = 2**(ndim-1)
1299 nb_id = boxes(id)%neighbors(nb)
1300
1301 if (af_neighb_low(nb)) then
1302 i = 1
1303 i_nb = nc+1
1304 else
1305 i = nc+1
1306 i_nb = 1
1307 end if
1308
1309 select case (d)
1310#if NDIM == 1
1311 case (1)
1312 do ic = 1, n_chnb
1313 ! Get index of child adjacent to neighbor
1314 i_ch = af_child_adj_nb(ic, nb)
1315 c_id = boxes(id)%children(i_ch)
1316 boxes(nb_id)%fc(i_nb, 1, f_ixs) = boxes(c_id)%fc(i, 1, f_ixs)
1317 end do
1318#elif NDIM == 2
1319 case (1)
1320 do ic = 1, n_chnb
1321 ! Get index of child adjacent to neighbor
1322 i_ch = af_child_adj_nb(ic, nb)
1323 c_id = boxes(id)%children(i_ch)
1324 ! Index offset of child w.r.t. parent
1325 ioff = nch*af_child_dix(:, i_ch)
1326 boxes(nb_id)%fc(i_nb, ioff(2)+1:ioff(2)+nch, 1, f_ixs) = 0.5_dp * ( &
1327 boxes(c_id)%fc(i, 1:nc:2, 1, f_ixs) + &
1328 boxes(c_id)%fc(i, 2:nc:2, 1, f_ixs))
1329 end do
1330 case (2)
1331 if (boxes(nb_id)%coord_t == af_cyl) then
1332 ! In cylindrical symmetry, we take the weighted average
1333 do ic = 1, n_chnb
1334 i_ch = af_child_adj_nb(ic, nb)
1335 c_id = boxes(id)%children(i_ch)
1336 ioff = nch*af_child_dix(:, i_ch)
1337
1338 do n = 1, nch
1339 call af_cyl_child_weights(boxes(nb_id), ioff(1)+n, w1, w2)
1340 boxes(nb_id)%fc(ioff(1)+n, i_nb, 2, f_ixs) = 0.5_dp * (&
1341 w1 * boxes(c_id)%fc(2*n-1, i, 2, f_ixs) + &
1342 w2 * boxes(c_id)%fc(2*n, i, 2, f_ixs))
1343 end do
1344 end do
1345 else
1346 ! Just take the average of the fine fluxes
1347 do ic = 1, n_chnb
1348 i_ch = af_child_adj_nb(ic, nb)
1349 c_id = boxes(id)%children(i_ch)
1350 ioff = nch*af_child_dix(:, i_ch)
1351 boxes(nb_id)%fc(ioff(1)+1:ioff(1)+nch, i_nb, 2, f_ixs) = 0.5_dp * ( &
1352 boxes(c_id)%fc(1:nc:2, i, 2, f_ixs) + &
1353 boxes(c_id)%fc(2:nc:2, i, 2, f_ixs))
1354 end do
1355 end if
1356#elif NDIM == 3
1357 case (1)
1358 do ic = 1, n_chnb
1359 i_ch = af_child_adj_nb(ic, nb)
1360 c_id = boxes(id)%children(i_ch)
1361 ioff = nch*af_child_dix(:, i_ch)
1362 boxes(nb_id)%fc(i_nb, ioff(2)+1:ioff(2)+nch, &
1363 ioff(3)+1:ioff(3)+nch, 1, f_ixs) = 0.25_dp * ( &
1364 boxes(c_id)%fc(i, 1:nc:2, 1:nc:2, 1, f_ixs) + &
1365 boxes(c_id)%fc(i, 2:nc:2, 1:nc:2, 1, f_ixs) + &
1366 boxes(c_id)%fc(i, 1:nc:2, 2:nc:2, 1, f_ixs) + &
1367 boxes(c_id)%fc(i, 2:nc:2, 2:nc:2, 1, f_ixs))
1368 end do
1369 case (2)
1370 do ic = 1, n_chnb
1371 i_ch = af_child_adj_nb(ic, nb)
1372 c_id = boxes(id)%children(i_ch)
1373 ioff = nch*af_child_dix(:, i_ch)
1374 boxes(nb_id)%fc(ioff(1)+1:ioff(1)+nch, i_nb, &
1375 ioff(3)+1:ioff(3)+nch, 2, f_ixs) = 0.25_dp * ( &
1376 boxes(c_id)%fc(1:nc:2, i, 1:nc:2, 2, f_ixs) + &
1377 boxes(c_id)%fc(2:nc:2, i, 1:nc:2, 2, f_ixs) + &
1378 boxes(c_id)%fc(1:nc:2, i, 2:nc:2, 2, f_ixs) + &
1379 boxes(c_id)%fc(2:nc:2, i, 2:nc:2, 2, f_ixs))
1380 end do
1381 case (3)
1382 do ic = 1, n_chnb
1383 i_ch = af_child_adj_nb(ic, nb)
1384 c_id = boxes(id)%children(i_ch)
1385 ioff = nch*af_child_dix(:, i_ch)
1386 boxes(nb_id)%fc(ioff(1)+1:ioff(1)+nch, &
1387 ioff(2)+1:ioff(2)+nch, i_nb, 3, f_ixs) = 0.25_dp * ( &
1388 boxes(c_id)%fc(1:nc:2, 1:nc:2, i, 3, f_ixs) + &
1389 boxes(c_id)%fc(2:nc:2, 1:nc:2, i, 3, f_ixs) + &
1390 boxes(c_id)%fc(1:nc:2, 2:nc:2, i, 3, f_ixs) + &
1391 boxes(c_id)%fc(2:nc:2, 2:nc:2, i, 3, f_ixs))
1392 end do
1393#endif
1394 end select
1395 end subroutine flux_from_children
1396
1397end module m_af_core
To fill ghost cells near physical boundaries in a custom way. If the number of ghost cells to fill is...
To fill ghost cells near physical boundaries.
To set cell-centered variables based on a user-defined function. This can be useful to avoid recomput...
Subroutine for prolongation.
To fill ghost cells near refinement boundaries.
Subroutine for restriction.
This module contains the core routines of Afivo, namely those that deal with initializing and changin...
Definition m_af_core.f90:3
This module contains routines related to the filling of ghost cells. Note that corner ghost cells are...
Module containing slope limiters.
This module contains the routines related to prolongation: going from coarse to fine variables.
This module contains routines for restriction: going from fine to coarse variables.
This module contains the basic types and constants that are used in the NDIM-dimensional version of A...
Definition m_af_types.f90:3
This module contains all kinds of different 'helper' routines for Afivo. If the number of routines fo...
Definition m_af_utils.f90:4
Type which stores all the boxes and levels, as well as some information about the number of boxes,...
The basic building block of afivo: a box with cell-centered and face centered data,...
Type which contains the indices of all boxes at a refinement level, as well as a list with all the "l...